@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.
Files changed (140) hide show
  1. package/L1_Foundation/L1_Foundation.js +13 -0
  2. package/L1_Foundation/bootstrap/bootstrap.js +11 -0
  3. package/L1_Foundation/bootstrap/bootstrap_hooks.js +123 -0
  4. package/L1_Foundation/bootstrap/bootstrap_index.js +15 -0
  5. package/L1_Foundation/bootstrap/bootstrap_logger.js +135 -0
  6. package/L1_Foundation/bootstrap/cdn_loader.js +217 -0
  7. package/L1_Foundation/bootstrap/module_registry.js +102 -0
  8. package/L1_Foundation/bootstrap/prism_loader.js +164 -0
  9. package/L1_Foundation/config/client_config.js +110 -0
  10. package/L1_Foundation/config/config.js +7 -0
  11. package/L1_Foundation/connection/connection.js +8 -0
  12. package/L1_Foundation/connection/websocket_connection.js +122 -0
  13. package/L1_Foundation/constants/bifrost_constants.js +284 -0
  14. package/L1_Foundation/constants/constants.js +7 -0
  15. package/L1_Foundation/logger/logger.js +10 -0
  16. package/L2_Handling/L2_Handling.js +15 -0
  17. package/L2_Handling/cache/cache.js +22 -0
  18. package/L2_Handling/cache/cache_constants.js +69 -0
  19. package/L2_Handling/cache/orchestration/cache_manager.js +299 -0
  20. package/L2_Handling/cache/orchestration/cache_orchestrator.js +260 -0
  21. package/L2_Handling/cache/orchestration/orchestration.js +12 -0
  22. package/L2_Handling/cache/storage/session_manager.js +289 -0
  23. package/L2_Handling/cache/storage/storage.js +10 -0
  24. package/L2_Handling/cache/storage/storage_manager.js +590 -0
  25. package/L2_Handling/display/composite/composite.js +13 -0
  26. package/L2_Handling/display/composite/dashboard_renderer.js +221 -0
  27. package/L2_Handling/display/composite/swiper_renderer.js +564 -0
  28. package/L2_Handling/display/composite/terminal_renderer.js +922 -0
  29. package/L2_Handling/display/composite/wizard_conditional_renderer.js +274 -0
  30. package/L2_Handling/display/display.js +30 -0
  31. package/L2_Handling/display/feedback/feedback.js +11 -0
  32. package/L2_Handling/display/feedback/progressbar_renderer.js +418 -0
  33. package/L2_Handling/display/feedback/spinner_renderer.js +246 -0
  34. package/L2_Handling/display/inputs/button_renderer.js +634 -0
  35. package/L2_Handling/display/inputs/form_renderer.js +583 -0
  36. package/L2_Handling/display/inputs/input_renderer.js +658 -0
  37. package/L2_Handling/display/inputs/inputs.js +12 -0
  38. package/L2_Handling/display/navigation/menu_renderer.js +206 -0
  39. package/L2_Handling/display/navigation/navigation.js +11 -0
  40. package/L2_Handling/display/navigation/navigation_renderer.js +703 -0
  41. package/L2_Handling/display/orchestration/orchestration.js +11 -0
  42. package/L2_Handling/display/orchestration/renderer.js +430 -0
  43. package/L2_Handling/display/orchestration/zdisplay_orchestrator.js +1759 -0
  44. package/L2_Handling/display/outputs/alert_renderer.js +161 -0
  45. package/L2_Handling/display/outputs/audio_renderer.js +94 -0
  46. package/L2_Handling/display/outputs/card_renderer.js +229 -0
  47. package/L2_Handling/display/outputs/code_renderer.js +66 -0
  48. package/L2_Handling/display/outputs/dl_renderer.js +131 -0
  49. package/L2_Handling/display/outputs/header_renderer.js +162 -0
  50. package/L2_Handling/display/outputs/icon_renderer.js +107 -0
  51. package/L2_Handling/display/outputs/image_renderer.js +145 -0
  52. package/L2_Handling/display/outputs/list_renderer.js +190 -0
  53. package/L2_Handling/display/outputs/outputs.js +19 -0
  54. package/L2_Handling/display/outputs/table_renderer.js +765 -0
  55. package/L2_Handling/display/outputs/text_renderer.js +818 -0
  56. package/L2_Handling/display/outputs/typography_renderer.js +293 -0
  57. package/L2_Handling/display/outputs/video_renderer.js +116 -0
  58. package/L2_Handling/display/primitives/document_structure_primitives.js +319 -0
  59. package/L2_Handling/display/primitives/form_primitives.js +526 -0
  60. package/L2_Handling/display/primitives/generic_containers.js +109 -0
  61. package/L2_Handling/display/primitives/interactive_primitives.js +305 -0
  62. package/L2_Handling/display/primitives/link_primitives.js +552 -0
  63. package/L2_Handling/display/primitives/lists_primitives.js +262 -0
  64. package/L2_Handling/display/primitives/media_primitives.js +383 -0
  65. package/L2_Handling/display/primitives/primitives.js +19 -0
  66. package/L2_Handling/display/primitives/semantic_element_primitive.js +226 -0
  67. package/L2_Handling/display/primitives/table_primitives.js +528 -0
  68. package/L2_Handling/display/primitives/typography_primitives.js +175 -0
  69. package/L2_Handling/display/specialized/input_request_renderer.js +467 -0
  70. package/L2_Handling/display/specialized/specialized.js +10 -0
  71. package/L2_Handling/hooks/hooks.js +9 -0
  72. package/L2_Handling/hooks/menu_integration.js +57 -0
  73. package/L2_Handling/hooks/widget_hook_manager.js +292 -0
  74. package/L2_Handling/message/message.js +8 -0
  75. package/L2_Handling/message/message_handler.js +701 -0
  76. package/L2_Handling/navigation/navigation.js +8 -0
  77. package/L2_Handling/navigation/navigation_manager.js +403 -0
  78. package/L2_Handling/zhooks/features/cache_live.js +287 -0
  79. package/L2_Handling/zhooks/features/crumbs_live.js +292 -0
  80. package/L2_Handling/zhooks/zhooks_manager.js +65 -0
  81. package/L2_Handling/zvaf/zvaf.js +8 -0
  82. package/L2_Handling/zvaf/zvaf_manager.js +334 -0
  83. package/L3_Abstraction/L3_Abstraction.js +12 -0
  84. package/L3_Abstraction/orchestrator/container_unwrapper.js +101 -0
  85. package/L3_Abstraction/orchestrator/group_renderer.js +698 -0
  86. package/L3_Abstraction/orchestrator/input_event_handler.js +797 -0
  87. package/L3_Abstraction/orchestrator/metadata_processor.js +249 -0
  88. package/L3_Abstraction/orchestrator/navbar_builder.js +201 -0
  89. package/L3_Abstraction/orchestrator/orchestrator.js +13 -0
  90. package/L3_Abstraction/orchestrator/wizard_gate_handler.js +360 -0
  91. package/L3_Abstraction/renderer/renderer.js +1 -0
  92. package/L3_Abstraction/session/session.js +1 -0
  93. package/L4_Orchestration/L4_Orchestration.js +11 -0
  94. package/L4_Orchestration/client/client.js +1 -0
  95. package/L4_Orchestration/facade/facade.js +9 -0
  96. package/L4_Orchestration/facade/manager_registry.js +118 -0
  97. package/L4_Orchestration/facade/renderer_registry.js +274 -0
  98. package/L4_Orchestration/lifecycle/asset_loader.js +255 -0
  99. package/L4_Orchestration/lifecycle/initializer.js +135 -0
  100. package/L4_Orchestration/lifecycle/lifecycle.js +8 -0
  101. package/L4_Orchestration/rendering/facade.js +94 -0
  102. package/L4_Orchestration/rendering/rendering.js +7 -0
  103. package/LICENSE +21 -0
  104. package/README.md +82 -0
  105. package/bifrost_client.js +204 -0
  106. package/bifrost_core.js +1686 -0
  107. package/docs/ARCHITECTURE.md +111 -0
  108. package/docs/PROTOCOL.md +106 -0
  109. package/docs/RENDERERS.md +101 -0
  110. package/docs/SECURITY.md +92 -0
  111. package/package.json +24 -0
  112. package/syntax/prism-zconfig.js +41 -0
  113. package/syntax/prism-zenv.js +69 -0
  114. package/syntax/prism-zolo-theme.css +288 -0
  115. package/syntax/prism-zolo.js +380 -0
  116. package/syntax/prism-zschema.js +38 -0
  117. package/syntax/prism-zspark.js +25 -0
  118. package/syntax/prism-zui.js +68 -0
  119. package/zSys/accessibility/accessibility.js +10 -0
  120. package/zSys/accessibility/emoji_accessibility.js +173 -0
  121. package/zSys/dom/block_utils.js +122 -0
  122. package/zSys/dom/container_utils.js +370 -0
  123. package/zSys/dom/dom.js +13 -0
  124. package/zSys/dom/dom_utils.js +328 -0
  125. package/zSys/dom/encoding_utils.js +117 -0
  126. package/zSys/dom/style_utils.js +71 -0
  127. package/zSys/errors/error_display.js +299 -0
  128. package/zSys/errors/errors.js +10 -0
  129. package/zSys/theme/color_utils.js +274 -0
  130. package/zSys/theme/dark_mode_utils.js +272 -0
  131. package/zSys/theme/size_utils.js +256 -0
  132. package/zSys/theme/spacing_utils.js +405 -0
  133. package/zSys/theme/theme.js +14 -0
  134. package/zSys/theme/zbase.css +1735 -0
  135. package/zSys/theme/zbase_inject.js +161 -0
  136. package/zSys/theme/ztheme_utils.js +305 -0
  137. package/zSys/validation/error_boundary.js +201 -0
  138. package/zSys/validation/validation.js +11 -0
  139. package/zSys/validation/validation_utils.js +238 -0
  140. package/zSys/zSys.js +14 -0
