chocola 1.3.6 → 1.3.7
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 +21 -407
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,427 +1,41 @@
|
|
|
1
|
-
#
|
|
1
|
+
# chocola
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Chocola is a JavaScript library for creating web user interfaces.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`chocola` only contains the functionality to build and serve web static builds. For production you may want to implement `chocola` to your workflow with other frameworks as Vite until official workflows are provided.
|
|
6
6
|
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
- **🧩 Component-Based Architecture** - Build reusable, modular components with ease
|
|
10
|
-
- **⚡ Reactive Runtime** - Components automatically update when reactive variables change
|
|
11
|
-
- **🔄 Reactive Variables** - Mutable state with `&{sfx.var}` syntax and automatic re-rendering
|
|
12
|
-
- **🎯 Context System** - Pass data to components using intuitive `ctx.*` attributes
|
|
13
|
-
- **🌐 Global State Management** - Share state across components with `sfx` variables
|
|
14
|
-
- **📡 Variable Subscription** - Subscribe to state changes across your application
|
|
15
|
-
- **🎭 Conditional Rendering** - Show/hide components dynamically with `chif` attribute
|
|
16
|
-
- **🔌 Component Lifecycle API** - Public APIs for mounting, manipulating, and removing components
|
|
17
|
-
- **📦 Built-in Bundler** - Automatic compilation and optimization
|
|
18
|
-
- **🔥 Hot Reload Development** - See changes instantly with the dev server
|
|
19
|
-
- **🎨 Template Syntax** - Clean HTML templates with `{}` and `&{}` interpolation
|
|
20
|
-
- **⚙️ Zero Config** - Works out of the box with sensible defaults
|
|
21
|
-
|
|
22
|
-
## 🚀 Quick Start
|
|
23
|
-
|
|
24
|
-
### Installation
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
npm install chocola
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### Project Structure
|
|
31
|
-
|
|
32
|
-
```
|
|
33
|
-
my-chocola-app/
|
|
34
|
-
├── src/
|
|
35
|
-
│ ├── lib/
|
|
36
|
-
│ │ ├── Counter.js
|
|
37
|
-
│ │ ├── TodoItem.js
|
|
38
|
-
│ │ └── html/
|
|
39
|
-
│ │ ├── counter.body.html
|
|
40
|
-
│ │ └── todoItem.body.html
|
|
41
|
-
│ ├── styles/
|
|
42
|
-
│ │ └── mainStyle.css
|
|
43
|
-
│ └── index.html
|
|
44
|
-
├── chocola.config.json
|
|
45
|
-
├── chocola.server.js
|
|
46
|
-
└── index.js
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### Configuration
|
|
50
|
-
|
|
51
|
-
Create a `chocola.config.json` file:
|
|
52
|
-
|
|
53
|
-
```json
|
|
54
|
-
{
|
|
55
|
-
"bundle": {
|
|
56
|
-
"srcDir": "/src",
|
|
57
|
-
"outDir": "/dist",
|
|
58
|
-
"libDir": "/lib",
|
|
59
|
-
"emptyOutDir": true
|
|
60
|
-
},
|
|
61
|
-
"dev": {
|
|
62
|
-
"hostname": "localhost",
|
|
63
|
-
"port": 3000
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## 📝 Creating Components
|
|
69
|
-
|
|
70
|
-
### 1. Define Your HTML Template
|
|
71
|
-
|
|
72
|
-
> NOTE: Reactivity, component APIs and global variables are not implemented yet.
|
|
73
|
-
> Any of these features displayed here are for future references and may be modified.
|
|
74
|
-
|
|
75
|
-
Create `src/lib/html/counter.html`:
|
|
7
|
+
## Usage
|
|
76
8
|
|
|
77
9
|
```html
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
<
|
|
83
|
-
|
|
10
|
+
<!-- counter.html -->
|
|
11
|
+
<div>
|
|
12
|
+
<button title={title}>{text}</button>
|
|
13
|
+
|
|
14
|
+
<div class="main">
|
|
15
|
+
<div class="number">${count}</div>
|
|
16
|
+
</div>
|
|
84
17
|
</div>
|
|
85
18
|
```
|
|
86
19
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
Create `src/lib/Counter.js`:
|
|
90
|
-
|
|
91
|
-
```javascript
|
|
92
|
-
import { lib } from "chocola";
|
|
20
|
+
```js
|
|
93
21
|
import HTML from "./html/counter.html";
|
|
22
|
+
import CSS from "./css/counter.css";
|
|
94
23
|
|
|
95
24
|
function RUNTIME(self, ctx) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// Event handlers
|
|
100
|
-
self.querySelector(".increment").addEventListener("click", () => {
|
|
101
|
-
sfx.incrementCount(); // Automatically updates the UI
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
self.querySelector(".decrement").addEventListener("click", () => {
|
|
105
|
-
sfx.decrementCount(); // Automatically updates the UI
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function EFFECTS(self, sfx) {
|
|
110
|
-
// Component lifecycle effects
|
|
111
|
-
sfx.onMount: () => {
|
|
112
|
-
console.log("Counter mounted with count:", sfx.count);
|
|
113
|
-
},
|
|
114
|
-
sfx.onUpdate: () => {
|
|
115
|
-
// Log updated variables
|
|
116
|
-
console.log("Counter updated:", sfx.diff);
|
|
117
|
-
},
|
|
118
|
-
sfx.onRemove: () => {
|
|
119
|
-
console.log("Counter removed");
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
// Create the component public API
|
|
123
|
-
const api = lib.api(self, sfx);
|
|
124
|
-
|
|
125
|
-
// Create methods to expose
|
|
126
|
-
api.incrementCount = () => {
|
|
127
|
-
sfx.count++
|
|
128
|
-
}
|
|
129
|
-
api.decrementCount = () => {
|
|
130
|
-
sfx.count--
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Expose the component API
|
|
134
|
-
return api
|
|
25
|
+
self.querySelector("button").addEventListener("click", () => {
|
|
26
|
+
ctx.count++;
|
|
27
|
+
})
|
|
135
28
|
}
|
|
136
29
|
|
|
137
30
|
export default function Counter() {
|
|
138
31
|
return {
|
|
139
32
|
body: HTML,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
### 3. Use the Component
|
|
147
|
-
|
|
148
|
-
In your `src/index.html`:
|
|
149
|
-
|
|
150
|
-
```html
|
|
151
|
-
<html>
|
|
152
|
-
<head>
|
|
153
|
-
<title>Chocola Counter App</title>
|
|
154
|
-
</head>
|
|
155
|
-
<body>
|
|
156
|
-
<app>
|
|
157
|
-
<Counter ctx.title="My Counter" sfx.initialCount="0"></Counter>
|
|
158
|
-
</app>
|
|
159
|
-
</body>
|
|
160
|
-
</html>
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
## 🎭 Component Anatomy
|
|
164
|
-
|
|
165
|
-
### Template (`body`)
|
|
166
|
-
- Standard HTML with template variables
|
|
167
|
-
- **Static context**: `{ctx.propertyName}`, `{sfx.propertyName}` - rendered once at initialization
|
|
168
|
-
- **Reactive state**: `&{sfx.propertyName}` - automatically updates on change
|
|
169
|
-
- Clean separation of markup and logic
|
|
170
|
-
|
|
171
|
-
### Runtime (`script`) - Optional
|
|
172
|
-
- Function that receives `self` (component API, properties and DOM element), `ctx` (static context), and `sfx` (dynamic context)
|
|
173
|
-
- Initialize runtime script and event handlers
|
|
174
|
-
- Full access to DOM APIs and browser features
|
|
175
|
-
- Executes when the component mounts
|
|
176
|
-
|
|
177
|
-
### Effects (`effects`) - Optional
|
|
178
|
-
- Function that receives `self` and `sfx`
|
|
179
|
-
- Returns lifecycle hooks: `onMount`, `onUpdate`, `onRemove`
|
|
180
|
-
- Manage side effects and component lifecycle
|
|
181
|
-
- Clean up resources when component is removed
|
|
182
|
-
|
|
183
|
-
## ⚡ Reactivity System
|
|
184
|
-
|
|
185
|
-
### Mutable Reactive Variables
|
|
186
|
-
|
|
187
|
-
Use `&{sfx.varName}` in templates for automatic reactivity:
|
|
188
|
-
|
|
189
|
-
```html
|
|
190
|
-
<div>
|
|
191
|
-
<p>Username: &{sfx.username}</p>
|
|
192
|
-
<p>Online: &{sfx.isOnline}</p>
|
|
193
|
-
</div>
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
```javascript
|
|
197
|
-
function RUNTIME(self, ctx) {
|
|
198
|
-
let sfx = self.sfx;
|
|
199
|
-
|
|
200
|
-
// Changes automatically update the UI
|
|
201
|
-
setTimeout(() => {
|
|
202
|
-
sfx.username = "Alice";
|
|
203
|
-
sfx.isOnline = true;
|
|
204
|
-
}, 2000);
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
### Variable Subscription
|
|
209
|
-
|
|
210
|
-
Subscribe to changes in reactive variables across components:
|
|
211
|
-
|
|
212
|
-
```javascript
|
|
213
|
-
import { app } from "chocola";
|
|
214
|
-
|
|
215
|
-
function RUNTIME(self, ctx) {
|
|
216
|
-
let sfx = self.sfx;
|
|
217
|
-
|
|
218
|
-
// Subscribe to global state
|
|
219
|
-
app.watch("globalCounter", (newValue) => {
|
|
220
|
-
console.log("Global counter changed to:", newValue);
|
|
221
|
-
sfx.localCount = newValue * 2;
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
### Conditional Rendering
|
|
227
|
-
|
|
228
|
-
Use the `chif` attribute to conditionally render components:
|
|
229
|
-
|
|
230
|
-
```html
|
|
231
|
-
<app>
|
|
232
|
-
<!-- Based on ctx variable (static) -->
|
|
233
|
-
<LoginForm chif="ctx.isLoggedOut"></LoginForm>
|
|
234
|
-
|
|
235
|
-
<!-- Based on sfx variable (reactive with &) -->
|
|
236
|
-
<Dashboard chif="sfx.&isAuthenticated"></Dashboard>
|
|
237
|
-
<LoadingSpinner chif="sfx.&isLoading"></LoadingSpinner>
|
|
238
|
-
</app>
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
```javascript
|
|
242
|
-
function RUNTIME(self, ctx) {
|
|
243
|
-
let sfx = self.sfx;
|
|
244
|
-
|
|
245
|
-
// Simulate authentication
|
|
246
|
-
setTimeout(() => {
|
|
247
|
-
sfx.isLoading = false;
|
|
248
|
-
sfx.isAuthenticated = true;
|
|
249
|
-
// Dashboard appears, LoadingSpinner disappears
|
|
250
|
-
}, 2000);
|
|
251
|
-
}
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
## 🌐 Global State Management
|
|
255
|
-
|
|
256
|
-
Share state across your entire application:
|
|
257
|
-
|
|
258
|
-
```javascript
|
|
259
|
-
// In any component
|
|
260
|
-
import * as globals from "path/to/globals.js";
|
|
261
|
-
|
|
262
|
-
function RUNTIME(self, ctx) {
|
|
263
|
-
// Set global variables
|
|
264
|
-
globals.userTheme = "dark";
|
|
265
|
-
globals.notifications = [];
|
|
266
|
-
|
|
267
|
-
// Access global variables from other components
|
|
268
|
-
console.log(globals.userTheme);
|
|
269
|
-
}
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
## 🔌 Component Public API
|
|
273
|
-
|
|
274
|
-
### Mounting Components Dynamically
|
|
275
|
-
|
|
276
|
-
```javascript
|
|
277
|
-
// In any component
|
|
278
|
-
import { lib } from "chocola";
|
|
279
|
-
import Counter from "./lib/Counter.js";
|
|
280
|
-
|
|
281
|
-
// Mount a component programmatically in RUNTIME and/or EFFECTS
|
|
282
|
-
function RUNTIME(self, ctx) {
|
|
283
|
-
const counterInstance = lib.mount(Counter)
|
|
284
|
-
.defCtx({
|
|
285
|
-
title: "Dynamic Counter",
|
|
286
|
-
initialCount: "10"
|
|
287
|
-
})
|
|
288
|
-
.render() // Render accepts a DOM element or component
|
|
289
|
-
// instance as a target parameter; default
|
|
290
|
-
// target is set as your <app> element
|
|
291
|
-
}
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
### Manipulating Components
|
|
295
|
-
|
|
296
|
-
```javascript
|
|
297
|
-
// Acces and modify variables
|
|
298
|
-
console.log(counterInstance.ctx.title);
|
|
299
|
-
counterInstance.sfx.count = 1;
|
|
300
|
-
|
|
301
|
-
// Call component API methods
|
|
302
|
-
counterInstance.reset();
|
|
303
|
-
console.log(counterInstance.getCount())
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
### Removing Components
|
|
307
|
-
|
|
308
|
-
```javascript
|
|
309
|
-
// Remove and clean up
|
|
310
|
-
counterInstance.remove();
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
## 🔧 Development
|
|
314
|
-
|
|
315
|
-
### Start Development Server
|
|
316
|
-
|
|
317
|
-
Create `chocola.server.js`:
|
|
318
|
-
|
|
319
|
-
```javascript
|
|
320
|
-
import { dev } from "chocola";
|
|
321
|
-
import path from "path";
|
|
322
|
-
import { fileURLToPath } from "url";
|
|
323
|
-
|
|
324
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
325
|
-
const __dirname = path.dirname(__filename);
|
|
326
|
-
|
|
327
|
-
dev.server(__dirname);
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
Run:
|
|
331
|
-
```bash
|
|
332
|
-
node chocola.server.js
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
Visit `http://localhost:3000` to see your app with hot reload enabled.
|
|
336
|
-
|
|
337
|
-
### Build for Production
|
|
338
|
-
|
|
339
|
-
Create `index.js`:
|
|
340
|
-
|
|
341
|
-
```javascript
|
|
342
|
-
import { app } from "chocola";
|
|
343
|
-
import path from "path";
|
|
344
|
-
import { fileURLToPath } from "url";
|
|
345
|
-
|
|
346
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
347
|
-
const __dirname = path.dirname(__filename);
|
|
348
|
-
|
|
349
|
-
app.build(__dirname);
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
Build:
|
|
353
|
-
```bash
|
|
354
|
-
node index.js
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
Your optimized app will be in the `dist/` directory.
|
|
358
|
-
|
|
359
|
-
---
|
|
360
|
-
|
|
361
|
-
## 🏗️ Build Output
|
|
362
|
-
|
|
363
|
-
Chocola automatically:
|
|
364
|
-
- ✅ Compiles components into optimized JavaScript
|
|
365
|
-
- ✅ Generates unique component IDs (`chid`)
|
|
366
|
-
- ✅ Bundles scripts with proper dependency resolution
|
|
367
|
-
- ✅ Processes templates and injects runtime code
|
|
368
|
-
- ✅ Sets up reactivity system for `&{sfx.*}` variables
|
|
369
|
-
- ✅ Optimizes conditional rendering with `chif` attributes
|
|
370
|
-
- ✅ Generates component API wrappers for mounting/unmounting
|
|
371
|
-
- ✅ Optimizes assets for production
|
|
372
|
-
|
|
373
|
-
## 🎯 Best Practices
|
|
374
|
-
|
|
375
|
-
### When to Use `ctx` vs `sfx`
|
|
376
|
-
|
|
377
|
-
- **Use `ctx`** for static configuration that won't change (titles, labels, initial values)
|
|
378
|
-
- **Use `sfx`** for dynamic data that updates over time and its configurations (counts, user input, API responses)
|
|
379
|
-
|
|
380
|
-
### Component Lifecycle
|
|
381
|
-
|
|
382
|
-
```javascript
|
|
383
|
-
function EFFECTS(self, sfx) {
|
|
384
|
-
return {
|
|
385
|
-
onMount: () => {
|
|
386
|
-
// Initialize, fetch data, set up subscriptions
|
|
387
|
-
},
|
|
388
|
-
onUpdate: () => {
|
|
389
|
-
// React to specific state changes
|
|
390
|
-
// Only runs when sfx variables change
|
|
391
|
-
},
|
|
392
|
-
onRemove: () => {
|
|
393
|
-
// Clean up timers, subscriptions, event listeners
|
|
394
|
-
}
|
|
395
|
-
};
|
|
33
|
+
styles: CSS,
|
|
34
|
+
script: RUNTIME
|
|
35
|
+
}
|
|
396
36
|
}
|
|
397
37
|
```
|
|
398
38
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
- Use `chif` with reactive variables for dynamic show/hide
|
|
402
|
-
- Use `chif` with static variables for static conditional rendering
|
|
403
|
-
- Components with `chif="false"` are not mounted at all (performance optimization)
|
|
404
|
-
|
|
405
|
-
## 🤝 Contributing
|
|
406
|
-
|
|
407
|
-
Contributions are welcome! Chocola is in active development and we'd love your input.
|
|
408
|
-
|
|
409
|
-
## 📄 License
|
|
410
|
-
|
|
411
|
-
MIT License - feel free to use Chocola in your projects!
|
|
412
|
-
|
|
413
|
-
## 🍫 Why Chocola?
|
|
414
|
-
|
|
415
|
-
- **Simple**: No complex build configurations or CLI tools to learn
|
|
416
|
-
- **Reactive**: Built-in reactivity without the complexity of larger frameworks
|
|
417
|
-
- **Fast**: Minimal runtime overhead with efficient reactive updates
|
|
418
|
-
- **Flexible**: Use as much or as little as you need
|
|
419
|
-
- **Modern**: Built with ES modules and modern JavaScript features
|
|
420
|
-
- **Powerful**: Global state, subscriptions, and lifecycle hooks out of the box
|
|
421
|
-
- **Sweet**: Developer experience that's actually enjoyable
|
|
422
|
-
|
|
423
|
-
---
|
|
424
|
-
|
|
425
|
-
Made with 🍫 and ❤️
|
|
39
|
+
## Documentation
|
|
426
40
|
|
|
427
|
-
|
|
41
|
+
See https://github.com/sad-gabi/chocola/wiki
|