fusee-framework 1.6.0 → 1.8.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.
Files changed (129) hide show
  1. package/README.md +145 -123
  2. package/app/benchmark/benchmark.js +633 -0
  3. package/app/benchmark/index.html +102 -0
  4. package/app/benchmark/styles.css +249 -0
  5. package/app/components/Counter.js +17 -7
  6. package/app/components/CounterSection.js +3 -4
  7. package/app/main.js +50 -62
  8. package/app/main.ts +78 -63
  9. package/app/pages/404.js +16 -0
  10. package/app/pages/[...all].js +35 -0
  11. package/app/pages/[...all].ts +35 -0
  12. package/app/pages/_layout.js +53 -0
  13. package/app/pages/_layout.ts +26 -0
  14. package/app/pages/about.js +23 -0
  15. package/app/pages/about.ts +29 -0
  16. package/app/pages/async-work.js +65 -0
  17. package/app/pages/composables.js +158 -0
  18. package/app/pages/composables.ts +158 -0
  19. package/app/pages/dynamic.js +40 -0
  20. package/app/pages/dynamic.ts +40 -0
  21. package/app/pages/index.js +137 -0
  22. package/app/pages/index.ts +87 -0
  23. package/app/pages/login.ts +21 -0
  24. package/app/pages/objects/[id].js +56 -0
  25. package/app/pages/objects/[id].ts +56 -0
  26. package/app/pages/posts/[category]/[slug].js +56 -0
  27. package/app/pages/posts/[category]/[slug].ts +56 -0
  28. package/app/pages/router-example.js +79 -0
  29. package/app/pages/router-example.ts +56 -0
  30. package/app/pages/scroll-demo.ts +102 -0
  31. package/app/pages/test-for.js +65 -0
  32. package/app/pages/test-for.ts +80 -0
  33. package/app/pages/users/[id].js +24 -0
  34. package/app/pages/users/[id].ts +46 -0
  35. package/app/pages/users/index.js +22 -0
  36. package/app/pages/users/index.ts +29 -0
  37. package/app/pages/users.js +43 -0
  38. package/app/pages/users.ts +78 -0
  39. package/app/providers/ChildComponent.js +8 -2
  40. package/app/providers/ChildComponent.ts +47 -47
  41. package/app/providers/GrandchildComponent.js +19 -0
  42. package/app/providers/ParentComponent.js +5 -1
  43. package/app/routes/About.js +1 -1
  44. package/app/routes/About.ts +1 -1
  45. package/app/routes/AuthRoutes.ts +41 -0
  46. package/app/routes/Home.js +9 -0
  47. package/app/routes/NotFound.js +16 -0
  48. package/app/routes/NotFound.ts +16 -0
  49. package/app/routes/RouterExample.js +78 -0
  50. package/app/routes/RouterExample.ts +56 -0
  51. package/app/routes/TestResource.js +47 -0
  52. package/app/routes/WildcardDemo.js +35 -0
  53. package/app/routes/WildcardDemo.ts +35 -0
  54. package/app/services.js +15 -0
  55. package/auto-imports.d.ts +9 -0
  56. package/bin/create-fusee-linux +0 -0
  57. package/bin/create-fusee-mac-arm64 +0 -0
  58. package/bin/create-fusee-mac-intel +0 -0
  59. package/bin/create-fusee-win.exe +0 -0
  60. package/bin/create-fusee.exe +0 -0
  61. package/bin/index.js +38 -0
  62. package/create-fusee-go/cmd/generate.go +72 -0
  63. package/create-fusee-go/cmd/init.go +38 -0
  64. package/create-fusee-go/cmd/root.go +121 -0
  65. package/create-fusee-go/go.mod +10 -0
  66. package/create-fusee-go/go.sum +10 -0
  67. package/create-fusee-go/internal/assets/assets.go +78 -0
  68. package/create-fusee-go/internal/assets/embed/framework/auto-import-preset.js +9 -0
  69. package/create-fusee-go/internal/assets/embed/framework/core/compiler.js +253 -0
  70. package/create-fusee-go/internal/assets/embed/framework/core/component.js +266 -0
  71. package/create-fusee-go/internal/assets/embed/framework/core/composable.js +27 -0
  72. package/create-fusee-go/internal/assets/embed/framework/core/directives.js +875 -0
  73. package/create-fusee-go/internal/assets/embed/framework/core/evaluator.js +153 -0
  74. package/create-fusee-go/internal/assets/embed/framework/core/event-delegation.js +191 -0
  75. package/create-fusee-go/internal/assets/embed/framework/core/signal.js +412 -0
  76. package/create-fusee-go/internal/assets/embed/framework/core/store.js +81 -0
  77. package/create-fusee-go/internal/assets/embed/framework/index.d.ts +3 -0
  78. package/create-fusee-go/internal/assets/embed/framework/index.js +10 -0
  79. package/create-fusee-go/internal/assets/embed/framework/router/file-router.js +177 -0
  80. package/create-fusee-go/internal/assets/embed/framework/router/router.js +462 -0
  81. package/create-fusee-go/internal/assets/embed/framework/types/compiler.d.ts +15 -0
  82. package/create-fusee-go/internal/assets/embed/framework/types/component.d.ts +88 -0
  83. package/create-fusee-go/internal/assets/embed/framework/types/composable.d.ts +14 -0
  84. package/create-fusee-go/internal/assets/embed/framework/types/directives.d.ts +55 -0
  85. package/create-fusee-go/internal/assets/embed/framework/types/evaluator.d.ts +13 -0
  86. package/create-fusee-go/internal/assets/embed/framework/types/event-delegation.d.ts +32 -0
  87. package/create-fusee-go/internal/assets/embed/framework/types/index.d.ts +22 -0
  88. package/create-fusee-go/internal/assets/embed/framework/types/router.d.ts +32 -0
  89. package/create-fusee-go/internal/assets/embed/framework/types/signal.d.ts +79 -0
  90. package/create-fusee-go/internal/assets/embed/framework/types/store.d.ts +8 -0
  91. package/create-fusee-go/internal/assets/templates/Counter.tmpl +26 -0
  92. package/create-fusee-go/internal/assets/templates/component.tmpl +11 -0
  93. package/create-fusee-go/internal/assets/templates/components/Loading.tmpl +24 -0
  94. package/create-fusee-go/internal/assets/templates/index.html.tmpl +15 -0
  95. package/create-fusee-go/internal/assets/templates/main.tmpl +14 -0
  96. package/create-fusee-go/internal/assets/templates/package.json.tmpl +14 -0
  97. package/create-fusee-go/internal/assets/templates/page.tmpl +12 -0
  98. package/create-fusee-go/internal/assets/templates/pages/about.tmpl +20 -0
  99. package/create-fusee-go/internal/assets/templates/pages/index.tmpl +22 -0
  100. package/create-fusee-go/internal/assets/templates/pages/layout.tmpl +18 -0
  101. package/create-fusee-go/internal/assets/templates/tsconfig.json.tmpl +14 -0
  102. package/create-fusee-go/internal/assets/templates/vite.config.js.tmpl +18 -0
  103. package/create-fusee-go/main.go +7 -0
  104. package/framework/auto-import-preset.js +13 -9
  105. package/framework/core/compiler.js +252 -249
  106. package/framework/core/component.js +279 -260
  107. package/framework/core/di.js +187 -0
  108. package/framework/core/directives.js +819 -786
  109. package/framework/core/evaluator.js +153 -70
  110. package/framework/core/event-delegation.js +33 -14
  111. package/framework/core/reconcile.js +151 -0
  112. package/framework/core/signal.js +679 -403
  113. package/framework/core/store.js +322 -81
  114. package/framework/index.js +12 -11
  115. package/framework/router/file-router.js +177 -0
  116. package/framework/router/router.js +554 -80
  117. package/framework/types/component.d.ts +89 -88
  118. package/framework/types/di.d.ts +43 -0
  119. package/framework/types/event-delegation.d.ts +0 -58
  120. package/framework/types/index.d.ts +32 -22
  121. package/framework/types/reconcile.d.ts +7 -0
  122. package/framework/types/router.d.ts +42 -15
  123. package/framework/types/signal.d.ts +147 -78
  124. package/framework/types/store.d.ts +66 -8
  125. package/index.html +638 -626
  126. package/package.json +5 -3
  127. package/tsconfig.json +1 -0
  128. package/vite.config.js +7 -1
  129. /package/{framework → create-fusee-go/internal/assets/embed/framework}/bin/create-fusee.js +0 -0
