@obosbbl/grunnmuren-react 3.2.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -350,6 +350,11 @@ const translations$1 = {
350
350
  nb: 'Neste',
351
351
  sv: 'Nästa',
352
352
  en: 'Next'
353
+ },
354
+ externalLink: {
355
+ nb: '(ekstern lenke)',
356
+ sv: '(extern länk)',
357
+ en: '(external link)'
353
358
  }
354
359
  };
355
360
 
@@ -477,12 +482,29 @@ const Avatar = ({ src, alt = '', className, onError, loading = 'lazy', ...rest }
477
482
  });
478
483
  };
479
484
 
480
- /**
481
- * A basic link component that extends react-aria-components Link with consistent styling.
482
- * Provides accessible focus styles and maintains design system consistency.
483
- */ const Link = ({ children, className, ...restProps })=>{
485
+ const _LinkContext = /*#__PURE__*/ createContext({});
486
+ const Link = ({ ref: _ref, ..._props })=>{
487
+ const [props, ref] = useContextProps(_props, _ref, _LinkContext);
488
+ const { className, _innerWrapper, children: _children, ...restProps } = props;
489
+ const locale = _useLocale();
490
+ const externalLinkSR = props.rel?.includes('external') ? /*#__PURE__*/ jsx("span", {
491
+ className: "sr-only",
492
+ children: translations$1.externalLink[locale]
493
+ }) : null;
494
+ const reactNodeChildren = /*#__PURE__*/ jsxs(Fragment, {
495
+ children: [
496
+ _children,
497
+ externalLinkSR
498
+ ]
499
+ });
500
+ const children = _innerWrapper ? _innerWrapper({
501
+ ...restProps,
502
+ children: typeof _children === 'function' ? (values)=>_children(values) : reactNodeChildren
503
+ }) : reactNodeChildren;
484
504
  return /*#__PURE__*/ jsx(Link$1, {
485
505
  ...restProps,
506
+ ref: ref,
507
+ "data-slot": "link",
486
508
  className: cx(className, 'inline-flex cursor-pointer items-center gap-1 font-medium hover:no-underline focus-visible:outline-current focus-visible:outline-focus-offset [&>svg]:shrink-0 [&>svg]:transition-transform'),
487
509
  children: children
488
510
  });
@@ -992,8 +1014,9 @@ const Carousel = ({ className, children, onChange, ...rest })=>{
992
1014
  }
993
1015
  isScrollingProgrammatically.current = true;
994
1016
  const elementWithFocusVisible = carouselRef.current?.querySelector(':focus-visible');
1017
+ const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
995
1018
  carouselItemsRef.current.children[scrollTargetIndex]?.scrollIntoView({
996
- behavior: 'smooth',
1019
+ behavior: prefersReducedMotion ? 'instant' : 'smooth',
997
1020
  inline: 'start',
998
1021
  block: 'nearest'
999
1022
  });
@@ -1121,7 +1144,9 @@ const Carousel = ({ className, children, onChange, ...rest })=>{
1121
1144
  {
1122
1145
  carouselItemsRef,
1123
1146
  onScroll,
1124
- activeIndex: scrollTargetIndex
1147
+ activeIndex: scrollTargetIndex,
1148
+ handlePrevious,
1149
+ handleNext
1125
1150
  }
1126
1151
  ],
1127
1152
  [
@@ -1192,14 +1217,35 @@ const CarouselItemsContext = /*#__PURE__*/ createContext({
1192
1217
  activeIndex: 0
1193
1218
  });
1194
1219
  const CarouselItems = ({ className, children })=>{
1220
+ const { carouselItemsRef, onScroll, activeIndex, handlePrevious, handleNext } = useContext(CarouselItemsContext);
1221
+ const prefersReducedMotion = useRef(window.matchMedia('(prefers-reduced-motion: reduce)').matches);
1222
+ // Update the ref when the media query changes
1223
+ useEffect(()=>{
1224
+ const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
1225
+ const handleChange = (e)=>{
1226
+ prefersReducedMotion.current = e.matches;
1227
+ };
1228
+ mediaQuery.addEventListener('change', handleChange);
1229
+ return ()=>mediaQuery.removeEventListener('change', handleChange);
1230
+ }, []);
1195
1231
  const handleKeyDown = (event)=>{
1196
1232
  // Prevent default behavior when holding down arrow keys (when repeat is true)
1197
1233
  // The default behavior in scroll snapping causes a staggering scroll effect that feels janky
1198
1234
  if (event.repeat && (event.key === 'ArrowLeft' || event.key === 'ArrowRight')) {
1199
1235
  event.preventDefault();
1236
+ return;
1237
+ }
1238
+ // For users with prefers-reduced-motion, trigger button click behavior instead of native scroll
1239
+ if (prefersReducedMotion.current) {
1240
+ if (event.key === 'ArrowLeft' && handlePrevious) {
1241
+ event.preventDefault();
1242
+ handlePrevious();
1243
+ } else if (event.key === 'ArrowRight' && handleNext) {
1244
+ event.preventDefault();
1245
+ handleNext();
1246
+ }
1200
1247
  }
1201
1248
  };
1202
- const { carouselItemsRef, onScroll, activeIndex } = useContext(CarouselItemsContext);
1203
1249
  return(// biome-ignore lint/a11y/noStaticElementInteractions: The keydown handler is only to prevent undesired scrolling behavior when using the arrow keys
1204
1250
  /*#__PURE__*/ jsx("div", {
1205
1251
  "data-slot": "carousel-items",
@@ -1926,50 +1972,61 @@ const Hero = ({ variant, className, children, ...rest })=>{
1926
1972
  });
1927
1973
  };
1928
1974
 
1929
- const LinkList = ({ className, children, ...restProps })=>{
1930
- const numberofLinks = Children.count(children);
1931
- return /*#__PURE__*/ jsx("div", {
1932
- className: cx(className, '@container'),
1933
- ...restProps,
1934
- children: /*#__PURE__*/ jsx("ul", {
1935
- className: cx('min-w-fit', // Hide dividers at the top of the list (overflow-y) and prevents arrow icon from overflowing container when animated to the right (overflow-x)
1936
- 'overflow-hidden', // Add a small gap between items that fits the divider lines (this way the divider line don't take up any space in each item)
1937
- 'grid auto-rows-max gap-y-px', // Gaps for when the list is displayed in multiple columns
1938
- '@lg:gap-x-12 @md:gap-x-9 @sm:gap-x-4 @xl:gap-x-16', numberofLinks > 5 && [
1939
- '@xl:grid-cols-2',
1940
- (numberofLinks === 9 || numberofLinks > 10) && '@4xl:grid-cols-3'
1941
- ]),
1942
- children: children
1943
- })
1975
+ // Sets the correct icons for each link in the link list
1976
+ const _LinkProvider = ({ children })=>/*#__PURE__*/ jsx(Provider, {
1977
+ values: [
1978
+ [
1979
+ _LinkContext,
1980
+ {
1981
+ _innerWrapper: ({ children, download, rel })=>(values)=>{
1982
+ let Icon = ArrowRight;
1983
+ if (download) {
1984
+ Icon = Download;
1985
+ } else if (rel?.includes('external')) {
1986
+ Icon = LinkExternal;
1987
+ }
1988
+ return /*#__PURE__*/ jsxs(Fragment, {
1989
+ children: [
1990
+ typeof children === 'function' ? children({
1991
+ ...values,
1992
+ defaultChildren: null
1993
+ }) : children,
1994
+ /*#__PURE__*/ jsx(Icon, {})
1995
+ ]
1996
+ });
1997
+ }
1998
+ }
1999
+ ]
2000
+ ],
2001
+ children: children
1944
2002
  });
1945
- };
1946
- const LinkListItem = ({ children, isExternal, className, ...restProps })=>{
1947
- let Icon = ArrowRight;
1948
- let iconTransition = cx('group-hover:motion-safe:translate-x-1');
1949
- if (restProps.download) {
1950
- Icon = Download;
1951
- iconTransition = cx('group-hover:motion-safe:translate-y-1');
1952
- } else if (isExternal) {
1953
- iconTransition = cx('group-hover:motion-safe:-translate-y-0.5 group-hover:motion-safe:translate-x-0.5');
1954
- Icon = LinkExternal;
1955
- }
1956
- return /*#__PURE__*/ jsx("li", {
1957
- // Creates divider lines that works in any grid layout and with the focus ring
1958
- className: "after:-top-px relative p-0.75 after:absolute after:right-0 after:left-0 after:h-px after:w-full after:bg-gray-light",
1959
- children: /*#__PURE__*/ jsxs(Link, {
1960
- ...restProps,
1961
- className: cx(className, 'group paragraph flex w-full cursor-pointer justify-between gap-x-2 py-3.5 font-medium no-underline focus-visible:outline-focus'),
1962
- children: [
1963
- /*#__PURE__*/ jsx("span", {
1964
- children: children
1965
- }),
1966
- /*#__PURE__*/ jsx(Icon, {
1967
- className: iconTransition
1968
- })
2003
+ const LinkListContainer = ({ className, ...restProps })=>// Dual providers makes for easier typing and more readable code
2004
+ /*#__PURE__*/ jsx(Provider, {
2005
+ values: [
2006
+ [
2007
+ HeadingContext,
2008
+ {
2009
+ size: 'm'
2010
+ }
1969
2011
  ]
2012
+ ],
2013
+ children: /*#__PURE__*/ jsx(_LinkProvider, {
2014
+ children: /*#__PURE__*/ jsx("div", {
2015
+ className: cx(className, 'link-list-container'),
2016
+ ...restProps
2017
+ })
1970
2018
  })
1971
2019
  });
1972
- };
2020
+ const LinkList = (props)=>/*#__PURE__*/ jsx(_LinkProvider, {
2021
+ children: /*#__PURE__*/ jsx("ul", {
2022
+ ...props,
2023
+ "data-slot": "link-list"
2024
+ })
2025
+ });
2026
+ const LinkListItem = (props)=>/*#__PURE__*/ jsx("li", {
2027
+ ...props,
2028
+ "data-slot": "link-list-item"
2029
+ });
1973
2030
 
1974
2031
  const DialogTrigger = (props)=>/*#__PURE__*/ jsx(DialogTrigger$1, {
1975
2032
  ...props
@@ -2831,4 +2888,4 @@ const VideoLoop = ({ src, format, alt, className })=>{
2831
2888
  });
2832
2889
  };
2833
2890
 
2834
- 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, 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, LinkList as UNSAFE_LinkList, LinkListItem as UNSAFE_LinkListItem, Modal as UNSAFE_Modal, 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 };
2891
+ 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, 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.2.0",
3
+ "version": "3.3.0",
4
4
  "description": "Grunnmuren components in React",
5
5
  "repository": {
6
6
  "url": "https://github.com/code-obos/grunnmuren"
@@ -24,7 +24,6 @@
24
24
  "@react-aria/utils": "^3.29.1",
25
25
  "@react-stately/form": "^3.1.5",
26
26
  "@react-stately/utils": "^3.10.7",
27
- "@types/node": "^24.0.0",
28
27
  "cva": "^1.0.0-0",
29
28
  "react-aria": "^3.41.1",
30
29
  "react-aria-components": "^1.10.1",
@@ -35,7 +34,8 @@
35
34
  "react": "^19"
36
35
  },
37
36
  "devDependencies": {
38
- "tailwindcss": "4.1.16"
37
+ "@types/node": "^24.0.0",
38
+ "tailwindcss": "4.1.17"
39
39
  },
40
40
  "scripts": {
41
41
  "build": "bunchee"