@@ -0,0 +1,526 @@
1
+ /**
2
+ *
3
+ * Form Primitives - Data Input Elements
4
+ *
5
+ *
6
+ * HTML form elements for user data input and submission.
7
+ * Covers all 18 input types plus form structure elements.
8
+ *
9
+ * @module rendering/form_primitives
10
+ * @layer 0.0 (RAWEST - form elements)
11
+ * @pattern Pure Factory Functions
12
+ *
13
+ * Philosophy:
14
+ * - Semantic data input (type enforcement)
15
+ * - Accessibility (labels, fieldsets, ARIA)
16
+ * - Native validation (email, url, number, etc.)
17
+ * - NO styling, NO classes (dress up later)
18
+ *
19
+ * Input Types Supported (18 total):
20
+ * - Text-based: text, email, password, search, tel, url
21
+ * - Numeric: number, range
22
+ * - Date/Time: date, datetime-local, month, week, time
23
+ * - Selection: checkbox, radio
24
+ * - File: file
25
+ * - Special: color, hidden
26
+ *
27
+ * Form Structure:
28
+ * - <form>: Container with submit handling
29
+ * - <fieldset> + <legend>: Group related inputs
30
+ * - <label>: Associate text with input (accessibility)
31
+ * - <input>: 18 different types
32
+ * - <textarea>: Multi-line text
33
+ * - <select> + <option> + <optgroup>: Dropdown menus
34
+ *
35
+ * Dependencies:
36
+ * - utils/dom_utils.js (createElement, setAttributes)
37
+ *
38
+ * Exports:
39
+ * - createInput(type, attributes) → HTMLInputElement
40
+ * - createTextarea(attributes) → HTMLTextAreaElement
41
+ * - createSelect(attributes) → HTMLSelectElement
42
+ * - createOption(value, text, attributes) → HTMLOptionElement
43
+ * - createOptgroup(label, attributes) → HTMLOptGroupElement
44
+ * - createLabel(forId, attributes) → HTMLLabelElement
45
+ * - createForm(attributes) → HTMLFormElement
46
+ * - createFieldset(attributes) → HTMLFieldSetElement
47
+ * - createLegend(attributes) → HTMLLegendElement
48
+ *
49
+ * Example:
50
+ * ```javascript
51
+ * import { createForm, createInput, createLabel } from './form_primitives.js';
52
+ *
53
+ * const form = createForm({ id: 'login' });
54
+ * const label = createLabel('email');
55
+ * label.textContent = 'Email:';
56
+ * const input = createInput('email', { id: 'email', required: true });
57
+ * form.appendChild(label);
58
+ * form.appendChild(input);
59
+ * ```
60
+ */
61
+
62
+ // ─────────────────────────────────────────────────────────────────
63
+ // Imports
64
+ // ─────────────────────────────────────────────────────────────────
65
+
66
+ // Layer 2: Utilities
67
+ import { createElement, setAttributes } from '../../../zSys/dom/dom_utils.js';
68
+
69
+ //
70
+ // Input Element (18 Types)
71
+ //
72
+
73
+ /**
74
+ * Valid HTML5 input types (18 total)
75
+ * Button-like types (submit, reset, button, image) are EXCLUDED - use <button> instead
76
+ */
77
+ const VALID_INPUT_TYPES = [
78
+ // Text-based inputs
79
+ 'text', 'email', 'password', 'search', 'tel', 'url',
80
+ // Numeric inputs
81
+ 'number', 'range',
82
+ // Date/Time inputs
83
+ 'date', 'datetime-local', 'month', 'week', 'time',
84
+ // Selection inputs
85
+ 'checkbox', 'radio',
86
+ // File input
87
+ 'file',
88
+ // Special inputs
89
+ 'color', 'hidden'
90
+ ];
91
+
92
+ /**
93
+ * Create an <input> element
94
+ *
95
+ * Supports all 18 semantic HTML5 input types.
96
+ * Type is validated and defaults to 'text'.
97
+ *
98
+ * INPUT TYPE REFERENCE:
99
+ *
100
+ * TEXT-BASED (6 types):
101
+ * - text: Plain text input (default)
102
+ * - email: Email address (native validation, keyboard optimized on mobile)
103
+ * - password: Hidden text (shows dots/asterisks)
104
+ * - search: Search queries (may show clear button)
105
+ * - tel: Telephone number (numeric keyboard on mobile)
106
+ * - url: URL input (native validation, keyboard optimized on mobile)
107
+ *
108
+ * NUMERIC (2 types):
109
+ * - number: Numeric input with steppers (supports min, max, step)
110
+ * - range: Slider control (supports min, max, step, value)
111
+ *
112
+ * DATE/TIME (5 types):
113
+ * - date: Date picker (YYYY-MM-DD)
114
+ * - datetime-local: Date + time picker (no timezone)
115
+ * - month: Month picker (YYYY-MM)
116
+ * - week: Week picker (YYYY-W##)
117
+ * - time: Time picker (HH:MM or HH:MM:SS)
118
+ *
119
+ * SELECTION (2 types):
120
+ * - checkbox: Toggle checkbox (supports checked)
121
+ * - radio: Radio button (group via same name attribute)
122
+ *
123
+ * FILE (1 type):
124
+ * - file: File upload (supports accept, multiple)
125
+ *
126
+ * SPECIAL (2 types):
127
+ * - color: Color picker (returns hex #RRGGBB)
128
+ * - hidden: Hidden input (no UI, stores value)
129
+ *
130
+ * @param {string} [type='text'] - Input type (one of 18 valid types)
131
+ * @param {Object} [attributes={}] - HTML attributes (id, name, required, placeholder, etc.)
132
+ * @returns {HTMLInputElement} The created input element
133
+ *
134
+ * @example
135
+ * // Text input
136
+ * const username = createInput('text', { id: 'username', name: 'username', required: true });
137
+ *
138
+ * // Email input (native validation)
139
+ * const email = createInput('email', { id: 'email', placeholder: 'you@example.com' });
140
+ *
141
+ * // Password input
142
+ * const password = createInput('password', { id: 'pwd', autocomplete: 'current-password' });
143
+ *
144
+ * // Number input with constraints
145
+ * const age = createInput('number', { min: 18, max: 120, step: 1 });
146
+ *
147
+ * // Date input
148
+ * const birthday = createInput('date', { id: 'dob', min: '1900-01-01', max: '2024-12-31' });
149
+ *
150
+ * // Checkbox
151
+ * const agree = createInput('checkbox', { id: 'agree', name: 'agree', value: 'yes' });
152
+ *
153
+ * // Radio button (group by same name)
154
+ * const radio1 = createInput('radio', { name: 'plan', value: 'basic', checked: true });
155
+ * const radio2 = createInput('radio', { name: 'plan', value: 'pro' });
156
+ *
157
+ * // File upload (multiple files, accept images only)
158
+ * const fileInput = createInput('file', { accept: 'image/*', multiple: true });
159
+ *
160
+ * // Color picker
161
+ * const colorPicker = createInput('color', { value: '#ff0000' });
162
+ *
163
+ * // Hidden input
164
+ * const hiddenToken = createInput('hidden', { name: 'csrf_token', value: 'abc123' });
165
+ */
166
+ export function createInput(type = 'text', attributes = {}) {
167
+ const input = createElement('input');
168
+
169
+ // Validate input type (default to 'text')
170
+ const validType = VALID_INPUT_TYPES.includes(type) ? type : 'text';
171
+
172
+ if (type && !VALID_INPUT_TYPES.includes(type)) {
173
+ console.warn(`[form_primitives] createInput: Invalid type "${type}", defaulting to "text". Valid types: ${VALID_INPUT_TYPES.join(', ')}`);
174
+ }
175
+
176
+ // Sensible defaults
177
+ const defaults = {
178
+ type: validType
179
+ // TODO: Add opt-in autocomplete control later (removed default autocomplete: 'off')
180
+ };
181
+
182
+ // Merge defaults with user attributes (user attributes take precedence)
183
+ setAttributes(input, { ...defaults, ...attributes });
184
+
185
+ return input;
186
+ }
187
+
188
+ //
189
+ // Textarea Element (Multi-line Text)
190
+ //
191
+
192
+ /**
193
+ * Create a <textarea> element
194
+ *
195
+ * Used for multi-line text input (comments, messages, descriptions).
196
+ * Separate element from <input>, NOT an input type.
197
+ *
198
+ * Common Attributes:
199
+ * - rows: Number of visible text rows (default browser behavior ~2)
200
+ * - cols: Width in characters (default browser behavior ~20)
201
+ * - maxlength: Maximum character count
202
+ * - placeholder: Placeholder text
203
+ * - required: Make field required
204
+ * - wrap: Text wrapping (soft/hard)
205
+ *
206
+ * @param {Object} [attributes={}] - HTML attributes (id, name, rows, cols, placeholder, etc.)
207
+ * @returns {HTMLTextAreaElement} The created textarea element
208
+ *
209
+ * @example
210
+ * // Basic textarea
211
+ * const comments = createTextarea({ id: 'comments', name: 'comments' });
212
+ *
213
+ * // Textarea with size constraints
214
+ * const message = createTextarea({
215
+ * rows: 5,
216
+ * cols: 50,
217
+ * maxlength: 500,
218
+ * placeholder: 'Enter your message...'
219
+ * });
220
+ *
221
+ * // Required textarea
222
+ * const feedback = createTextarea({ id: 'feedback', required: true });
223
+ */
224
+ export function createTextarea(attributes = {}) {
225
+ const textarea = createElement('textarea');
226
+
227
+ if (Object.keys(attributes).length > 0) {
228
+ setAttributes(textarea, attributes);
229
+ }
230
+
231
+ return textarea;
232
+ }
233
+
234
+ //
235
+ // Select Element (Dropdown Menu)
236
+ //
237
+
238
+ /**
239
+ * Create a <select> element
240
+ *
241
+ * Dropdown menu for selecting one or multiple options.
242
+ * Contains <option> elements (and optionally <optgroup>).
243
+ *
244
+ * Common Attributes:
245
+ * - multiple: Allow multiple selections (changes to listbox)
246
+ * - size: Number of visible options (for listbox mode)
247
+ * - required: Make selection required
248
+ * - disabled: Disable entire select
249
+ *
250
+ * @param {Object} [attributes={}] - HTML attributes (id, name, multiple, required, etc.)
251
+ * @returns {HTMLSelectElement} The created select element
252
+ *
253
+ * @example
254
+ * // Basic dropdown
255
+ * const country = createSelect({ id: 'country', name: 'country' });
256
+ *
257
+ * // Multiple selection listbox
258
+ * const skills = createSelect({ id: 'skills', name: 'skills', multiple: true, size: 5 });
259
+ *
260
+ * // Required select
261
+ * const plan = createSelect({ id: 'plan', name: 'plan', required: true });
262
+ */
263
+ export function createSelect(attributes = {}) {
264
+ const select = createElement('select');
265
+
266
+ if (Object.keys(attributes).length > 0) {
267
+ setAttributes(select, attributes);
268
+ }
269
+
270
+ return select;
271
+ }
272
+
273
+ /**
274
+ * Create an <option> element
275
+ *
276
+ * Individual option within a <select> dropdown.
277
+ * Must be a child of <select> or <optgroup>.
278
+ *
279
+ * @param {string} value - The option value (submitted with form)
280
+ * @param {string} text - The visible text for the option
281
+ * @param {Object} [attributes={}] - HTML attributes (selected, disabled, etc.)
282
+ * @returns {HTMLOptionElement} The created option element
283
+ *
284
+ * @example
285
+ * // Basic option
286
+ * const opt1 = createOption('us', 'United States');
287
+ *
288
+ * // Selected option
289
+ * const opt2 = createOption('ca', 'Canada', { selected: true });
290
+ *
291
+ * // Disabled option
292
+ * const opt3 = createOption('', '-- Select Country --', { disabled: true, selected: true });
293
+ */
294
+ export function createOption(value, text, attributes = {}) {
295
+ const option = createElement('option');
296
+
297
+ // Set value and text
298
+ option.value = value;
299
+ option.textContent = text;
300
+
301
+ if (Object.keys(attributes).length > 0) {
302
+ setAttributes(option, attributes);
303
+ }
304
+
305
+ return option;
306
+ }
307
+
308
+ /**
309
+ * Create an <optgroup> element
310
+ *
311
+ * Groups related options within a <select> dropdown.
312
+ * Must be a child of <select>, contains <option> elements.
313
+ *
314
+ * @param {string} label - The visible label for the group
315
+ * @param {Object} [attributes={}] - HTML attributes (disabled, etc.)
316
+ * @returns {HTMLOptGroupElement} The created optgroup element
317
+ *
318
+ * @example
319
+ * // Option group
320
+ * const northAmerica = createOptgroup('North America');
321
+ * northAmerica.appendChild(createOption('us', 'United States'));
322
+ * northAmerica.appendChild(createOption('ca', 'Canada'));
323
+ *
324
+ * const select = createSelect({ id: 'country' });
325
+ * select.appendChild(northAmerica);
326
+ */
327
+ export function createOptgroup(label, attributes = {}) {
328
+ const optgroup = createElement('optgroup');
329
+
330
+ // Set label
331
+ optgroup.label = label;
332
+
333
+ if (Object.keys(attributes).length > 0) {
334
+ setAttributes(optgroup, attributes);
335
+ }
336
+
337
+ return optgroup;
338
+ }
339
+
340
+ //
341
+ // Label Element (Accessibility)
342
+ //
343
+
344
+ /**
345
+ * Create a <label> element
346
+ *
347
+ * Associates descriptive text with form inputs (critical for accessibility).
348
+ * Two association methods:
349
+ * 1. "for" attribute pointing to input id (recommended)
350
+ * 2. Wrapping the input element (implicit association)
351
+ *
352
+ * Best Practice:
353
+ * - ALWAYS provide labels for inputs (except hidden)
354
+ * - Use "for" attribute for explicit association
355
+ * - Clicking label focuses/toggles associated input
356
+ *
357
+ * @param {string} [forId=''] - ID of the associated input element
358
+ * @param {Object} [attributes={}] - HTML attributes (id, class, etc.)
359
+ * @returns {HTMLLabelElement} The created label element
360
+ *
361
+ * @example
362
+ * // Explicit association (recommended)
363
+ * const label = createLabel('email', { class: 'form-label' });
364
+ * label.textContent = 'Email Address:';
365
+ * const input = createInput('email', { id: 'email' });
366
+ *
367
+ * // Implicit association (wrapping)
368
+ * const wrapperLabel = createLabel();
369
+ * wrapperLabel.textContent = 'Username: ';
370
+ * wrapperLabel.appendChild(createInput('text', { name: 'username' }));
371
+ */
372
+ export function createLabel(forId = '', attributes = {}) {
373
+ const label = createElement('label');
374
+
375
+ if (forId) {
376
+ setAttributes(label, { for: forId, ...attributes });
377
+ } else if (Object.keys(attributes).length > 0) {
378
+ setAttributes(label, attributes);
379
+ }
380
+
381
+ return label;
382
+ }
383
+
384
+ //
385
+ // Form Element (Container)
386
+ //
387
+
388
+ /**
389
+ * Create a <form> element
390
+ *
391
+ * Container for form inputs and submission handling.
392
+ * Provides native validation and submit events.
393
+ *
394
+ * Common Attributes:
395
+ * - action: URL to submit form data (default: current page)
396
+ * - method: HTTP method (GET or POST, default: GET)
397
+ * - enctype: Encoding type (for file uploads: multipart/form-data)
398
+ * - novalidate: Disable native HTML5 validation
399
+ * - autocomplete: Enable/disable autocomplete (on/off)
400
+ *
401
+ * Best Practice:
402
+ * - Use method="POST" for data modification
403
+ * - Use method="GET" for searches (idempotent)
404
+ * - Add enctype="multipart/form-data" for file uploads
405
+ * - Listen to 'submit' event, call preventDefault() for AJAX
406
+ *
407
+ * @param {Object} [attributes={}] - HTML attributes (action, method, enctype, etc.)
408
+ * @returns {HTMLFormElement} The created form element
409
+ *
410
+ * @example
411
+ * // Basic POST form
412
+ * const loginForm = createForm({
413
+ * id: 'login',
414
+ * method: 'POST',
415
+ * action: '/api/login'
416
+ * });
417
+ *
418
+ * // Search form (GET)
419
+ * const searchForm = createForm({
420
+ * method: 'GET',
421
+ * action: '/search'
422
+ * });
423
+ *
424
+ * // File upload form
425
+ * const uploadForm = createForm({
426
+ * method: 'POST',
427
+ * enctype: 'multipart/form-data'
428
+ * });
429
+ *
430
+ * // AJAX form (prevent default submission)
431
+ * const ajaxForm = createForm({ id: 'contact' });
432
+ * ajaxForm.addEventListener('submit', (e) => {
433
+ * e.preventDefault();
434
+ * // Handle with fetch/AJAX
435
+ * });
436
+ */
437
+ export function createForm(attributes = {}) {
438
+ const form = createElement('form');
439
+
440
+ if (Object.keys(attributes).length > 0) {
441
+ setAttributes(form, attributes);
442
+ }
443
+
444
+ return form;
445
+ }
446
+
447
+ //
448
+ // Fieldset + Legend (Form Grouping)
449
+ //
450
+
451
+ /**
452
+ * Create a <fieldset> element
453
+ *
454
+ * Groups related form controls with a visual border.
455
+ * Used for semantic grouping and accessibility.
456
+ * First child is typically <legend> (the group's caption).
457
+ *
458
+ * Best Practice:
459
+ * - Group related inputs (e.g., address fields, payment info)
460
+ * - Use <legend> as first child for the group title
461
+ * - Can be disabled (disables all contained inputs)
462
+ *
463
+ * @param {Object} [attributes={}] - HTML attributes (id, disabled, etc.)
464
+ * @returns {HTMLFieldSetElement} The created fieldset element
465
+ *
466
+ * @example
467
+ * // Address fieldset
468
+ * const addressFields = createFieldset({ id: 'address' });
469
+ * const legend = createLegend();
470
+ * legend.textContent = 'Shipping Address';
471
+ * addressFields.appendChild(legend);
472
+ *
473
+ * // Disabled fieldset (disables all inputs inside)
474
+ * const disabledFields = createFieldset({ disabled: true });
475
+ */
476
+ export function createFieldset(attributes = {}) {
477
+ const fieldset = createElement('fieldset');
478
+
479
+ if (Object.keys(attributes).length > 0) {
480
+ setAttributes(fieldset, attributes);
481
+ }
482
+
483
+ return fieldset;
484
+ }
485
+
486
+ /**
487
+ * Create a <legend> element
488
+ *
489
+ * Caption/title for a <fieldset> group.
490
+ * Must be the first child of <fieldset>.
491
+ *
492
+ * @param {Object} [attributes={}] - HTML attributes (id, class, etc.)
493
+ * @returns {HTMLLegendElement} The created legend element
494
+ *
495
+ * @example
496
+ * // Fieldset with legend
497
+ * const fieldset = createFieldset();
498
+ * const legend = createLegend({ class: 'fieldset-title' });
499
+ * legend.textContent = 'Personal Information';
500
+ * fieldset.appendChild(legend);
501
+ */
502
+ export function createLegend(attributes = {}) {
503
+ const legend = createElement('legend');
504
+
505
+ if (Object.keys(attributes).length > 0) {
506
+ setAttributes(legend, attributes);
507
+ }
508
+
509
+ return legend;
510
+ }
511
+
512
+ //
513
+ // Default Export (for convenience)
514
+ //
515
+ export default {
516
+ createInput,
517
+ createTextarea,
518
+ createSelect,
519
+ createOption,
520
+ createOptgroup,
521
+ createLabel,
522
+ createForm,
523
+ createFieldset,
524
+ createLegend
525
+ };
526
+
@@ -0,0 +1,109 @@
1
+ /**
2
+ *
3
+ * Generic Containers - RAWEST HTML Primitives (Block + Inline)
4
+ *
5
+ *
6
+ * The most atomic building blocks: <div> and <span>.
7
+ * These are semantic-free containers used purely for layout and grouping.
8
+ *
9
+ * @module rendering/generic_containers
10
+ * @layer 0.0 (RAWEST - true bottom)
11
+ * @pattern Pure Factory Functions
12
+ *
13
+ * Philosophy:
14
+ * - Block-level (<div>) for layout/structure
15
+ * - Inline (<span>) for phrasing content
16
+ * - NO styling, NO classes (dress up later)
17
+ * - Accept raw HTML attributes only
18
+ *
19
+ * Dependencies:
20
+ * - utils/dom_utils.js (createElement, setAttributes)
21
+ *
22
+ * Exports:
23
+ * - createDiv(attributes) → HTMLDivElement
24
+ * - createSpan(attributes) → HTMLSpanElement
25
+ *
26
+ * Example:
27
+ * ```javascript
28
+ * import { createDiv, createSpan } from './generic_containers.js';
29
+ *
30
+ * // Raw containers
31
+ * const container = createDiv({ id: 'main' });
32
+ * const badge = createSpan({ class: 'badge', 'data-count': '5' });
33
+ *
34
+ * // Dress up later with utilities
35
+ * container.classList.add('zContainer', 'zP-3');
36
+ * badge.classList.add('zBadge', 'zBadge-primary');
37
+ * ```
38
+ */
39
+
40
+ // ─────────────────────────────────────────────────────────────────
41
+ // Imports
42
+ // ─────────────────────────────────────────────────────────────────
43
+
44
+ // Layer 2: Utilities
45
+ import { createElement, setAttributes, createDiv } from '../../../zSys/dom/dom_utils.js';
46
+
47
+ //
48
+ // Re-exports from utils/dom_utils.js
49
+ //
50
+
51
+ /**
52
+ * Re-export createDiv from dom_utils.js for convenience
53
+ *
54
+ * NOTE: createDiv is now defined in Layer 2 (utils/dom_utils.js) to maintain
55
+ * proper architectural layering. This file (Layer 3 - Renderers) re-exports
56
+ * it for backward compatibility with existing renderer code.
57
+ *
58
+ * See: utils/dom_utils.js for the actual implementation
59
+ */
60
+ export { createDiv };
61
+
62
+ //
63
+ // Inline Container
64
+ //
65
+
66
+ /**
67
+ * Create a <span> element (inline container)
68
+ *
69
+ * The most generic inline container, used for:
70
+ * - Wrapping phrasing content (text, icons)
71
+ * - Badges, labels, tags
72
+ * - Inline styling/scripting hooks
73
+ * - Semantic-free inline containers (when <strong>, <em>, etc. don't apply)
74
+ *
75
+ * @param {Object} [attributes={}] - HTML attributes (id, class, data-*, aria-*, etc.)
76
+ * @returns {HTMLSpanElement} The created span element
77
+ *
78
+ * @example
79
+ * // Basic span (no attributes)
80
+ * const highlight = createSpan();
81
+ * highlight.textContent = 'Important';
82
+ *
83
+ * // Span with class (for styling hook)
84
+ * const badge = createSpan({ class: 'badge' });
85
+ *
86
+ * // Span with data attributes
87
+ * const tag = createSpan({ 'data-tag-id': '5', 'data-color': 'blue' });
88
+ *
89
+ * // Span for icon wrapper
90
+ * const iconWrapper = createSpan({ class: 'icon', 'aria-hidden': 'true' });
91
+ */
92
+ export function createSpan(attributes = {}) {
93
+ const span = createElement('span');
94
+
95
+ if (Object.keys(attributes).length > 0) {
96
+ setAttributes(span, attributes);
97
+ }
98
+
99
+ return span;
100
+ }
101
+
102
+ //
103
+ // Default Export (for convenience)
104
+ //
105
+ export default {
106
+ createDiv,
107
+ createSpan
108
+ };
109
+