vanillaforge 1.9.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/CHANGELOG.md ADDED
@@ -0,0 +1,466 @@
1
+ # Changelog
2
+
3
+ All notable changes to VanillaForge will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [1.9.0] - 2026-06-23
11
+
12
+ This release completes the public API surface and prepares the package for npm
13
+ publication.
14
+
15
+ ### Added
16
+
17
+ #### Service class re-exports
18
+ - `IconsService`, `ThemeService`, `AlertsService`, and `FontsService` are now exported
19
+ directly from `src/framework.js` alongside their plugin objects, matching the
20
+ existing `StoreService` export. Allows standalone instantiation and TypeScript type
21
+ annotations without importing from internal plugin paths.
22
+
23
+ #### Publish readiness
24
+ - `prepublishOnly` npm script — runs `npm test && npm run lint` automatically before
25
+ any `npm publish`.
26
+ - `package.json` `"files"` field tightened to include only framework source
27
+ (`src/framework.js`, `src/core/`, `src/components/base-component.js`,
28
+ `src/plugins/`, `src/utils/`) and `types/`. Demo files, build scripts, and
29
+ examples are no longer included in the published package.
30
+ - `FRAMEWORK_VERSION` constant bumped to `1.9.0`.
31
+
32
+ ## [1.8.0] - 2026-06-23
33
+
34
+ This release adds **route loaders** — async data-fetching that runs before a route
35
+ component mounts, so the first render always has data available.
36
+
37
+ ### Added
38
+
39
+ #### Route loaders (`src/core/router.js`)
40
+ - `loader` option on a route config object — an async function called before the
41
+ component mounts.
42
+ - Receives `{ params, path }` — the dynamic URL segments and the matched path.
43
+ - Return value is passed to the component as `this.props.data` on the first render.
44
+ - Loader errors are caught and logged; the component still mounts with
45
+ `props.data: undefined` so it can render a graceful fallback.
46
+ - Fully backward-compatible — routes registered as a bare component class continue
47
+ to work unchanged.
48
+ - TypeScript types: `RouteLoader`, `RouteLoaderContext`, and `RouteConfig.loader`
49
+ added to `types/index.d.ts`.
50
+ - `FRAMEWORK_VERSION` bumped to `1.8.0`.
51
+
52
+ #### Tests
53
+ - `tests/router-loaders.test.js` — covers: loader called before mount, return value
54
+ in `props.data`, `params` and `path` passed to loader, loader error handling,
55
+ bare-class routes still work, multiple routes with independent loaders.
56
+
57
+ #### Documentation
58
+ - `docs/roadmap.md` — route loaders moved to "Done (v1.8)".
59
+ - `docs/API.md` — "Route loaders" section with full usage example.
60
+
61
+ ---
62
+
63
+ ## [1.7.0] - 2026-06-23
64
+
65
+ This release adds the **shared store plugin** — a reactive key/value store accessible
66
+ from any component, no prop-drilling required.
67
+
68
+ ### Added
69
+
70
+ #### Store plugin (`src/plugins/store/store-plugin.js`)
71
+ - `storePlugin` — install with `app.use(storePlugin)`.
72
+ - `StoreService.set(key, value)` — writes a value; `Object.is` equality check
73
+ means identical values are silently ignored.
74
+ - `StoreService.get(key)` — returns the current value (`undefined` for unset keys).
75
+ - `StoreService.subscribe(key, fn)` — per-key subscription; handler receives
76
+ `(value, prev)`; returns an unsubscribe function.
77
+ - `StoreService.subscribeAll(fn)` — subscribes to all writes; handler receives
78
+ `(key, value, prev)`.
79
+ - `StoreService.delete(key)` — removes a key and fires change events with
80
+ `value: undefined`.
81
+ - `StoreService.keys()` — returns all stored key names.
82
+ - Emits `'store:change'` and `'store:change:<key>'` on the shared EventBus so any
83
+ code can react without holding a service reference.
84
+ - Exported from `src/framework.js` as `storePlugin` and `StoreService`.
85
+ - Full TypeScript generics in `types/index.d.ts`.
86
+ - `FRAMEWORK_VERSION` bumped to `1.7.0`.
87
+
88
+ #### Tests
89
+ - `tests/store.test.js` — covers: set/get round-trip, Object.is no-op, subscribe
90
+ per-key, unsubscribe, subscribeAll, delete fires events, keys(), EventBus events,
91
+ plugin registration, idempotency.
92
+
93
+ #### Documentation
94
+ - `docs/roadmap.md` — store plugin moved to "Done (v1.7)".
95
+ - `docs/plugins.md` — full "Store plugin" section with cross-component cart example.
96
+ - `docs/API.md` — `storePlugin` quick reference.
97
+
98
+ ---
99
+
100
+ ## [1.6.0] - 2026-06-23
101
+
102
+ This release adds **signals** — fine-grained reactive primitives that batch updates
103
+ and keep re-renders minimal without requiring `setState()`.
104
+
105
+ ### Added
106
+
107
+ #### Signals (`src/core/signal.js`, `src/components/base-component.js`)
108
+ - `Signal<T>` class — a reactive cell; reading `.value` returns the current value;
109
+ `.set(newValue)` updates it and notifies all subscribers.
110
+ - `Object.is` equality check — identical values are ignored, no unnecessary renders.
111
+ - `signal.subscribe(fn)` — returns an unsubscribe function; works standalone with no
112
+ component needed.
113
+ - `this.signal(initialValue)` on `BaseComponent` — creates a `Signal` linked to the
114
+ component. Calling `.set()` schedules a single batched morph re-render via
115
+ microtask; multiple `.set()` calls in the same synchronous block collapse into one.
116
+ - Auto-cleanup: signals created via `this.signal()` are destroyed when the
117
+ component is destroyed, preventing memory leaks.
118
+ - `Signal` exported from `src/framework.js` for standalone use.
119
+ - Full TypeScript generic `Signal<T>` in `types/index.d.ts`.
120
+ - `FRAMEWORK_VERSION` bumped to `1.6.0`.
121
+
122
+ #### Tests
123
+ - `tests/signals.test.js` — covers: read/write, Object.is no-op, subscribe/
124
+ unsubscribe, batched rendering, component signal auto-cleanup on destroy,
125
+ standalone signal, multiple subscribers.
126
+
127
+ #### Documentation
128
+ - `docs/roadmap.md` — signals moved to "Done (v1.6)".
129
+ - `docs/API.md` — "Signals" section with component and standalone examples.
130
+
131
+ ---
132
+
133
+ ## [1.5.0] - 2026-06-23
134
+
135
+ This release adds the **scaffold CLI** and **TypeScript declaration file** so new
136
+ projects can be created in one command and VS Code provides full type coverage.
137
+
138
+ ### Added
139
+
140
+ #### Scaffold CLI (`create-vanillaforge/`)
141
+ - `npx create-vanillaforge my-app` — interactive project scaffolder.
142
+ - `--template=<name>` flag for non-interactive use.
143
+ - Four templates:
144
+ - `minimal` — bare component + router, no plugins.
145
+ - `full` — all first-party plugins pre-installed.
146
+ - `todo-app` — fully-working Todo app matching the examples/ version.
147
+ - `router-app` — multi-route app with params and child components.
148
+ - Each generated project uses a GitHub git dependency + import map; no build step
149
+ needed in development.
150
+ - CLI package lives in `create-vanillaforge/` (monorepo style); entry point:
151
+ `create-vanillaforge/bin/cli.js`.
152
+ - See `docs/cli.md` for the full CLI reference.
153
+
154
+ #### TypeScript declarations (`types/index.d.ts`)
155
+ - Full declaration file covering every exported symbol: `createApp`, `FrameworkApp`,
156
+ `BaseComponent`, `Router`, `EventBus`, `Signal`, all plugin classes
157
+ (`IconsService`, `ThemeService`, `AlertsService`, `FontsService`, `StoreService`),
158
+ all option interfaces, and all constants.
159
+ - `package.json` updated: `"types": "types/index.d.ts"`, `"files"` array includes
160
+ `types/`, `"exports"` map includes the `"types"` condition.
161
+ - VS Code picks up types automatically in JavaScript projects (no extra config
162
+ needed when importing from the package).
163
+ - `FRAMEWORK_VERSION` bumped to `1.5.0`.
164
+
165
+ #### Documentation
166
+ - `docs/cli.md` — full CLI reference: usage, templates, flags, generated layout.
167
+ - `docs/roadmap.md` — scaffold + types moved to "Done (v1.5)".
168
+
169
+ ---
170
+
171
+ ## [1.4.0] - 2026-06-22
172
+
173
+ This release adds the **self-hosted fonts plugin** — Inter and JetBrains Mono bundled
174
+ as Latin-subset variable-weight woff2 data URIs. Zero external requests, no Google
175
+ Fonts, no file setup.
176
+
177
+ ### Added
178
+
179
+ #### Fonts plugin (`src/plugins/fonts/`)
180
+ - `fontsPlugin` — install with `app.use(fontsPlugin, { families: ['Inter', 'JetBrains Mono'] })`.
181
+ - Inter and JetBrains Mono bundled as Latin-subset, variable-weight woff2 data
182
+ URIs — zero external requests, works out of the box.
183
+ - Weight and style filtering: `{ name: 'Inter', weights: [400, 700], styles: ['normal'] }`.
184
+ For variable fonts `weights` is treated as a `[min, max]` range.
185
+ - `path` option to serve your own font files instead of bundled data URIs.
186
+ - Custom family registration via `FontsService.addFamily(name, manifest)` — returns
187
+ `this` for chaining.
188
+ - Theme token integration: loading Inter updates `--vf-font-sans`; loading JetBrains
189
+ Mono updates `--vf-font-mono` (no-op when `themePlugin` is absent).
190
+ - `FontsService.getFamilies()` — returns CSS family names of all loaded fonts.
191
+ - Idempotent `<style id="vf-fonts">` element — reuses existing element rather than
192
+ duplicating it.
193
+ - `display` option controls `font-display` (default: `'swap'`).
194
+ - Exported from `src/framework.js` as `fontsPlugin` and `FontsService`.
195
+ - `FRAMEWORK_VERSION` bumped to `1.4.0`.
196
+
197
+ #### Tests
198
+ - `tests/fonts.test.js` — covers: style element creation, Inter/JetBrains Mono
199
+ `@font-face` injection, weight range, style filtering, idempotency, `getFamilies()`,
200
+ theme token integration, custom path, `addFamily()`, `fontsPlugin` install.
201
+
202
+ #### Documentation
203
+ - `docs/roadmap.md` — fonts plugin moved to "Done (v1.4)".
204
+ - `docs/plugins.md` — "Built-in fonts plugin" section with full option table and
205
+ `addFamily()` example.
206
+
207
+ ---
208
+
209
+ ## [1.3.0] - 2026-06-22
210
+
211
+ This release adds the **alerts plugin** — zero-dependency toasts and confirm dialogs.
212
+ Apps no longer need SweetAlert, `window.confirm`, or any other notification library.
213
+ The plugin also replaces the old `Notification` class so the ErrorHandler automatically
214
+ uses the new styled UI.
215
+
216
+ ### Added
217
+
218
+ #### Alerts plugin (`src/plugins/alerts/`)
219
+ - `alertsPlugin` — install with `app.use(alertsPlugin)` or with options.
220
+ - `AlertsService` methods:
221
+ - `success(message)`, `error(message)`, `warning(message)`, `info(message)` —
222
+ show a slide-in toast that auto-dismisses after `duration` ms (default 4000).
223
+ - `confirm(message, opts)` — show a modal dialog; returns a `Promise<boolean>`
224
+ (true = confirmed, false = cancelled / backdrop click). Simultaneously calls
225
+ `opts.onConfirm` / `opts.onCancel` callbacks if provided.
226
+ - Toast options: `duration` (per-call override), type classes (`vf-toast-success`,
227
+ `vf-toast-error`, `vf-toast-warning`, `vf-toast-info`), built-in close button.
228
+ - Confirm options: `title` (optional heading), `confirmText`, `cancelText`,
229
+ `danger` (red confirm button), `onConfirm`, `onCancel`.
230
+ - `maxToasts` cap (default 5) — oldest toast is silently removed when exceeded.
231
+ - Injected styles (`<style id="vf-alerts-styles">`) use `--vf-*` custom properties
232
+ if the theme plugin is installed, with plain-CSS fallbacks if not.
233
+ - Backward-compatible `showToast(message, type)` and `showModal(title, message, opts)`
234
+ methods so the existing `ErrorHandler` works without changes.
235
+ - On install, `app.errorHandler.notification` is re-pointed to the new service,
236
+ so framework errors automatically use the styled toasts and dialogs.
237
+ - `alertsPlugin` exported from `src/framework.js` as part of the public API.
238
+ - `FRAMEWORK_VERSION` bumped to `1.3.0`.
239
+
240
+ #### Tests
241
+ - `tests/alerts.test.js` — 22 tests covering: container creation, style injection,
242
+ de-duplication, all four toast type classes, message rendering, auto-dismiss with
243
+ fake timers, close button, maxToasts trimming, `showToast()` backward compat,
244
+ `confirm()` Promise resolution (confirm / cancel / backdrop), `onConfirm` /
245
+ `onCancel` callbacks, DOM cleanup after close, title and danger-button options,
246
+ `showModal()` backward compat and close button, and full plugin integration
247
+ (registration, ErrorHandler wiring, options pass-through, idempotency).
248
+
249
+ #### Examples
250
+ - `examples/router-app/components/user-card.js` — adds a "Remove" button (trash
251
+ icon) that triggers a danger confirm dialog; on confirmation emits `user:remove`
252
+ and shows a success toast.
253
+ - `examples/router-app/components/users-list.js` — initialises state from the users
254
+ array, listens for `user:remove` on the EventBus, and drops the user from state so
255
+ the list re-renders without that card.
256
+ - `examples/router-app/index.html` — installs `alertsPlugin`; adds `.user-card-remove`
257
+ hover style; updates the subtitle.
258
+
259
+ #### Documentation
260
+ - `docs/roadmap.md` — alerts moved to "Done"; fonts/scaffold/signals renumbered.
261
+
262
+ ## [1.2.0] - 2026-06-22
263
+
264
+ This release adds the **CSS/theming plugin** — the first batteries-included styling
265
+ subsystem. Apps now look sensible out of the box without Tailwind, Bootstrap, or any
266
+ external CSS library, while remaining fully themeable.
267
+
268
+ ### Added
269
+
270
+ #### Theme plugin (`src/plugins/theme/`)
271
+ - `themePlugin` — install with `app.use(themePlugin)` or
272
+ `app.use(themePlugin, { tokens: { primary: '#6366f1', radius: '8px' } })`.
273
+ - `ThemeService` — creates a `<style id="vf-theme">` in `<head>` and fills it with
274
+ a `:root {}` block of CSS custom properties (`--vf-primary`, `--vf-radius`, …).
275
+ - **20 default tokens:** `primary`, `primaryDark`, `secondary`, `surface`,
276
+ `background`, `text`, `textMuted`, `border`, `danger`, `success`, `warning`,
277
+ `radius`, `radiusSm`, `radiusLg`, `fontSans`, `fontMono`,
278
+ `shadowSm`, `shadowMd`, `shadowLg`, `space`.
279
+ - Token names follow camelCase in JS and `--vf-kebab-case` in CSS
280
+ (`primaryDark` → `--vf-primary-dark`).
281
+ - `setTokens(map)` — merge new values and live-update the injected stylesheet.
282
+ Returns `this` for chaining.
283
+ - `getToken(name)` — read the current resolved value; returns `null` for unknown
284
+ names.
285
+ - `base: false` option — inject only the `:root {}` token block, skip the
286
+ base stylesheet.
287
+ - Idempotent `<style>` element — re-using an existing `#vf-theme` element so a
288
+ second ThemeService (e.g. after `app.provide('theme', …)`) doesn't leave orphans.
289
+ - Base stylesheet (`src/plugins/theme/base-styles.js`) — included by default:
290
+ box-sizing reset, body font/color/background wired to tokens, `.vf-card` surface
291
+ card, `.vf-btn` + `.vf-btn-primary/secondary/danger/success`, `.vf-icon` alignment.
292
+ - `themePlugin` exported from `src/framework.js` as part of the public API.
293
+ - `FRAMEWORK_VERSION` bumped to `1.2.0`.
294
+
295
+ #### Documentation
296
+ - `docs/roadmap.md` — CSS/theming moved to "Done"; alerts/notifications is now next.
297
+
298
+ #### Tests
299
+ - `tests/theme.test.js` — 16 tests covering: style element creation, `:root` block,
300
+ camelCase→kebab conversion, default token values, token overrides, base styles
301
+ inclusion/exclusion, idempotent element reuse, `setTokens()` update and chaining,
302
+ `getToken()` read/update/null, and `themePlugin` integration via `createApp`.
303
+
304
+ #### Examples
305
+ - `examples/router-app/index.html` installs `themePlugin` with custom token overrides
306
+ and replaces hard-coded hex values with `var(--vf-*)` references throughout its
307
+ hand-written stylesheet.
308
+
309
+ ## [1.1.0] - 2026-06-22
310
+
311
+ This release lays the **long-term foundation** for a batteries-included framework:
312
+ a plugin/service registry, component composition, and a built-in icons subsystem.
313
+ Every future subsystem (CSS/theming, alerts, fonts) slots into the same plugin API.
314
+
315
+ ### Added
316
+
317
+ #### Plugin / service registry (`src/framework.js`)
318
+ - `app.use(plugin, options)` — installs a plugin (a function or `{ name, install }` object).
319
+ Idempotent for named plugins, chainable, available before `app.initialize()`.
320
+ - `app.provide(name, instance)` — registers or replaces a named service in the registry.
321
+ - `app.get(name)` — looks up a service from the registry first, then falls back to registered
322
+ component classes. Fully backward-compatible with existing `app.get('eventBus')` etc.
323
+ - All built-in services (`eventBus`, `logger`, `errorHandler`, `notification`, `validation`,
324
+ `componentManager`, `performanceUtils`, `router`) are now in the registry.
325
+
326
+ #### Component composition (`src/components/base-component.js`, `src/core/dom-morph.js`, `src/core/component-manager.js`)
327
+ - `this.child(ClassOrName, props, key)` — declare a child component inside `getTemplate()`.
328
+ Returns a host placeholder; after the morph, `reconcileChildren()` mounts/updates/destroys
329
+ real child instances to match.
330
+ - `reconcileChildren()` — called automatically after every render. Mounts new children, updates
331
+ props on existing ones (re-renders only when props change), destroys children whose host was
332
+ removed from the template.
333
+ - DOM morph now treats `[data-vf-host]` elements as opaque boundaries — the mounted child's DOM
334
+ is never overwritten by a parent re-render.
335
+ - Event delegation scoped per component — clicks inside a child do not trigger the parent's
336
+ delegated handler.
337
+ - Child instances propagate `app` reference and component resolver down the tree, so
338
+ `this.service()`, `this.icon()`, and `this.child('by-name')` work at any nesting depth.
339
+ - Full teardown: `parent.destroy()` recursively destroys all children, clearing listeners and
340
+ instances with no leaks.
341
+ - `this.service(name)` — reach any plugin service from a component (`null` if absent).
342
+ - `this.icon(name, opts)` — shortcut to the icons service (empty string if absent).
343
+
344
+ #### Built-in icons plugin (`src/plugins/icons/`)
345
+ - `IconsService` — stores and renders inline SVG icons. Methods: `render(name, opts)`,
346
+ `register(name, svg)`, `has(name)`.
347
+ - `iconsPlugin` — install with `app.use(iconsPlugin)` or
348
+ `app.use(iconsPlugin, { icons: { myIcon: '<path .../>' } })`.
349
+ - Ships 20 original inline SVG icons: `check`, `close`, `trash`, `plus`, `minus`, `menu`,
350
+ `chevron-right`, `chevron-left`, `chevron-down`, `chevron-up`, `search`, `info`, `warning`,
351
+ `edit`, `arrow-left`, `arrow-right`, `home`, `user`, `settings`, `external-link`.
352
+ - `render()` options: `size` (default 24), `className`, `title` (adds accessible `<title>` +
353
+ `role="img"`), `color`.
354
+ - Unknown icons log a warning once (not repeatedly) and return an empty string.
355
+ - Exported from `src/framework.js` as part of the public API.
356
+ - Fully replaceable: `app.provide('icons', customService)` overrides the default.
357
+
358
+ #### Documentation
359
+ - `DEVELOPMENT.md` (repo root) — maintainer handbook: vision, resume-after-a-break checklist,
360
+ architecture map, plugin guide, conventions, commands, directory tour, and roadmap pointer.
361
+ - `docs/roadmap.md` — prioritised living roadmap for the next six capabilities (CSS/theming,
362
+ alerts, fonts, fast onboarding, signals, data+store, npm publish).
363
+ - `docs/composition.md` — full guide to component composition: `child()`, keys, props flow,
364
+ child lifecycle, event isolation, nesting, patterns, and gotchas.
365
+ - `docs/plugins.md` — plugin system guide: `use`/`provide`, icons reference, writing your own
366
+ plugin, plugin rules.
367
+ - `docs/README.md` updated with new features and doc links.
368
+ - `README.md` updated: features list, quick-start example with icons, documentation links,
369
+ expanded roadmap section.
370
+
371
+ #### Examples
372
+ - `examples/router-app/components/user-card.js` — new `UserCard` child component with its own
373
+ expand/collapse state, demonstrating stateful children and per-child event isolation.
374
+ - `examples/router-app/components/users-list.js` refactored to use `this.child(UserCard, ...)`,
375
+ with users keyed by id.
376
+ - `examples/router-app/components/user-detail.js` updated to use `this.icon('arrow-left')`.
377
+ - `examples/router-app/index.html` installs `iconsPlugin` and adds card styles.
378
+
379
+ #### Tests
380
+ - `tests/composition.test.js` — child rendering, props flow, keyed identity/reuse, child state
381
+ preservation across parent re-renders, removal/teardown, event isolation, by-name resolution.
382
+ - `tests/plugins.test.js` — `provide()`/`get()` round-trip, `use()` with function and object
383
+ plugins, idempotency, invalid plugin guard, chaining, override behavior.
384
+ - `tests/icons.test.js` — `IconsService.render()` (size/class/title/aria/color), warn-once for
385
+ unknown icons, `register()`/`has()`, `iconsPlugin` install and defaults, `BaseComponent.icon()`
386
+ with and without the plugin installed.
387
+ - Total test count: 88 (all passing).
388
+
389
+ ### Changed
390
+ - `src/framework.js`: version bumped to `1.1.0`.
391
+ - `src/core/component-manager.js`: `loadComponentClass()` now wires `instance.app` and
392
+ `instance._resolveComponent` on every mounted route component.
393
+
394
+ ## [1.0.1] - 2025-06-15 (production-ready refactor)
395
+
396
+ ### Changed
397
+ - **Unified the render pipeline.** `BaseComponent` is now the single owner of
398
+ rendering. The previous double-render (component init + a separate DOMRenderer)
399
+ and its three overlapping event systems were removed; `DOMRenderer` is gone.
400
+ - **Reactive rendering via DOM morphing.** `setState()`/`updateProps()` now patch
401
+ only changed nodes via a new zero-dependency `dom-morph` module, preserving the
402
+ focus and caret of focused inputs and reconciling `data-key` lists in place.
403
+ - **Single declarative event system.** `data-action` (click), `data-change`,
404
+ `data-input`, `data-keydown`, and `data-submit` are delegated once to the
405
+ component root and cleaned up on destroy.
406
+ - Configurable mount container via `createApp({ mountId })` (default `main-content`).
407
+
408
+ ### Fixed
409
+ - Router now navigates to the configured `fallback` route on a no-match, so the
410
+ 404 component actually renders.
411
+ - Router responds to `router:navigate` events from components.
412
+ - Todo example renders correctly (previously a blank page — it mounted into a
413
+ container the router never used).
414
+
415
+ ### Added
416
+ - DOM-morphing renderer (`src/core/dom-morph.js`).
417
+ - Routing example with route params (`examples/router-app/`).
418
+ - Test suite (Vitest + happy-dom) covering morph, components, router, event bus.
419
+ - Flat ESLint config (`eslint.config.js`) and CI workflow.
420
+
421
+ ## [1.0.0] - 2025-06-15
422
+
423
+ ### Added
424
+ - Initial release of Vanilla JS SPA Framework
425
+ - Component-based architecture with BaseComponent class
426
+ - Client-side routing with history API support
427
+ - Event-driven communication via EventBus
428
+ - Comprehensive error handling and logging system
429
+ - Build system for production deployment
430
+ - Framework debug utilities
431
+ - State management capabilities
432
+ - Form validation utilities
433
+ - SweetAlert integration for notifications
434
+ - Zero external dependencies
435
+ - Full ES module support
436
+ - TypeScript-friendly (JSDoc annotations)
437
+
438
+ ### Framework Features
439
+ - **ComponentManager** - Manages component lifecycle and registration
440
+ - **Router** - Handles client-side navigation and route protection
441
+ - **EventBus** - Pub/sub pattern for component communication
442
+ - **Logger** - Configurable logging system with levels
443
+ - **ErrorHandler** - Centralized error handling and reporting
444
+ - **Validator** - Input validation utilities
445
+ - **FrameworkDebug** - Development debugging tools
446
+
447
+ ### Examples
448
+ - Interactive counter demo
449
+ - Basic todo application example
450
+ - Component composition examples
451
+ - Routing demonstrations
452
+
453
+ ### Documentation
454
+ - Comprehensive README with examples
455
+ - Framework API documentation
456
+ - Getting started guide
457
+ - Best practices guide
458
+
459
+ ### Browser Support
460
+ - Modern browsers supporting ES2020+
461
+ - Chrome 80+, Firefox 72+, Safari 14+
462
+ - Edge 80+
463
+
464
+ ### Bundle Size
465
+ - Framework core: ~48 KB minified (~14.5 KB gzipped)
466
+ - Full demo bundle (with all utilities): ~56 KB minified
package/README.md ADDED
@@ -0,0 +1,198 @@
1
+ # 🔥 VanillaForge
2
+
3
+ **A small, zero-dependency JavaScript framework for building Single Page Applications with plain web standards.**
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![ES Modules](https://img.shields.io/badge/ES-Modules-blue.svg)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)
7
+ [![Tests](https://img.shields.io/badge/tests-vitest-success.svg)](#testing)
8
+
9
+ VanillaForge gives you components, client-side routing, and an event bus in a
10
+ few small ES modules — no dependencies and no required build step. It runs
11
+ straight from `src/` in the browser; the build is only for producing an
12
+ optimized bundle.
13
+
14
+ ## Why VanillaForge?
15
+
16
+ - **Zero runtime dependencies** — ships as plain ES modules.
17
+ - **Small** — the core is ~14.5 KB min+gzip (~48 KB minified).
18
+ - **Batteries-included** — icons, CSS/theming, alerts, self-hosted fonts, and a
19
+ shared reactive store, all built in. No Font Awesome, Bootstrap, SweetAlert, or
20
+ Google Fonts required — but you can still bring them in if you want.
21
+ - **Component composition** — embed child components directly inside parent
22
+ templates. Each child has isolated state, props, lifecycle, and event handling.
23
+ - **Plugin system** — every subsystem (icons, theme, alerts, fonts, store) is a
24
+ plugin you can install, replace, or skip.
25
+ - **Efficient updates** — re-renders are applied with a tiny DOM-morphing diff,
26
+ so only changed nodes are touched and focused inputs keep their cursor (see
27
+ [How rendering works](#how-rendering-works)).
28
+ - **Client-side routing** — history API, route params (`/users/:id`), and a
29
+ configurable fallback route.
30
+ - **Declarative events** — wire DOM events to methods with `data-*` attributes;
31
+ the framework handles delegation and cleanup.
32
+
33
+ ## Quick Start
34
+
35
+ ```bash
36
+ git clone https://github.com/Steve-GitCodex/vanillaforge.git
37
+ cd vanillaforge
38
+ npm install
39
+
40
+ # Run the demo (builds to dist/ and serves it)
41
+ npm run dev
42
+
43
+ # Or run an example directly (no build needed)
44
+ npm run example # Todo app
45
+ npm run example:router # Routing + params demo
46
+ ```
47
+
48
+ **Your first component:**
49
+
50
+ ```javascript
51
+ import { createApp, BaseComponent, iconsPlugin } from './src/framework.js';
52
+
53
+ class HelloWorld extends BaseComponent {
54
+ constructor(eventBus, props = {}) {
55
+ super(eventBus, props);
56
+ this.name = 'hello-world';
57
+ this.state = { count: 0 };
58
+ }
59
+
60
+ getTemplate() {
61
+ return `
62
+ <div class="hello">
63
+ <h1>Hello, VanillaForge!</h1>
64
+ <p>Clicked ${this.state.count} times.</p>
65
+ <button data-action="inc">
66
+ ${this.icon('plus', { size: 16 })} Click me
67
+ </button>
68
+ </div>
69
+ `;
70
+ }
71
+
72
+ getMethods() {
73
+ return { inc: () => this.setState({ count: this.state.count + 1 }) };
74
+ }
75
+ }
76
+
77
+ const app = createApp({ debug: true });
78
+ app.use(iconsPlugin); // built-in SVG icons
79
+ await app.initialize({ routes: { '/': HelloWorld } });
80
+ await app.start();
81
+ ```
82
+
83
+ The page needs a mount element (default id `main-content`, configurable via
84
+ `createApp({ mountId })`):
85
+
86
+ ```html
87
+ <div id="main-content"></div>
88
+ <script type="module" src="./app.js"></script>
89
+ ```
90
+
91
+ ## How rendering works
92
+
93
+ Calling `setState()` re-runs your `getTemplate()` and **morphs** the result onto
94
+ the live DOM instead of replacing `innerHTML`. The morph:
95
+
96
+ - patches only attributes/text/nodes that actually changed;
97
+ - preserves the focus and caret/selection of a focused input, so typing is never
98
+ interrupted by a re-render;
99
+ - reconciles lists by `data-key`, so reordering or removing an item reuses the
100
+ existing DOM nodes instead of rebuilding the list.
101
+
102
+ ```javascript
103
+ getTemplate() {
104
+ return `<ul>${this.state.items
105
+ .map((it) => `<li data-key="${it.id}">${it.label}</li>`)
106
+ .join('')}</ul>`;
107
+ }
108
+ ```
109
+
110
+ > Note: a full re-render still re-runs the whole template (then diffs it). Moving
111
+ > to fine-grained, signal-based updates is on the [roadmap](#roadmap).
112
+
113
+ ## Declarative events
114
+
115
+ Bind DOM events to `getMethods()` entries with attributes. Each attribute maps to
116
+ exactly one event so a handler fires once:
117
+
118
+ | Attribute | Fires on | Typical use |
119
+ | -------------- | --------- | --------------------------- |
120
+ | `data-action` | `click` | buttons, links |
121
+ | `data-change` | `change` | checkboxes, radios, selects |
122
+ | `data-input` | `input` | text inputs, textareas |
123
+ | `data-keydown` | `keydown` | keyboard shortcuts |
124
+ | `data-submit` | `submit` | forms |
125
+
126
+ Handlers receive `(event, matchedElement)`. Listeners are delegated to the
127
+ component's root element once and cleaned up automatically on destroy.
128
+
129
+ ## Examples
130
+
131
+ - [Todo App](examples/todo-app/) — local state, filtering, keyed list, and
132
+ focus-preserving input. Run with `npm run example`.
133
+ - [Routing demo](examples/router-app/) — a list view and a `/users/:id` detail
134
+ view driven by route params. Run with `npm run example:router`.
135
+
136
+ ## Testing
137
+
138
+ Tests run on [Vitest](https://vitest.dev) with [happy-dom](https://github.com/capricorn86/happy-dom)
139
+ (dev dependencies only — the framework itself stays dependency-free):
140
+
141
+ ```bash
142
+ npm test
143
+ ```
144
+
145
+ Coverage includes the DOM morph (focus/selection preservation, keyed lists), the
146
+ component lifecycle and event delegation, the router, the event bus, and both
147
+ examples.
148
+
149
+ ## Build
150
+
151
+ ```bash
152
+ npm run build # bundle src/app.js + CSS into dist/
153
+ NODE_ENV=production npm run build # minified bundle
154
+ ```
155
+
156
+ The build uses [esbuild](https://esbuild.github.io/) to bundle and tree-shake,
157
+ and copies/minifies discovered CSS. See [docs/build-system.md](docs/build-system.md).
158
+
159
+ ## Documentation
160
+
161
+ - [Components Guide](docs/components.md)
162
+ - [Component Composition](docs/composition.md)
163
+ - [Plugin System & Built-in Icons](docs/plugins.md)
164
+ - [Routing System](docs/router.md)
165
+ - [Event Bus](docs/event-bus.md)
166
+ - [API Reference](docs/API.md)
167
+ - [Build System](docs/build-system.md)
168
+ - [GitHub Pages](docs/github-pages.md)
169
+ - [Roadmap](docs/roadmap.md)
170
+
171
+ For maintainers returning after time away: see [DEVELOPMENT.md](DEVELOPMENT.md).
172
+
173
+ ## Browser Support
174
+
175
+ Modern browsers with ES2020+ support: Chrome 80+, Firefox 72+, Safari 14+, Edge 80+.
176
+
177
+ ## Roadmap
178
+
179
+ All five built-in plugins (icons, theme, alerts, fonts, store), component
180
+ composition, signals, route loaders, TypeScript types, and the scaffold CLI
181
+ are shipped. What's next:
182
+
183
+ - **npm publish** — stable `2.0.0` release to the npm registry.
184
+
185
+ Full details in [docs/roadmap.md](docs/roadmap.md).
186
+
187
+ ## Contributing
188
+
189
+ Issues and pull requests are welcome. Please run `npm test` and `npm run lint`
190
+ before opening a PR.
191
+
192
+ ## License
193
+
194
+ MIT — see [LICENSE](LICENSE).
195
+
196
+ ---
197
+
198
+ **Author:** Stephen Musyoka · [GitHub](https://github.com/Steve-GitCodex/vanillaforge) · [Issues](https://github.com/Steve-GitCodex/vanillaforge/issues)