@obosbbl/grunnmuren-react 3.3.4 → 3.3.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/dist/__stories__/layout.stories.cjs +25 -12
- package/dist/__stories__/layout.stories.js +25 -12
- package/dist/index.d.mts +57 -22
- package/dist/index.mjs +336 -297
- package/package.json +5 -2
|
@@ -298,7 +298,6 @@ const cardLinkVariants = cva.cva({
|
|
|
298
298
|
});
|
|
299
299
|
};
|
|
300
300
|
|
|
301
|
-
const roundedMediaCorners = '*:data-[slot="media"]:*:rounded-3xl';
|
|
302
301
|
// Common variant for "standard" and "full-bleed" Hero variants
|
|
303
302
|
const oneColumnLayout = [
|
|
304
303
|
// Vertical spacing in the <Content>
|
|
@@ -311,7 +310,7 @@ const oneColumnLayout = [
|
|
|
311
310
|
'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',
|
|
312
311
|
// <Media> and <Carousel> content takes up the full width on medium screens and above
|
|
313
312
|
'lg:*:data-[slot="media"]:col-span-full *:data-[slot="media"]:*:w-full',
|
|
314
|
-
'lg:*:data-[slot="carousel"]:col-span-full
|
|
313
|
+
'lg:*:data-[slot="carousel"]:col-span-full',
|
|
315
314
|
// Aligns <Content> and any element beside it (e.g. <Media>, <Badge>, <CTA> etc.) to the bottom of the <Content> container
|
|
316
315
|
'lg:items-end'
|
|
317
316
|
];
|
|
@@ -327,7 +326,10 @@ const variants = cva.cva({
|
|
|
327
326
|
// Vertical spacing in the <Content>
|
|
328
327
|
'*:data-[slot="content"]:gap-y-3',
|
|
329
328
|
// Make sure <Media> content fills any available vertical and horizontal space
|
|
330
|
-
'*:data-[slot="media"]:*:object-cover'
|
|
329
|
+
'*:data-[slot="media"]:*:object-cover',
|
|
330
|
+
'*:data-[slot="carousel"]:overflow-hidden *:data-[slot="carousel"]:rounded-3xl',
|
|
331
|
+
// Make the carousel items full width, so we scroll one at a time
|
|
332
|
+
'**:data-[slot="carousel-item"]:basis-full'
|
|
331
333
|
],
|
|
332
334
|
variants: {
|
|
333
335
|
/**
|
|
@@ -335,7 +337,6 @@ const variants = cva.cva({
|
|
|
335
337
|
* @default standard
|
|
336
338
|
* */ variant: {
|
|
337
339
|
standard: [
|
|
338
|
-
roundedMediaCorners,
|
|
339
340
|
oneColumnLayout,
|
|
340
341
|
nonFullBleedAspectRatiosForSmallScreens,
|
|
341
342
|
'lg:*:data-[slot="media"]:*:aspect-2/1'
|
|
@@ -345,32 +346,44 @@ const variants = cva.cva({
|
|
|
345
346
|
// Position the media and carousel content to fill the entire viewport width
|
|
346
347
|
'*:data-[slot="media"]:*:absolute *:data-[slot="media"]:*:left-0',
|
|
347
348
|
// Special case for Carousel, where the Media is nested inside a CarouselItem
|
|
348
|
-
'*:data-[slot="carousel"]:**:data-[slot="media"]:w-full
|
|
349
|
+
'*:data-[slot="carousel"]:**:data-[slot="media"]:w-full',
|
|
349
350
|
// Match the heights of the <Media> or <Carousel> wrapper for the Media content (e.g. image, VideoLoop, video etc.)
|
|
350
351
|
// This is necessary due to the absolute positioning of the media and carousel containers in this variant
|
|
351
352
|
// biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
|
|
352
353
|
'**:data-[slot="media"]:h-80 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]',
|
|
353
|
-
|
|
354
|
-
'**:data-[slot="media"]:*:h-80 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]',
|
|
354
|
+
'**:data-[slot="media"]:*:h-[inherit]',
|
|
355
355
|
// biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
|
|
356
356
|
'*:data-[slot="carousel"]:h-80 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]',
|
|
357
|
+
'*:data-[slot="carousel"]:w-full!',
|
|
357
358
|
// Override aspect ratio of the media and carousel-item slots (since we can not use aspect for full-bleed layout)
|
|
358
359
|
'**:data-[slot="carousel-item"]:data-[slot="media"]:*:aspect-none',
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
360
|
+
// break out the carousel out of the container
|
|
361
|
+
'**:data-[slot="carousel-items-container"]:absolute **:data-[slot="carousel-items-container"]:right-0 **:data-[slot="carousel-items-container"]:left-0 **:data-[slot="carousel-items-container"]:h-[inherit]',
|
|
362
|
+
// Positions the carousel controls inside the carousel
|
|
363
|
+
'**:data-[slot="carousel-controls"]:z-10 **:data-[slot="carousel-controls"]:mb-4 *:data-[slot="carousel"]:flex *:data-[slot="carousel"]:items-end *:data-[slot="carousel"]:justify-end'
|
|
362
364
|
],
|
|
363
365
|
'two-column': [
|
|
364
366
|
'lg:items-center lg:*:col-span-6',
|
|
365
367
|
// Vertical spacing in the <Content>
|
|
366
368
|
'lg:*:data-[slot="content"]:gap-y-7',
|
|
367
|
-
roundedMediaCorners,
|
|
368
369
|
nonFullBleedAspectRatiosForSmallScreens,
|
|
369
370
|
// Set media aspect ratio to 1:1 (square)
|
|
370
|
-
'lg:*:data-[slot="media"]:*:aspect-
|
|
371
|
+
'lg:*:data-[slot="media"]:*:aspect-square'
|
|
371
372
|
]
|
|
372
373
|
}
|
|
373
374
|
},
|
|
375
|
+
compoundVariants: [
|
|
376
|
+
{
|
|
377
|
+
variant: [
|
|
378
|
+
'standard',
|
|
379
|
+
'two-column'
|
|
380
|
+
],
|
|
381
|
+
className: [
|
|
382
|
+
'*:data-[slot="media"]:*:rounded-3xl',
|
|
383
|
+
'**:data-[slot="carousel-controls"]:absolute *:data-[slot="carousel"]:relative **:data-[slot="carousel-controls"]:right-4 **:data-[slot="carousel-controls"]:bottom-4 **:data-[slot="carousel-container"]:rounded-3xl'
|
|
384
|
+
]
|
|
385
|
+
}
|
|
386
|
+
],
|
|
374
387
|
defaultVariants: {
|
|
375
388
|
variant: 'standard'
|
|
376
389
|
}
|
|
@@ -296,7 +296,6 @@ const cardLinkVariants = cva({
|
|
|
296
296
|
});
|
|
297
297
|
};
|
|
298
298
|
|
|
299
|
-
const roundedMediaCorners = '*:data-[slot="media"]:*:rounded-3xl';
|
|
300
299
|
// Common variant for "standard" and "full-bleed" Hero variants
|
|
301
300
|
const oneColumnLayout = [
|
|
302
301
|
// Vertical spacing in the <Content>
|
|
@@ -309,7 +308,7 @@ const oneColumnLayout = [
|
|
|
309
308
|
'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',
|
|
310
309
|
// <Media> and <Carousel> content takes up the full width on medium screens and above
|
|
311
310
|
'lg:*:data-[slot="media"]:col-span-full *:data-[slot="media"]:*:w-full',
|
|
312
|
-
'lg:*:data-[slot="carousel"]:col-span-full
|
|
311
|
+
'lg:*:data-[slot="carousel"]:col-span-full',
|
|
313
312
|
// Aligns <Content> and any element beside it (e.g. <Media>, <Badge>, <CTA> etc.) to the bottom of the <Content> container
|
|
314
313
|
'lg:items-end'
|
|
315
314
|
];
|
|
@@ -325,7 +324,10 @@ const variants = cva({
|
|
|
325
324
|
// Vertical spacing in the <Content>
|
|
326
325
|
'*:data-[slot="content"]:gap-y-3',
|
|
327
326
|
// Make sure <Media> content fills any available vertical and horizontal space
|
|
328
|
-
'*:data-[slot="media"]:*:object-cover'
|
|
327
|
+
'*:data-[slot="media"]:*:object-cover',
|
|
328
|
+
'*:data-[slot="carousel"]:overflow-hidden *:data-[slot="carousel"]:rounded-3xl',
|
|
329
|
+
// Make the carousel items full width, so we scroll one at a time
|
|
330
|
+
'**:data-[slot="carousel-item"]:basis-full'
|
|
329
331
|
],
|
|
330
332
|
variants: {
|
|
331
333
|
/**
|
|
@@ -333,7 +335,6 @@ const variants = cva({
|
|
|
333
335
|
* @default standard
|
|
334
336
|
* */ variant: {
|
|
335
337
|
standard: [
|
|
336
|
-
roundedMediaCorners,
|
|
337
338
|
oneColumnLayout,
|
|
338
339
|
nonFullBleedAspectRatiosForSmallScreens,
|
|
339
340
|
'lg:*:data-[slot="media"]:*:aspect-2/1'
|
|
@@ -343,32 +344,44 @@ const variants = cva({
|
|
|
343
344
|
// Position the media and carousel content to fill the entire viewport width
|
|
344
345
|
'*:data-[slot="media"]:*:absolute *:data-[slot="media"]:*:left-0',
|
|
345
346
|
// Special case for Carousel, where the Media is nested inside a CarouselItem
|
|
346
|
-
'*:data-[slot="carousel"]:**:data-[slot="media"]:w-full
|
|
347
|
+
'*:data-[slot="carousel"]:**:data-[slot="media"]:w-full',
|
|
347
348
|
// Match the heights of the <Media> or <Carousel> wrapper for the Media content (e.g. image, VideoLoop, video etc.)
|
|
348
349
|
// This is necessary due to the absolute positioning of the media and carousel containers in this variant
|
|
349
350
|
// biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
|
|
350
351
|
'**:data-[slot="media"]:h-80 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]',
|
|
351
|
-
|
|
352
|
-
'**:data-[slot="media"]:*:h-80 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]',
|
|
352
|
+
'**:data-[slot="media"]:*:h-[inherit]',
|
|
353
353
|
// biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
|
|
354
354
|
'*:data-[slot="carousel"]:h-80 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]',
|
|
355
|
+
'*:data-[slot="carousel"]:w-full!',
|
|
355
356
|
// Override aspect ratio of the media and carousel-item slots (since we can not use aspect for full-bleed layout)
|
|
356
357
|
'**:data-[slot="carousel-item"]:data-[slot="media"]:*:aspect-none',
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
358
|
+
// break out the carousel out of the container
|
|
359
|
+
'**:data-[slot="carousel-items-container"]:absolute **:data-[slot="carousel-items-container"]:right-0 **:data-[slot="carousel-items-container"]:left-0 **:data-[slot="carousel-items-container"]:h-[inherit]',
|
|
360
|
+
// Positions the carousel controls inside the carousel
|
|
361
|
+
'**:data-[slot="carousel-controls"]:z-10 **:data-[slot="carousel-controls"]:mb-4 *:data-[slot="carousel"]:flex *:data-[slot="carousel"]:items-end *:data-[slot="carousel"]:justify-end'
|
|
360
362
|
],
|
|
361
363
|
'two-column': [
|
|
362
364
|
'lg:items-center lg:*:col-span-6',
|
|
363
365
|
// Vertical spacing in the <Content>
|
|
364
366
|
'lg:*:data-[slot="content"]:gap-y-7',
|
|
365
|
-
roundedMediaCorners,
|
|
366
367
|
nonFullBleedAspectRatiosForSmallScreens,
|
|
367
368
|
// Set media aspect ratio to 1:1 (square)
|
|
368
|
-
'lg:*:data-[slot="media"]:*:aspect-
|
|
369
|
+
'lg:*:data-[slot="media"]:*:aspect-square'
|
|
369
370
|
]
|
|
370
371
|
}
|
|
371
372
|
},
|
|
373
|
+
compoundVariants: [
|
|
374
|
+
{
|
|
375
|
+
variant: [
|
|
376
|
+
'standard',
|
|
377
|
+
'two-column'
|
|
378
|
+
],
|
|
379
|
+
className: [
|
|
380
|
+
'*:data-[slot="media"]:*:rounded-3xl',
|
|
381
|
+
'**:data-[slot="carousel-controls"]:absolute *:data-[slot="carousel"]:relative **:data-[slot="carousel-controls"]:right-4 **:data-[slot="carousel-controls"]:bottom-4 **:data-[slot="carousel-container"]:rounded-3xl'
|
|
382
|
+
]
|
|
383
|
+
}
|
|
384
|
+
],
|
|
372
385
|
defaultVariants: {
|
|
373
386
|
variant: 'standard'
|
|
374
387
|
}
|
package/dist/index.d.mts
CHANGED
|
@@ -2,7 +2,7 @@ import { DisclosureProps as DisclosureProps$1, ButtonProps as ButtonProps$1, Lin
|
|
|
2
2
|
export { ListBoxItemProps as ComboboxItemProps, DisclosureGroup, DisclosureGroupProps, Form, Group, LabelProps, ListBoxItemProps as SelectItemProps } from 'react-aria-components';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import * as react from 'react';
|
|
5
|
-
import { RefAttributes, HTMLAttributes, HTMLProps, ComponentProps, Ref,
|
|
5
|
+
import { RefAttributes, HTMLAttributes, HTMLProps, ComponentProps, Ref, ReactNode, RefObject, Dispatch, SetStateAction, JSX } from 'react';
|
|
6
6
|
import * as cva from 'cva';
|
|
7
7
|
import { VariantProps } from 'cva';
|
|
8
8
|
import { DisclosureState } from 'react-stately';
|
|
@@ -214,35 +214,70 @@ type CardLinkProps = (Omit<LinkProps$1, 'href'> & Required<Pick<LinkProps$1, 'hr
|
|
|
214
214
|
*/
|
|
215
215
|
declare const CardLink: ({ className: _className, href, ...restProps }: CardLinkProps) => react_jsx_runtime.JSX.Element;
|
|
216
216
|
|
|
217
|
-
type CarouselProps = Omit<HTMLProps<HTMLDivElement>, 'onChange'> & {
|
|
218
|
-
|
|
219
|
-
|
|
217
|
+
type CarouselProps = Omit<HTMLProps<HTMLDivElement>, 'onChange' | 'onSelect'> & {
|
|
218
|
+
children?: React.ReactNode;
|
|
219
|
+
/**
|
|
220
|
+
* Alignment of the items relative to the carousel viewport.
|
|
221
|
+
* @default 'center'
|
|
222
|
+
*/
|
|
223
|
+
align?: 'start' | 'center' | 'end';
|
|
224
|
+
/** Delay in milliseconds between each automatic transition of the carousel. Any interaction with the carousel will immediately stop the autoplay. */
|
|
225
|
+
autoPlayDelay?: number;
|
|
226
|
+
/**
|
|
227
|
+
* The initial snapped index of the carousel.
|
|
228
|
+
* @default 0
|
|
229
|
+
*/
|
|
230
|
+
initialIndex?: number;
|
|
231
|
+
/**
|
|
232
|
+
* Whether the carousel infinitely loops.
|
|
233
|
+
* @default false
|
|
234
|
+
*/
|
|
235
|
+
loop?: boolean;
|
|
236
|
+
/**
|
|
237
|
+
* Orientation of the carousel.
|
|
238
|
+
* @default 'horizontal'
|
|
239
|
+
*/
|
|
240
|
+
orientation?: 'horizontal' | 'vertical';
|
|
241
|
+
/**
|
|
242
|
+
* Callback invoked when the snapped index changes.
|
|
243
|
+
*/
|
|
244
|
+
onSelect?: (index: number) => void;
|
|
220
245
|
/**
|
|
221
|
-
* Callback
|
|
222
|
-
* The argument to the callback is an object containing `index` of the new item scrolled into view and the `id` of that item (if set on the `<CarouselItem>`)
|
|
223
|
-
* It also provides `prevIndex` which is the index of the previous item that was in view
|
|
224
|
-
* And `prevId`, which is the id of the previous item that was in view (if set on the `<CarouselItem>`)
|
|
225
|
-
* @param item { index: number; id?: string; prevIndex: number; prevId?: string }
|
|
246
|
+
* Callback invoked after the carousel scrolling "settles". Think of this as the debounced version of `onSelect`.
|
|
226
247
|
*/
|
|
227
|
-
|
|
248
|
+
onSettled?: (index: number) => void;
|
|
249
|
+
/**
|
|
250
|
+
* Whether the carousel should scroll with regular mouse/trackpad scroll gestures, in addition to swipe gestures.
|
|
251
|
+
* @default false
|
|
252
|
+
*/
|
|
253
|
+
scrollGestures?: boolean;
|
|
228
254
|
};
|
|
229
|
-
declare const Carousel: ({
|
|
255
|
+
declare const Carousel: ({ autoPlayDelay, align, children, initialIndex, orientation, onSelect, onSettled, loop, scrollGestures, ref, ...rest }: CarouselProps) => react_jsx_runtime.JSX.Element;
|
|
256
|
+
type CarouselItemsContainer = HTMLProps<HTMLDivElement> & {
|
|
257
|
+
children: React.ReactNode;
|
|
258
|
+
};
|
|
259
|
+
declare const CarouselItemsContainer: ({ children, className, ...rest }: CarouselItemsContainer) => react_jsx_runtime.JSX.Element;
|
|
230
260
|
type CarouselItemsProps = HTMLProps<HTMLDivElement> & {
|
|
231
261
|
/** The <CarouselItem/> components to be displayed within the carousel. */
|
|
232
262
|
children: React.ReactNode;
|
|
233
263
|
};
|
|
234
264
|
declare const CarouselItems: ({ className, children }: CarouselItemsProps) => react_jsx_runtime.JSX.Element;
|
|
265
|
+
type CarouselControlsProps = HTMLProps<HTMLDivElement> & {
|
|
266
|
+
/** The <CarouselItem/> components to be displayed within the carousel. */
|
|
267
|
+
children: React.ReactNode;
|
|
268
|
+
};
|
|
269
|
+
/**
|
|
270
|
+
* 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.
|
|
271
|
+
* It is used to render the prev/next buttons in the carousel for now.
|
|
272
|
+
*/
|
|
273
|
+
declare const CarouselControls: ({ children, className, ...rest }: CarouselControlsProps) => react_jsx_runtime.JSX.Element;
|
|
274
|
+
type CarouselButtonProps = ButtonProps & {
|
|
275
|
+
slot: 'next' | 'prev';
|
|
276
|
+
};
|
|
277
|
+
declare const CarouselButton: ({ className, isIconOnly, color, variant, slot, ...rest }: CarouselButtonProps) => react_jsx_runtime.JSX.Element;
|
|
235
278
|
type CarouselItemProps = HTMLProps<HTMLDivElement> & {
|
|
236
279
|
/** The component/components to display as the <CarouselItem/>. */
|
|
237
|
-
children:
|
|
238
|
-
};
|
|
239
|
-
type CarouselItem = Pick<CarouselItemProps, 'id'> & {
|
|
240
|
-
/** The index of the item that is currently in view */
|
|
241
|
-
index: number;
|
|
242
|
-
/** The index of the previous item that was in view */
|
|
243
|
-
prevIndex: number;
|
|
244
|
-
/** The id of the previous item that was in view */
|
|
245
|
-
prevId?: CarouselItemProps['id'];
|
|
280
|
+
children: React.ReactNode;
|
|
246
281
|
};
|
|
247
282
|
declare const CarouselItem: ({ className, children, ...rest }: CarouselItemProps) => react_jsx_runtime.JSX.Element;
|
|
248
283
|
|
|
@@ -758,5 +793,5 @@ type VideoLoopProps = {
|
|
|
758
793
|
};
|
|
759
794
|
declare const VideoLoop: ({ src, format, alt, className }: VideoLoopProps) => react_jsx_runtime.JSX.Element;
|
|
760
795
|
|
|
761
|
-
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, Disclosure, DisclosureButton, DisclosurePanel, DisclosureStateContext, ErrorMessage, Footer, GrunnmurenProvider, Heading, HeadingContext, Label, LinkList, LinkListContainer, LinkListItem, Media, MediaContext, NumberField, Radio, RadioGroup, Select, ListBoxHeader as SelectHeader, ListBoxItem as SelectItem, ListBoxSection as SelectSection, Tag, TagGroup, TagList, TextArea, TextField, Carousel as UNSAFE_Carousel, CarouselItem as UNSAFE_CarouselItem, CarouselItems as UNSAFE_CarouselItems, Dialog as UNSAFE_Dialog, DialogTrigger as UNSAFE_DialogTrigger, FileUpload as UNSAFE_FileUpload, Hero as UNSAFE_Hero, Link as UNSAFE_Link, Modal as UNSAFE_Modal, ProgressBar as UNSAFE_ProgressBar, ProgressBarValueText as UNSAFE_ProgressBarValueText, Tab as UNSAFE_Tab, TabList as UNSAFE_TabList, TabPanel as UNSAFE_TabPanel, Table as UNSAFE_Table, TableBody as UNSAFE_TableBody, TableCell as UNSAFE_TableCell, TableColumn as UNSAFE_TableColumn, TableColumnResizer as UNSAFE_TableColumnResizer, TableContainer as UNSAFE_TableContainer, TableHeader as UNSAFE_TableHeader, TableRow as UNSAFE_TableRow, Tabs as UNSAFE_Tabs, VideoLoop, _LinkContext, _useLocale as useLocale };
|
|
762
|
-
export type { AccordionItemProps, AccordionProps, Props as AlertboxProps, AvatarProps, BacklinkProps, BadgeProps, BreadcrumbProps, BreadcrumbsProps, ButtonProps, CaptionProps, CardLinkProps, CardProps, CheckboxGroupProps, CheckboxProps, ComboboxProps, ContentProps, DateFormatterProps, DescriptionProps, DisclosureButtonProps, DisclosurePanelProps, DisclosureProps, ErrorMessageProps, FooterProps, GrunnmurenProviderProps, HeadingProps, LinkListContainerProps, LinkListItemProps, LinkListProps, Locale, MediaProps, NumberFieldProps, RadioGroupProps, RadioProps, SelectProps, TagGroupProps, TagListProps, TagProps, TextAreaProps, TextFieldProps, CarouselItemProps as UNSAFE_CarouselItemProps, CarouselItemsProps as UNSAFE_CarouselItemsProps, CarouselProps as UNSAFE_CarouselProps, DialogProps as UNSAFE_DialogProps, DialogTriggerProps as UNSAFE_DialogTriggerProps, FileUploadProps as UNSAFE_FileUploadProps, HeroProps as UNSAFE_HeroProps, LinkProps as UNSAFE_LinkProps, ModalProps as UNSAFE_ModalProps, ProgressBarProps as UNSAFE_ProgressBarProps, ProgressBarValueTextProps as UNSAFE_ProgressBarValueTextProps, TabListProps as UNSAFE_TabListProps, TabPanelProps as UNSAFE_TabPanelProps, TabProps as UNSAFE_TabProps, TableBodyProps as UNSAFE_TableBodyProps, TableCellProps as UNSAFE_TableCellProps, TableColumnProps as UNSAFE_TableColumnProps, TableColumnResizerProps as UNSAFE_TableColumnResizerProps, TableContainerProps as UNSAFE_TableContainerProps, TableHeaderProps as UNSAFE_TableHeaderProps, TableProps as UNSAFE_TableProps, TableRowProps as UNSAFE_TableRowProps, TabsProps as UNSAFE_TabsProps };
|
|
796
|
+
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, Disclosure, DisclosureButton, DisclosurePanel, DisclosureStateContext, ErrorMessage, Footer, GrunnmurenProvider, Heading, HeadingContext, Label, LinkList, LinkListContainer, LinkListItem, Media, MediaContext, NumberField, Radio, RadioGroup, Select, ListBoxHeader as SelectHeader, ListBoxItem as SelectItem, ListBoxSection as SelectSection, Tag, TagGroup, TagList, TextArea, TextField, Carousel as UNSAFE_Carousel, CarouselButton as UNSAFE_CarouselButton, CarouselControls as UNSAFE_CarouselControls, CarouselItem as UNSAFE_CarouselItem, CarouselItems as UNSAFE_CarouselItems, CarouselItemsContainer as UNSAFE_CarouselItemsContainer, CarouselItemsContainer as UNSAFE_CarouselItemsContainerProps, Dialog as UNSAFE_Dialog, DialogTrigger as UNSAFE_DialogTrigger, FileUpload as UNSAFE_FileUpload, Hero as UNSAFE_Hero, Link as UNSAFE_Link, Modal as UNSAFE_Modal, ProgressBar as UNSAFE_ProgressBar, ProgressBarValueText as UNSAFE_ProgressBarValueText, Tab as UNSAFE_Tab, TabList as UNSAFE_TabList, TabPanel as UNSAFE_TabPanel, Table as UNSAFE_Table, TableBody as UNSAFE_TableBody, TableCell as UNSAFE_TableCell, TableColumn as UNSAFE_TableColumn, TableColumnResizer as UNSAFE_TableColumnResizer, TableContainer as UNSAFE_TableContainer, TableHeader as UNSAFE_TableHeader, TableRow as UNSAFE_TableRow, Tabs as UNSAFE_Tabs, VideoLoop, _LinkContext, _useLocale as useLocale };
|
|
797
|
+
export type { AccordionItemProps, AccordionProps, Props as AlertboxProps, AvatarProps, BacklinkProps, BadgeProps, BreadcrumbProps, BreadcrumbsProps, ButtonProps, CaptionProps, CardLinkProps, CardProps, CheckboxGroupProps, CheckboxProps, ComboboxProps, ContentProps, DateFormatterProps, DescriptionProps, DisclosureButtonProps, DisclosurePanelProps, DisclosureProps, ErrorMessageProps, FooterProps, GrunnmurenProviderProps, HeadingProps, LinkListContainerProps, LinkListItemProps, LinkListProps, Locale, MediaProps, NumberFieldProps, RadioGroupProps, RadioProps, SelectProps, TagGroupProps, TagListProps, TagProps, TextAreaProps, TextFieldProps, CarouselButtonProps as UNSAFE_CarouselButtonProps, CarouselControlsProps as UNSAFE_CarouselControlsProps, CarouselItemProps as UNSAFE_CarouselItemProps, CarouselItemsProps as UNSAFE_CarouselItemsProps, CarouselProps as UNSAFE_CarouselProps, DialogProps as UNSAFE_DialogProps, DialogTriggerProps as UNSAFE_DialogTriggerProps, FileUploadProps as UNSAFE_FileUploadProps, HeroProps as UNSAFE_HeroProps, LinkProps as UNSAFE_LinkProps, ModalProps as UNSAFE_ModalProps, ProgressBarProps as UNSAFE_ProgressBarProps, ProgressBarValueTextProps as UNSAFE_ProgressBarValueTextProps, TabListProps as UNSAFE_TabListProps, TabPanelProps as UNSAFE_TabPanelProps, TabProps as UNSAFE_TabProps, TableBodyProps as UNSAFE_TableBodyProps, TableCellProps as UNSAFE_TableCellProps, TableColumnProps as UNSAFE_TableColumnProps, TableColumnResizerProps as UNSAFE_TableColumnResizerProps, TableContainerProps as UNSAFE_TableContainerProps, TableHeaderProps as UNSAFE_TableHeaderProps, TableProps as UNSAFE_TableProps, TableRowProps as UNSAFE_TableRowProps, TabsProps as UNSAFE_TabsProps };
|
package/dist/index.mjs
CHANGED
|
@@ -3,16 +3,19 @@ import { useContextProps, DisclosureContext, DisclosureGroupStateContext, Provid
|
|
|
3
3
|
export { DisclosureGroup, Form, Group } from 'react-aria-components';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
import { cva, cx, compose } from 'cva';
|
|
6
|
-
import { createContext, useContext, useId, useRef, Children, useState, useEffect, isValidElement, cloneElement
|
|
6
|
+
import { createContext, useContext, useId, useRef, Children, useState, useEffect, useMemo, useCallback, isValidElement, cloneElement } from 'react';
|
|
7
7
|
import { ChevronDown, Error, Warning, CheckCircle, InfoCircle, Close, User, ChevronLeft, ChevronRight, LoadingSpinner, Check, Trash, ArrowRight, Download, LinkExternal, PlayerPause, PlayerPlay } from '@obosbbl/grunnmuren-icons-react';
|
|
8
|
-
import { filterDOMProps, mergeProps, mergeRefs,
|
|
8
|
+
import { filterDOMProps, mergeProps, mergeRefs, useObjectRef, useFormReset, useUpdateEffect } from '@react-aria/utils';
|
|
9
9
|
import { useFocusRing, useDisclosure, useProgressBar, useDateFormatter, useField } from 'react-aria';
|
|
10
10
|
import { useDisclosureState } from 'react-stately';
|
|
11
|
-
import
|
|
11
|
+
import Autoplay from 'embla-carousel-autoplay';
|
|
12
|
+
import useEmblaCarousel from 'embla-carousel-react';
|
|
13
|
+
import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures';
|
|
12
14
|
import { useFormValidation } from '@react-aria/form';
|
|
13
15
|
import { useFormValidationState } from '@react-stately/form';
|
|
14
16
|
import { useControlledState } from '@react-stately/utils';
|
|
15
17
|
import { PressResponder } from '@react-aria/interactions';
|
|
18
|
+
import { useDebouncedCallback } from 'use-debounce';
|
|
16
19
|
|
|
17
20
|
const HeadingContext = /*#__PURE__*/ createContext({});
|
|
18
21
|
const headingVariants = cva({
|
|
@@ -354,6 +357,11 @@ const translations$1 = {
|
|
|
354
357
|
sv: 'Nästa',
|
|
355
358
|
en: 'Next'
|
|
356
359
|
},
|
|
360
|
+
carousel: {
|
|
361
|
+
nb: 'Karusell',
|
|
362
|
+
sv: 'Karusell',
|
|
363
|
+
en: 'Carousel'
|
|
364
|
+
},
|
|
357
365
|
externalLink: {
|
|
358
366
|
nb: '(ekstern lenke)',
|
|
359
367
|
sv: '(extern länk)',
|
|
@@ -982,7 +990,9 @@ const cardLinkVariants = cva({
|
|
|
982
990
|
*
|
|
983
991
|
* Keep in mind that this hook relies on a browser API's and doesn't run on the server.
|
|
984
992
|
* You can supply an initial value that will be used for server side rendering.
|
|
985
|
-
|
|
993
|
+
*
|
|
994
|
+
* The default initial value is `false` as this aligns with most users. This is to prevent unecessary rerenders on mount for the common user.
|
|
995
|
+
*/ function usePrefersReducedMotion(initialValue = false) {
|
|
986
996
|
const [prefersReducedMotion, setPrefersReducedMotion] = useState(initialValue);
|
|
987
997
|
useEffect(()=>{
|
|
988
998
|
const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
|
|
@@ -998,188 +1008,137 @@ const cardLinkVariants = cva({
|
|
|
998
1008
|
return prefersReducedMotion;
|
|
999
1009
|
}
|
|
1000
1010
|
|
|
1001
|
-
const Carousel = ({
|
|
1011
|
+
const Carousel = ({ autoPlayDelay, align = 'center', children, initialIndex = 0, orientation = 'horizontal', onSelect, onSettled, loop = false, scrollGestures = false, ref, ...rest })=>{
|
|
1002
1012
|
const carouselRef = useRef(null);
|
|
1003
|
-
const
|
|
1004
|
-
const
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
const scrollTimeoutRef = useRef(null);
|
|
1009
|
-
const scrollQueue = useRef([]);
|
|
1010
|
-
const [hasReachedScrollStart, setHasReachedScrollStart] = useState(scrollTargetIndex === 0);
|
|
1011
|
-
const [hasReachedScrollEnd, setHasReachedScrollEnd] = useState(!carouselItemsRef.current || carouselItemsRef.current.children.length - 1 === scrollTargetIndex);
|
|
1012
|
-
const prefersReducedMotion = usePrefersReducedMotion();
|
|
1013
|
-
useEffect(()=>{
|
|
1014
|
-
setHasReachedScrollStart(scrollTargetIndex === 0);
|
|
1015
|
-
setHasReachedScrollEnd(!carouselItemsRef.current || carouselItemsRef.current.children.length - 1 === scrollTargetIndex);
|
|
1016
|
-
}, [
|
|
1017
|
-
scrollTargetIndex
|
|
1018
|
-
]);
|
|
1019
|
-
// Keep track of the previous index to determine if the user is scrolling forward or backward
|
|
1020
|
-
// This is used to determine which callback to call (onPrev or onNext)
|
|
1021
|
-
const prevIndex = useRef(0);
|
|
1022
|
-
// Processes the next scroll action in the queue, if any
|
|
1023
|
-
// All clicks on the prev/next buttons are queued while a programmatic scroll is in progress
|
|
1024
|
-
// This is to ensure that rapid clicks on the buttons do not cause janky scrolling behavior
|
|
1025
|
-
// while still a snappy response to user clicks
|
|
1026
|
-
const processQueue = ()=>{
|
|
1027
|
-
if (scrollQueue.current.length > 0 && !isScrollingProgrammatically.current) {
|
|
1028
|
-
const nextIndex = scrollQueue.current?.shift();
|
|
1029
|
-
if (nextIndex !== undefined) {
|
|
1030
|
-
setScrollTargetIndex(nextIndex);
|
|
1031
|
-
}
|
|
1013
|
+
const prefersReducedMotion = usePrefersReducedMotion() ?? false;
|
|
1014
|
+
const emblaPlugins = useMemo(()=>{
|
|
1015
|
+
const plugins = [];
|
|
1016
|
+
if (scrollGestures) {
|
|
1017
|
+
plugins.push(WheelGesturesPlugin());
|
|
1032
1018
|
}
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
if (scrollTimeoutRef.current) {
|
|
1040
|
-
clearTimeout(scrollTimeoutRef.current);
|
|
1041
|
-
}
|
|
1042
|
-
isScrollingProgrammatically.current = true;
|
|
1043
|
-
const elementWithFocusVisible = carouselRef.current?.querySelector(':focus-visible');
|
|
1044
|
-
const targetElement = carouselItemsRef.current.children[scrollTargetIndex];
|
|
1045
|
-
if (targetElement) {
|
|
1046
|
-
// Calculate the scroll position to scroll the target element into view
|
|
1047
|
-
const containerRect = carouselItemsRef.current.getBoundingClientRect();
|
|
1048
|
-
const targetRect = targetElement.getBoundingClientRect();
|
|
1049
|
-
const scrollLeft = carouselItemsRef.current.scrollLeft + (targetRect.left - containerRect.left);
|
|
1050
|
-
carouselItemsRef.current.scrollTo({
|
|
1051
|
-
left: Math.round(scrollLeft),
|
|
1052
|
-
behavior: prefersReducedMotion ? 'instant' : 'smooth'
|
|
1053
|
-
});
|
|
1054
|
-
}
|
|
1055
|
-
if (prevIndex.current !== scrollTargetIndex && onChange) {
|
|
1056
|
-
onChange({
|
|
1057
|
-
index: scrollTargetIndex,
|
|
1058
|
-
id: carouselItemsRef.current.children[scrollTargetIndex]?.id,
|
|
1059
|
-
prevIndex: prevIndex.current,
|
|
1060
|
-
prevId: carouselItemsRef.current.children[prevIndex.current]?.id
|
|
1061
|
-
});
|
|
1019
|
+
if (autoPlayDelay) {
|
|
1020
|
+
plugins.push(Autoplay({
|
|
1021
|
+
delay: autoPlayDelay,
|
|
1022
|
+
stopOnLastSnap: !loop,
|
|
1023
|
+
jump: prefersReducedMotion
|
|
1024
|
+
}));
|
|
1062
1025
|
}
|
|
1063
|
-
|
|
1064
|
-
scrollTimeoutRef.current = setTimeout(()=>{
|
|
1065
|
-
isScrollingProgrammatically.current = false;
|
|
1066
|
-
scrollTimeoutRef.current = null;
|
|
1067
|
-
if (elementWithFocusVisible && !carouselRef.current?.contains(document.activeElement)) {
|
|
1068
|
-
// Restore focus to the appropriate element after scrolling
|
|
1069
|
-
// First check if the prev or next buttons just got hidden due to reaching the start/end of the carousel
|
|
1070
|
-
// If so, move focus to the other button. This is to avoid a scroll jank that occurs if instead focus is restored to the carousel container
|
|
1071
|
-
// This jank happens because of the delays used for scrolling with these buttons (debounce, queuing etc.).
|
|
1072
|
-
switch(elementWithFocusVisible.slot){
|
|
1073
|
-
case 'prev':
|
|
1074
|
-
{
|
|
1075
|
-
// Focus was lost when the prev button turned invisible, set it to the next button
|
|
1076
|
-
const nextButton = carouselRef.current?.querySelector('[slot="next"]');
|
|
1077
|
-
nextButton?.focus();
|
|
1078
|
-
break;
|
|
1079
|
-
}
|
|
1080
|
-
case 'next':
|
|
1081
|
-
{
|
|
1082
|
-
// Focus was lost when the next button turned invisible, set it to the prev button
|
|
1083
|
-
const prevButton = carouselRef.current?.querySelector('[slot="prev"]');
|
|
1084
|
-
prevButton?.focus();
|
|
1085
|
-
break;
|
|
1086
|
-
}
|
|
1087
|
-
default:
|
|
1088
|
-
{
|
|
1089
|
-
// Focus was lost during while scrolling with left/right arrows, restore it to the carousel container
|
|
1090
|
-
carouselItemsRef.current?.focus();
|
|
1091
|
-
break;
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
processQueue(); // Process any queued scrolls
|
|
1096
|
-
}, 500);
|
|
1026
|
+
return plugins;
|
|
1097
1027
|
}, [
|
|
1098
|
-
|
|
1028
|
+
autoPlayDelay,
|
|
1029
|
+
scrollGestures,
|
|
1030
|
+
loop,
|
|
1099
1031
|
prefersReducedMotion
|
|
1100
1032
|
]);
|
|
1101
|
-
|
|
1033
|
+
const [emblaRef, emblaApi] = useEmblaCarousel({
|
|
1034
|
+
align,
|
|
1035
|
+
loop,
|
|
1036
|
+
startIndex: initialIndex,
|
|
1037
|
+
axis: orientation === 'horizontal' ? 'x' : 'y',
|
|
1038
|
+
inViewThreshold: 0.2
|
|
1039
|
+
}, emblaPlugins);
|
|
1040
|
+
const [slidesInView, setSlidesInView] = useState([
|
|
1041
|
+
initialIndex
|
|
1042
|
+
]);
|
|
1043
|
+
const previousSettledScrollIndex = useRef(initialIndex);
|
|
1102
1044
|
useEffect(()=>{
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1045
|
+
if (!emblaApi) {
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1048
|
+
const emblaHandler = (_, type)=>{
|
|
1049
|
+
const scrollSnapIndex = emblaApi.selectedScrollSnap();
|
|
1050
|
+
switch(type){
|
|
1051
|
+
case 'select':
|
|
1052
|
+
onSelect?.(scrollSnapIndex);
|
|
1053
|
+
break;
|
|
1054
|
+
case 'settle':
|
|
1055
|
+
{
|
|
1056
|
+
// We only invoke the callback if the scroll index actually changed from the previous settled index
|
|
1057
|
+
// Otherwise this gets triggered if the user does the tiniest bit of scrolling in the carousel, but doesn't transition to the next slide
|
|
1058
|
+
if (scrollSnapIndex !== previousSettledScrollIndex.current) {
|
|
1059
|
+
previousSettledScrollIndex.current = scrollSnapIndex;
|
|
1060
|
+
onSettled?.(scrollSnapIndex);
|
|
1061
|
+
}
|
|
1062
|
+
break;
|
|
1063
|
+
}
|
|
1064
|
+
case 'slidesInView':
|
|
1065
|
+
{
|
|
1066
|
+
setSlidesInView(emblaApi.slidesInView());
|
|
1067
|
+
break;
|
|
1068
|
+
}
|
|
1106
1069
|
}
|
|
1107
1070
|
};
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1071
|
+
emblaApi.on('select', emblaHandler);
|
|
1072
|
+
emblaApi.on('slidesInView', emblaHandler);
|
|
1073
|
+
emblaApi.on('settle', emblaHandler);
|
|
1074
|
+
return ()=>{
|
|
1075
|
+
emblaApi.off('select', emblaHandler);
|
|
1076
|
+
emblaApi.off('settle', emblaHandler);
|
|
1077
|
+
emblaApi.off('slidesInView', emblaHandler);
|
|
1078
|
+
};
|
|
1079
|
+
}, [
|
|
1080
|
+
emblaApi,
|
|
1081
|
+
onSelect,
|
|
1082
|
+
onSettled
|
|
1083
|
+
]);
|
|
1084
|
+
const handleNextPress = useCallback(()=>{
|
|
1085
|
+
if (!emblaApi) {
|
|
1112
1086
|
return;
|
|
1113
1087
|
}
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
//
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
// Check if the item is more than 50% visible within the container
|
|
1120
|
-
const visibleWidth = Math.min(rect.right, containerRect.right) - Math.max(rect.left, containerRect.left);
|
|
1121
|
-
const itemWidth = rect.width;
|
|
1122
|
-
return visibleWidth / itemWidth > 0.5;
|
|
1123
|
-
});
|
|
1124
|
-
if (newScrollTargetIndex !== -1 && newScrollTargetIndex !== scrollTargetIndex) {
|
|
1125
|
-
if (onChange) {
|
|
1126
|
-
onChange({
|
|
1127
|
-
index: newScrollTargetIndex,
|
|
1128
|
-
id: target.children[newScrollTargetIndex]?.id,
|
|
1129
|
-
prevIndex: prevIndex.current,
|
|
1130
|
-
prevId: target.children[prevIndex.current]?.id
|
|
1131
|
-
});
|
|
1132
|
-
}
|
|
1133
|
-
// Update the index and prevIndex
|
|
1134
|
-
setScrollTargetIndex(newScrollTargetIndex);
|
|
1135
|
-
prevIndex.current = newScrollTargetIndex;
|
|
1088
|
+
emblaApi.plugins().autoplay?.stop();
|
|
1089
|
+
emblaApi.scrollNext(prefersReducedMotion);
|
|
1090
|
+
// we need to move focus if we are about to disable this button due to start/end of carousel
|
|
1091
|
+
if (!loop && !emblaApi.canScrollNext() && carouselRef.current?.querySelector('button[slot="next"]')?.matches(':focus-visible')) {
|
|
1092
|
+
carouselRef.current?.querySelector('button[slot="prev"]')?.focus();
|
|
1136
1093
|
}
|
|
1137
|
-
},
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1094
|
+
}, [
|
|
1095
|
+
emblaApi,
|
|
1096
|
+
prefersReducedMotion,
|
|
1097
|
+
loop
|
|
1098
|
+
]);
|
|
1099
|
+
const handlePrevPress = useCallback(()=>{
|
|
1100
|
+
if (!emblaApi) {
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
emblaApi.plugins().autoplay?.stop();
|
|
1104
|
+
emblaApi.scrollPrev(prefersReducedMotion);
|
|
1105
|
+
// we need to move focus if we are about to disable this button due to start/end of carousel
|
|
1106
|
+
if (!loop && !emblaApi.canScrollPrev() && carouselRef.current?.querySelector('button[slot="prev"]')?.matches(':focus-visible')) {
|
|
1107
|
+
carouselRef.current?.querySelector('button[slot="next"]')?.focus();
|
|
1108
|
+
}
|
|
1109
|
+
}, [
|
|
1110
|
+
emblaApi,
|
|
1111
|
+
prefersReducedMotion,
|
|
1112
|
+
loop
|
|
1113
|
+
]);
|
|
1114
|
+
const locale = _useLocale();
|
|
1115
|
+
const handleKeyDown = useCallback((e)=>{
|
|
1116
|
+
if (e.key === 'ArrowRight' && !e.repeat) {
|
|
1117
|
+
handleNextPress();
|
|
1118
|
+
} else if (e.key === 'ArrowLeft' && !e.repeat) {
|
|
1119
|
+
handlePrevPress();
|
|
1120
|
+
}
|
|
1121
|
+
}, [
|
|
1122
|
+
handleNextPress,
|
|
1123
|
+
handlePrevPress
|
|
1124
|
+
]);
|
|
1125
|
+
return(// biome-ignore lint/a11y/useSemanticElements: we want to use a div
|
|
1126
|
+
/*#__PURE__*/ jsx("div", {
|
|
1127
|
+
...rest,
|
|
1128
|
+
"data-orientation": orientation,
|
|
1171
1129
|
"data-slot": "carousel",
|
|
1172
|
-
ref: carouselRef,
|
|
1130
|
+
ref: mergeRefs(ref, carouselRef),
|
|
1131
|
+
onKeyDown: handleKeyDown,
|
|
1132
|
+
role: "region",
|
|
1133
|
+
"aria-label": translations$1.carousel[locale],
|
|
1173
1134
|
children: /*#__PURE__*/ jsx(Provider, {
|
|
1174
1135
|
values: [
|
|
1175
1136
|
[
|
|
1176
|
-
|
|
1137
|
+
CarouselContext,
|
|
1177
1138
|
{
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
handlePrevious,
|
|
1182
|
-
handleNext
|
|
1139
|
+
slidesInView,
|
|
1140
|
+
'~emblaRef': emblaRef,
|
|
1141
|
+
orientation
|
|
1183
1142
|
}
|
|
1184
1143
|
],
|
|
1185
1144
|
[
|
|
@@ -1188,115 +1147,123 @@ const Carousel = ({ className, children, onChange, ...rest })=>{
|
|
|
1188
1147
|
slots: {
|
|
1189
1148
|
[DEFAULT_SLOT]: {},
|
|
1190
1149
|
prev: {
|
|
1191
|
-
'aria-label': previous[locale],
|
|
1192
|
-
|
|
1150
|
+
'aria-label': translations$1.previous[locale],
|
|
1151
|
+
isDisabled: !emblaApi?.canScrollPrev(),
|
|
1152
|
+
onPress: handlePrevPress
|
|
1193
1153
|
},
|
|
1194
1154
|
next: {
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
onPress:
|
|
1155
|
+
'aria-label': translations$1.next[locale],
|
|
1156
|
+
isDisabled: !emblaApi?.canScrollNext(),
|
|
1157
|
+
onPress: handleNextPress
|
|
1198
1158
|
}
|
|
1199
1159
|
}
|
|
1200
1160
|
}
|
|
1201
1161
|
]
|
|
1202
1162
|
],
|
|
1203
|
-
children:
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
})
|
|
1234
|
-
]
|
|
1235
|
-
})
|
|
1163
|
+
children: children
|
|
1164
|
+
})
|
|
1165
|
+
}));
|
|
1166
|
+
};
|
|
1167
|
+
const CarouselContext = /*#__PURE__*/ createContext({
|
|
1168
|
+
'~emblaRef': null,
|
|
1169
|
+
orientation: 'horizontal',
|
|
1170
|
+
slidesInView: []
|
|
1171
|
+
});
|
|
1172
|
+
const CarouselItemsContainer = ({ children, className, ...rest })=>{
|
|
1173
|
+
const { '~emblaRef': emblaRef } = useContext(CarouselContext);
|
|
1174
|
+
return /*#__PURE__*/ jsx("div", {
|
|
1175
|
+
className: cx(className, 'overflow-hidden'),
|
|
1176
|
+
ref: emblaRef,
|
|
1177
|
+
"data-slot": "carousel-items-container",
|
|
1178
|
+
...rest,
|
|
1179
|
+
children: children
|
|
1180
|
+
});
|
|
1181
|
+
};
|
|
1182
|
+
const CarouselItems = ({ className, children })=>{
|
|
1183
|
+
const { slidesInView, orientation } = useContext(CarouselContext);
|
|
1184
|
+
return /*#__PURE__*/ jsx("div", {
|
|
1185
|
+
className: cx(className, 'flex', orientation === 'vertical' && 'flex-col'),
|
|
1186
|
+
"data-slot": "carousel-items",
|
|
1187
|
+
children: Children.map(children, (child, index)=>{
|
|
1188
|
+
if (/*#__PURE__*/ isValidElement(child)) {
|
|
1189
|
+
return /*#__PURE__*/ cloneElement(child, {
|
|
1190
|
+
inert: slidesInView.includes(index) ? undefined : true
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1236
1193
|
})
|
|
1237
1194
|
});
|
|
1238
1195
|
};
|
|
1239
1196
|
/**
|
|
1240
1197
|
* 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.
|
|
1241
1198
|
* It is used to render the prev/next buttons in the carousel for now.
|
|
1242
|
-
*/ const
|
|
1243
|
-
className: cx(className, '
|
|
1244
|
-
'items-end *:h-fit'),
|
|
1199
|
+
*/ const CarouselControls = ({ children, className, ...rest })=>/*#__PURE__*/ jsx("div", {
|
|
1200
|
+
className: cx(className, 'flex justify-end gap-x-2'),
|
|
1245
1201
|
"data-slot": "carousel-controls",
|
|
1202
|
+
...rest,
|
|
1246
1203
|
children: children
|
|
1247
1204
|
});
|
|
1248
|
-
const
|
|
1249
|
-
|
|
1250
|
-
activeIndex: 0
|
|
1205
|
+
const carouselButtonVariants = cva({
|
|
1206
|
+
base: 'group data-disabled:invisible'
|
|
1251
1207
|
});
|
|
1252
|
-
const
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1208
|
+
const carouselButtonIconSlotVariants = cva({
|
|
1209
|
+
base: 'transition-transform',
|
|
1210
|
+
variants: {
|
|
1211
|
+
slot: {
|
|
1212
|
+
next: null,
|
|
1213
|
+
prev: null
|
|
1214
|
+
},
|
|
1215
|
+
orientation: {
|
|
1216
|
+
horizontal: null,
|
|
1217
|
+
vertical: null
|
|
1261
1218
|
}
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1219
|
+
},
|
|
1220
|
+
compoundVariants: [
|
|
1221
|
+
// horizontal controls
|
|
1222
|
+
{
|
|
1223
|
+
slot: 'next',
|
|
1224
|
+
orientation: 'horizontal',
|
|
1225
|
+
className: 'group-hover:motion-safe:translate-x-1'
|
|
1226
|
+
},
|
|
1227
|
+
{
|
|
1228
|
+
slot: 'prev',
|
|
1229
|
+
orientation: 'horizontal',
|
|
1230
|
+
className: 'group-hover:motion-safe:-translate-x-1 rotate-180'
|
|
1231
|
+
},
|
|
1232
|
+
// vertical controls
|
|
1233
|
+
{
|
|
1234
|
+
slot: 'next',
|
|
1235
|
+
orientation: 'vertical',
|
|
1236
|
+
className: 'rotate-90 group-hover:motion-safe:translate-y-1'
|
|
1237
|
+
},
|
|
1238
|
+
{
|
|
1239
|
+
slot: 'prev',
|
|
1240
|
+
orientation: 'vertical',
|
|
1241
|
+
className: 'group-hover:motion-safe:-translate-y-1 -rotate-90'
|
|
1271
1242
|
}
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
return /*#__PURE__*/ cloneElement(child, {
|
|
1291
|
-
inert: activeIndex === index ? undefined : true
|
|
1292
|
-
});
|
|
1293
|
-
}
|
|
1243
|
+
]
|
|
1244
|
+
});
|
|
1245
|
+
const CarouselButton = ({ className, isIconOnly = true, color = 'white', variant = 'primary', slot, ...rest })=>{
|
|
1246
|
+
const { orientation } = useContext(CarouselContext);
|
|
1247
|
+
return /*#__PURE__*/ jsx(Button, {
|
|
1248
|
+
className: carouselButtonVariants({
|
|
1249
|
+
className
|
|
1250
|
+
}),
|
|
1251
|
+
isIconOnly: isIconOnly,
|
|
1252
|
+
slot: slot,
|
|
1253
|
+
variant: variant,
|
|
1254
|
+
color: color,
|
|
1255
|
+
...rest,
|
|
1256
|
+
children: /*#__PURE__*/ jsx(ChevronRight, {
|
|
1257
|
+
className: carouselButtonIconSlotVariants({
|
|
1258
|
+
orientation,
|
|
1259
|
+
slot
|
|
1260
|
+
})
|
|
1294
1261
|
})
|
|
1295
|
-
})
|
|
1262
|
+
});
|
|
1296
1263
|
};
|
|
1297
1264
|
const CarouselItem = ({ className, children, ...rest })=>{
|
|
1298
1265
|
return /*#__PURE__*/ jsx("div", {
|
|
1299
|
-
className: cx(className, '
|
|
1266
|
+
className: cx(className, 'min-w-0 shrink-0 grow-0'),
|
|
1300
1267
|
"data-slot": "carousel-item",
|
|
1301
1268
|
...rest,
|
|
1302
1269
|
children: /*#__PURE__*/ jsx(Provider, {
|
|
@@ -1612,7 +1579,7 @@ function Combobox(props) {
|
|
|
1612
1579
|
/**
|
|
1613
1580
|
* A FileTrigger allows a user to access the file system with any pressable React Aria or React Spectrum component, or custom components built with usePress.
|
|
1614
1581
|
*/ const FileTrigger = (props)=>{
|
|
1615
|
-
const { onSelect, acceptedFileTypes, allowsMultiple, defaultCamera, children, acceptDirectory, ref, isInvalid, isRequired, name,
|
|
1582
|
+
const { onSelect, acceptedFileTypes, allowsMultiple, defaultCamera, children, acceptDirectory, ref, isInvalid, isRequired, name, ...rest } = props;
|
|
1616
1583
|
const inputRef = useObjectRef(ref);
|
|
1617
1584
|
return /*#__PURE__*/ jsxs(Fragment, {
|
|
1618
1585
|
children: [
|
|
@@ -1661,6 +1628,46 @@ const translations = {
|
|
|
1661
1628
|
en: 'Remove'
|
|
1662
1629
|
}
|
|
1663
1630
|
};
|
|
1631
|
+
/**
|
|
1632
|
+
* Extracts a simple file extension from a file name or converts MIME type to extension
|
|
1633
|
+
* @param file The file object
|
|
1634
|
+
* @returns A simple file extension (e.g., "pdf", "jpg", "svg")
|
|
1635
|
+
*/ function getFileExtension(file) {
|
|
1636
|
+
const match = file.name.match(/\.([^.]+)$/);
|
|
1637
|
+
if (match) {
|
|
1638
|
+
return match[1].toUpperCase();
|
|
1639
|
+
}
|
|
1640
|
+
const mimeType = file.type;
|
|
1641
|
+
if (!mimeType) {
|
|
1642
|
+
return '';
|
|
1643
|
+
}
|
|
1644
|
+
const parts = mimeType.split('/');
|
|
1645
|
+
if (parts.length === 2) {
|
|
1646
|
+
const subtype = parts[1].split('+')[0]; // Handle cases like "svg+xml"
|
|
1647
|
+
return subtype.toUpperCase();
|
|
1648
|
+
}
|
|
1649
|
+
return '';
|
|
1650
|
+
}
|
|
1651
|
+
/**
|
|
1652
|
+
* Formats a file size in bytes to a human-readable string (B, KB, MB, GB, etc.)
|
|
1653
|
+
* @param bytes The file size in bytes
|
|
1654
|
+
* @returns A formatted string with the appropriate unit
|
|
1655
|
+
*/ function formatFileSize(bytes) {
|
|
1656
|
+
if (bytes === 0) {
|
|
1657
|
+
return '0 B';
|
|
1658
|
+
}
|
|
1659
|
+
const units = [
|
|
1660
|
+
'B',
|
|
1661
|
+
'KB',
|
|
1662
|
+
'MB',
|
|
1663
|
+
'GB',
|
|
1664
|
+
'TB'
|
|
1665
|
+
];
|
|
1666
|
+
const base = 1024;
|
|
1667
|
+
const unitIndex = Math.floor(Math.log(bytes) / Math.log(base));
|
|
1668
|
+
const size = bytes / base ** unitIndex;
|
|
1669
|
+
return `${size.toFixed(2).replace(/\.?0+$/, '')} ${units[unitIndex]}`;
|
|
1670
|
+
}
|
|
1664
1671
|
/**
|
|
1665
1672
|
* Converts an array of files to a DataTransfer object which can be used as a FileList.
|
|
1666
1673
|
* This is necessary for setting the files on a native file input.
|
|
@@ -1688,7 +1695,7 @@ const translations = {
|
|
|
1688
1695
|
const extension = fileName.match(/(\.[^.]+)$/)?.[0] || '';
|
|
1689
1696
|
if (!fileNameCounts[baseName]) {
|
|
1690
1697
|
// Extract any number from the file name (if any, otherwise default to 0)
|
|
1691
|
-
const baseNameCount = Number.parseInt(fileName.match(/\((\d+)\)/)?.[1] ?? '0');
|
|
1698
|
+
const baseNameCount = Number.parseInt(fileName.match(/\((\d+)\)/)?.[1] ?? '0', 10);
|
|
1692
1699
|
fileNameCounts[baseName] = baseNameCount;
|
|
1693
1700
|
}
|
|
1694
1701
|
fileNameCounts[baseName]++;
|
|
@@ -1837,11 +1844,34 @@ const FileUpload = ({ children, files: _files, onChange, validate, isInvalid: _i
|
|
|
1837
1844
|
return /*#__PURE__*/ jsxs("li", {
|
|
1838
1845
|
children: [
|
|
1839
1846
|
/*#__PURE__*/ jsxs("div", {
|
|
1840
|
-
className: cx('flex items-center justify-between gap-
|
|
1847
|
+
className: cx('flex items-center justify-between gap-3 rounded-lg border p-1.5', hasError ? 'border-red bg-red-light' : 'border-gray'),
|
|
1841
1848
|
children: [
|
|
1842
|
-
|
|
1849
|
+
/*#__PURE__*/ jsxs("div", {
|
|
1850
|
+
className: "flex items-center gap-3",
|
|
1851
|
+
children: [
|
|
1852
|
+
/*#__PURE__*/ jsx("div", {
|
|
1853
|
+
className: "footnote rounded-md border border-gray-light bg-gray-lightest px-2.5 py-2",
|
|
1854
|
+
children: getFileExtension(file)
|
|
1855
|
+
}),
|
|
1856
|
+
/*#__PURE__*/ jsxs("div", {
|
|
1857
|
+
className: "flex flex-col",
|
|
1858
|
+
children: [
|
|
1859
|
+
/*#__PURE__*/ jsx("span", {
|
|
1860
|
+
className: "description truncate font-medium",
|
|
1861
|
+
children: fileName
|
|
1862
|
+
}),
|
|
1863
|
+
/*#__PURE__*/ jsx("span", {
|
|
1864
|
+
className: "footnote text-gray-dark",
|
|
1865
|
+
children: formatFileSize(file.size)
|
|
1866
|
+
})
|
|
1867
|
+
]
|
|
1868
|
+
})
|
|
1869
|
+
]
|
|
1870
|
+
}),
|
|
1843
1871
|
/*#__PURE__*/ jsx("button", {
|
|
1844
|
-
|
|
1872
|
+
type: "button",
|
|
1873
|
+
"aria-label": translations.remove[locale],
|
|
1874
|
+
className: cx('-m-2 grid h-11 w-11 shrink-0 cursor-pointer place-items-center rounded-xl', // Focus styles
|
|
1845
1875
|
'focus-visible:-outline-offset-8 focus-visible:outline-focus'),
|
|
1846
1876
|
onClick: ()=>{
|
|
1847
1877
|
// For controlled component
|
|
@@ -1852,8 +1882,6 @@ const FileUpload = ({ children, files: _files, onChange, validate, isInvalid: _i
|
|
|
1852
1882
|
// (without this, the focus will be set to the top of the page for screen readers)
|
|
1853
1883
|
buttonRef.current?.focus();
|
|
1854
1884
|
},
|
|
1855
|
-
"aria-label": translations.remove[locale],
|
|
1856
|
-
type: "button",
|
|
1857
1885
|
children: /*#__PURE__*/ jsx(Trash, {})
|
|
1858
1886
|
})
|
|
1859
1887
|
]
|
|
@@ -1885,7 +1913,6 @@ function GrunnmurenProvider({ children, locale = 'nb', navigate, useHref }) {
|
|
|
1885
1913
|
});
|
|
1886
1914
|
}
|
|
1887
1915
|
|
|
1888
|
-
const roundedMediaCorners = '*:data-[slot="media"]:*:rounded-3xl';
|
|
1889
1916
|
// Common variant for "standard" and "full-bleed" Hero variants
|
|
1890
1917
|
const oneColumnLayout = [
|
|
1891
1918
|
// Vertical spacing in the <Content>
|
|
@@ -1898,7 +1925,7 @@ const oneColumnLayout = [
|
|
|
1898
1925
|
'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',
|
|
1899
1926
|
// <Media> and <Carousel> content takes up the full width on medium screens and above
|
|
1900
1927
|
'lg:*:data-[slot="media"]:col-span-full *:data-[slot="media"]:*:w-full',
|
|
1901
|
-
'lg:*:data-[slot="carousel"]:col-span-full
|
|
1928
|
+
'lg:*:data-[slot="carousel"]:col-span-full',
|
|
1902
1929
|
// Aligns <Content> and any element beside it (e.g. <Media>, <Badge>, <CTA> etc.) to the bottom of the <Content> container
|
|
1903
1930
|
'lg:items-end'
|
|
1904
1931
|
];
|
|
@@ -1914,7 +1941,10 @@ const variants = cva({
|
|
|
1914
1941
|
// Vertical spacing in the <Content>
|
|
1915
1942
|
'*:data-[slot="content"]:gap-y-3',
|
|
1916
1943
|
// Make sure <Media> content fills any available vertical and horizontal space
|
|
1917
|
-
'*:data-[slot="media"]:*:object-cover'
|
|
1944
|
+
'*:data-[slot="media"]:*:object-cover',
|
|
1945
|
+
'*:data-[slot="carousel"]:overflow-hidden *:data-[slot="carousel"]:rounded-3xl',
|
|
1946
|
+
// Make the carousel items full width, so we scroll one at a time
|
|
1947
|
+
'**:data-[slot="carousel-item"]:basis-full'
|
|
1918
1948
|
],
|
|
1919
1949
|
variants: {
|
|
1920
1950
|
/**
|
|
@@ -1922,7 +1952,6 @@ const variants = cva({
|
|
|
1922
1952
|
* @default standard
|
|
1923
1953
|
* */ variant: {
|
|
1924
1954
|
standard: [
|
|
1925
|
-
roundedMediaCorners,
|
|
1926
1955
|
oneColumnLayout,
|
|
1927
1956
|
nonFullBleedAspectRatiosForSmallScreens,
|
|
1928
1957
|
'lg:*:data-[slot="media"]:*:aspect-2/1'
|
|
@@ -1932,32 +1961,44 @@ const variants = cva({
|
|
|
1932
1961
|
// Position the media and carousel content to fill the entire viewport width
|
|
1933
1962
|
'*:data-[slot="media"]:*:absolute *:data-[slot="media"]:*:left-0',
|
|
1934
1963
|
// Special case for Carousel, where the Media is nested inside a CarouselItem
|
|
1935
|
-
'*:data-[slot="carousel"]:**:data-[slot="media"]:w-full
|
|
1964
|
+
'*:data-[slot="carousel"]:**:data-[slot="media"]:w-full',
|
|
1936
1965
|
// Match the heights of the <Media> or <Carousel> wrapper for the Media content (e.g. image, VideoLoop, video etc.)
|
|
1937
1966
|
// This is necessary due to the absolute positioning of the media and carousel containers in this variant
|
|
1938
1967
|
// biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
|
|
1939
1968
|
'**:data-[slot="media"]:h-80 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]',
|
|
1940
|
-
|
|
1941
|
-
'**:data-[slot="media"]:*:h-80 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]',
|
|
1969
|
+
'**:data-[slot="media"]:*:h-[inherit]',
|
|
1942
1970
|
// biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
|
|
1943
1971
|
'*:data-[slot="carousel"]:h-80 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]',
|
|
1972
|
+
'*:data-[slot="carousel"]:w-full!',
|
|
1944
1973
|
// Override aspect ratio of the media and carousel-item slots (since we can not use aspect for full-bleed layout)
|
|
1945
1974
|
'**:data-[slot="carousel-item"]:data-[slot="media"]:*:aspect-none',
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1975
|
+
// break out the carousel out of the container
|
|
1976
|
+
'**:data-[slot="carousel-items-container"]:absolute **:data-[slot="carousel-items-container"]:right-0 **:data-[slot="carousel-items-container"]:left-0 **:data-[slot="carousel-items-container"]:h-[inherit]',
|
|
1977
|
+
// Positions the carousel controls inside the carousel
|
|
1978
|
+
'**:data-[slot="carousel-controls"]:z-10 **:data-[slot="carousel-controls"]:mb-4 *:data-[slot="carousel"]:flex *:data-[slot="carousel"]:items-end *:data-[slot="carousel"]:justify-end'
|
|
1949
1979
|
],
|
|
1950
1980
|
'two-column': [
|
|
1951
1981
|
'lg:items-center lg:*:col-span-6',
|
|
1952
1982
|
// Vertical spacing in the <Content>
|
|
1953
1983
|
'lg:*:data-[slot="content"]:gap-y-7',
|
|
1954
|
-
roundedMediaCorners,
|
|
1955
1984
|
nonFullBleedAspectRatiosForSmallScreens,
|
|
1956
1985
|
// Set media aspect ratio to 1:1 (square)
|
|
1957
|
-
'lg:*:data-[slot="media"]:*:aspect-
|
|
1986
|
+
'lg:*:data-[slot="media"]:*:aspect-square'
|
|
1958
1987
|
]
|
|
1959
1988
|
}
|
|
1960
1989
|
},
|
|
1990
|
+
compoundVariants: [
|
|
1991
|
+
{
|
|
1992
|
+
variant: [
|
|
1993
|
+
'standard',
|
|
1994
|
+
'two-column'
|
|
1995
|
+
],
|
|
1996
|
+
className: [
|
|
1997
|
+
'*:data-[slot="media"]:*:rounded-3xl',
|
|
1998
|
+
'**:data-[slot="carousel-controls"]:absolute *:data-[slot="carousel"]:relative **:data-[slot="carousel-controls"]:right-4 **:data-[slot="carousel-controls"]:bottom-4 **:data-[slot="carousel-container"]:rounded-3xl'
|
|
1999
|
+
]
|
|
2000
|
+
}
|
|
2001
|
+
],
|
|
1961
2002
|
defaultVariants: {
|
|
1962
2003
|
variant: 'standard'
|
|
1963
2004
|
}
|
|
@@ -2110,30 +2151,28 @@ const Modal = ({ isDismissable = true, isOpen, onOpenChange, defaultOpen, classN
|
|
|
2110
2151
|
};
|
|
2111
2152
|
const Dialog = ({ className, children, ...restProps })=>/*#__PURE__*/ jsx(Dialog$1, {
|
|
2112
2153
|
...restProps,
|
|
2113
|
-
className: cx('relative grid gap-y-5 outline-none', // Footer
|
|
2154
|
+
className: cx(className, 'relative grid gap-y-5 outline-none', // Footer
|
|
2114
2155
|
'[&_[data-slot="footer"]]:flex [&_[data-slot="footer"]]:gap-x-2'),
|
|
2115
|
-
children: ({ close })=>/*#__PURE__*/ jsx(
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
className: 'w-fit'
|
|
2130
|
-
}
|
|
2156
|
+
children: ({ close })=>/*#__PURE__*/ jsx(Provider, {
|
|
2157
|
+
values: [
|
|
2158
|
+
[
|
|
2159
|
+
ButtonContext$1,
|
|
2160
|
+
{
|
|
2161
|
+
// This is necessary to support multiple close buttons
|
|
2162
|
+
slots: {
|
|
2163
|
+
// We need to define default slot in order to also support non-slotted buttons (i.e. buttons without slot prop)
|
|
2164
|
+
[DEFAULT_SLOT]: {
|
|
2165
|
+
className: 'w-fit'
|
|
2166
|
+
},
|
|
2167
|
+
close: {
|
|
2168
|
+
onPress: close,
|
|
2169
|
+
className: 'w-fit'
|
|
2131
2170
|
}
|
|
2132
2171
|
}
|
|
2133
|
-
|
|
2134
|
-
]
|
|
2135
|
-
|
|
2136
|
-
|
|
2172
|
+
}
|
|
2173
|
+
]
|
|
2174
|
+
],
|
|
2175
|
+
children: children
|
|
2137
2176
|
})
|
|
2138
2177
|
});
|
|
2139
2178
|
|
|
@@ -2701,7 +2740,7 @@ const tabsVariants = cva({
|
|
|
2701
2740
|
const { className, children, ...restProps } = props;
|
|
2702
2741
|
return /*#__PURE__*/ jsx(Tab$1, {
|
|
2703
2742
|
...restProps,
|
|
2704
|
-
className: cx(className, 'data-focus-visible:-outline-offset-10 data-focus-visible:outline-2 data-focus-visible:outline-black', 'cursor-pointer border-transparent px-4 py-2 font-light
|
|
2743
|
+
className: cx(className, 'data-focus-visible:-outline-offset-10 data-focus-visible:outline-2 data-focus-visible:outline-black', 'description cursor-pointer border-transparent px-4 py-2 font-light', // Transition
|
|
2705
2744
|
'transition-colors duration-150 ease-out', // TODO: Should disabled tabs just be hidden?
|
|
2706
2745
|
'data-disabled:cursor-not-allowed data-disabled:opacity-50', // Selection
|
|
2707
2746
|
'data-selected:font-medium data-selected:text-blue-dark', // Hover with layout shift prevention using pseudo-element
|
|
@@ -2962,4 +3001,4 @@ const VideoLoop = ({ src, format, alt, className })=>{
|
|
|
2962
3001
|
});
|
|
2963
3002
|
};
|
|
2964
3003
|
|
|
2965
|
-
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, Disclosure, DisclosureButton, DisclosurePanel, DisclosureStateContext, ErrorMessage, Footer, GrunnmurenProvider, Heading, HeadingContext, Label, LinkList, LinkListContainer, LinkListItem, Media, MediaContext, NumberField, Radio, RadioGroup, Select, ListBoxHeader as SelectHeader, ListBoxItem as SelectItem, ListBoxSection as SelectSection, Tag, TagGroup, TagList, TextArea, TextField, Carousel as UNSAFE_Carousel, CarouselItem as UNSAFE_CarouselItem, CarouselItems as UNSAFE_CarouselItems, Dialog as UNSAFE_Dialog, DialogTrigger as UNSAFE_DialogTrigger, FileUpload as UNSAFE_FileUpload, Hero as UNSAFE_Hero, Link as UNSAFE_Link, Modal as UNSAFE_Modal, ProgressBar as UNSAFE_ProgressBar, ProgressBarValueText as UNSAFE_ProgressBarValueText, Tab as UNSAFE_Tab, TabList as UNSAFE_TabList, TabPanel as UNSAFE_TabPanel, Table as UNSAFE_Table, TableBody as UNSAFE_TableBody, TableCell as UNSAFE_TableCell, TableColumn as UNSAFE_TableColumn, TableColumnResizer as UNSAFE_TableColumnResizer, TableContainer as UNSAFE_TableContainer, TableHeader as UNSAFE_TableHeader, TableRow as UNSAFE_TableRow, Tabs as UNSAFE_Tabs, VideoLoop, _LinkContext, _useLocale as useLocale };
|
|
3004
|
+
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, Disclosure, DisclosureButton, DisclosurePanel, DisclosureStateContext, ErrorMessage, Footer, GrunnmurenProvider, Heading, HeadingContext, Label, LinkList, LinkListContainer, LinkListItem, Media, MediaContext, NumberField, Radio, RadioGroup, Select, ListBoxHeader as SelectHeader, ListBoxItem as SelectItem, ListBoxSection as SelectSection, Tag, TagGroup, TagList, TextArea, TextField, Carousel as UNSAFE_Carousel, CarouselButton as UNSAFE_CarouselButton, CarouselControls as UNSAFE_CarouselControls, CarouselItem as UNSAFE_CarouselItem, CarouselItems as UNSAFE_CarouselItems, CarouselItemsContainer as UNSAFE_CarouselItemsContainer, Dialog as UNSAFE_Dialog, DialogTrigger as UNSAFE_DialogTrigger, FileUpload as UNSAFE_FileUpload, Hero as UNSAFE_Hero, Link as UNSAFE_Link, Modal as UNSAFE_Modal, ProgressBar as UNSAFE_ProgressBar, ProgressBarValueText as UNSAFE_ProgressBarValueText, Tab as UNSAFE_Tab, TabList as UNSAFE_TabList, TabPanel as UNSAFE_TabPanel, Table as UNSAFE_Table, TableBody as UNSAFE_TableBody, TableCell as UNSAFE_TableCell, TableColumn as UNSAFE_TableColumn, TableColumnResizer as UNSAFE_TableColumnResizer, TableContainer as UNSAFE_TableContainer, TableHeader as UNSAFE_TableHeader, TableRow as UNSAFE_TableRow, Tabs as UNSAFE_Tabs, VideoLoop, _LinkContext, _useLocale as useLocale };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@obosbbl/grunnmuren-react",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.5",
|
|
4
4
|
"description": "Grunnmuren components in React",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "https://github.com/code-obos/grunnmuren"
|
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
"@react-stately/form": "^3.1.5",
|
|
26
26
|
"@react-stately/utils": "^3.10.7",
|
|
27
27
|
"cva": "^1.0.0-0",
|
|
28
|
+
"embla-carousel-autoplay": "^8.6.0",
|
|
29
|
+
"embla-carousel-react": "^8.6.0",
|
|
30
|
+
"embla-carousel-wheel-gestures": "^8.1.0",
|
|
28
31
|
"react-aria": "^3.41.1",
|
|
29
32
|
"react-aria-components": "^1.10.1",
|
|
30
33
|
"react-stately": "^3.39.0",
|
|
@@ -35,7 +38,7 @@
|
|
|
35
38
|
},
|
|
36
39
|
"devDependencies": {
|
|
37
40
|
"@types/node": "^24.0.0",
|
|
38
|
-
"tailwindcss": "4.1.
|
|
41
|
+
"tailwindcss": "4.1.18"
|
|
39
42
|
},
|
|
40
43
|
"scripts": {
|
|
41
44
|
"build": "bunchee"
|