native-document 1.0.9 → 1.0.11

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 CHANGED
@@ -1,505 +1,269 @@
1
- # 🚀 NativeDocument
1
+ # NativeDocument
2
2
 
3
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
- [![JavaScript](https://img.shields.io/badge/JavaScript-ES6+-yellow.svg)](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
5
- [![Size](https://img.shields.io/badge/Size-~15KB-green.svg)](https://github.com/yourusername/nativedocument)
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
4
+ [![Build Status](https://img.shields.io/badge/Build-Passing-brightgreen.svg)](#)
5
+ [![Version](https://img.shields.io/badge/Version-1.0.0-orange.svg)](#)
6
+ [![Bundle Size](https://img.shields.io/badge/Bundle%20Size-~25kb-green.svg)](#)
6
7
 
7
- > A lightweight, reactive JavaScript framework for building modern web applications with zero dependencies.
8
+ > **A reactive JavaScript framework that preserves native DOM simplicity without sacrificing modern features**
8
9
 
9
- NativeDocument provides a reactive programming model similar to React but using vanilla JavaScript and modern web APIs. It features automatic memory management, a complete set of HTML elements, routing, state management, and real-time DOM updates.
10
+ NativeDocument combines the familiarity of vanilla JavaScript with the power of modern reactivity. No compilation, no virtual DOM, just pure JavaScript with an intuitive API.
10
11
 
11
- ## Features
12
+ ## Why NativeDocument?
12
13
 
13
- - 🔄 **Reactive Observables** - Automatic DOM updates when data changes
14
- - 🧠 **Smart Memory Management** - Automatic cleanup with FinalizationRegistry
15
- - 🎯 **Zero Dependencies** - Pure vanilla JavaScript
16
- - 🛣️ **Built-in Router** - Hash, History, and Memory modes
17
- - 🏪 **Global State Management** - Share state across components
18
- - 📦 **Complete HTML Elements** - All HTML elements with extended functionality
19
- - 🎨 **Conditional Rendering** - ShowIf, ToggleView, ForEach components
20
- - ✅ **Runtime Validation** - Type checking and argument validation
21
-
22
-
23
- ## 🚀 Quick Start
24
-
25
- ### Installation
26
-
27
- ```bash
28
- # Download the minified version
29
- curl -o native-document.min.js https://raw.githubusercontent.com/afrocodeur/native-document/refs/heads/main/dist/native-document.min.js
30
-
31
- # Or include via CDN
14
+ ### **Instant Start**
15
+ ```html
32
16
  <script src="https://cdn.jsdelivr.net/gh/afrocodeur/native-document@latest/dist/native-document.min.js"></script>
33
17
  ```
34
18
 
35
- ```bash
36
- #Use degit
37
-
38
- npx degit afrocodeur/native-document-vite my-project
39
- cd my-project
40
- npm install
41
- npm start
42
- ```
43
-
44
-
19
+ ### **Familiar API**
20
+ ```javascript
21
+ import { Div, Button, Observable } from 'native-document/src/elements';
22
+ import { Observable } from 'native-document';
45
23
 
46
- ### Basic Example
24
+ // CDN
25
+ // const { Div, Button } = NativeDocument.elements;
26
+ // const { Observable } = NativeDocument;
47
27
 
48
- ```javascript
49
- const { Observable } = NativeDocument;
50
- const { H1, P, Button } = NativeDocument.elements;
51
- // Create reactive state
52
28
  const count = Observable(0);
53
- const message = Observable("Hello World!");
54
-
55
- // Create reactive UI
56
- const app = Div([
57
- H1(message),
58
- P(['Count: ',count]),
59
- Button("Increment").nd.on.click(() => count.set(count.val() + 1)),
60
- Button("Reset").nd.on.click(() => count.set(0))
29
+
30
+ const App = Div({ class: 'app' }, [
31
+ Div([ 'Count ', count]),
32
+ // OR Div(`Count ${count}`),
33
+ Button('Increment').nd.on.click(() => count.set(count.val() + 1))
61
34
  ]);
62
35
 
63
- // Mount to DOM
64
- document.body.appendChild(app);
36
+ document.body.appendChild(App);
65
37
  ```
66
38
 
67
- ## 📚 Core Concepts
39
+ ### **Complete Features**
40
+ - **Native reactivity** with observables
41
+ - **Global store** for state management
42
+ - **Built-in conditional rendering**
43
+ - **Full-featured router** (hash, history, memory modes)
44
+ - **Advanced debugging system**
45
+ - **Automatic memory management** via FinalizationRegistry
68
46
 
69
- ### Observables
70
-
71
- Observables are the heart of NativeDocument's reactivity system:
72
-
73
- ```javascript
74
- const { Observable } = NativeDocument;
75
- // Create observable
76
- const name = Observable("John");
47
+ ## Quick Installation
77
48
 
78
- // Get value
79
- console.log(name.val()); // "John"
80
-
81
- // Subscribe to changes
82
- const unsubscribe = name.subscribe((newValue, oldValue) => {
83
- console.log(`Changed from ${oldValue} to ${newValue}`);
84
- });
85
-
86
- // Set value
87
- name.set("Jane");
88
-
89
- // Cleanup
90
- unsubscribe();
49
+ ### Option 1: CDN (Instant Start)
50
+ ```html
51
+ <script src="https://cdn.jsdelivr.net/gh/afrocodeur/native-document@latest/dist/native-document.min.js"></script>
52
+ <script>
53
+ const { Div, Observable } = NativeDocument.elements
54
+ // Your code here
55
+ </script>
91
56
  ```
92
57
 
93
-
94
- ### 📦 Elements
95
-
96
- All HTML elements are available as functions:
97
-
98
- ```javascript
99
- const { Observable } = NativeDocument;
100
- const { Div, H1, H2, P, Link, Strong, Input, Button, Br } = NativeDocument.elements;
101
- // Basic elements
102
- const header = H1("My App");
103
- const paragraph = P("Welcome to NativeDocument!");
104
-
105
- // With attributes
106
- const link = Link({href: "https://example.com", target: "_blank" }, "Click me");
107
-
108
- const name = Observable('');
109
-
110
- // With reactive attributes
111
- const input = Input({
112
- type: "text",
113
- value: name, // Observable binding
114
- placeholder: "Enter name"
115
- });
116
-
117
- // Nested elements
118
- const card = Div({ class: "card" }, [
119
- H2("Card Title"),
120
- Strong(name),
121
- P("Card content here..."),
122
- Button("Action")
123
- ]);
124
-
125
- document.body.appendChild(Div([
126
- input,
127
- card,
128
- Br(),
129
- link
130
- ]));
58
+ ### Option 2: Vite Template (Complete Project)
59
+ ```bash
60
+ npx degit afrocodeur/native-document-vite my-app
61
+ cd my-app
62
+ npm install
63
+ npm run dev
131
64
  ```
132
65
 
66
+ ### Option 3: NPM/Yarn
67
+ ```bash
68
+ npm install native-document
69
+ # or
70
+ yarn add native-document
71
+ ```
133
72
 
134
- ### Conditional Rendering
73
+ ## Quick Example
135
74
 
136
75
  ```javascript
137
- const { Observable } = NativeDocument;
138
- const { ShowIf, Switch, When, Div, P, Button, Br, H2 } = NativeDocument.elements;
76
+ import { Div, Input, Button, ShowIf, ForEach } from 'native-document/src/elements'
77
+ import { Observable } from 'native-document'
139
78
 
79
+ // CDN
80
+ // const { Div, Input, Button, ShowIf, ForEach } = NativeDocument.elements;
81
+ // const { Observable } = NativeDocument;
140
82
 
141
- const isVisible = Observable(true);
142
- const user = Observable({ name: "John", age: 15 });
83
+ // Reactive state
84
+ const todos = Observable.array([])
85
+ const newTodo = Observable('')
143
86
 
144
- // Show/hide elements
145
- const conditionalContent = Div([
146
- ShowIf(isVisible, P("This content is visible!")),
147
- Button('Toggle').nd.on.click(() => isVisible.set((currentValue) => !currentValue))
148
- ]);
149
-
150
- const whenContent = Div([
151
- H2('When'),
152
- When(user.check(u => u.age >= 18))
153
- .show(() => P("Adult content"))
154
- .otherwise(() => P("Minor content")),
155
- ]);
87
+ // Todo Component
88
+ const TodoApp = Div({ class: 'todo-app' }, [
156
89
 
157
- // Toggle between two states
158
- const toggleContent = Div([
159
- H2('Switch'),
160
- Switch(
161
- user.check(u => u.age >= 18),
162
- () => P("Adult content"), // use function to create element only if requested
163
- () => P("Minor content")
164
- ),
165
- Button('Toggle user age').nd.on.click(() => user.set((currentValue) => ({ ...currentValue, age: currentValue.age === 25 ? 15 :25 })))
166
- ]);
90
+ // Input for new todo
91
+ Input({ placeholder: 'Add new task...', value: newTodo }),
167
92
 
168
- document.body.appendChild(Div([
169
- conditionalContent,
170
- Br(),
171
- whenContent,
172
- Br(),
173
- toggleContent
174
- ]));
175
- ```
176
-
177
- ### Lists and Iteration
178
-
179
- ```javascript
180
- const { Observable } = NativeDocument;
181
- const { ForEach, Div, P, Button, Br, H4 } = NativeDocument.elements;
182
-
183
- const items = Observable([
184
- { id: 1, name: "Apple", price: 1.20 },
185
- { id: 2, name: "Banana", price: 0.80 },
186
- { id: 3, name: "Orange", price: 1.50 }
93
+ // Add button
94
+ Button('Add Todo').nd.on.click(() => {
95
+ if (newTodo.val().trim()) {
96
+ todos.push({ id: Date.now(), text: newTodo.val(), done: false })
97
+ newTodo.set('')
98
+ }
99
+ }),
100
+
101
+ // Todo list
102
+ ForEach(todos, (todo, index) =>
103
+ Div({ class: 'todo-item' }, [
104
+ Input({ type: 'checkbox', checked: todo.done }),
105
+ `${todo.text}`,
106
+ Button('Delete').nd.on.click(() => todos.splice(index.val(), 1))
107
+ ]), /*item key (string | callback) */(item) => item),
108
+
109
+ // Empty state
110
+ ShowIf(
111
+ todos.check(list => list.length === 0),
112
+ Div({ class: 'empty' }, 'No todos yet!')
113
+ )
187
114
  ]);
188
115
 
189
- const itemList = ForEach(items, (item, index) =>
190
- Div({ class: "item" }, [
191
- H4(item.name),
192
- P(`$${item.price}`),
193
- Button("Remove").nd.on.click(() => {
194
- items.set((currentItems) => currentItems.filter(i => i.id !== item.id))
195
- })
196
- ]), 'id');
197
-
198
- document.body.appendChild(itemList);
116
+ document.body.appendChild(TodoApp)
199
117
  ```
200
118
 
201
- ### Forms
119
+ ## Core Concepts
202
120
 
121
+ ### Observables
122
+ Reactive data that automatically updates the DOM:
203
123
  ```javascript
124
+ import { Div } from 'native-document/src/elements'
125
+ import { Observable } from 'native-document'
204
126
 
205
- const { EmailInput, Form, Label, Strong, SubmitButton, Input, Div } = NativeDocument.elements;
206
- const { Observable } = NativeDocument;
207
-
208
- const formData = Observable.object({ name: "", email: "d.mamadou@miridoo.net" });
127
+ // CDN
128
+ // const { Div } = NativeDocument.elements;
129
+ // const { Observable } = NativeDocument;
209
130
 
210
- const FormItem = (title, input) => {
211
- return Div([
212
- Label(Strong(title)),
213
- Div(input)
214
- ]);
215
- }
131
+ const user = Observable({ name: 'John', age: 25 });
132
+ const greeting = Observable.computed(() => `Hello ${user.$value.name}!`, [user])
133
+ // Or const greeting = Observable.computed(() => `Hello ${user.val().name}!`, [user])
216
134
 
217
- const form = Form([
218
- FormItem("Name", Input({ value: formData.name })),
219
- FormItem("Email", Input({ value: formData.email })),
220
- SubmitButton("Submit")
221
- ]).nd.on.prevent.submit((event) => {
222
- console.log(Observable.value(formData));
223
- });
135
+ document.body.appendChild(Div(greeting));
224
136
 
225
- document.body.appendChild(form);
137
+ // user.name = 'Fausty'; // will not work
138
+ // user.$value = { ...user.$value, name: ' Hermes!' }; // will work
139
+ // user.set(data => ({ ...data, name: 'Hermes!' })); // will work
140
+ user.set({ ...user.val(), name: 'Hermes!' });
226
141
  ```
227
- ## 🛣️ Routing
228
-
229
- NativeDocument includes a powerful routing system:
230
142
 
143
+ ### Elements
144
+ Familiar HTML element creation with reactive bindings:
231
145
  ```javascript
146
+ import { Div, Button } from 'native-document/src/elements'
147
+ import { Observable } from 'native-document'
232
148
 
233
- const { Div, Button, Main } = NativeDocument.elements;
234
- const { Router, Link } = NativeDocument.router;
235
-
236
- const CustomMiddleware = (request, next) => {
237
- console.log('check custom middleware', request);
238
- // request.params.customValue = true;
239
- return next(request);
240
- };
241
- const AuthMiddleware = (request, next) => {
242
- console.log('check if user is authenticated');
243
- return next(request);
244
- };
149
+ // CDN
150
+ // const { Div, Button } = NativeDocument.elements;
151
+ // const { Observable } = NativeDocument;
245
152
 
246
-
247
- const DefaultLayout = (children) => {
153
+ const App = function() {
154
+ const isVisible = Observable(true)
155
+
248
156
  return Div([
249
- Main({ class: 'main-container', style: 'padding: 1rem 0' }, children),
250
- Div({ class: 'navigation-container'}, Div([
251
- Link({ to: '/' }, 'Home'), // Link from router
252
- Link({ to: { name: 'profile' } }, 'Profile'),
253
- Link({ to: { name: 'user.show', params: {id: 1} } }, 'Show User'),
254
- Link({ to: { name: 'admin.dashboard' } }, 'Show Admin Dashboard'),
255
- Link({ to: { name: 'admin.users' } }, 'Show Admin User'),
256
- Button('Product Page').nd.on.click(() => {
257
- const router = Router.get();
258
- // Navigate programmatically
259
- router.push('/product/123?name=ProductName');
260
- }),
261
- ]))
157
+ Div({
158
+ class: { 'hidden': isVisible.check(v => !v) },
159
+ style: { opacity: isVisible.check(v => v ? 1 : 0.2) }
160
+ }, 'Content'),
161
+ Button('Toggle').nd.on.click(() => isVisible.set(v => !v)),
262
162
  ]);
263
163
  };
264
164
 
265
- const HomePage = () => {
266
- return DefaultLayout(Div('Home page'));
267
- };
268
- const UserPage = ({ params, query }) => {
269
- return DefaultLayout(Div('User page for '+params.id));
270
- };
271
- const ProductPage = ({ params, query }) => {
272
- return DefaultLayout(Div('Product page '+params.id+' with product name '+query.name));
273
- };
274
- const AdminDashboard = () => {
275
- return DefaultLayout(Div('Admin dashboard'));
276
- };
277
- const AdminUsers = () => {
278
- return DefaultLayout(Div('Admin users'));
279
- };
280
- const ProfilePage = () => {
281
- return DefaultLayout(Div('Profile page'));
282
- }
283
-
284
-
285
- const router = Router.create({ mode: "history" }, (router) => {
286
- // Basic route
287
- router.add("/", HomePage, { name: 'home' });
288
-
289
- // Route with parameters
290
- router.add("/user/{id}", UserPage, { name: "user.show" });
291
-
292
- // Route with constraints
293
- router.add("/product/{id:number}", ProductPage);
294
-
295
- // Grouped routes with middleware
296
- router.group("/admin", { middlewares: [AuthMiddleware], name: 'admin' }, () => {
297
- router.add("/dashboard", AdminDashboard, { name: 'dashboard' }); // name = admin.dashboard
298
- router.add("/users", AdminUsers, { name: 'users' }); // name = admin.users
299
- });
300
-
301
- // Named routes
302
- router.add("/profile", ProfilePage, { name: "profile" });
303
-
304
- router.add(".*", () => {
305
- return DefaultLayout(
306
- Div([
307
- '404',
308
- Div('Route not found')
309
- ])
310
- );
311
- })
312
- }).mount(document.body);
313
-
314
- ```
315
-
316
- ## 🏪 State Management
317
-
318
- ### Global Store
319
-
320
- ```javascript
321
- const { Div, P, Button, ShowIf, When } = NativeDocument.elements;
322
- const { Store, Observable } = NativeDocument;
323
-
324
- const $ = Observable.computed;
325
-
326
- // Create global store
327
- Store.create("user", {
328
- name: "Anonymous",
329
- loginAt: '...',
330
- isLoggedIn: false
331
- });
332
-
333
- const Footer = () => {
334
- const user = Store.use("user");
335
- const dynamicLoginAtText = $(() => 'Login at '+user.val().loginAt, [user]);
336
-
337
- return Div({ class: 'footer-container', style: { padding: '1rem 0' }}, [
338
- ShowIf(user.check(u => u.isLoggedIn), P(dynamicLoginAtText))
339
- ]);
340
- };
341
-
342
- // Use in components
343
- const Header = () => {
344
- const user = Store.use("user");
345
-
346
- return Div([
347
- When(user.check(u => u.isLoggedIn))
348
- .show(() => {
349
- const dynamicHelloText = $(() => 'Hello '+user.val().name, [user]);
350
-
351
- return Div([
352
- P(dynamicHelloText),
353
- Button("Logout").nd.on.click(() => {
354
- user.set({ name: null, isLoggedIn: false })
355
- })
356
- ]);
357
- })
358
- .otherwise(() => {
359
- return Button('Login').nd.on.click(() => {
360
- user.set({ name: "John", loginAt: (new Date()).toLocaleString(), isLoggedIn: true })
361
- });
362
- })
363
- ]);
364
- };
365
-
366
- const App = () => {
367
- return Div([
368
- Header(),
369
- Footer()
370
- ]);
371
- }
372
-
373
165
  document.body.appendChild(App());
374
166
  ```
375
167
 
376
-
377
-
378
- ### Local State
379
-
168
+ ### Conditional Rendering
169
+ Built-in components for dynamic content:
380
170
  ```javascript
381
- const { Div, H2, Button } = NativeDocument.elements;
382
- const { Observable } = NativeDocument;
383
-
384
- const Counter = () => {
385
- const count = Observable(0);
171
+ ShowIf(user.check(u => u.isLoggedIn),
172
+ Div('Welcome back!')
173
+ )
386
174
 
387
- const Increment = () => count.set(count.val() + 1);
388
- const Decrement = () => count.set(currentValue => --currentValue)
175
+ Match(theme, {
176
+ 'dark': Div({ class: 'dark-mode' }),
177
+ 'light': Div({ class: 'light-mode' })
178
+ })
389
179
 
390
- return Div({}, [
391
- H2(['Count: ', count]),
392
- Button("-").nd.on.click(Decrement),
393
- Button("+").nd.on.click(Increment),
394
- ]);
395
- };
180
+ Switch(condition, onTrue, onFalse)
396
181
 
397
- document.body.appendChild(Counter());
182
+ When(condition)
183
+ .show(onTrue)
184
+ .otherwise(onFalse)
398
185
  ```
399
186
 
187
+ ## Documentation
400
188
 
401
- ## 🔧 Advanced Features
189
+ - **[Getting Started](docs/getting-started.md)** - Installation and first steps
190
+ - **[Core Concepts](docs/core-concepts.md)** - Understanding the fundamentals
191
+ - **[Observables](docs/observables.md)** - Reactive state management
192
+ - **[Elements](docs/elements.md)** - Creating and composing UI
193
+ - **[Conditional Rendering](docs/conditional-rendering.md)** - Dynamic content
194
+ - **[Routing](docs/routing.md)** - Navigation and URL management
195
+ - **[State Management](docs/state-management.md)** - Global state patterns
196
+ - **[Lifecycle Events](docs/lifecycle-events.md)** - Lifecycle events
197
+ - **[Memory Management](docs/memory-management.md)** - Memory management
198
+ - **[Anchor](docs/anchor.md)** - Anchor
402
199
 
403
- ### Lifecycle Hooks
200
+ ## Examples
404
201
 
405
- ```javascript
406
- const { Div, Button, ShowIf } = NativeDocument.elements;
407
- const { Observable } = NativeDocument;
408
-
409
- const MyComponent = () => {
410
- const element = Div('Hello my component');
411
-
412
- return element
413
- .nd.mounted(() => {
414
- console.log("Component mounted");
415
- })
416
- .nd.unmounted(() => {
417
- console.log("Component unmounted");
418
- });
419
- };
420
-
421
- const App = () => {
422
- const isActive = Observable(true);
202
+ ### Todo App
203
+ ```bash
204
+ # Complete todo application with local storage
205
+ git clone https://github.com/afrocodeur/native-document-examples
206
+ cd examples/todo-app
207
+ ```
423
208
 
424
- return Div([
425
- ShowIf(isActive, () => MyComponent()),
426
- Button('Toggle').nd.on.click(() => isActive.set(!isActive.val()))
427
- ]);
428
- }
209
+ ### SPA Router
210
+ ```bash
211
+ # Single Page Application with routing
212
+ cd examples/routing-spa
213
+ ```
429
214
 
430
- document.body.appendChild(App());
215
+ ### Reusable Components
216
+ ```bash
217
+ # Component library patterns
218
+ cd examples/components
431
219
  ```
432
220
 
221
+ ## Key Features Deep Dive
433
222
 
434
- ### Custom Validation
223
+ ### Performance Optimized
224
+ - Direct DOM manipulation (no virtual DOM overhead)
225
+ - Automatic batching of updates
226
+ - Lazy evaluation of computed values
227
+ - Efficient list rendering with keyed updates
435
228
 
229
+ ### Developer Experience
436
230
  ```javascript
437
- const { withValidation, ArgTypes } = NativeDocument;
231
+ // Built-in debugging
232
+ Observable.debug.enable()
438
233
 
439
- const createUser = (name, age, email) => {
440
- // Function implementation
441
- return { name, age, email };
442
- };
234
+ // Argument validation
235
+ const createUser = (function (name, age) {
236
+ // Auto-validates argument types
237
+ }).args(ArgTypes.string('name'), ArgTypes.number('age'))
443
238
 
444
- const createUserWithArgsValidation = withValidation(createUser, [
445
- ArgTypes.string("name"),
446
- ArgTypes.number("age"),
447
- ArgTypes.string("email")
448
- ]);
239
+ // Error boundaries
240
+ const AppWithBoundayError = App.errorBoundary(() => {
241
+ return Div('Error in the Create User component');
242
+ })
449
243
 
450
- // Usage
451
- const user = createUserWithArgsValidation("John", 25, "john@example.com");
244
+ document.body.appendChild(AppWithBoundayError());
452
245
  ```
453
246
 
454
- ### Custom Validation with Function prototype (args)
455
-
456
- ```javascript
457
-
458
- const { withValidation, ArgTypes, Observable } = NativeDocument;
459
-
460
- const createUser = ((name, age, email) => {
461
- // Function implementation
462
- console.log(name, age, email);
463
- return { name, age, email };
464
- }).args(ArgTypes.string('name'), ArgTypes.number('age'), ArgTypes.string('email'));
465
-
247
+ ## Contributing
466
248
 
467
- // Usage
468
- const user = createUser('John', 25, "john@example.com");
249
+ We welcome contributions! Please see our [Contributing Guide](docs/contributing.md) for details.
469
250
 
251
+ ### Development Setup
252
+ ```bash
253
+ git clone https://github.com/afrocodeur/native-document
254
+ cd native-document
255
+ npm install
256
+ npm run dev
470
257
  ```
471
258
 
259
+ ## License
472
260
 
473
- ## 🎨 Styling
261
+ MIT © [AfroCodeur](https://github.com/afrocodeur)
474
262
 
475
- NativeDocument works great with CSS:
263
+ ## Acknowledgments
476
264
 
477
- ```javascript
478
- const { Div, H2, Button, ShowIf } = NativeDocument.elements;
479
- const { withValidation, ArgTypes, Observable } = NativeDocument;
480
-
481
- const StyledComponent = () => {
482
- const isActive = Observable(false);
483
-
484
- return Div({
485
- class: {
486
- "component": true,
487
- "active": isActive,
488
- "inactive": isActive.check(active => !active)
489
- },
490
- style: {
491
- color: isActive.check(active => active ? "white" : "black"),
492
- backgroundColor: isActive.check(active => active ? "#2980b9" : "#7f8c8d"),
493
- padding: "20px",
494
- borderRadius: "4px"
495
- }
496
- }, [
497
- H2("Styled Component"),
498
- ShowIf(isActive, Div({ style: 'color: white; padding: 1rem 0'}, 'Styled Component is active')),
499
- Button("Toggle").nd.on.click(() => isActive.set((val) => !val))
500
- ]);
501
- };
265
+ Thanks to all contributors and the JavaScript community for inspiration.
266
+
267
+ ---
502
268
 
503
- // Usage
504
- document.body.appendChild(StyledComponent());
505
- ```
269
+ **Ready to build with native simplicity?** [Get Started →](docs/getting-started.md)