Gå til hovedinnhold

Alle @entur/*-pakker krever nå React 18.0.0 eller høyere som peer dependency. Dette er en breaking change.

Automatisk migrering med Claude Code

Designsystemet tilbyr en migreringsguide skrevet for AI-kodeagenter. Lim inn meldingen under i Claude Code – ingen installasjon eller oppsett kreves. Den fungerer også i andre agenter som kan hente URL-er, som GitHub Copilot og Cursor.

Oppgrader @entur/*-pakkene i dette prosjektet til siste major-versjon.

Les og følg denne migreringsguiden:
https://raw.githubusercontent.com/entur/design-system/main/skills/migrate-react-18/SKILL.md

Relative lenker i guiden (f.eks. references/breaking-changes.md) ligger under
https://raw.githubusercontent.com/entur/design-system/main/skills/migrate-react-18/

Breaking changes

Peer dependencies

Alle pakker krever nå:

  • react: >=18.0.0 (tidligere >=16.8.0)
  • react-dom: >=18.0.0 (tidligere >=16.8.0)

ESM exports

Alle @entur/*-pakker har nå et strengt exports-felt i package.json. Dette gir bundlere korrekt ESM/CJS-oppløsning, men begrenser hvilke importstier som fungerer.

Hva har endret seg

  • Hver pakke har nå "exports" med eksplisitte types-, import-, require- og default-betingelser.
  • Deep imports til dist/ som ikke er eksplisitt listet, vil feile.
  • CSS kan importeres via en ren ./styles-subpath.

Hva konsumenter må gjøre

Fjern custom alias/resolve-konfigurasjon – exports-feltet håndterer dette nativt.

Fiks dype dist/-imports:

// ❌ Før (vil feile)
import { Button } from '@entur/button/dist/Button';

// ✅ Etter
import { Button } from '@entur/button';

CSS-imports – både gammel og ny sti fungerer:

// ✅ Ny (anbefalt)
import '@entur/button/styles';

// ✅ Fungerer fortsatt
import '@entur/button/dist/styles.css';

@entur/tokens stil-imports:

// ✅ Ny (anbefalt)
@use '@entur/tokens/styles/base.scss' as *;
@use '@entur/tokens/styles/semantic.scss' as *;

// ✅ Fungerer fortsatt
@use '@entur/tokens/dist/base.scss' as *;
@use '@entur/tokens/dist/semantic.scss' as *;

@entur/utils SCSS-imports:

// ✅ Ny (anbefalt)
@use '@entur/utils/styles/breakpoints' as breakpoint;
@use '@entur/utils/styles/color-utils' as util;

// ✅ Fungerer fortsatt
@use '@entur/utils/dist/breakpoints.scss' as breakpoint;
@use '@entur/utils/dist/color-utils.scss' as util;

@entur/modal

Intern implementasjon er migrert fra @reach/dialog (utdatert) til det native HTML-elementet <dialog>. Dette fjerner alle tredjepartsavhengigheter for modal.

Hva har endret seg internt

  • @reach/dialog → Nativt <dialog>-element med showModal() / close()
  • Fokusfelle håndteres nå nativt av nettleseren (innebygd i <dialog>)
  • Fokusrestaurering ved lukking håndteres nativt
  • Bakgrunnsstyling bruker ::backdrop pseudo-element i stedet for en egen overlay-div
  • Scroll-lås bruker html:has(dialog[open]) CSS i stedet for JavaScript

Breaking changes

  • onDismiss er nå påkrevd på Modal. Native <dialog> tillater alltid lukking via Escape – onDismiss sikrer at parent-state holdes synkronisert.
  • Ny showCloseButton-prop (default: true) – styrer om lukkeknappen vises øverst til høyre.

Hva konsumenter må gjøre

  • Legg til onDismiss hvis det mangler – det er nå en påkrevd prop.
  • CSS som målretter <div>-overlay – oppdater til å målrette <dialog> eller bruk klassen .eds-modal__overlay.
  • Fjern referanser til data-reach-dialog-*-attributter.

Hva er bevart

  • Modal med open, onDismiss, size, title, closeLabel, closeOnClickOutside, initialFocusRef, align
  • ModalOverlay, ModalContent og Drawer – alle props bevart
  • Fokusfelle, fokusrestaurering, Escape-lukking og klikk-utenfor fungerer som før
  • Alle CSS-klassenavn (eds-modal__*, eds-drawer__*) er uendret

@entur/tab

Intern implementasjon er migrert fra @reach/tabs (utdatert) til en nativ ARIA-implementasjon uten tredjepartsavhengigheter.

Hva har endret seg internt

  • @reach/tabs → Nativ ARIA-implementasjon (null avhengigheter)
  • Tab-tilstand styres nå via React Context (TabsContext)
  • ARIA-attributter (role, aria-selected, aria-controls, aria-labelledby) settes direkte
  • Tastaturnavigasjon (ArrowLeft, ArrowRight, Home, End) er implementert nativt i TabList

Hva er bevart

  • Tabs med index, defaultIndex, onChange, as (kontrollert og ukontrollert)
  • TabList, Tab, TabPanel og TabPanels – alle props bevart
  • Tastaturnavigasjon, ARIA-roller og alle CSS-klassenavn (eds-tabs, eds-tab, eds-tab-list osv.)

Hva konsumenter må gjøre

  • Fjern data-reach-*-selektorer – erstatt med .eds-tab, .eds-tab-list, .eds-tab-panel, eller rolle-selektorer ([role="tab"] osv.).
  • Fjern ikke-standard props – typer er nå strengere. Alle standard HTML-attributter fungerer fortsatt.
  • Ikke hardkod genererte ID-er i tester – bruk aria-controls/aria-labelledby for å finne tilknyttede elementer.

Nye funksjoner

  • keepMounted-prop på TabPanels – beholder alle paneler i DOM med hidden-attributtet.
  • SSR-kompatibel – useId() produserer stabile ID-er mellom server og klient.
  • aria-label og aria-labelledby er nå eksplisitt typet på TabList.

@entur/expand

Intern implementasjon er migrert fra react-collapse (ikke vedlikeholdt siden 2021) til en CSS grid-animasjon uten avhengigheter.

Breaking changes – innhold forblir i DOM når det er lukket

Tidligere ble lukket innhold fjernet fra DOM. Nå forblir lukket innhold i DOM, men skjules med aria-hidden="true" og inert. For å gjenopprette gammel oppførsel:

// Gammel oppførsel: innhold fjernes fra DOM når det lukkes
<ExpandablePanel unmountOnClose={true} title="...">
  {children}
</ExpandablePanel>

Dette påvirker også SideNavigationGroup i @entur/menu.

Nye props

  • ExpandablePanel: open, onToggle (kontrollert modus), unmountOnClose
  • ExpandableText: unmountOnClose
  • AccordionItem: unmountOnClose
  • Accordion: openId, onToggle, defaultOpenId (kontrollert modus)
  • BaseExpand: unmountOnClose

Alle expand-komponenter støtter nå ref-forwarding via React.forwardRef.

Hva konsumenter må gjøre

  • De fleste konsumenter trenger ingen endringer – ny standardoppførsel er bedre for tilgjengelighet og ytelse
  • Hvis du er avhengig av at lukket innhold fjernes fra DOM, legg til unmountOnClose={true}
  • For kontrollert accordion-oppførsel kan du nå bruke openId og onToggle på Accordion

@entur/layout

LayoutWrapper fjernet

LayoutWrapper er fjernet. Bruk Grid fra @entur/layout/beta direkte:

// ❌ Før
import { LayoutWrapper } from '@entur/layout';
<LayoutWrapper>{children}</LayoutWrapper>

// ✅ Etter
import { Grid } from '@entur/layout/beta';
<Grid
  templateColumns={{
    base: 'repeat(4, 1fr)',
    m: 'repeat(8, 1fr)',
    lg: 'repeat(12, 1fr)',
  }}
  columnGap={{ base: 's-m', m: 'm-l' }}
>
  {children}
</Grid>

Responsive breakpoint-nøkler endret

Beta Grid bruker nye responsive breakpoint-nøkler:

  • sm → base
  • md → m
  • lg → lg (uendret)
  • xl → xl (uendret)
// ❌ Før
<Grid.Item colSpan={{ sm: '1 / -1', md: '1 / -1', lg: '3 / -3' }}>

// ✅ Etter
<Grid.Item colSpan={{ base: '1 / -1', m: '1 / -1', lg: '3 / -3' }}>

@entur/utils

useRandomId er avviklet

useRandomId fra @entur/utils er nå avviklet (deprecated). React 18 tilbyr useId() nativt. Erstatt slik:

// ❌ Før
import { useRandomId } from '@entur/utils';
const id = useRandomId('eds-my-component');

// ✅ Etter
import { useId } from 'react';
const id = `eds-my-component${useId()}`;

useRandomId fungerer fortsatt (den bruker useId() internt), men vil bli fjernet i en fremtidig major-versjon.

Tredjepartsavhengigheter

Fjernede avhengigheter

  • @reach/dialog → Erstattet av nativt <dialog>-element
  • @reach/tabs → Erstattet av nativ ARIA-implementasjon
  • react-collapse → Erstattet av CSS grid-animasjon