@simplybuilder/core-dom 2.0.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/AUTHORS +2 -0
- package/CONTRIBUTING.md +35 -0
- package/GOVERNANCE.md +10 -0
- package/LICENSE +21 -0
- package/MAINTAINERS.md +1 -0
- package/README.md +74 -0
- package/lib/attributes.d.ts +33 -0
- package/lib/core-dom.d.ts +1 -0
- package/lib/creator.d.ts +38 -0
- package/lib/dataset.d.ts +26 -0
- package/lib/extension.d.ts +80 -0
- package/lib/main.commonjs.cjs +594 -0
- package/lib/main.commonjs.min.cjs +3 -0
- package/lib/main.d.ts +49 -0
- package/lib/main.esm.min.mjs +3 -0
- package/lib/main.esm.mjs +594 -0
- package/lib/store.d.ts +52 -0
- package/lib/struct.d.ts +63 -0
- package/lib/types.d.ts +58 -0
- package/package.json +95 -0
package/lib/main.esm.mjs
ADDED
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
/*! SBCoreDom version 2.0.0 */
|
|
2
|
+
/**
|
|
3
|
+
* @module DomStoreModule
|
|
4
|
+
* @description
|
|
5
|
+
* Key-value store for DOM element references. Elements can be registered
|
|
6
|
+
* by a string key and retrieved or removed later. Supports two removal modes:
|
|
7
|
+
* mode 1 (with EventModule cleanup) and mode 2 (store only).
|
|
8
|
+
*/
|
|
9
|
+
const ElementRefStore = {};
|
|
10
|
+
/**
|
|
11
|
+
* Registers a DOM element in the store under a unique key.
|
|
12
|
+
* If the key already exists, the operation is silently ignored.
|
|
13
|
+
*
|
|
14
|
+
* @function addElementToStore
|
|
15
|
+
* @param {Object} data - Registration data.
|
|
16
|
+
* @param {string} data.key - Unique identifier for the element.
|
|
17
|
+
* @param {Element} data.value - The DOM element to store.
|
|
18
|
+
*/
|
|
19
|
+
function addElementToStore(data) {
|
|
20
|
+
const { key, value } = data;
|
|
21
|
+
if (key && value) {
|
|
22
|
+
if (typeof ElementRefStore[key] === 'undefined') {
|
|
23
|
+
ElementRefStore[key] = value;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Retrieves a stored DOM element by its key.
|
|
29
|
+
*
|
|
30
|
+
* @function getElementFromStore
|
|
31
|
+
* @param {string} key - The element's unique key.
|
|
32
|
+
* @returns {Element|undefined} - The stored element, or undefined.
|
|
33
|
+
*/
|
|
34
|
+
function getElementFromStore(key) {
|
|
35
|
+
if (key)
|
|
36
|
+
return ElementRefStore[key];
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Removes a DOM element from the store by its key.
|
|
41
|
+
* In mode 1 (default), calls `EventModule.removeAllEventsFromStore`
|
|
42
|
+
* before deleting. In mode 2, deletes from store only.
|
|
43
|
+
*
|
|
44
|
+
* @function removeElementFromStore
|
|
45
|
+
* @param {Object} data - Removal data.
|
|
46
|
+
* @param {string} data.key - The element's unique key.
|
|
47
|
+
* @param {number} [data.mode=1] - Removal mode: 1 with event cleanup, 2 store only.
|
|
48
|
+
* @param {Object} [data.EventModule] - Optional EventModule for listener cleanup.
|
|
49
|
+
* @returns {boolean} - True if the element was found and removed.
|
|
50
|
+
*/
|
|
51
|
+
function removeElementFromStore(data) {
|
|
52
|
+
const { key, mode = 1, EventModule = {} } = data;
|
|
53
|
+
if (!key)
|
|
54
|
+
return false;
|
|
55
|
+
try {
|
|
56
|
+
const element = ElementRefStore[key];
|
|
57
|
+
if (!element)
|
|
58
|
+
return false;
|
|
59
|
+
if (mode === 1 && typeof EventModule.removeAllEventsFromStore === 'function') {
|
|
60
|
+
EventModule.removeAllEventsFromStore(element);
|
|
61
|
+
}
|
|
62
|
+
delete ElementRefStore[key];
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Removes all entries from the store. Used for testing.
|
|
71
|
+
*
|
|
72
|
+
* @function clearStore
|
|
73
|
+
*/
|
|
74
|
+
function clearStore() {
|
|
75
|
+
for (const key of Object.keys(ElementRefStore)) {
|
|
76
|
+
delete ElementRefStore[key];
|
|
77
|
+
}
|
|
78
|
+
}/**
|
|
79
|
+
* @module DomExtensionModule
|
|
80
|
+
* @description
|
|
81
|
+
* Extension system for the DOM module. Allows external modules (e.g., EventModule)
|
|
82
|
+
* to register themselves via `domModuleExtends()` and hook into the DOM creation
|
|
83
|
+
* and removal pipeline. Version validation ensures compatibility at runtime.
|
|
84
|
+
*/
|
|
85
|
+
/**
|
|
86
|
+
* Internal store for module metadata, registered extensions, and version constraints.
|
|
87
|
+
*
|
|
88
|
+
* @private
|
|
89
|
+
* @ignore
|
|
90
|
+
* @type {Object}
|
|
91
|
+
*/
|
|
92
|
+
const internalStore = {
|
|
93
|
+
app: {
|
|
94
|
+
name: 'DomModule',
|
|
95
|
+
version: "2.0.0",
|
|
96
|
+
},
|
|
97
|
+
register: {},
|
|
98
|
+
allow: {
|
|
99
|
+
SBCoreEvent: { major: 2 },
|
|
100
|
+
},
|
|
101
|
+
clearExtensions() {
|
|
102
|
+
for (const key of Object.keys(this.register)) {
|
|
103
|
+
delete this.register[key];
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Validates that a module's version meets the minimum version requirements
|
|
109
|
+
* defined in `internalStore.allow`. Checks major, minor, and patch levels.
|
|
110
|
+
*
|
|
111
|
+
* @function validVersionSupport
|
|
112
|
+
* @param {Object} data - Module data with name and version.
|
|
113
|
+
* @param {string} data.name - Module identifier (e.g., 'EventModule').
|
|
114
|
+
* @param {string} data.version - Semantic version string (e.g., '1.0.0').
|
|
115
|
+
* @returns {boolean} - True if the module version is supported.
|
|
116
|
+
*/
|
|
117
|
+
function validVersionSupport(data) {
|
|
118
|
+
const { name, version } = data;
|
|
119
|
+
const constraint = internalStore.allow[name];
|
|
120
|
+
if (constraint && version) {
|
|
121
|
+
const arrVersion = version.split('.');
|
|
122
|
+
if (arrVersion.length >= 1) {
|
|
123
|
+
if (constraint.major !== undefined && arrVersion[0] && constraint.major > Number(arrVersion[0]))
|
|
124
|
+
return false;
|
|
125
|
+
if (constraint.minor !== undefined && arrVersion[1] && constraint.minor > Number(arrVersion[1]))
|
|
126
|
+
return false;
|
|
127
|
+
if (constraint.patch !== undefined && arrVersion[2] && constraint.patch > Number(arrVersion[2]))
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Registers an external module for DOM module integration.
|
|
136
|
+
* Validates version compatibility before storing.
|
|
137
|
+
* The registered module is then available to `createEventElement` and
|
|
138
|
+
* `removeElement` for declarative event binding and cleanup.
|
|
139
|
+
*
|
|
140
|
+
* @function domModuleExtends
|
|
141
|
+
* @param {Object} data - Module data.
|
|
142
|
+
* @param {string} data.name - Module identifier stored as key.
|
|
143
|
+
* @param {string} data.version - Module version for compatibility check.
|
|
144
|
+
* @returns {boolean} - True if registration was successful.
|
|
145
|
+
*/
|
|
146
|
+
function domModuleExtends(data) {
|
|
147
|
+
try {
|
|
148
|
+
const { name } = data;
|
|
149
|
+
if (validVersionSupport(data)) {
|
|
150
|
+
internalStore.register[name] = data;
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Returns the first registered extension, regardless of name.
|
|
161
|
+
* Used by struct.ts to find the EventModule without knowing its name.
|
|
162
|
+
*
|
|
163
|
+
* @function getAnyExtension
|
|
164
|
+
* @returns {Object|undefined} - The first registered module, or undefined.
|
|
165
|
+
*/
|
|
166
|
+
function getAnyExtension() {
|
|
167
|
+
for (const key of Object.keys(internalStore.register)) {
|
|
168
|
+
return internalStore.register[key];
|
|
169
|
+
}
|
|
170
|
+
return undefined;
|
|
171
|
+
}/**
|
|
172
|
+
* @module DomAttributeModule
|
|
173
|
+
* @description
|
|
174
|
+
* Utility functions for setting standard and namespaced attributes on DOM elements.
|
|
175
|
+
*/
|
|
176
|
+
/**
|
|
177
|
+
* Sets standard attributes on a DOM element.
|
|
178
|
+
* Iterates the attributes array and calls `element.setAttribute` for each entry.
|
|
179
|
+
*
|
|
180
|
+
* @function setAttr
|
|
181
|
+
* @param {Object} data - Attribute data.
|
|
182
|
+
* @param {HTMLElement|SVGElement} data.element - The target element.
|
|
183
|
+
* @param {Array<{name: string, value: string}>} data.attrs - Array of attribute name/value pairs.
|
|
184
|
+
*/
|
|
185
|
+
function setAttr(data) {
|
|
186
|
+
const { element, attrs } = data;
|
|
187
|
+
if (!attrs || attrs.length === 0)
|
|
188
|
+
return;
|
|
189
|
+
for (let i = attrs.length - 1; i >= 0; i--) {
|
|
190
|
+
const item = attrs[i];
|
|
191
|
+
if (item?.name) {
|
|
192
|
+
element.setAttribute(item.name, item.value);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Sets namespaced attributes on a DOM element (e.g., SVG attributes).
|
|
198
|
+
* Calls `element.setAttributeNS(null, name, value)` for each entry.
|
|
199
|
+
*
|
|
200
|
+
* @function setAttrNS
|
|
201
|
+
* @param {Object} data - Namespaced attribute data.
|
|
202
|
+
* @param {HTMLElement|SVGElement} data.element - The target element.
|
|
203
|
+
* @param {Array<{name: string, value: string}>} data.attrs - Array of attribute name/value pairs.
|
|
204
|
+
*/
|
|
205
|
+
function setAttrNS(data) {
|
|
206
|
+
const { element, attrs } = data;
|
|
207
|
+
if (!attrs || attrs.length === 0)
|
|
208
|
+
return;
|
|
209
|
+
for (let i = attrs.length - 1; i >= 0; i--) {
|
|
210
|
+
const item = attrs[i];
|
|
211
|
+
if (item?.name) {
|
|
212
|
+
element.setAttributeNS(null, item.name, item.value);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}/**
|
|
216
|
+
* @module DomDatasetModule
|
|
217
|
+
* @description
|
|
218
|
+
* Utility for setting dataset properties on DOM elements.
|
|
219
|
+
* When the dataset name is `state`, the element is automatically
|
|
220
|
+
* registered in the element store for later retrieval.
|
|
221
|
+
*/
|
|
222
|
+
/**
|
|
223
|
+
* Sets dataset properties on a DOM element.
|
|
224
|
+
* If a dataset entry has `name === 'state'`, the element is also
|
|
225
|
+
* registered in the element store using the state value as key.
|
|
226
|
+
*
|
|
227
|
+
* @function setData
|
|
228
|
+
* @param {Object} data - Dataset data.
|
|
229
|
+
* @param {HTMLElement|SVGElement} data.element - The target element.
|
|
230
|
+
* @param {Array<{name: string, value: string}>} data.dataset - Array of dataset name/value pairs.
|
|
231
|
+
*/
|
|
232
|
+
function setData(data) {
|
|
233
|
+
const { element, dataset } = data;
|
|
234
|
+
if (!dataset || dataset.length === 0)
|
|
235
|
+
return;
|
|
236
|
+
for (let i = dataset.length - 1; i >= 0; i--) {
|
|
237
|
+
const item = dataset[i];
|
|
238
|
+
if (item?.name) {
|
|
239
|
+
element.dataset[item.name] = item.value;
|
|
240
|
+
if (item.name === 'state') {
|
|
241
|
+
addElementToStore({ key: item.value, value: element });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}/**
|
|
246
|
+
* @module DomComponentModule
|
|
247
|
+
* @description
|
|
248
|
+
* Provides functions for creating and appending HTML and SVG elements.
|
|
249
|
+
* Handles attribute assignment, dataset configuration, and shadow DOM creation.
|
|
250
|
+
*/
|
|
251
|
+
/**
|
|
252
|
+
* Attaches a shadow root to an HTML element with the specified mode.
|
|
253
|
+
*
|
|
254
|
+
* @private
|
|
255
|
+
* @ignore
|
|
256
|
+
* @function attachShadow
|
|
257
|
+
* @param {HTMLElement} host - The element to attach the shadow root to.
|
|
258
|
+
* @param {'open'|'closed'} mode - The shadow DOM mode.
|
|
259
|
+
* @returns {ShadowRoot} The created shadow root.
|
|
260
|
+
*/
|
|
261
|
+
function attachShadow(host, mode) {
|
|
262
|
+
return host.attachShadow({ mode });
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Creates a shadow root from a string or object configuration.
|
|
266
|
+
* String mode creates a shadow root with that mode ('open'/'closed').
|
|
267
|
+
* Object mode can additionally include `styles` via CSSStyleSheet.
|
|
268
|
+
*
|
|
269
|
+
* @private
|
|
270
|
+
* @ignore
|
|
271
|
+
* @function createShadowFromConfig
|
|
272
|
+
* @param {HTMLElement} host - The element to attach the shadow root to.
|
|
273
|
+
* @param {ShadowConfig} shadow - Shadow configuration (string or object with mode/styles).
|
|
274
|
+
* @returns {ShadowRoot|undefined} The created shadow root, or undefined on failure.
|
|
275
|
+
*/
|
|
276
|
+
function createShadowFromConfig(host, shadow) {
|
|
277
|
+
if (typeof shadow === 'string') {
|
|
278
|
+
return attachShadow(host, shadow);
|
|
279
|
+
}
|
|
280
|
+
if (typeof shadow === 'object' && shadow !== null && 'mode' in shadow) {
|
|
281
|
+
const config = shadow;
|
|
282
|
+
const root = attachShadow(host, config.mode);
|
|
283
|
+
if (config.styles && typeof CSSStyleSheet !== 'undefined') {
|
|
284
|
+
try {
|
|
285
|
+
const sheet = new CSSStyleSheet();
|
|
286
|
+
sheet.replaceSync(config.styles);
|
|
287
|
+
root.adoptedStyleSheets = [sheet];
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return root;
|
|
293
|
+
}
|
|
294
|
+
return undefined;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Applies attributes, namespaced attributes, and dataset to an element.
|
|
298
|
+
*
|
|
299
|
+
* @private
|
|
300
|
+
* @ignore
|
|
301
|
+
* @function applyAttributes
|
|
302
|
+
* @param {HTMLElement|SVGElement} element - The target element.
|
|
303
|
+
* @param {Object} data - Element configuration with attr/attrNS/dataset arrays.
|
|
304
|
+
*/
|
|
305
|
+
function applyAttributes(element, data) {
|
|
306
|
+
if (data.attr?.length) {
|
|
307
|
+
setAttr({ element, attrs: data.attr });
|
|
308
|
+
}
|
|
309
|
+
if ('attrNS' in data && data.attrNS?.length) {
|
|
310
|
+
setAttrNS({ element, attrs: data.attrNS });
|
|
311
|
+
}
|
|
312
|
+
if (data.dataset?.length) {
|
|
313
|
+
setData({ element, dataset: data.dataset });
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Creates an HTML element and appends it to a parent.
|
|
318
|
+
* Supports attribute assignment, dataset configuration with automatic
|
|
319
|
+
* store registration, and optional shadow DOM creation.
|
|
320
|
+
*
|
|
321
|
+
* @function createHTMLElement
|
|
322
|
+
* @param {Object} [options] - Element creation options.
|
|
323
|
+
* @param {HTMLElement|ShadowRoot} [options.parent=document.body] - Parent element to append to.
|
|
324
|
+
* @param {Object} options.element - Element definition with type, attr, and dataset arrays.
|
|
325
|
+
* @param {string} options.element.type - HTML tag name (e.g., 'div', 'button').
|
|
326
|
+
* @param {Array} [options.element.attr] - Array of {name, value} attribute pairs.
|
|
327
|
+
* @param {Array} [options.element.dataset] - Array of {name, value} dataset pairs.
|
|
328
|
+
* @param {ShadowConfig} [options.shadow] - Shadow DOM configuration.
|
|
329
|
+
* @returns {HTMLElement|ShadowRoot|undefined} The created element, shadow root, or undefined on error.
|
|
330
|
+
*/
|
|
331
|
+
function createHTMLElement(data = {}) {
|
|
332
|
+
try {
|
|
333
|
+
const { parent, element: elementData, shadow } = data;
|
|
334
|
+
const element = document.createElement(elementData.type);
|
|
335
|
+
applyAttributes(element, elementData);
|
|
336
|
+
const targetParent = parent ?? document.body;
|
|
337
|
+
if (targetParent instanceof HTMLElement || targetParent instanceof SVGElement || targetParent instanceof ShadowRoot) {
|
|
338
|
+
targetParent.appendChild(element);
|
|
339
|
+
}
|
|
340
|
+
if (shadow && element.dataset?.state) {
|
|
341
|
+
const shadowRoot = createShadowFromConfig(element, shadow);
|
|
342
|
+
if (shadowRoot)
|
|
343
|
+
return shadowRoot;
|
|
344
|
+
}
|
|
345
|
+
return element;
|
|
346
|
+
}
|
|
347
|
+
catch (err) {
|
|
348
|
+
console.error(err);
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Creates an SVG element and appends it to a parent.
|
|
354
|
+
* Supports standard and namespaced attributes, and dataset configuration.
|
|
355
|
+
*
|
|
356
|
+
* @function createSVGElement
|
|
357
|
+
* @param {Object} [options] - Element creation options.
|
|
358
|
+
* @param {SVGElement|HTMLElement} [options.parent] - Parent element to append to.
|
|
359
|
+
* @param {Object} options.element - Element definition.
|
|
360
|
+
* @param {string} options.element.type - SVG tag name (e.g., 'circle', 'rect').
|
|
361
|
+
* @param {Array} [options.element.attr] - Array of {name, value} attribute pairs.
|
|
362
|
+
* @param {Array} [options.element.attrNS] - Array of {name, value} namespaced attribute pairs.
|
|
363
|
+
* @param {Array} [options.element.dataset] - Array of {name, value} dataset pairs.
|
|
364
|
+
* @returns {SVGElement|undefined} The created SVG element, or undefined on error.
|
|
365
|
+
*/
|
|
366
|
+
function createSVGElement(data = {}) {
|
|
367
|
+
try {
|
|
368
|
+
const { parent, element: elementData } = data;
|
|
369
|
+
const element = document.createElementNS('http://www.w3.org/2000/svg', elementData.type);
|
|
370
|
+
applyAttributes(element, elementData);
|
|
371
|
+
if (parent) {
|
|
372
|
+
if (parent instanceof HTMLElement || parent instanceof SVGElement) {
|
|
373
|
+
parent.appendChild(element);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return element;
|
|
377
|
+
}
|
|
378
|
+
catch (err) {
|
|
379
|
+
console.error(err);
|
|
380
|
+
return undefined;
|
|
381
|
+
}
|
|
382
|
+
}/**
|
|
383
|
+
* @module DomStructModule
|
|
384
|
+
* @description
|
|
385
|
+
* Provides declarative DOM tree construction from structured data (ElementStruct)
|
|
386
|
+
* and element removal with recursive event listener cleanup.
|
|
387
|
+
* Integrates with EventModule via the extension system for declarative event binding.
|
|
388
|
+
*/
|
|
389
|
+
/**
|
|
390
|
+
* Creates an event listener on a DOM element based on struct configuration.
|
|
391
|
+
* Reads the `EventModule` from registered extensions, looks up the action
|
|
392
|
+
* by name in `EventActions`, and attaches the listener via `addEventToStore`.
|
|
393
|
+
*
|
|
394
|
+
* @private
|
|
395
|
+
* @ignore
|
|
396
|
+
* @function createEventElement
|
|
397
|
+
* @param {Object} data - Event binding data.
|
|
398
|
+
* @param {ElementStruct} data.struct - The element struct containing event config.
|
|
399
|
+
* @param {Element} data.element - The DOM element to attach the listener to.
|
|
400
|
+
*/
|
|
401
|
+
function createEventElement(data) {
|
|
402
|
+
const { struct, element } = data;
|
|
403
|
+
const eventModule = getAnyExtension();
|
|
404
|
+
if (!eventModule)
|
|
405
|
+
return;
|
|
406
|
+
if (struct.event?.action && struct.event?.type) {
|
|
407
|
+
const eventActions = eventModule.EventActions;
|
|
408
|
+
if (eventActions && eventActions[struct.event.action]) {
|
|
409
|
+
const eventStoreSchema = {
|
|
410
|
+
element,
|
|
411
|
+
type: struct.event.type,
|
|
412
|
+
handler: eventActions[struct.event.action],
|
|
413
|
+
};
|
|
414
|
+
if (struct.event.node)
|
|
415
|
+
eventStoreSchema.nodeId = struct.event.node;
|
|
416
|
+
const addEvent = eventModule.addEventToStore;
|
|
417
|
+
addEvent(eventStoreSchema);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Builds a DOM tree from a structured definition.
|
|
423
|
+
* Creates the root element, applies attributes, text, HTML content,
|
|
424
|
+
* optional event bindings, and recursively creates children.
|
|
425
|
+
*
|
|
426
|
+
* @function createFromStruct
|
|
427
|
+
* @param {Object} data - Struct data.
|
|
428
|
+
* @param {ElementStruct} data.struct - The element structure definition.
|
|
429
|
+
* @param {HTMLElement|ShadowRoot} [data.parent=document.body] - Parent element to append to.
|
|
430
|
+
* @returns {Element|false} The created element, or false on failure.
|
|
431
|
+
*/
|
|
432
|
+
function createFromStruct(data) {
|
|
433
|
+
try {
|
|
434
|
+
if (typeof data !== 'object' || !data)
|
|
435
|
+
return false;
|
|
436
|
+
const { struct, parent = document.body } = data;
|
|
437
|
+
if (!struct?.element)
|
|
438
|
+
return false;
|
|
439
|
+
const isSvg = struct.type && struct.type.toLowerCase() === 'svg';
|
|
440
|
+
const attrArray = struct.attr ? Object.entries(struct.attr).map(([name, value]) => ({ name, value })) : [];
|
|
441
|
+
const datasetArray = struct.dataset ? Object.entries(struct.dataset).map(([name, value]) => ({ name, value })) : [];
|
|
442
|
+
let element;
|
|
443
|
+
if (isSvg) {
|
|
444
|
+
const attrNSArray = struct.attrNS ? Object.entries(struct.attrNS).map(([name, value]) => ({ name, value })) : [];
|
|
445
|
+
const svgData = {
|
|
446
|
+
parent: parent,
|
|
447
|
+
element: {
|
|
448
|
+
type: struct.element,
|
|
449
|
+
attr: attrArray,
|
|
450
|
+
attrNS: attrNSArray,
|
|
451
|
+
dataset: datasetArray,
|
|
452
|
+
},
|
|
453
|
+
};
|
|
454
|
+
element = createSVGElement(svgData);
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
const htmlData = {
|
|
458
|
+
parent: parent,
|
|
459
|
+
element: {
|
|
460
|
+
type: struct.element,
|
|
461
|
+
attr: attrArray,
|
|
462
|
+
dataset: datasetArray,
|
|
463
|
+
},
|
|
464
|
+
shadow: struct.shadow,
|
|
465
|
+
};
|
|
466
|
+
const result = createHTMLElement(htmlData);
|
|
467
|
+
if (result instanceof ShadowRoot) {
|
|
468
|
+
element = result.host;
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
element = result;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
if (!element)
|
|
475
|
+
return false;
|
|
476
|
+
if (struct.text !== undefined) {
|
|
477
|
+
element.textContent = struct.text;
|
|
478
|
+
}
|
|
479
|
+
if (struct.html !== undefined) {
|
|
480
|
+
element.innerHTML = struct.html;
|
|
481
|
+
}
|
|
482
|
+
createEventElement({ struct, element });
|
|
483
|
+
if (struct.children && struct.children.length > 0) {
|
|
484
|
+
for (const child of struct.children) {
|
|
485
|
+
createFromStruct({ struct: child, parent: element });
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return element;
|
|
489
|
+
}
|
|
490
|
+
catch (err) {
|
|
491
|
+
console.error(err);
|
|
492
|
+
return false;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Attempts to clean up an element from the store or its event listeners.
|
|
497
|
+
* If the element has a `data-state` attribute, it removes it from the store
|
|
498
|
+
* (with event cleanup if EventModule is registered). Otherwise, if EventModule
|
|
499
|
+
* is available, it removes all event listeners from the element.
|
|
500
|
+
*
|
|
501
|
+
* @private
|
|
502
|
+
* @ignore
|
|
503
|
+
* @function removeElementFromStoreOrEvents
|
|
504
|
+
* @param {Element} element - The element to clean up.
|
|
505
|
+
* @returns {boolean} - True if cleanup was performed.
|
|
506
|
+
*/
|
|
507
|
+
function removeElementFromStoreOrEvents(element) {
|
|
508
|
+
try {
|
|
509
|
+
const eventModule = getAnyExtension();
|
|
510
|
+
const htmlElement = element;
|
|
511
|
+
if (htmlElement.dataset?.state) {
|
|
512
|
+
removeElementFromStore({ key: htmlElement.dataset.state, mode: eventModule ? 1 : 2, EventModule: eventModule });
|
|
513
|
+
return true;
|
|
514
|
+
}
|
|
515
|
+
if (eventModule && typeof eventModule.removeAllEventsFromStore === 'function') {
|
|
516
|
+
const removeAll = eventModule.removeAllEventsFromStore;
|
|
517
|
+
removeAll(element);
|
|
518
|
+
return true;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
catch {
|
|
522
|
+
}
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Removes a DOM element and recursively cleans up its children.
|
|
527
|
+
* For each element with `[listener="true"]`, calls `removeAllEventsFromStore`.
|
|
528
|
+
* For each element with `[data-state]`, removes from the element store.
|
|
529
|
+
* Finally removes the element from the DOM.
|
|
530
|
+
*
|
|
531
|
+
* @function removeElement
|
|
532
|
+
* @param {Element} element - The element to remove.
|
|
533
|
+
*/
|
|
534
|
+
function removeElement(element) {
|
|
535
|
+
if (!element)
|
|
536
|
+
return;
|
|
537
|
+
removeElementFromStoreOrEvents(element);
|
|
538
|
+
const listeners = element.querySelectorAll('[listener="true"]');
|
|
539
|
+
for (let i = listeners.length - 1; i >= 0; i--) {
|
|
540
|
+
const item = listeners[i];
|
|
541
|
+
if (item) {
|
|
542
|
+
removeElementFromStoreOrEvents(item);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
const withState = element.querySelectorAll('[data-state]');
|
|
546
|
+
for (let i = withState.length - 1; i >= 0; i--) {
|
|
547
|
+
const item = withState[i];
|
|
548
|
+
if (item) {
|
|
549
|
+
const eventModule = getAnyExtension();
|
|
550
|
+
removeElementFromStore({ key: item.dataset.state, mode: eventModule ? 1 : 2, EventModule: eventModule });
|
|
551
|
+
item.removeAttribute('data-state');
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
element.remove();
|
|
555
|
+
}/**
|
|
556
|
+
* @module DomModule
|
|
557
|
+
* @description
|
|
558
|
+
* Central module for DOM manipulation in @simplybuilder/core. Provides element
|
|
559
|
+
* creation, attribute management, declarative DOM tree construction, element
|
|
560
|
+
* removal with recursive event cleanup, and an extension system for optional
|
|
561
|
+
* integration with @simplybuilder/core-event.
|
|
562
|
+
*/
|
|
563
|
+
const name = "SBCoreDom";
|
|
564
|
+
const version = "2.0.0";
|
|
565
|
+
/**
|
|
566
|
+
* Frozen singleton combining all DOM manipulation capabilities.
|
|
567
|
+
* Pass `domModuleExtends()` to register an EventModule for declarative
|
|
568
|
+
* event binding in `createFromStruct` and automatic listener cleanup in `removeElement`.
|
|
569
|
+
*
|
|
570
|
+
* @type {Object}
|
|
571
|
+
* @property {string} name - Module identifier.
|
|
572
|
+
* @property {string} version - Module version.
|
|
573
|
+
* @property {Function} domModuleExtends - Register an extension module.
|
|
574
|
+
* @property {Function} createHTMLElement - Create and append HTML elements.
|
|
575
|
+
* @property {Function} createSVGElement - Create and append SVG elements.
|
|
576
|
+
* @property {Function} addElementToStore - Store element reference by key.
|
|
577
|
+
* @property {Function} getElementFromStore - Retrieve stored element.
|
|
578
|
+
* @property {Function} removeElementFromStore - Remove element from store.
|
|
579
|
+
* @property {Function} createFromStruct - Build DOM tree from struct definition.
|
|
580
|
+
* @property {Function} removeElement - Remove element with listener cleanup.
|
|
581
|
+
*/
|
|
582
|
+
const DomModule = Object.freeze({
|
|
583
|
+
name,
|
|
584
|
+
version,
|
|
585
|
+
domModuleExtends,
|
|
586
|
+
createHTMLElement,
|
|
587
|
+
createSVGElement,
|
|
588
|
+
addElementToStore,
|
|
589
|
+
getElementFromStore,
|
|
590
|
+
removeElementFromStore,
|
|
591
|
+
createFromStruct,
|
|
592
|
+
removeElement,
|
|
593
|
+
});export{DomModule,addElementToStore,clearStore,createEventElement,createFromStruct,createHTMLElement,createSVGElement,DomModule as default,domModuleExtends,getElementFromStore,name,removeElement,removeElementFromStore,setAttr,setAttrNS,setData,validVersionSupport,version};
|
|
594
|
+
/*! https://simplybuilder.github.io */
|
package/lib/store.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module DomStoreModule
|
|
3
|
+
* @description
|
|
4
|
+
* Key-value store for DOM element references. Elements can be registered
|
|
5
|
+
* by a string key and retrieved or removed later. Supports two removal modes:
|
|
6
|
+
* mode 1 (with EventModule cleanup) and mode 2 (store only).
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Registers a DOM element in the store under a unique key.
|
|
10
|
+
* If the key already exists, the operation is silently ignored.
|
|
11
|
+
*
|
|
12
|
+
* @function addElementToStore
|
|
13
|
+
* @param {Object} data - Registration data.
|
|
14
|
+
* @param {string} data.key - Unique identifier for the element.
|
|
15
|
+
* @param {Element} data.value - The DOM element to store.
|
|
16
|
+
*/
|
|
17
|
+
declare function addElementToStore(data: {
|
|
18
|
+
key: string;
|
|
19
|
+
value: Element;
|
|
20
|
+
}): void;
|
|
21
|
+
/**
|
|
22
|
+
* Retrieves a stored DOM element by its key.
|
|
23
|
+
*
|
|
24
|
+
* @function getElementFromStore
|
|
25
|
+
* @param {string} key - The element's unique key.
|
|
26
|
+
* @returns {Element|undefined} - The stored element, or undefined.
|
|
27
|
+
*/
|
|
28
|
+
declare function getElementFromStore(key: string): Element | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Removes a DOM element from the store by its key.
|
|
31
|
+
* In mode 1 (default), calls `EventModule.removeAllEventsFromStore`
|
|
32
|
+
* before deleting. In mode 2, deletes from store only.
|
|
33
|
+
*
|
|
34
|
+
* @function removeElementFromStore
|
|
35
|
+
* @param {Object} data - Removal data.
|
|
36
|
+
* @param {string} data.key - The element's unique key.
|
|
37
|
+
* @param {number} [data.mode=1] - Removal mode: 1 with event cleanup, 2 store only.
|
|
38
|
+
* @param {Object} [data.EventModule] - Optional EventModule for listener cleanup.
|
|
39
|
+
* @returns {boolean} - True if the element was found and removed.
|
|
40
|
+
*/
|
|
41
|
+
declare function removeElementFromStore(data: {
|
|
42
|
+
key: string;
|
|
43
|
+
mode?: number;
|
|
44
|
+
EventModule?: Record<string, unknown>;
|
|
45
|
+
}): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Removes all entries from the store. Used for testing.
|
|
48
|
+
*
|
|
49
|
+
* @function clearStore
|
|
50
|
+
*/
|
|
51
|
+
declare function clearStore(): void;
|
|
52
|
+
export { addElementToStore, getElementFromStore, removeElementFromStore, clearStore, };
|