fusee-framework 1.5.3 → 1.7.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 (115) hide show
  1. package/README.md +30 -13
  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/Counter.ts +1 -1
  7. package/app/components/CounterSection.js +3 -4
  8. package/app/main.js +29 -62
  9. package/app/main.ts +72 -63
  10. package/app/pages/404.js +16 -0
  11. package/app/pages/[...all].js +35 -0
  12. package/app/pages/[...all].ts +35 -0
  13. package/app/pages/_layout.js +26 -0
  14. package/app/pages/_layout.ts +26 -0
  15. package/app/pages/about.js +23 -0
  16. package/app/pages/about.ts +29 -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 +117 -0
  22. package/app/pages/index.ts +78 -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 +56 -0
  29. package/app/pages/router-example.ts +56 -0
  30. package/app/pages/test-for.js +65 -0
  31. package/app/pages/test-for.ts +80 -0
  32. package/app/pages/users/[id].js +24 -0
  33. package/app/pages/users/[id].ts +46 -0
  34. package/app/pages/users/index.js +22 -0
  35. package/app/pages/users/index.ts +29 -0
  36. package/app/pages/users.js +43 -0
  37. package/app/pages/users.ts +78 -0
  38. package/app/routes/About.js +1 -1
  39. package/app/routes/About.ts +1 -1
  40. package/app/routes/AuthRoutes.ts +41 -0
  41. package/app/routes/Home.js +9 -0
  42. package/app/routes/NotFound.js +16 -0
  43. package/app/routes/NotFound.ts +16 -0
  44. package/app/routes/RouterExample.js +56 -0
  45. package/app/routes/RouterExample.ts +56 -0
  46. package/app/routes/WildcardDemo.js +35 -0
  47. package/app/routes/WildcardDemo.ts +35 -0
  48. package/auto-imports.d.ts +1 -0
  49. package/bin/create-fusee-linux +0 -0
  50. package/bin/create-fusee-mac-arm64 +0 -0
  51. package/bin/create-fusee-mac-intel +0 -0
  52. package/bin/create-fusee-win.exe +0 -0
  53. package/bin/create-fusee.exe +0 -0
  54. package/bin/index.js +38 -0
  55. package/create-fusee-go/cmd/generate.go +72 -0
  56. package/create-fusee-go/cmd/init.go +38 -0
  57. package/create-fusee-go/cmd/root.go +121 -0
  58. package/create-fusee-go/go.mod +10 -0
  59. package/create-fusee-go/go.sum +10 -0
  60. package/create-fusee-go/internal/assets/assets.go +78 -0
  61. package/create-fusee-go/internal/assets/embed/framework/auto-import-preset.js +9 -0
  62. package/create-fusee-go/internal/assets/embed/framework/core/compiler.js +253 -0
  63. package/create-fusee-go/internal/assets/embed/framework/core/component.js +266 -0
  64. package/create-fusee-go/internal/assets/embed/framework/core/composable.js +27 -0
  65. package/create-fusee-go/internal/assets/embed/framework/core/directives.js +875 -0
  66. package/create-fusee-go/internal/assets/embed/framework/core/evaluator.js +153 -0
  67. package/create-fusee-go/internal/assets/embed/framework/core/event-delegation.js +191 -0
  68. package/create-fusee-go/internal/assets/embed/framework/core/signal.js +412 -0
  69. package/create-fusee-go/internal/assets/embed/framework/core/store.js +81 -0
  70. package/create-fusee-go/internal/assets/embed/framework/index.d.ts +3 -0
  71. package/create-fusee-go/internal/assets/embed/framework/index.js +10 -0
  72. package/create-fusee-go/internal/assets/embed/framework/router/file-router.js +177 -0
  73. package/create-fusee-go/internal/assets/embed/framework/router/router.js +462 -0
  74. package/create-fusee-go/internal/assets/embed/framework/types/compiler.d.ts +15 -0
  75. package/create-fusee-go/internal/assets/embed/framework/types/component.d.ts +88 -0
  76. package/create-fusee-go/internal/assets/embed/framework/types/composable.d.ts +14 -0
  77. package/create-fusee-go/internal/assets/embed/framework/types/directives.d.ts +55 -0
  78. package/create-fusee-go/internal/assets/embed/framework/types/evaluator.d.ts +13 -0
  79. package/create-fusee-go/internal/assets/embed/framework/types/event-delegation.d.ts +32 -0
  80. package/create-fusee-go/internal/assets/embed/framework/types/index.d.ts +22 -0
  81. package/create-fusee-go/internal/assets/embed/framework/types/router.d.ts +32 -0
  82. package/create-fusee-go/internal/assets/embed/framework/types/signal.d.ts +79 -0
  83. package/create-fusee-go/internal/assets/embed/framework/types/store.d.ts +8 -0
  84. package/create-fusee-go/internal/assets/templates/Counter.tmpl +26 -0
  85. package/create-fusee-go/internal/assets/templates/component.tmpl +11 -0
  86. package/create-fusee-go/internal/assets/templates/components/Loading.tmpl +24 -0
  87. package/create-fusee-go/internal/assets/templates/index.html.tmpl +15 -0
  88. package/create-fusee-go/internal/assets/templates/main.tmpl +14 -0
  89. package/create-fusee-go/internal/assets/templates/package.json.tmpl +14 -0
  90. package/create-fusee-go/internal/assets/templates/page.tmpl +12 -0
  91. package/create-fusee-go/internal/assets/templates/pages/about.tmpl +20 -0
  92. package/create-fusee-go/internal/assets/templates/pages/index.tmpl +22 -0
  93. package/create-fusee-go/internal/assets/templates/pages/layout.tmpl +18 -0
  94. package/create-fusee-go/internal/assets/templates/tsconfig.json.tmpl +14 -0
  95. package/create-fusee-go/internal/assets/templates/vite.config.js.tmpl +18 -0
  96. package/create-fusee-go/main.go +7 -0
  97. package/framework/auto-import-preset.js +1 -1
  98. package/framework/core/compiler.js +252 -249
  99. package/framework/core/component.js +265 -260
  100. package/framework/core/directives.js +875 -632
  101. package/framework/core/evaluator.js +153 -70
  102. package/framework/core/event-delegation.js +191 -0
  103. package/framework/core/signal.js +412 -404
  104. package/framework/index.js +10 -11
  105. package/framework/router/file-router.js +177 -0
  106. package/framework/router/router.js +462 -80
  107. package/framework/types/component.d.ts +0 -4
  108. package/framework/types/event-delegation.d.ts +32 -0
  109. package/framework/types/index.d.ts +3 -0
  110. package/framework/types/router.d.ts +32 -15
  111. package/framework/types/signal.d.ts +1 -0
  112. package/index.html +638 -563
  113. package/package.json +5 -3
  114. package/tsconfig.json +1 -0
  115. /package/{framework → create-fusee-go/internal/assets/embed/framework}/bin/create-fusee.js +0 -0
