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