@zenithbuild/core 0.4.7 → 0.5.0-beta.2.2

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 (110) hide show
  1. package/CORE_CONTRACT.md +143 -0
  2. package/README.md +11 -31
  3. package/bin/zenith.js +68 -0
  4. package/package.json +41 -53
  5. package/src/config.js +134 -0
  6. package/src/core-template.js +30 -0
  7. package/src/errors.js +54 -0
  8. package/src/guards.js +61 -0
  9. package/src/hash.js +52 -0
  10. package/src/index.js +26 -0
  11. package/src/ir/index.js +1 -0
  12. package/src/order.js +69 -0
  13. package/src/path.js +131 -0
  14. package/src/schema.js +28 -0
  15. package/src/version.js +67 -0
  16. package/bin/zen-build.ts +0 -2
  17. package/bin/zen-dev.ts +0 -2
  18. package/bin/zen-preview.ts +0 -2
  19. package/bin/zenith.ts +0 -2
  20. package/cli/commands/add.ts +0 -37
  21. package/cli/commands/build.ts +0 -37
  22. package/cli/commands/create.ts +0 -702
  23. package/cli/commands/dev.ts +0 -335
  24. package/cli/commands/index.ts +0 -112
  25. package/cli/commands/preview.ts +0 -62
  26. package/cli/commands/remove.ts +0 -33
  27. package/cli/index.ts +0 -10
  28. package/cli/main.ts +0 -101
  29. package/cli/utils/branding.ts +0 -178
  30. package/cli/utils/content.ts +0 -112
  31. package/cli/utils/logger.ts +0 -46
  32. package/cli/utils/plugin-manager.ts +0 -114
  33. package/cli/utils/project.ts +0 -77
  34. package/compiler/README.md +0 -380
  35. package/compiler/build-analyzer.ts +0 -122
  36. package/compiler/css/index.ts +0 -317
  37. package/compiler/discovery/componentDiscovery.ts +0 -178
  38. package/compiler/discovery/layouts.ts +0 -70
  39. package/compiler/errors/compilerError.ts +0 -56
  40. package/compiler/finalize/finalizeOutput.ts +0 -192
  41. package/compiler/finalize/generateFinalBundle.ts +0 -82
  42. package/compiler/index.ts +0 -82
  43. package/compiler/ir/types.ts +0 -162
  44. package/compiler/output/types.ts +0 -34
  45. package/compiler/parse/detectMapExpressions.ts +0 -102
  46. package/compiler/parse/parseScript.ts +0 -46
  47. package/compiler/parse/parseTemplate.ts +0 -599
  48. package/compiler/parse/parseZenFile.ts +0 -66
  49. package/compiler/parse/scriptAnalysis.ts +0 -91
  50. package/compiler/parse/trackLoopContext.ts +0 -82
  51. package/compiler/runtime/dataExposure.ts +0 -317
  52. package/compiler/runtime/generateDOM.ts +0 -246
  53. package/compiler/runtime/generateHydrationBundle.ts +0 -407
  54. package/compiler/runtime/hydration.ts +0 -309
  55. package/compiler/runtime/navigation.ts +0 -432
  56. package/compiler/runtime/thinRuntime.ts +0 -160
  57. package/compiler/runtime/transformIR.ts +0 -363
  58. package/compiler/runtime/wrapExpression.ts +0 -95
  59. package/compiler/runtime/wrapExpressionWithLoop.ts +0 -83
  60. package/compiler/spa-build.ts +0 -917
  61. package/compiler/ssg-build.ts +0 -422
  62. package/compiler/test/validate-test.ts +0 -104
  63. package/compiler/transform/classifyExpression.ts +0 -444
  64. package/compiler/transform/componentResolver.ts +0 -312
  65. package/compiler/transform/componentScriptTransformer.ts +0 -147
  66. package/compiler/transform/expressionTransformer.ts +0 -385
  67. package/compiler/transform/fragmentLowering.ts +0 -634
  68. package/compiler/transform/generateBindings.ts +0 -47
  69. package/compiler/transform/generateHTML.ts +0 -28
  70. package/compiler/transform/layoutProcessor.ts +0 -132
  71. package/compiler/transform/slotResolver.ts +0 -292
  72. package/compiler/transform/transformNode.ts +0 -126
  73. package/compiler/transform/transformTemplate.ts +0 -38
  74. package/compiler/validate/invariants.ts +0 -292
  75. package/compiler/validate/validateExpressions.ts +0 -168
  76. package/core/config/index.ts +0 -16
  77. package/core/config/loader.ts +0 -69
  78. package/core/config/types.ts +0 -89
  79. package/core/index.ts +0 -135
  80. package/core/lifecycle/index.ts +0 -49
  81. package/core/lifecycle/zen-mount.ts +0 -182
  82. package/core/lifecycle/zen-unmount.ts +0 -88
  83. package/core/plugins/index.ts +0 -7
  84. package/core/plugins/registry.ts +0 -81
  85. package/core/reactivity/index.ts +0 -54
  86. package/core/reactivity/tracking.ts +0 -167
  87. package/core/reactivity/zen-batch.ts +0 -57
  88. package/core/reactivity/zen-effect.ts +0 -139
  89. package/core/reactivity/zen-memo.ts +0 -146
  90. package/core/reactivity/zen-ref.ts +0 -52
  91. package/core/reactivity/zen-signal.ts +0 -121
  92. package/core/reactivity/zen-state.ts +0 -180
  93. package/core/reactivity/zen-untrack.ts +0 -44
  94. package/dist/cli.js +0 -11659
  95. package/dist/zen-build.js +0 -15633
  96. package/dist/zen-dev.js +0 -15633
  97. package/dist/zen-preview.js +0 -15633
  98. package/dist/zenith.js +0 -15633
  99. package/router/index.ts +0 -76
  100. package/router/manifest.ts +0 -314
  101. package/router/navigation/ZenLink.zen +0 -231
  102. package/router/navigation/index.ts +0 -78
  103. package/router/navigation/zen-link.ts +0 -584
  104. package/router/runtime.ts +0 -458
  105. package/router/types.ts +0 -168
  106. package/runtime/build.ts +0 -17
  107. package/runtime/bundle-generator.ts +0 -943
  108. package/runtime/client-runtime.ts +0 -549
  109. package/runtime/serve.ts +0 -93
  110. package/tsconfig.json +0 -28
