@arc-js/core 0.0.57 → 0.0.59

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/README.md CHANGED
@@ -5,32 +5,33 @@
5
5
  ![React](https://img.shields.io/badge/React-18+-61DAFB)
6
6
  ![React Router](https://img.shields.io/badge/React%20Router-6+-CA4245)
7
7
 
8
- **@arc-js/core** est un module de routage intelligent et auto-configuré pour les applications React avec TypeScript/Javascript. Il fournit un système de routage basé sur la structure de fichiers, des hooks de navigation avancés et une configuration minimale pour les applications modulaires.
8
+ **@arc-js/core** est un ensemble de hooks et utilitaires de routage avancés pour les applications React avec TypeScript/JavaScript. Il fournit des fonctionnalités de navigation avancées, une gestion automatique des langues et des utilitaires pour simplifier le développement d'applications React Router.
9
9
 
10
10
  ## ✨ Fonctionnalités Principales
11
11
 
12
- ### 🗺️ Routage Auto-Généré
13
- - **Génération automatique des routes** à partir de la structure du système de fichiers
14
- - **Support des layouts hiérarchiques** avec héritage automatique
15
- - **Pages d'erreur spécifiques** par sous-répertoire
16
- - **Configuration modulaire** avec support des modules indépendants
17
-
18
- ### 🧭 Hooks de Navigation Avancés
12
+ ### 🧭 Navigation Avancée
19
13
  - **Navigation type-safe** avec validation des paramètres
20
14
  - **Gestion automatique des query strings** avec support multi-langue
21
15
  - **Résolution de routes** avec paramètres dynamiques
22
16
  - **Navigation avec rechargement** pour les mises à jour critiques
23
-
24
- ### ⚙️ Configuration Modulaire
25
- - **Configuration par module** avec fichiers `config.json`
26
- - **Activation/désactivation** dynamique des modules
27
- - **Chemins personnalisables** par module
28
- - **Détection automatique** des fichiers de pages
29
-
30
- ### 🛡️ Sécurité et Fiabilité
31
- - **Validation des chemins** avec fallback sécurisé
32
- - **Gestion des erreurs** avec pages d'erreur hiérarchiques
33
- - **Logs détaillés** en mode développement seulement
17
+ - **Analyse d'URL** complète avec extraction des données
18
+
19
+ ### 🌍 Support Multi-Langue
20
+ - **Gestion automatique** du paramètre de langue `lang`
21
+ - **Support intégré** pour français et anglais
22
+ - **Fallback sécurisé** vers le français par défaut
23
+ - **Codes de langue** standardisés (fr_FR, en_US)
24
+
25
+ ### Utilitaires de Routage
26
+ - **Validation de route actuelle** avec correspondance de chemin
27
+ - **Extraction des paramètres** de query string
28
+ - **Génération d'URL** avec paramètres et queries
29
+ - **Navigation externe** vers des URL spécifiques
30
+
31
+ ### 🛡️ Gestion d'Erreurs
32
+ - **Fallback sécurisé** pour les routes invalides
33
+ - **Validation stricte** des paramètres d'entrée
34
+ - **Logs détaillés** en mode développement
34
35
  - **Types TypeScript complets** pour une meilleure autocomplétion
35
36
 
36
37
  ## 📦 Installation
@@ -38,48 +39,21 @@
38
39
  ### Via npm/yarn/pnpm
39
40
 
40
41
  ```bash
41
- npm install @arc-js/core react-router-dom react
42
+ npm install @arc-js/core react-router-dom @arc-js/qust react
42
43
  # ou
43
- yarn add @arc-js/core react-router-dom react
44
+ yarn add @arc-js/core react-router-dom @arc-js/qust react
44
45
  # ou
45
- pnpm add @arc-js/core react-router-dom react
46
+ pnpm add @arc-js/core react-router-dom @arc-js/qust react
46
47
  ```
47
48
 
48
49
  ### Dépendances requises
49
50
  - React 18+
50
51
  - React Router DOM 6+
51
52
  - TypeScript 5.0+ (recommandé)
52
- - @arc-js/qust (pour la manipulation de query strings)
53
+ - @arc-js/qust 1.0.0+ (pour la manipulation de query strings)
53
54
 
54
55
  ## 🚀 Démarrage Rapide
55
56
 
56
- ### Structure de projet recommandée
57
-
58
- ```
59
- src/
60
- ├── pages/
61
- │ ├── _layout.tsx # Layout racine
62
- │ ├── _error.tsx # Page d'erreur racine
63
- │ ├── index.tsx # Page d'accueil
64
- │ ├── about/
65
- │ │ ├── _layout.tsx # Layout spécifique à /about
66
- │ │ ├── _error.tsx # Erreur spécifique à /about
67
- │ │ ├── index.tsx # /about
68
- │ │ └── team.tsx # /about/team
69
- │ └── users/
70
- │ ├── _layout.tsx # Layout spécifique à /users
71
- │ ├── [id].tsx # /users/:id (paramètre dynamique)
72
- │ └── index.tsx # /users
73
- ├── modules/
74
- │ └── admin/
75
- │ ├── config.json # Configuration du module admin
76
- │ └── pages/
77
- │ ├── _layout.tsx # Layout du module admin
78
- │ ├── dashboard.tsx # /admin/dashboard
79
- │ └── users.tsx # /admin/users
80
- └── main.tsx
81
- ```
82
-
83
57
  ### Configuration de base
84
58
 
85
59
  ```typescript
@@ -87,33 +61,56 @@ src/
87
61
  import React from 'react';
88
62
  import ReactDOM from 'react-dom/client';
89
63
  import { BrowserRouter } from 'react-router-dom';
90
- import getRoutes from '@arc-js/core';
91
- import { RouterProvider, createBrowserRouter } from 'react-router-dom';
92
-
93
- const App = () => {
94
- const routes = getRoutes();
95
- const router = createBrowserRouter(routes);
96
-
97
- return <RouterProvider router={router} />;
98
- };
64
+ import App from './App';
99
65
 
100
66
  ReactDOM.createRoot(document.getElementById('root')!).render(
101
67
  <React.StrictMode>
102
- <App />
68
+ <BrowserRouter>
69
+ <App />
70
+ </BrowserRouter>
103
71
  </React.StrictMode>
104
72
  );
105
73
  ```
106
74
 
107
- ### Fichier config.json d'un module
75
+ ### Utilisation du hook principal
108
76
 
109
- ```json
110
- {
111
- "path": "/admin",
112
- "name": "Administration",
113
- "description": "Module d'administration",
114
- "author": "Votre Équipe",
115
- "isEnabled": true
116
- }
77
+ ```typescript
78
+ // App.tsx
79
+ import { useRootingActions } from '@arc-js/core';
80
+
81
+ const App = () => {
82
+ const {
83
+ params,
84
+ queries,
85
+ resolveRoute,
86
+ goToRoute,
87
+ checkIfIsCurrentRoute
88
+ } = useRootingActions();
89
+
90
+ // Navigation vers une page avec paramètres
91
+ const navigateToUser = (userId: string) => {
92
+ goToRoute({
93
+ path: '/users/:id',
94
+ params: { id: userId },
95
+ queries: { lang: 'fr', view: 'profile' }
96
+ });
97
+ };
98
+
99
+ // Vérifier si on est sur la page d'accueil
100
+ const isHome = checkIfIsCurrentRoute('/');
101
+
102
+ return (
103
+ <div>
104
+ <h1>Mon Application</h1>
105
+ {isHome && <p>Vous êtes sur la page d'accueil</p>}
106
+ <button onClick={() => navigateToUser('123')}>
107
+ Voir l'utilisateur 123
108
+ </button>
109
+ </div>
110
+ );
111
+ };
112
+
113
+ export default App;
117
114
  ```
118
115
 
119
116
  ## 📚 Documentation API
@@ -125,32 +122,29 @@ import { useRootingActions } from '@arc-js/core';
125
122
 
126
123
  const MyComponent = () => {
127
124
  const {
128
- params, // Paramètres de route (ex: { id: "123" })
129
- queries, // Query parameters (ex: { lang: "fr", page: "1" })
130
- navigate, // Fonction navigate de react-router-dom
131
- resolveRoute, // Résoudre une route avec paramètres
125
+ // Paramètres de l'URL actuelle
126
+ params, // { id: "123", slug: "article" }
127
+ queries, // { lang: "fr", page: "1" }
128
+ pathName, // "/users/123/profile"
129
+ urlSearch, // "?lang=fr&page=1"
130
+
131
+ // Fonctions de navigation
132
+ navigate, // navigate() de react-router-dom
133
+ resolveRoute, // Générer une URL complète
132
134
  goToRoute, // Naviguer vers une route
133
135
  goAndReloadRoute, // Naviguer avec rechargement
134
- pathName, // Chemin actuel
135
- urlSearch, // Query string actuelle
136
+ goToUrl, // Naviguer vers une URL externe
137
+
138
+ // Utilitaires
139
+ getParams, // Obtenir les paramètres d'URL
136
140
  getUrlData, // Analyser une URL
137
- checkIfIsCurrentRoute // Vérifier si on est sur une route
141
+ checkIfIsCurrentRoute // Vérifier la route actuelle
138
142
  } = useRootingActions();
139
143
 
140
- // Exemple d'utilisation
141
- const handleClick = () => {
142
- goToRoute({
143
- path: '/users/:id',
144
- params: { id: '123' },
145
- queries: { lang: 'fr', view: 'details' }
146
- });
147
- };
148
-
149
144
  return (
150
145
  <div>
151
- <button onClick={handleClick}>
152
- Voir l'utilisateur 123
153
- </button>
146
+ <p>ID Utilisateur: {params.id}</p>
147
+ <p>Langue: {queries.lang || 'fr'}</p>
154
148
  </div>
155
149
  );
156
150
  };
@@ -161,258 +155,194 @@ const MyComponent = () => {
161
155
  ```typescript
162
156
  // Configuration de navigation
163
157
  interface ConfigGoToRoute {
164
- path?: string;
165
- params?: any;
166
- queries?: any;
167
- refreshPage?: boolean;
168
- replace?: boolean;
169
- enableLoader?: boolean;
158
+ path?: string; // Chemin de la route (ex: "/users/:id")
159
+ params?: any; // Paramètres de route (ex: { id: "123" })
160
+ queries?: any; // Query parameters (ex: { lang: "fr" })
161
+ refreshPage?: boolean; // Forcer le rechargement
162
+ replace?: boolean; // Remplacer l'historique
163
+ enableLoader?: boolean; // Afficher un loader
170
164
  }
171
165
 
172
- // Configuration de résolution de route
166
+ // Configuration de résolution
173
167
  interface ConfigResolveRoute {
174
168
  path?: string;
175
169
  params?: any;
176
170
  queries?: any;
177
171
  }
178
172
 
179
- // Route générée automatiquement
180
- interface RouteDefinition {
181
- truePath: string; // Chemin physique du fichier
182
- pathParent?: string; // Chemin parent
183
- path: string; // Chemin de la route
184
- component: React.ComponentType<any>;
185
- layout?: React.ComponentType<{ children: ReactNode }>;
186
- error?: React.ComponentType<{}>;
173
+ // Configuration de navigation externe
174
+ interface ConfigGoToSpecificUrl {
175
+ path?: string;
176
+ queries?: any;
177
+ refreshPage?: boolean;
178
+ replace?: boolean;
179
+ enableLoader?: boolean;
187
180
  }
188
181
 
189
- // Configuration d'un module
190
- interface ConfigDatasDefinition {
191
- path: string; // Chemin de base du module
192
- name: string | undefined;
193
- author: string | undefined;
194
- isEnabled: boolean; // Activation du module
182
+ // Valeur de retour du hook
183
+ interface RootingActionReturns {
184
+ params: Readonly<Params<string>>;
185
+ queries: any;
186
+ getParams: () => URLSearchParams;
187
+ navigate: NavigateFunction;
188
+ resolveRoute: (config: ConfigResolveRoute) => string;
189
+ goToRoute: (config: ConfigGoToRoute) => void;
190
+ goAndReloadRoute: (config: ConfigGoAndReloadRoute) => void;
191
+ pathName: string;
192
+ urlSearch: string;
193
+ getUrlData: (url: string | URL) => {
194
+ host: string;
195
+ hostname: string;
196
+ pathname: string;
197
+ search: string;
198
+ queries: any;
199
+ } | undefined;
200
+ goToUrl: (config: ConfigGoToSpecificUrl) => string;
201
+ checkIfIsCurrentRoute: (path?: string, exact?: boolean, strict?: boolean) => boolean;
195
202
  }
196
203
  ```
197
204
 
198
205
  ### Fonctions utilitaires
199
206
 
200
207
  ```typescript
201
- import { nativeResolveRoute } from '@arc-js/core';
208
+ import { nativeResolveRoute, getLang, getLangCode } from '@arc-js/core';
202
209
 
203
- // Résoudre une URL sans utiliser le hook
204
- const url = nativeResolveRoute({
205
- path: '/users/:id',
210
+ // Générer une URL sans utiliser le hook
211
+ const userProfileUrl = nativeResolveRoute({
212
+ path: '/users/:id/profile',
206
213
  params: { id: '456' },
207
- queries: { lang: 'en', tab: 'profile' }
214
+ queries: { lang: 'en', tab: 'settings' }
208
215
  });
216
+ // Résultat: "/users/456/profile?lang=en&tab=settings"
209
217
 
210
- console.log(url); // "/users/456?lang=en&tab=profile"
218
+ // Gestion des langues
219
+ const currentLang = getLang('fr'); // "fr" (valide)
220
+ const fallbackLang = getLang('es'); // "fr" (fallback)
221
+ const langCode = getLangCode('en'); // "en_US"
211
222
  ```
212
223
 
213
224
  ## 🔧 Utilisation Avancée
214
225
 
215
- ### Pages dynamiques avec paramètres
226
+ ### Navigation avec gestion de langue
216
227
 
217
228
  ```typescript
218
- // src/pages/users/[id].tsx
219
- import { useRootingActions } from '@arc-js/core';
220
-
221
- const UserPage = () => {
222
- const { params, queries } = useRootingActions();
223
- const userId = params.id;
224
- const lang = queries.lang || 'fr';
229
+ const LanguageAwareNavigation = () => {
230
+ const { goToRoute, queries } = useRootingActions();
231
+ const currentLang = queries.lang || 'fr';
232
+
233
+ const navigateWithLang = (path: string, params?: any, additionalQueries?: any) => {
234
+ goToRoute({
235
+ path,
236
+ params,
237
+ queries: {
238
+ ...additionalQueries,
239
+ lang: currentLang
240
+ }
241
+ });
242
+ };
225
243
 
226
244
  return (
227
245
  <div>
228
- <h1>Utilisateur {userId}</h1>
229
- <p>Langue: {lang}</p>
246
+ <button onClick={() => navigateWithLang('/about', null, { section: 'team' })}>
247
+ Voir l'équipe
248
+ </button>
230
249
  </div>
231
250
  );
232
251
  };
233
-
234
- export default UserPage;
235
- ```
236
-
237
- ### Layouts hiérarchiques
238
-
239
- ```typescript
240
- // src/pages/_layout.tsx (Layout racine)
241
- const RootLayout = ({ children }) => (
242
- <div className="app">
243
- <header>Mon Application</header>
244
- <main>{children}</main>
245
- <footer>© 2024</footer>
246
- </div>
247
- );
248
-
249
- // src/pages/admin/_layout.tsx (Layout admin)
250
- const AdminLayout = ({ children }) => (
251
- <div className="admin">
252
- <nav>Menu Admin</nav>
253
- <div className="admin-content">{children}</div>
254
- </div>
255
- );
256
252
  ```
257
253
 
258
- ### Pages d'erreur spécifiques
254
+ ### Analyse d'URL externe
259
255
 
260
256
  ```typescript
261
- // src/pages/_error.tsx (Erreur globale)
262
- const GlobalErrorPage = () => (
263
- <div>
264
- <h1>Une erreur est survenue</h1>
265
- <p>Veuillez réessayer plus tard.</p>
266
- </div>
267
- );
268
-
269
- // src/pages/admin/_error.tsx (Erreur admin)
270
- const AdminErrorPage = () => (
271
- <div className="admin-error">
272
- <h1>Erreur d'administration</h1>
273
- <p>Contactez le support technique.</p>
274
- </div>
275
- );
276
- ```
277
-
278
- ### Configuration de modules
279
-
280
- ```typescript
281
- // src/modules/blog/config.json
282
- {
283
- "path": "/blog",
284
- "name": "Blog",
285
- "description": "Module de blog",
286
- "author": "Équipe Rédaction",
287
- "isEnabled": true
288
- }
289
-
290
- // src/modules/blog/pages/index.tsx sera accessible à /blog
291
- // src/modules/blog/pages/[slug].tsx sera accessible à /blog/:slug
292
- ```
293
-
294
- ## 🎯 Exemples Complets
295
-
296
- ### Exemple 1 : Application avec authentification
297
-
298
- ```typescript
299
- // src/pages/_layout.tsx
300
- import { useRootingActions } from '@arc-js/core';
301
- import { Link } from 'react-router-dom';
302
-
303
- const AppLayout = ({ children }) => {
304
- const { checkIfIsCurrentRoute } = useRootingActions();
305
- const isActive = (path: string) => checkIfIsCurrentRoute(path);
306
-
307
- return (
308
- <div>
309
- <nav>
310
- <Link to="/" className={isActive('/') ? 'active' : ''}>
311
- Accueil
312
- </Link>
313
- <Link to="/about" className={isActive('/about') ? 'active' : ''}>
314
- À propos
315
- </Link>
316
- <Link to="/contact" className={isActive('/contact') ? 'active' : ''}>
317
- Contact
318
- </Link>
319
- </nav>
320
- {children}
321
- </div>
322
- );
323
- };
324
-
325
- // src/pages/protected/_layout.tsx
326
- import { useEffect } from 'react';
327
- import { useRootingActions } from '@arc-js/core';
328
-
329
- const ProtectedLayout = ({ children }) => {
330
- const { goToRoute } = useRootingActions();
257
+ const UrlAnalyzer = () => {
258
+ const { getUrlData } = useRootingActions();
331
259
 
332
- useEffect(() => {
333
- const token = localStorage.getItem('auth_token');
334
- if (!token) {
335
- goToRoute({
336
- path: '/login',
337
- queries: { redirect: window.location.pathname }
338
- });
260
+ const analyzeUrl = () => {
261
+ const urlData = getUrlData('https://example.com/products/123?color=red&size=L');
262
+
263
+ if (urlData) {
264
+ console.log('Host:', urlData.host); // "example.com"
265
+ console.log('Path:', urlData.pathname); // "/products/123"
266
+ console.log('Queries:', urlData.queries); // { color: "red", size: "L" }
339
267
  }
340
- }, []);
268
+ };
341
269
 
342
- return token ? children : null;
270
+ return (
271
+ <button onClick={analyzeUrl}>
272
+ Analyser l'URL
273
+ </button>
274
+ );
343
275
  };
344
276
  ```
345
277
 
346
- ### Exemple 2 : Dashboard avec multi-langue
278
+ ### Navigation conditionnelle
347
279
 
348
280
  ```typescript
349
- // src/pages/dashboard/index.tsx
350
- import { useRootingActions } from '@arc-js/core';
351
- import { useState, useEffect } from 'react';
352
-
353
- const DashboardPage = () => {
354
- const { queries, goToRoute, resolveRoute } = useRootingActions();
355
- const [lang, setLang] = useState(queries.lang || 'fr');
281
+ const SmartNavigation = () => {
282
+ const { goToRoute, checkIfIsCurrentRoute } = useRootingActions();
356
283
 
357
- const changeLanguage = (newLang: string) => {
358
- goToRoute({
359
- path: '/dashboard',
360
- queries: { ...queries, lang: newLang }
361
- });
362
- };
363
-
364
- const getReportUrl = (reportId: string) => {
365
- return resolveRoute({
366
- path: '/dashboard/reports/:id',
367
- params: { id: reportId },
368
- queries: { lang, format: 'pdf' }
369
- });
284
+ const navigateSmartly = (path: string) => {
285
+ // Si déjà sur la page, ne rien faire
286
+ if (checkIfIsCurrentRoute(path)) {
287
+ return;
288
+ }
289
+
290
+ // Sinon, naviguer
291
+ goToRoute({ path });
370
292
  };
371
293
 
372
294
  return (
373
- <div>
374
- <div>
375
- Langue:
376
- <button onClick={() => changeLanguage('fr')}>FR</button>
377
- <button onClick={() => changeLanguage('en')}>EN</button>
378
- </div>
379
-
380
- <a href={getReportUrl('monthly')}>
381
- Télécharger le rapport mensuel
382
- </a>
383
- </div>
295
+ <nav>
296
+ <button onClick={() => navigateSmartly('/')}>
297
+ Accueil
298
+ </button>
299
+ <button onClick={() => navigateSmartly('/about')}>
300
+ À propos
301
+ </button>
302
+ </nav>
384
303
  );
385
304
  };
386
305
  ```
387
306
 
388
- ### Exemple 3 : Formulaire avec redirection
307
+ ## 🎯 Exemples Complets
308
+
309
+ ### Exemple 1 : Formulaire avec redirection
389
310
 
390
311
  ```typescript
391
- // src/pages/contact/index.tsx
392
312
  import { useState } from 'react';
393
313
  import { useRootingActions } from '@arc-js/core';
394
314
 
395
- const ContactPage = () => {
315
+ const ContactForm = () => {
396
316
  const { goToRoute, goAndReloadRoute } = useRootingActions();
397
- const [formData, setFormData] = useState({ name: '', email: '' });
317
+ const [formData, setFormData] = useState({ name: '', email: '', message: '' });
398
318
 
399
319
  const handleSubmit = async (e: React.FormEvent) => {
400
320
  e.preventDefault();
401
321
 
402
- // Simulation d'envoi
403
- const success = await submitContactForm(formData);
404
-
405
- if (success) {
406
- // Redirection simple
407
- goToRoute({
408
- path: '/contact/success',
409
- queries: { ref: 'contact-form' }
322
+ try {
323
+ // Envoyer les données
324
+ const response = await fetch('/api/contact', {
325
+ method: 'POST',
326
+ body: JSON.stringify(formData)
410
327
  });
411
- } else {
412
- // Redirection avec rechargement pour nettoyer le cache
413
- goAndReloadRoute({
328
+
329
+ if (response.ok) {
330
+ // Redirection simple vers la page de confirmation
331
+ goToRoute({
332
+ path: '/contact/success',
333
+ queries: { ref: 'contact-form' }
334
+ });
335
+ } else {
336
+ // Redirection avec rechargement pour nettoyer les erreurs
337
+ goAndReloadRoute({
338
+ path: '/contact',
339
+ queries: { error: 'submission_failed' }
340
+ });
341
+ }
342
+ } catch (error) {
343
+ goToRoute({
414
344
  path: '/contact',
415
- queries: { error: 'submission_failed' }
345
+ queries: { error: 'network_error' }
416
346
  });
417
347
  }
418
348
  };
@@ -422,166 +352,220 @@ const ContactPage = () => {
422
352
  <input
423
353
  value={formData.name}
424
354
  onChange={e => setFormData({...formData, name: e.target.value})}
425
- placeholder="Nom"
355
+ placeholder="Votre nom"
426
356
  />
427
357
  <input
358
+ type="email"
428
359
  value={formData.email}
429
360
  onChange={e => setFormData({...formData, email: e.target.value})}
430
- placeholder="Email"
361
+ placeholder="Votre email"
362
+ />
363
+ <textarea
364
+ value={formData.message}
365
+ onChange={e => setFormData({...formData, message: e.target.value})}
366
+ placeholder="Votre message"
367
+ rows={4}
431
368
  />
432
- <button type="submit">Envoyer</button>
369
+ <button type="submit">
370
+ Envoyer
371
+ </button>
433
372
  </form>
434
373
  );
435
374
  };
436
375
  ```
437
376
 
438
- ## 🔧 Configuration Avancée
377
+ ### Exemple 2 : Système de pagination
439
378
 
440
- ### Variables d'environnement
441
-
442
- ```bash
443
- # .env
444
- VITE_APP_NAME="Mon Application"
445
- VITE_API_URL="http://localhost:3000"
379
+ ```typescript
380
+ import { useRootingActions } from '@arc-js/core';
446
381
 
447
- # Activation des logs détaillés
448
- NODE_ENV=development # Logs complets
449
- NODE_ENV=production # Logs minimaux
382
+ const PaginatedList = ({ items, currentPage, totalPages }) => {
383
+ const { goToRoute, queries } = useRootingActions();
384
+
385
+ const goToPage = (page: number) => {
386
+ goToRoute({
387
+ path: '/items',
388
+ queries: {
389
+ ...queries,
390
+ page: page.toString()
391
+ }
392
+ });
393
+ };
394
+
395
+ return (
396
+ <div>
397
+ <h2>Liste des éléments</h2>
398
+
399
+ {/* Liste des éléments */}
400
+ <ul>
401
+ {items.map(item => (
402
+ <li key={item.id}>{item.name}</li>
403
+ ))}
404
+ </ul>
405
+
406
+ {/* Pagination */}
407
+ <div className="pagination">
408
+ <button
409
+ disabled={currentPage <= 1}
410
+ onClick={() => goToPage(currentPage - 1)}
411
+ >
412
+ Précédent
413
+ </button>
414
+
415
+ <span>Page {currentPage} sur {totalPages}</span>
416
+
417
+ <button
418
+ disabled={currentPage >= totalPages}
419
+ onClick={() => goToPage(currentPage + 1)}
420
+ >
421
+ Suivant
422
+ </button>
423
+ </div>
424
+ </div>
425
+ );
426
+ };
450
427
  ```
451
428
 
452
- ### Extension de la configuration
429
+ ### Exemple 3 : Menu de navigation intelligent
453
430
 
454
431
  ```typescript
455
- // custom-routes.ts
456
- import { getRoutes as getBaseRoutes } from '@arc-js/core';
457
- import { RouteDefinition } from '@arc-js/core/types';
432
+ import { useRootingActions } from '@arc-js/core';
458
433
 
459
- export async function getRoutes() {
460
- const baseRoutes = await getBaseRoutes();
434
+ const NavigationMenu = () => {
435
+ const { goToRoute, checkIfIsCurrentRoute } = useRootingActions();
461
436
 
462
- // Ajouter des routes manuelles
463
- const customRoutes: RouteDefinition[] = [
464
- {
465
- truePath: '/src/pages/custom.tsx',
466
- path: '/custom-route',
467
- component: () => <div>Route personnalisée</div>,
468
- layout: undefined,
469
- error: undefined
470
- }
437
+ const menuItems = [
438
+ { path: '/', label: 'Accueil' },
439
+ { path: '/products', label: 'Produits' },
440
+ { path: '/about', label: 'À propos' },
441
+ { path: '/contact', label: 'Contact' }
471
442
  ];
472
443
 
473
- return [...baseRoutes, ...customRoutes];
474
- }
444
+ return (
445
+ <nav className="navigation">
446
+ {menuItems.map(item => {
447
+ const isActive = checkIfIsCurrentRoute(item.path);
448
+
449
+ return (
450
+ <button
451
+ key={item.path}
452
+ className={`nav-item \${isActive ? 'active' : ''}`}
453
+ onClick={() => goToRoute({ path: item.path })}
454
+ >
455
+ {item.label}
456
+ </button>
457
+ );
458
+ })}
459
+ </nav>
460
+ );
461
+ };
475
462
  ```
476
463
 
477
- ### Personnalisation du routage
464
+ ### Exemple 4 : Sélecteur de langue
478
465
 
479
466
  ```typescript
480
- // custom-router.tsx
481
467
  import { useRootingActions } from '@arc-js/core';
482
- import type { ConfigGoToRoute } from '@arc-js/core';
483
468
 
484
- export const useCustomRooting = () => {
485
- const baseActions = useRootingActions();
469
+ const LanguageSelector = () => {
470
+ const { goToRoute, queries } = useRootingActions();
471
+ const currentLang = queries.lang || 'fr';
486
472
 
487
- const goToRouteWithAnalytics = (
488
- config: ConfigGoToRoute,
489
- analyticsEvent?: string
490
- ) => {
491
- // Envoyer l'événement analytics
492
- if (analyticsEvent) {
493
- window.gtag?.('event', analyticsEvent, {
494
- path: config.path,
495
- params: config.params
496
- });
497
- }
498
-
499
- // Utiliser la navigation standard
500
- return baseActions.goToRoute(config);
501
- };
473
+ const languages = [
474
+ { code: 'fr', name: 'Français', flag: '🇫🇷' },
475
+ { code: 'en', name: 'English', flag: '🇬🇧' },
476
+ { code: 'es', name: 'Español', flag: '🇪🇸' }
477
+ ];
502
478
 
503
- return {
504
- ...baseActions,
505
- goToRouteWithAnalytics
479
+ const changeLanguage = (langCode: string) => {
480
+ goToRoute({
481
+ path: window.location.pathname,
482
+ queries: {
483
+ ...queries,
484
+ lang: langCode
485
+ }
486
+ });
506
487
  };
488
+
489
+ return (
490
+ <div className="language-selector">
491
+ {languages.map(lang => (
492
+ <button
493
+ key={lang.code}
494
+ className={`lang-btn \${currentLang === lang.code ? 'active' : ''}`}
495
+ onClick={() => changeLanguage(lang.code)}
496
+ title={lang.name}
497
+ >
498
+ {lang.flag} {lang.name}
499
+ </button>
500
+ ))}
501
+ </div>
502
+ );
507
503
  };
508
504
  ```
509
505
 
510
- ## 🛡️ Gestion des Erreurs
506
+ ## 🔧 Configuration
511
507
 
512
- ### Structure d'erreur hiérarchique
508
+ ### Configuration des langues
513
509
 
510
+ ```typescript
511
+ // Configuration par défaut dans @arc-js/core
512
+ export const langs = ['en', 'fr']; // Langues supportées
513
+ export const langCodes = {
514
+ 'fr': 'fr_FR',
515
+ 'en': 'en_US',
516
+ };
514
517
  ```
515
- pages/
516
- ├── _error.tsx # Erreur globale
517
- ├── admin/
518
- │ ├── _error.tsx # Erreur admin (surcharge globale)
519
- │ └── dashboard/
520
- │ └── _error.tsx # Erreur dashboard (surcharge admin)
521
- └── public/
522
- └── _error.tsx # Erreur section publique
518
+
519
+ ### Variables d'environnement
520
+
521
+ ```bash
522
+ # .env
523
+ NODE_ENV=development # development | debug | production
523
524
  ```
524
525
 
525
- ### Page d'erreur avancée
526
+ ## 🛡️ Gestion des Erreurs
526
527
 
527
- ```typescript
528
- // src/pages/_error.tsx
529
- import { useRouteError, Link } from 'react-router-dom';
530
- import { useRootingActions } from '@arc-js/core';
528
+ ### Fallback sécurisé
531
529
 
532
- const ErrorPage = () => {
533
- const error = useRouteError();
534
- const { pathName, goToRoute } = useRootingActions();
535
-
536
- console.error('Route Error:', error);
530
+ ```typescript
531
+ const SafeNavigation = () => {
532
+ const { resolveRoute, goToRoute } = useRootingActions();
537
533
 
538
- const handleRetry = () => {
539
- goToRoute({
540
- path: pathName,
541
- refreshPage: true // Forcer le rechargement
542
- });
534
+ const safeGoToRoute = (config: ConfigGoToRoute) => {
535
+ try {
536
+ goToRoute(config);
537
+ } catch (error) {
538
+ console.error('Navigation error:', error);
539
+ // Fallback vers la page d'accueil
540
+ goToRoute({ path: '/' });
541
+ }
543
542
  };
544
543
 
545
544
  return (
546
- <div className="error-container">
547
- <h1>Oups ! Une erreur est survenue</h1>
548
- <p>Désolé, une erreur inattendue s'est produite.</p>
549
-
550
- <div className="error-actions">
551
- <button onClick={handleRetry}>
552
- Réessayer
553
- </button>
554
- <Link to="/">
555
- Retour à l'accueil
556
- </Link>
557
- </div>
558
- </div>
545
+ <button onClick={() => safeGoToRoute({ path: '/invalid-route' })}>
546
+ Naviguer en sécurité
547
+ </button>
559
548
  );
560
549
  };
561
550
  ```
562
551
 
563
552
  ## 📋 Table des Conventions
564
553
 
565
- ### Fichiers spéciaux
554
+ ### Paramètres de query string
566
555
 
567
- | Fichier | Chemin de route | Description |
568
- |---------|----------------|-------------|
569
- | `index.tsx` | `/` (racine) ou `/dossier/` | Page d'index |
570
- | `_layout.tsx` | Non accessible | Layout pour le dossier |
571
- | `_error.tsx` | Non accessible | Page d'erreur pour le dossier |
572
- | `_404.tsx` | `*` | Page 404 (non trouvé) |
573
- | `[param].tsx` | `/:param` | Paramètre dynamique |
574
- | `[...slug].tsx` | `/*` | Catch-all route |
556
+ | Paramètre | Type | Description | Valeur par défaut |
557
+ |-----------|------|-------------|-------------------|
558
+ | `lang` | `fr` \| `en` | Langue de l'application | `fr` |
559
+ | `page` | number | Numéro de page | `1` |
560
+ | `sort` | string | Tri des résultats | `date` |
561
+ | `filter` | string | Filtre appliqué | `all` |
575
562
 
576
- ### Paramètres de query string
563
+ ### Codes de langue
577
564
 
578
- | Paramètre | Type | Description |
579
- |-----------|------|-------------|
580
- | `lang` | `fr` \| `en` | Langue de l'application |
581
- | `ref` | string | Référence pour le tracking |
582
- | `modal` | string | Ouvrir un modal spécifique |
583
- | `page` | number | Numéro de page (pagination) |
584
- | `sort` | string | Tri des résultats |
565
+ | Code court | Code long | Description |
566
+ |------------|-----------|-------------|
567
+ | `fr` | `fr_FR` | Français (France) |
568
+ | `en` | `en_US` | Anglais (États-Unis) |
585
569
 
586
570
  ## 🔧 Build et Développement
587
571
 
@@ -593,32 +577,11 @@ const ErrorPage = () => {
593
577
  "dev": "vite",
594
578
  "build": "tsc && vite build",
595
579
  "preview": "vite preview",
596
- "type-check": "tsc --noEmit",
597
- "generate-routes": "node scripts/generate-routes.js"
580
+ "type-check": "tsc --noEmit"
598
581
  }
599
582
  }
600
583
  ```
601
584
 
602
- ### Configuration Vite
603
-
604
- ```typescript
605
- // vite.config.ts
606
- import { defineConfig } from 'vite';
607
- import react from '@vitejs/plugin-react';
608
-
609
- export default defineConfig({
610
- plugins: [react()],
611
- resolve: {
612
- alias: {}
613
- },
614
- build: {
615
- rollupOptions: {
616
- external: ['react', 'react-dom', 'react-router-dom']
617
- }
618
- }
619
- });
620
- ```
621
-
622
585
  ### Configuration TypeScript
623
586
 
624
587
  ```json
@@ -630,7 +593,6 @@ export default defineConfig({
630
593
  "skipLibCheck": true,
631
594
  "moduleResolution": "bundler",
632
595
  "allowImportingTsExtensions": true,
633
- "resolveJsonModule": true,
634
596
  "isolatedModules": true,
635
597
  "noEmit": true,
636
598
  "jsx": "react-jsx",
@@ -640,7 +602,7 @@ export default defineConfig({
640
602
  "noFallthroughCasesInSwitch": true,
641
603
  "types": ["vite/client"]
642
604
  },
643
- "include": ["src"]
605
+ "include": ["src", "node_modules/@arc-js/core/**/*"]
644
606
  }
645
607
  ```
646
608
 
@@ -657,6 +619,6 @@ Envoyez nous un mail à l'adresse `contact.inicode@gmail.com` pour :
657
619
 
658
620
  ---
659
621
 
660
- **@arc-js/core** - Le système de routage intelligent pour React et TypeScript.
622
+ **@arc-js/core** - Les hooks et utilitaires de routage avancés pour React et TypeScript.
661
623
 
662
624
  *Développé par l'équipe INICODE*