@@ -0,0 +1,40 @@
1
+ import { DynamicA } from '../components/DynamicA.js'
2
+ import { DynamicB } from '../components/DynamicB.js'
3
+
4
+ export const TestDynamic = defineComponent({
5
+ components: { DynamicA, DynamicB },
6
+ setup() {
7
+ const currentType = signal('DynamicA')
8
+ const sharedTitle = signal('Dynamic Test Active')
9
+
10
+ return {
11
+ currentType,
12
+ sharedTitle,
13
+ toggle: () => {
14
+ currentType(currentType() === 'DynamicA' ? 'DynamicB' : 'DynamicA')
15
+ },
16
+ template: `
17
+ <div class="page">
18
+ <h1>Dynamic Components System (Vue-style)</h1>
19
+ <p>Using the custom <code>f-is</code> directive.</p>
20
+
21
+ <div style="margin: 20px 0; display: flex; gap: 10px; align-items: center;">
22
+ <button @click="toggle" class="primary-btn">Toggle Component</button>
23
+ <span>Active: <strong>{{ currentType }}</strong></span>
24
+ </div>
25
+
26
+ <input f-model="sharedTitle" style="margin-bottom: 20px; padding: 8px; border-radius: 4px; border: 1px solid #444; background: #222; color: white; width: 100%;">
27
+
28
+ <hr style="border: 0; border-top: 1px solid #444; margin: 30px 0;">
29
+
30
+ <div f-is="currentType" :title="sharedTitle"></div>
31
+
32
+ <p style="margin-top: 40px; color: #888; font-size: 0.9em;">
33
+ Note: The component above changes reactively when you click the button.
34
+ The <code>:title</code> prop is automatically passed to the active component.
35
+ </p>
36
+ </div>
37
+ `
38
+ }
39
+ }
40
+ })
@@ -0,0 +1,137 @@
1
+ import { Counter } from '../components/Counter.js'
2
+ import { UserForm } from '../components/UserForm.js'
3
+ import { CounterSection } from '../components/CounterSection.js'
4
+ import { Card } from '../components/Card.js'
5
+ import { EmitTest } from '../components/EmitTest.js'
6
+ import { ParentComponent } from '../providers/index.js'
7
+
8
+ export const Home = defineComponent({
9
+ components: { UserForm, CounterSection, Card, EmitTest, ParentComponent },
10
+ setup() {
11
+ const title = signal('Welcome!')
12
+ inspect(title)
13
+
14
+ const isActive = signal(false)
15
+ const isDisabled = signal(false)
16
+ const isLarge = signal(false)
17
+ const basicClasses = computed(() => ({
18
+ active: isActive(),
19
+ disabled: isDisabled(),
20
+ 'is-large': isLarge()
21
+ }))
22
+
23
+ const toggleActive = () => isActive(!isActive())
24
+ const toggleDisabled = () => isDisabled(!isDisabled())
25
+ const toggleLarge = () => isLarge(!isLarge())
26
+
27
+ return {
28
+ title,
29
+ changeTitle: () => title('Changed Title!'),
30
+
31
+ isActive,
32
+ isDisabled,
33
+ isLarge,
34
+ basicClasses,
35
+ toggleActive,
36
+ toggleDisabled,
37
+ toggleLarge,
38
+
39
+ // 🧪 Emit Event Handlers
40
+ handleCounterChange: (value) => console.log('📢 Counter changed to:', value),
41
+ handleCounterReset: () => console.log('🔄 Counter reset requested!'),
42
+ handleCustomEvent: (count, multiplier) => console.log('🎯 Custom event:', { count, multiplier }),
43
+
44
+ // 🧪 Emit Test Handlers
45
+ handleSimpleClick: () => console.log('✅ SIMPLE CLICK received from child!'),
46
+ handleClickWithData: (count, label, timestamp) => console.log('✅ CLICK WITH DATA:', { count, label, timestamp }),
47
+ handleObjectEvent: (data) => console.log('✅ OBJECT EVENT received:', data),
48
+
49
+ template: `
50
+ <div class="page">
51
+ <h1>{{ title.toUpperCase() }}</h1>
52
+ <p>This is an SPA built with my own JavaScript custom framework!</p>
53
+ <p>Made with passion by Sebastian Șomu</p>
54
+
55
+ <!-- Navigation -->
56
+ <div style="display: flex; gap: 0.5rem; flex-wrap: wrap; margin: 1.5rem 0; padding: 1rem; background: #2a2a2a; border-radius: 8px;">
57
+ <a href="#classlist" f-link style="color: #f59e0b; text-decoration: none; padding: 0.5rem 1rem; background: #3a3a3a; border-radius: 4px;">🎨 f-classList</a>
58
+ <a href="#userform" f-link style="color: #10b981; text-decoration: none; padding: 0.5rem 1rem; background: #3a3a3a; border-radius: 4px;">📝 User Form</a>
59
+ <a href="#counter" f-link style="color: #3b82f6; text-decoration: none; padding: 0.5rem 1rem; background: #3a3a3a; border-radius: 4px;">🔢 Counter</a>
60
+ <a href="#emit" f-link style="color: #4da6ff; text-decoration: none; padding: 0.5rem 1rem; background: #3a3a3a; border-radius: 4px;">🧪 Emit Events</a>
61
+ <a href="#slots" f-link style="color: #8b5cf6; text-decoration: none; padding: 0.5rem 1rem; background: #3a3a3a; border-radius: 4px;">🎴 Slots</a>
62
+ <a href="#interpolation" f-link style="color: #e83e8c; text-decoration: none; padding: 0.5rem 1rem; background: #3a3a3a; border-radius: 4px;">🔤 Interpolation</a>
63
+ <a href="#provide" f-link style="color: #4CAF50; text-decoration: none; padding: 0.5rem 1rem; background: #3a3a3a; border-radius: 4px;">🔗 Provide/Inject</a>
64
+ </div>
65
+
66
+ <button @click="changeTitle" class="primary-btn" style="margin-bottom: 20px;">Change App Title</button>
67
+
68
+ <!-- 🎨 f-classList Demo -->
69
+ <h3 id="classlist" style="margin-top: 40px; margin-bottom: 20px; color: #f59e0b;">🎨 f-classList Demo</h3>
70
+ <div class="demo-box" f-classList="basicClasses">
71
+ Demo Box (hover me!)
72
+ </div>
73
+ <div style="display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 1rem;">
74
+ <button @click="toggleActive" :class="isActive ? 'btn-on' : 'btn-off'" style="padding: 0.5rem 1rem; border-radius: 6px; cursor: pointer;">
75
+ {{ isActive ? '✓ Active' : '○ Active' }}
76
+ </button>
77
+ <button @click="toggleDisabled" :class="isDisabled ? 'btn-on' : 'btn-off'" style="padding: 0.5rem 1rem; border-radius: 6px; cursor: pointer;">
78
+ {{ isDisabled ? '✓ Disabled' : '○ Disabled' }}
79
+ </button>
80
+ <button @click="toggleLarge" :class="isLarge ? 'btn-on' : 'btn-off'" style="padding: 0.5rem 1rem; border-radius: 6px; cursor: pointer;">
81
+ {{ isLarge ? '✓ Large' : '○ Large' }}
82
+ </button>
83
+ </div>
84
+
85
+ <h3 id="userform" style="margin-top: 40px; margin-bottom: 20px; color: #10b981;">📝 User Form Demo</h3>
86
+ {{ UserForm }}
87
+
88
+ <h3 id="counter" style="margin-top: 40px; margin-bottom: 20px; color: #3b82f6;">🔢 Counter Demo</h3>
89
+ {{ CounterSection @counter-change="handleCounterChange" @counter-reset="handleCounterReset" @custom-event="handleCustomEvent" :pageTitle="title" }}
90
+
91
+ <!-- 🧪 EMIT TEST - NEW SEPARATE COMPONENT -->
92
+ <h3 id="emit" style="margin-top: 40px; margin-bottom: 20px; color: #4da6ff;">🧪 EMIT EVENTS TEST LAB</h3>
93
+ {{ EmitTest @simple-click="handleSimpleClick" @click-with-data="handleClickWithData" @object-event="handleObjectEvent" }}
94
+
95
+ <!-- 🧪 Slots Test -->
96
+ <h3 id="slots" style="margin-top: 40px; margin-bottom: 20px;">🎴 Slots Test</h3>
97
+
98
+ {{ Card title="Custom Card" }}
99
+ <template slot="header">
100
+ <p style="color: #10b981; font-weight: bold;">🎯 Custom header from parent!</p>
101
+ </template>
102
+ <p style="color: #f59e0b;">This is custom content passed through the default slot.</p>
103
+ <p>You can pass any HTML content here!</p>
104
+ <template slot="footer">
105
+ <button style="background: #3b82f6; color: white; border: none; padding: 5px 10px; border-radius: 4px; cursor: pointer;">
106
+ Custom Footer Button
107
+ </button>
108
+ </template>
109
+ {{ /Card }}
110
+
111
+ {{ Card title="Default Slots Card" }}
112
+ <p>This card uses only the default slot - no named slots provided.</p>
113
+ {{ /Card }}
114
+
115
+ <!-- 🧪 INTERPOLATION TEST -->
116
+ <h3 id="interpolation" style="margin-top: 40px; margin-bottom: 20px; color: #e83e8c;">🔤 INTERPOLATION TEST</h3>
117
+ <div style="background: #2a2a2a; padding: 15px; border-radius: 8px; border: 1px solid #444;">
118
+ <p><strong>Escaped Braces:</strong> \\{{ this is not evaluated }}</p>
119
+ <p><strong>String Literal with Braces:</strong> {{ "Look, {{ braces }} inside a string!" }}</p>
120
+ <p><strong>Dynamic + Escaped:</strong> {{ isActive ? 'Currently: \\{{ Active }}' : 'Currently: \\{{ Inactive }}' }}</p>
121
+ </div>
122
+
123
+ <!-- 🧪 PROVIDE / INJECT TEST -->
124
+ <h3 id="provide" style="margin-top: 40px; margin-bottom: 20px; color: #4CAF50;">🔗 PROVIDE / INJECT TEST</h3>
125
+ {{ ParentComponent }}
126
+
127
+ <!-- Back to top -->
128
+ <div style="text-align: center; margin-top: 3rem; padding: 2rem;">
129
+ <a href="/" f-link style="color: white; text-decoration: none; padding: 0.75rem 1.5rem; background: #3b82f6; border-radius: 6px; font-weight: bold;">
130
+ ⬆️ Back to Top
131
+ </a>
132
+ </div>
133
+ </div>
134
+ `
135
+ }
136
+ }
137
+ })
@@ -0,0 +1,87 @@
1
+ import { UserForm } from '../components/UserForm.js'
2
+ import { CounterSection } from '../components/CounterSection.js'
3
+
4
+ type HomeResult = {
5
+ title: Signal<string>
6
+ changeTitle: () => void
7
+ isActive: Signal<boolean>
8
+ isDisabled: Signal<boolean>
9
+ isLarge: Signal<boolean>
10
+ basicClasses: Computed<ClassListObject>
11
+ toggleActive: () => void
12
+ toggleDisabled: () => void
13
+ toggleLarge: () => void
14
+ template: string
15
+ }
16
+
17
+ type ClassListObject = Record<string, boolean>
18
+
19
+ export const Home = defineComponent({
20
+ components: { UserForm, CounterSection },
21
+ setup(): HomeResult {
22
+ const title = signal<string>('Welcome!')
23
+
24
+ const isActive = signal(false)
25
+ const isDisabled = signal(false)
26
+ const isLarge = signal(false)
27
+ const basicClasses = computed(() => ({
28
+ active: isActive(),
29
+ disabled: isDisabled(),
30
+ 'is-large': isLarge()
31
+ }))
32
+
33
+ const toggleActive = () => isActive(!isActive())
34
+ const toggleDisabled = () => isDisabled(!isDisabled())
35
+ const toggleLarge = () => isLarge(!isLarge())
36
+
37
+ return {
38
+ title,
39
+ changeTitle: () => title('Changed Title!'),
40
+ isActive,
41
+ isDisabled,
42
+ isLarge,
43
+ basicClasses,
44
+ toggleActive,
45
+ toggleDisabled,
46
+ toggleLarge,
47
+ template: `
48
+ <div class="page">
49
+ <h1>{{ title.toUpperCase() }}</h1>
50
+ <p>This is an SPA built with my own (TypeScript!) custom framework!</p>
51
+ <p>Made with passion by Sebastian Șomu</p>
52
+
53
+ <div style="display: flex; gap: 0.75rem; flex-wrap: wrap; margin: 1rem 0;">
54
+ <a href="/scroll-demo" f-link class="cmp-btn" style="background: linear-gradient(135deg, #8b8bff, #6b6bff);">
55
+ 🔽 Scroll Behavior Demo
56
+ </a>
57
+ <a href="/users" f-link class="cmp-btn">
58
+ 👥 Router Example
59
+ </a>
60
+ </div>
61
+
62
+ <button @click="changeTitle" class="primary-btn" style="margin-bottom: 20px;">Change App Title</button>
63
+
64
+ <h3 style="margin-top: 40px; margin-bottom: 20px; color: #f59e0b;">🎨 f-classList Demo</h3>
65
+ <div class="demo-box" f-classList="basicClasses">
66
+ Demo Box (hover me!)
67
+ </div>
68
+ <div style="display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 1rem;">
69
+ <button @click="toggleActive" :class="isActive ? 'btn-on' : 'btn-off'" style="padding: 0.5rem 1rem; border-radius: 6px; cursor: pointer;">
70
+ {{ isActive ? '✓ Active' : '○ Active' }}
71
+ </button>
72
+ <button @click="toggleDisabled" :class="isDisabled ? 'btn-on' : 'btn-off'" style="padding: 0.5rem 1rem; border-radius: 6px; cursor: pointer;">
73
+ {{ isDisabled ? '✓ Disabled' : '○ Disabled' }}
74
+ </button>
75
+ <button @click="toggleLarge" :class="isLarge ? 'btn-on' : 'btn-off'" style="padding: 0.5rem 1rem; border-radius: 6px; cursor: pointer;">
76
+ {{ isLarge ? '✓ Large' : '○ Large' }}
77
+ </button>
78
+ </div>
79
+
80
+ {{ UserForm }}
81
+
82
+ {{ CounterSection :pageTitle="title" }}
83
+ </div>
84
+ `
85
+ }
86
+ }
87
+ })
@@ -0,0 +1,21 @@
1
+ import { defineComponent, navigate } from '../../framework/index.js'
2
+
3
+ export const Login = defineComponent({
4
+ setup() {
5
+ return {
6
+ login() {
7
+ localStorage.setItem('fake_auth_token', 'true')
8
+ navigate('/dashboard')
9
+ },
10
+ template: `
11
+ <div class="page">
12
+ <h1 style="color: #ff6b6b;">🔑 Login Required</h1>
13
+ <div class="demo-card">
14
+ <p>You were redirected here because the route you tried to access is protected by middleware.</p>
15
+ <button class="cmp-btn" @click="login()" style="margin-top: 1rem; border-color: #34d399; color: #34d399;">Simulate Login</button>
16
+ </div>
17
+ </div>
18
+ `
19
+ }
20
+ }
21
+ })
@@ -0,0 +1,56 @@
1
+ import { currentRoute, navigate, routeParams, computed, defineComponent } from '../../../framework/index.js'
2
+
3
+ export const RouterExample = defineComponent({
4
+ setup() {
5
+ const path = currentRoute
6
+ const params = routeParams
7
+ const paramsJson = computed(() => JSON.stringify(params()))
8
+
9
+ return {
10
+ path,
11
+ paramsJson,
12
+ navigate,
13
+ template: `
14
+ <div class="page">
15
+ <h1>🔗 Router API Demo</h1>
16
+
17
+ <div class="demo-card">
18
+ <h2>currentRoute Signal</h2>
19
+ <code style="color: #8b8bff; font-size: 1.5rem;">{{ path }}</code>
20
+ </div>
21
+
22
+ <div class="demo-card">
23
+ <h2>routeParams Signal (Dynamic Routes)</h2>
24
+ <div style="display: flex; gap: 10px; margin-bottom: 10px;">
25
+ <a href="/objects/123" f-link class="cmp-btn" style="text-decoration: none;">Object 123</a>
26
+ <a href="/objects/456" f-link class="cmp-btn" style="text-decoration: none;">Object 456</a>
27
+ <a href="/posts/tech/my-post" f-link class="cmp-btn" style="text-decoration: none;">Post Route</a>
28
+ </div>
29
+ <code style="color: #34d399; font-size: 1.2rem;">{{ paramsJson }}</code>
30
+ <p style="margin-top: 10px; color: #888; font-size: 0.9rem;">
31
+ Dynamic routes use :param syntax (e.g., /users/:id or /posts/:category/:slug)
32
+ </p>
33
+ </div>
34
+
35
+ <div class="demo-card">
36
+ <h2>navigate() Test</h2>
37
+ <div style="display: flex; gap: 10px;">
38
+ <button @click="navigate('/')" class="cmp-btn">Home</button>
39
+ <button @click="navigate('/about')" class="cmp-btn">About</button>
40
+ <button @click="navigate('/wildcard-test-123')" class="cmp-btn" style="border-color: #f59e0b; color: #f59e0b;">Wildcard</button>
41
+ <button @click="navigate('/nonexistent')" class="cmp-btn" style="border-color: #ff6b6b; color: #ff6b6b;">404 Test</button>
42
+ </div>
43
+ </div>
44
+
45
+ <div class="demo-card">
46
+ <h2>f-link Test</h2>
47
+ <div style="display: flex; gap: 10px;">
48
+ <a href="/" f-link class="cmp-btn" style="text-decoration: none;">Home</a>
49
+ <a href="/about" f-link class="cmp-btn" style="text-decoration: none;">About</a>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ `
54
+ }
55
+ }
56
+ })
@@ -0,0 +1,56 @@
1
+ import { currentRoute, navigate, routeParams, computed, defineComponent } from '../../../framework/index.js'
2
+
3
+ export const RouterExample = defineComponent({
4
+ setup() {
5
+ const path = currentRoute
6
+ const params = routeParams
7
+ const paramsJson = computed(() => JSON.stringify(params()))
8
+
9
+ return {
10
+ path,
11
+ paramsJson,
12
+ navigate,
13
+ template: `
14
+ <div class="page">
15
+ <h1>🔗 Router API Demo</h1>
16
+
17
+ <div class="demo-card">
18
+ <h2>currentRoute Signal</h2>
19
+ <code style="color: #8b8bff; font-size: 1.5rem;">{{ path }}</code>
20
+ </div>
21
+
22
+ <div class="demo-card">
23
+ <h2>routeParams Signal (Dynamic Routes)</h2>
24
+ <div style="display: flex; gap: 10px; margin-bottom: 10px;">
25
+ <a href="/objects/123" f-link class="cmp-btn" style="text-decoration: none;">Object 123</a>
26
+ <a href="/objects/456" f-link class="cmp-btn" style="text-decoration: none;">Object 456</a>
27
+ <a href="/posts/tech/my-post" f-link class="cmp-btn" style="text-decoration: none;">Post Route</a>
28
+ </div>
29
+ <code style="color: #34d399; font-size: 1.2rem;">{{ paramsJson }}</code>
30
+ <p style="margin-top: 10px; color: #888; font-size: 0.9rem;">
31
+ Dynamic routes use :param syntax (e.g., /users/:id or /posts/:category/:slug)
32
+ </p>
33
+ </div>
34
+
35
+ <div class="demo-card">
36
+ <h2>navigate() Test</h2>
37
+ <div style="display: flex; gap: 10px;">
38
+ <button @click="navigate('/')" class="cmp-btn">Home</button>
39
+ <button @click="navigate('/about')" class="cmp-btn">About</button>
40
+ <button @click="navigate('/wildcard-test-123')" class="cmp-btn" style="border-color: #f59e0b; color: #f59e0b;">Wildcard</button>
41
+ <button @click="navigate('/nonexistent')" class="cmp-btn" style="border-color: #ff6b6b; color: #ff6b6b;">404 Test</button>
42
+ </div>
43
+ </div>
44
+
45
+ <div class="demo-card">
46
+ <h2>f-link Test</h2>
47
+ <div style="display: flex; gap: 10px;">
48
+ <a href="/" f-link class="cmp-btn" style="text-decoration: none;">Home</a>
49
+ <a href="/about" f-link class="cmp-btn" style="text-decoration: none;">About</a>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ `
54
+ }
55
+ }
56
+ })
@@ -0,0 +1,56 @@
1
+ import { currentRoute, navigate, routeParams, computed } from '../../../../framework/index.js'
2
+
3
+ export const RouterExample = defineComponent({
4
+ setup() {
5
+ const path = currentRoute
6
+ const params = routeParams
7
+ const paramsJson = computed(() => JSON.stringify(params()))
8
+
9
+ return {
10
+ path,
11
+ paramsJson,
12
+ navigate,
13
+ template: `
14
+ <div class="page">
15
+ <h1>🔗 Router API Demo</h1>
16
+
17
+ <div class="demo-card">
18
+ <h2>currentRoute Signal</h2>
19
+ <code style="color: #8b8bff; font-size: 1.5rem;">{{ path }}</code>
20
+ </div>
21
+
22
+ <div class="demo-card">
23
+ <h2>routeParams Signal (Dynamic Routes)</h2>
24
+ <div style="display: flex; gap: 10px; margin-bottom: 10px;">
25
+ <a href="/objects/123" f-link class="cmp-btn" style="text-decoration: none;">Object 123</a>
26
+ <a href="/objects/456" f-link class="cmp-btn" style="text-decoration: none;">Object 456</a>
27
+ <a href="/posts/tech/my-post" f-link class="cmp-btn" style="text-decoration: none;">Post Route</a>
28
+ </div>
29
+ <code style="color: #34d399; font-size: 1.2rem;">{{ paramsJson }}</code>
30
+ <p style="margin-top: 10px; color: #888; font-size: 0.9rem;">
31
+ Dynamic routes use :param syntax (e.g., /users/:id or /posts/:category/:slug)
32
+ </p>
33
+ </div>
34
+
35
+ <div class="demo-card">
36
+ <h2>navigate() Test</h2>
37
+ <div style="display: flex; gap: 10px;">
38
+ <button @click="navigate('/')" class="cmp-btn">Home</button>
39
+ <button @click="navigate('/about')" class="cmp-btn">About</button>
40
+ <button @click="navigate('/404')" class="cmp-btn" style="border-color: #ff6b6b; color: #ff6b6b;">404 Page</button>
41
+ <button @click="navigate('/wildcard-test-123')" class="cmp-btn" style="border-color: #f59e0b; color: #f59e0b;">Wildcard</button>
42
+ </div>
43
+ </div>
44
+
45
+ <div class="demo-card">
46
+ <h2>f-link Test</h2>
47
+ <div style="display: flex; gap: 10px;">
48
+ <a href="/" f-link class="cmp-btn" style="text-decoration: none;">Home</a>
49
+ <a href="/about" f-link class="cmp-btn" style="text-decoration: none;">About</a>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ `
54
+ }
55
+ }
56
+ })
@@ -0,0 +1,56 @@
1
+ import { currentRoute, navigate, routeParams, computed } from '../../../../framework/index.js'
2
+
3
+ export const RouterExample = defineComponent({
4
+ setup() {
5
+ const path = currentRoute
6
+ const params = routeParams
7
+ const paramsJson = computed(() => JSON.stringify(params()))
8
+
9
+ return {
10
+ path,
11
+ paramsJson,
12
+ navigate,
13
+ template: `
14
+ <div class="page">
15
+ <h1>🔗 Router API Demo</h1>
16
+
17
+ <div class="demo-card">
18
+ <h2>currentRoute Signal</h2>
19
+ <code style="color: #8b8bff; font-size: 1.5rem;">{{ path }}</code>
20
+ </div>
21
+
22
+ <div class="demo-card">
23
+ <h2>routeParams Signal (Dynamic Routes)</h2>
24
+ <div style="display: flex; gap: 10px; margin-bottom: 10px;">
25
+ <a href="/objects/123" f-link class="cmp-btn" style="text-decoration: none;">Object 123</a>
26
+ <a href="/objects/456" f-link class="cmp-btn" style="text-decoration: none;">Object 456</a>
27
+ <a href="/posts/tech/my-post" f-link class="cmp-btn" style="text-decoration: none;">Post Route</a>
28
+ </div>
29
+ <code style="color: #34d399; font-size: 1.2rem;">{{ paramsJson }}</code>
30
+ <p style="margin-top: 10px; color: #888; font-size: 0.9rem;">
31
+ Dynamic routes use :param syntax (e.g., /users/:id or /posts/:category/:slug)
32
+ </p>
33
+ </div>
34
+
35
+ <div class="demo-card">
36
+ <h2>navigate() Test</h2>
37
+ <div style="display: flex; gap: 10px;">
38
+ <button @click="navigate('/')" class="cmp-btn">Home</button>
39
+ <button @click="navigate('/about')" class="cmp-btn">About</button>
40
+ <button @click="navigate('/wildcard-test-123')" class="cmp-btn" style="border-color: #f59e0b; color: #f59e0b;">Wildcard</button>
41
+ <button @click="navigate('/nonexistent')" class="cmp-btn" style="border-color: #ff6b6b; color: #ff6b6b;">404 Test</button>
42
+ </div>
43
+ </div>
44
+
45
+ <div class="demo-card">
46
+ <h2>f-link Test</h2>
47
+ <div style="display: flex; gap: 10px;">
48
+ <a href="/" f-link class="cmp-btn" style="text-decoration: none;">Home</a>
49
+ <a href="/about" f-link class="cmp-btn" style="text-decoration: none;">About</a>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ `
54
+ }
55
+ }
56
+ })
@@ -0,0 +1,79 @@
1
+ import { currentRoute, navigate, routeParams, routeQuery, computed } from '../../framework/index.js'
2
+
3
+ export const RouterExample = defineComponent({
4
+ setup() {
5
+ const path = currentRoute
6
+ const params = routeParams
7
+ const query = routeQuery
8
+ const paramsJson = computed(() => JSON.stringify(params()))
9
+ const queryJson = computed(() => JSON.stringify(query()))
10
+
11
+ const updateQuery = () => {
12
+ const now = new Date().toLocaleTimeString()
13
+ const basePath = path().split('?')[0]
14
+ navigate(`${basePath}?t=${encodeURIComponent(now)}&user=guest`)
15
+ }
16
+
17
+ return {
18
+ path,
19
+ paramsJson,
20
+ queryJson,
21
+ navigate,
22
+ updateQuery,
23
+ template: `
24
+ <div class="page">
25
+ <h1>🔗 Router API Demo</h1>
26
+
27
+ <div class="demo-card">
28
+ <h2>currentRoute Signal</h2>
29
+ <code style="color: #8b8bff; font-size: 1.5rem;">{{ path }}</code>
30
+ </div>
31
+
32
+ <div class="demo-card">
33
+ <h2>routeQuery Signal (Query Params)</h2>
34
+ <div style="display: flex; gap: 10px; margin-bottom: 10px;">
35
+ <a href="/router-example?search=framework&page=1" f-link class="cmp-btn" style="text-decoration: none;">?search=framework&page=1</a>
36
+ <a href="/router-example?filter=active&sort=desc" f-link class="cmp-btn" style="text-decoration: none;">?filter=active&sort=desc</a>
37
+ <button @click="updateQuery" class="cmp-btn">Update Time via Query</button>
38
+ </div>
39
+ <code style="color: #f59e0b; font-size: 1.2rem;">{{ queryJson }}</code>
40
+ <p style="margin-top: 10px; color: #888; font-size: 0.9rem;">
41
+ Query parameters are automatically parsed into the routeQuery signal.
42
+ </p>
43
+ </div>
44
+
45
+ <div class="demo-card">
46
+ <h2>routeParams Signal (Dynamic Routes)</h2>
47
+ <div style="display: flex; gap: 10px; margin-bottom: 10px;">
48
+ <a href="/objects/123" f-link class="cmp-btn" style="text-decoration: none;">Object 123</a>
49
+ <a href="/objects/456" f-link class="cmp-btn" style="text-decoration: none;">Object 456</a>
50
+ <a href="/posts/tech/my-post" f-link class="cmp-btn" style="text-decoration: none;">Post Route</a>
51
+ </div>
52
+ <code style="color: #34d399; font-size: 1.2rem;">{{ paramsJson }}</code>
53
+ <p style="margin-top: 10px; color: #888; font-size: 0.9rem;">
54
+ Dynamic routes use :param syntax (e.g., /users/:id or /posts/:category/:slug)
55
+ </p>
56
+ </div>
57
+
58
+ <div class="demo-card">
59
+ <h2>navigate() Test</h2>
60
+ <div style="display: flex; gap: 10px;">
61
+ <button @click="navigate('/')" class="cmp-btn">Home</button>
62
+ <button @click="navigate('/about')" class="cmp-btn">About</button>
63
+ <button @click="navigate('/404')" class="cmp-btn" style="border-color: #ff6b6b; color: #ff6b6b;">404 Page</button>
64
+ <button @click="navigate('/wildcard-test-123')" class="cmp-btn" style="border-color: #f59e0b; color: #f59e0b;">Wildcard</button>
65
+ </div>
66
+ </div>
67
+
68
+ <div class="demo-card">
69
+ <h2>f-link Test</h2>
70
+ <div style="display: flex; gap: 10px;">
71
+ <a href="/" f-link class="cmp-btn" style="text-decoration: none;">Home</a>
72
+ <a href="/about" f-link class="cmp-btn" style="text-decoration: none;">About</a>
73
+ </div>
74
+ </div>
75
+ </div>
76
+ `
77
+ }
78
+ }
79
+ })