@obosbbl/grunnmuren-react 3.4.5 → 3.4.6

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.
@@ -109,21 +109,11 @@ const cardVariants = cva.cva({
109
109
  // by setting a higher z-index than the pseudo-element (which implicitly z-index 0)
110
110
  '[&_a:not([data-slot="card-link"])]:z-[1] [&_button]:z-[1] [&_input]:z-[1]',
111
111
  // **** Badge ****
112
- '[&_[data-slot="media"]_[data-slot="badge"]]:absolute [&_[data-slot="media"]_[data-slot="badge"]]:top-0',
112
+ '*:data-[slot=media]:*:data-[slot=badge]:absolute',
113
+ '*:data-[slot=media]:*:data-[slot=badge]:first:top-3.5 *:data-[slot=media]:*:data-[slot=badge]:first:left-3.5',
113
114
  // Increasing z-index Preserves badge position when media content is hovered (the transform scale effect might otherwise move the badge behind the other media content)
114
- '[&_[data-slot="media"]_[data-slot="badge"]]:z-[1]',
115
- // Left aligned - override default corner radius of the badge
116
- '[&_[data-slot="media"]_[data-slot="badge"]:first-child]:rounded-tl-2xl',
117
- '[&_[data-slot="media"]_[data-slot="badge"]:first-child]:rounded-br-2xl',
118
- '[&_[data-slot="media"]_[data-slot="badge"]:first-child]:rounded-tr-none',
119
- '[&_[data-slot="media"]_[data-slot="badge"]:first-child]:rounded-bl-none',
120
- // Right aligned - override default corner radius of the badge
121
- '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:rounded-tl-none',
122
- '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:rounded-br-none',
123
- '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:rounded-tr-2xl',
124
- '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:rounded-bl-2xl',
125
- // ... and position the badge at the right edge of the media content
126
- '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:right-0'
115
+ '*:data-[slot=media]:*:data-[slot=badge]:z-[1]',
116
+ '*:data-[slot=media]:*:data-[slot=badge]:last:top-3.5 *:data-[slot=media]:*:data-[slot=badge]:last:right-3.5'
127
117
  ],
128
118
  variants: {
129
119
  /**
@@ -107,21 +107,11 @@ const cardVariants = cva({
107
107
  // by setting a higher z-index than the pseudo-element (which implicitly z-index 0)
108
108
  '[&_a:not([data-slot="card-link"])]:z-[1] [&_button]:z-[1] [&_input]:z-[1]',
109
109
  // **** Badge ****
110
- '[&_[data-slot="media"]_[data-slot="badge"]]:absolute [&_[data-slot="media"]_[data-slot="badge"]]:top-0',
110
+ '*:data-[slot=media]:*:data-[slot=badge]:absolute',
111
+ '*:data-[slot=media]:*:data-[slot=badge]:first:top-3.5 *:data-[slot=media]:*:data-[slot=badge]:first:left-3.5',
111
112
  // Increasing z-index Preserves badge position when media content is hovered (the transform scale effect might otherwise move the badge behind the other media content)
112
- '[&_[data-slot="media"]_[data-slot="badge"]]:z-[1]',
113
- // Left aligned - override default corner radius of the badge
114
- '[&_[data-slot="media"]_[data-slot="badge"]:first-child]:rounded-tl-2xl',
115
- '[&_[data-slot="media"]_[data-slot="badge"]:first-child]:rounded-br-2xl',
116
- '[&_[data-slot="media"]_[data-slot="badge"]:first-child]:rounded-tr-none',
117
- '[&_[data-slot="media"]_[data-slot="badge"]:first-child]:rounded-bl-none',
118
- // Right aligned - override default corner radius of the badge
119
- '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:rounded-tl-none',
120
- '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:rounded-br-none',
121
- '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:rounded-tr-2xl',
122
- '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:rounded-bl-2xl',
123
- // ... and position the badge at the right edge of the media content
124
- '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:right-0'
113
+ '*:data-[slot=media]:*:data-[slot=badge]:z-[1]',
114
+ '*:data-[slot=media]:*:data-[slot=badge]:last:top-3.5 *:data-[slot=media]:*:data-[slot=badge]:last:right-3.5'
125
115
  ],
126
116
  variants: {
127
117
  /**
package/dist/index.d.mts CHANGED
@@ -275,8 +275,18 @@ type CardLinkProps = (Omit<LinkProps$1, 'href'> & Required<Pick<LinkProps$1, 'hr
275
275
  */
276
276
  declare const CardLink: ({ className: _className, href, ...restProps }: CardLinkProps) => react_jsx_runtime.JSX.Element;
277
277
 
278
- type CarouselProps = Omit<HTMLProps<HTMLDivElement>, 'onChange' | 'onSelect'> & {
278
+ type CarouselMethods = {
279
+ /** Navigate to a specific slide by index. */
280
+ goToSlide: (index: number) => void;
281
+ /** Navigate to the next slide. */
282
+ goToNextSlide: () => void;
283
+ /** Navigate to the previous slide. */
284
+ goToPrevSlide: () => void;
285
+ };
286
+ type CarouselElement = HTMLDivElement & CarouselMethods;
287
+ type CarouselProps = Omit<HTMLProps<HTMLDivElement>, 'onChange' | 'onSelect' | 'ref'> & {
279
288
  children?: React.ReactNode;
289
+ ref?: React.Ref<CarouselElement>;
280
290
  /**
281
291
  * Alignment of the items relative to the carousel viewport.
282
292
  * @default 'center'
@@ -317,6 +327,7 @@ declare const Carousel: ({ autoPlayDelay, align, children, initialIndex, orienta
317
327
  type CarouselContextValue = {
318
328
  slidesInView: number[];
319
329
  orientation: 'horizontal' | 'vertical';
330
+ '~shouldUseAriaCarouselPattern': boolean;
320
331
  /**
321
332
  * @private
322
333
  */
@@ -331,7 +342,7 @@ type CarouselItemsProps = HTMLProps<HTMLDivElement> & {
331
342
  /** The <CarouselItem/> components to be displayed within the carousel. */
332
343
  children: React.ReactNode;
333
344
  };
334
- declare const CarouselItems: ({ className, children }: CarouselItemsProps) => react_jsx_runtime.JSX.Element;
345
+ declare const CarouselItems: ({ className, children, ...restProps }: CarouselItemsProps) => react_jsx_runtime.JSX.Element;
335
346
  type CarouselControlsProps = HTMLProps<HTMLDivElement> & {
336
347
  /** The <CarouselItem/> components to be displayed within the carousel. */
337
348
  children: React.ReactNode;
@@ -430,7 +441,7 @@ type HeadingProps = Omit<HTMLProps<HTMLHeadingElement>, 'size'> & VariantProps<t
430
441
  };
431
442
  declare const HeadingContext: react.Context<ContextValue<Partial<HeadingProps>, HTMLHeadingElement>>;
432
443
  declare const headingVariants: (props?: ({
433
- size?: "s" | "xl" | "l" | "m" | "xs" | undefined;
444
+ size?: "xl" | "l" | "m" | "s" | "xs" | undefined;
434
445
  } & ({
435
446
  class?: cva.ClassValue;
436
447
  className?: never;
@@ -582,9 +593,11 @@ type ModalOverlayProps = Omit<ModalOverlayProps$1, 'isDismissable' | 'style'> &
582
593
  zIndex?: number;
583
594
  /** @default true Makes the modal dismissable */
584
595
  isDismissable?: boolean;
596
+ /** @default false When true, the modal takes up the full screen */
597
+ fullscreen?: boolean;
585
598
  };
586
599
  type ModalProps = ModalOverlayProps;
587
- declare const Modal: ({ isDismissable, isOpen, onOpenChange, defaultOpen, className, zIndex, ...restProps }: ModalProps) => react_jsx_runtime.JSX.Element;
600
+ declare const Modal: ({ isDismissable, isOpen, onOpenChange, defaultOpen, className, zIndex, fullscreen, ...restProps }: ModalProps) => react_jsx_runtime.JSX.Element;
588
601
  type DialogProps = DialogProps$1 & {
589
602
  children: React.ReactNode;
590
603
  };
@@ -898,4 +911,4 @@ type VideoLoopProps = {
898
911
  declare const VideoLoop: ({ src, format, alt, className }: VideoLoopProps) => react_jsx_runtime.JSX.Element;
899
912
 
900
913
  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, CarouselContext as UNSAFE_CarouselContext, 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, HeroContext as UNSAFE_HeroContext, Link as UNSAFE_Link, Modal as UNSAFE_Modal, Step as UNSAFE_Step, Stepper as UNSAFE_Stepper, 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, _useLocale as useLocale };
901
- 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, CarouselContextValue as UNSAFE_CarouselContextValue, 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, HeroContextValue as UNSAFE_HeroContextValue, HeroProps as UNSAFE_HeroProps, LinkProps as UNSAFE_LinkProps, ModalProps as UNSAFE_ModalProps, StepProps as UNSAFE_StepProps, StepperProps as UNSAFE_StepperProps, 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 };
914
+ 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, CarouselContextValue as UNSAFE_CarouselContextValue, CarouselControlsProps as UNSAFE_CarouselControlsProps, CarouselItemProps as UNSAFE_CarouselItemProps, CarouselItemsProps as UNSAFE_CarouselItemsProps, CarouselProps as UNSAFE_CarouselProps, CarouselElement as UNSAFE_CarouselRef, DialogProps as UNSAFE_DialogProps, DialogTriggerProps as UNSAFE_DialogTriggerProps, FileUploadProps as UNSAFE_FileUploadProps, HeroContextValue as UNSAFE_HeroContextValue, HeroProps as UNSAFE_HeroProps, LinkProps as UNSAFE_LinkProps, ModalProps as UNSAFE_ModalProps, StepProps as UNSAFE_StepProps, StepperProps as UNSAFE_StepperProps, 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,7 +3,7 @@ import { RouterProvider } from 'react-aria-components';
3
3
  export { 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, useMemo, useCallback, isValidElement, cloneElement, use } from 'react';
6
+ import { createContext, useContext, useId, useRef, Children, useState, useEffect, useMemo, useCallback, useImperativeHandle, isValidElement, cloneElement, use } from 'react';
7
7
  import { useContextProps, Provider, DEFAULT_SLOT, useSlottedContext } from 'react-aria-components/slots';
8
8
  import { ChevronDown, Error, Warning, CheckCircle, InfoCircle, Close, User, ChevronLeft, ChevronRight, LoadingSpinner, Check, Trash, Download, LinkExternal, ArrowRight, Edit, PlayerPause, PlayerPlay } from '@obosbbl/grunnmuren-icons-react';
9
9
  import { ButtonContext as ButtonContext$1, Button as Button$1 } from 'react-aria-components/Button';
@@ -23,6 +23,8 @@ import Autoplay from 'embla-carousel-autoplay';
23
23
  import useEmblaCarousel from 'embla-carousel-react';
24
24
  import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures';
25
25
  import { GroupContext, Group } from 'react-aria-components/Group';
26
+ import { Dialog as Dialog$1, DialogTrigger as DialogTrigger$1, OverlayTriggerStateContext } from 'react-aria-components/Dialog';
27
+ import { Modal as Modal$1, ModalOverlay } from 'react-aria-components/Modal';
26
28
  import { CheckboxContext, Checkbox as Checkbox$1 } from 'react-aria-components/Checkbox';
27
29
  import { Text } from 'react-aria-components/Text';
28
30
  import { CheckboxGroup as CheckboxGroup$1 } from 'react-aria-components/CheckboxGroup';
@@ -43,8 +45,6 @@ import { useFormValidationState } from 'react-stately/private/form/useFormValida
43
45
  import { useControlledState } from 'react-stately/useControlledState';
44
46
  import { PressResponder } from 'react-aria/private/interactions/PressResponder';
45
47
  import { useObjectRef } from 'react-aria/useObjectRef';
46
- import { Dialog as Dialog$1, DialogTrigger as DialogTrigger$1 } from 'react-aria-components/Dialog';
47
- import { Modal as Modal$1, ModalOverlay } from 'react-aria-components/Modal';
48
48
  import { NumberField as NumberField$1 } from 'react-aria-components/NumberField';
49
49
  import { Radio as Radio$1, RadioGroup as RadioGroup$1 } from 'react-aria-components/RadioGroup';
50
50
  import { Select as Select$1, SelectValue } from 'react-aria-components/Select';
@@ -638,9 +638,9 @@ const badgeVariants = cva({
638
638
  variants: {
639
639
  color: {
640
640
  'gray-dark': 'bg-gray-dark text-white',
641
- mint: 'bg-mint',
642
- sky: 'bg-sky',
643
- white: 'bg-white',
641
+ mint: 'bg-mint text-black',
642
+ sky: 'bg-sky text-black',
643
+ white: 'bg-white text-black',
644
644
  'blue-dark': 'bg-blue-dark text-white',
645
645
  'green-dark': 'bg-green-dark text-white'
646
646
  },
@@ -891,21 +891,11 @@ const cardVariants = cva({
891
891
  // by setting a higher z-index than the pseudo-element (which implicitly z-index 0)
892
892
  '[&_a:not([data-slot="card-link"])]:z-[1] [&_button]:z-[1] [&_input]:z-[1]',
893
893
  // **** Badge ****
894
- '[&_[data-slot="media"]_[data-slot="badge"]]:absolute [&_[data-slot="media"]_[data-slot="badge"]]:top-0',
894
+ '*:data-[slot=media]:*:data-[slot=badge]:absolute',
895
+ '*:data-[slot=media]:*:data-[slot=badge]:first:top-3.5 *:data-[slot=media]:*:data-[slot=badge]:first:left-3.5',
895
896
  // Increasing z-index Preserves badge position when media content is hovered (the transform scale effect might otherwise move the badge behind the other media content)
896
- '[&_[data-slot="media"]_[data-slot="badge"]]:z-[1]',
897
- // Left aligned - override default corner radius of the badge
898
- '[&_[data-slot="media"]_[data-slot="badge"]:first-child]:rounded-tl-2xl',
899
- '[&_[data-slot="media"]_[data-slot="badge"]:first-child]:rounded-br-2xl',
900
- '[&_[data-slot="media"]_[data-slot="badge"]:first-child]:rounded-tr-none',
901
- '[&_[data-slot="media"]_[data-slot="badge"]:first-child]:rounded-bl-none',
902
- // Right aligned - override default corner radius of the badge
903
- '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:rounded-tl-none',
904
- '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:rounded-br-none',
905
- '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:rounded-tr-2xl',
906
- '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:rounded-bl-2xl',
907
- // ... and position the badge at the right edge of the media content
908
- '[&_[data-slot="media"]_[data-slot="badge"]:last-child]:right-0'
897
+ '*:data-[slot=media]:*:data-[slot=badge]:z-[1]',
898
+ '*:data-[slot=media]:*:data-[slot=badge]:last:top-3.5 *:data-[slot=media]:*:data-[slot=badge]:last:right-3.5'
909
899
  ],
910
900
  variants: {
911
901
  /**
@@ -1213,6 +1203,106 @@ const Hero = ({ variant, className, children, ...rest })=>{
1213
1203
  });
1214
1204
  };
1215
1205
 
1206
+ const DialogTrigger = (props)=>/*#__PURE__*/ jsx(DialogTrigger$1, {
1207
+ ...props
1208
+ });
1209
+ const _ModalOverlay = ({ style = {}, zIndex = 10, fullscreen, ...restProps })=>/*#__PURE__*/ jsx(ModalOverlay, {
1210
+ ...restProps,
1211
+ className: ({ isEntering, isExiting })=>cx('fixed inset-0 flex min-h-full items-center justify-center overflow-y-auto bg-black/25 text-center backdrop-blur-sm', !fullscreen && 'p-4', isEntering && 'fade-in animate-in duration-300 ease-out', isExiting && 'fade-out animate-out duration-200 ease-in', // Using the motion-safe class does not work, so we use motion-reduce to overwrite instead
1212
+ 'motion-reduce:animate-none'),
1213
+ style: {
1214
+ zIndex,
1215
+ ...style
1216
+ }
1217
+ });
1218
+ const Modal = ({ isDismissable = true, isOpen, onOpenChange, defaultOpen, className, zIndex, fullscreen = false, ...restProps })=>{
1219
+ const locale = _useLocale();
1220
+ return /*#__PURE__*/ jsx(Provider, {
1221
+ values: [
1222
+ [
1223
+ HeadingContext,
1224
+ {
1225
+ slots: {
1226
+ [DEFAULT_SLOT]: {},
1227
+ title: {
1228
+ className: 'heading-s',
1229
+ _outerWrapper: (children)=>/*#__PURE__*/ jsxs("div", {
1230
+ className: "flex items-center justify-between gap-x-2",
1231
+ children: [
1232
+ children,
1233
+ isDismissable && /*#__PURE__*/ jsx(Button, {
1234
+ slot: "close",
1235
+ variant: "tertiary",
1236
+ className: "data-focus-visible:outline-focus-inset px-2.5!",
1237
+ "aria-label": translations$1.close[locale],
1238
+ onPress: ()=>onOpenChange?.(false),
1239
+ children: /*#__PURE__*/ jsx(Close, {})
1240
+ })
1241
+ ]
1242
+ })
1243
+ }
1244
+ }
1245
+ }
1246
+ ]
1247
+ ],
1248
+ children: /*#__PURE__*/ jsx(_ModalOverlay, {
1249
+ isOpen: isOpen,
1250
+ onOpenChange: onOpenChange,
1251
+ defaultOpen: defaultOpen,
1252
+ isDismissable: isDismissable,
1253
+ zIndex: zIndex,
1254
+ fullscreen: fullscreen,
1255
+ children: /*#__PURE__*/ jsx(Modal$1, {
1256
+ ...restProps,
1257
+ className: ({ isEntering, isExiting })=>cx(className, 'overflow-auto bg-white text-left shadow-xl', fullscreen ? 'fixed inset-0' : 'w-full max-w-md rounded-2xl p-4 align-middle', isEntering && 'zoom-in-95 animate-in duration-300 ease-out', isExiting && 'zoom-out-95 animate-out duration-200 ease-in', // Using the motion-safe class does not work, so we use motion-reduce to overwrite instead
1258
+ 'motion-reduce:animate-none')
1259
+ })
1260
+ })
1261
+ });
1262
+ };
1263
+ const Dialog = ({ className, children, ...restProps })=>/*#__PURE__*/ jsx(Dialog$1, {
1264
+ ...restProps,
1265
+ className: cx(className, 'relative flex flex-col gap-y-5 outline-none', // Footer
1266
+ '**:data-[slot="footer"]:flex **:data-[slot="footer"]:gap-x-2'),
1267
+ children: ({ close })=>/*#__PURE__*/ jsx(Provider, {
1268
+ values: [
1269
+ [
1270
+ ButtonContext$1,
1271
+ {
1272
+ // This is necessary to support multiple close buttons
1273
+ slots: {
1274
+ // We need to define default slot in order to also support non-slotted buttons (i.e. buttons without slot prop)
1275
+ [DEFAULT_SLOT]: {
1276
+ className: 'w-fit'
1277
+ },
1278
+ close: {
1279
+ onPress: close,
1280
+ className: 'w-fit'
1281
+ }
1282
+ }
1283
+ }
1284
+ ]
1285
+ ],
1286
+ children: children
1287
+ })
1288
+ });
1289
+ /**
1290
+ * Reset the ButtonContext from react-aria-components that Dialog provides
1291
+ * (only allows "close" slot) so nested components can set up their own
1292
+ * button slots (e.g. Carousel's "prev" / "next").
1293
+ */ const _ModalButtonContextReset = ({ children })=>{
1294
+ const isInsideOverlay = !!useContext(OverlayTriggerStateContext);
1295
+ return isInsideOverlay ? /*#__PURE__*/ jsx(Provider, {
1296
+ values: [
1297
+ [
1298
+ ButtonContext$1,
1299
+ null
1300
+ ]
1301
+ ],
1302
+ children: children
1303
+ }) : children;
1304
+ };
1305
+
1216
1306
  /**
1217
1307
  * Hook that detects the user's preference for reduced motion.
1218
1308
  *
@@ -1284,13 +1374,18 @@ const Carousel = ({ autoPlayDelay, align = 'center', children, initialIndex = 0,
1284
1374
  loop,
1285
1375
  prefersReducedMotion
1286
1376
  ]);
1287
- const [emblaRef, emblaApi] = useEmblaCarousel({
1377
+ const emblaOptions = useMemo(()=>({
1378
+ align,
1379
+ loop,
1380
+ startIndex: initialIndex,
1381
+ axis: orientation === 'horizontal' ? 'x' : 'y'
1382
+ }), [
1288
1383
  align,
1289
1384
  loop,
1290
- startIndex: initialIndex,
1291
- axis: orientation === 'horizontal' ? 'x' : 'y',
1292
- inViewThreshold: 0.2
1293
- }, emblaPlugins);
1385
+ initialIndex,
1386
+ orientation
1387
+ ]);
1388
+ const [emblaRef, emblaApi] = useEmblaCarousel(emblaOptions, emblaPlugins);
1294
1389
  const [slidesInView, setSlidesInView] = useState([
1295
1390
  initialIndex
1296
1391
  ]);
@@ -1308,6 +1403,7 @@ const Carousel = ({ autoPlayDelay, align = 'center', children, initialIndex = 0,
1308
1403
  switch(type){
1309
1404
  case 'select':
1310
1405
  onSelect?.(scrollSnapIndex);
1406
+ setSlidesInView(emblaApi.slidesInView());
1311
1407
  setCanScrollNext(emblaApi.canScrollNext());
1312
1408
  setCanScrollPrev(emblaApi.canScrollPrev());
1313
1409
  break;
@@ -1328,6 +1424,7 @@ const Carousel = ({ autoPlayDelay, align = 'center', children, initialIndex = 0,
1328
1424
  }
1329
1425
  case 'init':
1330
1426
  {
1427
+ setSlidesInView(emblaApi.slidesInView());
1331
1428
  setCanScrollNext(emblaApi.canScrollNext());
1332
1429
  setCanScrollPrev(emblaApi.canScrollPrev());
1333
1430
  break;
@@ -1401,6 +1498,19 @@ const Carousel = ({ autoPlayDelay, align = 'center', children, initialIndex = 0,
1401
1498
  handlePrevPress,
1402
1499
  emblaApi
1403
1500
  ]);
1501
+ useImperativeHandle(ref, ()=>{
1502
+ const el = carouselRef.current;
1503
+ if (!el) {
1504
+ return el; // Just to satisfy the return type, this case should never actually happen
1505
+ }
1506
+ el.goToSlide = (index)=>emblaApi?.scrollTo(index, prefersReducedMotion);
1507
+ el.goToNextSlide = ()=>emblaApi?.scrollNext(prefersReducedMotion);
1508
+ el.goToPrevSlide = ()=>emblaApi?.scrollPrev(prefersReducedMotion);
1509
+ return el;
1510
+ }, [
1511
+ emblaApi,
1512
+ prefersReducedMotion
1513
+ ]);
1404
1514
  const hasHeroContext = !!useContext(HeroContext);
1405
1515
  const nextPrevStyles = hasHeroContext ? {
1406
1516
  color: 'white',
@@ -1408,82 +1518,107 @@ const Carousel = ({ autoPlayDelay, align = 'center', children, initialIndex = 0,
1408
1518
  } : {
1409
1519
  variant: 'tertiary'
1410
1520
  };
1521
+ const shouldUseAriaCarouselPattern = !autoPlayDelay;
1411
1522
  return(// oxlint-disable-next-line jsx-a11y/no-static-element-interactions
1412
1523
  /*#__PURE__*/ jsx("div", {
1413
1524
  ...rest,
1525
+ role: shouldUseAriaCarouselPattern ? 'region' : undefined,
1526
+ "aria-roledescription": shouldUseAriaCarouselPattern ? 'carousel' : undefined,
1414
1527
  "data-orientation": orientation,
1415
1528
  "data-slot": "carousel",
1416
- ref: mergeRefs(ref, carouselRef),
1529
+ ref: carouselRef,
1417
1530
  onKeyDown: handleKeyDown,
1418
- children: /*#__PURE__*/ jsx(Provider, {
1419
- values: [
1420
- [
1421
- CarouselContext,
1422
- {
1423
- slidesInView,
1424
- '~emblaRef': emblaRef,
1425
- orientation
1426
- }
1427
- ],
1428
- [
1429
- ButtonContext,
1430
- {
1431
- slots: {
1432
- [DEFAULT_SLOT]: {},
1433
- prev: {
1434
- 'aria-label': translations$1.previous[locale],
1435
- isDisabled: !canScrollPrev,
1436
- onPress: handlePrevPress,
1437
- ...nextPrevStyles
1438
- },
1439
- next: {
1440
- 'aria-label': translations$1.next[locale],
1441
- isDisabled: !canScrollNext,
1442
- onPress: handleNextPress,
1443
- ...nextPrevStyles
1531
+ children: /*#__PURE__*/ jsx(_ModalButtonContextReset, {
1532
+ children: /*#__PURE__*/ jsx(Provider, {
1533
+ values: [
1534
+ [
1535
+ CarouselContext,
1536
+ {
1537
+ slidesInView,
1538
+ '~emblaRef': emblaRef,
1539
+ orientation,
1540
+ '~shouldUseAriaCarouselPattern': shouldUseAriaCarouselPattern
1541
+ }
1542
+ ],
1543
+ [
1544
+ ButtonContext,
1545
+ {
1546
+ slots: {
1547
+ [DEFAULT_SLOT]: {},
1548
+ prev: {
1549
+ 'aria-label': translations$1.previous[locale],
1550
+ isDisabled: !canScrollPrev,
1551
+ onPress: handlePrevPress,
1552
+ ...nextPrevStyles
1553
+ },
1554
+ next: {
1555
+ 'aria-label': translations$1.next[locale],
1556
+ isDisabled: !canScrollNext,
1557
+ onPress: handleNextPress,
1558
+ ...nextPrevStyles
1559
+ }
1444
1560
  }
1445
1561
  }
1446
- }
1447
- ]
1448
- ],
1449
- children: children
1562
+ ]
1563
+ ],
1564
+ children: children
1565
+ })
1450
1566
  })
1451
1567
  }));
1452
1568
  };
1569
+ const CarouselItemIndexContext = /*#__PURE__*/ createContext(0);
1453
1570
  const CarouselContext = /*#__PURE__*/ createContext({
1454
1571
  '~emblaRef': null,
1455
1572
  orientation: 'horizontal',
1456
- slidesInView: []
1573
+ slidesInView: [],
1574
+ '~shouldUseAriaCarouselPattern': true
1457
1575
  });
1458
1576
  const CarouselItemsContainer = ({ children, className, ...rest })=>{
1459
- const { '~emblaRef': emblaRef } = useContext(CarouselContext);
1577
+ const { '~emblaRef': emblaRef, '~shouldUseAriaCarouselPattern': shouldUseAriaCarouselPattern } = useContext(CarouselContext);
1460
1578
  return /*#__PURE__*/ jsx("div", {
1461
1579
  className: cx(className, 'overflow-hidden'),
1462
1580
  ref: emblaRef,
1463
1581
  "data-slot": "carousel-items-container",
1464
1582
  ...rest,
1583
+ "aria-live": shouldUseAriaCarouselPattern ? 'polite' : undefined,
1584
+ "aria-atomic": shouldUseAriaCarouselPattern ? false : undefined,
1465
1585
  children: children
1466
1586
  });
1467
1587
  };
1468
- const CarouselItems = ({ className, children })=>{
1588
+ const CarouselItems = ({ className, children, ...restProps })=>{
1469
1589
  const { orientation } = useContext(CarouselContext);
1590
+ let itemIndex = 0;
1470
1591
  return /*#__PURE__*/ jsx("div", {
1471
1592
  className: cx(className, 'flex', orientation === 'vertical' && 'flex-col'),
1472
1593
  "data-slot": "carousel-items",
1473
- children: children
1594
+ ...restProps,
1595
+ children: Children.map(children, (child)=>{
1596
+ if (/*#__PURE__*/ isValidElement(child)) {
1597
+ const currentIndex = itemIndex++;
1598
+ return /*#__PURE__*/ jsx(CarouselItemIndexContext.Provider, {
1599
+ value: currentIndex,
1600
+ children: child
1601
+ });
1602
+ }
1603
+ return child;
1604
+ })
1474
1605
  });
1475
1606
  };
1476
1607
  /**
1477
1608
  * 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.
1478
1609
  * It is used to render the prev/next buttons in the carousel for now.
1479
- */ const CarouselControls = ({ children, className, ...rest })=>/*#__PURE__*/ jsx("div", {
1610
+ */ const CarouselControls = ({ children, className, ...rest })=>{
1611
+ const { '~shouldUseAriaCarouselPattern': shouldUseAriaCarouselPattern } = useContext(CarouselContext);
1612
+ return /*#__PURE__*/ jsx("div", {
1480
1613
  className: cx(className, 'flex justify-end gap-x-2'),
1481
1614
  "data-slot": "carousel-controls",
1482
1615
  ...rest,
1483
- // All items of the carousel are accessible to the screen reader at all times, so these controls will only confuse screen reader users
1484
- "aria-hidden": "true",
1616
+ // When not using the aria carousel pattern, all items are accessible to the screen reader at all times,
1617
+ // so these controls will only confuse screen reader users
1618
+ "aria-hidden": !shouldUseAriaCarouselPattern,
1485
1619
  children: children
1486
1620
  });
1621
+ };
1487
1622
  const carouselButtonVariants = cva({
1488
1623
  base: 'group data-disabled:invisible'
1489
1624
  });
@@ -1542,10 +1677,15 @@ const CarouselButton = ({ className, isIconOnly = true, slot, ...rest })=>{
1542
1677
  });
1543
1678
  };
1544
1679
  const CarouselItem = ({ className, children, ...rest })=>{
1680
+ const itemIndex = useContext(CarouselItemIndexContext);
1681
+ const { slidesInView, '~shouldUseAriaCarouselPattern': shouldUseAriaCarouselPattern } = useContext(CarouselContext);
1545
1682
  return /*#__PURE__*/ jsx("div", {
1546
1683
  ...rest,
1684
+ inert: shouldUseAriaCarouselPattern && !slidesInView.includes(itemIndex) ? true : undefined,
1547
1685
  className: cx(className, 'min-w-0 shrink-0 grow-0', '*:data-[slot=media]:aspect-square', '*:data-[slot=media]:max-sm:data-[fit="contain"]:*:object-cover', '*:data-[slot=media]:sm:aspect-4/3', '*:data-[slot=media]:md:aspect-3/2', '*:data-[slot=media]:lg:aspect-2/1', '*:data-[slot=media]:*:h-full', '*:data-[slot=media]:*:w-full', '*:data-[slot=media]:data-[fit="contain"]:bg-blue-dark'),
1548
1686
  "data-slot": "carousel-item",
1687
+ role: shouldUseAriaCarouselPattern ? 'group' : undefined,
1688
+ "aria-roledescription": shouldUseAriaCarouselPattern ? 'slide' : undefined,
1549
1689
  children: /*#__PURE__*/ jsx(Provider, {
1550
1690
  values: [
1551
1691
  [
@@ -2222,89 +2362,6 @@ const LinkListItem = ({ children, className, ...props })=>{
2222
2362
  });
2223
2363
  };
2224
2364
 
2225
- const DialogTrigger = (props)=>/*#__PURE__*/ jsx(DialogTrigger$1, {
2226
- ...props
2227
- });
2228
- const _ModalOverlay = ({ style = {}, zIndex = 10, ...restProps })=>/*#__PURE__*/ jsx(ModalOverlay, {
2229
- ...restProps,
2230
- className: ({ isEntering, isExiting })=>cx('fixed inset-0 flex min-h-full items-center justify-center overflow-y-auto bg-black/25 p-4 text-center backdrop-blur-sm', isEntering && 'fade-in animate-in duration-300 ease-out', isExiting && 'fade-out animate-out duration-200 ease-in', // Using the motion-safe class does not work, so we use motion-reduce to overwrite instead
2231
- 'motion-reduce:animate-none'),
2232
- style: {
2233
- zIndex,
2234
- ...style
2235
- }
2236
- });
2237
- const Modal = ({ isDismissable = true, isOpen, onOpenChange, defaultOpen, className, zIndex, ...restProps })=>{
2238
- const locale = _useLocale();
2239
- return /*#__PURE__*/ jsx(Provider, {
2240
- values: [
2241
- [
2242
- HeadingContext,
2243
- {
2244
- slots: {
2245
- [DEFAULT_SLOT]: {},
2246
- title: {
2247
- className: 'heading-s',
2248
- _outerWrapper: (children)=>/*#__PURE__*/ jsxs("div", {
2249
- className: "flex items-center justify-between gap-x-2",
2250
- children: [
2251
- children,
2252
- isDismissable && /*#__PURE__*/ jsx(Button, {
2253
- slot: "close",
2254
- variant: "tertiary",
2255
- className: "data-focus-visible:outline-focus-inset px-2.5!",
2256
- "aria-label": translations$1.close[locale],
2257
- onPress: ()=>onOpenChange?.(false),
2258
- children: /*#__PURE__*/ jsx(Close, {})
2259
- })
2260
- ]
2261
- })
2262
- }
2263
- }
2264
- }
2265
- ]
2266
- ],
2267
- children: /*#__PURE__*/ jsx(_ModalOverlay, {
2268
- isOpen: isOpen,
2269
- onOpenChange: onOpenChange,
2270
- defaultOpen: defaultOpen,
2271
- isDismissable: isDismissable,
2272
- zIndex: zIndex,
2273
- children: /*#__PURE__*/ jsx(Modal$1, {
2274
- ...restProps,
2275
- className: ({ isEntering, isExiting })=>cx(className, 'w-full max-w-md overflow-hidden rounded-2xl bg-white p-4 text-left align-middle shadow-xl', isEntering && 'zoom-in-95 animate-in duration-300 ease-out', isExiting && 'zoom-out-95 animate-out duration-200 ease-in', // Using the motion-safe class does not work, so we use motion-reduce to overwrite instead
2276
- 'motion-reduce:animate-none')
2277
- })
2278
- })
2279
- });
2280
- };
2281
- const Dialog = ({ className, children, ...restProps })=>/*#__PURE__*/ jsx(Dialog$1, {
2282
- ...restProps,
2283
- className: cx(className, 'relative grid gap-y-5 outline-none', // Footer
2284
- '**:data-[slot="footer"]:flex **:data-[slot="footer"]:gap-x-2'),
2285
- children: ({ close })=>/*#__PURE__*/ jsx(Provider, {
2286
- values: [
2287
- [
2288
- ButtonContext$1,
2289
- {
2290
- // This is necessary to support multiple close buttons
2291
- slots: {
2292
- // We need to define default slot in order to also support non-slotted buttons (i.e. buttons without slot prop)
2293
- [DEFAULT_SLOT]: {
2294
- className: 'w-fit'
2295
- },
2296
- close: {
2297
- onPress: close,
2298
- className: 'w-fit'
2299
- }
2300
- }
2301
- }
2302
- ]
2303
- ],
2304
- children: children
2305
- })
2306
- });
2307
-
2308
2365
  // This component is based on a copy of ../textfield/TextField, refactoring is TBD: https://github.com/code-obos/grunnmuren/pull/722#issuecomment-1931478786
2309
2366
  const inputVariants$1 = compose(input, cva({
2310
2367
  base: '',
@@ -2386,7 +2443,7 @@ const defaultClasses = cx([
2386
2443
  'data-focus-visible:before:ring-focus-offset',
2387
2444
  // invalid - The border is 1 px thicker when invalid. We don't actually want to change the border width, as that causes the element's size to change
2388
2445
  // so we use an inner outline to artifically pad the border
2389
- 'data-invalid:data-selected:before:bg-red! data-invalid:before:border-red data-invalid:before:outline-red data-invalid:before:outline data-invalid:before:outline-[3px] data-invalid:before:outline-offset-[-3px] data-invalid:before:outline-solid'
2446
+ 'data-invalid:data-selected:before:bg-red! data-invalid:before:border-red data-invalid:before:outline-red data-invalid:before:outline-3 data-invalid:before:outline-offset-[-3px] data-invalid:before:outline-solid'
2390
2447
  ]);
2391
2448
  function Radio(props) {
2392
2449
  const { children, className, description, ...restProps } = props;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obosbbl/grunnmuren-react",
3
- "version": "3.4.5",
3
+ "version": "3.4.6",
4
4
  "description": "Grunnmuren components in React",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -18,7 +18,6 @@
18
18
  }
19
19
  },
20
20
  "dependencies": {
21
- "@obosbbl/grunnmuren-icons-react": "^2.1.2",
22
21
  "cva": "^1.0.0-0",
23
22
  "embla-carousel-autoplay": "^8.6.0",
24
23
  "embla-carousel-react": "^8.6.0",
@@ -26,11 +25,12 @@
26
25
  "react-aria": "^3.48.0",
27
26
  "react-aria-components": "^1.17.0",
28
27
  "react-stately": "^3.46.0",
29
- "use-debounce": "^10.0.4"
28
+ "use-debounce": "^10.0.4",
29
+ "@obosbbl/grunnmuren-icons-react": "^2.2.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/node": "^24.0.0",
33
- "tailwindcss": "4.2.1"
33
+ "tailwindcss": "4.2.2"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "react": "^19"