@@ -0,0 +1,80 @@
1
+ type Item = {
2
+ id: number
3
+ name: string
4
+ }
5
+
6
+ type TestForResult = {
7
+ items: Signal<Item[]>
8
+ search: Signal<string>
9
+ filteredItems: Computed<Item[]>
10
+ namesSummary: Computed<string>
11
+ updateItem: (id: number, name: string) => void
12
+ addItem: () => void
13
+ shuffleItems: () => void
14
+ template: string
15
+ }
16
+
17
+ export const TestFor = defineComponent({
18
+ setup(): TestForResult {
19
+ const items = signal<Item[]>([
20
+ { id: 1, name: 'Item 1' },
21
+ { id: 2, name: 'Item 2' },
22
+ { id: 3, name: 'Item 3' }
23
+ ])
24
+ const search = signal('')
25
+ const filteredItems = items.filter(i =>
26
+ i.name.toLowerCase().includes(search().toLowerCase())
27
+ )
28
+ const namesSummary = filteredItems.map(i => i.name).join(', ')
29
+
30
+ return {
31
+ items,
32
+ search,
33
+ filteredItems,
34
+ namesSummary,
35
+ updateItem: (id, newName) => {
36
+ items(items().map(i => i.id === id ? { ...i, name: newName } : i))
37
+ },
38
+ addItem: () => {
39
+ const nextIds = items().map(i => i.id)
40
+ const nextId = nextIds.length > 0 ? Math.max(...nextIds) + 1 : 1
41
+ items.push({ id: nextId, name: `Item ${nextId}` })
42
+ },
43
+ shuffleItems: () => {
44
+ items.sort(() => Math.random() - 0.5)
45
+ },
46
+ template: `
47
+ <div class="page">
48
+ <h1>Keyed f-for Test (TypeScript)</h1>
49
+ <p>Focus an input below, then click "Shuffle" or "Add". The focus should stay!</p>
50
+
51
+ <p style="color: #8b8bff; background: #8b8bff11; padding: 10px; border-radius: 4px; border-left: 3px solid #8b8bff;">
52
+ 🔗 <strong>Reactive Summary:</strong> {{ namesSummary || 'No items found' }}
53
+ </p>
54
+
55
+ <div style="margin-bottom: 20px; display: flex; flex-direction: column; gap: 10px;">
56
+ <input type="text" f-model="search" placeholder="🔍 Filter items..."
57
+ style="padding: 10px; border-radius: 4px; border: 1px solid #444; background: #111; color: #fff; width: 100%;" />
58
+
59
+ <div style="display: flex; gap: 10px;">
60
+ <button @click="addItem" class="primary-btn">Add Item</button>
61
+ <button @click="shuffleItems" class="primary-btn">Shuffle Items</button>
62
+ </div>
63
+ </div>
64
+
65
+ <div style="display: flex; flex-direction: column; gap: 10px;">
66
+ <div f-for="item in filteredItems" :key="item.id"
67
+ style="padding: 10px; border: 1px solid #333; display: flex; gap: 10px; align-items: center;">
68
+ <span>ID: {{ item.id }}</span>
69
+ <input type="text"
70
+ :value="item.name"
71
+ @input="updateItem(item().id, $event.target.value)"
72
+ placeholder="Type here..."
73
+ style="background: #111; color: #fff; border: 1px solid #444; padding: 5px;" />
74
+ </div>
75
+ </div>
76
+ </div>
77
+ `
78
+ }
79
+ }
80
+ })
@@ -0,0 +1,24 @@
1
+ import { routeParams, computed } from '../../../framework/index.js'
2
+
3
+ /**
4
+ * User Detail (JS) — child of the /users layout.
5
+ */
6
+ export const UserDetail = defineComponent({
7
+ setup() {
8
+ const params = routeParams
9
+ const userId = computed(() => params().id || '?')
10
+
11
+ return {
12
+ userId,
13
+ template: `
14
+ <div class="page">
15
+ <h1>👤 User #{{ userId }} (JS)</h1>
16
+ <div class="demo-card">
17
+ <p>This content area changes while the sidebar persists.</p>
18
+ <p>Current User ID: <strong style="color: #8b8bff;">{{ userId }}</strong></p>
19
+ </div>
20
+ </div>
21
+ `
22
+ }
23
+ }
24
+ })
@@ -0,0 +1,46 @@
1
+ import { routeParams, computed, defineComponent } from '../../../framework/index'
2
+
3
+ /**
4
+ * User Detail — child of the /users layout.
5
+ * Renders inside the layout's <div data-router-view> for /users/:id.
6
+ */
7
+ export const UserDetail = defineComponent({
8
+ setup() {
9
+ const params = routeParams
10
+ const userId = computed(() => params().id || '?')
11
+
12
+ return {
13
+ userId,
14
+ params,
15
+ template: `
16
+ <div class="page">
17
+ <h1>👤 User #{{ userId }}</h1>
18
+
19
+ <div class="demo-card">
20
+ <h2>User Profile</h2>
21
+ <p style="color: #8b8bff; font-size: 1.2rem; margin-bottom: 0.5rem;">
22
+ ID: <strong>{{ userId }}</strong>
23
+ </p>
24
+ <p style="color: #888; font-size: 0.9rem;">
25
+ This page renders inside the Users layout.
26
+ The sidebar persists — only this content area changes.
27
+ </p>
28
+ </div>
29
+
30
+ <div class="demo-card" style="margin-top: 1rem;">
31
+ <h2>Navigate to Other Users</h2>
32
+ <div style="display: flex; gap: 0.5rem; flex-wrap: wrap;">
33
+ <a href="/users/1" f-link class="cmp-btn" style="text-decoration: none;">User #1</a>
34
+ <a href="/users/2" f-link class="cmp-btn" style="text-decoration: none;">User #2</a>
35
+ <a href="/users/42" f-link class="cmp-btn" style="text-decoration: none;">User #42</a>
36
+ <a href="/users/999" f-link class="cmp-btn" style="text-decoration: none;">User #999</a>
37
+ </div>
38
+ <p style="margin-top: 0.75rem; color: #555; font-size: 0.8rem;">
39
+ ⚡ Notice: the layout sidebar does NOT re-render when switching users!
40
+ </p>
41
+ </div>
42
+ </div>
43
+ `
44
+ }
45
+ }
46
+ })
@@ -0,0 +1,22 @@
1
+ export const UsersIndex = defineComponent({
2
+ setup() {
3
+ return {
4
+ template: `
5
+ <div class="page">
6
+ <h1>📋 All Users (JS)</h1>
7
+ <p>Select a user from the sidebar to view their profile.</p>
8
+ <div style="display: grid; gap: 0.75rem; margin-top: 1rem;">
9
+ <a href="/users/1" f-link class="demo-card" style="text-decoration: none;">
10
+ <h2>👤 Alice Johnson</h2>
11
+ <p>ID: 1 · Engineer</p>
12
+ </a>
13
+ <a href="/users/2" f-link class="demo-card" style="text-decoration: none;">
14
+ <h2>👤 Bob Smith</h2>
15
+ <p>ID: 2 · Designer</p>
16
+ </a>
17
+ </div>
18
+ </div>
19
+ `
20
+ }
21
+ }
22
+ })
@@ -0,0 +1,29 @@
1
+ import { defineComponent } from '../../../framework/index'
2
+
3
+ export const UsersIndex = defineComponent({
4
+ setup() {
5
+ return {
6
+ template: `
7
+ <div class="page">
8
+ <h1>📋 All Users</h1>
9
+ <p style="margin-bottom: 1.5rem;">Select a user from the sidebar to view their profile.</p>
10
+
11
+ <div style="display: grid; gap: 0.75rem;">
12
+ <a href="/users/1" f-link class="demo-card" style="text-decoration: none; cursor: pointer; transition: border-color 0.2s;">
13
+ <h2 style="font-size: 1rem;">👤 Alice Johnson</h2>
14
+ <p style="font-size: 0.85rem; color: #888;">ID: 1 · Engineer</p>
15
+ </a>
16
+ <a href="/users/2" f-link class="demo-card" style="text-decoration: none; cursor: pointer; transition: border-color 0.2s;">
17
+ <h2 style="font-size: 1rem;">👤 Bob Smith</h2>
18
+ <p style="font-size: 0.85rem; color: #888;">ID: 2 · Designer</p>
19
+ </a>
20
+ <a href="/users/42" f-link class="demo-card" style="text-decoration: none; cursor: pointer; transition: border-color 0.2s;">
21
+ <h2 style="font-size: 1rem;">👤 Charlie Dev</h2>
22
+ <p style="font-size: 0.85rem; color: #888;">ID: 42 · Architect</p>
23
+ </a>
24
+ </div>
25
+ </div>
26
+ `
27
+ }
28
+ }
29
+ })
@@ -0,0 +1,43 @@
1
+ import { currentRoute, routeParams, computed } from '../../framework/index.js'
2
+
3
+ /**
4
+ * Users Layout (JS) — persists across all /users/* child routes.
5
+ */
6
+ export const UsersLayout = defineComponent({
7
+ setup() {
8
+ const path = currentRoute
9
+ const params = routeParams
10
+ const paramsJson = computed(() => JSON.stringify(params()))
11
+
12
+ return {
13
+ path,
14
+ paramsJson,
15
+ template: `
16
+ <div style="display: flex; gap: 2rem; min-height: 60vh;">
17
+ <aside style="
18
+ width: 220px;
19
+ flex-shrink: 0;
20
+ background: #13131d;
21
+ border: 1px solid #2a2a3a;
22
+ border-radius: 12px;
23
+ padding: 1.25rem;
24
+ ">
25
+ <h3 style="color: #8b8bff; font-size: 0.85rem; text-transform: uppercase; margin-bottom: 1rem;">👥 Users</h3>
26
+ <nav style="display: flex; flex-direction: column; gap: 0.5rem;">
27
+ <a href="/users" f-link class="cmp-btn" style="text-decoration: none; text-align: left;">📋 All Users</a>
28
+ <a href="/users/1" f-link class="cmp-btn" style="text-decoration: none; text-align: left;">👤 User #1</a>
29
+ <a href="/users/2" f-link class="cmp-btn" style="text-decoration: none; text-align: left;">👤 User #2</a>
30
+ </nav>
31
+ <div style="margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid #2a2a3a; font-size: 0.75rem; color: #555;">
32
+ <p>Route: <span style="color: #8b8bff;">{{ path }}</span></p>
33
+ <p>Params: <span style="color: #34d399;">{{ paramsJson }}</span></p>
34
+ </div>
35
+ </aside>
36
+ <main style="flex: 1;">
37
+ <div data-router-view></div>
38
+ </main>
39
+ </div>
40
+ `
41
+ }
42
+ }
43
+ })
@@ -0,0 +1,78 @@
1
+ import { currentRoute, routeParams, computed, defineComponent } from '../../framework/index'
2
+
3
+ /**
4
+ * Users Layout — persists across all /users/* child routes.
5
+ * Contains a sidebar nav and a <div data-router-view> where children render.
6
+ */
7
+ export const UsersLayout = defineComponent({
8
+ setup() {
9
+ const path = currentRoute
10
+ const params = routeParams
11
+ const paramsJson = computed(() => JSON.stringify(params()))
12
+
13
+ return {
14
+ path,
15
+ paramsJson,
16
+ template: `
17
+ <div style="display: flex; gap: 2rem; min-height: 60vh;">
18
+ <!-- Sidebar (persists across child navigations) -->
19
+ <aside style="
20
+ width: 220px;
21
+ flex-shrink: 0;
22
+ background: #13131d;
23
+ border: 1px solid #2a2a3a;
24
+ border-radius: 12px;
25
+ padding: 1.25rem;
26
+ ">
27
+ <h3 style="
28
+ color: #8b8bff;
29
+ font-size: 0.85rem;
30
+ text-transform: uppercase;
31
+ letter-spacing: 0.1em;
32
+ margin-bottom: 1rem;
33
+ ">👥 Users</h3>
34
+
35
+ <nav style="display: flex; flex-direction: column; gap: 0.5rem;">
36
+ <a href="/users" f-link class="cmp-btn" style="
37
+ text-decoration: none;
38
+ text-align: left;
39
+ font-size: 0.9rem;
40
+ ">📋 All Users</a>
41
+ <a href="/users/1" f-link class="cmp-btn" style="
42
+ text-decoration: none;
43
+ text-align: left;
44
+ font-size: 0.9rem;
45
+ ">👤 User #1</a>
46
+ <a href="/users/2" f-link class="cmp-btn" style="
47
+ text-decoration: none;
48
+ text-align: left;
49
+ font-size: 0.9rem;
50
+ ">👤 User #2</a>
51
+ <a href="/users/42" f-link class="cmp-btn" style="
52
+ text-decoration: none;
53
+ text-align: left;
54
+ font-size: 0.9rem;
55
+ ">👤 User #42</a>
56
+ </nav>
57
+
58
+ <div style="
59
+ margin-top: 1.5rem;
60
+ padding-top: 1rem;
61
+ border-top: 1px solid #2a2a3a;
62
+ font-size: 0.75rem;
63
+ color: #555;
64
+ ">
65
+ <p style="margin-bottom: 4px;">Route: <span style="color: #8b8bff;">{{ path }}</span></p>
66
+ <p>Params: <span style="color: #34d399;">{{ paramsJson }}</span></p>
67
+ </div>
68
+ </aside>
69
+
70
+ <!-- Child route renders here -->
71
+ <main style="flex: 1; min-width: 0;">
72
+ <div data-router-view></div>
73
+ </main>
74
+ </div>
75
+ `
76
+ }
77
+ }
78
+ })
@@ -14,7 +14,7 @@ export const About = defineComponent({
14
14
  <div class="page">
15
15
  <h1>About</h1>
16
16
  <p>Framework custom — SPA prototipe</p>
17
- <p><strong>Features:</strong> signals, defineComponent, hash router, lifecycle hooks.</p>
17
+ <p><strong>Features:</strong> signals, defineComponent, History API router, lifecycle hooks.</p>
18
18
  <p class="status">{{ loaded }}</p>
19
19
  </div>
20
20
  `
@@ -20,7 +20,7 @@ export const About = defineComponent({
20
20
  <div class="page">
21
21
  <h1>About</h1>
22
22
  <p>Framework custom — prototip SPA.</p>
23
- <p><strong>Features:</strong> signals, defineComponent, hash router, lifecycle hooks.</p>
23
+ <p><strong>Features:</strong> signals, defineComponent, History API router, lifecycle hooks.</p>
24
24
  <p class="status">{{ loaded }}</p>
25
25
  </div>
26
26
  `
@@ -0,0 +1,41 @@
1
+ import { currentRoute, navigate } from '../../framework/index.js'
2
+
3
+ // Demo: Multiple paths for the same component
4
+ // Navigating between /login and /register will NOT cause re-render
5
+ export const AuthRoutes = defineComponent({
6
+ setup() {
7
+ const path = currentRoute
8
+
9
+ return {
10
+ path,
11
+ navigate,
12
+ template: `
13
+ <div class="page">
14
+ <h1>🔐 Auth Page (Multiple Paths Demo)</h1>
15
+ <div class="demo-card">
16
+ <p>Current path: <code>{{ path }}</code></p>
17
+ <p style="color: #888; margin-top: 10px;">
18
+ This component handles multiple paths: <code>/login</code> and <code>/register</code>
19
+ </p>
20
+ <p style="color: #34d399;">
21
+ ✅ The component is NOT re-rendered when switching between these paths!
22
+ </p>
23
+ </div>
24
+
25
+ <div class="demo-card">
26
+ <h2>Switch Paths (No Re-render)</h2>
27
+ <div style="display: flex; gap: 10px;">
28
+ <button @click="navigate('/login')" class="cmp-btn">Go to /login</button>
29
+ <button @click="navigate('/register')" class="cmp-btn" style="border-color: #8b8bff; color: #8b8bff;">Go to /register</button>
30
+ </div>
31
+ </div>
32
+
33
+ <div class="demo-card">
34
+ <h2>Test Re-render</h2>
35
+ <button @click="navigate('/about')" class="cmp-btn" style="border-color: #f59e0b; color: #f59e0b;">Go to /about (causes re-render)</button>
36
+ </div>
37
+ </div>
38
+ `
39
+ }
40
+ }
41
+ })
@@ -1,3 +1,4 @@
1
+ import { Counter } from '../components/Counter.js'
1
2
  import { UserForm } from '../components/UserForm.js'
2
3
  import { CounterSection } from '../components/CounterSection.js'
3
4
  import { Card } from '../components/Card.js'
@@ -98,6 +99,14 @@ export const Home = defineComponent({
98
99
  <p>This card uses only the default slot - no named slots provided.</p>
99
100
  {{ /Card }}
100
101
 
102
+ <!-- 🧪 INTERPOLATION TEST -->
103
+ <h3 style="margin-top: 40px; margin-bottom: 20px; color: #e83e8c;">🔤 INTERPOLATION TEST</h3>
104
+ <div style="background: #2a2a2a; padding: 15px; border-radius: 8px; border: 1px solid #444;">
105
+ <p><strong>Escaped Braces:</strong> \\{{ this is not evaluated }}</p>
106
+ <p><strong>String Literal with Braces:</strong> {{ "Look, {{ braces }} inside a string!" }}</p>
107
+ <p><strong>Dynamic + Escaped:</strong> {{ isActive ? 'Currently: \\{{ Active }}' : 'Currently: \\{{ Inactive }}' }}</p>
108
+ </div>
109
+
101
110
  <!-- 🧪 PROVIDE / INJECT TEST -->
102
111
  <h3 style="margin-top: 40px; margin-bottom: 20px; color: #4CAF50;">🔗 PROVIDE / INJECT TEST</h3>
103
112
  {{ ParentComponent }}
@@ -0,0 +1,16 @@
1
+ import { navigate } from '../../framework/index.js'
2
+
3
+ export const NotFound = defineComponent({
4
+ setup() {
5
+ return {
6
+ navigate,
7
+ template: `
8
+ <div class="page">
9
+ <h1 style="color: #ff6b6b;">404 - Page Not Found</h1>
10
+ <p>The requested route does not exist.</p>
11
+ <button @click="navigate('/')" class="primary-btn">Go Home</button>
12
+ </div>
13
+ `
14
+ }
15
+ }
16
+ })
@@ -0,0 +1,16 @@
1
+ import { navigate } from '../../framework/index.js'
2
+
3
+ export const NotFound = defineComponent({
4
+ setup() {
5
+ return {
6
+ navigate,
7
+ template: `
8
+ <div class="page">
9
+ <h1 style="color: #ff6b6b;">404 - Page Not Found</h1>
10
+ <p>The requested route does not exist.</p>
11
+ <button @click="navigate('/')" class="primary-btn">Go Home</button>
12
+ </div>
13
+ `
14
+ }
15
+ }
16
+ })
@@ -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="/users/123" f-link class="cmp-btn" style="text-decoration: none;">User 123</a>
26
+ <a href="/users/456" f-link class="cmp-btn" style="text-decoration: none;">User 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="/users/123" f-link class="cmp-btn" style="text-decoration: none;">User 123</a>
26
+ <a href="/users/456" f-link class="cmp-btn" style="text-decoration: none;">User 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,35 @@
1
+ import { currentRoute, navigate } from '../../framework/index.js'
2
+
3
+ export const WildcardDemo = defineComponent({
4
+ setup() {
5
+ const path = currentRoute
6
+
7
+ return {
8
+ path,
9
+ navigate,
10
+ template: `
11
+ <div class="page">
12
+ <h1 style="color: #f59e0b;">🎯 Wildcard Match!</h1>
13
+ <p>This route matched via wildcard <code>path: '*'</code></p>
14
+
15
+ <div class="demo-card">
16
+ <h2>Current Path</h2>
17
+ <code style="color: #f59e0b; font-size: 1.5rem;">{{ path }}</code>
18
+ </div>
19
+
20
+ <div class="demo-card">
21
+ <h2>Test Wildcard</h2>
22
+ <p>Any path works here:</p>
23
+ <div style="display: flex; gap: 10px; flex-wrap: wrap;">
24
+ <button @click="navigate('/random-123')" class="cmp-btn">/random-123</button>
25
+ <button @click="navigate('/test/abc')" class="cmp-btn">/test/abc</button>
26
+ <button @click="navigate('/deep/nested/path')" class="cmp-btn">/deep/nested/path</button>
27
+ </div>
28
+ </div>
29
+
30
+ <button @click="navigate('/')" class="primary-btn">Back Home</button>
31
+ </div>
32
+ `
33
+ }
34
+ }
35
+ })
@@ -0,0 +1,35 @@
1
+ import { currentRoute, navigate } from '../../framework/index.js'
2
+
3
+ export const WildcardDemo = defineComponent({
4
+ setup() {
5
+ const path = currentRoute
6
+
7
+ return {
8
+ path,
9
+ navigate,
10
+ template: `
11
+ <div class="page">
12
+ <h1 style="color: #f59e0b;">🎯 Wildcard Match!</h1>
13
+ <p>This route matched via wildcard <code>path: '*'</code></p>
14
+
15
+ <div class="demo-card">
16
+ <h2>Current Path</h2>
17
+ <code style="color: #f59e0b; font-size: 1.5rem;">{{ path }}</code>
18
+ </div>
19
+
20
+ <div class="demo-card">
21
+ <h2>Test Wildcard</h2>
22
+ <p>Any path works here:</p>
23
+ <div style="display: flex; gap: 10px; flex-wrap: wrap;">
24
+ <button @click="navigate('/random-123')" class="cmp-btn">/random-123</button>
25
+ <button @click="navigate('/test/abc')" class="cmp-btn">/test/abc</button>
26
+ <button @click="navigate('/deep/nested/path')" class="cmp-btn">/deep/nested/path</button>
27
+ </div>
28
+ </div>
29
+
30
+ <button @click="navigate('/')" class="primary-btn">Back Home</button>
31
+ </div>
32
+ `
33
+ }
34
+ }
35
+ })
package/auto-imports.d.ts CHANGED
@@ -17,6 +17,7 @@ declare global {
17
17
  const inspect: typeof import('fusee-framework').inspect
18
18
  const mountOutlet: typeof import('fusee-framework').mountOutlet
19
19
  const mountTemplate: typeof import('fusee-framework').mountTemplate
20
+ const onCleanup: typeof import('fusee-framework').onCleanup
20
21
  const onMount: typeof import('fusee-framework').onMount
21
22
  const onUnmount: typeof import('fusee-framework').onUnmount
22
23
  const provide: typeof import('fusee-framework').provide
Binary file
Binary file
Binary file