Update print statement from 'Hello' to 'Goodbye'

This commit is contained in:
Natxo
2026-03-14 01:08:13 +01:00
committed by GitHub
parent f7950057f5
commit 3a952f089e

116
Readme.md
View File

@@ -122,7 +122,7 @@ count(5);
count(prev => prev + 1); // Use function for previous value count(prev => prev + 1); // Use function for previous value
// Read with dependency tracking (inside effect) // Read with dependency tracking (inside effect)
$$(() => { $e(() => {
console.log(count()); // Will be registered as dependency console.log(count()); // Will be registered as dependency
}); });
``` ```
@@ -130,7 +130,7 @@ $$(() => {
#### Computed Signal #### Computed Signal
```typescript ```typescript
import { $, $$ } from 'sigpro'; import { $, $e } from 'sigpro';
const firstName = $('John'); const firstName = $('John');
const lastName = $('Doe'); const lastName = $('Doe');
@@ -178,20 +178,20 @@ type Signal<T> = {
--- ---
### `$$(effect)` - Effects ### `$e(effect)` - Effects
Executes a function and automatically re-runs it when its dependencies change. Executes a function and automatically re-runs it when its dependencies change.
#### Basic Effect #### Basic Effect
```typescript ```typescript
import { $, $$ } from 'sigpro'; import { $, $e } from 'sigpro';
const count = $(0); const count = $(0);
const name = $('World'); const name = $('World');
// Effect runs immediately and on dependency changes // Effect runs immediately and on dependency changes
$$(() => { $e(() => {
console.log(`Count is: ${count()}`); // Only depends on count console.log(`Count is: ${count()}`); // Only depends on count
}); });
// Log: "Count is: 0" // Log: "Count is: 0"
@@ -205,11 +205,11 @@ name('Universe'); // No log (name is not a dependency)
#### Effect with Cleanup #### Effect with Cleanup
```typescript ```typescript
import { $, $$ } from 'sigpro'; import { $, $e } from 'sigpro';
const userId = $(1); const userId = $(1);
$$(() => { $e(() => {
const id = userId(); const id = userId();
let isSubscribed = true; let isSubscribed = true;
@@ -233,17 +233,17 @@ userId(2); // Previous subscription cleaned up, new one created
#### Nested Effects #### Nested Effects
```typescript ```typescript
import { $, $$ } from 'sigpro'; import { $, $e } from 'sigpro';
const show = $(true); const show = $(true);
const count = $(0); const count = $(0);
$$(() => { $e(() => {
if (!show()) return; if (!show()) return;
// This effect is nested inside the conditional // This effect is nested inside the conditional
// It will only be active when show() is true // It will only be active when show() is true
$$(() => { $e(() => {
console.log('Count changed:', count()); console.log('Count changed:', count());
}); });
}); });
@@ -256,12 +256,12 @@ show(true); // Inner effect recreated, logs "Count changed: 1"
#### Manual Effect Control #### Manual Effect Control
```typescript ```typescript
import { $, $$ } from 'sigpro'; import { $, $e } from 'sigpro';
const count = $(0); const count = $(0);
// Stop effect manually // Stop effect manually
const stop = $$(() => { const stop = $e(() => {
console.log('Effect running:', count()); console.log('Effect running:', count());
}); });
@@ -438,7 +438,7 @@ html`<div class=${className}></div>`
html`<a href="${href}" class="link ${className}">Link</a>` html`<a href="${href}" class="link ${className}">Link</a>`
// Reactive attributes update when signal changes // Reactive attributes update when signal changes
$$(() => { $e(() => {
// The attribute updates automatically // The attribute updates automatically
console.log('Class changed:', className()); console.log('Class changed:', className());
}); });
@@ -582,16 +582,16 @@ const Page = () => html`
--- ---
### `$component(tagName, setupFunction, observedAttributes)` - Web Components ### `$c(tagName, setupFunction, observedAttributes)` - Web Components
Creates Custom Elements with reactive properties. Uses Light DOM (no Shadow DOM) and a slot system based on node filtering. Creates Custom Elements with reactive properties. Uses Light DOM (no Shadow DOM) and a slot system based on node filtering.
#### Basic Component #### Basic Component
```javascript ```javascript
import { $, $component, html } from 'sigpro'; import { $, $c, html } from 'sigpro';
$component('my-counter', (props, context) => { $c('my-counter', (props, context) => {
// props contains signals for each observed attribute // props contains signals for each observed attribute
// context: { slot, emit, host, onUnmount } // context: { slot, emit, host, onUnmount }
@@ -628,9 +628,9 @@ Usage:
#### Component with Named Slots #### Component with Named Slots
```javascript ```javascript
import { $, $component, html } from 'sigpro'; import { $, $c, html } from 'sigpro';
$component('my-card', (props, { slot }) => { $c('my-card', (props, { slot }) => {
return html` return html`
<div class="card"> <div class="card">
<div class="header"> <div class="header">
@@ -666,9 +666,9 @@ Usage:
#### Component with Props and Events #### Component with Props and Events
```javascript ```javascript
import { $, $component, html } from 'sigpro'; import { $, $c, html } from 'sigpro';
$component('todo-item', (props, { emit, host }) => { $c('todo-item', (props, { emit, host }) => {
const handleToggle = () => { const handleToggle = () => {
props.completed(c => !c); props.completed(c => !c);
emit('toggle', { id: props.id(), completed: props.completed() }); emit('toggle', { id: props.id(), completed: props.completed() });
@@ -708,13 +708,13 @@ Usage:
#### Component with Cleanup #### Component with Cleanup
```javascript ```javascript
import { $, $component, html, $$ } from 'sigpro'; import { $, $c, html, $e } from 'sigpro';
$component('timer-widget', (props, { onUnmount }) => { $c('timer-widget', (props, { onUnmount }) => {
const seconds = $(0); const seconds = $(0);
// Effect with automatic cleanup // Effect with automatic cleanup
$$(() => { $e(() => {
const interval = setInterval(() => { const interval = setInterval(() => {
seconds(s => s + 1); seconds(s => s + 1);
}, 1000); }, 1000);
@@ -740,9 +740,9 @@ $component('timer-widget', (props, { onUnmount }) => {
#### Complete Context API #### Complete Context API
```javascript ```javascript
import { $, $component, html } from 'sigpro'; import { $, $c, html } from 'sigpro';
$component('context-demo', (props, context) => { $c('context-demo', (props, context) => {
// Context properties: // Context properties:
// - slot(name) - Gets child nodes with matching slot attribute // - slot(name) - Gets child nodes with matching slot attribute
// - emit(name, detail) - Dispatches custom event // - emit(name, detail) - Dispatches custom event
@@ -784,9 +784,9 @@ $component('context-demo', (props, context) => {
#### Practical Example: Todo App Component #### Practical Example: Todo App Component
```javascript ```javascript
import { $, $component, html } from 'sigpro'; import { $, $c, html } from 'sigpro';
$component('todo-app', () => { $c('todo-app', () => {
const todos = $([]); const todos = $([]);
const newTodo = $(''); const newTodo = $('');
const filter = $('all'); const filter = $('all');
@@ -873,7 +873,7 @@ $component('todo-app', () => {
}, []); }, []);
``` ```
#### Key Points About `$component`: #### Key Points About `$c`:
1. **Light DOM only** - No Shadow DOM, children are accessible and styleable from outside 1. **Light DOM only** - No Shadow DOM, children are accessible and styleable from outside
2. **Slot system** - `slot()` function filters child nodes by `slot` attribute 2. **Slot system** - `slot()` function filters child nodes by `slot` attribute
@@ -884,16 +884,16 @@ $component('todo-app', () => {
--- ---
### `$router(routes)` - Router ### `$r(routes)` - Router
Hash-based router for SPAs with reactive integration. Hash-based router for SPAs with reactive integration.
#### Basic Routing #### Basic Routing
```typescript ```typescript
import { $router, html } from 'sigpro'; import { $r, html } from 'sigpro';
const router = $router([ const router = $r([
{ {
path: '/', path: '/',
component: () => html` component: () => html`
@@ -916,9 +916,9 @@ document.body.appendChild(router);
#### Route Parameters #### Route Parameters
```typescript ```typescript
import { $router, html } from 'sigpro'; import { $r, html } from 'sigpro';
const router = $router([ const router = $r([
{ {
path: '/user/:id', path: '/user/:id',
component: (params) => html` component: (params) => html`
@@ -945,9 +945,9 @@ const router = $router([
#### Nested Routes #### Nested Routes
```typescript ```typescript
import { $router, html, $ } from 'sigpro'; import { $r, html, $ } from 'sigpro';
const router = $router([ const router = $r([
{ {
path: '/', path: '/',
component: () => html` component: () => html`
@@ -961,7 +961,7 @@ const router = $router([
path: '/dashboard', path: '/dashboard',
component: () => { component: () => {
// Nested router // Nested router
const subRouter = $router([ const subRouter = $r([
{ {
path: '/', path: '/',
component: () => html`<h2>Dashboard Home</h2>` component: () => html`<h2>Dashboard Home</h2>`
@@ -994,19 +994,19 @@ const router = $router([
#### Route Guards #### Route Guards
```typescript ```typescript
import { $router, html, $ } from 'sigpro'; import { $r, html, $ } from 'sigpro';
const isAuthenticated = $(false); const isAuthenticated = $(false);
const requireAuth = (component) => (params) => { const requireAuth = (component) => (params) => {
if (!isAuthenticated()) { if (!isAuthenticated()) {
$router.go('/login'); $r.go('/login');
return null; return null;
} }
return component(params); return component(params);
}; };
const router = $router([ const router = $r([
{ {
path: '/', path: '/',
component: () => html`<h1>Public Home</h1>` component: () => html`<h1>Public Home</h1>`
@@ -1030,25 +1030,25 @@ const router = $router([
#### Navigation #### Navigation
```typescript ```typescript
import { $router } from 'sigpro'; import { $r } from 'sigpro';
// Navigate to path // Navigate to path
$router.go('/user/42'); $r.go('/user/42');
// Navigate with replace // Navigate with replace
$router.go('/dashboard', { replace: true }); $r.go('/dashboard', { replace: true });
// Go back // Go back
$router.back(); $r.back();
// Go forward // Go forward
$router.forward(); $r.forward();
// Get current path // Get current path
const currentPath = $router.getCurrentPath(); const currentPath = $r.getCurrentPath();
// Listen to navigation // Listen to navigation
$router.listen((path, oldPath) => { $r.listen((path, oldPath) => {
console.log(`Navigated from ${oldPath} to ${path}`); console.log(`Navigated from ${oldPath} to ${path}`);
}); });
``` ```
@@ -1056,9 +1056,9 @@ $router.listen((path, oldPath) => {
#### Route Transitions #### Route Transitions
```typescript ```typescript
import { $router, html, $$ } from 'sigpro'; import { $r, html, $e } from 'sigpro';
const router = $router([ const router = $r([
{ {
path: '/', path: '/',
component: () => html`<div class="page home">Home</div>` component: () => html`<div class="page home">Home</div>`
@@ -1070,7 +1070,7 @@ const router = $router([
]); ]);
// Add transitions // Add transitions
$$(() => { $e(() => {
const currentPath = router.getCurrentPath(); const currentPath = router.getCurrentPath();
const pages = document.querySelectorAll('.page'); const pages = document.querySelectorAll('.page');
@@ -1092,7 +1092,7 @@ $$(() => {
### Real-time Todo Application ### Real-time Todo Application
```typescript ```typescript
import { $, $$, html, $component } from 'sigpro'; import { $, $e, html, $c } from 'sigpro';
// Styles // Styles
const styles = html` const styles = html`
@@ -1178,7 +1178,7 @@ const styles = html`
</style> </style>
`; `;
$component('todo-app', () => { $c('todo-app', () => {
// State // State
const todos = $(() => { const todos = $(() => {
const saved = localStorage.getItem('todos'); const saved = localStorage.getItem('todos');
@@ -1191,7 +1191,7 @@ $component('todo-app', () => {
const editText = $(''); const editText = $('');
// Save to localStorage on changes // Save to localStorage on changes
$$(() => { $e(() => {
localStorage.setItem('todos', JSON.stringify(todos())); localStorage.setItem('todos', JSON.stringify(todos()));
}); });
@@ -1363,7 +1363,7 @@ $component('todo-app', () => {
### Data Dashboard with Real-time Updates ### Data Dashboard with Real-time Updates
```typescript ```typescript
import { $, $$, html, $component } from 'sigpro'; import { $, $e, html, $c } from 'sigpro';
// Simulated WebSocket connection // Simulated WebSocket connection
class DataStream { class DataStream {
@@ -1389,14 +1389,14 @@ class DataStream {
} }
} }
$component('data-dashboard', () => { $c('data-dashboard', () => {
const stream = new DataStream(); const stream = new DataStream();
const dataPoints = $([]); const dataPoints = $([]);
const selectedCategory = $('all'); const selectedCategory = $('all');
const timeWindow = $(60); // seconds const timeWindow = $(60); // seconds
// Subscribe to data stream // Subscribe to data stream
$$(() => { $e(() => {
const unsubscribe = stream.subscribe((newData) => { const unsubscribe = stream.subscribe((newData) => {
dataPoints(prev => { dataPoints(prev => {
const updated = [...prev, newData]; const updated = [...prev, newData];
@@ -1501,14 +1501,14 @@ $component('data-dashboard', () => {
### Custom Hooks ### Custom Hooks
```typescript ```typescript
import { $, $$ } from 'sigpro'; import { $, $e } from 'sigpro';
// useLocalStorage hook // useLocalStorage hook
function useLocalStorage(key, initialValue) { function useLocalStorage(key, initialValue) {
const stored = localStorage.getItem(key); const stored = localStorage.getItem(key);
const signal = $(stored ? JSON.parse(stored) : initialValue); const signal = $(stored ? JSON.parse(stored) : initialValue);
$$(() => { $e(() => {
localStorage.setItem(key, JSON.stringify(signal())); localStorage.setItem(key, JSON.stringify(signal()));
}); });
@@ -1520,7 +1520,7 @@ function useDebounce(signal, delay) {
const debounced = $(signal()); const debounced = $(signal());
let timeout; let timeout;
$$(() => { $e(() => {
const value = signal(); const value = signal();
clearTimeout(timeout); clearTimeout(timeout);
timeout = setTimeout(() => { timeout = setTimeout(() => {