@design.estate/dees-domtools 2.3.3 → 2.3.5
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/dist_bundle/bundle.js +857 -3842
- package/dist_bundle/bundle.js.map +4 -4
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/domtools.classes.domtools.d.ts +2 -0
- package/dist_ts/domtools.classes.domtools.js +60 -24
- package/package.json +8 -8
- package/readme.md +426 -51
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/domtools.classes.domtools.ts +59 -24
package/readme.md
CHANGED
|
@@ -1,104 +1,479 @@
|
|
|
1
1
|
# @design.estate/dees-domtools
|
|
2
|
-
tools to simplify complex css structures
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
> 🎨 A comprehensive TypeScript toolkit for simplifying DOM manipulation, CSS management, and web component development
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
Modern web development made elegant. `@design.estate/dees-domtools` provides a powerful suite of utilities for managing complex CSS structures, handling browser events, implementing smooth scrolling, and building responsive web applications with ease.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
🚀 **Smart DOM Management** - Singleton-based DomTools instance with race-condition-free initialization
|
|
10
|
+
📱 **Responsive Breakpoints** - Built-in support for desktop, tablet, phablet, and phone viewports with container queries
|
|
11
|
+
🎭 **Theme Management** - Automatic dark/light mode detection and switching with RxJS observables
|
|
12
|
+
⌨️ **Keyboard Shortcuts** - Elegant keyboard event handling with combo support
|
|
13
|
+
📜 **Smooth Scrolling** - Native and Lenis-powered smooth scrolling with automatic detection
|
|
14
|
+
🎯 **State Management** - Integrated state management with smartstate
|
|
15
|
+
🧭 **Routing** - Client-side routing with smartrouter
|
|
16
|
+
🌐 **WebSetup** - Easy management of website metadata, favicons, and SEO tags
|
|
17
|
+
💅 **CSS Utilities** - Grid helpers, breakpoint utilities, and base styles for web components
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @design.estate/dees-domtools
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or with pnpm:
|
|
7
26
|
|
|
8
27
|
```bash
|
|
9
|
-
|
|
28
|
+
pnpm add @design.estate/dees-domtools
|
|
10
29
|
```
|
|
11
30
|
|
|
12
|
-
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { DomTools } from '@design.estate/dees-domtools';
|
|
35
|
+
|
|
36
|
+
// Initialize DomTools (singleton pattern - safe to call multiple times)
|
|
37
|
+
const domtools = await DomTools.setupDomTools();
|
|
38
|
+
|
|
39
|
+
// Wait for DOM to be ready
|
|
40
|
+
await domtools.domReady.promise;
|
|
41
|
+
|
|
42
|
+
// Now you're ready to rock! 🎸
|
|
43
|
+
console.log('DOM is ready, head and body elements are available');
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Core API
|
|
47
|
+
|
|
48
|
+
### DomTools Instance
|
|
49
|
+
|
|
50
|
+
The `DomTools` class is the heart of the library. It provides a singleton instance that manages all the utilities.
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { DomTools } from '@design.estate/dees-domtools';
|
|
54
|
+
|
|
55
|
+
// Setup with options
|
|
56
|
+
const domtools = await DomTools.setupDomTools({
|
|
57
|
+
ignoreGlobal: false // Set to true to create isolated instance
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Access DOM elements (available after domReady)
|
|
61
|
+
await domtools.domReady.promise;
|
|
62
|
+
const head = domtools.elements.headElement;
|
|
63
|
+
const body = domtools.elements.bodyElement;
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Key Properties:**
|
|
67
|
+
|
|
68
|
+
- `domtools.router` - SmartRouter instance for client-side routing
|
|
69
|
+
- `domtools.themeManager` - Theme management (dark/light mode)
|
|
70
|
+
- `domtools.scroller` - Smooth scrolling utilities
|
|
71
|
+
- `domtools.keyboard` - Keyboard event handling
|
|
72
|
+
- `domtools.websetup` - Website metadata management
|
|
73
|
+
- `domtools.smartstate` - State management
|
|
74
|
+
- `domtools.deesComms` - Communication utilities
|
|
75
|
+
|
|
76
|
+
**Lifecycle Promises:**
|
|
77
|
+
|
|
78
|
+
- `domtools.domToolsReady.promise` - Resolves when DomTools is initialized
|
|
79
|
+
- `domtools.domReady.promise` - Resolves when DOM is interactive/complete
|
|
80
|
+
- `domtools.globalStylesReady.promise` - Resolves when global styles are set
|
|
81
|
+
|
|
82
|
+
### Responsive Breakpoints
|
|
83
|
+
|
|
84
|
+
Built-in breakpoint system with both media queries and container queries:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { breakpoints, css } from '@design.estate/dees-domtools';
|
|
88
|
+
import { css as litCss } from 'lit';
|
|
89
|
+
|
|
90
|
+
// Breakpoint values (in pixels)
|
|
91
|
+
breakpoints.desktop // 1600px
|
|
92
|
+
breakpoints.notebook // 1240px
|
|
93
|
+
breakpoints.tablet // 1024px
|
|
94
|
+
breakpoints.phablet // 600px
|
|
95
|
+
breakpoints.phone // 400px
|
|
96
|
+
|
|
97
|
+
// Use with Lit components
|
|
98
|
+
const myStyles = litCss`
|
|
99
|
+
.container {
|
|
100
|
+
padding: 20px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
${breakpoints.cssForTablet(litCss`
|
|
104
|
+
.container {
|
|
105
|
+
padding: 10px;
|
|
106
|
+
}
|
|
107
|
+
`)}
|
|
108
|
+
|
|
109
|
+
${breakpoints.cssForPhone(litCss`
|
|
110
|
+
.container {
|
|
111
|
+
padding: 5px;
|
|
112
|
+
}
|
|
113
|
+
`)}
|
|
114
|
+
`;
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Available breakpoint helpers:
|
|
118
|
+
- `cssForDesktop(css)` - Styles for 1600px and above
|
|
119
|
+
- `cssForNotebook(css)` - Styles for 1240px and below
|
|
120
|
+
- `cssForTablet(css)` - Styles for 1024px and below
|
|
121
|
+
- `cssForPhablet(css)` - Styles for 600px and below
|
|
122
|
+
- `cssForPhone(css)` - Styles for 400px and below
|
|
123
|
+
|
|
124
|
+
### Theme Management
|
|
125
|
+
|
|
126
|
+
Automatic theme detection with system preference support:
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
const domtools = await DomTools.setupDomTools();
|
|
130
|
+
const { themeManager } = domtools;
|
|
131
|
+
|
|
132
|
+
// Toggle between dark and light
|
|
133
|
+
themeManager.toggleDarkBright();
|
|
134
|
+
|
|
135
|
+
// Set specific theme
|
|
136
|
+
themeManager.goDark();
|
|
137
|
+
themeManager.goBright();
|
|
138
|
+
|
|
139
|
+
// Enable automatic global background changes
|
|
140
|
+
await themeManager.enableAutomaticGlobalThemeChange();
|
|
141
|
+
|
|
142
|
+
// Subscribe to theme changes
|
|
143
|
+
themeManager.themeObservable.subscribe((isBright) => {
|
|
144
|
+
console.log(`Theme is now: ${isBright ? 'light' : 'dark'}`);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Check current theme
|
|
148
|
+
if (themeManager.goBrightBoolean) {
|
|
149
|
+
console.log('Light mode active');
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Keyboard Shortcuts
|
|
154
|
+
|
|
155
|
+
Handle keyboard events with ease, including complex combinations:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { Keyboard, Key } from '@design.estate/dees-domtools';
|
|
159
|
+
|
|
160
|
+
const domtools = await DomTools.setupDomTools();
|
|
161
|
+
await domtools.domReady.promise;
|
|
13
162
|
|
|
14
|
-
|
|
163
|
+
// Access the keyboard instance
|
|
164
|
+
const { keyboard } = domtools;
|
|
15
165
|
|
|
16
|
-
|
|
166
|
+
// Listen for Ctrl+S
|
|
167
|
+
keyboard.on([Key.Ctrl, Key.S]).subscribe((event) => {
|
|
168
|
+
event.preventDefault();
|
|
169
|
+
console.log('Save triggered!');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Listen for Ctrl+Shift+P
|
|
173
|
+
keyboard.on([Key.Ctrl, Key.Shift, Key.P]).subscribe(() => {
|
|
174
|
+
console.log('Command palette opened!');
|
|
175
|
+
});
|
|
17
176
|
|
|
18
|
-
|
|
177
|
+
// Programmatically trigger key presses
|
|
178
|
+
keyboard.triggerKeyPress([Key.Ctrl, Key.S]);
|
|
19
179
|
|
|
20
|
-
|
|
180
|
+
// Clean up when done
|
|
181
|
+
keyboard.stopListening();
|
|
182
|
+
```
|
|
21
183
|
|
|
22
|
-
|
|
23
|
-
- **Responsive Design Helpers**: Tools for managing responsive designs more easily, with utilities for breakpoints, and adaptable grids.
|
|
24
|
-
- **Element Utilities**: Simplified interactions with DOM elements, including dynamic style manipulations and more.
|
|
25
|
-
- **Theme Management**: Simplify the process of theme toggling (dark mode/light mode) in your applications.
|
|
26
|
-
- **Keyboard Event Handling**: Utilities for managing keyboard events, facilitating better interaction handling.
|
|
27
|
-
- **External Resources Management**: Easily manage external CSS and JavaScript resources within your project.
|
|
184
|
+
**Available Keys:**
|
|
28
185
|
|
|
29
|
-
|
|
186
|
+
All standard keyboard keys are available in the `Key` enum, including:
|
|
187
|
+
- Modifiers: `Ctrl`, `Shift`, `Alt`
|
|
188
|
+
- Letters: `A` through `Z`
|
|
189
|
+
- Numbers: `Zero` through `Nine`
|
|
190
|
+
- Function keys: `F1` through `F12`
|
|
191
|
+
- Navigation: `Home`, `End`, `PageUp`, `PageDown`, arrows
|
|
192
|
+
- And many more...
|
|
30
193
|
|
|
31
|
-
|
|
194
|
+
### Smooth Scrolling
|
|
195
|
+
|
|
196
|
+
Powerful scrolling utilities with Lenis integration:
|
|
32
197
|
|
|
33
198
|
```typescript
|
|
34
|
-
|
|
199
|
+
const domtools = await DomTools.setupDomTools();
|
|
200
|
+
const { scroller } = domtools;
|
|
201
|
+
|
|
202
|
+
// Scroll to an element smoothly
|
|
203
|
+
const targetElement = document.querySelector('#section-2');
|
|
204
|
+
await scroller.toElement(targetElement, {
|
|
205
|
+
duration: 1000,
|
|
206
|
+
easing: 'easeInOutQuad'
|
|
207
|
+
});
|
|
35
208
|
|
|
36
|
-
//
|
|
37
|
-
|
|
209
|
+
// Enable Lenis smooth scrolling
|
|
210
|
+
await scroller.enableLenisScroll({
|
|
211
|
+
disableOnNativeSmoothScroll: true // Auto-disable if browser has native smooth scroll
|
|
212
|
+
});
|
|
38
213
|
|
|
39
|
-
//
|
|
40
|
-
|
|
214
|
+
// Register scroll callbacks
|
|
215
|
+
scroller.onScroll(() => {
|
|
216
|
+
console.log('Page scrolled!');
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// Detect if native smooth scrolling is enabled
|
|
220
|
+
const hasNativeSmooth = await scroller.detectNativeSmoothScroll();
|
|
41
221
|
```
|
|
42
222
|
|
|
43
|
-
###
|
|
223
|
+
### CSS Utilities
|
|
44
224
|
|
|
45
|
-
|
|
225
|
+
Helper functions for common CSS patterns:
|
|
46
226
|
|
|
47
227
|
```typescript
|
|
48
228
|
import { css } from '@design.estate/dees-domtools';
|
|
49
229
|
|
|
50
|
-
//
|
|
51
|
-
const
|
|
230
|
+
// Create responsive grid columns
|
|
231
|
+
const gridTemplate = css.cssGridColumns(4, 16);
|
|
232
|
+
// Returns: calc((100%/4) - (48px/4)) calc((100%/4) - (48px/4)) ...
|
|
233
|
+
|
|
234
|
+
// Use in your styles
|
|
235
|
+
const styles = `
|
|
236
|
+
.grid {
|
|
237
|
+
display: grid;
|
|
238
|
+
grid-template-columns: ${gridTemplate};
|
|
239
|
+
gap: 16px;
|
|
240
|
+
}
|
|
241
|
+
`;
|
|
52
242
|
```
|
|
53
243
|
|
|
54
|
-
###
|
|
244
|
+
### Global Styles & External Resources
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
const domtools = await DomTools.setupDomTools();
|
|
248
|
+
|
|
249
|
+
// Add global CSS
|
|
250
|
+
await domtools.setGlobalStyles(`
|
|
251
|
+
body {
|
|
252
|
+
margin: 0;
|
|
253
|
+
font-family: 'Inter', sans-serif;
|
|
254
|
+
}
|
|
255
|
+
`);
|
|
55
256
|
|
|
56
|
-
|
|
257
|
+
// Load external CSS
|
|
258
|
+
await domtools.setExternalCss('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
|
|
259
|
+
|
|
260
|
+
// Load external JavaScript
|
|
261
|
+
await domtools.setExternalScript('https://cdn.example.com/analytics.js');
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Website Metadata
|
|
265
|
+
|
|
266
|
+
Manage your website's metadata easily:
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
const domtools = await DomTools.setupDomTools();
|
|
270
|
+
|
|
271
|
+
await domtools.setWebsiteInfo({
|
|
272
|
+
metaObject: {
|
|
273
|
+
title: 'My Awesome App',
|
|
274
|
+
description: 'The best app ever created',
|
|
275
|
+
keywords: ['awesome', 'app', 'web'],
|
|
276
|
+
author: 'Your Name'
|
|
277
|
+
},
|
|
278
|
+
faviconUrl: '/favicon.ico',
|
|
279
|
+
appleTouchIconUrl: '/apple-touch-icon.png'
|
|
280
|
+
});
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Web Component Base Styles
|
|
284
|
+
|
|
285
|
+
Kickstart your Lit elements with pre-configured styles:
|
|
57
286
|
|
|
58
287
|
```typescript
|
|
59
|
-
import {
|
|
288
|
+
import { LitElement } from 'lit';
|
|
289
|
+
import { elementBasic } from '@design.estate/dees-domtools';
|
|
60
290
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
291
|
+
class MyElement extends LitElement {
|
|
292
|
+
static styles = [elementBasic.staticStyles];
|
|
293
|
+
|
|
294
|
+
async connectedCallback() {
|
|
295
|
+
super.connectedCallback();
|
|
296
|
+
await elementBasic.setup(this);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
64
299
|
```
|
|
65
300
|
|
|
66
|
-
|
|
301
|
+
The `elementBasic.staticStyles` includes:
|
|
302
|
+
- Box-sizing reset
|
|
303
|
+
- Smooth transitions for background and color
|
|
304
|
+
- Custom scrollbar styles
|
|
305
|
+
- Default font family (Geist Sans, Inter fallback)
|
|
306
|
+
|
|
307
|
+
### State Management
|
|
67
308
|
|
|
68
|
-
|
|
309
|
+
Integrated state management with smartstate:
|
|
69
310
|
|
|
70
311
|
```typescript
|
|
71
|
-
|
|
72
|
-
|
|
312
|
+
const domtools = await DomTools.setupDomTools();
|
|
313
|
+
|
|
314
|
+
// Access the state part
|
|
315
|
+
const state = domtools.domToolsStatePart;
|
|
316
|
+
|
|
317
|
+
// Get current state
|
|
318
|
+
const currentState = state.getState();
|
|
319
|
+
console.log(currentState.virtualViewport); // 'native'
|
|
320
|
+
console.log(currentState.jwt); // null
|
|
321
|
+
|
|
322
|
+
// Update state
|
|
323
|
+
state.setState({
|
|
324
|
+
virtualViewport: 'tablet',
|
|
325
|
+
jwt: 'your-token-here'
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Subscribe to state changes
|
|
329
|
+
state.subscribe((newState) => {
|
|
330
|
+
console.log('State updated:', newState);
|
|
331
|
+
});
|
|
73
332
|
```
|
|
74
333
|
|
|
75
|
-
###
|
|
334
|
+
### Run Once Pattern
|
|
76
335
|
|
|
77
|
-
|
|
336
|
+
Execute expensive operations only once, even if called multiple times:
|
|
78
337
|
|
|
79
338
|
```typescript
|
|
80
|
-
|
|
339
|
+
const domtools = await DomTools.setupDomTools();
|
|
81
340
|
|
|
82
|
-
//
|
|
83
|
-
const
|
|
341
|
+
// This will only execute once, even if called multiple times
|
|
342
|
+
const result = await domtools.runOnce('myExpensiveOperation', async () => {
|
|
343
|
+
console.log('Running expensive operation...');
|
|
344
|
+
await someExpensiveAsyncOperation();
|
|
345
|
+
return 'result';
|
|
346
|
+
});
|
|
84
347
|
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
console.log('
|
|
348
|
+
// Subsequent calls return the same result without re-executing
|
|
349
|
+
const sameResult = await domtools.runOnce('myExpensiveOperation', async () => {
|
|
350
|
+
console.log('This will never run!');
|
|
351
|
+
return 'different result';
|
|
88
352
|
});
|
|
353
|
+
|
|
354
|
+
console.log(result === sameResult); // true
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
Error handling is built-in - if the function throws, all waiting callers receive the same error.
|
|
358
|
+
|
|
359
|
+
## Advanced Usage
|
|
360
|
+
|
|
361
|
+
### Combining Features
|
|
362
|
+
|
|
363
|
+
Here's a real-world example combining multiple features:
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
import { DomTools, breakpoints, elementBasic, Key } from '@design.estate/dees-domtools';
|
|
367
|
+
import { LitElement, html, css as litCss } from 'lit';
|
|
368
|
+
import { customElement } from 'lit/decorators.js';
|
|
369
|
+
|
|
370
|
+
@customElement('my-app')
|
|
371
|
+
class MyApp extends LitElement {
|
|
372
|
+
static styles = [
|
|
373
|
+
elementBasic.staticStyles,
|
|
374
|
+
litCss`
|
|
375
|
+
:host {
|
|
376
|
+
display: block;
|
|
377
|
+
padding: 2rem;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
${breakpoints.cssForTablet(litCss`
|
|
381
|
+
:host {
|
|
382
|
+
padding: 1rem;
|
|
383
|
+
}
|
|
384
|
+
`)}
|
|
385
|
+
`
|
|
386
|
+
];
|
|
387
|
+
|
|
388
|
+
private domtools?: DomTools;
|
|
389
|
+
|
|
390
|
+
async connectedCallback() {
|
|
391
|
+
super.connectedCallback();
|
|
392
|
+
|
|
393
|
+
// Setup DomTools
|
|
394
|
+
this.domtools = await elementBasic.setup(this);
|
|
395
|
+
await this.domtools.domReady.promise;
|
|
396
|
+
|
|
397
|
+
// Setup keyboard shortcuts
|
|
398
|
+
this.domtools.keyboard.on([Key.Ctrl, Key.K]).subscribe(() => {
|
|
399
|
+
this.openCommandPalette();
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// Subscribe to theme changes
|
|
403
|
+
this.domtools.themeManager.themeObservable.subscribe((isBright) => {
|
|
404
|
+
this.requestUpdate();
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// Enable smooth scrolling
|
|
408
|
+
await this.domtools.scroller.enableLenisScroll({
|
|
409
|
+
disableOnNativeSmoothScroll: true
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
private openCommandPalette() {
|
|
414
|
+
console.log('Command palette opened!');
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
render() {
|
|
418
|
+
const isDark = !this.domtools?.themeManager.goBrightBoolean;
|
|
419
|
+
|
|
420
|
+
return html`
|
|
421
|
+
<div class="app" style="background: ${isDark ? '#1a1a1a' : '#ffffff'}">
|
|
422
|
+
<h1>My Awesome App</h1>
|
|
423
|
+
<button @click=${() => this.domtools?.themeManager.toggleDarkBright()}>
|
|
424
|
+
Toggle Theme
|
|
425
|
+
</button>
|
|
426
|
+
</div>
|
|
427
|
+
`;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## TypeScript Support
|
|
433
|
+
|
|
434
|
+
This package is written in TypeScript and provides full type definitions:
|
|
435
|
+
|
|
436
|
+
```typescript
|
|
437
|
+
import type {
|
|
438
|
+
IDomToolsState,
|
|
439
|
+
IDomToolsContructorOptions,
|
|
440
|
+
TViewport
|
|
441
|
+
} from '@design.estate/dees-domtools';
|
|
442
|
+
|
|
443
|
+
// Custom state interface
|
|
444
|
+
interface MyState extends IDomToolsState {
|
|
445
|
+
customProperty: string;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Type-safe viewport handling
|
|
449
|
+
const viewport: TViewport = 'tablet';
|
|
89
450
|
```
|
|
90
451
|
|
|
91
|
-
|
|
452
|
+
## Browser Support
|
|
453
|
+
|
|
454
|
+
Targets the latest version of Chrome. For other browsers, you may need to include polyfills.
|
|
455
|
+
|
|
456
|
+
## Why @design.estate/dees-domtools?
|
|
457
|
+
|
|
458
|
+
✅ **Race-condition free** - Carefully designed initialization prevents common timing issues
|
|
459
|
+
✅ **TypeScript first** - Full type safety and IntelliSense support
|
|
460
|
+
✅ **Modern APIs** - Built on Lit, RxJS, and other modern web standards
|
|
461
|
+
✅ **Batteries included** - Everything you need for sophisticated web apps
|
|
462
|
+
✅ **Production ready** - Used in real-world applications at design.estate
|
|
463
|
+
✅ **Well maintained** - Active development and support
|
|
464
|
+
|
|
465
|
+
## Related Packages
|
|
92
466
|
|
|
93
|
-
|
|
94
|
-
- **Embrace Responsiveness**: Leverage the responsive design helpers to ensure your application looks great on any device.
|
|
95
|
-
- **Consistent Theme Handling**: Utilize the theme management tools to provide a seamless experience for your users, allowing them to choose their preferred theme.
|
|
467
|
+
This library integrates with the design.estate ecosystem:
|
|
96
468
|
|
|
97
|
-
|
|
469
|
+
- `@design.estate/dees-comms` - Communication utilities
|
|
470
|
+
- `@push.rocks/websetup` - Website setup and meta management
|
|
471
|
+
- `@push.rocks/smartrouter` - Client-side routing
|
|
472
|
+
- `@push.rocks/smartstate` - State management
|
|
98
473
|
|
|
99
474
|
## License and Legal Information
|
|
100
475
|
|
|
101
|
-
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
|
476
|
+
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
|
102
477
|
|
|
103
478
|
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
|
104
479
|
|
|
@@ -108,7 +483,7 @@ This project is owned and maintained by Task Venture Capital GmbH. The names and
|
|
|
108
483
|
|
|
109
484
|
### Company Information
|
|
110
485
|
|
|
111
|
-
Task Venture Capital GmbH
|
|
486
|
+
Task Venture Capital GmbH
|
|
112
487
|
Registered at District court Bremen HRB 35230 HB, Germany
|
|
113
488
|
|
|
114
489
|
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@design.estate/dees-domtools',
|
|
6
|
-
version: '2.3.
|
|
6
|
+
version: '2.3.5',
|
|
7
7
|
description: 'A package providing tools to simplify complex CSS structures and web development tasks, featuring TypeScript support and integration with various web technologies.'
|
|
8
8
|
}
|
|
@@ -18,32 +18,54 @@ export class DomTools {
|
|
|
18
18
|
// ======
|
|
19
19
|
// STATIC
|
|
20
20
|
// ======
|
|
21
|
+
private static initializationPromise: Promise<DomTools> | null = null;
|
|
22
|
+
|
|
21
23
|
/**
|
|
22
24
|
* setups domtools
|
|
23
25
|
*/
|
|
24
|
-
public static async setupDomTools(optionsArg: IDomToolsContructorOptions = {}) {
|
|
25
|
-
|
|
26
|
-
if (!
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
26
|
+
public static async setupDomTools(optionsArg: IDomToolsContructorOptions = {}): Promise<DomTools> {
|
|
27
|
+
// If initialization is already in progress and we're not ignoring global, wait for it
|
|
28
|
+
if (!optionsArg.ignoreGlobal && DomTools.initializationPromise) {
|
|
29
|
+
return await DomTools.initializationPromise;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Create initialization promise to prevent race conditions
|
|
33
|
+
if (!optionsArg.ignoreGlobal) {
|
|
34
|
+
DomTools.initializationPromise = (async () => {
|
|
35
|
+
let domToolsInstance: DomTools;
|
|
36
|
+
if (!globalThis.deesDomTools) {
|
|
37
|
+
globalThis.deesDomTools = new DomTools(optionsArg);
|
|
38
|
+
domToolsInstance = globalThis.deesDomTools;
|
|
39
|
+
|
|
40
|
+
// lets make sure the dom is ready
|
|
41
|
+
const readyStateChangedFunc = () => {
|
|
42
|
+
if (document.readyState === 'interactive' || document.readyState === 'complete') {
|
|
43
|
+
domToolsInstance.elements.headElement = document.querySelector('head');
|
|
44
|
+
domToolsInstance.elements.bodyElement = document.querySelector('body');
|
|
45
|
+
// Initialize keyboard now that document.body exists
|
|
46
|
+
domToolsInstance.keyboard = new Keyboard(document.body);
|
|
47
|
+
domToolsInstance.domReady.resolve();
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
// Check current state immediately to avoid race condition
|
|
51
|
+
if (document.readyState === 'interactive' || document.readyState === 'complete') {
|
|
52
|
+
readyStateChangedFunc();
|
|
53
|
+
} else {
|
|
54
|
+
document.addEventListener('readystatechange', readyStateChangedFunc);
|
|
55
|
+
}
|
|
56
|
+
domToolsInstance.domToolsReady.resolve();
|
|
57
|
+
} else {
|
|
58
|
+
domToolsInstance = globalThis.deesDomTools;
|
|
36
59
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
domToolsInstance = new DomTools(optionsArg);
|
|
60
|
+
await domToolsInstance.domToolsReady.promise;
|
|
61
|
+
return domToolsInstance;
|
|
62
|
+
})();
|
|
63
|
+
return await DomTools.initializationPromise;
|
|
42
64
|
} else {
|
|
43
|
-
|
|
65
|
+
// ignoreGlobal case - create isolated instance
|
|
66
|
+
const domToolsInstance = new DomTools(optionsArg);
|
|
67
|
+
return domToolsInstance;
|
|
44
68
|
}
|
|
45
|
-
await domToolsInstance.domToolsReady.promise;
|
|
46
|
-
return domToolsInstance;
|
|
47
69
|
}
|
|
48
70
|
|
|
49
71
|
/**
|
|
@@ -95,7 +117,7 @@ export class DomTools {
|
|
|
95
117
|
public deesComms = new plugins.deesComms.DeesComms();
|
|
96
118
|
public scroller = new Scroller(this);
|
|
97
119
|
public themeManager = new ThemeManager(this);
|
|
98
|
-
public keyboard =
|
|
120
|
+
public keyboard: Keyboard = null; // Initialized after DOM ready to avoid accessing document.body before it exists
|
|
99
121
|
|
|
100
122
|
public domToolsReady = plugins.smartpromise.defer();
|
|
101
123
|
public domReady = plugins.smartpromise.defer();
|
|
@@ -105,6 +127,7 @@ export class DomTools {
|
|
|
105
127
|
|
|
106
128
|
private runOnceTrackerStringMap = new plugins.lik.Stringmap();
|
|
107
129
|
private runOnceResultMap = new plugins.lik.FastMap();
|
|
130
|
+
private runOnceErrorMap = new plugins.lik.FastMap();
|
|
108
131
|
|
|
109
132
|
/**
|
|
110
133
|
* run a function once and always get the Promise of the first execution
|
|
@@ -116,15 +139,27 @@ export class DomTools {
|
|
|
116
139
|
if (!this.runOnceTrackerStringMap.checkString(identifierArg)) {
|
|
117
140
|
this.runOnceTrackerStringMap.addString(identifierArg);
|
|
118
141
|
this.runOnceTrackerStringMap.addString(runningId);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
142
|
+
try {
|
|
143
|
+
const result = await funcArg();
|
|
144
|
+
this.runOnceResultMap.addToMap(identifierArg, result);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
// Store error so waiting callers can receive it
|
|
147
|
+
this.runOnceErrorMap.addToMap(identifierArg, error);
|
|
148
|
+
} finally {
|
|
149
|
+
// Always remove running flag to prevent permanent stuck state
|
|
150
|
+
this.runOnceTrackerStringMap.removeString(runningId);
|
|
151
|
+
}
|
|
122
152
|
}
|
|
123
153
|
return await this.runOnceTrackerStringMap.registerUntilTrue(
|
|
124
154
|
(stringMap) => {
|
|
125
155
|
return !stringMap.includes(runningId);
|
|
126
156
|
},
|
|
127
157
|
() => {
|
|
158
|
+
// Check if there was an error and re-throw it
|
|
159
|
+
const error = this.runOnceErrorMap.getByKey(identifierArg);
|
|
160
|
+
if (error) {
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
128
163
|
return this.runOnceResultMap.getByKey(identifierArg);
|
|
129
164
|
}
|
|
130
165
|
);
|