@arc-js/meta 0.0.1

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 ADDED
@@ -0,0 +1,557 @@
1
+ # @arc-js/meta
2
+
3
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
4
+ ![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-007ACC)
5
+ ![React](https://img.shields.io/badge/React-19+-61DAFB)
6
+ ![Vite](https://img.shields.io/badge/Vite-6+-646CFF)
7
+
8
+ **@arc-js/meta** est une bibliothèque React/TypeScript/Javascript légère et performante pour la gestion dynamique des métadonnées HTML (title, description, keywords, author, etc.) dans les applications SPA. Elle permet de mettre à jour les métadonnées de la page de manière déclarative et impérative, avec un support complet de TypeScript, Javascript.
9
+
10
+ ## ✨ Fonctionnalités Principales
11
+
12
+ ### 📄 Gestion Complète des Métadonnées
13
+ - **Mise à jour dynamique du titre** de la page (`<title>`)
14
+ - **Gestion des métadonnées HTML standards** : description, keywords, author, etc.
15
+ - **Support des métadonnées HTTP-EQUIV** (Content-Type, etc.)
16
+ - **Mise à jour en temps réel** lors des changements de route ou d'état
17
+
18
+ ### 🎯 Deux Approches d'Utilisation
19
+ - **Composant déclaratif** `<Metadata />` pour une utilisation simple
20
+ - **Hook impératif** `useMetaActions()` pour un contrôle avancé
21
+ - **API flexible** permettant les deux approches dans la même application
22
+
23
+ ### ⚡ Performance Optimisée
24
+ - **Mises à jour ciblées** uniquement des métadonnées modifiées
25
+ - **Aucune dépendance lourde**
26
+ - **Bundle size minimal** (< 3KB gzipped)
27
+ - **Zéro impact sur le rendu React**
28
+
29
+ ### 🔧 Intégration Facile
30
+ - **Installation en une commande**
31
+ - **Configuration minimale requise**
32
+ - **Compatibilité totale avec TypeScript**
33
+ - **Intégration transparente avec Vite et React Router**
34
+
35
+ ## 📦 Installation
36
+
37
+ ### Via npm/yarn/pnpm
38
+
39
+ ```bash
40
+ npm install @arc-js/meta
41
+ # ou
42
+ yarn add @arc-js/meta
43
+ # ou
44
+ pnpm add @arc-js/meta
45
+ ```
46
+
47
+ ### Dépendances requises
48
+ - React 19+
49
+ - TypeScript 5.0+ (recommandé)
50
+ - Vite (optionnel, mais recommandé)
51
+
52
+ ## 🚀 Démarrage Rapide
53
+
54
+ ### Utilisation avec le composant déclaratif
55
+
56
+ ```typescript
57
+ // App.tsx
58
+ import React from 'react';
59
+ import Metadata from '@arc-js/meta/components';
60
+ import { BrowserRouter, Routes, Route } from 'react-router-dom';
61
+
62
+ const HomePage = () => (
63
+ <>
64
+ <Metadata
65
+ title="Page d'Accueil - Mon Application"
66
+ description="Bienvenue sur notre application révolutionnaire"
67
+ keywords={['accueil', 'application', 'révolutionnaire']}
68
+ author="INICODE Team"
69
+ />
70
+ <h1>Bienvenue !</h1>
71
+ </>
72
+ );
73
+
74
+ const AboutPage = () => (
75
+ <>
76
+ <Metadata
77
+ title="À Propos - Mon Application"
78
+ description="Découvrez notre histoire et notre équipe"
79
+ keywords={['à propos', 'équipe', 'histoire']}
80
+ author="INICODE Team"
81
+ />
82
+ <h1>À Propos</h1>
83
+ </>
84
+ );
85
+
86
+ const App = () => {
87
+ return (
88
+ <BrowserRouter>
89
+ <Routes>
90
+ <Route path="/" element={<HomePage />} />
91
+ <Route path="/about" element={<AboutPage />} />
92
+ </Routes>
93
+ </BrowserRouter>
94
+ );
95
+ };
96
+
97
+ export default App;
98
+ ```
99
+
100
+ ### Utilisation avec le hook impératif
101
+
102
+ ```typescript
103
+ // ProductPage.tsx
104
+ import React, { useEffect } from 'react';
105
+ import { useMetaActions } from '@arc-js/meta/hooks';
106
+
107
+ const ProductPage = ({ product }) => {
108
+ const { setHeader } = useMetaActions();
109
+
110
+ useEffect(() => {
111
+ setHeader({
112
+ title: `\${product.name} - Boutique en ligne`,
113
+ description: product.description,
114
+ keywords: ['produit', product.category, 'achat'],
115
+ author: 'INICODE Shop',
116
+ });
117
+ }, [product]);
118
+
119
+ return (
120
+ <div>
121
+ <h1>{product.name}</h1>
122
+ <p>{product.description}</p>
123
+ </div>
124
+ );
125
+ };
126
+
127
+ export default ProductPage;
128
+ ```
129
+
130
+ ## 📚 Documentation API
131
+
132
+ ### Composant `Metadata`
133
+
134
+ ```typescript
135
+ import Metadata from '@arc-js/meta/components';
136
+
137
+ // Props disponibles
138
+ interface ParamsMetadata {
139
+ title?: string; // Titre de la page (<title>)
140
+ description?: string; // Meta description
141
+ keywords?: string[]; // Mots-clés (seront joints par ', ')
142
+ author?: string; // Auteur de la page
143
+ // ... autres métadonnées supportées
144
+ }
145
+
146
+ // Utilisation
147
+ <Metadata
148
+ title="Mon Titre"
149
+ description="Ma description"
150
+ keywords={['mot1', 'mot2']}
151
+ author="John Doe"
152
+ />
153
+ ```
154
+
155
+ ### Hook `useMetaActions`
156
+
157
+ ```typescript
158
+ import { useMetaActions } from '@arc-js/meta/hooks';
159
+
160
+ const MyComponent = () => {
161
+ const { setHeader } = useMetaActions();
162
+
163
+ // Configuration possible
164
+ interface ConfigSetHeader {
165
+ title?: string;
166
+ description?: string;
167
+ keywords?: string[];
168
+ author?: string;
169
+ subject?: string;
170
+ language?: string;
171
+ // ... toutes les métadonnées HTML standard
172
+ }
173
+
174
+ // Exemple d'utilisation
175
+ const updateMetadata = () => {
176
+ setHeader({
177
+ title: 'Nouveau Titre',
178
+ description: 'Nouvelle description',
179
+ keywords: ['react', 'metadata'],
180
+ author: 'INICODE',
181
+ language: 'fr-FR'
182
+ });
183
+ };
184
+
185
+ return (
186
+ <button onClick={updateMetadata}>
187
+ Mettre à jour les métadonnées
188
+ </button>
189
+ );
190
+ };
191
+ ```
192
+
193
+ ## 🔧 Utilisation Avancée
194
+
195
+ ### Métadonnées personnalisées
196
+
197
+ ```typescript
198
+ // Le système supporte de nombreuses métadonnées HTML
199
+ setHeader({
200
+ title: 'Titre de la page',
201
+ description: 'Description pour les moteurs de recherche',
202
+ keywords: ['technologie', 'react', 'typescript'],
203
+ author: 'Équipe de développement',
204
+ subject: 'Développement Web',
205
+ copyright: '© 2024 INICODE',
206
+ language: 'fr-FR',
207
+ abstract: 'Résumé de la page',
208
+ topic: 'Programmation',
209
+ summary: 'Sommaire du contenu',
210
+ designer: 'Jean Dupont',
211
+ 'reply-to': 'contact@example.com',
212
+ owner: 'INICODE SAS',
213
+ url: 'https://example.com',
214
+ 'identifier-URL': 'https://example.com/page-id'
215
+ });
216
+ ```
217
+
218
+ ### Intégration avec React Router
219
+
220
+ ```typescript
221
+ // routes/MetaRoute.tsx
222
+ import { useEffect } from 'react';
223
+ import { useMetaActions } from '@arc-js/meta/hooks';
224
+
225
+ interface MetaRouteProps {
226
+ children: React.ReactNode;
227
+ title?: string;
228
+ description?: string;
229
+ keywords?: string[];
230
+ }
231
+
232
+ const MetaRoute = ({ children, title, description, keywords }: MetaRouteProps) => {
233
+ const { setHeader } = useMetaActions();
234
+
235
+ useEffect(() => {
236
+ if (title || description || keywords) {
237
+ setHeader({
238
+ title,
239
+ description,
240
+ keywords,
241
+ });
242
+ }
243
+ }, [title, description, keywords]);
244
+
245
+ return <>{children}</>;
246
+ };
247
+
248
+ // Utilisation dans votre router
249
+ <Route
250
+ path="/products/:id"
251
+ element={
252
+ <MetaRoute
253
+ title="Détails du Produit"
254
+ description="Consultez les détails complets de notre produit"
255
+ keywords={['produit', 'détails', 'spécifications']}
256
+ >
257
+ <ProductDetails />
258
+ </MetaRoute>
259
+ }
260
+ />
261
+ ```
262
+
263
+ ### Gestion des métadonnées HTTP-EQUIV
264
+
265
+ ```typescript
266
+ // Le système met automatiquement à jour certaines métadonnées HTTP-EQUIV
267
+ // Par défaut : Content-Type: text/html; charset=UTF-8
268
+ // Extension possible pour supporter d'autres en-têtes
269
+
270
+ // Exemple d'extension personnalisée
271
+ const setCustomHttpEquiv = () => {
272
+ // Le système peut être étendu pour gérer d'autres en-têtes
273
+ // comme refresh, content-security-policy, etc.
274
+ };
275
+ ```
276
+
277
+ ## 🎯 Exemples Complets
278
+
279
+ ### Exemple 1 : Blog avec métadonnées dynamiques
280
+
281
+ ```typescript
282
+ // BlogPost.tsx
283
+ import React, { useEffect } from 'react';
284
+ import { useParams } from 'react-router-dom';
285
+ import { useMetaActions } from '@arc-js/meta/hooks';
286
+ import { blogPosts } from '../data/blogPosts';
287
+
288
+ const BlogPost = () => {
289
+ const { id } = useParams();
290
+ const { setHeader } = useMetaActions();
291
+ const post = blogPosts.find(p => p.id === id);
292
+
293
+ useEffect(() => {
294
+ if (post) {
295
+ setHeader({
296
+ title: `\${post.title} - Mon Blog`,
297
+ description: post.excerpt,
298
+ keywords: [...post.tags, 'blog', 'article'],
299
+ author: post.author,
300
+ subject: post.category,
301
+ });
302
+ }
303
+ }, [post]);
304
+
305
+ if (!post) return <div>Article non trouvé</div>;
306
+
307
+ return (
308
+ <article>
309
+ <h1>{post.title}</h1>
310
+ <div>Par {post.author} • {post.date}</div>
311
+ <div>{post.content}</div>
312
+ </article>
313
+ );
314
+ };
315
+ ```
316
+
317
+ ### Exemple 2 : E-commerce avec métadonnées SEO
318
+
319
+ ```typescript
320
+ // CategoryPage.tsx
321
+ import React, { useEffect } from 'react';
322
+ import { useSearchParams } from 'react-router-dom';
323
+ import { useMetaActions } from '@arc-js/meta/hooks';
324
+ import ProductGrid from '../components/ProductGrid';
325
+ import { getCategoryInfo } from '../api/categories';
326
+
327
+ const CategoryPage = () => {
328
+ const [searchParams] = useSearchParams();
329
+ const categoryId = searchParams.get('category');
330
+ const { setHeader } = useMetaActions();
331
+ const [category, setCategory] = React.useState(null);
332
+
333
+ useEffect(() => {
334
+ const loadCategory = async () => {
335
+ const data = await getCategoryInfo(categoryId);
336
+ setCategory(data);
337
+
338
+ // Mettre à jour les métadonnées
339
+ setHeader({
340
+ title: `\${data.name} - Boutique en ligne`,
341
+ description: `Découvrez notre sélection de \${data.name.toLowerCase()}. \${data.description}`,
342
+ keywords: [data.name, 'achat', 'boutique', ...data.keywords],
343
+ author: 'INICODE E-commerce',
344
+ });
345
+ };
346
+
347
+ if (categoryId) {
348
+ loadCategory();
349
+ }
350
+ }, [categoryId]);
351
+
352
+ return (
353
+ <div>
354
+ {category && (
355
+ <>
356
+ <h1>{category.name}</h1>
357
+ <p>{category.description}</p>
358
+ <ProductGrid categoryId={categoryId} />
359
+ </>
360
+ )}
361
+ </div>
362
+ );
363
+ };
364
+ ```
365
+
366
+ ### Exemple 3 : Application multi-langues
367
+
368
+ ```typescript
369
+ // LocalizedPage.tsx
370
+ import React, { useEffect } from 'react';
371
+ import { useTranslation } from '@arc-js/intl'; // Intégration avec @arc-js/intl
372
+ import { useMetaActions } from '@arc-js/meta/hooks';
373
+
374
+ const LocalizedPage = () => {
375
+ const { t, currentLocale } = useTranslation();
376
+ const { setHeader } = useMetaActions();
377
+
378
+ useEffect(() => {
379
+ // Utiliser les traductions pour les métadonnées
380
+ setHeader({
381
+ title: t('page.title'),
382
+ description: t('page.description'),
383
+ keywords: t('page.keywords', { returnObjects: true }),
384
+ author: t('common.author'),
385
+ language: currentLocale,
386
+ });
387
+ }, [currentLocale, t]);
388
+
389
+ return (
390
+ <div>
391
+ <h1>{t('page.title')}</h1>
392
+ <p>{t('page.content')}</p>
393
+ </div>
394
+ );
395
+ };
396
+ ```
397
+
398
+ ## 🔧 Configuration
399
+
400
+ ### Variables d'environnement
401
+
402
+ ```bash
403
+ # .env
404
+ VITE_APP_TITLE="Mon Application"
405
+ VITE_DEFAULT_AUTHOR="Équipe de développement"
406
+ ```
407
+
408
+ ### Configuration TypeScript
409
+
410
+ ```json
411
+ {
412
+ "compilerOptions": {
413
+ "target": "ES2020",
414
+ "lib": ["DOM", "DOM.Iterable", "ES2020"],
415
+ "module": "ESNext",
416
+ "moduleResolution": "bundler",
417
+ "strict": true,
418
+ "types": ["vite/client"]
419
+ }
420
+ }
421
+ ```
422
+
423
+ ## 🛡️ Gestion des Erreurs
424
+
425
+ ### Fallback automatique
426
+
427
+ ```typescript
428
+ // En cas d'erreur, le système utilise des valeurs par défaut
429
+ const ErrorExample = () => {
430
+ const { setHeader } = useMetaActions();
431
+
432
+ const trySetHeader = () => {
433
+ try {
434
+ setHeader({
435
+ title: undefined, // Sera ignoré
436
+ description: 'Description valide',
437
+ });
438
+ } catch (error) {
439
+ // En mode debug, les erreurs sont loggées
440
+ if (import.meta.env.MODE === 'debug') {
441
+ console.error('Erreur de métadonnées:', error);
442
+ }
443
+
444
+ // Fallback au titre de l'application
445
+ setHeader({
446
+ title: import.meta.env.VITE_APP_TITLE,
447
+ });
448
+ }
449
+ };
450
+
451
+ return <button onClick={trySetHeader}>Tester</button>;
452
+ };
453
+ ```
454
+
455
+ ### Validation des métadonnées
456
+
457
+ ```typescript
458
+ // Fonction utilitaire de validation
459
+ const validateMetadata = (metadata: any) => {
460
+ const errors: string[] = [];
461
+
462
+ if (metadata.title && metadata.title.length > 60) {
463
+ errors.push('Le titre ne doit pas dépasser 60 caractères pour le SEO');
464
+ }
465
+
466
+ if (metadata.description && metadata.description.length > 160) {
467
+ errors.push('La description ne doit pas dépasser 160 caractères pour le SEO');
468
+ }
469
+
470
+ if (metadata.keywords && metadata.keywords.length > 10) {
471
+ errors.push('Il est recommandé de ne pas dépasser 10 mots-clés');
472
+ }
473
+
474
+ return errors;
475
+ };
476
+
477
+ // Utilisation
478
+ const setValidatedHeader = (config: any) => {
479
+ const errors = validateMetadata(config);
480
+
481
+ if (errors.length > 0) {
482
+ console.warn('Avertissements SEO:', errors);
483
+ }
484
+
485
+ setHeader(config);
486
+ };
487
+ ```
488
+
489
+ ## 📋 Table des Métadonnées Supportées
490
+
491
+ ### Métadonnées standard
492
+
493
+ | Nom | Description | Exemple |
494
+ |-----|-------------|---------|
495
+ | `title` | Titre de la page (balise `<title>`) | `Page d'Accueil` |
496
+ | `description` | Description pour le SEO | `Bienvenue sur notre site...` |
497
+ | `keywords` | Mots-clés pour le SEO | `['react', 'typescript', 'vite']` |
498
+ | `author` | Auteur de la page | `INICODE Team` |
499
+ | `subject` | Sujet de la page | `Technologie` |
500
+ | `language` | Langue de la page | `fr-FR` |
501
+ | `copyright` | Droits d'auteur | `© 2024` |
502
+ | `abstract` | Résumé | `Résumé du contenu...` |
503
+ | `topic` | Thème principal | `Développement Web` |
504
+ | `summary` | Sommaire | `Sommaire détaillé...` |
505
+
506
+ ### Métadonnées HTTP-EQUIV
507
+
508
+ | Nom | Description | Valeur par défaut |
509
+ |-----|-------------|-------------------|
510
+ | `Content-Type` | Type de contenu et encodage | `text/html; charset=UTF-8` |
511
+
512
+ ## 🔧 Build et Développement
513
+
514
+ ### Scripts recommandés
515
+
516
+ ```json
517
+ {
518
+ "scripts": {
519
+ "dev": "vite",
520
+ "build": "tsc && vite build",
521
+ "preview": "vite preview",
522
+ "type-check": "tsc --noEmit"
523
+ }
524
+ }
525
+ ```
526
+
527
+ ### Structure de projet recommandée
528
+
529
+ ```
530
+ src/
531
+ ├── components/
532
+ │ ├── MetadataWrapper.tsx # Wrapper personnalisé
533
+ │ └── SeoManager.tsx # Gestionnaire SEO avancé
534
+ ├── hooks/
535
+ │ └── useMetadata.ts # Hook personnalisé étendu
536
+ ├── utils/
537
+ │ └── metadata-validator.ts # Validateur de métadonnées
538
+ └── main.tsx
539
+ ```
540
+
541
+ ## 📄 Licence
542
+
543
+ MIT License - Voir le fichier [LICENSE](LICENSE) pour plus de détails.
544
+
545
+ ## 🐛 Signaler un Bug
546
+
547
+ Envoyez-nous un mail à l'adresse `contact.inicode@gmail.com` pour :
548
+ - Signaler un bug
549
+ - Proposer une amélioration
550
+ - Poser une question sur l'utilisation
551
+ - Demander une nouvelle fonctionnalité
552
+
553
+ ---
554
+
555
+ **@arc-js/meta** - La solution simple et efficace pour gérer les métadonnées dans React.
556
+
557
+ *Développé par l'équipe INICODE*
package/components.jsx ADDED
@@ -0,0 +1,33 @@
1
+ import { useEffect } from 'react';
2
+ import { setHeader } from './utils';
3
+ import { useConfig } from '@arc-js/config-manager';
4
+ import { useTranslation } from '@arc-js/intl/hooks/useTranslation';
5
+ import React from "react"
6
+
7
+
8
+ function Metadata(params) {
9
+ const {
10
+ isLoading
11
+ } = useConfig();
12
+ const {
13
+ currentLocale
14
+ } = useTranslation();
15
+ useEffect(() => {
16
+ setHeader({
17
+ title: params.title,
18
+ description: params.description,
19
+ keywords: params.keywords,
20
+ author: params.author
21
+ });
22
+ }, []);
23
+ useEffect(() => {
24
+ setHeader({
25
+ title: params.title,
26
+ description: params.description,
27
+ keywords: params.keywords,
28
+ author: params.author
29
+ });
30
+ }, [isLoading, currentLocale]);
31
+ return React.createElement(React.Fragment, null);
32
+ }
33
+ export default Metadata;
package/components.tsx ADDED
@@ -0,0 +1,41 @@
1
+
2
+ import { useEffect } from 'react';
3
+ import { setHeader } from './utils';
4
+ import { useConfig } from '@arc-js/config-manager';
5
+ import { useTranslation } from '@arc-js/intl/hooks/useTranslation';
6
+
7
+
8
+
9
+ interface ParamsMetadata {
10
+ title?: string;
11
+ description?: string;
12
+ keywords?: string[];
13
+ author?: string;
14
+ };
15
+
16
+
17
+ function Metadata(params: ParamsMetadata) {
18
+ const { isLoading } = useConfig();
19
+ const { currentLocale } = useTranslation();
20
+
21
+ useEffect(() => {
22
+ setHeader({
23
+ title: params.title,
24
+ description: params.description,
25
+ keywords: params.keywords,
26
+ author: params.author,
27
+ });
28
+ }, []);
29
+ useEffect(() => {
30
+ setHeader({
31
+ title: params.title,
32
+ description: params.description,
33
+ keywords: params.keywords,
34
+ author: params.author,
35
+ });
36
+ }, [ isLoading, currentLocale ]);
37
+
38
+ return (<></>);
39
+ }
40
+
41
+ export default Metadata;
package/hooks.jsx ADDED
@@ -0,0 +1,27 @@
1
+
2
+ import React from "react";
3
+ import * as utils from './utils';
4
+
5
+ export const useMetaActions = () => {
6
+ const setHeader = config => {
7
+ const AppName = 'APP';
8
+ try {
9
+ const headerConf = {
10
+ title: config.title,
11
+ description: config.description,
12
+ keywords: config.keywords,
13
+ author: config.author
14
+ };
15
+ utils.setHeader(headerConf);
16
+ return headerConf;
17
+ } catch (error) {
18
+ console.log(error);
19
+ return {
20
+ title: AppName
21
+ };
22
+ }
23
+ };
24
+ return {
25
+ setHeader
26
+ };
27
+ };
package/hooks.tsx ADDED
@@ -0,0 +1,51 @@
1
+
2
+ import * as utils from './utils';
3
+
4
+
5
+
6
+ interface ConfigSetHeader {
7
+ title?: string;
8
+ description?: string;
9
+ keywords?: string[];
10
+ author?: string;
11
+ }
12
+
13
+ interface ResultSetHeader {
14
+ title?: string;
15
+ description?: string;
16
+ keywords?: string[];
17
+ author?: string;
18
+ }
19
+
20
+ interface MetaActionReturns {
21
+ setHeader: (config: ConfigSetHeader) => void;
22
+ }
23
+
24
+
25
+ export const useMetaActions = () => {
26
+
27
+ const setHeader = (config: ConfigSetHeader) => {
28
+ const AppName: string = 'APP';
29
+ try {
30
+ const headerConf = {
31
+ title: config.title,
32
+ description: config.description,
33
+ keywords: config.keywords,
34
+ author: config.author,
35
+ };
36
+ utils.setHeader(headerConf);
37
+
38
+ return headerConf as ResultSetHeader;
39
+ } catch (error) {
40
+ console.log(error);
41
+
42
+ return {
43
+ title: AppName,
44
+ } as ResultSetHeader;
45
+ }
46
+ };
47
+
48
+ return {
49
+ setHeader,
50
+ } as MetaActionReturns;
51
+ }
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@arc-js/meta",
3
+ "publishConfig": {
4
+ "access": "public"
5
+ },
6
+ "version": "0.0.1",
7
+ "description": "META est une bibliothèque React/TypeScript/Javascript légère et performante pour la gestion dynamique des métadonnées HTML (title, description, keywords, author, etc.) dans les applications SPA. Elle permet de mettre à jour les métadonnées de la page de manière déclarative et impérative, avec un support complet de TypeScript, Javascript.",
8
+ "main": "index.js",
9
+ "keywords": [],
10
+ "author": "INICODE <contact.inicode@gmail.com>",
11
+ "license": "MIT",
12
+ "scripts": {
13
+ "init": "npm init --scope=@arc-js/meta",
14
+ "login": "npm login"
15
+ },
16
+ "devDependencies": {
17
+ "@vitejs/plugin-react": "^4.3.4",
18
+ "vite": "^6.4.1"
19
+ },
20
+ "dependencies": {
21
+ "react-router-dom": "^7.11.0",
22
+ "react": "^19.2.3",
23
+ "react-dom": "^19.2.3",
24
+ "@arc-js/intl": "^0.0.7",
25
+ "@arc-js/config-manager": "^0.0.2"
26
+ }
27
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable", "ESNext"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+
9
+ "moduleResolution": "bundler",
10
+ "allowImportingTsExtensions": true,
11
+ "isolatedModules": true,
12
+ "moduleDetection": "force",
13
+ "noEmit": true,
14
+ "jsx": "react-jsx",
15
+
16
+ "strict": true,
17
+ "noUnusedLocals": true,
18
+ "noUnusedParameters": true,
19
+ "noFallthroughCasesInSwitch": true,
20
+ "noUncheckedSideEffectImports": true
21
+ },
22
+ "include": ["src/**/*"],
23
+ "exclude": [
24
+ "node_modules",
25
+ "**/*.d.ts"
26
+ ]
27
+ }
package/utils.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ declare function setHeader(header: {
2
+ title?: string;
3
+ description?: string;
4
+ keywords?: string[];
5
+ author?: string;
6
+ }): void;
7
+
8
+ export { setHeader };
package/utils.js ADDED
@@ -0,0 +1,79 @@
1
+ function setHeader(header) {
2
+ const allHeader = (typeof header === 'object' &&
3
+ Array.isArray(header) == false) ? header : {};
4
+ const datas = {
5
+ title: (typeof (allHeader === null || allHeader === void 0 ? void 0 : allHeader.title) === 'string' && (allHeader === null || allHeader === void 0 ? void 0 : allHeader.title.length) > 0 ? `${allHeader === null || allHeader === void 0 ? void 0 : allHeader.title}` : undefined),
6
+ };
7
+ const metadatas = {
8
+ author: allHeader === null || allHeader === void 0 ? void 0 : allHeader.author,
9
+ description: ((typeof (allHeader === null || allHeader === void 0 ? void 0 : allHeader.description) === 'string' &&
10
+ (allHeader === null || allHeader === void 0 ? void 0 : allHeader.description.length) > 0) ? allHeader === null || allHeader === void 0 ? void 0 : allHeader.description : undefined),
11
+ keywords: ((typeof allHeader.keywords == 'object' &&
12
+ Array.isArray(allHeader.keywords) == true &&
13
+ allHeader.keywords.length > 0) ? allHeader.keywords.join(', ') : undefined),
14
+ subject: ((typeof (allHeader === null || allHeader === void 0 ? void 0 : allHeader.subject) === 'string' &&
15
+ (allHeader === null || allHeader === void 0 ? void 0 : allHeader.subject.length) > 0) ? allHeader === null || allHeader === void 0 ? void 0 : allHeader.subject : undefined),
16
+ copyright: ((typeof (allHeader === null || allHeader === void 0 ? void 0 : allHeader.copyright) === 'string' &&
17
+ (allHeader === null || allHeader === void 0 ? void 0 : allHeader.copyright.length) > 0) ? allHeader === null || allHeader === void 0 ? void 0 : allHeader.copyright : undefined),
18
+ language: ((typeof (allHeader === null || allHeader === void 0 ? void 0 : allHeader.language) === 'string' &&
19
+ (allHeader === null || allHeader === void 0 ? void 0 : allHeader.language.length) > 0) ? allHeader === null || allHeader === void 0 ? void 0 : allHeader.language : undefined),
20
+ abstract: ((typeof (allHeader === null || allHeader === void 0 ? void 0 : allHeader.abstract) === 'string' &&
21
+ (allHeader === null || allHeader === void 0 ? void 0 : allHeader.abstract.length) > 0) ? allHeader === null || allHeader === void 0 ? void 0 : allHeader.abstract : undefined),
22
+ topic: ((typeof (allHeader === null || allHeader === void 0 ? void 0 : allHeader.topic) === 'string' &&
23
+ (allHeader === null || allHeader === void 0 ? void 0 : allHeader.topic.length) > 0) ? allHeader === null || allHeader === void 0 ? void 0 : allHeader.topic : undefined),
24
+ summary: ((typeof (allHeader === null || allHeader === void 0 ? void 0 : allHeader.summary) === 'string' &&
25
+ (allHeader === null || allHeader === void 0 ? void 0 : allHeader.summary.length) > 0) ? allHeader === null || allHeader === void 0 ? void 0 : allHeader.summary : undefined),
26
+ Classification: ((typeof (allHeader === null || allHeader === void 0 ? void 0 : allHeader.Classification) === 'string' &&
27
+ (allHeader === null || allHeader === void 0 ? void 0 : allHeader.Classification.length) > 0) ? allHeader === null || allHeader === void 0 ? void 0 : allHeader.Classification : undefined),
28
+ designer: ((typeof (allHeader === null || allHeader === void 0 ? void 0 : allHeader.designer) === 'string' &&
29
+ (allHeader === null || allHeader === void 0 ? void 0 : allHeader.designer.length) > 0) ? allHeader === null || allHeader === void 0 ? void 0 : allHeader.designer : undefined),
30
+ 'reply-to': ((typeof allHeader['reply-to'] === 'string' &&
31
+ allHeader['reply-to'].length > 0) ? allHeader['reply-to'] : undefined),
32
+ owner: ((typeof (allHeader === null || allHeader === void 0 ? void 0 : allHeader.owner) === 'string' &&
33
+ (allHeader === null || allHeader === void 0 ? void 0 : allHeader.owner.length) > 0) ? allHeader === null || allHeader === void 0 ? void 0 : allHeader.owner : undefined),
34
+ url: ((typeof (allHeader === null || allHeader === void 0 ? void 0 : allHeader.url) === 'string' &&
35
+ (allHeader === null || allHeader === void 0 ? void 0 : allHeader.url.length) > 0) ? allHeader === null || allHeader === void 0 ? void 0 : allHeader.url : undefined),
36
+ 'identifier-URL': ((typeof allHeader['identifier-URL'] === 'string' &&
37
+ allHeader['identifier-URL'].length > 0) ? allHeader['identifier-URL'] : undefined),
38
+ };
39
+ const metadataHttpEquiv = {
40
+ 'Content-Type': 'text/html; charset=UTF-8',
41
+ };
42
+ if (!!datas.title) {
43
+ document.title = datas.title;
44
+ }
45
+ Object.keys(metadatas).map((key) => {
46
+ var _a;
47
+ const metadata = metadatas[key];
48
+ if (!!metadata) {
49
+ let selector = document.querySelector(`meta[name="${key}"]`);
50
+ if (!selector) {
51
+ const newElement = document.createElement("meta");
52
+ newElement.setAttribute("name", key);
53
+ (_a = document.querySelector('head')) === null || _a === void 0 ? void 0 : _a.appendChild(newElement);
54
+ }
55
+ selector = document.querySelector(`meta[name="${key}"]`);
56
+ if (selector) {
57
+ selector === null || selector === void 0 ? void 0 : selector.setAttribute("content", metadata);
58
+ }
59
+ }
60
+ });
61
+ Object.keys(metadataHttpEquiv).map((key) => {
62
+ var _a;
63
+ const metadata = metadataHttpEquiv[key];
64
+ if (!!metadata) {
65
+ let selector = document.querySelector(`meta[http-equiv="${key}"]`);
66
+ if (!selector) {
67
+ const newElement = document.createElement("meta");
68
+ newElement.setAttribute("http-equiv", key);
69
+ (_a = document.querySelector('head')) === null || _a === void 0 ? void 0 : _a.appendChild(newElement);
70
+ }
71
+ selector = document.querySelector(`meta[http-equiv="${key}"]`);
72
+ if (selector) {
73
+ selector === null || selector === void 0 ? void 0 : selector.setAttribute("content", metadata);
74
+ }
75
+ }
76
+ });
77
+ }
78
+
79
+ export { setHeader };
package/utils.min.js ADDED
@@ -0,0 +1,2 @@
1
+ function setHeader(t){var t="object"==typeof t&&0==Array.isArray(t)?t:{},e={title:"string"==typeof(null==t?void 0:t.title)&&0<(null==t?void 0:t.title.length)?""+(null==t?void 0:t.title):void 0};let o={author:null==t?void 0:t.author,description:!("string"==typeof(null==t?void 0:t.description)&&0<(null==t?void 0:t.description.length))||null==t?void 0:t.description,keywords:"object"==typeof t.keywords&&1==Array.isArray(t.keywords)&&0<t.keywords.length?t.keywords.join(", "):void 0,subject:!("string"==typeof(null==t?void 0:t.subject)&&0<(null==t?void 0:t.subject.length))||null==t?void 0:t.subject,copyright:!("string"==typeof(null==t?void 0:t.copyright)&&0<(null==t?void 0:t.copyright.length))||null==t?void 0:t.copyright,language:!("string"==typeof(null==t?void 0:t.language)&&0<(null==t?void 0:t.language.length))||null==t?void 0:t.language,abstract:!("string"==typeof(null==t?void 0:t.abstract)&&0<(null==t?void 0:t.abstract.length))||null==t?void 0:t.abstract,topic:!("string"==typeof(null==t?void 0:t.topic)&&0<(null==t?void 0:t.topic.length))||null==t?void 0:t.topic,summary:!("string"==typeof(null==t?void 0:t.summary)&&0<(null==t?void 0:t.summary.length))||null==t?void 0:t.summary,Classification:!("string"==typeof(null==t?void 0:t.Classification)&&0<(null==t?void 0:t.Classification.length))||null==t?void 0:t.Classification,designer:!("string"==typeof(null==t?void 0:t.designer)&&0<(null==t?void 0:t.designer.length))||null==t?void 0:t.designer,"reply-to":"string"==typeof t["reply-to"]&&0<t["reply-to"].length?t["reply-to"]:void 0,owner:!("string"==typeof(null==t?void 0:t.owner)&&0<(null==t?void 0:t.owner.length))||null==t?void 0:t.owner,url:!("string"==typeof(null==t?void 0:t.url)&&0<(null==t?void 0:t.url.length))||null==t?void 0:t.url,"identifier-URL":"string"==typeof t["identifier-URL"]&&0<t["identifier-URL"].length?t["identifier-URL"]:void 0},r={"Content-Type":"text/html; charset=UTF-8"};e.title&&(document.title=e.title),Object.keys(o).map(t=>{var e,l,i,n=o[t];n&&((l=document.querySelector(`meta[name="${t}"]`))||((i=document.createElement("meta")).setAttribute("name",t),null!=(e=document.querySelector("head"))&&e.appendChild(i)),l=document.querySelector(`meta[name="${t}"]`))&&null!=l&&l.setAttribute("content",n)}),Object.keys(r).map(t=>{var e,l,i,n=r[t];n&&((l=document.querySelector(`meta[http-equiv="${t}"]`))||((i=document.createElement("meta")).setAttribute("http-equiv",t),null!=(e=document.querySelector("head"))&&e.appendChild(i)),l=document.querySelector(`meta[http-equiv="${t}"]`))&&null!=l&&l.setAttribute("content",n)})}export{setHeader};
2
+ //# sourceMappingURL=utils.min.js.map