@abyss-project/commons-front-core 10.1.0 → 11.0.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.
Files changed (139) hide show
  1. package/README.md +319 -334
  2. package/catalog/catalog-entries.ts +0 -2
  3. package/catalog/pages/index.ts +0 -4
  4. package/dist/{AbyssCookieConsentProvider-DTHchhfw.js → AbyssCookieConsentProvider-C3NZfWxR.js} +1532 -2151
  5. package/dist/{CookieConsentSettings.component-D13TqxZl.js → CookieConsentSettings.component-Dvbp3MIX.js} +1 -1
  6. package/dist/cookie-consent.js +2 -2
  7. package/dist/{design-theme-BGMTwRaP.js → design-theme-sPEoMB7j.js} +12200 -9258
  8. package/dist/hooks/quota-dialog.store.d.ts +1 -1
  9. package/dist/hooks/use-rich-intl.hook.d.ts +44 -666
  10. package/dist/{index-BlhbGVkk.js → index-BVGdsnC4.js} +2 -2
  11. package/dist/{index-s2djh_x_.js → index-C2KrTHAO.js} +2 -2
  12. package/dist/{index-kfzQWNLP.js → index-C9FzqvHz.js} +2 -2
  13. package/dist/{index-B9pFhQQG.js → index-CB-jdY_E.js} +2 -2
  14. package/dist/{index-JEsamj6m.js → index-CCaW-38I.js} +2 -2
  15. package/dist/{index-BUqYHWKw.js → index-CKCWWoQb.js} +3 -3
  16. package/dist/{index-Dop3xXC3.js → index-CNcmCFNN.js} +1 -1
  17. package/dist/{index-40JUFFwY.js → index-CXwwKVPn.js} +3 -3
  18. package/dist/{index-CdL2MLmd.js → index-Cb-uMz_V.js} +3 -3
  19. package/dist/{index-tN8hz-IX.js → index-CrWjgIMV.js} +4 -4
  20. package/dist/{index-BFBonBC2.js → index-D9s128sK.js} +4 -4
  21. package/dist/{index-D0EC1_iy.js → index-DD25yrsQ.js} +4 -4
  22. package/dist/{index-Cccq9d1E.js → index-DEqCdX0Q.js} +2 -2
  23. package/dist/{index-BsOQZ-n8.js → index-DIpJhT2r.js} +2 -2
  24. package/dist/index-DPi7aKci.js +95942 -0
  25. package/dist/{index-oBWWShwb.js → index-Di1amUHq.js} +2 -2
  26. package/dist/{index-CM-90k5s.js → index-DtHUaGVU.js} +3 -3
  27. package/dist/{index-Dk1JTU4K.js → index-QNJIP2m4.js} +2 -2
  28. package/dist/{index-DqAkOKf8.js → index-Ut9uJwau.js} +2 -2
  29. package/dist/{index-D7AFc1sX.js → index-aYivWEyJ.js} +2 -2
  30. package/dist/{index-CBrydj4V.js → index-lE9lxmTc.js} +2 -2
  31. package/dist/{index-BcRgJqSB.js → index-whpnjq54.js} +2 -2
  32. package/dist/index.js +7900 -5669
  33. package/dist/legacy/components/PdfEditor/PdfEditor.d.ts +1 -1
  34. package/dist/legacy/components/PdfEditor/index.d.ts +2 -2
  35. package/dist/legacy/components/PdfEditor/signature/SignatureDrawCanvas.d.ts +1 -1
  36. package/dist/legacy/components/PdfEditor/signature/SignaturePicker.d.ts +1 -1
  37. package/dist/legacy/components/PdfEditor/signature/SignatureSaveButton.d.ts +1 -1
  38. package/dist/legacy/components/PdfEditor/signature/SignatureSavedList.d.ts +1 -1
  39. package/dist/legacy/components/PdfEditor/signature/SignatureUploadDropzone.d.ts +1 -1
  40. package/dist/legacy/components/PdfEditor/signature/resolve-asset.d.ts +1 -1
  41. package/dist/legacy/components/PdfEditor/tools/FillFieldsTool.d.ts +1 -1
  42. package/dist/legacy/components/PdfEditor/tools/ShapeTool.d.ts +1 -1
  43. package/dist/legacy/components/PdfEditor/tools/SignatureTool.d.ts +1 -1
  44. package/dist/legacy/components/PdfEditor/tools/TextTool.d.ts +1 -1
  45. package/dist/legacy/components/PdfEditor/tools/Toolbar.d.ts +1 -1
  46. package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/types.d.ts +1 -1
  47. package/dist/legacy/components/PdfEditor/viewer/InsertPagesButton.d.ts +1 -1
  48. package/dist/legacy/components/PdfEditor/viewer/PageOverlay.d.ts +1 -1
  49. package/dist/legacy/components/PdfEditor/viewer/PageSidebar.d.ts +2 -2
  50. package/dist/legacy/components/PdfEditor/viewer/PageThumbnail.d.ts +2 -2
  51. package/dist/legacy/components/PdfEditor/viewer/PdfCanvas.d.ts +1 -1
  52. package/dist/legacy.js +209 -26787
  53. package/dist/translations/en.d.ts +22 -333
  54. package/dist/translations/fr.d.ts +22 -333
  55. package/package.json +5 -12
  56. package/vite.config.ts +0 -4
  57. package/catalog/pages/MarkdownEditor.tsx +0 -48
  58. package/catalog/pages/PdfEditor.tsx +0 -153
  59. package/dist/AbyssCloud-IuD91X6C.js +0 -2949
  60. package/dist/Tabs-CZQ1JYlW.js +0 -2315
  61. package/dist/_commonjsHelpers-DaMA6jEr.js +0 -8
  62. package/dist/components/editors/MarkdownEditor/MarkdownEditor.d.ts +0 -19
  63. package/dist/components/editors/MarkdownEditor/MarkdownEditor.spec.d.ts +0 -1
  64. package/dist/components/editors/MarkdownEditor/crepe-labels.d.ts +0 -17
  65. package/dist/components/editors/MarkdownEditor/index.d.ts +0 -2
  66. package/dist/components/editors/MarkdownEditor/markdown-theme.d.ts +0 -7
  67. package/dist/components/editors/PdfEditor/PdfEditor.d.ts +0 -9
  68. package/dist/components/editors/PdfEditor/PdfEditor.spec.d.ts +0 -1
  69. package/dist/components/editors/PdfEditor/engine/open-pdf-document.d.ts +0 -8
  70. package/dist/components/editors/PdfEditor/index.d.ts +0 -3
  71. package/dist/components/editors/PdfEditor/pdf-colors.d.ts +0 -26
  72. package/dist/components/editors/PdfEditor/pdf-colors.spec.d.ts +0 -1
  73. package/dist/components/editors/PdfEditor/signature/SignatureDrawPad.d.ts +0 -15
  74. package/dist/components/editors/PdfEditor/signature/SignaturePicker.d.ts +0 -31
  75. package/dist/components/editors/PdfEditor/signature/SignaturePicker.spec.d.ts +0 -1
  76. package/dist/components/editors/PdfEditor/signature/SignatureSaveButton.d.ts +0 -14
  77. package/dist/components/editors/PdfEditor/signature/SignatureSavedList.d.ts +0 -19
  78. package/dist/components/editors/PdfEditor/signature/SignatureUploadPanel.d.ts +0 -14
  79. package/dist/components/editors/PdfEditor/signature/resolve-asset.d.ts +0 -19
  80. package/dist/components/editors/PdfEditor/signature/resolve-asset.spec.d.ts +0 -1
  81. package/dist/components/editors/PdfEditor/signature/test-support/pdf-editor-test-harness.d.ts +0 -28
  82. package/dist/components/editors/PdfEditor/toolbar/EraserIcon.d.ts +0 -3
  83. package/dist/components/editors/PdfEditor/toolbar/GroupPanel.d.ts +0 -17
  84. package/dist/components/editors/PdfEditor/toolbar/PanelRow.d.ts +0 -14
  85. package/dist/components/editors/PdfEditor/toolbar/PdfToolbar.d.ts +0 -65
  86. package/dist/components/editors/PdfEditor/toolbar/PdfToolbar.spec.d.ts +0 -1
  87. package/dist/components/editors/PdfEditor/toolbar/SavedAssets.d.ts +0 -24
  88. package/dist/components/editors/PdfEditor/toolbar/ToolGroupButton.d.ts +0 -20
  89. package/dist/components/editors/PdfEditor/toolbar/tool-groups.d.ts +0 -34
  90. package/dist/components/editors/PdfEditor/toolbar/tool-options/DrawOptions.d.ts +0 -6
  91. package/dist/components/editors/PdfEditor/toolbar/tool-options/FillFieldsOptions.d.ts +0 -13
  92. package/dist/components/editors/PdfEditor/toolbar/tool-options/HighlightOptions.d.ts +0 -6
  93. package/dist/components/editors/PdfEditor/toolbar/tool-options/RedactOptions.d.ts +0 -6
  94. package/dist/components/editors/PdfEditor/toolbar/tool-options/ShapeOptions.d.ts +0 -6
  95. package/dist/components/editors/PdfEditor/toolbar/tool-options/SignatureOptions.d.ts +0 -5
  96. package/dist/components/editors/PdfEditor/toolbar/tool-options/TextOptions.d.ts +0 -6
  97. package/dist/components/editors/PdfEditor/toolbar/tool-options/ToolOptions.d.ts +0 -14
  98. package/dist/components/editors/PdfEditor/toolbar/tool-options/swatches.d.ts +0 -2
  99. package/dist/components/editors/PdfEditor/toolbar/tool-settings.d.ts +0 -14
  100. package/dist/components/editors/PdfEditor/viewer/InsertPagesButton.d.ts +0 -14
  101. package/dist/components/editors/PdfEditor/viewer/InsertPagesButton.spec.d.ts +0 -1
  102. package/dist/components/editors/PdfEditor/viewer/InsertPagesDialog.d.ts +0 -28
  103. package/dist/components/editors/PdfEditor/viewer/PageOverlay.d.ts +0 -37
  104. package/dist/components/editors/PdfEditor/viewer/PageOverlay.spec.d.ts +0 -1
  105. package/dist/components/editors/PdfEditor/viewer/PageSidebar.d.ts +0 -16
  106. package/dist/components/editors/PdfEditor/viewer/PageSidebar.spec.d.ts +0 -1
  107. package/dist/components/editors/PdfEditor/viewer/PageThumbnail.d.ts +0 -16
  108. package/dist/components/editors/PdfEditor/viewer/PdfCanvas.d.ts +0 -26
  109. package/dist/components/editors/PdfEditor/viewer/PdfCanvas.spec.d.ts +0 -1
  110. package/dist/components/editors/PdfEditor/viewer/ViewerControls.d.ts +0 -21
  111. package/dist/components/editors/PdfEditor/viewer/ViewerControls.spec.d.ts +0 -1
  112. package/dist/components/editors/PdfEditor/viewer/test-support/viewer-test-harness.d.ts +0 -30
  113. package/dist/components/editors/editors-guard.spec.d.ts +0 -1
  114. package/dist/components/editors/index.d.ts +0 -2
  115. package/dist/editors.d.ts +0 -1
  116. package/dist/editors.js +0 -5151
  117. package/dist/sortable.esm-DM2HNEC7.js +0 -69322
  118. package/dist/translations/editors-i18n.spec.d.ts +0 -1
  119. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/hooks/use-acro-form-fields.d.ts +0 -0
  120. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/hooks/use-export.d.ts +0 -0
  121. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/hooks/use-page-order.d.ts +0 -0
  122. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/hooks/use-pdf-document.d.ts +0 -0
  123. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/hooks/use-undo-redo.d.ts +0 -0
  124. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/hooks/use-uploaded-docs.d.ts +0 -0
  125. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/operations/actions.d.ts +0 -0
  126. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/operations/apply.d.ts +0 -0
  127. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/operations/apply.spec.d.ts +0 -0
  128. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/operations/compute-page-order.d.ts +0 -0
  129. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/operations/compute-page-order.spec.d.ts +0 -0
  130. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/operations/extract.d.ts +0 -0
  131. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/operations/extract.spec.d.ts +0 -0
  132. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/operations/pdf-data-url.d.ts +0 -0
  133. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/operations/rasterize.d.ts +0 -0
  134. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/operations/redact.d.ts +0 -0
  135. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/operations/redact.spec.d.ts +0 -0
  136. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/operations/reducer.d.ts +0 -0
  137. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/operations/reducer.spec.d.ts +0 -0
  138. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/operations/rotate-coords.d.ts +0 -0
  139. /package/dist/{components/editors/PdfEditor/engine → legacy/components/PdfEditor}/operations/rotate-coords.spec.d.ts +0 -0
