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 +597 -143
- package/bin/domma-cli.js +5 -5
- package/bin/postinstall.js +1 -1
- package/package.json +11 -6
- package/public/dist/bundles/domma-complete.css +556 -116
- package/public/dist/bundles/domma-data-focused.css +556 -116
- package/public/dist/bundles/domma-essentials.css +556 -116
- package/public/dist/bundles/domma-full.css +556 -116
- package/public/dist/bundles/domma-minimal.css +11 -14
- package/public/dist/domma-flags.esm.js +3 -3
- package/public/dist/domma-flags.min.js +3 -3
- package/public/dist/domma-syntax.min.js +3 -3
- package/public/dist/domma.css +6 -9
- package/public/dist/domma.esm.js +5 -5
- package/public/dist/domma.min.js +5 -5
- package/public/dist/elements.css +488 -45
- package/public/dist/grid.css +3 -3
- package/public/dist/syntax.css +3 -3
- package/public/dist/themes/domma-themes.css +57 -57
- package/templates/kickstart-spa/README.md +1 -1
- package/public/dist/bundles/domma-grayve.css +0 -16852
- package/public/dist/themes/grayve.css +0 -213
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
|
|
13
|
-
- **Utilities** (`_`) -
|
|
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
|
|
16
|
-
- **
|
|
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
|
-
- **
|
|
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
|
|
22
|
-
- **
|
|
23
|
-
- **
|
|
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
|
-
**
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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/
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
|
|
|
190
|
-
|
|
191
|
-
| **
|
|
192
|
-
| **
|
|
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 =
|
|
291
|
+
const modal = E.modal('#my-modal', {backdrop: true});
|
|
239
292
|
modal.open();
|
|
240
293
|
|
|
241
294
|
// Interactive Tables
|
|
242
|
-
const table =
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
**
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
-
|
|
316
|
-
-
|
|
317
|
-
|
|
318
|
-
-
|
|
319
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
331
|
-
|
|
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
|
-
**
|
|
517
|
+
**Page Roller** - drag-and-drop page builder:
|
|
335
518
|
```javascript
|
|
336
|
-
|
|
519
|
+
const builder = E.pageRoller('#page-roller-container');
|
|
337
520
|
```
|
|
338
521
|
|
|
339
|
-
**
|
|
522
|
+
**Schema Builder** - visual Blueprint designer:
|
|
340
523
|
```javascript
|
|
341
|
-
|
|
524
|
+
const schema = E.schemaBuilder('#schema-builder-container');
|
|
342
525
|
```
|
|
343
526
|
|
|
344
|
-
**Editor** -
|
|
527
|
+
**Editor** - text, rich-text and code modes with autosave:
|
|
345
528
|
```javascript
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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** -
|
|
538
|
+
**Print-to-PDF** - export any element:
|
|
353
539
|
```javascript
|
|
354
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
**
|
|
400
|
-
-
|
|
401
|
-
-
|
|
402
|
-
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
//
|
|
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
|
-
|
|
757
|
+
32 production-ready UI components.
|
|
514
758
|
|
|
515
759
|
**Dialogs & Overlays:**
|
|
516
760
|
- `modal()` - Modal dialogs with backdrop
|
|
517
|
-
- `
|
|
518
|
-
- `toast()` - Toast notifications
|
|
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()` -
|
|
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
|
|
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 &
|
|
797
|
+
**Data & Time:**
|
|
549
798
|
- `treeView()` - Hierarchical tree display
|
|
550
|
-
- `progression()` -
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
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
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
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
|
-
|
|
649
|
-
|
|
650
|
-
|
|
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
|
-
###
|
|
978
|
+
### Router (`R` or `Domma.router`)
|
|
655
979
|
|
|
656
|
-
|
|
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
|
-
|
|
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:**
|
|
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
|
|
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-
|
|
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');
|
|
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
|
-
#
|
|
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
|
-
|
|
1202
|
+
Contact management and collaboration platform.
|
|
753
1203
|
|
|
754
|
-
-
|
|
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
|
-
- [
|
|
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:
|
|
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
|
|