@zenithbuild/core 0.6.2 → 0.6.4

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 (112) hide show
  1. package/CORE_CONTRACT.md +145 -0
  2. package/README.md +14 -29
  3. package/bin/zenith.js +89 -0
  4. package/package.json +39 -56
  5. package/src/config.js +136 -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 -388
  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 -83
  43. package/compiler/ir/types.ts +0 -174
  44. package/compiler/output/types.ts +0 -34
  45. package/compiler/parse/detectMapExpressions.ts +0 -102
  46. package/compiler/parse/importTypes.ts +0 -78
  47. package/compiler/parse/parseImports.ts +0 -309
  48. package/compiler/parse/parseScript.ts +0 -46
  49. package/compiler/parse/parseTemplate.ts +0 -599
  50. package/compiler/parse/parseZenFile.ts +0 -66
  51. package/compiler/parse/scriptAnalysis.ts +0 -91
  52. package/compiler/parse/trackLoopContext.ts +0 -82
  53. package/compiler/runtime/dataExposure.ts +0 -317
  54. package/compiler/runtime/generateDOM.ts +0 -246
  55. package/compiler/runtime/generateHydrationBundle.ts +0 -407
  56. package/compiler/runtime/hydration.ts +0 -309
  57. package/compiler/runtime/navigation.ts +0 -432
  58. package/compiler/runtime/thinRuntime.ts +0 -160
  59. package/compiler/runtime/transformIR.ts +0 -370
  60. package/compiler/runtime/wrapExpression.ts +0 -95
  61. package/compiler/runtime/wrapExpressionWithLoop.ts +0 -83
  62. package/compiler/spa-build.ts +0 -917
  63. package/compiler/ssg-build.ts +0 -422
  64. package/compiler/test/validate-test.ts +0 -104
  65. package/compiler/transform/classifyExpression.ts +0 -444
  66. package/compiler/transform/componentResolver.ts +0 -312
  67. package/compiler/transform/componentScriptTransformer.ts +0 -303
  68. package/compiler/transform/expressionTransformer.ts +0 -385
  69. package/compiler/transform/fragmentLowering.ts +0 -634
  70. package/compiler/transform/generateBindings.ts +0 -47
  71. package/compiler/transform/generateHTML.ts +0 -28
  72. package/compiler/transform/layoutProcessor.ts +0 -132
  73. package/compiler/transform/slotResolver.ts +0 -292
  74. package/compiler/transform/transformNode.ts +0 -126
  75. package/compiler/transform/transformTemplate.ts +0 -38
  76. package/compiler/validate/invariants.ts +0 -292
  77. package/compiler/validate/validateExpressions.ts +0 -168
  78. package/core/config/index.ts +0 -16
  79. package/core/config/loader.ts +0 -69
  80. package/core/config/types.ts +0 -89
  81. package/core/index.ts +0 -135
  82. package/core/lifecycle/index.ts +0 -49
  83. package/core/lifecycle/zen-mount.ts +0 -182
  84. package/core/lifecycle/zen-unmount.ts +0 -88
  85. package/core/plugins/index.ts +0 -7
  86. package/core/plugins/registry.ts +0 -81
  87. package/core/reactivity/index.ts +0 -54
  88. package/core/reactivity/tracking.ts +0 -167
  89. package/core/reactivity/zen-batch.ts +0 -57
  90. package/core/reactivity/zen-effect.ts +0 -139
  91. package/core/reactivity/zen-memo.ts +0 -146
  92. package/core/reactivity/zen-ref.ts +0 -52
  93. package/core/reactivity/zen-signal.ts +0 -121
  94. package/core/reactivity/zen-state.ts +0 -180
  95. package/core/reactivity/zen-untrack.ts +0 -44
  96. package/dist/cli.js +0 -11665
  97. package/dist/zen-build.js +0 -21172
  98. package/dist/zen-dev.js +0 -21172
  99. package/dist/zen-preview.js +0 -21172
  100. package/dist/zenith.js +0 -21172
  101. package/router/index.ts +0 -28
  102. package/router/manifest.ts +0 -314
  103. package/router/navigation/ZenLink.zen +0 -231
  104. package/router/navigation/index.ts +0 -78
  105. package/router/navigation/zen-link.ts +0 -584
  106. package/router/runtime.ts +0 -458
  107. package/router/types.ts +0 -168
  108. package/runtime/build.ts +0 -17
  109. package/runtime/bundle-generator.ts +0 -1247
  110. package/runtime/client-runtime.ts +0 -549
  111. package/runtime/serve.ts +0 -93
  112. package/tsconfig.json +0 -28
package/router/index.ts DELETED
@@ -1,28 +0,0 @@
1
- /**
2
- * Zenith Router
3
- *
4
- * This module re-exports from @zenithbuild/router package.
5
- *
6
- * The router has been extracted to its own package for:
7
- * - Independent versioning
8
- * - Better separation of concerns
9
- * - Easier maintenance
10
- *
11
- * @example
12
- * ```ts
13
- * import { navigate, isActive, prefetch } from 'zenith/router'
14
- *
15
- * // Navigate programmatically
16
- * navigate('/about')
17
- *
18
- * // Check active state
19
- * if (isActive('/blog')) {
20
- * console.log('On blog section')
21
- * }
22
- * ```
23
- *
24
- * @deprecated Import directly from '@zenithbuild/router' for new projects
25
- */
26
-
27
- // Re-export everything from @zenithbuild/router
28
- export * from "@zenithbuild/router"
@@ -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
-