domma-js 0.42.0 → 0.44.1

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
@@ -9,20 +9,51 @@ modern UI components in one cohesive package.
9
9
 
10
10
  ## Features
11
11
 
12
- - **DOM Manipulation** (`$`) - jQuery-compatible API with 90+ methods
13
- - **Utilities** (`_`) - 120+ Lodash-compatible utility functions with function composition
12
+ - **DOM Manipulation** (`$`) - jQuery-compatible API with 106 methods
13
+ - **Utilities** (`_`) - 202 Lodash-compatible utility functions with function composition
14
14
  - **Dates** (`D`) - Moment.js-style chainable date manipulation
15
- - **Models** (`M`) - Reactive data models with pub/sub events and two-way DOM binding
16
- - **Elements** (`E`) - 28 UI components (modals, tabs, carousels, navbars, slideovers, and more)
15
+ - **Models** (`M`) - Reactive models, dependency tracking, pub/sub events and declarative DOM bindings
16
+ - **Blueprints** (`B`) - One schema definition that drives models, forms and CRUD
17
+ - **Elements** (`E`) - 32 UI components (modals, tabs, carousels, navbars, context menus, slideovers, and more)
18
+ - **Effects** (`Domma.effects`) - 12 scripted animations (scribe, reveal, counter, ripple, strobe, and more)
17
19
  - **Tables** (`T`) - DataTable-like functionality (sort, filter, paginate, export to CSV/JSON)
18
20
  - **Forms** (`F`) - Blueprint-driven form generation with validation, wizards, and CRUD helpers
19
- - **Icons** (`I`) - 200+ SVG icons in 15 categories with auto-scan
21
+ - **Router** (`R`) - Client-side routing with view registration and middleware
22
+ - **Icons** (`I`) - 521 SVG icons in 18 categories with auto-scan
23
+ - **Flags** (`FL`) - Nation flags as inline SVG, in an opt-in bundle
20
24
  - **HTTP Client** (`H`) - Simple async HTTP requests with JSON handling
21
- - **Storage** (`S`) - localStorage wrapper with auto JSON serialization
22
- - **Themes** - 10+ built-in themes with light/dark variants and system detection
23
- - **Config Engine** - Declarative JSON-based behavior configuration with mutable API
25
+ - **Storage** (`S`) - localStorage wrapper with auto JSON serialisation
26
+ - **Auth** (`A`) - Token-based authentication with login, register and profile components
27
+ - **Components** - Define real Custom Elements with reactive state and fine-grained bindings
28
+ - **Themes** - 33 built-in themes across 13 light/dark families plus a six-theme Admin set
29
+ - **Config Engine** - Declarative JSON-based behaviour configuration with a mutable API
24
30
  - **CSS Features** - Utility classes (glow, shadows, elevation, fireworks, grid)
