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.
- package/README.md +30 -13
- package/app/benchmark/benchmark.js +633 -0
- package/app/benchmark/index.html +102 -0
- package/app/benchmark/styles.css +249 -0
- package/app/components/Counter.js +17 -7
- package/app/components/Counter.ts +1 -1
- package/app/components/CounterSection.js +3 -4
- package/app/main.js +29 -62
- package/app/main.ts +72 -63
- package/app/pages/404.js +16 -0
- package/app/pages/[...all].js +35 -0
- package/app/pages/[...all].ts +35 -0
- package/app/pages/_layout.js +26 -0
- package/app/pages/_layout.ts +26 -0
- package/app/pages/about.js +23 -0
- package/app/pages/about.ts +29 -0
- package/app/pages/composables.js +158 -0
- package/app/pages/composables.ts +158 -0
- package/app/pages/dynamic.js +40 -0
- package/app/pages/dynamic.ts +40 -0
- package/app/pages/index.js +117 -0
- package/app/pages/index.ts +78 -0
- package/app/pages/login.ts +21 -0
- package/app/pages/objects/[id].js +56 -0
- package/app/pages/objects/[id].ts +56 -0
- package/app/pages/posts/[category]/[slug].js +56 -0
- package/app/pages/posts/[category]/[slug].ts +56 -0
- package/app/pages/router-example.js +56 -0
- package/app/pages/router-example.ts +56 -0
- package/app/pages/test-for.js +65 -0
- package/app/pages/test-for.ts +80 -0
- package/app/pages/users/[id].js +24 -0
- package/app/pages/users/[id].ts +46 -0
- package/app/pages/users/index.js +22 -0
- package/app/pages/users/index.ts +29 -0
- package/app/pages/users.js +43 -0
- package/app/pages/users.ts +78 -0
- package/app/routes/About.js +1 -1
- package/app/routes/About.ts +1 -1
- package/app/routes/AuthRoutes.ts +41 -0
- package/app/routes/Home.js +9 -0
- package/app/routes/NotFound.js +16 -0
- package/app/routes/NotFound.ts +16 -0
- package/app/routes/RouterExample.js +56 -0
- package/app/routes/RouterExample.ts +56 -0
- package/app/routes/WildcardDemo.js +35 -0
- package/app/routes/WildcardDemo.ts +35 -0
- package/auto-imports.d.ts +1 -0
- package/bin/create-fusee-linux +0 -0
- package/bin/create-fusee-mac-arm64 +0 -0
- package/bin/create-fusee-mac-intel +0 -0
- package/bin/create-fusee-win.exe +0 -0
- package/bin/create-fusee.exe +0 -0
- package/bin/index.js +38 -0
- package/create-fusee-go/cmd/generate.go +72 -0
- package/create-fusee-go/cmd/init.go +38 -0
- package/create-fusee-go/cmd/root.go +121 -0
- package/create-fusee-go/go.mod +10 -0
- package/create-fusee-go/go.sum +10 -0
- package/create-fusee-go/internal/assets/assets.go +78 -0
- package/create-fusee-go/internal/assets/embed/framework/auto-import-preset.js +9 -0
- package/create-fusee-go/internal/assets/embed/framework/core/compiler.js +253 -0
- package/create-fusee-go/internal/assets/embed/framework/core/component.js +266 -0
- package/create-fusee-go/internal/assets/embed/framework/core/composable.js +27 -0
- package/create-fusee-go/internal/assets/embed/framework/core/directives.js +875 -0
- package/create-fusee-go/internal/assets/embed/framework/core/evaluator.js +153 -0
- package/create-fusee-go/internal/assets/embed/framework/core/event-delegation.js +191 -0
- package/create-fusee-go/internal/assets/embed/framework/core/signal.js +412 -0
- package/create-fusee-go/internal/assets/embed/framework/core/store.js +81 -0
- package/create-fusee-go/internal/assets/embed/framework/index.d.ts +3 -0
- package/create-fusee-go/internal/assets/embed/framework/index.js +10 -0
- package/create-fusee-go/internal/assets/embed/framework/router/file-router.js +177 -0
- package/create-fusee-go/internal/assets/embed/framework/router/router.js +462 -0
- package/create-fusee-go/internal/assets/embed/framework/types/compiler.d.ts +15 -0
- package/create-fusee-go/internal/assets/embed/framework/types/component.d.ts +88 -0
- package/create-fusee-go/internal/assets/embed/framework/types/composable.d.ts +14 -0
- package/create-fusee-go/internal/assets/embed/framework/types/directives.d.ts +55 -0
- package/create-fusee-go/internal/assets/embed/framework/types/evaluator.d.ts +13 -0
- package/create-fusee-go/internal/assets/embed/framework/types/event-delegation.d.ts +32 -0
- package/create-fusee-go/internal/assets/embed/framework/types/index.d.ts +22 -0
- package/create-fusee-go/internal/assets/embed/framework/types/router.d.ts +32 -0
- package/create-fusee-go/internal/assets/embed/framework/types/signal.d.ts +79 -0
- package/create-fusee-go/internal/assets/embed/framework/types/store.d.ts +8 -0
- package/create-fusee-go/internal/assets/templates/Counter.tmpl +26 -0
- package/create-fusee-go/internal/assets/templates/component.tmpl +11 -0
- package/create-fusee-go/internal/assets/templates/components/Loading.tmpl +24 -0
- package/create-fusee-go/internal/assets/templates/index.html.tmpl +15 -0
- package/create-fusee-go/internal/assets/templates/main.tmpl +14 -0
- package/create-fusee-go/internal/assets/templates/package.json.tmpl +14 -0
- package/create-fusee-go/internal/assets/templates/page.tmpl +12 -0
- package/create-fusee-go/internal/assets/templates/pages/about.tmpl +20 -0
- package/create-fusee-go/internal/assets/templates/pages/index.tmpl +22 -0
- package/create-fusee-go/internal/assets/templates/pages/layout.tmpl +18 -0
- package/create-fusee-go/internal/assets/templates/tsconfig.json.tmpl +14 -0
- package/create-fusee-go/internal/assets/templates/vite.config.js.tmpl +18 -0
- package/create-fusee-go/main.go +7 -0
- package/framework/auto-import-preset.js +1 -1
- package/framework/core/compiler.js +252 -249
- package/framework/core/component.js +265 -260
- package/framework/core/directives.js +875 -632
- package/framework/core/evaluator.js +153 -70
- package/framework/core/event-delegation.js +191 -0
- package/framework/core/signal.js +412 -404
- package/framework/index.js +10 -11
- package/framework/router/file-router.js +177 -0
- package/framework/router/router.js +462 -80
- package/framework/types/component.d.ts +0 -4
- package/framework/types/event-delegation.d.ts +32 -0
- package/framework/types/index.d.ts +3 -0
- package/framework/types/router.d.ts +32 -15
- package/framework/types/signal.d.ts +1 -0
- package/index.html +638 -563
- package/package.json +5 -3
- package/tsconfig.json +1 -0
- /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
|
+
})
|
package/app/routes/About.js
CHANGED
|
@@ -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,
|
|
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
|
`
|
package/app/routes/About.ts
CHANGED
|
@@ -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,
|
|
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
|
+
})
|
package/app/routes/Home.js
CHANGED
|
@@ -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
|