package/README.md CHANGED
@@ -1,334 +1,319 @@
1
- # Abyss Commons Front Core
2
-
3
- `@abyss-project/commons-front-core`
4
-
5
- Composants React, hooks, design system et traductions partagés par les frontends Abyss.
6
-
7
- _Shared React components, hooks, design system and translations for Abyss frontends._
8
-
9
- ## Installation
10
-
11
- ```bash
12
- npm install @abyss-project/commons-front-core
13
- # or
14
- pnpm add @abyss-project/commons-front-core
15
- ```
16
-
17
- ## Liens
18
-
19
- - **Documentation** : [https://docs.abyss-project.fr/abyss-project](https://docs.abyss-project.fr/abyss-project)
20
- - **NPM** : [@abyss-project/commons-front-core](https://www.npmjs.com/package/@abyss-project/commons-front-core)
21
- - **Application Abyss** : [app.abyss-project.fr](https://app.abyss-project.fr)
22
- - **Statut des services** : [status.abyss-project.fr](https://status.abyss-project.fr)
23
-
24
- ## Usage
25
-
26
- Voir la [documentation produit](https://docs.abyss-project.fr/abyss-project) pour les guides d'utilisation, la configuration du Core, les exemples d'appel et la référence des permissions.
27
-
28
- ## RUM
29
-
30
- Le RUM navigateur d'un front (SDK `@abyss-project/monitor-browser`, peer `^1.3.2` ; `setContact` et `setTheme` demandent la version publiée par #285 F) se démarre par `AbyssRumProvider`, monté **sous** `AbyssCookieConsentProvider`, sous le `ThemeProvider` MUI et, quand le front en a un, sous `AuthProvider` :
31
-
32
- ```tsx
33
- <AbyssErrorBoundary appName="abyss-cloud">
34
- <AuthProvider client={authClient}>
35
- <AbyssCookieConsentProvider consentVersion={COOKIE_CONSENT_VERSION} isAuthenticated={isAuthenticated}>
36
- <AbyssRumProvider config={buildRumOptions()}>
37
- <App />
38
- </AbyssRumProvider>
39
- </AbyssCookieConsentProvider>
40
- </AuthProvider>
41
- </AbyssErrorBoundary>
42
- ```
43
-
44
- - **`config` est requise** (raison de la majeure 8.0.0 : aucun front ne peut oublier son RUM). `config={null}` désactive le RUM explicitement : rien n'est installé. Elle reçoit les options de `AbyssRum.init` (`apiUrl`, `proxyUrl`, `applicationId`, `token`, `release`, `instrumentedOrigins`, `routeResolver`…), sauf `consent`, que le provider fournit.
45
- - **Une seule initialisation.** `AbyssRum.init` est appelé au premier commit avec une `config` non nulle, une fois, StrictMode compris. Une `config` qui change ensuite est **ignorée** : le SDK vit autant que la page.
46
- - **Consentement.** Le replay exige la catégorie analytics de `AbyssCookieConsentProvider`, relue à chaque décision du SDK : un consentement donné ou retiré après le démarrage est suivi. Sans provider de consentement, analytics vaut refusé.
47
- - **Acteur.** Sous `AuthProvider`, l'acteur de la session est l'id de l'utilisateur connecté, `null` à la déconnexion, inchangé pendant le chargement de la session. Sans `AuthProvider`, aucun acteur.
48
- - **`feedbackTicket`** (`intakeSlug`, `internalTicketSectionId`, `appName`, `sessionUrl(sessionId, offsetMs)`, `locale?()`) : chaque retour utilisateur enregistré par Monitor devient un ticket Internal Tickets, par l'intake public d'abyss-console (`fileInternalTicketIntake`, peer `@abyss-project/console` `^12.4.0`, configuré par `AbyssConsoleCore.setConfig` du front). Titre `[<appName>] Retour utilisateur` ; description : le message, l'e-mail, la route et le lien vers la session. Le déclarant est l'e-mail saisi, sinon celui de l'utilisateur connecté ; un retour anonyme sans e-mail ne crée aucun ticket et reste dans Monitor. Un échec de création est journalisé (`console.warn`) et avalé. `locale()` est relue à chaque retour : sa sous-étiquette primaire (`en-GB` → `en`) part comme `locale` de l'intake, la langue des courriels de suivi ; une langue que l'intake ne parle pas (hors `UserLanguage`) n'est pas envoyée.
49
- - **`onFeedbackSent`** : rappel du front, appelé pour chaque retour enregistré, après le ticket (créé, sauté ou en échec).
50
- - **Contact (#285 F §7).** Sous `AuthProvider`, `AbyssRum.setContact({ email, name })` reçoit l'e-mail et l'alias de l'utilisateur connecté, `null` à la déconnexion, rien pendant le chargement de la session. Le SDK le garde en mémoire, jamais dans la télémétrie : il pré-remplit « Réponse à … » du signalement et ne part qu'avec un retour. Avec `config={null}`, aucun contact n'est donné.
51
- - **Thème (#285 F §6.4).** Monté sous le `ThemeProvider` MUI du front, le provider passe à `AbyssRum.setTheme` l'accent (`palette.primary.main`), le rayon (`shape.borderRadius`, borné à 0–48 px) et le mode (`palette.mode`) ; un changement de mode est suivi. Les variables CSS `--abyss-monitor-accent` et `--abyss-monitor-radius` de la page, et l'apparence enregistrée sur une demande de retour, priment.
52
- - **« Signaler un problème » (#285 F §7).** Avec une `config` non nulle, le provider offre le signalement du SDK aux menus de compte du core placés dessous : `AccountMenu` (après les entrées de l'hôte) et le `AbyssLayoutMenu` legacy (après Facturation) montrent l'entrée « Signaler un problème » / « Report a problem », qui ferme le menu et appelle `AbyssRum.showReportDialog({ locale })` dans la langue du front (`en*` → `RumReportLocale.EN`, sinon `RumReportLocale.FR`). Sans provider ou avec `config={null}`, l'entrée n'existe pas. Elle n'apparaît que tant que `AbyssRum.isReportAvailable()` est vrai — SDK démarré, configuration de l'environnement reçue avec les retours activés (réglage « Retours utilisateurs » dans Monitor) — et le provider la réévalue à chaque `AbyssRum.onConfigChange` : absente avant la réponse de configuration et quand les retours sont coupés.
53
- - **Actions clés (#285 F).** `trackKeyAction(AbyssKeyActionEvent.X)` enregistre, au point de succès d'une action du front, une action RUM nommée d'après l'événement du catalogue (`board.card.completed`) : une demande de retour déclenchée par une action s'y règle. Sans RUM démarré, l'appel ne fait rien et ne lève jamais.
54
- - **Erreurs de rendu.** `AbyssErrorBoundary` envoie l'erreur qu'il attrape à `AbyssRum.captureError(error, { source: 'error-boundary' })` ; sans RUM démarré, l'appel ne fait rien.
55
-
56
- ### Construire les options : `buildAbyssRumProviderConfig`
57
-
58
- Les fronts Abyss ne recopient pas leurs options : ils passent leurs valeurs de config brutes (chaîne vide = absente) au constructeur partagé, qui rend `AbyssRumProviderConfig | null`.
59
-
60
- ```ts
61
- import { buildAbyssRumProviderConfig } from '@abyss-project/commons-front-core';
62
-
63
- export const buildRumOptions = () =>
64
- buildAbyssRumProviderConfig({
65
- token: config.app.abyssMonitor.rumToken,
66
- applicationId: config.app.abyssMonitor.applicationId,
67
- monitorApiUrl: config.app.abyssMonitor.api,
68
- apiUrl: config.app.abyssCloud.api, // l'API du front : relais `/_t` et origine instrumentée
69
- mainApiUrl: config.app.abyss.api, // l'API d'abyss-main : origine instrumentée
70
- release: config.app.abyssMonitor.release,
71
- routeTemplates: CLOUD_ROUTE_TEMPLATES, // gabarits complets du routeur
72
- appName: 'AbyssCloud',
73
- mainFrontUrl: config.app.abyss.site, // la page de session vit dans le front d'abyss-main
74
- feedbackIntakeSlug: config.app.abyssMonitor.feedbackIntakeSlug,
75
- feedbackSectionId: config.app.abyssMonitor.feedbackSectionId,
76
- organizationId: config.app.abyssMonitor.organizationId,
77
- projectId: config.app.abyssMonitor.projectId,
78
- locale: () => currentLanguage(),
79
- });
80
- ```
81
-
82
- - **`null`** sans jeton, application, API Monitor, API du front ou API d'abyss-main (ou si l'une des trois URL n'en est pas une) : rien n'est installé.
83
- - **Relais et corrélation** : `proxyUrl` = origine de `apiUrl` + `/_t` ; `instrumentedOrigins` = origines de `apiUrl` et `mainApiUrl` (une seule fois si c'est la même), plus celle de Monitor avec `instrumentMonitorApi: true` (front d'abyss-main, qui appelle Monitor lui-même).
84
- - **Routes** : `routeResolver` = `createRouteResolver(routeTemplates)`.
85
- - **Ticket de retour** posé seulement quand l'intake, sa section, l'organisation, le projet et `mainFrontUrl` sont là ; son lien est `abyssMainRumSessionPath`, à l'instant du retour en secondes entières.
86
-
87
- ### Gabarits de route : `createRouteResolver(patterns)`
88
-
89
- `createRouteResolver(patterns: readonly string[]): (location: Location) => string` donne au SDK le gabarit de la route (`/org/:orgId/boards/:boardId`), que le SDK masque ensuite comme toute URL. Les gabarits sont **complets** (routes imbriquées comprises) et classés comme react-router les classe (`matchRoutes`) : un segment statique l'emporte sur un paramètre, un paramètre sur un `*`, quel que soit l'ordre de la liste. Sans correspondance : `location.pathname`.
90
-
91
- ### Page d'une session : `abyssMainRumSessionPath`
92
-
93
- `ABYSS_MAIN_RUM_SESSION_ROUTE` (`/org/:orgId/project/:projectId/application/:applicationId/monitor/rum/sessions/:sessionId`) est la seule source du chemin de la page d'une session dans le front d'abyss-main, qui le monte. `abyssMainRumSessionPath({ orgId, projectId, applicationId }, sessionId, t?)` le remplit (id de session encodé) et ajoute `?t=` en secondes entières, jamais négatif.
94
-
95
- ## Changements visibles
96
-
97
- ### 10.1.0
98
-
99
- Zone 4c-1 de la refonte du design system (carte #286) : les éditeurs Markdown et PDF sur le design system.
100
-
101
- - **Nouvelle entrée `@abyss-project/commons-front-core/editors`** : `MarkdownEditor`, `PdfEditor`, `PdfOperationType`
102
- et les types du PDF. Ils ne sont pas sur l'entrée racine, pour que pdf.js, pdf-lib et Crepe ne pèsent pas sur les
103
- applications qui ne les utilisent pas (ADR-0212). Le worker de pdf.js se charge à la première ouverture d'un PDF.
104
- - **`MarkdownEditor`** : mêmes props qu'`AbyssMarkdownEditor`, moteur Crepe gardé, couleurs et polices des jetons,
105
- libellés de Crepe traduits, poignée de 44 px au toucher. Les classes `.milkdown` et `.ProseMirror` ne changent pas.
106
- - **`PdfEditor`** : mêmes props que l'éditeur legacy ; barre regroupée en six groupes, page blanche dans les deux
107
- thèmes, couleurs d'annotation fixes (`pdf-colors`). Les opérations déjà enregistrées se rejouent à l'identique.
108
- - **Legacy** : `AbyssMarkdownEditor` et `PdfEditor` restent sous `/legacy` jusqu'à la zone 4c-2 ; le moteur du PDF
109
- legacy est désormais celui de `/editors` (comportement inchangé).
110
- - **Épinglage de `@abyss-project/main`** : inchangé par rapport à la 10.0.0.
111
-
112
- ### 9.6.0
113
-
114
- Correctifs de la zone 4b (carte #286), relevés par son e2e responsive.
115
-
116
- - **`Drawer`, `BottomSheet`** : sous 768 px, le bouton de fermeture fait 44×44 px au moins (il en faisait 32 sous le
117
- thème legacy, qui garde ses boutons icône à leur taille de bureau). `AnchoredPanel` en profite : sous 768 px sa
118
- feuille est une `BottomSheet`, dont c'est le bouton « Fermer ». Au-dessus, le popover garde son bouton d'origine.
119
- - **`InvoiceDetailView`** (venu de la carte #285, livraison E) : ne lit plus aucun membre de `@abyss-project/main` à
120
- l'évaluation du paquet (libellés des lignes de déduction, badge de statut), ce que `load-safety.spec.ts` vérifie.
121
- Rendu inchangé.
122
- - **Épinglage de `@abyss-project/main`** : le `workspace:*` du dépôt devient, dans le paquet publié, la version
123
- exacte de main, ici **19.0.0**. Un hôte qui installe ce core doit être sur `@abyss-project/main` 19.0.0.
124
-
125
- ### 9.5.1
126
-
127
- - **`testId` sur `TabItem` et `MenuItem`** : rendu en `data-testid` sur l'élément interactif (`role="tab"`,
128
- `role="menuitem"`), absent sans lui. `Menu` accepte aussi `testId` sur son conteneur. Les e2e des hôtes lisent ces
129
- identifiants, que `Tabs` et `Menu` ne transmettaient pas.
130
- - **`Kbd` dans les déclarations publiées** : son type est écrit à la main (un composant de `kbd`), car le type déduit
131
- ne pouvait pas être nommé dans les `.d.ts` et `Kbd` en était absent, bien que la racine l'exporte.
132
-
133
- ### 9.5.0
134
-
135
- Éditeurs des outils du front principal sur le design system (carte #286, zone 4b). Pièces nouvelles, chacune documentée
136
- dans le `README.md` de son dossier et montrée dans le catalogue.
137
-
138
- - **`AnchoredPanel`** (`layers`) : petit formulaire ou sélecteur posé contre son déclencheur (`anchorEl`, `open`,
139
- `onClose`, `title`, `placement`, `width`). À partir de 768 px, un popover au style de `Menu` (surface `bg.surface`,
140
- filet `border.subtle`, ombre `elevations.overlay`) avec titre et bouton « Fermer » ; en dessous, une `BottomSheet`.
141
- Focus piégé, `Escape` et clic hors du panneau ferment, le focus revient au déclencheur. Il porte des champs, pas
142
- des actions (`Menu`).
143
- - **`Kbd`** (`layers`) : l'indication de touche de `Menu` et de `CommandPalette` est exportée de la racine, rendu
144
- inchangé.
145
- - **Couleurs de création d'un canevas** (`theme`) : `CANVAS_NEUTRAL_INK`, `CANVAS_COMMENT_FILL`, `CANVAS_COMMENT_INK` et
146
- `CANVAS_SHAPE_STROKE`, écrites en dur à côté de `CHOICE_SWATCHES`. Ce qu'un canevas donne à une forme ou à un texte
147
- qu'un utilisateur crée : la couleur est enregistrée avec l'objet, identique pour tous les lecteurs et lisible sur
148
- le fond `bg.canvas` clair comme sur le sombre (3:1 au moins ; 4,5:1 pour l'encre du commentaire sur son fond).
149
- - **Traductions** : clé `ds.layers.anchored-panel.close` (FR et EN).
150
-
151
- ### 9.4.0
152
-
153
- Tickets du programme Abyss Founders (carte #285, livraison D). Détail dans [`src/legacy/components/Support/README.md`](src/legacy/components/Support/README.md).
154
-
155
- - **`SupportMessageThread`** : un message système (`systemEvent`, sans auteur) s'affiche comme un avis centré dont le texte vient des traductions `support.system.<ÉVÉNEMENT>` ; un événement réservé à l'admin (`isAdminNote`) n'est montré qu'aux admins, marqué « Note admin ».
156
- - **`SupportTicketCreateStepper`** : la catégorie `FUNDING_PROGRAMME` n'est jamais proposée ; reçue par `initialValues`, elle est vidée et `onRedirectedCategory` est appelé pour envoyer l'utilisateur vers la page Programme.
157
- - **`SupportCategorySelect`, `SupportSidebar`** : `FUNDING_PROGRAMME` n'est proposée ni dans le champ catégorie du formulaire de création ni dans la recatégorisation admin ; un ticket de cette catégorie garde sa catégorie (chip sans champ). Le filtre multiple la propose toujours.
158
- - **Traductions** : `support.category.FUNDING_PROGRAMME`, `support.system.*` (dont `REQUEST_WITHDRAWN` et `ENVELOPE_EXPIRED`), FR et EN.
159
-
160
- ### 9.3.1 à 9.3.3
161
-
162
- Correctifs de la zone 4a (carte #286), relevés par son e2e responsive et sa revue finale.
163
-
164
- - **9.3.1, `CopyField`** : sous 768 px, le bouton d'affichage fait 44×44 px et le bouton de copie 44 px de haut.
165
- - **9.3.2, `DropZone`** : la limite s'écrit nombre, espace insécable, unité (« 2,00 Go »).
166
- - **9.3.3, `FormField`** : le libellé est un `FormLabel` statique au-dessus du champ, quel que soit le thème MUI chargé
167
- (la surcharge legacy de `MuiInputLabel-outlined` le plaçait dans le cadre).
168
- - **9.3.3, `KeyValueList`** : `stackOnMobile` empile libellé et valeur sous 768 px.
169
-
170
- ### 9.3.0
171
-
172
- Pages des outils du front principal sur le design system (carte #286, zone 4a). Pièces nouvelles et évolutions,
173
- chacune documentée dans le `README.md` de son dossier et montrée dans le catalogue.
174
-
175
- - **`BarChart`** (`data`) : barres Nivo sous `abyssNivoTheme`, groupées ou empilées (`stacked`), verticales ou
176
- horizontales (`BarChartLayout`) ; une série par `id`, une catégorie par groupe, une clé absente n'est pas une barre ;
177
- infobulle à la valeur propre de la série ; légende au-delà d'une série ; figure nommée et tableau des valeurs pour
178
- les lecteurs d'écran ; « Aucune donnée à afficher » sans valeur. Graduations de l'axe des catégories selon la
179
- largeur mesurée. Remplace `AbyssBarChart`.
180
- - **Ton sémantique des séries** (`data`) : `ChartSeriesTone` (`Success`, `Warning`, `Danger`, `Info`, `Neutral`) et
181
- `seriesColorTokens`, partagés par `LineChart` et `BarChart`. Une série à ton prend le jeton `status.*` de son ton ;
182
- les séries sans ton gardent la palette `data.series.*` dans leur ordre (ADR-0174, avenant 9.3.0).
183
- - **`LineChart`** (`data`) : `tone` par série et `stacked` (aires empilées depuis zéro, une abscisse absente d'une
184
- série comptée à zéro ; infobulle et tableau gardent les valeurs propres). Le reste du contrat 9.2.0 est inchangé.
185
- - **`AmbientBackground`** (`structure`) : fond de décor animé et sobre (lueurs d'`accent` et de `data.series.5` en
186
- `color-mix` sur les variables `--abyss-*`), `aria-hidden`, hors du flux, `Viewport` ou `Container` ; figé sous
187
- `prefers-reduced-motion`, sous 768 px et avec `paused`, état exposé par `data-motion`. Remplace `WaterParticles`.
188
- - **`ConfirmDialogTone.Warning`** (`layers`) : bouton en `status.warning`, texte dans l'encre `paper`/`paper.on` la
189
- plus contrastée, focus initial sur « Annuler » ; accepté par `useConfirmDialog`.
190
- - **`DataTable`** (`data`) : `label` facultatif, nom accessible de la table et de la liste mobile.
191
- - **Palette de choix** (`theme`) : `CHOICE_SWATCHES`, douze teintes catégorielles (une tous les 30° depuis la teinte
192
- de marque, `0.72 0.12` en OKLCH), valeurs hexadécimales stables, lisibles sous l'encre `paper.on` à 4,5:1 au moins
193
- dans les deux thèmes. **`ColorField`** les propose quand l'hôte ne passe pas `swatches` (devenu facultatif).
194
- - **Utilitaires sortis de `legacy/`** : `getFileIcon` et `getFileColor` sont exportés de la racine ; `getFileColor`
195
- y rend une couleur des jetons, `var(--abyss-data-series-n)` ou `var(--abyss-text-muted)`.
196
- - **Traductions** : clés `ds.data.bar-chart.*` (FR et EN).
197
-
198
- ### 9.2.0
199
-
200
- Organisation et projet du front principal sur le design system (carte #286, zone 3). Pièces nouvelles et évolutions,
201
- chacune documentée dans le `README.md` de son dossier et montrée dans le catalogue.
202
-
203
- - **`AvatarGroup`** (`meaning`) : pile d'avatars nommés, `max` au-delà duquel « +N » est nommé par les noms restants (`intl.formatList`) et les liste en infobulle ; aucun élément interactif. Remplace `UserAvatarList`.
204
- - **`TeamAvatar`** (`meaning`) : initiale d'équipe sur sa couleur, encre `paper` ou `paper.on` la plus contrastée ; une couleur absente ou illisible (`CSS.supports`) donne la teinte neutre au lieu d'une exception (dette `DS-TEAM-COLOR`).
205
- - **`Pagination`** (`data`) : précédent, numéros de page avec ellipses (sept places fixes), suivant ; page courante
206
- en `aria-current="page"`, bornes désactivées, rien sous deux pages ; sous 768 px, précédent, « Page x sur y »,
207
- suivant, cibles de 44 px.
208
- - **`LineChart`** (`data`) : courbes Nivo sous `abyssNivoTheme`, échelle de temps ou linéaire, aire facultative ;
209
- couleurs prises dans l'ordre de la palette de séries, jamais passées par l'hôte ; légende au-delà d'une série ;
210
- figure nommée et tableau des valeurs pour les lecteurs d'écran ; « Aucune donnée à afficher » sans point.
211
- Graduations de l'axe x selon la largeur mesurée du graphique (et non celle de l'écran) : pas le plus fin, jamais plus
212
- fin que les données, dont les libellés mono gardent `space[8]` entre eux ; un libellé qui déborderait des marges
213
- n'est pas affiché.
214
- - **Palette de séries** (`theme`) : jetons `data.series.1` à `data.series.6` (et `--abyss-data-series-*`), ordre
215
- exporté par `DATA_SERIES_TOKENS` ; luminosité et chroma égales, 3:1 au moins sur les fonds (ADR-0174, avenant).
216
- - **`UserPicker`** (`inputs`) : choix simple ou multiple d'utilisateurs (`{ id, name, email, pictureUrl }`), avatar,
217
- nom et e-mail par option ; filtre local sur le nom et l'e-mail, ou recherche serveur par `onSearch` avec `loading` ;
218
- `disabledIds` ; en multiple, puces parcourues à la flèche gauche et retirées par Retour arrière ou Suppr ; sous
219
- 768 px, 44 px par option, puces de 44 px de haut dont la croix de retrait est un carré tactile, et texte du champ
220
- jamais plus étroit que 44 px quand les puces remplissent la ligne.
221
- - **`CompanySearchField`** (`inputs`) : contrat de `CompanySearchAutocomplete` (Pappers, `onSelect(PappersCompany)`,
222
- erreur distincte d'une réponse vide, date de création dans la langue de l'utilisateur) sur `FormField` et les jetons
223
- du core ; temporisation annulée au démontage, réponse dépassée ignorée.
224
- - **Types sortis de `legacy/`** : `PappersCompany` et `CurrentFamilyInfo` (avec `CurrentFamilyStatus`) sont exportés de
225
- la racine ; `/legacy` les réexporte.
226
- - **Traductions** : clés `ds.inputs.user-picker.*` et `ds.inputs.company-search-field.*` (FR et EN).
227
- - **`EntityImageField`** (`inputs`) : image d'entité changée sur place, `EntityImageVariant.Avatar` (pastille d'appareil photo, `EntityImageShape.Round` ou `Square`) ou `Banner` (bouton en surimpression) ; sélecteur de l'appareil, ou menu d'`ImportButton` avec `cloudImport` ; envoi indiqué, annoncé, et bloquant.
228
- - **`useConfirmDialog`** et **`ConfirmDialogProvider`** (`layers`) : `confirm(options)` renvoie `Promise<boolean>` et ouvre le `ConfirmDialog` ; une demande à la fois, les suivantes attendent ; hors du fournisseur, une erreur qui le nomme.
229
- - **`CopyField.loadValue`** : la valeur n'est demandée qu'au premier « Afficher » ou « Copier », puis gardée ; chargement sur le bouton, échec annoncé et rejouable. `value` et `loadValue` sont exclusifs.
230
- - **`Section tone`** : `SectionTone.Danger` met le titre et un filet en `status.danger` (zones de danger).
231
- - **`DataTable`, liste mobile** : sous 768 px, chaque contrôle de la colonne `trailing` (lien, bouton, `role="button"`, `role="link"`, `role="menuitem"`) offre une cible de 44 × 44 (`densityValues.touchTarget`), même rendu en `size="small"` par l'hôte ; rien ne change à partir de 768 px.
232
-
233
- ### 9.1.1
234
-
235
- - **`useServiceTour`** : sous un `AbyssCookieConsentProvider`, une première visite attend que le bandeau de cookies
236
- soit tranché. Sur mobile, le bandeau recouvrait la feuille de la visite et bloquait « Suivant ». `start()` n'attend pas.
237
- - **`ProductTour`** : la découpe suit sa cible à chaque image tant que la visite est ouverte. Une cible déplacée sans
238
- redimensionnement ni défilement (police web chargée au-dessus d'elle) laissait la découpe 20 px à côté.
239
-
240
- ### 9.1.0
241
-
242
- - **`ProductTour`** (`layers`) : visite guidée d'un service (carte #285, spec §6.7). Bulle ancrée sur l'élément
243
- `data-tour`, page voilée autour d'une découpe, compteur et points d'étape, « Suivant » / « Terminer » et « Passer la
244
- visite » ; Échap passe la visite, les flèches changent d'étape, focus piégé ; feuille du bas sous 768 px (boutons de
245
- 44 px) ; sans mouvement sous `prefers-reduced-motion`. Une étape dont la cible manque s'affiche au centre d'un écran
246
- voilé.
247
- - **`useServiceTour(service, { eligible })`** : ouvre la visite à la première visite (aucun état
248
- `users.settings.serviceTours[service]`), la relance à la demande (`start`) et écrit `completedAt` ou `skippedAt` par
249
- `AbyssCore.sdk.user.updateSettings`.
250
- - **Menu « Famille » du legacy** (`buildAbyssFamilyMenuSection`) : sans famille, l'entrée mène à `/family/new`
251
- d'abyss-main au lieu de `/onboarding`.
252
- - **Traductions** : `ds.layers.product-tour.*` (FR et EN).
253
-
254
- ### 8.3.0
255
-
256
- Compte et facturation du front principal sur le design system (carte #286, zone 2). Sept pièces nouvelles, chacune
257
- documentée dans le `README.md` de son dossier et montrée dans le catalogue.
258
-
259
- - **`Tabs`** (`structure`) : rangée d'onglets liés aux routes ou boutons, variantes `TabsVariant.Primary` et
260
- `Secondary`, un seul arrêt de tabulation, flèches, Début et Fin ; défilement horizontal avec fondu tant qu'il reste
261
- des onglets à droite (`useScrollOverflowCue`), 44 px de haut sous 768 px.
262
- - **`Callout`** (`states`) : bandeau `CalloutSeverity.Info`, `Success`, `Warning`, `Danger`, avec titre, action,
263
- fermeture et icône facultatifs ; l'action passe sous le texte sous 768 px.
264
- - **`FormField`** (`inputs`) : libellé, aide et erreur autour d'un `OutlinedInput`, `InputBase` ou `Select` ; `id`,
265
- `aria-describedby` et `labelId` reliés, erreur et obligation passées au contrôle.
266
- - **`SettingsRow`** (`inputs`) : libellé, description et contrôle à droite ; empilée sous 768 px.
267
- - **`Switch` du thème** : sous 768 px, la zone tactile de tout interrupteur (38 px dessinés) est portée à 44 px de
268
- haut.
269
- - **`UsageMeter`** (`data`) : consommation sur un plafond, seuils en parts du plafond, jauge `meter` ; sans plafond, la
270
- valeur seule.
271
- - **`InvoiceDetailView`** (`data`) : corps de présentation du détail d'une facture (lignes, déductions, gestes, prise en
272
- charge des programmes, totaux), partagé par le front client et le back-office ; données et actions en props.
273
- - **`CopyField`** (`inputs`) : valeur masquable et copiable, résultat de la copie annoncé dans une région vivante.
274
- - **`NumberField`** (`inputs`) : nombre saisi et affiché avec les séparateurs de la langue, « , » ou « . » lus comme
275
- marque décimale, borné (`min`) et arrondi (`decimals`) en sortie du champ ; remplace `AbyssNumberField` du legacy
276
- pour le design system.
277
- - **`DataTable`** : deux options de colonne, `wrap` (la cellule passe à la ligne au lieu d'être coupée) et
278
- `hideHeader` (en-tête lu par les technologies d'assistance, non dessiné, pour une colonne d'actions en icône).
279
- - **`Tabs`** : l'onglet choisi est ramené à l'écran aussi quand la rangée ou un onglet change de taille.
280
- - **Traductions** : clés `ds.states.callout.*`, `ds.inputs.copy-field.*` et `ds.data.usage-meter.*` (FR et EN).
281
-
282
- Pièces que les pages de compte importaient encore de `/legacy`, refaites dans le nouveau système (les copies legacy
283
- restent pour les hôtes legacy) :
284
-
285
- - **`UserAvatar`, `OrganizationAvatar`, `ProjectAvatar`** (`meaning`) : photo ou logo, sinon l'initiale ; taille
286
- `size` en px. La fiche de profil au clic du legacy n'est pas reprise (sans appelant).
287
- - **`ContextSelector`** (`inputs`) : mon espace, puis un groupe par organisation et ses projets ;
288
- `ContextValue.kind` est l'énumération `ContextKind`.
289
- - **`DropZone`** (`inputs`) : dépôt et bouton de choix, refus (taille, type, nombre) écrits sous la zone, entrée
290
- AbyssCloud avec `cloudImport`.
291
- - **`ImportButton`** (`inputs`) : menu appareil, lien (adresse vérifiée, échec dit), AbyssCloud.
292
- - **`CloudImport`**, **`ImportFromCloudModal`**, **`QRCodeModal`** (`business`) : le sélecteur AbyssCloud, sa
293
- modale (`open`, `onClose`, `onImport`), et un lien en QR code (`open` au lieu de `isOpen`).
294
- - **Jetons `paper` et `paper.on`** : une page claire et son encre dans les deux thèmes, pour ce qui est dessiné à
295
- l'encre sombre (code QR, signature en PNG transparent). ADR-0174 §3 complété.
296
- - **Logique pure partagée** : `deriveQuotaOfferState`, `QuotaOfferState`, `offersAction`, `shouldSuggestModule`
297
- (table de décision de l'offre de quota) sortent de `legacy/` et s'exportent de la racine ; `/legacy` les
298
- réexporte toujours. `isAcceptedFile` (filtre `accept` du sélecteur cloud) passe aussi hors de `legacy/`.
299
- - **Traductions** : `ds.inputs.context-selector.*`, `ds.inputs.drop-zone.*`, `ds.inputs.import-button.*`,
300
- `ds.business.cloud-import.*`, `ds.business.qr-code.*` (FR et EN).
301
-
302
- ### 8.2.0
303
-
304
- Shell et tableaux de bord du front principal sur le design system (carte #286, zone 1).
305
-
306
- - **Nouveau** : `AppShell` prend `chromeless` (plein écran sans cadre), les entrées `external` et `action`,
307
- l'action de section (`NavSection.action`) et les entrées internes du pied ; `NotificationsMenu`, `AccountMenu`,
308
- `DesignCssVariables` et `focusRing` sont exportés ; `CommandPalette` gagne icônes, sous-titres, récents, sources
309
- asynchrones et ouverture filtrée.
310
- - **Paliers** : les composants du design system basculent à 768 et 1200 px (`designMedia`, `useDesignBreakpoint`)
311
- quel que soit le provider. Sous le thème legacy, l'`AppShell` montre le rail dès 768 px (et non plus à 900), la
312
- `Modal` une fenêtre dès 768 px, et la bannière MFA passe son bouton sous le texte quand il ne tient plus à côté.
313
- - **Largeur de `Drawer` et de `Toast` sous le thème legacy** : la largeur par défaut passe de 600 à 480 px (palier
314
- `sm` des jetons, et non plus le `sm` de MUI). Un hôte qui comptait sur 600 px passe `width` explicitement au
315
- `Drawer`.
316
- - **Largeur de `Modal` et de `CommandPalette` sous le thème legacy** : elle reste tirée des `theme.breakpoints` de
317
- MUI (prop `size` de la `Modal` passée à `maxWidth`, `sm` pour la palette). Sous le thème legacy, `md` vaut 900 px
318
- et `sm` 600 px, contre 768 et 480 sous `AbyssThemeProvider` : la même `Modal` est donc plus large chez un hôte
319
- legacy. Suivi : `DS-LEGACY-WIDTHS` dans `docs/internal/TECH-DEBT.md` d'abyss-main.
320
- - **Sélecteur d'espace** : un espace qui porte le nom de son type (« Espace personnel ») n'a plus de seconde ligne
321
- répétant ce type.
322
- - **Navigation** : la liste des sections garde une barre de défilement fine et visible quand elle dépasse la
323
- hauteur de la fenêtre.
324
- - **`PageState`** : `forbidden.message` remplace la description générique de l’accès refusé, pour nommer à qui
325
- demander l’accès (organisation, projet).
326
- - **`PageState`** : le bloc d’état passe son action sous le texte dès que son emplacement fait moins de 512 px
327
- (colonne latérale), et plus seulement sous 768 px d’écran.
328
- - **`PageHeader`** : de 768 px à la largeur du bureau, les actions passent sous le titre dès qu'elles ne tiennent
329
- plus à côté d'un titre de 256 px.
330
-
331
-
332
- ## Support
333
-
334
- Pour toute demande, ouvrir un ticket depuis [l'application Abyss](https://app.abyss-project.fr/dashboard/account/tickets/create).
1
+ # Abyss Commons Front Core
2
+
3
+ `@abyss-project/commons-front-core`
4
+
5
+ Composants React, hooks, design system et traductions partagés par les frontends Abyss.
6
+
7
+ _Shared React components, hooks, design system and translations for Abyss frontends._
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @abyss-project/commons-front-core
13
+ # or
14
+ pnpm add @abyss-project/commons-front-core
15
+ ```
16
+
17
+ ## Liens
18
+
19
+ - **Documentation** : [https://docs.abyss-project.fr/abyss-project](https://docs.abyss-project.fr/abyss-project)
20
+ - **NPM** : [@abyss-project/commons-front-core](https://www.npmjs.com/package/@abyss-project/commons-front-core)
21
+ - **Application Abyss** : [app.abyss-project.fr](https://app.abyss-project.fr)
22
+ - **Statut des services** : [status.abyss-project.fr](https://status.abyss-project.fr)
23
+
24
+ ## Usage
25
+
26
+ Voir la [documentation produit](https://docs.abyss-project.fr/abyss-project) pour les guides d'utilisation, la configuration du Core, les exemples d'appel et la référence des permissions.
27
+
28
+ ## RUM
29
+
30
+ Le RUM navigateur d'un front (SDK `@abyss-project/monitor-browser`, peer `^1.3.2` ; `setContact` et `setTheme` demandent la version publiée par #285 F) se démarre par `AbyssRumProvider`, monté **sous** `AbyssCookieConsentProvider`, sous le `ThemeProvider` MUI et, quand le front en a un, sous `AuthProvider` :
31
+
32
+ ```tsx
33
+ <AbyssErrorBoundary appName="abyss-cloud">
34
+ <AuthProvider client={authClient}>
35
+ <AbyssCookieConsentProvider consentVersion={COOKIE_CONSENT_VERSION} isAuthenticated={isAuthenticated}>
36
+ <AbyssRumProvider config={buildRumOptions()}>
37
+ <App />
38
+ </AbyssRumProvider>
39
+ </AbyssCookieConsentProvider>
40
+ </AuthProvider>
41
+ </AbyssErrorBoundary>
42
+ ```
43
+
44
+ - **`config` est requise** (raison de la majeure 8.0.0 : aucun front ne peut oublier son RUM). `config={null}` désactive le RUM explicitement : rien n'est installé. Elle reçoit les options de `AbyssRum.init` (`apiUrl`, `proxyUrl`, `applicationId`, `token`, `release`, `instrumentedOrigins`, `routeResolver`…), sauf `consent`, que le provider fournit.
45
+ - **Une seule initialisation.** `AbyssRum.init` est appelé au premier commit avec une `config` non nulle, une fois, StrictMode compris. Une `config` qui change ensuite est **ignorée** : le SDK vit autant que la page.
46
+ - **Consentement.** Le replay exige la catégorie analytics de `AbyssCookieConsentProvider`, relue à chaque décision du SDK : un consentement donné ou retiré après le démarrage est suivi. Sans provider de consentement, analytics vaut refusé.
47
+ - **Acteur.** Sous `AuthProvider`, l'acteur de la session est l'id de l'utilisateur connecté, `null` à la déconnexion, inchangé pendant le chargement de la session. Sans `AuthProvider`, aucun acteur.
48
+ - **`feedbackTicket`** (`intakeSlug`, `internalTicketSectionId`, `appName`, `sessionUrl(sessionId, offsetMs)`, `locale?()`) : chaque retour utilisateur enregistré par Monitor devient un ticket Internal Tickets, par l'intake public d'abyss-console (`fileInternalTicketIntake`, peer `@abyss-project/console` `^12.4.0`, configuré par `AbyssConsoleCore.setConfig` du front). Titre `[<appName>] Retour utilisateur` ; description : le message, l'e-mail, la route et le lien vers la session. Le déclarant est l'e-mail saisi, sinon celui de l'utilisateur connecté ; un retour anonyme sans e-mail ne crée aucun ticket et reste dans Monitor. Un échec de création est journalisé (`console.warn`) et avalé. `locale()` est relue à chaque retour : sa sous-étiquette primaire (`en-GB` → `en`) part comme `locale` de l'intake, la langue des courriels de suivi ; une langue que l'intake ne parle pas (hors `UserLanguage`) n'est pas envoyée.
49
+ - **`onFeedbackSent`** : rappel du front, appelé pour chaque retour enregistré, après le ticket (créé, sauté ou en échec).
50
+ - **Contact (#285 F §7).** Sous `AuthProvider`, `AbyssRum.setContact({ email, name })` reçoit l'e-mail et l'alias de l'utilisateur connecté, `null` à la déconnexion, rien pendant le chargement de la session. Le SDK le garde en mémoire, jamais dans la télémétrie : il pré-remplit « Réponse à … » du signalement et ne part qu'avec un retour. Avec `config={null}`, aucun contact n'est donné.
51
+ - **Thème (#285 F §6.4).** Monté sous le `ThemeProvider` MUI du front, le provider passe à `AbyssRum.setTheme` l'accent (`palette.primary.main`), le rayon (`shape.borderRadius`, borné à 0–48 px) et le mode (`palette.mode`) ; un changement de mode est suivi. Les variables CSS `--abyss-monitor-accent` et `--abyss-monitor-radius` de la page, et l'apparence enregistrée sur une demande de retour, priment.
52
+ - **« Signaler un problème » (#285 F §7).** Avec une `config` non nulle, le provider offre le signalement du SDK aux menus de compte du core placés dessous : `AccountMenu` (après les entrées de l'hôte) et le `AbyssLayoutMenu` legacy (après Facturation) montrent l'entrée « Signaler un problème » / « Report a problem », qui ferme le menu et appelle `AbyssRum.showReportDialog({ locale })` dans la langue du front (`en*` → `RumReportLocale.EN`, sinon `RumReportLocale.FR`). Sans provider ou avec `config={null}`, l'entrée n'existe pas. Elle n'apparaît que tant que `AbyssRum.isReportAvailable()` est vrai — SDK démarré, configuration de l'environnement reçue avec les retours activés (réglage « Retours utilisateurs » dans Monitor) — et le provider la réévalue à chaque `AbyssRum.onConfigChange` : absente avant la réponse de configuration et quand les retours sont coupés.
53
+ - **Actions clés (#285 F).** `trackKeyAction(AbyssKeyActionEvent.X)` enregistre, au point de succès d'une action du front, une action RUM nommée d'après l'événement du catalogue (`board.card.completed`) : une demande de retour déclenchée par une action s'y règle. Sans RUM démarré, l'appel ne fait rien et ne lève jamais.
54
+ - **Erreurs de rendu.** `AbyssErrorBoundary` envoie l'erreur qu'il attrape à `AbyssRum.captureError(error, { source: 'error-boundary' })` ; sans RUM démarré, l'appel ne fait rien.
55
+
56
+ ### Construire les options : `buildAbyssRumProviderConfig`
57
+
58
+ Les fronts Abyss ne recopient pas leurs options : ils passent leurs valeurs de config brutes (chaîne vide = absente) au constructeur partagé, qui rend `AbyssRumProviderConfig | null`.
59
+
60
+ ```ts
61
+ import { buildAbyssRumProviderConfig } from '@abyss-project/commons-front-core';
62
+
63
+ export const buildRumOptions = () =>
64
+ buildAbyssRumProviderConfig({
65
+ token: config.app.abyssMonitor.rumToken,
66
+ applicationId: config.app.abyssMonitor.applicationId,
67
+ monitorApiUrl: config.app.abyssMonitor.api,
68
+ apiUrl: config.app.abyssCloud.api, // l'API du front : relais `/_t` et origine instrumentée
69
+ mainApiUrl: config.app.abyss.api, // l'API d'abyss-main : origine instrumentée
70
+ release: config.app.abyssMonitor.release,
71
+ routeTemplates: CLOUD_ROUTE_TEMPLATES, // gabarits complets du routeur
72
+ appName: 'AbyssCloud',
73
+ mainFrontUrl: config.app.abyss.site, // la page de session vit dans le front d'abyss-main
74
+ feedbackIntakeSlug: config.app.abyssMonitor.feedbackIntakeSlug,
75
+ feedbackSectionId: config.app.abyssMonitor.feedbackSectionId,
76
+ organizationId: config.app.abyssMonitor.organizationId,
77
+ projectId: config.app.abyssMonitor.projectId,
78
+ locale: () => currentLanguage(),
79
+ });
80
+ ```
81
+
82
+ - **`null`** sans jeton, application, API Monitor, API du front ou API d'abyss-main (ou si l'une des trois URL n'en est pas une) : rien n'est installé.
83
+ - **Relais et corrélation** : `proxyUrl` = origine de `apiUrl` + `/_t` ; `instrumentedOrigins` = origines de `apiUrl` et `mainApiUrl` (une seule fois si c'est la même), plus celle de Monitor avec `instrumentMonitorApi: true` (front d'abyss-main, qui appelle Monitor lui-même).
84
+ - **Routes** : `routeResolver` = `createRouteResolver(routeTemplates)`.
85
+ - **Ticket de retour** posé seulement quand l'intake, sa section, l'organisation, le projet et `mainFrontUrl` sont là ; son lien est `abyssMainRumSessionPath`, à l'instant du retour en secondes entières.
86
+
87
+ ### Gabarits de route : `createRouteResolver(patterns)`
88
+
89
+ `createRouteResolver(patterns: readonly string[]): (location: Location) => string` donne au SDK le gabarit de la route (`/org/:orgId/boards/:boardId`), que le SDK masque ensuite comme toute URL. Les gabarits sont **complets** (routes imbriquées comprises) et classés comme react-router les classe (`matchRoutes`) : un segment statique l'emporte sur un paramètre, un paramètre sur un `*`, quel que soit l'ordre de la liste. Sans correspondance : `location.pathname`.
90
+
91
+ ### Page d'une session : `abyssMainRumSessionPath`
92
+
93
+ `ABYSS_MAIN_RUM_SESSION_ROUTE` (`/org/:orgId/project/:projectId/application/:applicationId/monitor/rum/sessions/:sessionId`) est la seule source du chemin de la page d'une session dans le front d'abyss-main, qui le monte. `abyssMainRumSessionPath({ orgId, projectId, applicationId }, sessionId, t?)` le remplit (id de session encodé) et ajoute `?t=` en secondes entières, jamais négatif.
94
+
95
+ ## Changements visibles
96
+
97
+ ### 9.6.0
98
+
99
+ Correctifs de la zone 4b (carte #286), relevés par son e2e responsive.
100
+
101
+ - **`Drawer`, `BottomSheet`** : sous 768 px, le bouton de fermeture fait 44×44 px au moins (il en faisait 32 sous le
102
+ thème legacy, qui garde ses boutons icône à leur taille de bureau). `AnchoredPanel` en profite : sous 768 px sa
103
+ feuille est une `BottomSheet`, dont c'est le bouton « Fermer ». Au-dessus, le popover garde son bouton d'origine.
104
+ - **`InvoiceDetailView`** (venu de la carte #285, livraison E) : ne lit plus aucun membre de `@abyss-project/main` à
105
+ l'évaluation du paquet (libellés des lignes de déduction, badge de statut), ce que `load-safety.spec.ts` vérifie.
106
+ Rendu inchangé.
107
+ - **Épinglage de `@abyss-project/main`** : le `workspace:*` du dépôt devient, dans le paquet publié, la version
108
+ exacte de main, ici **19.0.0**. Un hôte qui installe ce core doit être sur `@abyss-project/main` 19.0.0.
109
+
110
+ ### 9.5.1
111
+
112
+ - **`testId` sur `TabItem` et `MenuItem`** : rendu en `data-testid` sur l'élément interactif (`role="tab"`,
113
+ `role="menuitem"`), absent sans lui. `Menu` accepte aussi `testId` sur son conteneur. Les e2e des hôtes lisent ces
114
+ identifiants, que `Tabs` et `Menu` ne transmettaient pas.
115
+ - **`Kbd` dans les déclarations publiées** : son type est écrit à la main (un composant de `kbd`), car le type déduit
116
+ ne pouvait pas être nommé dans les `.d.ts` et `Kbd` en était absent, bien que la racine l'exporte.
117
+
118
+ ### 9.5.0
119
+
120
+ Éditeurs des outils du front principal sur le design system (carte #286, zone 4b). Pièces nouvelles, chacune documentée
121
+ dans le `README.md` de son dossier et montrée dans le catalogue.
122
+
123
+ - **`AnchoredPanel`** (`layers`) : petit formulaire ou sélecteur posé contre son déclencheur (`anchorEl`, `open`,
124
+ `onClose`, `title`, `placement`, `width`). À partir de 768 px, un popover au style de `Menu` (surface `bg.surface`,
125
+ filet `border.subtle`, ombre `elevations.overlay`) avec titre et bouton « Fermer » ; en dessous, une `BottomSheet`.
126
+ Focus piégé, `Escape` et clic hors du panneau ferment, le focus revient au déclencheur. Il porte des champs, pas
127
+ des actions (`Menu`).
128
+ - **`Kbd`** (`layers`) : l'indication de touche de `Menu` et de `CommandPalette` est exportée de la racine, rendu
129
+ inchangé.
130
+ - **Couleurs de création d'un canevas** (`theme`) : `CANVAS_NEUTRAL_INK`, `CANVAS_COMMENT_FILL`, `CANVAS_COMMENT_INK` et
131
+ `CANVAS_SHAPE_STROKE`, écrites en dur à côté de `CHOICE_SWATCHES`. Ce qu'un canevas donne à une forme ou à un texte
132
+ qu'un utilisateur crée : la couleur est enregistrée avec l'objet, identique pour tous les lecteurs et lisible sur
133
+ le fond `bg.canvas` clair comme sur le sombre (3:1 au moins ; 4,5:1 pour l'encre du commentaire sur son fond).
134
+ - **Traductions** : clé `ds.layers.anchored-panel.close` (FR et EN).
135
+
136
+ ### 9.4.0
137
+
138
+ Tickets du programme Abyss Founders (carte #285, livraison D). Détail dans [`src/legacy/components/Support/README.md`](src/legacy/components/Support/README.md).
139
+
140
+ - **`SupportMessageThread`** : un message système (`systemEvent`, sans auteur) s'affiche comme un avis centré dont le texte vient des traductions `support.system.<ÉVÉNEMENT>` ; un événement réservé à l'admin (`isAdminNote`) n'est montré qu'aux admins, marqué « Note admin ».
141
+ - **`SupportTicketCreateStepper`** : la catégorie `FUNDING_PROGRAMME` n'est jamais proposée ; reçue par `initialValues`, elle est vidée et `onRedirectedCategory` est appelé pour envoyer l'utilisateur vers la page Programme.
142
+ - **`SupportCategorySelect`, `SupportSidebar`** : `FUNDING_PROGRAMME` n'est proposée ni dans le champ catégorie du formulaire de création ni dans la recatégorisation admin ; un ticket de cette catégorie garde sa catégorie (chip sans champ). Le filtre multiple la propose toujours.
143
+ - **Traductions** : `support.category.FUNDING_PROGRAMME`, `support.system.*` (dont `REQUEST_WITHDRAWN` et `ENVELOPE_EXPIRED`), FR et EN.
144
+
145
+ ### 9.3.1 à 9.3.3
146
+
147
+ Correctifs de la zone 4a (carte #286), relevés par son e2e responsive et sa revue finale.
148
+
149
+ - **9.3.1, `CopyField`** : sous 768 px, le bouton d'affichage fait 44×44 px et le bouton de copie 44 px de haut.
150
+ - **9.3.2, `DropZone`** : la limite s'écrit nombre, espace insécable, unité (« 2,00 Go »).
151
+ - **9.3.3, `FormField`** : le libellé est un `FormLabel` statique au-dessus du champ, quel que soit le thème MUI chargé
152
+ (la surcharge legacy de `MuiInputLabel-outlined` le plaçait dans le cadre).
153
+ - **9.3.3, `KeyValueList`** : `stackOnMobile` empile libellé et valeur sous 768 px.
154
+
155
+ ### 9.3.0
156
+
157
+ Pages des outils du front principal sur le design system (carte #286, zone 4a). Pièces nouvelles et évolutions,
158
+ chacune documentée dans le `README.md` de son dossier et montrée dans le catalogue.
159
+
160
+ - **`BarChart`** (`data`) : barres Nivo sous `abyssNivoTheme`, groupées ou empilées (`stacked`), verticales ou
161
+ horizontales (`BarChartLayout`) ; une série par `id`, une catégorie par groupe, une clé absente n'est pas une barre ;
162
+ infobulle à la valeur propre de la série ; légende au-delà d'une série ; figure nommée et tableau des valeurs pour
163
+ les lecteurs d'écran ; « Aucune donnée à afficher » sans valeur. Graduations de l'axe des catégories selon la
164
+ largeur mesurée. Remplace `AbyssBarChart`.
165
+ - **Ton sémantique des séries** (`data`) : `ChartSeriesTone` (`Success`, `Warning`, `Danger`, `Info`, `Neutral`) et
166
+ `seriesColorTokens`, partagés par `LineChart` et `BarChart`. Une série à ton prend le jeton `status.*` de son ton ;
167
+ les séries sans ton gardent la palette `data.series.*` dans leur ordre (ADR-0174, avenant 9.3.0).
168
+ - **`LineChart`** (`data`) : `tone` par série et `stacked` (aires empilées depuis zéro, une abscisse absente d'une
169
+ série comptée à zéro ; infobulle et tableau gardent les valeurs propres). Le reste du contrat 9.2.0 est inchangé.
170
+ - **`AmbientBackground`** (`structure`) : fond de décor animé et sobre (lueurs d'`accent` et de `data.series.5` en
171
+ `color-mix` sur les variables `--abyss-*`), `aria-hidden`, hors du flux, `Viewport` ou `Container` ; figé sous
172
+ `prefers-reduced-motion`, sous 768 px et avec `paused`, état exposé par `data-motion`. Remplace `WaterParticles`.
173
+ - **`ConfirmDialogTone.Warning`** (`layers`) : bouton en `status.warning`, texte dans l'encre `paper`/`paper.on` la
174
+ plus contrastée, focus initial sur « Annuler » ; accepté par `useConfirmDialog`.
175
+ - **`DataTable`** (`data`) : `label` facultatif, nom accessible de la table et de la liste mobile.
176
+ - **Palette de choix** (`theme`) : `CHOICE_SWATCHES`, douze teintes catégorielles (une tous les 30° depuis la teinte
177
+ de marque, `0.72 0.12` en OKLCH), valeurs hexadécimales stables, lisibles sous l'encre `paper.on` à 4,5:1 au moins
178
+ dans les deux thèmes. **`ColorField`** les propose quand l'hôte ne passe pas `swatches` (devenu facultatif).
179
+ - **Utilitaires sortis de `legacy/`** : `getFileIcon` et `getFileColor` sont exportés de la racine ; `getFileColor`
180
+ y rend une couleur des jetons, `var(--abyss-data-series-n)` ou `var(--abyss-text-muted)`.
181
+ - **Traductions** : clés `ds.data.bar-chart.*` (FR et EN).
182
+
183
+ ### 9.2.0
184
+
185
+ Organisation et projet du front principal sur le design system (carte #286, zone 3). Pièces nouvelles et évolutions,
186
+ chacune documentée dans le `README.md` de son dossier et montrée dans le catalogue.
187
+
188
+ - **`AvatarGroup`** (`meaning`) : pile d'avatars nommés, `max` au-delà duquel « +N » est nommé par les noms restants (`intl.formatList`) et les liste en infobulle ; aucun élément interactif. Remplace `UserAvatarList`.
189
+ - **`TeamAvatar`** (`meaning`) : initiale d'équipe sur sa couleur, encre `paper` ou `paper.on` la plus contrastée ; une couleur absente ou illisible (`CSS.supports`) donne la teinte neutre au lieu d'une exception (dette `DS-TEAM-COLOR`).
190
+ - **`Pagination`** (`data`) : précédent, numéros de page avec ellipses (sept places fixes), suivant ; page courante
191
+ en `aria-current="page"`, bornes désactivées, rien sous deux pages ; sous 768 px, précédent, « Page x sur y »,
192
+ suivant, cibles de 44 px.
193
+ - **`LineChart`** (`data`) : courbes Nivo sous `abyssNivoTheme`, échelle de temps ou linéaire, aire facultative ;
194
+ couleurs prises dans l'ordre de la palette de séries, jamais passées par l'hôte ; légende au-delà d'une série ;
195
+ figure nommée et tableau des valeurs pour les lecteurs d'écran ; « Aucune donnée à afficher » sans point.
196
+ Graduations de l'axe x selon la largeur mesurée du graphique (et non celle de l'écran) : pas le plus fin, jamais plus
197
+ fin que les données, dont les libellés mono gardent `space[8]` entre eux ; un libellé qui déborderait des marges
198
+ n'est pas affiché.
199
+ - **Palette de séries** (`theme`) : jetons `data.series.1` à `data.series.6` (et `--abyss-data-series-*`), ordre
200
+ exporté par `DATA_SERIES_TOKENS` ; luminosité et chroma égales, 3:1 au moins sur les fonds (ADR-0174, avenant).
201
+ - **`UserPicker`** (`inputs`) : choix simple ou multiple d'utilisateurs (`{ id, name, email, pictureUrl }`), avatar,
202
+ nom et e-mail par option ; filtre local sur le nom et l'e-mail, ou recherche serveur par `onSearch` avec `loading` ;
203
+ `disabledIds` ; en multiple, puces parcourues à la flèche gauche et retirées par Retour arrière ou Suppr ; sous
204
+ 768 px, 44 px par option, puces de 44 px de haut dont la croix de retrait est un carré tactile, et texte du champ
205
+ jamais plus étroit que 44 px quand les puces remplissent la ligne.
206
+ - **`CompanySearchField`** (`inputs`) : contrat de `CompanySearchAutocomplete` (Pappers, `onSelect(PappersCompany)`,
207
+ erreur distincte d'une réponse vide, date de création dans la langue de l'utilisateur) sur `FormField` et les jetons
208
+ du core ; temporisation annulée au démontage, réponse dépassée ignorée.
209
+ - **Types sortis de `legacy/`** : `PappersCompany` et `CurrentFamilyInfo` (avec `CurrentFamilyStatus`) sont exportés de
210
+ la racine ; `/legacy` les réexporte.
211
+ - **Traductions** : clés `ds.inputs.user-picker.*` et `ds.inputs.company-search-field.*` (FR et EN).
212
+ - **`EntityImageField`** (`inputs`) : image d'entité changée sur place, `EntityImageVariant.Avatar` (pastille d'appareil photo, `EntityImageShape.Round` ou `Square`) ou `Banner` (bouton en surimpression) ; sélecteur de l'appareil, ou menu d'`ImportButton` avec `cloudImport` ; envoi indiqué, annoncé, et bloquant.
213
+ - **`useConfirmDialog`** et **`ConfirmDialogProvider`** (`layers`) : `confirm(options)` renvoie `Promise<boolean>` et ouvre le `ConfirmDialog` ; une demande à la fois, les suivantes attendent ; hors du fournisseur, une erreur qui le nomme.
214
+ - **`CopyField.loadValue`** : la valeur n'est demandée qu'au premier « Afficher » ou « Copier », puis gardée ; chargement sur le bouton, échec annoncé et rejouable. `value` et `loadValue` sont exclusifs.
215
+ - **`Section tone`** : `SectionTone.Danger` met le titre et un filet en `status.danger` (zones de danger).
216
+ - **`DataTable`, liste mobile** : sous 768 px, chaque contrôle de la colonne `trailing` (lien, bouton, `role="button"`, `role="link"`, `role="menuitem"`) offre une cible de 44 × 44 (`densityValues.touchTarget`), même rendu en `size="small"` par l'hôte ; rien ne change à partir de 768 px.
217
+
218
+ ### 9.1.1
219
+
220
+ - **`useServiceTour`** : sous un `AbyssCookieConsentProvider`, une première visite attend que le bandeau de cookies
221
+ soit tranché. Sur mobile, le bandeau recouvrait la feuille de la visite et bloquait « Suivant ». `start()` n'attend pas.
222
+ - **`ProductTour`** : la découpe suit sa cible à chaque image tant que la visite est ouverte. Une cible déplacée sans
223
+ redimensionnement ni défilement (police web chargée au-dessus d'elle) laissait la découpe 20 px à côté.
224
+
225
+ ### 9.1.0
226
+
227
+ - **`ProductTour`** (`layers`) : visite guidée d'un service (carte #285, spec §6.7). Bulle ancrée sur l'élément
228
+ `data-tour`, page voilée autour d'une découpe, compteur et points d'étape, « Suivant » / « Terminer » et « Passer la
229
+ visite » ; Échap passe la visite, les flèches changent d'étape, focus piégé ; feuille du bas sous 768 px (boutons de
230
+ 44 px) ; sans mouvement sous `prefers-reduced-motion`. Une étape dont la cible manque s'affiche au centre d'un écran
231
+ voilé.
232
+ - **`useServiceTour(service, { eligible })`** : ouvre la visite à la première visite (aucun état
233
+ `users.settings.serviceTours[service]`), la relance à la demande (`start`) et écrit `completedAt` ou `skippedAt` par
234
+ `AbyssCore.sdk.user.updateSettings`.
235
+ - **Menu « Famille » du legacy** (`buildAbyssFamilyMenuSection`) : sans famille, l'entrée mène à `/family/new`
236
+ d'abyss-main au lieu de `/onboarding`.
237
+ - **Traductions** : `ds.layers.product-tour.*` (FR et EN).
238
+
239
+ ### 8.3.0
240
+
241
+ Compte et facturation du front principal sur le design system (carte #286, zone 2). Sept pièces nouvelles, chacune
242
+ documentée dans le `README.md` de son dossier et montrée dans le catalogue.
243
+
244
+ - **`Tabs`** (`structure`) : rangée d'onglets liés aux routes ou boutons, variantes `TabsVariant.Primary` et
245
+ `Secondary`, un seul arrêt de tabulation, flèches, Début et Fin ; défilement horizontal avec fondu tant qu'il reste
246
+ des onglets à droite (`useScrollOverflowCue`), 44 px de haut sous 768 px.
247
+ - **`Callout`** (`states`) : bandeau `CalloutSeverity.Info`, `Success`, `Warning`, `Danger`, avec titre, action,
248
+ fermeture et icône facultatifs ; l'action passe sous le texte sous 768 px.
249
+ - **`FormField`** (`inputs`) : libellé, aide et erreur autour d'un `OutlinedInput`, `InputBase` ou `Select` ; `id`,
250
+ `aria-describedby` et `labelId` reliés, erreur et obligation passées au contrôle.
251
+ - **`SettingsRow`** (`inputs`) : libellé, description et contrôle à droite ; empilée sous 768 px.
252
+ - **`Switch` du thème** : sous 768 px, la zone tactile de tout interrupteur (38 px dessinés) est portée à 44 px de
253
+ haut.
254
+ - **`UsageMeter`** (`data`) : consommation sur un plafond, seuils en parts du plafond, jauge `meter` ; sans plafond, la
255
+ valeur seule.
256
+ - **`InvoiceDetailView`** (`data`) : corps de présentation du détail d'une facture (lignes, déductions, gestes, prise en
257
+ charge des programmes, totaux), partagé par le front client et le back-office ; données et actions en props.
258
+ - **`CopyField`** (`inputs`) : valeur masquable et copiable, résultat de la copie annoncé dans une région vivante.
259
+ - **`NumberField`** (`inputs`) : nombre saisi et affiché avec les séparateurs de la langue, « , » ou « . » lus comme
260
+ marque décimale, borné (`min`) et arrondi (`decimals`) en sortie du champ ; remplace `AbyssNumberField` du legacy
261
+ pour le design system.
262
+ - **`DataTable`** : deux options de colonne, `wrap` (la cellule passe à la ligne au lieu d'être coupée) et
263
+ `hideHeader` (en-tête lu par les technologies d'assistance, non dessiné, pour une colonne d'actions en icône).
264
+ - **`Tabs`** : l'onglet choisi est ramené à l'écran aussi quand la rangée ou un onglet change de taille.
265
+ - **Traductions** : clés `ds.states.callout.*`, `ds.inputs.copy-field.*` et `ds.data.usage-meter.*` (FR et EN).
266
+
267
+ Pièces que les pages de compte importaient encore de `/legacy`, refaites dans le nouveau système (les copies legacy
268
+ restent pour les hôtes legacy) :
269
+
270
+ - **`UserAvatar`, `OrganizationAvatar`, `ProjectAvatar`** (`meaning`) : photo ou logo, sinon l'initiale ; taille
271
+ `size` en px. La fiche de profil au clic du legacy n'est pas reprise (sans appelant).
272
+ - **`ContextSelector`** (`inputs`) : mon espace, puis un groupe par organisation et ses projets ;
273
+ `ContextValue.kind` est l'énumération `ContextKind`.
274
+ - **`DropZone`** (`inputs`) : dépôt et bouton de choix, refus (taille, type, nombre) écrits sous la zone, entrée
275
+ AbyssCloud avec `cloudImport`.
276
+ - **`ImportButton`** (`inputs`) : menu appareil, lien (adresse vérifiée, échec dit), AbyssCloud.
277
+ - **`CloudImport`**, **`ImportFromCloudModal`**, **`QRCodeModal`** (`business`) : le sélecteur AbyssCloud, sa
278
+ modale (`open`, `onClose`, `onImport`), et un lien en QR code (`open` au lieu de `isOpen`).
279
+ - **Jetons `paper` et `paper.on`** : une page claire et son encre dans les deux thèmes, pour ce qui est dessiné à
280
+ l'encre sombre (code QR, signature en PNG transparent). ADR-0174 §3 complété.
281
+ - **Logique pure partagée** : `deriveQuotaOfferState`, `QuotaOfferState`, `offersAction`, `shouldSuggestModule`
282
+ (table de décision de l'offre de quota) sortent de `legacy/` et s'exportent de la racine ; `/legacy` les
283
+ réexporte toujours. `isAcceptedFile` (filtre `accept` du sélecteur cloud) passe aussi hors de `legacy/`.
284
+ - **Traductions** : `ds.inputs.context-selector.*`, `ds.inputs.drop-zone.*`, `ds.inputs.import-button.*`,
285
+ `ds.business.cloud-import.*`, `ds.business.qr-code.*` (FR et EN).
286
+
287
+ ### 8.2.0
288
+
289
+ Shell et tableaux de bord du front principal sur le design system (carte #286, zone 1).
290
+
291
+ - **Nouveau** : `AppShell` prend `chromeless` (plein écran sans cadre), les entrées `external` et `action`,
292
+ l'action de section (`NavSection.action`) et les entrées internes du pied ; `NotificationsMenu`, `AccountMenu`,
293
+ `DesignCssVariables` et `focusRing` sont exportés ; `CommandPalette` gagne icônes, sous-titres, récents, sources
294
+ asynchrones et ouverture filtrée.
295
+ - **Paliers** : les composants du design system basculent à 768 et 1200 px (`designMedia`, `useDesignBreakpoint`)
296
+ quel que soit le provider. Sous le thème legacy, l'`AppShell` montre le rail dès 768 px (et non plus à 900), la
297
+ `Modal` une fenêtre dès 768 px, et la bannière MFA passe son bouton sous le texte quand il ne tient plus à côté.
298
+ - **Largeur de `Drawer` et de `Toast` sous le thème legacy** : la largeur par défaut passe de 600 à 480 px (palier
299
+ `sm` des jetons, et non plus le `sm` de MUI). Un hôte qui comptait sur 600 px passe `width` explicitement au
300
+ `Drawer`.
301
+ - **Largeur de `Modal` et de `CommandPalette` sous le thème legacy** : elle reste tirée des `theme.breakpoints` de
302
+ MUI (prop `size` de la `Modal` passée à `maxWidth`, `sm` pour la palette). Sous le thème legacy, `md` vaut 900 px
303
+ et `sm` 600 px, contre 768 et 480 sous `AbyssThemeProvider` : la même `Modal` est donc plus large chez un hôte
304
+ legacy. Suivi : `DS-LEGACY-WIDTHS` dans `docs/internal/TECH-DEBT.md` d'abyss-main.
305
+ - **Sélecteur d'espace** : un espace qui porte le nom de son type (« Espace personnel ») n'a plus de seconde ligne
306
+ répétant ce type.
307
+ - **Navigation** : la liste des sections garde une barre de défilement fine et visible quand elle dépasse la
308
+ hauteur de la fenêtre.
309
+ - **`PageState`** : `forbidden.message` remplace la description générique de l’accès refusé, pour nommer à qui
310
+ demander l’accès (organisation, projet).
311
+ - **`PageState`** : le bloc d’état passe son action sous le texte dès que son emplacement fait moins de 512 px
312
+ (colonne latérale), et plus seulement sous 768 px d’écran.
313
+ - **`PageHeader`** : de 768 px à la largeur du bureau, les actions passent sous le titre dès qu'elles ne tiennent
314
+ plus à côté d'un titre de 256 px.
315
+
316
+
317
+ ## Support
318
+
319
+ Pour toute demande, ouvrir un ticket depuis [l'application Abyss](https://app.abyss-project.fr/dashboard/account/tickets/create).