sigpro 1.0.14 → 1.2.39
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 +164 -1008
- package/dist/sigpro.editor.js +1 -0
- package/dist/sigpro.grid.js +78 -0
- package/dist/sigpro.js +1 -0
- package/dist/sigpro.ui.css +2 -0
- package/dist/sigpro.ui.js +1 -0
- package/dist/sigpro.utils.js +1 -0
- package/dist/sigpro.vite.js +4 -0
- package/package.json +64 -14
- package/sigpro.d.ts +395 -0
- package/.github/workflows/publish.yml +0 -25
- package/bun.lock +0 -385
- package/docs/404.html +0 -22
- package/docs/api/components.html +0 -595
- package/docs/api/effects.html +0 -787
- package/docs/api/fetch.html +0 -873
- package/docs/api/pages.html +0 -405
- package/docs/api/quick.html +0 -217
- package/docs/api/routing.html +0 -628
- package/docs/api/signals.html +0 -683
- package/docs/api/storage.html +0 -820
- package/docs/assets/api_components.md.BlFwj17l.js +0 -571
- package/docs/assets/api_components.md.BlFwj17l.lean.js +0 -1
- package/docs/assets/api_effects.md.Br_yStBS.js +0 -763
- package/docs/assets/api_effects.md.Br_yStBS.lean.js +0 -1
- package/docs/assets/api_fetch.md.DQLBJSoq.js +0 -849
- package/docs/assets/api_fetch.md.DQLBJSoq.lean.js +0 -1
- package/docs/assets/api_pages.md.BP19nHXw.js +0 -381
- package/docs/assets/api_pages.md.BP19nHXw.lean.js +0 -1
- package/docs/assets/api_quick.md.BDS3ttnt.js +0 -193
- package/docs/assets/api_quick.md.BDS3ttnt.lean.js +0 -1
- package/docs/assets/api_routing.md.7SNAZXtp.js +0 -604
- package/docs/assets/api_routing.md.7SNAZXtp.lean.js +0 -1
- package/docs/assets/api_signals.md.CrW68-BA.js +0 -659
- package/docs/assets/api_signals.md.CrW68-BA.lean.js +0 -1
- package/docs/assets/api_storage.md.COEWBXHk.js +0 -796
- package/docs/assets/api_storage.md.COEWBXHk.lean.js +0 -1
- package/docs/assets/app.DtmzNmNl.js +0 -1
- package/docs/assets/chunks/framework.C8AWLET_.js +0 -19
- package/docs/assets/chunks/theme.yfWKMLQM.js +0 -1
- package/docs/assets/guide_getting-started.md.BeQpK3vd.js +0 -172
- package/docs/assets/guide_getting-started.md.BeQpK3vd.lean.js +0 -1
- package/docs/assets/guide_why.md.DXchYMN-.js +0 -23
- package/docs/assets/guide_why.md.DXchYMN-.lean.js +0 -1
- package/docs/assets/index.md.uvMJmU4o.js +0 -1
- package/docs/assets/index.md.uvMJmU4o.lean.js +0 -1
- package/docs/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
- package/docs/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
- package/docs/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
- package/docs/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
- package/docs/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
- package/docs/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
- package/docs/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
- package/docs/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
- package/docs/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
- package/docs/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
- package/docs/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
- package/docs/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
- package/docs/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
- package/docs/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
- package/docs/assets/style.DJRheFKp.css +0 -1
- package/docs/assets/ui_intro.md.gZ21GFqo.js +0 -1
- package/docs/assets/ui_intro.md.gZ21GFqo.lean.js +0 -1
- package/docs/assets/vite_plugin.md.gDWEi8f0.js +0 -225
- package/docs/assets/vite_plugin.md.gDWEi8f0.lean.js +0 -1
- package/docs/guide/getting-started.html +0 -196
- package/docs/guide/why.html +0 -47
- package/docs/hashmap.json +0 -1
- package/docs/index.html +0 -25
- package/docs/logo.svg +0 -118
- package/docs/ui/intro.html +0 -25
- package/docs/vite/plugin.html +0 -249
- package/docs/vp-icons.css +0 -1
- package/index.js +0 -3
- package/packages/docs/.vitepress/cache/deps/@theme_index.js +0 -275
- package/packages/docs/.vitepress/cache/deps/@theme_index.js.map +0 -7
- package/packages/docs/.vitepress/cache/deps/_metadata.json +0 -40
- package/packages/docs/.vitepress/cache/deps/chunk-3S55Y3P7.js +0 -12951
- package/packages/docs/.vitepress/cache/deps/chunk-3S55Y3P7.js.map +0 -7
- package/packages/docs/.vitepress/cache/deps/chunk-RLEUDPPB.js +0 -9719
- package/packages/docs/.vitepress/cache/deps/chunk-RLEUDPPB.js.map +0 -7
- package/packages/docs/.vitepress/cache/deps/package.json +0 -3
- package/packages/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +0 -4505
- package/packages/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +0 -7
- package/packages/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +0 -583
- package/packages/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +0 -7
- package/packages/docs/.vitepress/cache/deps/vue.js +0 -347
- package/packages/docs/.vitepress/cache/deps/vue.js.map +0 -7
- package/packages/docs/.vitepress/config.js +0 -68
- package/packages/docs/api/components.md +0 -760
- package/packages/docs/api/effects.md +0 -1039
- package/packages/docs/api/fetch.md +0 -998
- package/packages/docs/api/pages.md +0 -497
- package/packages/docs/api/quick.md +0 -436
- package/packages/docs/api/routing.md +0 -784
- package/packages/docs/api/signals.md +0 -899
- package/packages/docs/api/storage.md +0 -952
- package/packages/docs/guide/getting-started.md +0 -308
- package/packages/docs/guide/why.md +0 -135
- package/packages/docs/index.md +0 -84
- package/packages/docs/logo.svg +0 -118
- package/packages/docs/public/logo.svg +0 -118
- package/packages/docs/ui/intro.md +0 -16
- package/packages/docs/vite/plugin.md +0 -423
- package/packages/sigpro/plugin.js +0 -91
- package/packages/sigpro/plugin.min.js +0 -1
- package/packages/sigpro/sigpro.js +0 -631
- package/packages/sigpro/sigpro.min.js +0 -1
- package/vite.config.js +0 -24
|
@@ -1,436 +0,0 @@
|
|
|
1
|
-
# Quick API Reference ⚡
|
|
2
|
-
|
|
3
|
-
A comprehensive reference for all SigPro APIs. Everything you need to build reactive web applications with signals and web components.
|
|
4
|
-
|
|
5
|
-
## 📋 API Functions Reference
|
|
6
|
-
|
|
7
|
-
| Function | Description | Example |
|
|
8
|
-
|----------|-------------|---------|
|
|
9
|
-
| **`$(initialValue)`** | Creates a reactive signal (getter/setter) | `const count = $(0)` |
|
|
10
|
-
| **`$(computedFn)`** | Creates a computed signal | `const full = $(() => first() + last())` |
|
|
11
|
-
| **`$.effect(fn)`** | Runs effect when dependencies change | `$.effect(() => console.log(count()))` |
|
|
12
|
-
| **`$.page(setupFn)`** | Creates a page with automatic cleanup | `$.page(() => html`<div>Page</div>`)` |
|
|
13
|
-
| **`$.component(tagName, setupFn, attrs, useShadow)`** | Creates reactive Web Component | `$.component('my-menu', setup, ['items'])` |
|
|
14
|
-
| **`$.router(routes)`** | Creates a hash-based router | `$.router([{path:'/', component:Home}])` |
|
|
15
|
-
| **`$.router.go(path)`** | Navigates to a route | `$.router.go('/user/42')` |
|
|
16
|
-
| **`$.fetch(url, data, loadingSignal)`** | Fetch wrapper with loading state | `const data = await $.fetch('/api', data, loading)` |
|
|
17
|
-
| **`$.storage(key, initialValue, storageType)`** | Persistent signal (local/sessionStorage) | `const theme = $.storage('theme', 'light')` |
|
|
18
|
-
| **`` html`...` ``** | Template literal for reactive HTML | `` html`<div>${count}</div>` `` |
|
|
19
|
-
|
|
20
|
-
### Signal Methods
|
|
21
|
-
|
|
22
|
-
| Method | Description | Example |
|
|
23
|
-
|--------|-------------|---------|
|
|
24
|
-
| **`signal()`** | Gets current value | `count()` |
|
|
25
|
-
| **`signal(newValue)`** | Sets new value | `count(5)` |
|
|
26
|
-
| **`signal(prev => new)`** | Updates using previous value | `count(c => c + 1)` |
|
|
27
|
-
|
|
28
|
-
### Component Context Properties
|
|
29
|
-
|
|
30
|
-
| Property | Description | Example |
|
|
31
|
-
|----------|-------------|---------|
|
|
32
|
-
| **`props`** | Reactive component properties | `props.title()` |
|
|
33
|
-
| **`slot(name)`** | Accesses slot content | `slot()` or `slot('footer')` |
|
|
34
|
-
| **`emit(event, data)`** | Dispatches custom event | `emit('update', value)` |
|
|
35
|
-
| **`onUnmount(cb)`** | Registers cleanup callback | `onUnmount(() => clearInterval(timer))` |
|
|
36
|
-
|
|
37
|
-
### Page Context Properties
|
|
38
|
-
|
|
39
|
-
| Property | Description | Example |
|
|
40
|
-
|----------|-------------|---------|
|
|
41
|
-
| **`params`** | Route parameters | `params.id`, `params.slug` |
|
|
42
|
-
| **`onUnmount(cb)`** | Registers cleanup callback | `onUnmount(() => clearInterval(timer))` |
|
|
43
|
-
|
|
44
|
-
### HTML Directives
|
|
45
|
-
|
|
46
|
-
| Directive | Description | Example |
|
|
47
|
-
|-----------|-------------|---------|
|
|
48
|
-
| **`@event`** | Event listener | `` @click=${handler} `` |
|
|
49
|
-
| **`:property`** | Two-way binding | `` :value=${signal} `` |
|
|
50
|
-
| **`?attribute`** | Boolean attribute | `` ?disabled=${signal} `` |
|
|
51
|
-
| **`.property`** | DOM property binding | `` .scrollTop=${value} `` |
|
|
52
|
-
| **`class:name`** | Conditional class | `` class:active=${isActive} `` |
|
|
53
|
-
|
|
54
|
-
<style>
|
|
55
|
-
table {
|
|
56
|
-
width: 100%;
|
|
57
|
-
border-collapse: collapse;
|
|
58
|
-
margin: 1.5rem 0;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
th {
|
|
62
|
-
background-color: var(--vp-c-bg-soft);
|
|
63
|
-
padding: 0.75rem;
|
|
64
|
-
text-align: left;
|
|
65
|
-
font-weight: 600;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
td {
|
|
69
|
-
padding: 0.75rem;
|
|
70
|
-
border-bottom: 1px solid var(--vp-c-divider);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
tr:hover {
|
|
74
|
-
background-color: var(--vp-c-bg-soft);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
code {
|
|
78
|
-
font-size: 0.9em;
|
|
79
|
-
padding: 0.2em 0.4em;
|
|
80
|
-
border-radius: 4px;
|
|
81
|
-
background-color: var(--vp-c-bg-mute);
|
|
82
|
-
}
|
|
83
|
-
</style>
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
## 📡 Signals - `$(initialValue)`
|
|
87
|
-
|
|
88
|
-
Creates a reactive value that notifies dependents when changed.
|
|
89
|
-
|
|
90
|
-
| Pattern | Example | Description |
|
|
91
|
-
|---------|---------|-------------|
|
|
92
|
-
| **Basic Signal** | `const count = $(0)` | Create signal with initial value |
|
|
93
|
-
| **Getter** | `count()` | Read current value |
|
|
94
|
-
| **Setter** | `count(5)` | Set new value directly |
|
|
95
|
-
| **Updater** | `count(prev => prev + 1)` | Update based on previous value |
|
|
96
|
-
| **Computed** | `const full = $(() => first() + last())` | Auto-updating derived signal |
|
|
97
|
-
|
|
98
|
-
### Examples
|
|
99
|
-
|
|
100
|
-
```javascript
|
|
101
|
-
// Basic signal
|
|
102
|
-
const count = $(0);
|
|
103
|
-
console.log(count()); // 0
|
|
104
|
-
count(5);
|
|
105
|
-
count(c => c + 1); // 6
|
|
106
|
-
|
|
107
|
-
// Computed signal
|
|
108
|
-
const firstName = $('John');
|
|
109
|
-
const lastName = $('Doe');
|
|
110
|
-
const fullName = $(() => `${firstName()} ${lastName()}`);
|
|
111
|
-
console.log(fullName()); // "John Doe"
|
|
112
|
-
firstName('Jane'); // fullName auto-updates to "Jane Doe"
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
## 🔄 Effects - `$.effect(fn)`
|
|
116
|
-
|
|
117
|
-
Executes a function and automatically re-runs when its dependencies change.
|
|
118
|
-
|
|
119
|
-
| Pattern | Example | Description |
|
|
120
|
-
|---------|---------|-------------|
|
|
121
|
-
| **Basic Effect** | `$.effect(() => console.log(count()))` | Run effect on dependency changes |
|
|
122
|
-
| **Cleanup** | `$.effect(() => { timer = setInterval(...); return () => clearInterval(timer) })` | Return cleanup function |
|
|
123
|
-
| **Stop Effect** | `const stop = $.effect(...); stop()` | Manually stop an effect |
|
|
124
|
-
|
|
125
|
-
### Examples
|
|
126
|
-
|
|
127
|
-
```javascript
|
|
128
|
-
// Auto-running effect
|
|
129
|
-
const count = $(0);
|
|
130
|
-
$.effect(() => {
|
|
131
|
-
console.log(`Count is: ${count()}`);
|
|
132
|
-
}); // Logs immediately and whenever count changes
|
|
133
|
-
|
|
134
|
-
// Effect with cleanup
|
|
135
|
-
const userId = $(1);
|
|
136
|
-
$.effect(() => {
|
|
137
|
-
const id = userId();
|
|
138
|
-
const timer = setInterval(() => fetchUser(id), 5000);
|
|
139
|
-
return () => clearInterval(timer); // Cleanup before re-run
|
|
140
|
-
});
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## 📄 Pages - `$.page(setupFunction)`
|
|
144
|
-
|
|
145
|
-
Creates a page with automatic cleanup of all signals and effects when navigated away.
|
|
146
|
-
|
|
147
|
-
```javascript
|
|
148
|
-
// pages/about.js
|
|
149
|
-
import { $, html } from 'sigpro';
|
|
150
|
-
|
|
151
|
-
export default $.page(() => {
|
|
152
|
-
const count = $(0);
|
|
153
|
-
|
|
154
|
-
// Auto-cleaned on navigation
|
|
155
|
-
$.effect(() => {
|
|
156
|
-
document.title = `Count: ${count()}`;
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
return html`
|
|
160
|
-
<div>
|
|
161
|
-
<h1>About Page</h1>
|
|
162
|
-
<p>Count: ${count}</p>
|
|
163
|
-
<button @click=${() => count(c => c + 1)}>+</button>
|
|
164
|
-
</div>
|
|
165
|
-
`;
|
|
166
|
-
});
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
### With Parameters
|
|
170
|
-
|
|
171
|
-
```javascript
|
|
172
|
-
export default $.page(({ params, onUnmount }) => {
|
|
173
|
-
const userId = params.id;
|
|
174
|
-
|
|
175
|
-
// Manual cleanup if needed
|
|
176
|
-
const interval = setInterval(() => refresh(), 10000);
|
|
177
|
-
onUnmount(() => clearInterval(interval));
|
|
178
|
-
|
|
179
|
-
return html`<div>User: ${userId}</div>`;
|
|
180
|
-
});
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
## 🧩 Components - `$.component(tagName, setup, observedAttributes, useShadowDOM)`
|
|
184
|
-
|
|
185
|
-
Creates Custom Elements with reactive properties.
|
|
186
|
-
|
|
187
|
-
### Parameters
|
|
188
|
-
|
|
189
|
-
| Parameter | Type | Default | Description |
|
|
190
|
-
|-----------|------|---------|-------------|
|
|
191
|
-
| `tagName` | `string` | required | Custom element tag (must include hyphen) |
|
|
192
|
-
| `setupFunction` | `Function` | required | Function that renders the component |
|
|
193
|
-
| `observedAttributes` | `string[]` | `[]` | Attributes to observe for changes |
|
|
194
|
-
| `useShadowDOM` | `boolean` | `false` | `true` = Shadow DOM (encapsulated), `false` = Light DOM |
|
|
195
|
-
|
|
196
|
-
### Light DOM Example (Default)
|
|
197
|
-
|
|
198
|
-
```javascript
|
|
199
|
-
// button.js - inherits global styles
|
|
200
|
-
$.component('my-button', (props, { slot, emit }) => {
|
|
201
|
-
return html`
|
|
202
|
-
<button
|
|
203
|
-
class="px-4 py-2 bg-blue-500 text-white rounded"
|
|
204
|
-
@click=${() => emit('click')}
|
|
205
|
-
>
|
|
206
|
-
${slot()}
|
|
207
|
-
</button>
|
|
208
|
-
`;
|
|
209
|
-
}, ['variant']); // Observe 'variant' attribute
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
### Shadow DOM Example
|
|
213
|
-
|
|
214
|
-
```javascript
|
|
215
|
-
// calendar.js - encapsulated styles
|
|
216
|
-
$.component('my-calendar', (props) => {
|
|
217
|
-
return html`
|
|
218
|
-
<style>
|
|
219
|
-
/* These styles are isolated */
|
|
220
|
-
.calendar {
|
|
221
|
-
background: white;
|
|
222
|
-
border-radius: 8px;
|
|
223
|
-
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
224
|
-
}
|
|
225
|
-
</style>
|
|
226
|
-
<div class="calendar">
|
|
227
|
-
${renderCalendar(props.date())}
|
|
228
|
-
</div>
|
|
229
|
-
`;
|
|
230
|
-
}, ['date'], true); // true = use Shadow DOM
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
## 🌐 Router - `$.router(routes)`
|
|
234
|
-
|
|
235
|
-
Creates a hash-based router with automatic page cleanup.
|
|
236
|
-
|
|
237
|
-
### Route Definition
|
|
238
|
-
|
|
239
|
-
```javascript
|
|
240
|
-
const routes = [
|
|
241
|
-
// Simple routes
|
|
242
|
-
{ path: '/', component: HomePage },
|
|
243
|
-
{ path: '/about', component: AboutPage },
|
|
244
|
-
|
|
245
|
-
// Routes with parameters
|
|
246
|
-
{ path: '/user/:id', component: UserPage },
|
|
247
|
-
{ path: '/user/:id/posts/:pid', component: PostPage },
|
|
248
|
-
|
|
249
|
-
// RegExp routes for advanced matching
|
|
250
|
-
{ path: /^\/posts\/(?<id>\d+)$/, component: PostPage },
|
|
251
|
-
];
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
### Usage
|
|
255
|
-
|
|
256
|
-
```javascript
|
|
257
|
-
import { $, html } from 'sigpro';
|
|
258
|
-
import Home from './pages/Home.js';
|
|
259
|
-
import User from './pages/User.js';
|
|
260
|
-
|
|
261
|
-
const router = $.router([
|
|
262
|
-
{ path: '/', component: Home },
|
|
263
|
-
{ path: '/user/:id', component: User },
|
|
264
|
-
]);
|
|
265
|
-
|
|
266
|
-
// Navigation
|
|
267
|
-
$.router.go('/user/42');
|
|
268
|
-
$.router.go('about'); // Same as '/about'
|
|
269
|
-
|
|
270
|
-
// In templates
|
|
271
|
-
html`
|
|
272
|
-
<nav>
|
|
273
|
-
<a href="#/">Home</a>
|
|
274
|
-
<a href="#/user/42">Profile</a>
|
|
275
|
-
<button @click=${() => $.router.go('/contact')}>
|
|
276
|
-
Contact
|
|
277
|
-
</button>
|
|
278
|
-
</nav>
|
|
279
|
-
`;
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
## 📦 Storage - `$.storage(key, initialValue, [storage])`
|
|
283
|
-
|
|
284
|
-
Persistent signal that syncs with localStorage or sessionStorage.
|
|
285
|
-
|
|
286
|
-
```javascript
|
|
287
|
-
// localStorage (default)
|
|
288
|
-
const theme = $.storage('theme', 'light');
|
|
289
|
-
const user = $.storage('user', null);
|
|
290
|
-
const settings = $.storage('settings', { notifications: true });
|
|
291
|
-
|
|
292
|
-
// sessionStorage
|
|
293
|
-
const tempData = $.storage('temp', {}, sessionStorage);
|
|
294
|
-
|
|
295
|
-
// Usage like a normal signal
|
|
296
|
-
theme('dark'); // Auto-saves to localStorage
|
|
297
|
-
console.log(theme()); // 'dark' (even after page refresh)
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
## 🌐 Fetch - `$.fetch(url, data, [loading])`
|
|
301
|
-
|
|
302
|
-
Simple fetch wrapper with automatic JSON handling.
|
|
303
|
-
|
|
304
|
-
```javascript
|
|
305
|
-
const loading = $(false);
|
|
306
|
-
|
|
307
|
-
async function loadUser(id) {
|
|
308
|
-
const user = await $.fetch(`/api/users/${id}`, null, loading);
|
|
309
|
-
if (user) userData(user);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// In template
|
|
313
|
-
html`
|
|
314
|
-
<div>
|
|
315
|
-
${() => loading() ? html`<spinner></spinner>` : html`
|
|
316
|
-
<p>${userData()?.name}</p>
|
|
317
|
-
`}
|
|
318
|
-
</div>
|
|
319
|
-
`;
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
## 🎨 Template Literals - `` html`...` ``
|
|
323
|
-
|
|
324
|
-
Creates reactive DOM fragments with directives.
|
|
325
|
-
|
|
326
|
-
### Directives Reference
|
|
327
|
-
|
|
328
|
-
| Directive | Example | Description |
|
|
329
|
-
|-----------|---------|-------------|
|
|
330
|
-
| **Event** | `@click=${handler}` | Add event listener |
|
|
331
|
-
| **Two-way binding** | `:value=${signal}` | Bind signal to input value |
|
|
332
|
-
| **Boolean attribute** | `?disabled=${signal}` | Toggle boolean attribute |
|
|
333
|
-
| **Property** | `.scrollTop=${value}` | Set DOM property directly |
|
|
334
|
-
| **Class toggle** | `class:active=${isActive}` | Toggle class conditionally |
|
|
335
|
-
|
|
336
|
-
### Examples
|
|
337
|
-
|
|
338
|
-
```javascript
|
|
339
|
-
const text = $('');
|
|
340
|
-
const isDisabled = $(false);
|
|
341
|
-
const activeTab = $('home');
|
|
342
|
-
|
|
343
|
-
html`
|
|
344
|
-
<!-- Event binding -->
|
|
345
|
-
<button @click=${() => count(c => c + 1)}>+</button>
|
|
346
|
-
|
|
347
|
-
<!-- Two-way binding -->
|
|
348
|
-
<input :value=${text} />
|
|
349
|
-
<p>You typed: ${text}</p>
|
|
350
|
-
|
|
351
|
-
<!-- Boolean attributes -->
|
|
352
|
-
<button ?disabled=${isDisabled}>Submit</button>
|
|
353
|
-
|
|
354
|
-
<!-- Class toggles -->
|
|
355
|
-
<div class:active=${activeTab() === 'home'}>
|
|
356
|
-
Home content
|
|
357
|
-
</div>
|
|
358
|
-
|
|
359
|
-
<!-- Property binding -->
|
|
360
|
-
<div .scrollTop=${scrollPosition}></div>
|
|
361
|
-
`;
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
## 🎯 Complete Component Example
|
|
365
|
-
|
|
366
|
-
```javascript
|
|
367
|
-
import { $, html } from 'sigpro';
|
|
368
|
-
|
|
369
|
-
// Create a component
|
|
370
|
-
$.component('user-profile', (props, { slot, emit }) => {
|
|
371
|
-
// Reactive state
|
|
372
|
-
const user = $(null);
|
|
373
|
-
const loading = $(false);
|
|
374
|
-
|
|
375
|
-
// Load user data when userId changes
|
|
376
|
-
$.effect(() => {
|
|
377
|
-
const id = props.userId();
|
|
378
|
-
if (id) {
|
|
379
|
-
loading(true);
|
|
380
|
-
$.fetch(`/api/users/${id}`, null, loading)
|
|
381
|
-
.then(data => user(data));
|
|
382
|
-
}
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
// Computed value
|
|
386
|
-
const fullName = $(() =>
|
|
387
|
-
user() ? `${user().firstName} ${user().lastName}` : ''
|
|
388
|
-
);
|
|
389
|
-
|
|
390
|
-
// Template
|
|
391
|
-
return html`
|
|
392
|
-
<div class="user-profile">
|
|
393
|
-
${() => loading() ? html`
|
|
394
|
-
<div class="spinner">Loading...</div>
|
|
395
|
-
` : user() ? html`
|
|
396
|
-
<h2>${fullName}</h2>
|
|
397
|
-
<p>Email: ${user().email}</p>
|
|
398
|
-
<button @click=${() => emit('select', user())}>
|
|
399
|
-
${slot('Select')}
|
|
400
|
-
</button>
|
|
401
|
-
` : html`
|
|
402
|
-
<p>User not found</p>
|
|
403
|
-
`}
|
|
404
|
-
</div>
|
|
405
|
-
`;
|
|
406
|
-
}, ['user-id']); // Observe userId attribute
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
<style>
|
|
410
|
-
table {
|
|
411
|
-
width: 100%;
|
|
412
|
-
border-collapse: collapse;
|
|
413
|
-
margin: 1.5rem 0;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
th {
|
|
417
|
-
background-color: var(--vp-c-bg-soft);
|
|
418
|
-
padding: 0.75rem;
|
|
419
|
-
text-align: left;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
td {
|
|
423
|
-
padding: 0.75rem;
|
|
424
|
-
border-bottom: 1px solid var(--vp-c-divider);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
tr:hover {
|
|
428
|
-
background-color: var(--vp-c-bg-soft);
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
code {
|
|
432
|
-
font-size: 0.9em;
|
|
433
|
-
padding: 0.2em 0.4em;
|
|
434
|
-
border-radius: 4px;
|
|
435
|
-
}
|
|
436
|
-
</style>
|