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,117 @@
|
|
|
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
|
+
<button @click="changeTitle" class="primary-btn" style="margin-bottom: 20px;">Change App Title</button>
|
|
56
|
+
|
|
57
|
+
<!-- 🎨 f-classList Demo -->
|
|
58
|
+
<h3 style="margin-top: 40px; margin-bottom: 20px; color: #f59e0b;">🎨 f-classList Demo</h3>
|
|
59
|
+
<div class="demo-box" f-classList="basicClasses">
|
|
60
|
+
Demo Box (hover me!)
|
|
61
|
+
</div>
|
|
62
|
+
<div style="display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 1rem;">
|
|
63
|
+
<button @click="toggleActive" :class="isActive ? 'btn-on' : 'btn-off'" style="padding: 0.5rem 1rem; border-radius: 6px; cursor: pointer;">
|
|
64
|
+
{{ isActive ? '✓ Active' : '○ Active' }}
|
|
65
|
+
</button>
|
|
66
|
+
<button @click="toggleDisabled" :class="isDisabled ? 'btn-on' : 'btn-off'" style="padding: 0.5rem 1rem; border-radius: 6px; cursor: pointer;">
|
|
67
|
+
{{ isDisabled ? '✓ Disabled' : '○ Disabled' }}
|
|
68
|
+
</button>
|
|
69
|
+
<button @click="toggleLarge" :class="isLarge ? 'btn-on' : 'btn-off'" style="padding: 0.5rem 1rem; border-radius: 6px; cursor: pointer;">
|
|
70
|
+
{{ isLarge ? '✓ Large' : '○ Large' }}
|
|
71
|
+
</button>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
{{ UserForm }}
|
|
75
|
+
|
|
76
|
+
{{ CounterSection @counter-change="handleCounterChange" @counter-reset="handleCounterReset" @custom-event="handleCustomEvent" :pageTitle="title" }}
|
|
77
|
+
|
|
78
|
+
<!-- 🧪 EMIT TEST - NEW SEPARATE COMPONENT -->
|
|
79
|
+
<h3 style="margin-top: 40px; margin-bottom: 20px; color: #4da6ff;">🧪 EMIT EVENTS TEST LAB</h3>
|
|
80
|
+
{{ EmitTest @simple-click="handleSimpleClick" @click-with-data="handleClickWithData" @object-event="handleObjectEvent" }}
|
|
81
|
+
|
|
82
|
+
<!-- 🧪 Slots Test -->
|
|
83
|
+
<h3 style="margin-top: 40px; margin-bottom: 20px;">🎴 Slots Test</h3>
|
|
84
|
+
|
|
85
|
+
{{ Card title="Custom Card" }}
|
|
86
|
+
<template slot="header">
|
|
87
|
+
<p style="color: #10b981; font-weight: bold;">🎯 Custom header from parent!</p>
|
|
88
|
+
</template>
|
|
89
|
+
<p style="color: #f59e0b;">This is custom content passed through the default slot.</p>
|
|
90
|
+
<p>You can pass any HTML content here!</p>
|
|
91
|
+
<template slot="footer">
|
|
92
|
+
<button style="background: #3b82f6; color: white; border: none; padding: 5px 10px; border-radius: 4px; cursor: pointer;">
|
|
93
|
+
Custom Footer Button
|
|
94
|
+
</button>
|
|
95
|
+
</template>
|
|
96
|
+
{{ /Card }}
|
|
97
|
+
|
|
98
|
+
{{ Card title="Default Slots Card" }}
|
|
99
|
+
<p>This card uses only the default slot - no named slots provided.</p>
|
|
100
|
+
{{ /Card }}
|
|
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
|
+
|
|
110
|
+
<!-- 🧪 PROVIDE / INJECT TEST -->
|
|
111
|
+
<h3 style="margin-top: 40px; margin-bottom: 20px; color: #4CAF50;">🔗 PROVIDE / INJECT TEST</h3>
|
|
112
|
+
{{ ParentComponent }}
|
|
113
|
+
</div>
|
|
114
|
+
`
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
})
|
|
@@ -0,0 +1,78 @@
|
|
|
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
|
+
<button @click="changeTitle" class="primary-btn" style="margin-bottom: 20px;">Change App Title</button>
|
|
54
|
+
|
|
55
|
+
<h3 style="margin-top: 40px; margin-bottom: 20px; color: #f59e0b;">🎨 f-classList Demo</h3>
|
|
56
|
+
<div class="demo-box" f-classList="basicClasses">
|
|
57
|
+
Demo Box (hover me!)
|
|
58
|
+
</div>
|
|
59
|
+
<div style="display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 1rem;">
|
|
60
|
+
<button @click="toggleActive" :class="isActive ? 'btn-on' : 'btn-off'" style="padding: 0.5rem 1rem; border-radius: 6px; cursor: pointer;">
|
|
61
|
+
{{ isActive ? '✓ Active' : '○ Active' }}
|
|
62
|
+
</button>
|
|
63
|
+
<button @click="toggleDisabled" :class="isDisabled ? 'btn-on' : 'btn-off'" style="padding: 0.5rem 1rem; border-radius: 6px; cursor: pointer;">
|
|
64
|
+
{{ isDisabled ? '✓ Disabled' : '○ Disabled' }}
|
|
65
|
+
</button>
|
|
66
|
+
<button @click="toggleLarge" :class="isLarge ? 'btn-on' : 'btn-off'" style="padding: 0.5rem 1rem; border-radius: 6px; cursor: pointer;">
|
|
67
|
+
{{ isLarge ? '✓ Large' : '○ Large' }}
|
|
68
|
+
</button>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
{{ UserForm }}
|
|
72
|
+
|
|
73
|
+
{{ CounterSection :pageTitle="title" }}
|
|
74
|
+
</div>
|
|
75
|
+
`
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
})
|
|
@@ -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,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,65 @@
|
|
|
1
|
+
export const TestFor = defineComponent({
|
|
2
|
+
setup() {
|
|
3
|
+
const items = signal([
|
|
4
|
+
{ id: 1, name: 'Item 1' },
|
|
5
|
+
{ id: 2, name: 'Item 2' },
|
|
6
|
+
{ id: 3, name: 'Item 3' }
|
|
7
|
+
])
|
|
8
|
+
const search = signal('')
|
|
9
|
+
|
|
10
|
+
const filteredItems = items.filter(item =>
|
|
11
|
+
item.name.toLowerCase().includes(search().toLowerCase())
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
inspect(items)
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
items,
|
|
18
|
+
search,
|
|
19
|
+
filteredItems,
|
|
20
|
+
namesSummary: filteredItems.map(i => i.name).join(', '),
|
|
21
|
+
|
|
22
|
+
updateItem: (id, newName) => {
|
|
23
|
+
items(items().map(i => i.id === id ? { ...i, name: newName } : i))
|
|
24
|
+
},
|
|
25
|
+
addItem: () => {
|
|
26
|
+
const nextId = Math.max(0, ...items().map(i => i.id)) + 1
|
|
27
|
+
items.push({ id: nextId, name: `Item ${nextId}` })
|
|
28
|
+
},
|
|
29
|
+
shuffleItems: () => {
|
|
30
|
+
items.sort(() => Math.random() - 0.5)
|
|
31
|
+
},
|
|
32
|
+
template: `
|
|
33
|
+
<div class="page">
|
|
34
|
+
<h1>Keyed f-for Test</h1>
|
|
35
|
+
<p>Focus an input below, then click "Shuffle" or "Add". The focus should stay!</p>
|
|
36
|
+
<p style="color: #8b8bff; background: #8b8bff11; padding: 10px; border-radius: 4px; border-left: 3px solid #8b8bff;">
|
|
37
|
+
🔗 <strong>Reactive Summary:</strong> {{ namesSummary || 'No items found' }}
|
|
38
|
+
</p>
|
|
39
|
+
|
|
40
|
+
<div style="margin-bottom: 20px; display: flex; flex-direction: column; gap: 10px;">
|
|
41
|
+
<input type="text" f-model="search" placeholder="🔍 Filter items..."
|
|
42
|
+
style="padding: 10px; border-radius: 4px; border: 1px solid #444; background: #111; color: #fff; width: 100%;" />
|
|
43
|
+
|
|
44
|
+
<div style="display: flex; gap: 10px;">
|
|
45
|
+
<button @click="addItem" class="primary-btn">Add Item</button>
|
|
46
|
+
<button @click="shuffleItems" class="primary-btn">Shuffle Items</button>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<div style="display: flex; flex-direction: column; gap: 10px;">
|
|
51
|
+
<div f-for="item in filteredItems" :key="item.id"
|
|
52
|
+
style="padding: 10px; border: 1px solid #333; display: flex; gap: 10px; align-items: center;">
|
|
53
|
+
<span>ID: {{ item.id }}</span>
|
|
54
|
+
<input type="text"
|
|
55
|
+
:value="item.name"
|
|
56
|
+
@input="updateItem(item().id, $event.target.value)"
|
|
57
|
+
placeholder="Type here..."
|
|
58
|
+
style="background: #111; color: #fff; border: 1px solid #444; padding: 5px;" />
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
`
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
})
|