@devsantara/head 0.2.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.
- package/LICENSE +21 -0
- package/README.md +330 -0
- package/dist/adapters/index.d.ts +39 -0
- package/dist/adapters/index.js +72 -0
- package/dist/index.d.ts +293 -0
- package/dist/index.js +484 -0
- package/dist/types-Cvpk_Zha.d.ts +455 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Devsantara
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
# @devsantara/head
|
|
2
|
+
|
|
3
|
+
**A lightweight, type-safe HTML `<head>` builder for modern web applications.**
|
|
4
|
+
|
|
5
|
+
Build SEO-friendly metadata with a fluent API, full TypeScript support, and framework adapters for **React**, **TanStack Router/Start**, and more.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
> [!WARNING]
|
|
10
|
+
> **Early Development**: This library is in active development (v0.x.x). Expect breaking changes between minor versions until v1.0. We recommend pinning to exact versions in production.
|
|
11
|
+
|
|
12
|
+
## ✨ Features
|
|
13
|
+
|
|
14
|
+
### Developer Experience First
|
|
15
|
+
|
|
16
|
+
- **Fluent Builder API** – Chain methods naturally for readable, maintainable metadata configuration
|
|
17
|
+
- **Full TypeScript Support** – Autocomplete, type checking, and inline documentation in your IDE
|
|
18
|
+
- **Zero Dependencies** – Lightweight core with optional framework adapters
|
|
19
|
+
|
|
20
|
+
### Comprehensive Head Management
|
|
21
|
+
|
|
22
|
+
- **SEO Essentials** – Title, description, canonical URLs, robots directives.
|
|
23
|
+
- **Social Media** – Open Graph and Twitter Card meta tags for rich previews.
|
|
24
|
+
- **Mobile Optimization** – Viewport configuration, color schemes, PWA icons.
|
|
25
|
+
- **Advanced Tags** – Alternates, manifests, stylesheets, scripts, and custom meta tags.
|
|
26
|
+
- **Simplified URL Management** – Most metadata (Open Graph, canonical, alternates) requires absolute URLs. Set `metadataBase` once and use convenient relative paths everywhere.
|
|
27
|
+
- **Continuously Expanding** – Actively adding more metadata types based on community feedback.
|
|
28
|
+
|
|
29
|
+
### Framework Integration
|
|
30
|
+
|
|
31
|
+
- **React Adapter** – Generate React components directly from your metadata
|
|
32
|
+
- **TanStack Router** – First-class support for route-level metadata
|
|
33
|
+
- **Framework Agnostic** – Works with vanilla JS, SSR, SSG, or any rendering strategy
|
|
34
|
+
|
|
35
|
+
## 📦 Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# npm
|
|
39
|
+
npm install @devsantara/head
|
|
40
|
+
|
|
41
|
+
# pnpm
|
|
42
|
+
pnpm add @devsantara/head
|
|
43
|
+
|
|
44
|
+
# yarn
|
|
45
|
+
yarn add @devsantara/head
|
|
46
|
+
|
|
47
|
+
# bun
|
|
48
|
+
bun add @devsantara/head
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
> **Note:** Framework adapters are included in the core package. No additional installations needed.
|
|
52
|
+
|
|
53
|
+
## 🚀 Quick Start
|
|
54
|
+
|
|
55
|
+
### Basic Usage
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { HeadBuilder } from '@devsantara/head';
|
|
59
|
+
|
|
60
|
+
const head = new HeadBuilder()
|
|
61
|
+
.addTitle('My Awesome Website')
|
|
62
|
+
.addDescription('A comprehensive guide to web development')
|
|
63
|
+
.addViewport({ width: 'device-width', initialScale: 1 })
|
|
64
|
+
.build();
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// Output (HeadElement[]):
|
|
69
|
+
[
|
|
70
|
+
{
|
|
71
|
+
type: 'title',
|
|
72
|
+
attributes: { children: 'My Awesome Website' },
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
type: 'meta',
|
|
76
|
+
attributes: {
|
|
77
|
+
name: 'description',
|
|
78
|
+
content: 'A comprehensive guide to web development',
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
type: 'meta',
|
|
83
|
+
attributes: {
|
|
84
|
+
name: 'viewport',
|
|
85
|
+
content: 'width=device-width, initial-scale=1',
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
];
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### With Metadata Base URL
|
|
92
|
+
|
|
93
|
+
Use `metadataBase` to automatically resolve relative URLs to absolute URLs:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { HeadBuilder } from '@devsantara/head';
|
|
97
|
+
|
|
98
|
+
const head = new HeadBuilder({
|
|
99
|
+
metadataBase: new URL('https://devsantara.com'), // <- Add metadata base URL
|
|
100
|
+
})
|
|
101
|
+
.addTitle('My Blog Post')
|
|
102
|
+
.addOpenGraph((helper) => ({
|
|
103
|
+
title: 'My Blog Post',
|
|
104
|
+
url: helper.resolveUrl('/blog/my-post'),
|
|
105
|
+
image: {
|
|
106
|
+
url: helper.resolveUrl('/images/og-image.jpg'),
|
|
107
|
+
},
|
|
108
|
+
}))
|
|
109
|
+
.build();
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// Output (HeadElement[]):
|
|
114
|
+
[
|
|
115
|
+
{
|
|
116
|
+
type: 'title',
|
|
117
|
+
attributes: { children: 'My Blog Post' },
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
type: 'meta',
|
|
121
|
+
attributes: {
|
|
122
|
+
property: 'og:title',
|
|
123
|
+
content: 'My Blog Post',
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
type: 'meta',
|
|
128
|
+
attributes: {
|
|
129
|
+
property: 'og:url',
|
|
130
|
+
content: 'https://devsantara.com/blog/my-post',
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
type: 'meta',
|
|
135
|
+
attributes: {
|
|
136
|
+
property: 'og:image',
|
|
137
|
+
content: 'https://devsantara.com/images/og-image.jpg',
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
];
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### With React Adapter
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
import { HeadBuilder } from '@devsantara/head';
|
|
147
|
+
import { HeadReactAdapter } from '@devsantara/head/adapters';
|
|
148
|
+
|
|
149
|
+
const head = new HeadBuilder({
|
|
150
|
+
adapter: new HeadReactAdapter(), // <- Add React adapter
|
|
151
|
+
})
|
|
152
|
+
.addTitle('My Awesome Website')
|
|
153
|
+
.addDescription('A comprehensive guide to web development')
|
|
154
|
+
.build();
|
|
155
|
+
|
|
156
|
+
// Use in your document
|
|
157
|
+
export function Document() {
|
|
158
|
+
return (
|
|
159
|
+
<html>
|
|
160
|
+
<head>{head}</head>
|
|
161
|
+
{/* ... */}
|
|
162
|
+
</html>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
// Output (React.ReactNode[]):
|
|
169
|
+
[
|
|
170
|
+
<title>My Awesome Website</title>,
|
|
171
|
+
<meta
|
|
172
|
+
name="description"
|
|
173
|
+
content="A comprehensive guide to web development"
|
|
174
|
+
/>,
|
|
175
|
+
];
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### With TanStack Router/Start Adapter
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
import { HeadBuilder } from '@devsantara/head';
|
|
182
|
+
import { HeadTanstackRouterAdapter } from '@devsantara/head/adapters';
|
|
183
|
+
import { createRootRoute } from '@tanstack/react-router';
|
|
184
|
+
|
|
185
|
+
export const Route = createRootRoute({
|
|
186
|
+
head: () => {
|
|
187
|
+
return new HeadBuilder({
|
|
188
|
+
adapter: new HeadTanstackRouterAdapter(), // <- Add Tanstack router adapter
|
|
189
|
+
})
|
|
190
|
+
.addTitle('About Us')
|
|
191
|
+
.addDescription('Learn more about our company')
|
|
192
|
+
.build();
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// Output (Tanstack Router Head[]):
|
|
199
|
+
[
|
|
200
|
+
meta: [
|
|
201
|
+
{ title: 'About Us' },
|
|
202
|
+
{
|
|
203
|
+
name: 'description',
|
|
204
|
+
content: 'Learn more about our company',
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
links:[],
|
|
208
|
+
scripts:[],
|
|
209
|
+
styles: []
|
|
210
|
+
]
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## 📚 API Reference
|
|
214
|
+
|
|
215
|
+
### Core Methods
|
|
216
|
+
|
|
217
|
+
| Method | Description |
|
|
218
|
+
| --------- | -------------------------------------------------------------- |
|
|
219
|
+
| `build()` | Builds and returns the final head elements (or adapted output) |
|
|
220
|
+
|
|
221
|
+
### Basic Elements
|
|
222
|
+
|
|
223
|
+
For advanced use cases not covered by the essential methods below, use these basic methods to add any custom element directly.
|
|
224
|
+
|
|
225
|
+
| Method | Description |
|
|
226
|
+
| ------------------------------------------------------- | ------------------------------------------------ |
|
|
227
|
+
| `addTitle(title: string)` | Adds a `<title>` element |
|
|
228
|
+
| `addMeta(attributes: HeadAttributeTypeMap['meta'])` | Adds a `<meta>` element with custom attributes |
|
|
229
|
+
| `addLink(attributes: HeadAttributeTypeMap['link'])` | Adds a `<link>` element with custom attributes |
|
|
230
|
+
| `addScript(attributes: HeadAttributeTypeMap['script'])` | Adds a `<script>` element with custom attributes |
|
|
231
|
+
| `addStyle(attributes: HeadAttributeTypeMap['style'])` | Adds a `<style>` element with custom attributes |
|
|
232
|
+
|
|
233
|
+
### Essential Methods
|
|
234
|
+
|
|
235
|
+
High-level convenience methods for common metadata patterns. These methods handle the complexity of creating properly structured head.
|
|
236
|
+
|
|
237
|
+
| Method | Description |
|
|
238
|
+
| ---------------------------------------------------------------------- | ----------------------------------------------------------- |
|
|
239
|
+
| `addDescription(description: string)` | Adds a meta description tag |
|
|
240
|
+
| `addCanonical(valueOrFn: BuilderOption<string \| URL>)` | Adds a canonical URL link |
|
|
241
|
+
| `addRobots(options: RobotsOptions)` | Adds robots meta tag for search engine directives |
|
|
242
|
+
| `addCharSet(charset: CharSet)` | Adds character encoding declaration |
|
|
243
|
+
| `addViewport(options: ViewportOptions)` | Adds viewport configuration for responsive design |
|
|
244
|
+
| `addColorScheme(colorScheme: ColorScheme)` | Adds color scheme preference (light/dark mode) |
|
|
245
|
+
| `addOpenGraph(valueOrFn: BuilderOption<OpenGraphOptions>)` | Adds Open Graph meta tags for social media previews |
|
|
246
|
+
| `addTwitter(valueOrFn: BuilderOption<TwitterOptions>)` | Adds Twitter Card meta tags |
|
|
247
|
+
| `addIcon(preset: IconPreset, valueOrFn: BuilderOption<IconOptions>)` | Adds favicon or app icons (favicon, apple-touch-icon, etc.) |
|
|
248
|
+
| `addStylesheet(href: string \| URL, options?: StylesheetOptions)` | Adds an external stylesheet link |
|
|
249
|
+
| `addManifest(valueOrFn: BuilderOption<string \| URL>)` | Adds a web app manifest link |
|
|
250
|
+
| `addAlternateLocale(valueOrFn: BuilderOption<AlternateLocaleOptions>)` | Adds alternate language/locale links |
|
|
251
|
+
|
|
252
|
+
> **💡 Tip:** Most methods support either direct values or callback functions that receive a helper object with `resolveUrl()` for dynamic URL resolution.
|
|
253
|
+
|
|
254
|
+
## 🔌 Adapters
|
|
255
|
+
|
|
256
|
+
Adapters transform the raw `HeadElement[]` output into framework-specific formats. The library includes built-in adapters for popular frameworks, and you can create custom adapters for your specific needs.
|
|
257
|
+
|
|
258
|
+
### Built-in Adapters
|
|
259
|
+
|
|
260
|
+
| Framework | Adapter | Output Type |
|
|
261
|
+
| --------------------- | --------------------------- | ----------------------------- |
|
|
262
|
+
| React | `HeadReactAdapter` | `React.ReactNode[]` |
|
|
263
|
+
| Tanstack Router/Start | `HeadTanstackRouterAdapter` | TanStack Router `Head` object |
|
|
264
|
+
|
|
265
|
+
### Creating Custom Adapters
|
|
266
|
+
|
|
267
|
+
You can create your own adapter by implementing the `HeadAdapter<T>` interface:
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
import type { HeadAdapter, HeadElement } from '@devsantara/head';
|
|
271
|
+
|
|
272
|
+
// Create a custom adapter that outputs HTML strings
|
|
273
|
+
class HeadHTMLAdapter implements HeadAdapter<string> {
|
|
274
|
+
transform(elements: HeadElement[]): string {
|
|
275
|
+
return elements
|
|
276
|
+
.map((element) => {
|
|
277
|
+
const { type, attributes } = element;
|
|
278
|
+
const attrs = Object.entries(attributes)
|
|
279
|
+
.filter(([key]) => key !== 'children')
|
|
280
|
+
.map(([key, value]) => `${key}="${value}"`)
|
|
281
|
+
.join(' ');
|
|
282
|
+
|
|
283
|
+
const children = attributes.children || '';
|
|
284
|
+
|
|
285
|
+
if (type === 'meta' || type === 'link') {
|
|
286
|
+
return `<${type} ${attrs}>`;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return `<${type} ${attrs}>${children}</${type}>`;
|
|
290
|
+
})
|
|
291
|
+
.join('\n');
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
// Use your custom adapter
|
|
298
|
+
const html = new HeadBuilder({
|
|
299
|
+
adapter: new HeadHTMLAdapter(), // <- Add custom HTML adapter
|
|
300
|
+
})
|
|
301
|
+
.addTitle('My Site')
|
|
302
|
+
.addDescription('My description')
|
|
303
|
+
.build();
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
```html
|
|
307
|
+
<!-- Output (HTML string) -->
|
|
308
|
+
<title>My Site</title>
|
|
309
|
+
<meta name="description" content="My description" />
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Adapter Interface
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
interface HeadAdapter<T> {
|
|
316
|
+
transform(elements: HeadElement[]): T;
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**Parameters:**
|
|
321
|
+
|
|
322
|
+
- `elements` - Array of head elements with `type` and `attributes`
|
|
323
|
+
|
|
324
|
+
**Returns:**
|
|
325
|
+
|
|
326
|
+
- `T` - Your custom output format (string, object, framework components, etc.)
|
|
327
|
+
|
|
328
|
+
## 📄 License
|
|
329
|
+
|
|
330
|
+
Licensed under the [MIT license](./LICENSE).
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { c as HeadMetaAttributes, i as HeadAdapter, l as HeadScriptAttributes, o as HeadElement, s as HeadLinkAttributes, u as HeadStyleAttributes } from "../types-Cvpk_Zha.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/adapters/react-adapter.d.ts
|
|
5
|
+
type HeadReactAdapterResult = ReactNode[];
|
|
6
|
+
/**
|
|
7
|
+
* Adapter that transforms head elements into React components for rendering in React applications.
|
|
8
|
+
*/
|
|
9
|
+
declare class HeadReactAdapter implements HeadAdapter<HeadReactAdapterResult> {
|
|
10
|
+
/**
|
|
11
|
+
* Transforms head elements into React components.
|
|
12
|
+
*
|
|
13
|
+
* @param elements - Array of head elements to transform
|
|
14
|
+
* @returns Array of React components ready for rendering
|
|
15
|
+
*/
|
|
16
|
+
transform(elements: HeadElement[]): HeadReactAdapterResult;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/adapters/tanstack-router-adapter.d.ts
|
|
20
|
+
interface HeadTanStackRouterAdapterResult {
|
|
21
|
+
links?: HeadLinkAttributes[];
|
|
22
|
+
scripts?: HeadScriptAttributes[];
|
|
23
|
+
meta?: HeadMetaAttributes[];
|
|
24
|
+
styles?: HeadStyleAttributes[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Adapter that transforms head elements into TanStack Router head configuration format.
|
|
28
|
+
*/
|
|
29
|
+
declare class HeadTanstackRouterAdapter implements HeadAdapter<HeadTanStackRouterAdapterResult> {
|
|
30
|
+
/**
|
|
31
|
+
* Transforms head elements into TanStack Router head configuration with elements organized by type.
|
|
32
|
+
*
|
|
33
|
+
* @param elements - Array of head elements to transform
|
|
34
|
+
* @returns Head configuration object with categorized elements
|
|
35
|
+
*/
|
|
36
|
+
transform(elements: HeadElement[]): HeadTanStackRouterAdapterResult;
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { HeadReactAdapter, HeadReactAdapterResult, HeadTanStackRouterAdapterResult, HeadTanstackRouterAdapter };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { createElement } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/react-adapter.ts
|
|
4
|
+
/**
|
|
5
|
+
* Adapter that transforms head elements into React components for rendering in React applications.
|
|
6
|
+
*/
|
|
7
|
+
var HeadReactAdapter = class {
|
|
8
|
+
/**
|
|
9
|
+
* Transforms head elements into React components.
|
|
10
|
+
*
|
|
11
|
+
* @param elements - Array of head elements to transform
|
|
12
|
+
* @returns Array of React components ready for rendering
|
|
13
|
+
*/
|
|
14
|
+
transform(elements) {
|
|
15
|
+
return elements.map((element, index) => {
|
|
16
|
+
const { type, attributes } = element;
|
|
17
|
+
return createElement(type, {
|
|
18
|
+
key: `head-${type}-${index}`,
|
|
19
|
+
...attributes
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/utils.ts
|
|
27
|
+
/**
|
|
28
|
+
* Type guard that checks if a head element matches a specific element type.
|
|
29
|
+
*
|
|
30
|
+
* @param element - The head element to check
|
|
31
|
+
* @param type - The expected element type
|
|
32
|
+
* @returns True if the element matches the specified type
|
|
33
|
+
*/
|
|
34
|
+
function isElementOfType(element, type) {
|
|
35
|
+
return element.type === type;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/adapters/tanstack-router-adapter.ts
|
|
40
|
+
/**
|
|
41
|
+
* Adapter that transforms head elements into TanStack Router head configuration format.
|
|
42
|
+
*/
|
|
43
|
+
var HeadTanstackRouterAdapter = class {
|
|
44
|
+
/**
|
|
45
|
+
* Transforms head elements into TanStack Router head configuration with elements organized by type.
|
|
46
|
+
*
|
|
47
|
+
* @param elements - Array of head elements to transform
|
|
48
|
+
* @returns Head configuration object with categorized elements
|
|
49
|
+
*/
|
|
50
|
+
transform(elements) {
|
|
51
|
+
const config = {
|
|
52
|
+
meta: [],
|
|
53
|
+
links: [],
|
|
54
|
+
scripts: [],
|
|
55
|
+
styles: []
|
|
56
|
+
};
|
|
57
|
+
for (const element of elements) if (isElementOfType(element, "meta")) config.meta?.push(element.attributes);
|
|
58
|
+
else if (isElementOfType(element, "link")) config.links?.push(element.attributes);
|
|
59
|
+
else if (isElementOfType(element, "script")) config.scripts?.push(element.attributes);
|
|
60
|
+
else if (isElementOfType(element, "style")) config.styles?.push(element.attributes);
|
|
61
|
+
else if (isElementOfType(element, "title"))
|
|
62
|
+
/**
|
|
63
|
+
* TanStack Router automatically dedupes title and meta tags
|
|
64
|
+
* so we only need to push the title as a meta element
|
|
65
|
+
*/
|
|
66
|
+
config.meta?.push({ title: String(element.attributes.children) });
|
|
67
|
+
return config;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
//#endregion
|
|
72
|
+
export { HeadReactAdapter, HeadTanstackRouterAdapter };
|