package/router/index.ts DELETED
@@ -1,76 +0,0 @@
1
- /**
2
- * Zenith Router
3
- *
4
- * File-based SPA router for Zenith framework.
5
- * Includes routing, navigation, and ZenLink components.
6
- *
7
- * @example
8
- * ```ts
9
- * import { navigate, isActive, prefetch } from 'zenith/router'
10
- *
11
- * // Navigate programmatically
12
- * navigate('/about')
13
- *
14
- * // Check active state
15
- * if (isActive('/blog')) {
16
- * console.log('On blog section')
17
- * }
18
- * ```
19
- */
20
-
21
- // Core router types and utilities
22
- export * from "./types"
23
- export * from "./manifest"
24
-
25
- // Router runtime (core router implementation)
26
- // These are the primary exports for router functionality
27
- export {
28
- initRouter,
29
- resolveRoute,
30
- navigate,
31
- getRoute,
32
- onRouteChange,
33
- beforeEach,
34
- afterEach,
35
- isActive,
36
- prefetch,
37
- isPrefetched
38
- } from "./runtime"
39
-
40
- // Navigation utilities (additional helpers and zen* prefixed exports)
41
- // Note: Some functions like navigate, isActive, prefetch are also in runtime
42
- // We export runtime's versions above, and navigation's unique functions here
43
- export {
44
- // Navigation API (zen* prefixed names)
45
- zenNavigate,
46
- zenBack,
47
- zenForward,
48
- zenGo,
49
- zenIsActive,
50
- zenPrefetch,
51
- zenIsPrefetched,
52
- zenGetRoute,
53
- zenGetParam,
54
- zenGetQuery,
55
- createZenLink,
56
- zenLink,
57
- // Additional navigation utilities (not in runtime)
58
- back,
59
- forward,
60
- go,
61
- getParam,
62
- getQuery,
63
- isExternalUrl,
64
- shouldUseSPANavigation,
65
- normalizePath,
66
- setGlobalTransition,
67
- getGlobalTransition,
68
- createTransitionContext
69
- } from "./navigation/index"
70
-
71
- // Navigation-specific types
72
- export type {
73
- ZenLinkProps,
74
- TransitionContext,
75
- TransitionHandler
76
- } from "./navigation/index"
@@ -1,314 +0,0 @@
1
- /**
2
- * Zenith Route Manifest Generator
3
- *
4
- * Scans pages/ directory at build time and generates a route manifest
5
- * with proper scoring for deterministic route matching.
6
- */
7
-
8
- import fs from "fs"
9
- import path from "path"
10
- import {
11
- type RouteDefinition,
12
- type ParsedSegment,
13
- SegmentType
14
- } from "./types"
15
-
16
- /**
17
- * Scoring constants for route ranking
18
- * Higher scores = higher priority
19
- */
20
- const SEGMENT_SCORES = {
21
- [SegmentType.STATIC]: 10,
22
- [SegmentType.DYNAMIC]: 5,
23
- [SegmentType.CATCH_ALL]: 1,
24
- [SegmentType.OPTIONAL_CATCH_ALL]: 0
25
- } as const
26
-
27
- /**
28
- * Discover all .zen files in the pages directory
29
- */
30
- export function discoverPages(pagesDir: string): string[] {
31
- const pages: string[] = []
32
-
33
- function walk(dir: string): void {
34
- if (!fs.existsSync(dir)) return
35
-
36
- const entries = fs.readdirSync(dir, { withFileTypes: true })
37
-
38
- for (const entry of entries) {
39
- const fullPath = path.join(dir, entry.name)
40
-
41
- if (entry.isDirectory()) {
42
- walk(fullPath)
43
- } else if (entry.isFile() && entry.name.endsWith(".zen")) {
44
- pages.push(fullPath)
45
- }
46
- }
47
- }
48
-
49
- walk(pagesDir)
50
- return pages
51
- }
52
-
53
- /**
54
- * Convert a file path to a route path
55
- *
56
- * Examples:
57
- * pages/index.zen → /
58
- * pages/about.zen → /about
59
- * pages/blog/index.zen → /blog
60
- * pages/blog/[id].zen → /blog/:id
61
- * pages/posts/[...slug].zen → /posts/*slug
62
- * pages/[[...all]].zen → /*all (optional)
63
- */
64
- export function filePathToRoutePath(filePath: string, pagesDir: string): string {
65
- // Get relative path from pages directory
66
- const relativePath = path.relative(pagesDir, filePath)
67
-
68
- // Remove .zen extension
69
- const withoutExt = relativePath.replace(/\.zen$/, "")
70
-
71
- // Split into segments
72
- const segments = withoutExt.split(path.sep)
73
-
74
- // Transform segments
75
- const routeSegments: string[] = []
76
-
77
- for (const segment of segments) {
78
- // Handle index files (they represent the directory root)
79
- if (segment === "index") {
80
- continue
81
- }
82
-
83
- // Handle optional catch-all: [[...param]]
84
- const optionalCatchAllMatch = segment.match(/^\[\[\.\.\.(\w+)\]\]$/)
85
- if (optionalCatchAllMatch) {
86
- routeSegments.push(`*${optionalCatchAllMatch[1]}?`)
87
- continue
88
- }
89
-
90
- // Handle required catch-all: [...param]
91
- const catchAllMatch = segment.match(/^\[\.\.\.(\w+)\]$/)
92
- if (catchAllMatch) {
93
- routeSegments.push(`*${catchAllMatch[1]}`)
94
- continue
95
- }
96
-
97
- // Handle dynamic segment: [param]
98
- const dynamicMatch = segment.match(/^\[(\w+)\]$/)
99
- if (dynamicMatch) {
100
- routeSegments.push(`:${dynamicMatch[1]}`)
101
- continue
102
- }
103
-
104
- // Static segment
105
- routeSegments.push(segment)
106
- }
107
-
108
- // Build route path
109
- const routePath = "/" + routeSegments.join("/")
110
-
111
- // Normalize trailing slashes
112
- return routePath === "/" ? "/" : routePath.replace(/\/$/, "")
113
- }
114
-
115
- /**
116
- * Parse a route path into segments with type information
117
- */
118
- export function parseRouteSegments(routePath: string): ParsedSegment[] {
119
- if (routePath === "/") {
120
- return []
121
- }
122
-
123
- const segments = routePath.slice(1).split("/")
124
- const parsed: ParsedSegment[] = []
125
-
126
- for (const segment of segments) {
127
- // Optional catch-all: *param?
128
- if (segment.startsWith("*") && segment.endsWith("?")) {
129
- parsed.push({
130
- type: SegmentType.OPTIONAL_CATCH_ALL,
131
- paramName: segment.slice(1, -1),
132
- raw: segment
133
- })
134
- continue
135
- }
136
-
137
- // Required catch-all: *param
138
- if (segment.startsWith("*")) {
139
- parsed.push({
140
- type: SegmentType.CATCH_ALL,
141
- paramName: segment.slice(1),
142
- raw: segment
143
- })
144
- continue
145
- }
146
-
147
- // Dynamic: :param
148
- if (segment.startsWith(":")) {
149
- parsed.push({
150
- type: SegmentType.DYNAMIC,
151
- paramName: segment.slice(1),
152
- raw: segment
153
- })
154
- continue
155
- }
156
-
157
- // Static
158
- parsed.push({
159
- type: SegmentType.STATIC,
160
- raw: segment
161
- })
162
- }
163
-
164
- return parsed
165
- }
166
-
167
- /**
168
- * Calculate route score based on segments
169
- * Higher scores = higher priority for matching
170
- */
171
- export function calculateRouteScore(segments: ParsedSegment[]): number {
172
- if (segments.length === 0) {
173
- // Root route gets a high score
174
- return 100
175
- }
176
-
177
- let score = 0
178
-
179
- for (const segment of segments) {
180
- score += SEGMENT_SCORES[segment.type]
181
- }
182
-
183
- // Bonus for having more static segments (specificity)
184
- const staticCount = segments.filter(s => s.type === SegmentType.STATIC).length
185
- score += staticCount * 2
186
-
187
- return score
188
- }
189
-
190
- /**
191
- * Extract parameter names from parsed segments
192
- */
193
- export function extractParamNames(segments: ParsedSegment[]): string[] {
194
- return segments
195
- .filter(s => s.paramName !== undefined)
196
- .map(s => s.paramName!)
197
- }
198
-
199
- /**
200
- * Convert route path to regex pattern
201
- *
202
- * Examples:
203
- * /about → /^\/about\/?$/
204
- * /blog/:id → /^\/blog\/([^/]+)\/?$/
205
- * /posts/*slug → /^\/posts\/(.+)\/?$/
206
- * / → /^\/$/
207
- * /*all? → /^(?:\/(.*))?$/ (optional catch-all)
208
- */
209
- export function routePathToRegex(routePath: string): RegExp {
210
- if (routePath === "/") {
211
- return /^\/$/
212
- }
213
-
214
- const segments = routePath.slice(1).split("/")
215
- const regexParts: string[] = []
216
-
217
- for (let i = 0; i < segments.length; i++) {
218
- const segment = segments[i]
219
- if (!segment) continue
220
-
221
- // Optional catch-all: *param?
222
- if (segment.startsWith("*") && segment.endsWith("?")) {
223
- // Optional catch-all - matches zero or more path segments
224
- // Should only be at the end
225
- regexParts.push("(?:\\/(.*))?")
226
- continue
227
- }
228
-
229
- // Required catch-all: *param
230
- if (segment.startsWith("*")) {
231
- // Required catch-all - matches one or more path segments
232
- regexParts.push("\\/(.+)")
233
- continue
234
- }
235
-
236
- // Dynamic: :param
237
- if (segment.startsWith(":")) {
238
- regexParts.push("\\/([^/]+)")
239
- continue
240
- }
241
-
242
- // Static segment - escape special regex characters
243
- const escaped = segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
244
- regexParts.push(`\\/${escaped}`)
245
- }
246
-
247
- // Build final regex with optional trailing slash
248
- const pattern = `^${regexParts.join("")}\\/?$`
249
- return new RegExp(pattern)
250
- }
251
-
252
- /**
253
- * Generate a route definition from a file path
254
- */
255
- export function generateRouteDefinition(
256
- filePath: string,
257
- pagesDir: string
258
- ): RouteDefinition {
259
- const routePath = filePathToRoutePath(filePath, pagesDir)
260
- const segments = parseRouteSegments(routePath)
261
- const paramNames = extractParamNames(segments)
262
- const score = calculateRouteScore(segments)
263
-
264
- return {
265
- path: routePath,
266
- segments,
267
- paramNames,
268
- score,
269
- filePath
270
- }
271
- }
272
-
273
- /**
274
- * Generate route manifest from pages directory
275
- * Returns route definitions sorted by score (highest first)
276
- */
277
- export function generateRouteManifest(pagesDir: string): RouteDefinition[] {
278
- const pages = discoverPages(pagesDir)
279
-
280
- const definitions = pages.map(filePath =>
281
- generateRouteDefinition(filePath, pagesDir)
282
- )
283
-
284
- // Sort by score descending (highest priority first)
285
- definitions.sort((a, b) => b.score - a.score)
286
-
287
- return definitions
288
- }
289
-
290
- /**
291
- * Generate the route manifest as JavaScript code for runtime
292
- */
293
- export function generateRouteManifestCode(definitions: RouteDefinition[]): string {
294
- const routeEntries = definitions.map(def => {
295
- const regex = routePathToRegex(def.path)
296
-
297
- return ` {
298
- path: ${JSON.stringify(def.path)},
299
- regex: ${regex.toString()},
300
- paramNames: ${JSON.stringify(def.paramNames)},
301
- score: ${def.score},
302
- filePath: ${JSON.stringify(def.filePath)}
303
- }`
304
- })
305
-
306
- return `// Auto-generated route manifest
307
- // Do not edit directly
308
-
309
- export const routeManifest = [
310
- ${routeEntries.join(",\n")}
311
- ];
312
- `
313
- }
314
-
@@ -1,231 +0,0 @@
1
- <script>
2
- // Props extend HTMLAnchorElement properties + custom ZenLink attributes
3
- // Standard anchor attributes: href, target, rel, download, hreflang, type, ping, referrerPolicy, etc.
4
- // Custom ZenLink attributes: preload, exact, onClick
5
- type Props = {
6
- // Standard HTMLAnchorElement attributes
7
- href?: string
8
- target?: '_blank' | '_self' | '_parent' | '_top' | string
9
- rel?: string
10
- download?: string | boolean
11
- hreflang?: string
12
- type?: string
13
- ping?: string
14
- referrerPolicy?: string
15
- class?: string
16
- id?: string
17
- title?: string
18
- ariaLabel?: string
19
- role?: string
20
- tabIndex?: number | string
21
- // Custom ZenLink attributes
22
- preload?: boolean
23
- exact?: boolean
24
- onClick?: (event?: MouseEvent) => void | boolean
25
- }
26
-
27
- /**
28
- * Handle link click - prevents default and uses SPA navigation
29
- * Respects target="_blank" and other standard anchor behaviors
30
- */
31
- function handleClick(event, el) {
32
- // Ensure attributes are set from props
33
- if (el) {
34
- ensureAttributes(el)
35
- }
36
-
37
- // Get target from the element attribute (more reliable than prop)
38
- const linkTarget = el ? el.getAttribute('target') : (typeof target !== 'undefined' ? target : null)
39
-
40
- // If target is _blank, _parent, or _top, let browser handle it (opens in new tab/window)
41
- if (linkTarget === '_blank' || linkTarget === '_parent' || linkTarget === '_top') {
42
- // Let browser handle standard navigation
43
- return
44
- }
45
-
46
- // Allow modifier keys for native behavior (Cmd/Ctrl+click, etc.)
47
- if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
48
- return
49
- }
50
-
51
- // Get href from element or prop
52
- const linkHref = el ? el.getAttribute('href') : (typeof href !== 'undefined' ? href : null)
53
- if (!linkHref) return
54
-
55
- // Check if external URL (http://, https://, //, mailto:, tel:, etc.)
56
- if (linkHref.startsWith('http://') ||
57
- linkHref.startsWith('https://') ||
58
- linkHref.startsWith('//') ||
59
- linkHref.startsWith('mailto:') ||
60
- linkHref.startsWith('tel:') ||
61
- linkHref.startsWith('javascript:')) {
62
- // External/special link - open in new tab if target not specified
63
- if (!linkTarget) {
64
- el?.setAttribute('target', '_blank')
65
- el?.setAttribute('rel', 'noopener noreferrer')
66
- }
67
- // Let browser handle it
68
- return
69
- }
70
-
71
- // Prevent default navigation for internal SPA links
72
- event.preventDefault()
73
- event.stopPropagation()
74
-
75
- // Call onClick prop if provided
76
- if (typeof onClick === 'function') {
77
- const result = onClick(event)
78
- // If onClick returns false, cancel navigation
79
- if (result === false) {
80
- return
81
- }
82
- }
83
-
84
- // Normalize path for comparison
85
- const normalizedHref = linkHref === '' ? '/' : linkHref
86
- const currentPath = window.location.pathname === '' ? '/' : window.location.pathname
87
-
88
- // Only navigate if path is different (idempotent navigation)
89
- if (normalizedHref !== currentPath) {
90
- console.log('[ZenLink] Navigating to:', linkHref)
91
- // Navigate using SPA router
92
- if (window.__zenith_router && window.__zenith_router.navigate) {
93
- console.log('[ZenLink] Using router.navigate')
94
- window.__zenith_router.navigate(linkHref)
95
- } else {
96
- console.log('[ZenLink] Using fallback history API')
97
- // Fallback to history API
98
- window.history.pushState(null, '', linkHref)
99
- window.dispatchEvent(new PopStateEvent('popstate'))
100
- }
101
- } else {
102
- console.log('[ZenLink] Already on route:', linkHref, '- skipping navigation')
103
- }
104
- }
105
-
106
- /**
107
- * Handle mouse enter for preloading
108
- */
109
- function handleMouseEnter(event, el) {
110
- // Ensure attributes are set
111
- if (el) {
112
- ensureAttributes(el)
113
- }
114
-
115
- const shouldPreload = typeof preload !== 'undefined' ? preload : false
116
- console.log('[ZenLink] handleMouseEnter called, preload:', shouldPreload)
117
- if (!shouldPreload) {
118
- console.log('[ZenLink] Preload disabled, returning early')
119
- return
120
- }
121
-
122
- const linkHref = el ? el.getAttribute('href') : (typeof href !== 'undefined' ? href : null)
123
- if (!linkHref) {
124
- return
125
- }
126
-
127
- // Skip external URLs
128
- if (linkHref.startsWith('http://') || linkHref.startsWith('https://') || linkHref.startsWith('//')) {
129
- return
130
- }
131
-
132
- console.log('[ZenLink] Prefetch triggered on hover:', linkHref)
133
-
134
- // Prefetch the route
135
- if (window.__zenith_router && window.__zenith_router.prefetch) {
136
- console.log('[ZenLink] Calling router.prefetch for:', linkHref)
137
- window.__zenith_router.prefetch(linkHref).then(() => {
138
- console.log('[ZenLink] Prefetch complete for:', linkHref)
139
- }).catch((error) => {
140
- console.warn('[ZenLink] Prefetch failed for:', linkHref, error)
141
- })
142
- } else {
143
- console.warn('[ZenLink] Router prefetch not available')
144
- }
145
- }
146
-
147
- // Apply attributes on mount
148
- if (typeof zenOnMount !== 'undefined') {
149
- zenOnMount(() => {
150
- setTimeout(() => {
151
- // Find all ZenLink anchor elements and apply attributes
152
- document.querySelectorAll('a[data-zen-component="Zenlink"]').forEach(el => {
153
- ensureAttributes(el)
154
- })
155
- }, 0)
156
- })
157
- }
158
-
159
- /**
160
- * Apply standard anchor attributes from props to the element
161
- * Called when the element is clicked to ensure attributes are set
162
- */
163
- function ensureAttributes(el) {
164
- if (!el) return
165
-
166
- // Set attributes from props (only if they exist and aren't already set)
167
- const attrs = {
168
- target: typeof target !== 'undefined' ? target : null,
169
- rel: typeof rel !== 'undefined' ? rel : null,
170
- download: typeof download !== 'undefined' ? download : null,
171
- hreflang: typeof hreflang !== 'undefined' ? hreflang : null,
172
- type: typeof type !== 'undefined' ? type : null,
173
- ping: typeof ping !== 'undefined' ? ping : null,
174
- referrerPolicy: typeof referrerPolicy !== 'undefined' ? referrerPolicy : null,
175
- id: typeof id !== 'undefined' ? id : null,
176
- title: typeof title !== 'undefined' ? title : null,
177
- ariaLabel: typeof ariaLabel !== 'undefined' ? ariaLabel : null,
178
- role: typeof role !== 'undefined' ? role : null,
179
- tabIndex: typeof tabIndex !== 'undefined' ? tabIndex : null
180
- }
181
-
182
- // Map to HTML attribute names
183
- const htmlAttrs = {
184
- target: 'target',
185
- rel: 'rel',
186
- download: 'download',
187
- hreflang: 'hreflang',
188
- type: 'type',
189
- ping: 'ping',
190
- referrerPolicy: 'referrerpolicy',
191
- id: 'id',
192
- title: 'title',
193
- ariaLabel: 'aria-label',
194
- role: 'role',
195
- tabIndex: 'tabindex'
196
- }
197
-
198
- // Set attributes that have values
199
- for (const [prop, value] of Object.entries(attrs)) {
200
- if (value !== null && value !== undefined && value !== '') {
201
- const htmlAttr = htmlAttrs[prop]
202
- if (htmlAttr && !el.hasAttribute(htmlAttr)) {
203
- el.setAttribute(htmlAttr, String(value))
204
- }
205
- }
206
- }
207
- }
208
-
209
- </script>
210
-
211
- <style>
212
- .zen-link {
213
- color: inherit;
214
- text-decoration: none;
215
- cursor: pointer;
216
- }
217
-
218
- .zen-link:hover {
219
- text-decoration: underline;
220
- }
221
- </style>
222
-
223
- <a
224
- href="{ href }"
225
- class="zen-link { class }"
226
- onclick="handleClick"
227
- onmouseenter="handleMouseEnter"
228
- style="cursor: pointer;"
229
- >
230
- <slot />
231
- </a>
@@ -1,78 +0,0 @@
1
- /**
2
- * Zenith Navigation System
3
- *
4
- * Provides SPA navigation utilities and the ZenLink API.
5
- *
6
- * @example
7
- * ```ts
8
- * import { navigate, isActive, prefetch, zenLink } from 'zenith/core'
9
- *
10
- * // Programmatic navigation
11
- * navigate('/about')
12
- *
13
- * // Check active state
14
- * if (isActive('/blog')) {
15
- * console.log('On blog section')
16
- * }
17
- *
18
- * // Prefetch for faster navigation
19
- * prefetch('/dashboard')
20
- *
21
- * // Create link programmatically
22
- * const link = zenLink({ href: '/contact', children: 'Contact' })
23
- * ```
24
- */
25
-
26
- // Export all navigation utilities
27
- export {
28
- // Navigation API
29
- zenNavigate,
30
- navigate,
31
- zenBack,
32
- back,
33
- zenForward,
34
- forward,
35
- zenGo,
36
- go,
37
-
38
- // Active state
39
- zenIsActive,
40
- isActive,
41
-
42
- // Prefetching
43
- zenPrefetch,
44
- prefetch,
45
- zenIsPrefetched,
46
- isPrefetched,
47
-
48
- // Transitions API
49
- setGlobalTransition,
50
- getGlobalTransition,
51
- createTransitionContext,
52
-
53
- // Route state
54
- zenGetRoute,
55
- getRoute,
56
- zenGetParam,
57
- getParam,
58
- zenGetQuery,
59
- getQuery,
60
-
61
- // ZenLink factory
62
- createZenLink,
63
- zenLink,
64
-
65
- // Utilities
66
- isExternalUrl,
67
- shouldUseSPANavigation,
68
- normalizePath
69
- } from './zen-link'
70
-
71
- // Export types
72
- export type {
73
- ZenLinkProps,
74
- TransitionContext,
75
- TransitionHandler,
76
- NavigateOptions
77
- } from './zen-link'
78
-