@zolomedia/bifrost-client 1.7.74
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/L1_Foundation/L1_Foundation.js +13 -0
- package/L1_Foundation/bootstrap/bootstrap.js +11 -0
- package/L1_Foundation/bootstrap/bootstrap_hooks.js +123 -0
- package/L1_Foundation/bootstrap/bootstrap_index.js +15 -0
- package/L1_Foundation/bootstrap/bootstrap_logger.js +135 -0
- package/L1_Foundation/bootstrap/cdn_loader.js +217 -0
- package/L1_Foundation/bootstrap/module_registry.js +102 -0
- package/L1_Foundation/bootstrap/prism_loader.js +164 -0
- package/L1_Foundation/config/client_config.js +110 -0
- package/L1_Foundation/config/config.js +7 -0
- package/L1_Foundation/connection/connection.js +8 -0
- package/L1_Foundation/connection/websocket_connection.js +122 -0
- package/L1_Foundation/constants/bifrost_constants.js +284 -0
- package/L1_Foundation/constants/constants.js +7 -0
- package/L1_Foundation/logger/logger.js +10 -0
- package/L2_Handling/L2_Handling.js +15 -0
- package/L2_Handling/cache/cache.js +22 -0
- package/L2_Handling/cache/cache_constants.js +69 -0
- package/L2_Handling/cache/orchestration/cache_manager.js +299 -0
- package/L2_Handling/cache/orchestration/cache_orchestrator.js +260 -0
- package/L2_Handling/cache/orchestration/orchestration.js +12 -0
- package/L2_Handling/cache/storage/session_manager.js +289 -0
- package/L2_Handling/cache/storage/storage.js +10 -0
- package/L2_Handling/cache/storage/storage_manager.js +590 -0
- package/L2_Handling/display/composite/composite.js +13 -0
- package/L2_Handling/display/composite/dashboard_renderer.js +221 -0
- package/L2_Handling/display/composite/swiper_renderer.js +564 -0
- package/L2_Handling/display/composite/terminal_renderer.js +922 -0
- package/L2_Handling/display/composite/wizard_conditional_renderer.js +274 -0
- package/L2_Handling/display/display.js +30 -0
- package/L2_Handling/display/feedback/feedback.js +11 -0
- package/L2_Handling/display/feedback/progressbar_renderer.js +418 -0
- package/L2_Handling/display/feedback/spinner_renderer.js +246 -0
- package/L2_Handling/display/inputs/button_renderer.js +634 -0
- package/L2_Handling/display/inputs/form_renderer.js +583 -0
- package/L2_Handling/display/inputs/input_renderer.js +658 -0
- package/L2_Handling/display/inputs/inputs.js +12 -0
- package/L2_Handling/display/navigation/menu_renderer.js +206 -0
- package/L2_Handling/display/navigation/navigation.js +11 -0
- package/L2_Handling/display/navigation/navigation_renderer.js +703 -0
- package/L2_Handling/display/orchestration/orchestration.js +11 -0
- package/L2_Handling/display/orchestration/renderer.js +430 -0
- package/L2_Handling/display/orchestration/zdisplay_orchestrator.js +1759 -0
- package/L2_Handling/display/outputs/alert_renderer.js +161 -0
- package/L2_Handling/display/outputs/audio_renderer.js +94 -0
- package/L2_Handling/display/outputs/card_renderer.js +229 -0
- package/L2_Handling/display/outputs/code_renderer.js +66 -0
- package/L2_Handling/display/outputs/dl_renderer.js +131 -0
- package/L2_Handling/display/outputs/header_renderer.js +162 -0
- package/L2_Handling/display/outputs/icon_renderer.js +107 -0
- package/L2_Handling/display/outputs/image_renderer.js +145 -0
- package/L2_Handling/display/outputs/list_renderer.js +190 -0
- package/L2_Handling/display/outputs/outputs.js +19 -0
- package/L2_Handling/display/outputs/table_renderer.js +765 -0
- package/L2_Handling/display/outputs/text_renderer.js +818 -0
- package/L2_Handling/display/outputs/typography_renderer.js +293 -0
- package/L2_Handling/display/outputs/video_renderer.js +116 -0
- package/L2_Handling/display/primitives/document_structure_primitives.js +319 -0
- package/L2_Handling/display/primitives/form_primitives.js +526 -0
- package/L2_Handling/display/primitives/generic_containers.js +109 -0
- package/L2_Handling/display/primitives/interactive_primitives.js +305 -0
- package/L2_Handling/display/primitives/link_primitives.js +552 -0
- package/L2_Handling/display/primitives/lists_primitives.js +262 -0
- package/L2_Handling/display/primitives/media_primitives.js +383 -0
- package/L2_Handling/display/primitives/primitives.js +19 -0
- package/L2_Handling/display/primitives/semantic_element_primitive.js +226 -0
- package/L2_Handling/display/primitives/table_primitives.js +528 -0
- package/L2_Handling/display/primitives/typography_primitives.js +175 -0
- package/L2_Handling/display/specialized/input_request_renderer.js +467 -0
- package/L2_Handling/display/specialized/specialized.js +10 -0
- package/L2_Handling/hooks/hooks.js +9 -0
- package/L2_Handling/hooks/menu_integration.js +57 -0
- package/L2_Handling/hooks/widget_hook_manager.js +292 -0
- package/L2_Handling/message/message.js +8 -0
- package/L2_Handling/message/message_handler.js +701 -0
- package/L2_Handling/navigation/navigation.js +8 -0
- package/L2_Handling/navigation/navigation_manager.js +403 -0
- package/L2_Handling/zhooks/features/cache_live.js +287 -0
- package/L2_Handling/zhooks/features/crumbs_live.js +292 -0
- package/L2_Handling/zhooks/zhooks_manager.js +65 -0
- package/L2_Handling/zvaf/zvaf.js +8 -0
- package/L2_Handling/zvaf/zvaf_manager.js +334 -0
- package/L3_Abstraction/L3_Abstraction.js +12 -0
- package/L3_Abstraction/orchestrator/container_unwrapper.js +101 -0
- package/L3_Abstraction/orchestrator/group_renderer.js +698 -0
- package/L3_Abstraction/orchestrator/input_event_handler.js +797 -0
- package/L3_Abstraction/orchestrator/metadata_processor.js +249 -0
- package/L3_Abstraction/orchestrator/navbar_builder.js +201 -0
- package/L3_Abstraction/orchestrator/orchestrator.js +13 -0
- package/L3_Abstraction/orchestrator/wizard_gate_handler.js +360 -0
- package/L3_Abstraction/renderer/renderer.js +1 -0
- package/L3_Abstraction/session/session.js +1 -0
- package/L4_Orchestration/L4_Orchestration.js +11 -0
- package/L4_Orchestration/client/client.js +1 -0
- package/L4_Orchestration/facade/facade.js +9 -0
- package/L4_Orchestration/facade/manager_registry.js +118 -0
- package/L4_Orchestration/facade/renderer_registry.js +274 -0
- package/L4_Orchestration/lifecycle/asset_loader.js +255 -0
- package/L4_Orchestration/lifecycle/initializer.js +135 -0
- package/L4_Orchestration/lifecycle/lifecycle.js +8 -0
- package/L4_Orchestration/rendering/facade.js +94 -0
- package/L4_Orchestration/rendering/rendering.js +7 -0
- package/LICENSE +21 -0
- package/README.md +82 -0
- package/bifrost_client.js +204 -0
- package/bifrost_core.js +1686 -0
- package/docs/ARCHITECTURE.md +111 -0
- package/docs/PROTOCOL.md +106 -0
- package/docs/RENDERERS.md +101 -0
- package/docs/SECURITY.md +92 -0
- package/package.json +24 -0
- package/syntax/prism-zconfig.js +41 -0
- package/syntax/prism-zenv.js +69 -0
- package/syntax/prism-zolo-theme.css +288 -0
- package/syntax/prism-zolo.js +380 -0
- package/syntax/prism-zschema.js +38 -0
- package/syntax/prism-zspark.js +25 -0
- package/syntax/prism-zui.js +68 -0
- package/zSys/accessibility/accessibility.js +10 -0
- package/zSys/accessibility/emoji_accessibility.js +173 -0
- package/zSys/dom/block_utils.js +122 -0
- package/zSys/dom/container_utils.js +370 -0
- package/zSys/dom/dom.js +13 -0
- package/zSys/dom/dom_utils.js +328 -0
- package/zSys/dom/encoding_utils.js +117 -0
- package/zSys/dom/style_utils.js +71 -0
- package/zSys/errors/error_display.js +299 -0
- package/zSys/errors/errors.js +10 -0
- package/zSys/theme/color_utils.js +274 -0
- package/zSys/theme/dark_mode_utils.js +272 -0
- package/zSys/theme/size_utils.js +256 -0
- package/zSys/theme/spacing_utils.js +405 -0
- package/zSys/theme/theme.js +14 -0
- package/zSys/theme/zbase.css +1735 -0
- package/zSys/theme/zbase_inject.js +161 -0
- package/zSys/theme/ztheme_utils.js +305 -0
- package/zSys/validation/error_boundary.js +201 -0
- package/zSys/validation/validation.js +11 -0
- package/zSys/validation/validation_utils.js +238 -0
- package/zSys/zSys.js +14 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Container Utilities - Layout Primitives
|
|
4
|
+
*
|
|
5
|
+
*
|
|
6
|
+
* Pure functions for creating and managing layout containers.
|
|
7
|
+
* These are the TRUE primitives - before text, before headers, before anything.
|
|
8
|
+
*
|
|
9
|
+
* @module rendering/container_utils
|
|
10
|
+
* @layer 0 (Foundation - below Layer 2 utilities)
|
|
11
|
+
* @pattern Pure Functions (no state, no side effects)
|
|
12
|
+
*
|
|
13
|
+
* Philosophy:
|
|
14
|
+
* - "Container first" - Everything needs a home
|
|
15
|
+
* - Pure functions (input → output, no side effects)
|
|
16
|
+
* - Uses zTheme exclusively (no custom CSS)
|
|
17
|
+
* - Composable (containers can nest)
|
|
18
|
+
*
|
|
19
|
+
* Dependencies:
|
|
20
|
+
* - Layer 2: dom_utils.js
|
|
21
|
+
*
|
|
22
|
+
* Exports:
|
|
23
|
+
* - createContainer()
|
|
24
|
+
* - createSection()
|
|
25
|
+
* - createWrapper()
|
|
26
|
+
* - applyContainerStyles()
|
|
27
|
+
*
|
|
28
|
+
* Example:
|
|
29
|
+
* ```javascript
|
|
30
|
+
* import { createContainer, createWrapper } from './container_utils.js';
|
|
31
|
+
*
|
|
32
|
+
* const container = createContainer(['zContainer', 'zMy-4']);
|
|
33
|
+
* const flexWrapper = createWrapper(['zD-flex', 'zGap-3']);
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
// ─────────────────────────────────────────────────────────────────
|
|
38
|
+
// Imports
|
|
39
|
+
// ─────────────────────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
// Layer 2: Utilities
|
|
42
|
+
import { createElement, setAttributes } from './dom_utils.js';
|
|
43
|
+
|
|
44
|
+
//
|
|
45
|
+
// Container Creation Functions
|
|
46
|
+
//
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Create a main content container (zTheme: zContainer)
|
|
50
|
+
*
|
|
51
|
+
* A container is the primary layout element that provides:
|
|
52
|
+
* - Max width constraints
|
|
53
|
+
* - Horizontal centering
|
|
54
|
+
* - Responsive padding
|
|
55
|
+
*
|
|
56
|
+
* @param {Array<string>} [classes=[]] - Additional CSS classes to apply
|
|
57
|
+
* @param {Object} [attributes={}] - HTML attributes (id, data-*, etc.)
|
|
58
|
+
* @returns {HTMLElement} Div element with zContainer class
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* // Basic centered container
|
|
62
|
+
* const container = createContainer();
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* // Container with vertical margin
|
|
66
|
+
* const container = createContainer(['zMy-4']);
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* // Fluid container (full width)
|
|
70
|
+
* const fluidContainer = createContainer(['zContainer-fluid']);
|
|
71
|
+
*/
|
|
72
|
+
export function createContainer(classes = [], attributes = {}) {
|
|
73
|
+
const containerClasses = ['zContainer', ...classes];
|
|
74
|
+
const container = createElement('div', containerClasses);
|
|
75
|
+
|
|
76
|
+
if (Object.keys(attributes).length > 0) {
|
|
77
|
+
setAttributes(container, attributes);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return container;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Create a semantic section element
|
|
85
|
+
*
|
|
86
|
+
* Sections are semantic HTML5 elements for content grouping.
|
|
87
|
+
* Use for major page sections (hero, features, footer, etc.)
|
|
88
|
+
*
|
|
89
|
+
* @param {Array<string>} [classes=[]] - CSS classes to apply
|
|
90
|
+
* @param {Object} [attributes={}] - HTML attributes
|
|
91
|
+
* @returns {HTMLElement} Section element
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* // Hero section with background
|
|
95
|
+
* const hero = createSection(['zBg-primary', 'zText-white', 'zPy-5']);
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* // Feature section with ID
|
|
99
|
+
* const features = createSection(['zPy-4'], { id: 'features' });
|
|
100
|
+
*/
|
|
101
|
+
export function createSection(classes = [], attributes = {}) {
|
|
102
|
+
const section = createElement('section', classes);
|
|
103
|
+
|
|
104
|
+
if (Object.keys(attributes).length > 0) {
|
|
105
|
+
setAttributes(section, attributes);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return section;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Create a generic wrapper div (for grouping/layout)
|
|
113
|
+
*
|
|
114
|
+
* Wrappers are flexible divs for:
|
|
115
|
+
* - Grouping related elements
|
|
116
|
+
* - Applying flex/grid layouts
|
|
117
|
+
* - Creating visual boundaries
|
|
118
|
+
*
|
|
119
|
+
* @param {Array<string>} [classes=[]] - CSS classes to apply
|
|
120
|
+
* @param {Object} [attributes={}] - HTML attributes
|
|
121
|
+
* @returns {HTMLElement} Div element (no default classes)
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* // Flex row wrapper
|
|
125
|
+
* const row = createWrapper(['zD-flex', 'zGap-3', 'zFlex-items-center']);
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* // Grid wrapper
|
|
129
|
+
* const grid = createWrapper(['zD-grid', 'zGap-4'], { style: 'grid-template-columns: repeat(3, 1fr);' });
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* // Card body wrapper
|
|
133
|
+
* const cardBody = createWrapper(['zCard-body', 'zP-3']);
|
|
134
|
+
*/
|
|
135
|
+
export function createWrapper(classes = [], attributes = {}) {
|
|
136
|
+
const wrapper = createElement('div', classes);
|
|
137
|
+
|
|
138
|
+
if (Object.keys(attributes).length > 0) {
|
|
139
|
+
setAttributes(wrapper, attributes);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return wrapper;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
//
|
|
146
|
+
// Container Styling Functions
|
|
147
|
+
//
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Apply container-specific styles via config object
|
|
151
|
+
*
|
|
152
|
+
* This is a higher-level function for applying multiple style concerns at once.
|
|
153
|
+
* Useful when you need to apply layout, display, and alignment in one call.
|
|
154
|
+
*
|
|
155
|
+
* @param {HTMLElement} element - Element to style
|
|
156
|
+
* @param {Object} config - Style configuration
|
|
157
|
+
* @param {string} [config.display] - Display mode (flex, grid, block, inline-block)
|
|
158
|
+
* @param {string} [config.direction] - Flex direction (row, column)
|
|
159
|
+
* @param {string} [config.align] - Alignment (start, center, end, stretch)
|
|
160
|
+
* @param {string} [config.justify] - Justification (start, center, end, between, around)
|
|
161
|
+
* @param {number} [config.gap] - Gap size (0-5)
|
|
162
|
+
* @param {boolean} [config.wrap] - Enable flex wrap
|
|
163
|
+
* @returns {HTMLElement} Element with styles applied
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* // Create a flex container with centering
|
|
167
|
+
* const wrapper = createWrapper();
|
|
168
|
+
* applyContainerStyles(wrapper, {
|
|
169
|
+
* display: 'flex',
|
|
170
|
+
* direction: 'row',
|
|
171
|
+
* align: 'center',
|
|
172
|
+
* justify: 'between',
|
|
173
|
+
* gap: 3
|
|
174
|
+
* });
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* // Create a grid container
|
|
178
|
+
* const grid = createWrapper();
|
|
179
|
+
* applyContainerStyles(grid, {
|
|
180
|
+
* display: 'grid',
|
|
181
|
+
* gap: 4
|
|
182
|
+
* });
|
|
183
|
+
*/
|
|
184
|
+
export function applyContainerStyles(element, config = {}) {
|
|
185
|
+
const classes = [];
|
|
186
|
+
|
|
187
|
+
// Display mode
|
|
188
|
+
if (config.display) {
|
|
189
|
+
const displayMap = {
|
|
190
|
+
'flex': 'zD-flex',
|
|
191
|
+
'grid': 'zD-grid',
|
|
192
|
+
'block': 'zD-block',
|
|
193
|
+
'inline-block': 'zD-inline-block',
|
|
194
|
+
'none': 'zD-none'
|
|
195
|
+
};
|
|
196
|
+
const displayClass = displayMap[config.display];
|
|
197
|
+
if (displayClass) {
|
|
198
|
+
classes.push(displayClass);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Flex direction (only applies if display is flex)
|
|
203
|
+
if (config.direction && config.display === 'flex') {
|
|
204
|
+
const directionMap = {
|
|
205
|
+
'row': 'zFlex-row',
|
|
206
|
+
'column': 'zFlex-column',
|
|
207
|
+
'row-reverse': 'zFlex-row-reverse',
|
|
208
|
+
'column-reverse': 'zFlex-column-reverse'
|
|
209
|
+
};
|
|
210
|
+
const directionClass = directionMap[config.direction];
|
|
211
|
+
if (directionClass) {
|
|
212
|
+
classes.push(directionClass);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Alignment (align-items - vertical alignment in row, horizontal in column)
|
|
217
|
+
if (config.align) {
|
|
218
|
+
const alignMap = {
|
|
219
|
+
'start': 'zFlex-items-start',
|
|
220
|
+
'center': 'zFlex-items-center',
|
|
221
|
+
'end': 'zFlex-items-end',
|
|
222
|
+
'stretch': 'zFlex-items-stretch',
|
|
223
|
+
'baseline': 'zFlex-items-baseline'
|
|
224
|
+
};
|
|
225
|
+
const alignClass = alignMap[config.align];
|
|
226
|
+
if (alignClass) {
|
|
227
|
+
classes.push(alignClass);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Justification (justify-content - horizontal alignment in row, vertical in column)
|
|
232
|
+
if (config.justify) {
|
|
233
|
+
const justifyMap = {
|
|
234
|
+
'start': 'zFlex-start',
|
|
235
|
+
'center': 'zFlex-center',
|
|
236
|
+
'end': 'zFlex-end',
|
|
237
|
+
'between': 'zFlex-between',
|
|
238
|
+
'around': 'zFlex-around',
|
|
239
|
+
'evenly': 'zFlex-evenly'
|
|
240
|
+
};
|
|
241
|
+
const justifyClass = justifyMap[config.justify];
|
|
242
|
+
if (justifyClass) {
|
|
243
|
+
classes.push(justifyClass);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Gap
|
|
248
|
+
if (typeof config.gap === 'number' && config.gap >= 0 && config.gap <= 5) {
|
|
249
|
+
classes.push(`zGap-${config.gap}`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Flex wrap
|
|
253
|
+
if (config.wrap) {
|
|
254
|
+
classes.push('zFlex-wrap');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Apply all classes at once
|
|
258
|
+
if (classes.length > 0) {
|
|
259
|
+
element.classList.add(...classes);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return element;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
//
|
|
266
|
+
// Flex Utility Functions (for programmatic class generation)
|
|
267
|
+
//
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Get zTheme flex justify-content class (horizontal alignment)
|
|
271
|
+
* @param {string} justify - Justify: 'start', 'center', 'end', 'between', 'around', 'evenly'
|
|
272
|
+
* @returns {string} zTheme justify class
|
|
273
|
+
*/
|
|
274
|
+
export function getFlexJustifyClass(justify = 'start') {
|
|
275
|
+
const justifyMap = {
|
|
276
|
+
start: 'zFlex-start',
|
|
277
|
+
center: 'zFlex-center',
|
|
278
|
+
end: 'zFlex-end',
|
|
279
|
+
between: 'zFlex-between',
|
|
280
|
+
around: 'zFlex-around',
|
|
281
|
+
evenly: 'zFlex-evenly'
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
return justifyMap[justify] || 'zFlex-start';
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Get zTheme flex align-items class (vertical alignment)
|
|
289
|
+
* @param {string} align - Align: 'start', 'center', 'end', 'stretch', 'baseline'
|
|
290
|
+
* @returns {string} zTheme align class
|
|
291
|
+
*/
|
|
292
|
+
export function getFlexAlignClass(align = 'stretch') {
|
|
293
|
+
const alignMap = {
|
|
294
|
+
start: 'zFlex-items-start',
|
|
295
|
+
center: 'zFlex-items-center',
|
|
296
|
+
end: 'zFlex-items-end',
|
|
297
|
+
stretch: 'zFlex-items-stretch',
|
|
298
|
+
baseline: 'zFlex-items-baseline'
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
return alignMap[align] || 'zFlex-items-stretch';
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Get zTheme flex direction class
|
|
306
|
+
* @param {string} direction - Direction: 'row', 'column', 'row-reverse', 'column-reverse'
|
|
307
|
+
* @returns {string} zTheme flex direction class
|
|
308
|
+
*/
|
|
309
|
+
export function getFlexDirectionClass(direction = 'row') {
|
|
310
|
+
const directionMap = {
|
|
311
|
+
row: 'zFlex-row',
|
|
312
|
+
column: 'zFlex-column',
|
|
313
|
+
'row-reverse': 'zFlex-row-reverse',
|
|
314
|
+
'column-reverse': 'zFlex-column-reverse'
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
return directionMap[direction] || 'zFlex-row';
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Create a container element for a zKey with metadata support
|
|
322
|
+
* @param {string} zKey - The zKey identifier
|
|
323
|
+
* @param {Object} metadata - Metadata object (may contain _zClass, _zHTML)
|
|
324
|
+
* @returns {Promise<HTMLElement>} Container element (div by default, or semantic element if _zHTML is specified)
|
|
325
|
+
*/
|
|
326
|
+
export async function createZKeyContainer(zKey, metadata = {}) {
|
|
327
|
+
// Use centralized semantic element primitive (SSOT for _zHTML)
|
|
328
|
+
const { createSemanticElement } = await import('../../L2_Handling/display/primitives/semantic_element_primitive.js');
|
|
329
|
+
const elementType = metadata._zHTML || 'div';
|
|
330
|
+
const container = createSemanticElement(elementType);
|
|
331
|
+
|
|
332
|
+
// Check for custom classes in metadata
|
|
333
|
+
if (metadata._zClass !== undefined) {
|
|
334
|
+
if (metadata._zClass === '' || metadata._zClass === null) {
|
|
335
|
+
// Empty string or null = no container classes (opt-out)
|
|
336
|
+
container.className = '';
|
|
337
|
+
} else {
|
|
338
|
+
// Apply custom classes
|
|
339
|
+
const classes = Array.isArray(metadata._zClass)
|
|
340
|
+
? metadata._zClass
|
|
341
|
+
: metadata._zClass.split(',').map(c => c.trim());
|
|
342
|
+
container.className = classes.join(' ');
|
|
343
|
+
}
|
|
344
|
+
} else {
|
|
345
|
+
// Default: responsive zTheme container
|
|
346
|
+
container.className = 'zContainer-fluid zp-2';
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Set data attribute for debugging
|
|
350
|
+
container.setAttribute('data-zkey', zKey);
|
|
351
|
+
// Set id for DevTools navigation and CSS targeting
|
|
352
|
+
container.setAttribute('id', zKey);
|
|
353
|
+
|
|
354
|
+
return container;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
//
|
|
358
|
+
// Default Export (for convenience)
|
|
359
|
+
//
|
|
360
|
+
export default {
|
|
361
|
+
createContainer,
|
|
362
|
+
createSection,
|
|
363
|
+
createWrapper,
|
|
364
|
+
applyContainerStyles,
|
|
365
|
+
getFlexJustifyClass,
|
|
366
|
+
getFlexAlignClass,
|
|
367
|
+
getFlexDirectionClass,
|
|
368
|
+
createZKeyContainer
|
|
369
|
+
};
|
|
370
|
+
|
package/zSys/dom/dom.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* zSys/dom - DOM Utilities Barrel
|
|
3
|
+
*
|
|
4
|
+
* DOM manipulation utilities (element creation, containers, blocks, encoding).
|
|
5
|
+
*
|
|
6
|
+
* @module zSys/dom
|
|
7
|
+
* @layer zSys (System Utilities)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export * from './block_utils.js';
|
|
11
|
+
export * from './container_utils.js';
|
|
12
|
+
export * from './dom_utils.js';
|
|
13
|
+
export * from './encoding_utils.js';
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* DOM Utilities - Pure DOM Manipulation Functions
|
|
4
|
+
*
|
|
5
|
+
*
|
|
6
|
+
* Pure functions for DOM manipulation. Zero dependencies, zero state,
|
|
7
|
+
* zero side effects (except the DOM operations themselves).
|
|
8
|
+
*
|
|
9
|
+
* @module utils/dom_utils
|
|
10
|
+
* @layer 2
|
|
11
|
+
* @pattern Pure Functions
|
|
12
|
+
*
|
|
13
|
+
* Dependencies:
|
|
14
|
+
* - Layer 0: Browser DOM APIs only
|
|
15
|
+
*
|
|
16
|
+
* Exports:
|
|
17
|
+
* - createElement: Create element with classes and attributes
|
|
18
|
+
* - safeQuery: Safe querySelector (returns null instead of throwing)
|
|
19
|
+
* - safeQueryAll: Safe querySelectorAll (returns array instead of NodeList)
|
|
20
|
+
* - clearElement: Clear element content safely
|
|
21
|
+
* - appendChildren: Append multiple children at once
|
|
22
|
+
* - removeElement: Remove element safely (checks parent exists)
|
|
23
|
+
* - replaceElement: Replace element with another
|
|
24
|
+
* - setAttributes: Set multiple attributes at once
|
|
25
|
+
* - toggleClasses: Toggle multiple classes at once
|
|
26
|
+
* - createTextNode: Create text node (safe alternative to textContent)
|
|
27
|
+
*
|
|
28
|
+
* Example:
|
|
29
|
+
* ```javascript
|
|
30
|
+
* import { createElement, appendChildren } from './dom_utils.js';
|
|
31
|
+
*
|
|
32
|
+
* const button = createElement('button', ['zBtn', 'zBtnPrimary'], { type: 'button' });
|
|
33
|
+
* const icon = createElement('i', ['bi', 'bi-check']);
|
|
34
|
+
* appendChildren(button, [icon, createTextNode('Submit')]);
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
//
|
|
39
|
+
// DOM Creation & Manipulation
|
|
40
|
+
//
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Create an HTML element with classes and attributes
|
|
44
|
+
*
|
|
45
|
+
* @param {string} tag - HTML tag name (e.g., 'div', 'button', 'input')
|
|
46
|
+
* @param {string[]} [classNames=[]] - Array of CSS class names to add
|
|
47
|
+
* @param {Object} [attributes={}] - HTML attributes to set {id, type, disabled, etc}
|
|
48
|
+
* @returns {HTMLElement} Created element
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* const button = createElement('button', ['zBtn', 'zBtnPrimary'], {
|
|
52
|
+
* type: 'button',
|
|
53
|
+
* id: 'submit-btn',
|
|
54
|
+
* disabled: false
|
|
55
|
+
* });
|
|
56
|
+
*
|
|
57
|
+
* @throws {Error} If tag is empty or invalid
|
|
58
|
+
*/
|
|
59
|
+
export function createElement(tag, classNames = [], attributes = {}) {
|
|
60
|
+
if (!tag || typeof tag !== 'string') {
|
|
61
|
+
throw new Error('[createElement] tag must be a non-empty string');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const element = document.createElement(tag);
|
|
65
|
+
|
|
66
|
+
// Add classes
|
|
67
|
+
if (classNames && classNames.length > 0) {
|
|
68
|
+
element.classList.add(...classNames);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Set attributes
|
|
72
|
+
if (attributes && typeof attributes === 'object') {
|
|
73
|
+
setAttributes(element, attributes);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return element;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Create a text node (safe alternative to textContent)
|
|
81
|
+
*
|
|
82
|
+
* @param {string} text - Text content
|
|
83
|
+
* @returns {Text} Text node
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* const textNode = createTextNode('Hello, World!');
|
|
87
|
+
* element.appendChild(textNode);
|
|
88
|
+
*/
|
|
89
|
+
export function createTextNode(text) {
|
|
90
|
+
return document.createTextNode(text || '');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
//
|
|
94
|
+
// DOM Querying
|
|
95
|
+
//
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Safe querySelector (returns null instead of throwing)
|
|
99
|
+
*
|
|
100
|
+
* @param {string} selector - CSS selector
|
|
101
|
+
* @param {Element|Document} [context=document] - Search context
|
|
102
|
+
* @returns {Element|null} Found element or null
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* const element = safeQuery('#my-element');
|
|
106
|
+
* if (element) {
|
|
107
|
+
* element.classList.add('active');
|
|
108
|
+
* }
|
|
109
|
+
*/
|
|
110
|
+
export function safeQuery(selector, context = document) {
|
|
111
|
+
try {
|
|
112
|
+
return context.querySelector(selector);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
this.logger.warn(`[safeQuery] Invalid selector: ${selector}`, error);
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Safe querySelectorAll (returns array instead of NodeList)
|
|
121
|
+
*
|
|
122
|
+
* @param {string} selector - CSS selector
|
|
123
|
+
* @param {Element|Document} [context=document] - Search context
|
|
124
|
+
* @returns {Element[]} Array of found elements (empty if none found)
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* const buttons = safeQueryAll('.zBtn');
|
|
128
|
+
* buttons.forEach(btn => btn.disabled = true);
|
|
129
|
+
*/
|
|
130
|
+
export function safeQueryAll(selector, context = document) {
|
|
131
|
+
try {
|
|
132
|
+
return Array.from(context.querySelectorAll(selector));
|
|
133
|
+
} catch (error) {
|
|
134
|
+
this.logger.warn(`[safeQueryAll] Invalid selector: ${selector}`, error);
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
//
|
|
140
|
+
// DOM Modification
|
|
141
|
+
//
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Clear element content safely
|
|
145
|
+
*
|
|
146
|
+
* @param {Element} element - Element to clear
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* const container = document.getElementById('content');
|
|
150
|
+
* clearElement(container);
|
|
151
|
+
*/
|
|
152
|
+
export function clearElement(element) {
|
|
153
|
+
if (!element) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Remove all children
|
|
158
|
+
while (element.firstChild) {
|
|
159
|
+
element.removeChild(element.firstChild);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Append multiple children to a parent element at once
|
|
165
|
+
*
|
|
166
|
+
* @param {Element} parent - Parent element
|
|
167
|
+
* @param {(Element|Text)[]} [children=[]] - Array of child elements or text nodes
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* const container = createElement('div');
|
|
171
|
+
* const header = createElement('h1');
|
|
172
|
+
* const paragraph = createElement('p');
|
|
173
|
+
* appendChildren(container, [header, paragraph]);
|
|
174
|
+
*/
|
|
175
|
+
export function appendChildren(parent, children = []) {
|
|
176
|
+
if (!parent || !Array.isArray(children)) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
children.forEach(child => {
|
|
181
|
+
if (child) {
|
|
182
|
+
parent.appendChild(child);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Remove element from DOM safely (checks if parent exists)
|
|
189
|
+
*
|
|
190
|
+
* @param {Element} element - Element to remove
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* const button = document.getElementById('old-button');
|
|
194
|
+
* removeElement(button);
|
|
195
|
+
*/
|
|
196
|
+
export function removeElement(element) {
|
|
197
|
+
if (element && element.parentNode) {
|
|
198
|
+
element.parentNode.removeChild(element);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Replace element with another element
|
|
204
|
+
*
|
|
205
|
+
* @param {Element} oldElement - Element to replace
|
|
206
|
+
* @param {Element} newElement - Replacement element
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* const oldButton = document.getElementById('old-btn');
|
|
210
|
+
* const newButton = createElement('button', ['zBtn', 'zBtnSuccess']);
|
|
211
|
+
* replaceElement(oldButton, newButton);
|
|
212
|
+
*/
|
|
213
|
+
export function replaceElement(oldElement, newElement) {
|
|
214
|
+
if (!oldElement || !newElement || !oldElement.parentNode) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
oldElement.parentNode.replaceChild(newElement, oldElement);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
//
|
|
222
|
+
// Attributes & Classes
|
|
223
|
+
//
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Set multiple attributes on an element at once
|
|
227
|
+
*
|
|
228
|
+
* @param {Element} element - Target element
|
|
229
|
+
* @param {Object} attributes - Attributes to set {name: value}
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* const input = createElement('input');
|
|
233
|
+
* setAttributes(input, {
|
|
234
|
+
* type: 'text',
|
|
235
|
+
* id: 'username',
|
|
236
|
+
* placeholder: 'Enter username',
|
|
237
|
+
* required: true
|
|
238
|
+
* });
|
|
239
|
+
*/
|
|
240
|
+
export function setAttributes(element, attributes = {}) {
|
|
241
|
+
if (!element || !attributes) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
Object.entries(attributes).forEach(([key, value]) => {
|
|
246
|
+
if (value === null || value === undefined) {
|
|
247
|
+
element.removeAttribute(key);
|
|
248
|
+
} else if (typeof value === 'boolean') {
|
|
249
|
+
// Handle boolean attributes (disabled, required, etc)
|
|
250
|
+
if (value) {
|
|
251
|
+
element.setAttribute(key, '');
|
|
252
|
+
} else {
|
|
253
|
+
element.removeAttribute(key);
|
|
254
|
+
}
|
|
255
|
+
} else {
|
|
256
|
+
element.setAttribute(key, value);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Toggle multiple classes on an element at once
|
|
263
|
+
*
|
|
264
|
+
* @param {Element} element - Target element
|
|
265
|
+
* @param {string[]} classes - Array of class names to toggle
|
|
266
|
+
* @param {boolean|null} [force=null] - Force add (true) or remove (false), or toggle (null)
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* // Toggle classes
|
|
270
|
+
* toggleClasses(button, ['active', 'highlighted']);
|
|
271
|
+
*
|
|
272
|
+
* // Force add classes
|
|
273
|
+
* toggleClasses(button, ['disabled', 'inactive'], true);
|
|
274
|
+
*
|
|
275
|
+
* // Force remove classes
|
|
276
|
+
* toggleClasses(button, ['active', 'highlighted'], false);
|
|
277
|
+
*/
|
|
278
|
+
export function toggleClasses(element, classes = [], force = null) {
|
|
279
|
+
if (!element || !Array.isArray(classes)) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
classes.forEach(className => {
|
|
284
|
+
if (className) {
|
|
285
|
+
if (force === null) {
|
|
286
|
+
element.classList.toggle(className);
|
|
287
|
+
} else {
|
|
288
|
+
element.classList.toggle(className, force);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
//
|
|
295
|
+
// Container Helpers (Layer 2 - Pure Utilities)
|
|
296
|
+
//
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Create a div element with optional attributes
|
|
300
|
+
*
|
|
301
|
+
* Utility function to create a div with attributes in one call.
|
|
302
|
+
* This is a Layer 2 (Utilities) function - pure, no business logic.
|
|
303
|
+
*
|
|
304
|
+
* @param {Object} [attributes={}] - Attributes to set on the div
|
|
305
|
+
* @returns {HTMLDivElement} The created div element
|
|
306
|
+
*
|
|
307
|
+
* @example
|
|
308
|
+
* // Simple div
|
|
309
|
+
* const container = createDiv();
|
|
310
|
+
*
|
|
311
|
+
* // Div with classes
|
|
312
|
+
* const card = createDiv({ class: 'zCard zCard-primary' });
|
|
313
|
+
*
|
|
314
|
+
* // Div with multiple attributes
|
|
315
|
+
* const item = createDiv({ 'data-item-id': '123', 'data-type': 'product' });
|
|
316
|
+
*
|
|
317
|
+
* // Div with ARIA attributes for accessibility
|
|
318
|
+
* const alert = createDiv({ role: 'alert', 'aria-live': 'polite' });
|
|
319
|
+
*/
|
|
320
|
+
export function createDiv(attributes = {}) {
|
|
321
|
+
const div = createElement('div');
|
|
322
|
+
|
|
323
|
+
if (Object.keys(attributes).length > 0) {
|
|
324
|
+
setAttributes(div, attributes);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return div;
|
|
328
|
+
}
|