Migration Radix UI -> Base UI
Vous migrez les wrappers shadcn, les compositions Radix faites à la main et leurs
consommateurs vers @base-ui/react, en gardant le projet compilable à chaque étape.
Soyez précis ; ne devinez jamais une correspondance. Lorsqu'une propriété ou une partie
ne se trouve pas dans ces fichiers de référence, vérifiez node_modules/@base-ui/react/**/*.d.ts avant
de transformer, et enregistrez les lacunes dans le rapport.
Pré-vérification (toujours)
npx shadcn@latest info --json(ou le lanceur du projet) : donne la base actuelle, STYLE (ex.radix-lyra), la version de tailwind, les alias, les composants installés et le gestionnaire de paquets. Fiez-vous à lui plutôt qu'à une déduction.- Détectez le gestionnaire de paquets (champ packageManager / fichier de verrouillage : pnpm-lock.yaml, bun.lock, yarn.lock, package-lock.json) et utilisez-LE pour chaque installation. Ne laissez jamais un fichier de verrouillage obsolète.
- Exigez un arbre git propre ; travaillez sur une branche ; un commit par composant.
- Vérification de base AVANT de toucher aux dépendances : exécutez la vérification de type/construction du projet afin que les échecs préexistants ne vous soient jamais attribués.
- Installez
@base-ui/reacten parallèle de radix. Les paquets Radix ne sont supprimés qu'après la migration du DERNIER composant (les deux coexistent bien).
Stratégie : d'abord la paire dorée, ensuite le moteur de transformation
- Paire dorée via la CLI (recommandé). Si le projet est shadcn avec un
style connu (
radix-<style>), la CLI shadcn elle-même est l'exécuteur de la paire dorée :- Classez CHAQUE wrapper d'interface utilisateur D'ABORD : différenciez le fichier de l'utilisateur par rapport à son
origine standard, en utilisant le style components.json LITTÉRALEMENT dans l'URL
(
https://ui.shadcn.com/r/styles/<style>/<component>.json, files[0].content). Cela fonctionne pour les styles préfixés (radix-nova) ET les styles historiques sans préfixe (new-york, new-york-v4, default), qui sont tous encore servis. - Mode PROJET ENTIER : basculez le style
components.jsonderadix-<style>->base-<style>maintenant. Mode PROGRESSIF : ne basculez PAS encore (le projet est encore principalement radix ; le basculement a lieu une fois, après le dernier composant); récupérez les variantes de base directement par URL à la place (https://ui.shadcn.com/r/styles/base-<style>/<component>.json). - Wrappers VIERGES, mode projet entier :
shadcn add <component> --overwritedélivre la variante de base avec la résolution exacte des icônes/polices/préréglages du projet. Ne faites jamais--all --overwriteen bloc ; allez composant par composant, ou vous serez submergé par la dérive de version du registre. Mode PROGRESSIF : n'utilisez jamais--overwrite(cela détruit l'original que les consommateurs importent encore); écrivez le contenu de la variante de base récupérée dans<component>-base.tsxà la place. - Wrappers PERSONNALISÉS : récupérez la variante de base et rejouez le diff de l'utilisateur
dessus (leurs personnalisations doivent SURVIVRE ;
--overwriteles détruirait). Implémentation mécanique qui fonctionne à grande échelle :git merge-file user.tsx radix-golden.tsx base-golden.tsx(fusion à trois voies, avec la version radix dorée comme ancêtre) résout automatiquement la plupart des fichiers ; résolvez manuellement les conflits avec les tables de référence. - BALAYAGE OBLIGATOIRE des résidus sur CHAQUE fichier de paire dorée, y compris ceux qui
ont fusionné "proprement" :
grep -n "radix-ui\|@radix-ui\|IconPlaceholder"par fichier. Le registre réorganise parfois les fonctions entre les variantes, ce qui fait que les fusions à trois voies signalent zéro conflit tout en laissant des morceaux radix obsolètes en place. Une fusion propre n'est PAS une preuve que le fichier est propre. Ceci est plus fiable que de reconstruire des transformations ; utilisez-le chaque fois que la paire existe. Le code consommateur/application n'a pas de mécanisme CLI : migrez-le toujours à la main en vous référant àconsumer-props.md.
- Classez CHAQUE wrapper d'interface utilisateur D'ABORD : différenciez le fichier de l'utilisateur par rapport à son
origine standard, en utilisant le style components.json LITTÉRALEMENT dans l'URL
(
- Styles obsolètes (new-york, new-york-v4, default) : classement uniquement, pas de rejeu.
Ceux-ci n'ont pas de contrepartie en base (il n'y a pas de base-new-york), et
recibler sur une variante base- restylerait l'application de l'utilisateur. Utilisez
la version radix dorée UNIQUEMENT pour détecter les personnalisations, puis exécutez le moteur de
transformation sur le PROPRE fichier de l'utilisateur : reconnectez les primitives, gardez leurs classes
exactes, appliquez les renommages de classes. Leur apparence reste la leur. À la fin d'une
migration de projet entier avec style obsolète, SIGNALEZ (ne corrigez pas) : le nom du style
indique encore radix à la CLI, donc les futurs
shadcn addlivreront des variantes radix ; l'utilisateur décide s'il souhaite changer de style ou ajouter manuellement. - Moteur de transformation (solution de secours). Code Radix fait à la main, projets non-shadcn,
styles inconnus : transformez en utilisant
universal-patterns.md(imports dans les DEUX formes :radix-uiet@radix-ui/react-*; asChild -> render avec l'exemple travaillé ; Portal>Positioner>Popup ; la règle FORWARD du positionneur ; renommages de parties), les tables de propriétés par famille (overlays.md,menus.md,form-controls.md,disclosure.md,display-misc.md),class-mapping.mdpour les réécritures d'attributs de données/variables CSS, etwrapper-shapes.mdpour les formes cibles exactes (flèche d'info-bulle, valeurs par défaut de SubContent, anatomie de select).
Modes
Progressif (par défaut). "Migrer accordéon" = un composant, motif strangler-fig :
- Détectez d'abord l'état en cours : un fichier
<component>-base.tsxexistant, des consommateurs répartis entre les anciennes/nouvelles importations. Les fichiers SONT l'état ; reprenez, ne recommencez jamais. - Si le composant importe d'autres wrappers d'interface utilisateur encore sur radix (select -> button), ARRÊTEZ et recommandez de migrer d'abord ceux-ci, de bas en haut.
- Écrivez la version migrée dans
<component>-base.tsx(original intact ; contenu de la paire dorée récupéré par URL, ou transformé à la main, selon la stratégie ci-dessus) ; vérifiez les types. Reconnectez les consommateurs UN PAR UN (importations + les propriétés du site d'appel dansconsumer-props.md) ; vérifiez les types de chacun. Lorsqu'aucun consommateur n'importe l'original : supprimez-le, renommez-base-> original, inversez les importations en arrière, vérification finale, commitez. Lorsque le DERNIER wrapper radix du projet est finalisé, basculezcomponents.jsonversbase-<style>et supprimez les dépendances radix.
Projet entier (uniquement si demandé explicitement) : même travail par composant dans
l'ordre des dépendances (wrappers feuilles/partagés comme button et label d'abord). Après
les wrappers, balayez TOUT le code de l'application avec consumer-props.md — la surface de rupture
des sites d'appel est beaucoup plus grande que asChild. Ensuite, supprimez les dépendances radix, installez,
construction complète.
Règles strictes
- NE touchez JAMAIS aux bibliothèques non-Radix ou à leurs wrappers : cmdk (commande), vaul (tiroir), sonner, input-otp, react-day-picker (calendrier), recharts (graphique). Signalez-les comme intentionnellement non touchés.
- Pas de contrepartie dans Base UI : AspectRatio -> div avec aspect-ratio CSS ; Label ->
<label>natif ; VisuallyHidden ->sr-only; Direction -> Direction Provider (propriétédirection, pasdir). Popover Anchor et NavigationMenu Indicator n'ont pas d'équivalent : passage passif + drapeau. button.tsxmigre vers la VRAIE primitive@base-ui/react/button, jamais un wrapper useRender fait à la main.- Les différences de comportement sont SIGNALÉES, jamais corrigées en silence (activation manuelle des onglets, éléments de menu qui ne se ferment pas au clic, délai de 50ms du nav-menu). La cible est un Base UI idiomatique correspondant au registre de base shadcn.
- Rapport honnête : les fichiers ignorés/revenus sont listés comme signalés, jamais comme migrés. Les échecs préexistants sont nommés comme préexistants.
Vérifier et rapporter
Vérification des types par fichier, construction par lot, construction complète à la fin par rapport à la ligne de base.
Les rapports se trouvent dans un répertoire .migration/ à la racine du projet, UN FICHIER PAR
COMPOSANT : .migration/<component>.md (ex. .migration/accordion.md).
Règles :
- Chaque exécution écrit (ou écrase complètement) le fichier pour chaque composant qu'elle a migré. Réexécuter un composant remplace son rapport ; ne touchez jamais aux fichiers des autres composants.
- Une exécution multi-composants ("migrer alert-dialog et dropdown-menu") écrit un fichier par composant, chacun autonome ; les notes de balayage des consommateurs partagés sont répétées dans chaque fichier concerné.
- Le mode projet entier écrit les fichiers par composant plus
.migration/project.md(échange de dépendances, résumé du balayage du code applicatif, résultat final de la construction). - Il n'y a PAS de fichier d'index. L'état de la migration est dérivé du disque, non
maintenu : analysez le répertoire d'interface utilisateur du projet (l'alias
uide shadcn info, ex. components/ui ou src/components/ui) pour les importations radix restantes lorsque l'on vous demande "que reste-t-il ?". Terminez chaque résumé d'exécution avec ce nombre dérivé ("N wrappers restent sur Radix").
Chaque .migration/<component>.md utilise EXACTEMENT cette structure (elle est
documentée publiquement ; les rapports doivent correspondre) :
# <component>
<date, stratégie utilisée (paire dorée via CLI / fusion / moteur), verdict en une ligne>
## Modifié
<chaque fichier touché, avec ce qui a changé et pourquoi ; inclure fichier:ligne pour tout
élément notable. Confirmer que le balayage des résidus est propre :
grep -n "radix-ui\|@radix-ui" sur les fichiers de ce composant>
## Laissé de côté
<fichiers qui semblent liés mais n'ont pas été intentionnellement touchés, avec la raison
(cmdk/vaul/sonner ne sont pas radix ; dérive sans rapport ; etc.)>
## Changements de comportement
<différences qui se compilent bien mais agissent différemment ; signalées, jamais corrigées
(activation des onglets, fermeture au clic des menus, délais...). Section vide si aucune>
## Vérifier manuellement
<courte liste de vérification QA manuelle pour cette famille de primitives : retour de focus sur
les dialogues, navigation clavier + saisie partielle sur les menus/select, sensation de délai d'info-bulle,
événements de validation de curseur. Étapes concrètes, une minute de clics>