25
- - **Developer Tools** - Theme Roller, Page Roller, Editor, Print-to-PDF
31
+ - **Developer Tools** - Theme Roller, Page Roller, Schema Builder, Editor, Print-to-PDF
32
+
33
+ Everything above ships in one bundle with no runtime dependencies. Nothing uses `eval` or the `Function`
34
+ constructor, so Domma runs under a `script-src 'self'` Content Security Policy.
35
+
36
+ ## Ecosystem
37
+
38
+ Two pieces of Domma are now published as their own packages, so they can be used **without** Domma. This
39
+ repository is simply one consumer of each.
40
+
41
+ | Package | What it is | Where it lives |
42
+ |---------|-----------|----------------|
43
+ | [`domma-reactive`](https://www.npmjs.com/package/domma-reactive) | Dependency-tracked reactivity and fine-grained DOM bindings - the engine beneath `M.observable`, `M.computed` and `M.applyBindings` | Bundled into `domma.min.js`; [repo](https://github.com/pinpointzero73/domma-reactive) |
44
+ | [`domma-celebrate`](https://www.npmjs.com/package/domma-celebrate) | Eight seasonal celebration themes and their canvas engine, code-split so each theme loads only when it is in season | Copied into `dist/celebrate/` at build time; [repo](https://github.com/pinpointzero73/domma-celebrate) |
45
+
46
+ **`domma-reactive` has moved out.** The reactive core was extracted into a standalone MIT-licensed package
47
+ and is now consumed from the npm registry rather than lived in this repository. Nothing changes for Domma
48
+ users: `M.observable()`, `M.computed()`, `M.effect()` and `M.applyBindings()` behave exactly as before, and
49
+ the package is bundled into `domma.min.js` by rollup. What has changed is that the reactivity layer is now
50
+ usable on its own - about 20 KB gzipped, no dependencies, no build step - in projects that want bindings
51
+ without the rest of the framework.
52
+
53
+ ```bash
54
+ npm install domma-reactive # reactivity and bindings, standalone
55
+ npm install domma-celebrate # seasonal celebrations, standalone
56
+ ```
26
57
 
27
58
  ## Installation
28
59
 
@@ -33,26 +64,42 @@ Get a complete project structure with development server in seconds:
33
64
  ```bash
34
65
  npm init -y
35
66
  npm install domma-js
36
- npx domma init # Creates project structure (prompts to start server)
67
+ npx domma-js init # Creates project structure (prompts to start server)
37
68
  ```
38
69
 
39
- **Or manually start the server:**
70
+ `init` scaffolds a **Single Page Application** by default. Pass `--mpa` for a traditional multi-page site,
71
+ or `--quick` to skip the prompts.
72
+
40
73
  ```bash
41
- npm start # Starts on port 3000
42
- npm run serve # Same as npm start
43
- npm run serve:8080 # Custom port
74
+ npx domma-js init # Interactive - choose SPA or MPA (SPA is the default)
75
+ npx domma-js init --spa # Explicit SPA
76
+ npx domma-js init --mpa # Multi-Page Application
77
+ npx domma-js init --quick # Accept every default
44
78
  ```
45
79
 
46
80
  This creates:
47
81
 
48
- - ✅ Complete project structure with 5 sample pages
82
+ - ✅ Complete project structure with sample pages or views
49
83
  - ✅ JSON configuration (`domma.config.json`)
50
84
  - ✅ Navbar and footer (configured via JSON)
51
- - ✅ Theme system with 16+ themes
85
+ - ✅ Theme system with all 33 themes
52
86
  - ✅ npm scripts (`start`, `serve`) in package.json
53
87
  - ✅ Development server with live reload
54
88
  - ✅ All features ready to use
55
89
 
90
+ ### Growing a Project
91
+
92
+ The CLI scaffolds new pages and views for you, wiring up paths and routes:
93
+
94
+ ```bash
95
+ npx domma-js add page admin # MPA: creates admin/
96
+ npx domma-js add page pages/dashboard # MPA: one level deep
97
+ npx domma-js add view settings # SPA: creates the view and its route
98
+ npx domma-js setup-ai # Add AI assistance files to an existing project
99
+ ```
100
+
101
+ Page paths are resolved automatically from folder depth, so a page two levels down still finds its assets.
102
+
56
103
  ### Development Server
57
104
 
58
105
  Start the built-in development server with live reload:
@@ -66,8 +113,8 @@ npm run serve:3096 # Explicit port 3096
66
113
 
67
114
  **Using CLI directly:**
68
115
  ```bash
69
- npx domma serve # Start server (auto-detects MPA/SPA)
70
- npx domma serve --port 3096 # Custom port
116
+ npx domma-js serve # Start server (auto-detects MPA/SPA)
117
+ npx domma-js serve --port 8080 # Custom port
71
118
  ```
72
119
 
73
120
  The server auto-detects your project type (MPA/SPA) and serves from the correct directory with live reload enabled.
@@ -76,7 +123,7 @@ The server auto-detects your project type (MPA/SPA) and serves from the correct
76
123
  ```bash
77
124
  # 1. Create project
78
125
  npm install domma-js
79
- npx domma init
126
+ npx domma-js init
80
127
 
81
128
  # 2. Start developing (auto-starts server or run manually)
82
129
  npm start # Opens http://localhost:3096
@@ -152,16 +199,16 @@ For quick prototyping without npm:
152
199
  <script src="https://cdn.jsdelivr.net/npm/domma-js@latest/public/dist/domma.min.js"></script>
153
200
  ```
154
201
 
155
- > **Tip:** Replace `@latest` with a specific version (e.g., `@0.9.18`) for production to ensure stability.
202
+ > **Tip:** Replace `@latest` with a specific version (e.g., `@0.43.0`) for production to ensure stability.
156
203
 
157
204
  ## Live Demo
158
205
 
159
- 🚀 **[Try Domma Online](https://dommajs.org/)** - Interactive showcase with 40+ examples
206
+ 🚀 **[Try Domma Online](https://dommajs.org/)** - Interactive showcase with 87 example pages
160
207
 
161
208
  Explore all features:
162
209
  - **[Showcase](https://dommajs.org/showcase/)** - Component examples and tutorials
163
210
  - **[MiniApps](https://dommajs.org/miniapps/)** - Real-world applications
164
- - **[Download](https://dommajs.org/showcase/download/)** - Preset bundles and archives
211
+ - **[Download](https://dommajs.org/download/)** - Preset bundles, archives and the Kickstart Builder
165
212
 
166
213
  ## Short Aliases
167
214
 
@@ -169,7 +216,7 @@ Explore all features:
169
216
  |------------|-------------------|-------|------------------------------------------|
170
217
  | DOM | `Domma()` | `$` | jQuery-style DOM manipulation |
171
218
  | Utils | `Domma.utils` | `_` | Lodash-style utilities |
172
- | Models | `Domma.models` | `M` | Reactive models & pub/sub |
219
+ | Models | `Domma.models` | `M` | Reactive models, bindings & pub/sub |
173
220
  | Blueprints | Blueprint Methods | `B` | Blueprint composition (extend, pick, omit) |
174
221
  | Dates | `Domma.dates` | `D` | Date manipulation |
175
222
  | Storage | `Domma.storage` | `S` | localStorage wrapper |
@@ -179,28 +226,34 @@ Explore all features:
179
226
  | Elements | `Domma.elements` | `E` | UI components |
180
227
  | Icons | `Domma.icons` | `I` | SVG icon system |
181
228
  | Tables | `Domma.tables` | `T` | DataTable functionality |
229
+ | Router | `Domma.router` | `R` | Client-side router |
230
+ | Flags | `Domma.flags` | `FL` | Nation flags (opt-in bundle) |
231
+
232
+ `Domma.effects`, `Domma.theme`, `Domma.sanitize` and `Domma.components` have no single-letter alias.
182
233
 
183
234
  ## Bundle Options
184
235
 
185
- Choose the right bundle for your needs:
236
+ Choose the right bundle for your needs. Gzipped is the size that reaches the browser.
237
+
238
+ | Bundle | Minified | Gzipped | Includes |
239
+ |--------|---------:|--------:|----------|
240
+ | **full** | 628 KB | 148 KB | All modules and components |
241
+ | **essentials** | 518 KB | 120 KB | Core + models, elements, config |
242
+ | **data-focused** | 203 KB | 45 KB | Core + models, tables, http, storage |
243
+ | **minimal** | 175 KB | 37 KB | DOM, utils, dates - zero UI |
244
+ | **no-ui** | 102 KB | 32 KB | Core utilities only (DOM + utils) |
186
245
 
187
- | Bundle | Size | Includes |
188
- |--------|------|----------|
189
- | **full** | 390KB | All modules and components |
190
- | **minimal** | 163KB | DOM, utils, dates - zero UI |
191
- | **essentials** | 328KB | Core + models, elements, config |
192
- | **data-focused** | 190KB | Core + models, tables, http, storage |
193
- | **no-ui** | 41KB | Core utilities only (DOM + utils) |
246
+ Two further bundles load alongside any of the above:
247
+
248
+ | Bundle | Minified | Gzipped | Includes |
249
+ |--------|---------:|--------:|----------|
250
+ | **tools** | 228 KB | 52 KB | Theme Roller, Page Roller, Schema Builder, Editor, Print-to-PDF |
251
+ | **flags** | 20 KB | 6 KB | Nation flags (`FL`) |
194
252
 
195
253
  ```html
196
254
  <!-- Use specific bundles via CDN -->
197
- <!-- Minimal bundle (163KB) -->
198
255
  <script src="https://dommajs.org/dist/domma-minimal.min.js"></script>
199
-
200
- <!-- Essentials bundle (328KB) -->
201
256
  <script src="https://dommajs.org/dist/domma-essentials.min.js"></script>
202
-
203
- <!-- Data-focused bundle (190KB) -->
204
257
  <script src="https://dommajs.org/dist/domma-data-focused.min.js"></script>
205
258
 
206
259
  <!-- Via unpkg -->
@@ -235,11 +288,11 @@ M.on('cart:add', (item) => updateCart(item));
235
288
  M.emit('cart:add', {id: 1, name: 'Widget'});
236
289
 
237
290
  // UI Components
238
- const modal = Domma.elements.modal('#my-modal', {backdrop: true});
291
+ const modal = E.modal('#my-modal', {backdrop: true});
239
292
  modal.open();
240
293
 
241
294
  // Interactive Tables
242
- const table = Domma.tables.create('#users', {
295
+ const table = T.create('#users', {
243
296
  data: usersArray,
244
297
  columns: [
245
298
  {key: 'name', title: 'Name', sortable: true},
@@ -250,6 +303,122 @@ const table = Domma.tables.create('#users', {
250
303
  });
251
304
  ```
252
305
 
306
+ ## Reactivity & Bindings
307
+
308
+ The reactive layer - published standalone as [`domma-reactive`](https://www.npmjs.com/package/domma-reactive)
309
+ and bundled here - lets you write down a relationship once and have Domma maintain it.
310
+
311
+ **Observables and computed values** work out their own dependencies at runtime:
312
+
313
+ ```javascript
314
+ const count = M.observable(0);
315
+ const doubled = M.computed(() => count.value * 2);
316
+
317
+ doubled.get(); // 0
318
+ count.value = 5;
319
+ doubled.get(); // 10
320
+
321
+ count.peek(); // read without subscribing
322
+
323
+ M.effect(() => console.log('count is', count.value)); // re-runs on every write
324
+ ```
325
+
326
+ Writes are batched and flushed on the next microtask, so ten assignments cause one update.
327
+ `M.flush()` forces it synchronously; `M.untracked(fn)` reads without creating a dependency.
328
+
329
+ **Declarative bindings** activate markup that already exists - they never rewrite your page:
330
+
331
+ ```html
332
+ <div id="app">
333
+ <h1 data-bind-text="title">Rendered by the server</h1>
334
+
335
+ <input data-model="query" placeholder="Search…">
336
+ <p data-if="query">Searching for <span data-bind-text="query"></span></p>
337
+
338
+ <ul data-each="rows key=id">
339
+ <li data-bind-text="name">template row</li>
340
+ </ul>
341
+
342
+ <button data-on-click="clear">Clear</button>
343
+ </div>
344
+ ```
345
+
346
+ ```javascript
347
+ const model = M.create({
348
+ title: {type: M.types.string},
349
+ query: {type: M.types.string},
350
+ rows: {type: M.types.array}
351
+ }, {
352
+ title: 'Live',
353
+ query: '',
354
+ rows: [{id: 1, name: 'Ada'}, {id: 2, name: 'Grace'}]
355
+ });
356
+
357
+ M.applyBindings(model, '#app', {
358
+ methods: {
359
+ clear() { model.set('query', ''); }
360
+ }
361
+ });
362
+ ```
363
+
364
+ The binding vocabulary is `data-bind-text`, `data-bind-class`, `data-bind-style`, `data-bind-style-<prop>`,
365
+ `data-bind-<prop>`, `data-model`, `data-on-<event>`, `data-if`, `data-each`, `data-options` and
366
+ `data-focus`. `data-each` reconciles by key, so deleting a row leaves every other row's DOM node, focus and
367
+ scroll position intact. Extend the vocabulary with `M.registerBinding()` and `M.registerHelper()`.
368
+
369
+ Expressions are parsed by hand rather than compiled with the `Function` constructor, so bindings work under
370
+ a `script-src 'self'` Content Security Policy. A binding whose expression will not parse logs one warning
371
+ naming the expression and is skipped; the rest of the page keeps working.
372
+
373
+ See [docs/Reactivity.md](./docs/Reactivity.md) and [docs/Bindings.md](./docs/Bindings.md).
374
+
375
+ ## Components
376
+
377
+ Define a real Custom Element with reactive state, props, computed values and lifecycle hooks. The same
378
+ bindings work inside a component template.
379
+
380
+ ```javascript
381
+ Domma.component('user-card', {
382
+ templateUrl: 'components/user-card/template.html',
383
+
384
+ props: {
385
+ userId: {type: M.types.number, required: true},
386
+ label: {type: M.types.string, default: 'User'}
387
+ },
388
+
389
+ data() {
390
+ return {name: '', email: '', loading: true};
391
+ },
392
+
393
+ computed: {
394
+ initials() {
395
+ return this.data.name.split(' ').map(n => n[0]).join('').toUpperCase();
396
+ }
397
+ },
398
+
399
+ methods: {
400
+ async fetchUser() {
401
+ const user = await H.get(`/api/users/${this.props.userId}`);
402
+ this.set({ name: user.name, email: user.email, loading: false });
403
+ }
404
+ },
405
+
406
+ onMount() { this.fetchUser(); },
407
+ onPropsChanged(name) { if (name === 'userId') this.fetchUser(); },
408
+
409
+ // Scoped styles, injected into the Shadow DOM
410
+ style: `.card { padding: var(--dm-spacing-md, 1rem); border-radius: 8px; }`
411
+ });
412
+ ```
413
+
414
+ ```html
415
+ <user-card user-id="42" label="Account owner"></user-card>
416
+ ```
417
+
418
+ Tag names must contain a hyphen; Domma prefixes `domma-` automatically if yours does not. Lifecycle hooks
419
+ are `onBeforeMount`, `onMount`, `onUpdated`, `onPropsChanged`, `onBeforeUnmount` and `onUnmount`.
420
+ See [docs/Components.md](./docs/Components.md).
421
+
253
422
  ## CSS Features
254
423
 
255
424
  Domma includes comprehensive utility classes for rapid UI development.
@@ -289,12 +458,16 @@ Domma includes comprehensive utility classes for rapid UI development.
289
458
  </div>
290
459
  ```
291
460
 
461
+ Display utilities use the Tailwind spellings (`.block`, `.flex`, `.grid`, `.hidden`). There are no
462
+ Bootstrap-style `.d-*` variants.
463
+
292
464
  ## Themes
293
465
 
294
- 10+ built-in themes with light/dark variants and automatic system detection.
466
+ 33 built-in themes: 13 families with light and dark variants, a bare `core-light`, and a six-theme Admin
467
+ set that pairs two finishes with three accents.
295
468
 
296
469
  ```javascript
297
- // Initialize with theme
470
+ // Initialise with theme
298
471
  Domma.theme.init({ theme: 'ocean-dark' });
299
472
 
300
473
  // Change theme dynamically
@@ -305,58 +478,78 @@ Domma.theme.toggle();
305
478
 
306
479
  // Auto-detect system preference
307
480
  Domma.theme.init({ autoDetect: true });
481
+
482
+ // List everything available
483
+ Domma.theme.listThemes(); // also listBases() and listVariants()
308
484
  ```
309
485
 
310
- **Available Themes:**
311
- - charcoal (light/dark)
312
- - ocean (light/dark)
313
- - forest (light/dark)
314
- - sunset (light/dark)
315
- - lavender (light/dark)
316
- - crimson (light/dark)
317
- - slate (light/dark)
318
- - amber (light/dark)
319
- - teal (light/dark)
320
- - rose (light/dark)
486
+ **Light/dark families:**
487
+ charcoal · ocean · forest · sunset · royal · lemon · silver · mint · dreamy · grayve · unicorn ·
488
+ christmas · wedding
489
+
490
+ **Admin family** (standalone, no light/dark variant):
491
+ `admin-smooth-steel` · `admin-smooth-indigo` · `admin-smooth-teal` ·
492
+ `admin-sharp-steel` · `admin-sharp-indigo` · `admin-sharp-teal`
493
+
494
+ The default is `charcoal-dark`. Pass `{disabled: true}` to `theme.init()` (or `noStyles: true` to
495
+ `$.setup()`) to turn Domma theming off entirely and bring your own stylesheet.
321
496
 
322
497
  ## Developer Tools
323
498
 
324
- Domma includes powerful developer tools in a separate bundle.
499
+ Domma includes developer tools in a separate bundle. Load it **after** the core bundle; each tool is then
500
+ available as an `Domma.elements` factory taking a host selector.
325
501
 
326
502
  ```html
327
- <!-- Load tools bundle via CDN -->
503
+ <script src="https://dommajs.org/dist/domma.min.js"></script>
328
504
  <script src="https://dommajs.org/dist/domma-tools.min.js"></script>
505
+ ```
329
506
 
330
- <!-- Or via unpkg -->
331
- <script src="https://unpkg.com/domma-js@latest/public/dist/domma-tools.min.js"></script>
507
+ **Theme Roller** - visual theme customisation with live preview:
508
+ ```javascript
509
+ const roller = E.themeRoller('#theme-roller-container', {
510
+ baseTheme: 'charcoal-light',
511
+ showPresets: true,
512
+ livePreview: true,
513
+ onChange: (variable, value) => console.log(variable, value)
514
+ });
332
515
  ```
333
516
 
334
- **Theme Roller** - Visual theme customization tool:
517
+ **Page Roller** - drag-and-drop page builder:
335
518
  ```javascript
336
- Domma.themeRoller.open();
519
+ const builder = E.pageRoller('#page-roller-container');
337
520
  ```
338
521
 
339
- **Page Roller** - Drag-and-drop page builder:
522
+ **Schema Builder** - visual Blueprint designer:
340
523
  ```javascript
341
- Domma.pageRoller.init();
524
+ const schema = E.schemaBuilder('#schema-builder-container');
342
525
  ```
343
526
 
344
- **Editor** - Rich content editor with export:
527
+ **Editor** - text, rich-text and code modes with autosave:
345
528
  ```javascript
346
- Domma.editor.create('#editor', {
347
- toolbar: ['bold', 'italic', 'heading', 'list'],
348
- onSave: (content) => console.log(content)
529
+ E.editor('#editor', {
530
+ mode: 'rich', // 'text' | 'rich' | 'code'
531
+ toolbar: [['bold', 'italic'], ['link', 'image']],
532
+ imagePaste: true,
533
+ autosave: true,
534
+ storage: 'my-notes'
349
535
  });
350
536
  ```
351
537
 
352
- **Print-to-PDF** - Export any element to PDF:
538
+ **Print-to-PDF** - export any element:
353
539
  ```javascript
354
- Domma.printToPDF('#content', { filename: 'export.pdf' });
540
+ const printer = E.printToPDF('#content', {
541
+ pageSize: 'A4',
542
+ orientation: 'portrait',
543
+ margins: 'normal'
544
+ });
545
+ printer.print();
355
546
  ```
356
547
 
548
+ The bundle also registers `window.DommaTools` with the same five factories.
549
+
357
550
  ## Config Engine
358
551
 
359
- Define behavior declaratively with JSON configuration.
552
+ Define behaviour declaratively with JSON configuration.
360
553
 
361
554
  **Basic Setup:**
362
555
  ```javascript
@@ -381,6 +574,9 @@ $.setup({
381
574
  });
382
575
  ```
383
576
 
577
+ `$.setup()` also accepts top-level `theme`, `autoDetectTheme`, `persistTheme`, `scanIcons`, `cloak` and
578
+ `noStyles` keys.
579
+
384
580
  **Mutable Configuration API:**
385
581
  ```javascript
386
582
  // Update existing configuration
@@ -390,22 +586,28 @@ $.update('#my-modal', {
390
586
 
391
587
  // Retrieve configuration
392
588
  const config = $.config('#my-modal');
393
- console.log(config);
589
+
590
+ // Reach the live component instance
591
+ const modal = $.getComponent('#my-modal');
592
+ modal.open();
394
593
 
395
594
  // Reset/destroy configuration
396
595
  $.reset('#my-modal'); // Removes component and unbinds events
397
596
  ```
398
597
 
399
- **Supported Components (16 total):**
400
- - card, modal, tabs, accordion, tooltip, carousel, dropdown
401
- - badge, backToTop, buttonGroup, loader, breadcrumbs, navbar
402
- - notification, timer, alarm
598
+ **Recognised component types (29):**
599
+ - Overlays: modal, dropdown, contextMenu, cookieConsent, notification
600
+ - Navigation: tabs, navbar, sidebar, footer, breadcrumbs, backToTop
601
+ - Content: card, accordion, carousel, listGroup, tooltip
602
+ - Indicators: badge, numberBadge, loader, timer, alarm
603
+ - Input: form, buttonGroup, autocomplete, pillbox, signature
604
+ - Effects: breathe, pulse, scribe
403
605
 
404
606
  ## Namespaces
405
607
 
406
608
  ### DOM (`$` or `Domma`)
407
609
 
408
- jQuery-compatible DOM manipulation with 90+ methods.
610
+ jQuery-compatible DOM manipulation with 106 methods.
409
611
 
410
612
  ```javascript
411
613
  // Selecting & traversing
@@ -425,7 +627,7 @@ $('#box').fadeIn(400).slideUp(300);
425
627
 
426
628
  ### Utils (`_` or `Domma.utils`)
427
629
 
428
- 120+ Lodash-compatible utility functions.
630
+ 202 Lodash-compatible utility functions.
429
631
 
430
632
  ```javascript
431
633
  // Arrays
@@ -452,6 +654,9 @@ _.memoize(expensive);
452
654
  _.camelCase('hello world'); // 'helloWorld'
453
655
  _.kebabCase('helloWorld'); // 'hello-world'
454
656
  _.truncate(text, { length: 50 });
657
+
658
+ // Templates (Mustache-style)
659
+ _.render('Hello {{name}}', { name: 'Ada' });
455
660
  ```
456
661
 
457
662
  ### Dates (`D` or `Domma.dates`)
@@ -482,15 +687,41 @@ D('2025-01-01').isBefore('2025-12-31');
482
687
  D().diff(otherDate, 'days');
483
688
  ```
484
689
 
690
+ ### Blueprints (`B`)
691
+
692
+ One schema definition, used everywhere: models, forms and CRUD all read the same blueprint.
693
+
694
+ ```javascript
695
+ const person = {
696
+ name: { type: M.types.string, required: true },
697
+ email: { type: M.types.string, pattern: /@/ },
698
+ age: { type: M.types.number, min: 0, max: 150 }
699
+ };
700
+
701
+ const employee = B.extend(person, {
702
+ department: { type: M.types.string, required: true }
703
+ });
704
+
705
+ const publicView = B.pick(employee, ['name', 'department']);
706
+ const withoutAge = B.omit(employee, ['age']);
707
+
708
+ M.create(employee); // a reactive model
709
+ F.render('#form', employee, {}); // a validated form
710
+ F.crud({ schema: employee, endpoint: '/api/staff' }); // the whole CRUD screen
711
+ ```
712
+
713
+ See [docs/Blueprints.md](./docs/Blueprints.md).
714
+
485
715
  ### Models (`M` or `Domma.models`)
486
716
 
487
- Reactive data models with pub/sub events.
717
+ Reactive data models, dependency tracking, pub/sub and DOM bindings.
488
718
 
489
719
  ```javascript
490
- // Pub/Sub
720
+ // Pub/Sub (subscribe/publish are the long forms of on/emit)
491
721
  M.on('user:login', (data) => console.log(data));
492
722
  M.emit('user:login', { username: 'alice' });
493
723
  M.off('user:login', handler);
724
+ M.once('app:ready', init);
494
725
 
495
726
  // Reactive Models
496
727
  const user = M.create({
@@ -503,25 +734,39 @@ user.set('name', 'Bob');
503
734
  user.onChange((field, newVal, oldVal) => {});
504
735
  user.validate();
505
736
 
506
- // DOM Binding
737
+ // Persistence
738
+ user.save();
739
+ user.load();
740
+
741
+ // Shared stores
742
+ M.store('settings', { theme: 'dark' });
743
+ M.getStore('settings');
744
+
745
+ // DOM Binding - one field, one element
507
746
  M.bind(user, 'name', '#name-input', { twoWay: true });
508
747
  M.bind(user, 'name', '#display', { format: v => `Hello, ${v}!` });
748
+
749
+ // Declarative bindings - whole subtrees
750
+ M.applyBindings(user, '#app');
509
751
  ```
510
752
 
753
+ See [Reactivity & Bindings](#reactivity--bindings) above for observables, computeds and `data-bind-*`.
754
+
511
755
  ### Elements (`E` or `Domma.elements`)
512
756
 
513
- 28 production-ready UI components with JavaScript interactivity.
757
+ 32 production-ready UI components.
514
758
 
515
759
  **Dialogs & Overlays:**
516
760
  - `modal()` - Modal dialogs with backdrop
517
- - `dialog` - Promise-based alert/confirm/prompt
518
- - `toast()` - Toast notifications (static method)
761
+ - `alert()` / `confirm()` / `prompt()` - Promise-based dialogs
762
+ - `toast()` - Toast notifications
519
763
  - `slideover()` - Panel overlays from screen edges
520
764
  - `dropdown()` - Dropdown menus
765
+ - `contextMenu()` - Right-click menus, delegated and nestable
521
766
 
522
767
  **Navigation:**
523
768
  - `tabs()` - Tabbed navigation
524
- - `navbar()` - Responsive navigation bar
769
+ - `navbar()` - Responsive navigation bar with recursive multi-level dropdowns
525
770
  - `sidebar()` - Sidebar with unlimited nesting
526
771
  - `breadcrumbs()` - Navigation breadcrumbs
527
772
  - `backToTop()` - Scroll-to-top button
@@ -529,7 +774,8 @@ M.bind(user, 'name', '#display', { format: v => `Hello, ${v}!` });
529
774
  **Content Display:**
530
775
  - `card()` - Cards with hover and collapsible support
531
776
  - `accordion()` - Expandable/collapsible sections
532
- - `carousel()` - Image/content carousels
777
+ - `carousel()` - Carousels with slide, fade and crossfade transitions
778
+ - `listGroup()` - Selectable lists with keyboard navigation
533
779
  - `hero` - Hero sections (CSS-only)
534
780
  - `footer()` - Footer with 3 layout modes
535
781
 
@@ -537,17 +783,20 @@ M.bind(user, 'name', '#display', { format: v => `Hello, ${v}!` });
537
783
  - `autocomplete()` - Input with suggestions
538
784
  - `pillbox()` - Multi-select tag input
539
785
  - `buttonGroup()` - Radio/checkbox button groups
786
+ - `chooser()` - Card or chip single/multi-select with theme-aware accents
787
+ - `signature()` - Canvas signature pad with undo/redo and PNG/SVG export
540
788
 
541
789
  **Feedback & Indicators:**
542
790
  - `loader()` - Loading indicators (spinner, dots, pulse, bars)
543
- - `badge()` - Badge/notification indicators
791
+ - `badge()` - Badge indicators
792
+ - `numberBadge()` - Notification counters with dot mode and pulse
544
793
  - `tooltip()` - Hover tooltips
545
794
  - `notification()` - Desktop notifications
546
795
  - `cookieConsent()` - Cookie consent banner
547
796
 
548
- **Data & Visualization:**
797
+ **Data & Time:**
549
798
  - `treeView()` - Hierarchical tree display
550
- - `progression()` - Timeline/roadmap component
799
+ - `progression()` - Unified timeline/roadmap component
551
800
  - `timer()` - Countdown timer
552
801
  - `alarm()` - Scheduled alerts
553
802
 
@@ -563,13 +812,21 @@ const tabs = E.tabs('#product-tabs', {
563
812
 
564
813
  // Autocomplete with async data
565
814
  E.autocomplete('#search', {
566
- dataSource: async (query) => {
567
- const res = await fetch(`/api/search?q=${query}`);
568
- return res.json();
569
- },
815
+ dataSource: async (query) => H.get(`/api/search?q=${query}`),
570
816
  onSelect: (item) => console.log(item)
571
817
  });
572
818
 
819
+ // Right-click menu, bound to a container and delegated to its rows
820
+ E.contextMenu('#invoice-table', {
821
+ match: 'tr[data-id]',
822
+ items: (row) => [
823
+ { label: 'Edit', icon: 'edit', action: () => edit(row.dataset.id) },
824
+ { label: 'Delete', icon: 'trash', danger: true },
825
+ { type: 'divider' },
826
+ { label: 'Export', icon: 'download', submenu: exportFormats }
827
+ ]
828
+ });
829
+
573
830
  // Sidebar with nesting
574
831
  E.sidebar('#main-nav', {
575
832
  mobileBreakpoint: 768,
@@ -581,12 +838,60 @@ const confirmed = await E.confirm('Delete this item?');
581
838
  if (confirmed) deleteItem();
582
839
  ```
583
840
 
584
- ### Tables (`Domma.tables`)
841
+ > `timeline()` still works but is deprecated - use `progression({ mode: 'timeline' })`.
842
+
843
+ ### Effects (`Domma.effects`)
844
+
845
+ 12 scripted animations. Every effect honours `prefers-reduced-motion` and returns a control object with
846
+ `pause()`, `resume()`, `stop()`, `restart()` and `destroy()`.
847
+
848
+ | Effect | Does |
849
+ |--------|------|
850
+ | `scribe()` | Types text by character, word or sentence, with undo and looping |
851
+ | `reveal()` | Scroll-triggered entrance animations via IntersectionObserver |
852
+ | `counter()` | Animated number counting with easing and scroll trigger |
853
+ | `scramble()` | Cipher/decode text reveal in four orders |
854
+ | `ripple()` | Material-style click ripple |
855
+ | `shake()` | Attention/error shake |
856
+ | `pulse()` | Pulsing scale |
857
+ | `breathe()` | Sinusoidal floating |
858
+ | `twinkle()` | Sparkle overlay |
859
+ | `tickerTape()` | Canvas ticker-tape parade, continuous or one-shot burst |
860
+ | `butterflies()` | Canvas butterflies that wander, rise and flap |
861
+ | `strobe()` | Canvas strobe lighting with six presets |
862
+
863
+ ```javascript
864
+ Domma.effects.scribe('#headline', {
865
+ mode: 'word', // 'typewriter' | 'word' | 'sentence'
866
+ speed: 50,
867
+ loop: true,
868
+ actions: [
869
+ { render: 'Hello', effect: 'bounce' },
870
+ { wait: '2s' },
871
+ { undoRender: 'all' },
872
+ { render: 'Welcome to Domma', effect: 'fade' }
873
+ ]
874
+ });
875
+
876
+ Domma.effects.counter('#revenue', {
877
+ to: 148320,
878
+ prefix: '£',
879
+ separator: ',',
880
+ trigger: 'scroll' // 'immediate' | 'scroll'
881
+ });
882
+
883
+ const party = Domma.effects.tickerTape(null, { palette: 'theme', burst: true });
884
+ ```
885
+
886
+ Canvas effects accept a container selector, or `null` for a full-page overlay. `strobe()` warns above 5 Hz
887
+ and disables itself under `prefers-reduced-motion`.
888
+
889
+ ### Tables (`T` or `Domma.tables`)
585
890
 
586
891
  DataTable-like functionality.
587
892
 
588
893
  ```javascript
589
- const table = Domma.tables.create('#users', {
894
+ const table = T.create('#users', {
590
895
  data: usersArray,
591
896
  columns: [
592
897
  { key: 'name', title: 'Name', sortable: true },
@@ -620,46 +925,108 @@ table.toJSON();
620
925
 
621
926
  Blueprint-driven form generation with validation, wizards, and CRUD helpers.
622
927
 
928
+ A form is built from a blueprint and some initial data, then rendered where you want it.
929
+
623
930
  ```javascript
624
- // Blueprint-driven form
625
- const form = F.create('#user-form', {
626
- fields: [
627
- { name: 'name', type: 'string', label: 'Full Name', required: true },
628
- { name: 'email', type: 'email', label: 'Email', required: true },
629
- { name: 'age', type: 'number', label: 'Age', min: 18, max: 120 },
630
- { name: 'role', type: 'select', label: 'Role', options: ['Admin', 'User'] }
631
- ],
931
+ const userBlueprint = {
932
+ name: { type: 'string', label: 'Full Name', required: true },
933
+ email: { type: 'email', label: 'Email', required: true },
934
+ age: { type: 'number', label: 'Age', min: 18, max: 120 },
935
+ role: { type: 'select', label: 'Role', options: ['Admin', 'User'] }
936
+ };
937
+
938
+ // Build, then render
939
+ const form = F.create(userBlueprint, initialData, {
632
940
  layout: 'grid', // 'stacked', 'inline', or 'grid'
633
- onSubmit: (data) => console.log(data)
941
+ onSubmit: (data, instance) => console.log(data)
942
+ });
943
+ form.renderTo('#user-form');
944
+
945
+ // Or do both in one call
946
+ F.render('#user-form', userBlueprint, initialData, { layout: 'grid' });
947
+
948
+ // Form in a modal, with save/error handling
949
+ F.modal(userBlueprint, initialData, {
950
+ onSave: async (data) => H.post('/api/users', data),
951
+ onError: (err) => E.toast(err.message, { type: 'danger' })
634
952
  });
635
953
 
636
954
  // Multi-step wizard
637
- const wizard = F.wizard('#registration', {
638
- steps: [
639
- { title: 'Account', fields: [/*...*/] },
640
- { title: 'Profile', fields: [/*...*/] },
641
- { title: 'Confirm', fields: [/*...*/] }
642
- ],
955
+ F.wizard('#registration', {
956
+ schema: {
957
+ steps: [
958
+ { title: 'Account', fields: { email: {...}, password: {...} } },
959
+ { title: 'Profile', fields: { name: {...} } }
960
+ ]
961
+ },
962
+ data: {},
643
963
  onComplete: (data) => saveUser(data)
644
964
  });
645
965
 
646
- // CRUD helper
966
+ // CRUD helper - form, table and API wired together
647
967
  const crud = F.crud({
648
- apiUrl: '/api/users',
649
- fields: blueprint,
650
- table: '#users-table'
968
+ schema: userBlueprint,
969
+ endpoint: '/api/users',
970
+ tableSelector: '#users-table',
971
+ title: 'Manage Users',
972
+ primaryKey: 'id',
973
+ displayField: 'name'
651
974
  });
975
+ await crud.init();
652
976
  ```
653
977
 
654
- ### Icons (`I` or `Domma.icons`)
978
+ ### Router (`R` or `Domma.router`)
655
979
 
656
- 200+ SVG icons in 15 categories with declarative and imperative APIs.
980
+ Hash-based client-side routing for single-page applications - the mode `npx domma-js init` scaffolds by
981
+ default. Views render into one container; navigation links are ordinary `<a href="#/about">` anchors.
657
982
 
658
983
  ```javascript
659
- // Declarative (auto-scan on load)
984
+ R.init({
985
+ container: '#app',
986
+ views: {
987
+ home: '<h1>Home</h1>',
988
+ about: { template: '<h1>About</h1>', onMount: ($el) => {} },
989
+ user: async (params) => `<h1>User ${params.id}</h1>`
990
+ },
991
+ routes: [
992
+ { path: '/', view: 'home', title: 'Home' },
993
+ { path: '/user/:id', view: 'user', title: 'User Profile',
994
+ onEnter: async (params) => loadUser(params.id) }
995
+ ],
996
+ default: '/',
997
+ notFound: '404',
998
+ transitions: { enter: 'fadeIn', leave: 'fadeOut', duration: 200 }
999
+ });
1000
+
1001
+ // Register more later
1002
+ R.view('settings', { templateUrl: 'views/settings.html' });
1003
+ R.route({ path: '/settings', view: 'settings' });
1004
+
1005
+ // Middleware - runs before every navigation
1006
+ R.use((to, from, next) => {
1007
+ if (to.meta?.requiresAuth && !A.isAuthenticated()) R.navigate('/login');
1008
+ else next();
1009
+ });
1010
+
1011
+ // Navigate
1012
+ R.navigate('/user/42');
1013
+ R.navigate('/login', { replace: true });
1014
+ R.back();
1015
+ R.forward();
1016
+ R.current(); // the current route object
1017
+ R.destroy();
1018
+ ```
1019
+
1020
+ ### Icons (`I` or `Domma.icons`)
1021
+
1022
+ 521 SVG icons in 18 categories, with declarative and imperative APIs.
1023
+
1024
+ ```html
660
1025
  <button data-icon="check">Save</button>
661
1026
  <span data-icon="user" data-icon-size="24"></span>
1027
+ ```
662
1028
 
1029
+ ```javascript
663
1030
  // Manual scan after DOM updates
664
1031
  I.scan();
665
1032
 
@@ -671,11 +1038,39 @@ $('#icon-container').html(html);
671
1038
  I.inject('#my-icon', 'star');
672
1039
  ```
673
1040
 
674
- **Categories:** actions, arrows, communication, devices, editor, files, hardware, media, navigation, notifications, social, status, toggle, ui, weather
1041
+ **Categories:** ui · navigation · communication · media · files · social · commerce · finance · status ·
1042
+ devices · weather · health · sport · buildings · transport · code · emojis · seasonal
1043
+
1044
+ Icons are single-colour and follow `currentColor`, so they theme for free. `$.setup({ scanIcons: true })`
1045
+ scans on startup.
1046
+
1047
+ ### Flags (`FL` or `Domma.flags`)
1048
+
1049
+ Nation flags as inline SVG, keyed by ISO 3166-1 alpha-2 code. **Opt-in bundle** - flags are multi-colour
1050
+ artwork that cannot follow `currentColor`, so they are not in the core bundle.
1051
+
1052
+ ```html
1053
+ <script src="dist/domma.min.js"></script>
1054
+ <script src="dist/domma-flags.min.js"></script>
1055
+
1056
+ <span data-flag="gb"></span>
1057
+ <span data-flag="fr" data-flag-shape="circle"></span>
1058
+ ```
1059
+
1060
+ ```javascript
1061
+ FL.render('us', { shape: 'rounded', width: 32, border: true });
1062
+ FL.scan(); // activate data-flag attributes
1063
+ FL.list('europe'); // codes in a region
1064
+ FL.search('king'); // fuzzy name search
1065
+ FL.register('xx', { /* ... */ }); // add your own
1066
+ ```
1067
+
1068
+ 56 flags across five regions ship as compact descriptors, expanded to SVG lazily on first render and then
1069
+ memoised. About 20 KB minified, 6 KB gzipped. See [docs/Flags.md](./docs/Flags.md).
675
1070
 
676
1071
  ### HTTP (`H` or `Domma.http`)
677
1072
 
678
- Simple async HTTP client with automatic JSON handling.
1073
+ Simple async HTTP client with automatic JSON handling. `H.get()` resolves to parsed JSON, not a `Response`.
679
1074
 
680
1075
  ```javascript
681
1076
  // GET request
@@ -694,15 +1089,16 @@ await H.delete('/api/users/1');
694
1089
 
695
1090
  ### Storage (`S` or `Domma.storage`)
696
1091
 
697
- localStorage wrapper with automatic JSON serialization.
1092
+ localStorage wrapper with automatic JSON serialisation. Keys are namespaced under a `domma:` prefix, so
1093
+ `S.set('user', …)` does not collide with anything else on the origin.
698
1094
 
699
1095
  ```javascript
700
- // Store data (auto-serializes)
1096
+ // Store data (auto-serialises)
701
1097
  S.set('user', { name: 'Alice', role: 'admin' });
702
1098
  S.set('preferences', { theme: 'dark', lang: 'en' });
703
1099
 
704
1100
  // Retrieve (auto-parses)
705
- const user = S.get('user'); // Returns object
1101
+ const user = S.get('user'); // Returns object
706
1102
  const theme = S.get('theme', 'light'); // With default
707
1103
 
708
1104
  // Other methods
@@ -712,16 +1108,62 @@ S.keys(); // List all Domma keys
712
1108
  S.clear(); // Clear all Domma data
713
1109
  ```
714
1110
 
1111
+ ### Auth (`A` or `Domma.auth`)
1112
+
1113
+ Token-based authentication with ready-made login, register and profile components.
1114
+
1115
+ ```javascript
1116
+ A.init({ apiUrl: '/api', autoCheck: true });
1117
+
1118
+ await A.login({ email, password });
1119
+ await A.register({ name, email, password });
1120
+ A.logout();
1121
+
1122
+ A.isAuthenticated();
1123
+ A.getUser();
1124
+ A.getHeaders(); // Authorization header for your own requests
1125
+
1126
+ // Role helpers
1127
+ A.getRole();
1128
+ A.hasRole('editor');
1129
+ A.hasAnyRole(['admin', 'editor']);
1130
+ A.isAdmin();
1131
+ A.isSubscriber();
1132
+ A.isGuest();
1133
+
1134
+ A.on('login', (user) => R.navigate('/dashboard'));
1135
+ A.on('logout', () => R.navigate('/'));
1136
+ A.on('tokenExpired', () => R.navigate('/login'));
1137
+ ```
1138
+
1139
+ ### Sanitize (`Domma.sanitize`)
1140
+
1141
+ HTML sanitisation used wherever user content reaches `innerHTML`. It delegates to **DOMPurify** when that
1142
+ is present on the page. When it is not, it escapes the HTML entirely and warns - safe, but markup is lost,
1143
+ so include DOMPurify if you need user formatting to survive.
1144
+
1145
+ ```html
1146
+ <script src="https://cdn.jsdelivr.net/npm/dompurify@3/dist/purify.min.js"></script>
1147
+ ```
1148
+
1149
+ ```javascript
1150
+ Domma.sanitize.sanitise(userHtml); // 'default' preset
1151
+ Domma.sanitize.sanitise(userHtml, { preset: 'strict' });
1152
+ Domma.sanitize.sanitiseBasic(comment); // only b, i, em, strong, br
1153
+ Domma.sanitize.sanitiseUserContent(post); // strict preset
1154
+ Domma.sanitize.escape(text); // no HTML at all
1155
+ Domma.sanitize.hasDOMPurify(); // is the real thing loaded?
1156
+ ```
1157
+
715
1158
  ## Demo & Showcase
716
1159
 
717
1160
  ```bash
718
- # Run the demo
719
- npm run demo
720
-
721
- # Run the showcase (comprehensive examples)
722
- npm run showcase
1161
+ npm run dev # build, then serve public/ with live reload
723
1162
  ```
724
1163
 
1164
+ Then open `/showcase/`. 87 showcase pages cover every module. Each one is loaded into jsdom by `npm test`,
1165
+ which asserts it renders and logs nothing - so an example that stops working fails the build.
1166
+
725
1167
  ## MiniApps
726
1168
 
727
1169
  Real-world, production-ready applications built with Domma.
@@ -747,13 +1189,20 @@ Powerful document editor with rich text formatting and export capabilities.
747
1189
  - Auto-save with Domma.storage
748
1190
  - **Try it:** [Domma Docs Live](https://dommajs.org/miniapps/docs/)
749
1191
 
1192
+ ### Address Lookup
1193
+
1194
+ UK postcode and address finder.
1195
+
1196
+ - Search by postcode, pick from the matching addresses
1197
+ - Results cached client-side with Domma.storage
1198
+ - **Try it:** [Address Lookup Live](https://dommajs.org/miniapps/address/)
1199
+
750
1200
  ### Nexus
751
1201
 
752
- Project management and collaboration platform.
1202
+ Contact management and collaboration platform.
753
1203
 
754
- - Task tracking and assignment
1204
+ - Contact tracking and organisation
755
1205
  - Team collaboration tools
756
- - Real-time updates
757
1206
  - **Try it:** [Nexus Live](https://dommajs.org/miniapps/nexus/)
758
1207
 
759
1208
  ## Documentation
@@ -768,21 +1217,29 @@ Domma uses distributed CLAUDE.md files for focused, context-specific guidance:
768
1217
  - Showcase-specific guides in `/public/showcase/*/CLAUDE.md`:
769
1218
  - [Showcase Meta Guide](./public/showcase/CLAUDE.md)
770
1219
  - [DOM](./public/showcase/dom/CLAUDE.md), [Utils](./public/showcase/utils/CLAUDE.md), [Dates](./public/showcase/dates/CLAUDE.md), [Models](./public/showcase/models/CLAUDE.md)
771
- - [Tables](./public/showcase/tables/CLAUDE.md), [Elements](./public/showcase/elements/CLAUDE.md), [Config](./public/showcase/config/CLAUDE.md)
772
- - [HTTP](./public/showcase/http/CLAUDE.md), [Storage](./public/showcase/storage/CLAUDE.md), [Developer Tools](./public/showcase/theme-roller/CLAUDE.md)
1220
+ - [Tables](./public/showcase/tables/CLAUDE.md), [Elements](./public/showcase/elements/CLAUDE.md), [Effects](./public/showcase/effects/CLAUDE.md), [Config](./public/showcase/config/CLAUDE.md)
1221
+ - [HTTP](./public/showcase/http/CLAUDE.md), [Storage](./public/showcase/storage/CLAUDE.md), [Router](./public/showcase/router/CLAUDE.md), [Developer Tools](./public/showcase/theme-roller/CLAUDE.md)
773
1222
 
774
1223
  ### For Users
775
1224
 
776
1225
  - [`docs/GettingStarted.md`](./docs/GettingStarted.md) - Quick start guide
777
1226
  - [`docs/API.md`](./docs/API.md) - Complete API reference
778
1227
  - [`docs/DommaDocumentation.md`](./docs/DommaDocumentation.md) - Comprehensive documentation
779
- - [Showcase](./public/showcase/index.html) - 40+ interactive examples
1228
+ - [`docs/Reactivity.md`](./docs/Reactivity.md) - Dependency tracking, computeds, batching
1229
+ - [`docs/Bindings.md`](./docs/Bindings.md) - `M.applyBindings()` and the `data-bind-*` vocabulary
1230
+ - [`docs/Blueprints.md`](./docs/Blueprints.md) - One schema for models, forms and CRUD
1231
+ - [`docs/Components.md`](./docs/Components.md) - Custom Elements with reactive state
1232
+ - [`docs/ContextMenu.md`](./docs/ContextMenu.md) - Container binding, delegation and the nesting cascade
1233
+ - [`docs/Flags.md`](./docs/Flags.md) - The opt-in flags module
1234
+ - [`docs/SchemaBuilder.md`](./docs/SchemaBuilder.md) - Visual Blueprint designer
1235
+ - [Showcase](./public/showcase/index.html) - 87 interactive examples
780
1236
 
781
1237
  ### For Contributors
782
1238
 
783
1239
  - Build system: See `npm run build` and `rollup.config.js`
784
- - Testing: Open `tests/test.html` in browser or run `npm test`
1240
+ - Testing: `npm test` runs the Vitest suite (20 test files, plus the showcase page harness)
785
1241
  - Custom bundles: See [`src/bundles/CLAUDE.md`](./src/bundles/CLAUDE.md)
1242
+ - Release process: [`docs/RELEASING.md`](./docs/RELEASING.md)
786
1243
 
787
1244
  ## Development
788
1245
 
@@ -790,11 +1247,19 @@ Domma uses distributed CLAUDE.md files for focused, context-specific guidance:
790
1247
  # Install dependencies
791
1248
  npm install
792
1249
 
793
- # Build
1250
+ # Build (JS bundles, CSS, archives, kickstart files, miniapps)
794
1251
  npm run build
795
1252
 
1253
+ # Build just the JS or just the CSS
1254
+ npm run build:js
1255
+ npm run build:css
1256
+
796
1257
  # Run tests
797
1258
  npm test
1259
+
1260
+ # Validators (ratchets - each fails only when a file gets worse)
1261
+ npm run validate # classes, theme contrast, conventions
1262
+ npm run validate:showcase # load all 87 showcase pages in jsdom
798
1263
  ```
799
1264
 
800
1265
  **MiniApps:**
@@ -805,21 +1270,10 @@ npm run build:miniapp:garage # Build specific miniapp
805
1270
  NODE_ENV=production npm run build # Production build
806
1271
  ```
807
1272
 
808
- ## Bundle Size
809
-
810
- | Bundle | Size | Description |
811
- |--------|------|-------------|
812
- | **full** | 390KB | Complete framework with all modules |
813
- | **minimal** | 163KB | DOM + Utils + Dates only |
814
- | **essentials** | 328KB | Core + Models + Elements + Config |
815
- | **data-focused** | 190KB | Core + Models + Tables + HTTP + Storage |
816
- | **no-ui** | 41KB | Core utilities without UI components |
817
-
818
- All sizes are minified. Choose the bundle that fits your needs!
819
-
820
1273
  ## Browser Support
821
1274
 
822
- Modern browsers (ES6+)
1275
+ Modern browsers (ES6+). No `eval` and no `Function` constructor, so Domma runs under a
1276
+ `script-src 'self'` Content Security Policy.
823
1277
 
824
1278
  ## License
825
1279