jsgui3-server 0.0.140 → 0.0.141

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 (32) hide show
  1. package/.github/agents/jsgui3-server.agent.md +699 -0
  2. package/.github/instructions/copilot.instructions.md +180 -0
  3. package/.playwright-mcp/page-2025-11-29T23-39-18-629Z.png +0 -0
  4. package/.playwright-mcp/page-2025-11-29T23-39-31-903Z.png +0 -0
  5. package/.playwright-mcp/page-2025-11-30T00-33-56-265Z.png +0 -0
  6. package/.playwright-mcp/page-2025-11-30T00-34-06-619Z.png +0 -0
  7. package/docs/agent-development-guide.md +108 -4
  8. package/docs/api-reference.md +116 -0
  9. package/docs/controls-development.md +127 -0
  10. package/docs/css/luxuryObsidianCss.js +1203 -0
  11. package/docs/css/obsidian-scrollbars.css +370 -0
  12. package/docs/diagrams/jsgui3-stack.svg +568 -0
  13. package/docs/guides/JSGUI3_UI_ARCHITECTURE_GUIDE.md +2527 -0
  14. package/docs/guides/OBSIDIAN_LUXURY_DESIGN_GUIDE.md +847 -0
  15. package/docs/jsgui3-vs-express-comparison.svg +542 -0
  16. package/docs/jsgui3-vs-nestjs-comparison.svg +550 -0
  17. package/docs/publishers-guide.md +76 -0
  18. package/docs/troubleshooting.md +51 -0
  19. package/examples/controls/15) window, observable SSE/README.md +125 -0
  20. package/examples/controls/15) window, observable SSE/check.js +144 -0
  21. package/examples/controls/15) window, observable SSE/client.js +395 -0
  22. package/examples/controls/15) window, observable SSE/server.js +111 -0
  23. package/http/responders/static/Static_Route_HTTP_Responder.js +16 -16
  24. package/module.js +7 -0
  25. package/package.json +7 -6
  26. package/port-utils.js +112 -0
  27. package/serve-factory.js +27 -5
  28. package/tests/README.md +40 -26
  29. package/tests/examples-controls.e2e.test.js +164 -0
  30. package/tests/observable-sse.test.js +363 -0
  31. package/tests/port-utils.test.js +114 -0
  32. package/tests/test-runner.js +13 -12
@@ -0,0 +1,180 @@
1
+ ---
2
+ description: "GitHub Copilot instructions for jsgui3-server development"
3
+ applyTo: "**"
4
+ ---
5
+
6
+ # GitHub Copilot — jsgui3-server Playbook
7
+
8
+ ## Primary References
9
+
10
+ - **`AGENTS.md`** — Root agent guidance with documentation index
11
+ - **`.github/agents/jsgui3-server.agent.md`** — Detailed patterns and anti-patterns
12
+ - **`docs/agent-development-guide.md`** — Broken functionality tracker (CHECK FIRST)
13
+
14
+ ## Core Conventions
15
+
16
+ ### Naming (Non-Negotiable)
17
+ ```javascript
18
+ // Variables, functions → snake_case
19
+ const my_variable = 'value';
20
+ function process_data() {}
21
+
22
+ // Classes → PascalCase
23
+ class My_Control extends Active_HTML_Document {}
24
+ ```
25
+
26
+ ### Control Lifecycle (The Canonical Pattern)
27
+ ```javascript
28
+ class My_Control extends Active_HTML_Document {
29
+ constructor(spec = {}) {
30
+ spec.__type_name = spec.__type_name || 'my_control';
31
+ super(spec);
32
+ const { context } = this;
33
+
34
+ const compose = () => {
35
+ // Build UI here
36
+ };
37
+
38
+ if (!spec.el) { compose(); } // Conditional compose!
39
+ }
40
+
41
+ activate() {
42
+ if (!this.__active) { // Guard against double activation!
43
+ super.activate();
44
+ // Event bindings here
45
+ }
46
+ }
47
+ }
48
+
49
+ My_Control.css = `/* styles */`; // CSS as static property!
50
+ ```
51
+
52
+ ## Quick Commands
53
+
54
+ ```bash
55
+ # Run example
56
+ cd examples/controls/001_demo_page && node server.js
57
+
58
+ # Tests
59
+ npm test # All
60
+ npm run test:bundlers # Bundler tests
61
+ npm run test:publishers # Publisher tests
62
+
63
+ # Debug mode
64
+ JSGUI_DEBUG=1 node server.js
65
+ ```
66
+
67
+ ## Before You Code
68
+
69
+ 1. **Check known issues**: `docs/agent-development-guide.md` has the broken functionality tracker
70
+ 2. **Find patterns**: Look at `examples/controls/` for reference implementations
71
+ 3. **Update docs**: If you find something broken, document it immediately
72
+
73
+ ## Anti-Patterns to Avoid
74
+
75
+ | ❌ Wrong | ✅ Right |
76
+ |----------|----------|
77
+ | `document.getElementById()` | `this.body.add.div({ id: 'x' })` |
78
+ | Always compose in constructor | `if (!spec.el) { compose(); }` |
79
+ | `activate()` without guard | `if (!this.__active) { super.activate(); }` |
80
+ | `server.start()` immediately | `server.on('ready', () => server.start())` |
81
+ | `new controls.h2({ text: 'Hi' })` | `h2.add('Hi')` — Use `.add()` for text! |
82
+ | `controls.button` (lowercase) | `controls.Button` (PascalCase for composites) |
83
+
84
+ ## ⚠️ Critical: Text Content in Controls
85
+
86
+ **HTML elements** (div, span, h2) use `.add()` for text:
87
+ ```javascript
88
+ const title = new controls.h2({ context });
89
+ title.add('My Title'); // ✅ Correct
90
+
91
+ // ❌ WRONG: text property won't render for HTML elements
92
+ const title = new controls.h2({ context, text: 'My Title' }); // Empty!
93
+ ```
94
+
95
+ **Composite controls** (Button, Checkbox) DO support `text` property:
96
+ ```javascript
97
+ const button = new controls.Button({ context, text: 'Click' }); // ✅ Works
98
+ ```
99
+
100
+ **Control naming:**
101
+ - HTML elements: lowercase (`controls.div`, `controls.h2`)
102
+ - Composites: PascalCase (`controls.Button`, `controls.Window`)
103
+
104
+ **Set IDs via:** `control.dom.attributes.id = 'my-id'`
105
+
106
+ ## Key Architectural Facts
107
+
108
+ - **Isomorphic**: Controls render server-side, activate client-side
109
+ - **ESBuild**: JavaScript bundling handled by ESBuild
110
+ - **CSS extraction**: CSS comes from static `.css` property on control classes
111
+ - **Publishers**: Different content types (webpage, function, css) have dedicated publishers
112
+ - **Context**: Central runtime object - extract with `const { context } = this;`
113
+
114
+ ## When Creating Controls
115
+
116
+ 1. Set `__type_name` before `super()`
117
+ 2. Extract `context` after `super()`
118
+ 3. Define `compose()` function for UI building
119
+ 4. Use `if (!spec.el) { compose(); }` for conditional composition
120
+ 5. Guard `activate()` with `if (!this.__active)`
121
+ 6. Put CSS on static `.css` property
122
+
123
+ ## Server Startup
124
+
125
+ ```javascript
126
+ // Recommended: Server.serve() API
127
+ const Server = require('jsgui3-server');
128
+ Server.serve({
129
+ Ctrl: My_Control,
130
+ src_path_client_js: __dirname + '/client.js',
131
+ port: 8080
132
+ });
133
+
134
+ // Auto-port selection (avoids conflicts)
135
+ Server.serve({
136
+ Ctrl: My_Control,
137
+ src_path_client_js,
138
+ port: 'auto' // or port: 0
139
+ });
140
+
141
+ // Manual: Wait for 'ready' event
142
+ const server = new Server({ Ctrl, src_path_client_js });
143
+ server.on('ready', () => server.start(8080));
144
+ ```
145
+
146
+ ## Port Utilities
147
+
148
+ ```javascript
149
+ const { get_free_port, is_port_available } = require('jsgui3-server');
150
+
151
+ const port = await get_free_port(); // Find any free port
152
+ const available = await is_port_available(8080); // Check specific port
153
+ ```
154
+
155
+ ## Data Binding
156
+
157
+ ```javascript
158
+ const { Data_Object, field } = require('obext');
159
+
160
+ const model = new Data_Object({
161
+ count: field(0)
162
+ });
163
+
164
+ model.on('change.count', (e) => {
165
+ // React to changes
166
+ });
167
+
168
+ model.count++; // Triggers change event
169
+ ```
170
+
171
+ ## Documentation When Stuck
172
+
173
+ | Topic | File |
174
+ |-------|------|
175
+ | Architecture overview | `README.md` |
176
+ | Comprehensive API | `docs/comprehensive-documentation.md` |
177
+ | Control development | `docs/controls-development.md` |
178
+ | Publisher system | `docs/publishers-guide.md` |
179
+ | Troubleshooting | `docs/troubleshooting.md` |
180
+ | **Broken stuff** | `docs/agent-development-guide.md` |
@@ -106,6 +106,20 @@ jsgui3-server/
106
106
  - [x] Data binding with observable models
107
107
  - [x] CSS as static properties
108
108
 
109
+ #### Port Utilities (NEW)
110
+ - [x] `get_free_port()` - Find available port
111
+ - [x] `is_port_available()` - Check if port is free
112
+ - [x] `get_free_ports()` - Find multiple ports
113
+ - [x] `get_port_or_free()` - Prefer port or find free
114
+ - [x] `port: 'auto'` option in Server.serve()
115
+ - [x] Documented in api-reference.md
116
+
117
+ #### Observable Publisher (Documented)
118
+ - [x] HTTP_Observable_Publisher for SSE streaming
119
+ - [x] Integration with `fnl` observables
120
+ - [x] Working example in `examples/controls/15) window, observable SSE/`
121
+ - [x] Documented in publishers-guide.md
122
+
109
123
  ### 🚧 In Progress / Partially Complete
110
124
 
111
125
  #### Website Publisher
@@ -192,6 +206,7 @@ jsgui3-server/
192
206
  - Emit single clear "Server ready" message
193
207
  - Ensure all publishers are ready before signaling
194
208
  - Update CLI to wait for proper ready signal
209
+ - **Note**: Currently emits "ready" twice, causing port conflicts in tests
195
210
 
196
211
  4. **Default Holding Page**
197
212
  - Serve simple HTML when no content configured
@@ -199,22 +214,28 @@ jsgui3-server/
199
214
  - Allow configuration override
200
215
 
201
216
  ### Medium Priority
202
- 5. **File Manager Interface**
217
+ 5. **Observable API Integration**
218
+ - Detect observable returns in HTTP_Function_Publisher
219
+ - Auto-switch to SSE transport for observable endpoints
220
+ - Add client-side `context.subscribe()` for consuming streams
221
+ - Document observable publishing patterns
222
+
223
+ 6. **File Manager Interface**
203
224
  - Create admin UI for browsing/serving directories
204
225
  - Integrate with file system resource
205
226
  - Add upload/download capabilities
206
227
 
207
- 6. **CSS Bundling Cleanup**
228
+ 7. **CSS Bundling Cleanup**
208
229
  - Remove legacy bundle paths
209
230
  - Consolidate CSS extraction logic
210
231
  - Ensure reliable CSS bundling
211
232
 
212
- 7. **Configuration File Support**
233
+ 8. **Configuration File Support**
213
234
  - Add `jsgui.config.js` support
214
235
  - Implement `--config` CLI option
215
236
  - Document configuration patterns
216
237
 
217
- 8. **Graceful Shutdown**
238
+ 9. **Graceful Shutdown**
218
239
  - Handle SIGINT/SIGTERM signals
219
240
  - Clean up resources properly
220
241
  - Print shutdown confirmation
@@ -232,6 +253,45 @@ jsgui3-server/
232
253
 
233
254
  ## Development Patterns
234
255
 
256
+ ### Observable Pattern (Core to jsgui3-server)
257
+
258
+ The `fnl` module provides observables used throughout for async operations with intermediate results:
259
+
260
+ ```javascript
261
+ const {obs} = require('fnl');
262
+
263
+ // Creating an observable
264
+ const my_async_operation = obs((next, complete, error) => {
265
+ // Emit progress/intermediate values
266
+ next({ stage: 'parsing', progress: 25 });
267
+ next({ stage: 'bundling', progress: 75 });
268
+
269
+ // Complete with final result (acts like promise resolution)
270
+ complete({ bundle: compiled_code });
271
+
272
+ // Or error (acts like promise rejection)
273
+ // error(new Error('compilation failed'));
274
+
275
+ // Return cleanup functions (optional)
276
+ return [() => cleanup_resources()];
277
+ });
278
+
279
+ // Consuming an observable
280
+ my_async_operation.on('next', data => console.log('Progress:', data));
281
+ my_async_operation.on('complete', result => console.log('Done:', result));
282
+ my_async_operation.on('error', err => console.error('Failed:', err));
283
+ ```
284
+
285
+ **Key locations using observables:**
286
+ - `publishers/http-observable-publisher.js` — SSE streaming to clients
287
+ - `resources/processors/bundlers/*.js` — All bundling operations
288
+ - `publishers/http-website-publisher.js` — Website build pipeline
289
+
290
+ **Observable vs Promise:**
291
+ - Use **observable** when operation has meaningful intermediate states (bundling progress, streaming data)
292
+ - Use **promise** for simple async one-shot operations
293
+ - The `http-function-publisher.js` already detects promises; extend to detect observables
294
+
235
295
  ### Control Creation Pattern
236
296
  ```javascript
237
297
  class MyControl extends Active_HTML_Document {
@@ -264,6 +324,41 @@ class MyControl extends Active_HTML_Document {
264
324
  MyControl.css = `/* CSS styles */`;
265
325
  ```
266
326
 
327
+ ### ⚠️ Critical Pattern: Text Content in Controls
328
+
329
+ **This is a common pitfall!** HTML element controls and composite controls handle text differently:
330
+
331
+ ```javascript
332
+ // ❌ WRONG: text property/assignment doesn't work for HTML elements
333
+ const title = new controls.h2({ context, text: 'My Title' }); // Won't render!
334
+ const div = new controls.div({ context });
335
+ div.text = 'Content'; // Won't render!
336
+
337
+ // ✅ CORRECT: Use .add() for HTML elements (div, span, h2, etc.)
338
+ const title = new controls.h2({ context });
339
+ title.add('My Title'); // ✅ Renders correctly
340
+
341
+ const div = new controls.div({ context });
342
+ div.add('Content'); // ✅ Renders correctly
343
+
344
+ // ✅ Composite controls (Button, Checkbox) DO support text property
345
+ const button = new controls.Button({ context, text: 'Click Me' }); // ✅ Works
346
+ ```
347
+
348
+ **Why?** HTML elements are thin wrappers where text is a child node. Composite controls like `Button` have internal `compose_button()` that calls `this.add(this.text)`.
349
+
350
+ **Control Naming:**
351
+ | Type | Naming | Examples |
352
+ |------|--------|----------|
353
+ | HTML elements | lowercase | `controls.div`, `controls.span`, `controls.h2` |
354
+ | Composite controls | PascalCase | `controls.Button`, `controls.Window`, `controls.Checkbox` |
355
+
356
+ **Setting Element IDs:**
357
+ ```javascript
358
+ const div = new controls.div({ context });
359
+ div.dom.attributes.id = 'my-id'; // ✅ Correct way to set ID
360
+ ```
361
+
267
362
  ### Publisher Creation Pattern
268
363
  ```javascript
269
364
  class CustomPublisher extends HTTP_Publisher {
@@ -321,9 +416,18 @@ class CustomResource extends Resource {
321
416
 
322
417
  ### Architecture Insights
323
418
  - **Event-Driven Design**: Heavy use of Evented_Class and observable patterns
419
+ - **Observable-First Async**: `fnl` observables used for all multi-stage operations (bundling, compilation)
324
420
  - **Resource Pool Pattern**: Centralized resource management
325
421
  - **Publisher Abstraction**: Clean separation of content types
326
422
  - **Context System**: Runtime environment management
423
+ - **SSE Infrastructure**: `HTTP_Observable_Publisher` already implements Server-Sent Events for streaming
424
+
425
+ ### Observable Pattern (Strategic Differentiator)
426
+ The `obs()` factory from `fnl` is used throughout for operations with intermediate results:
427
+ - Bundlers emit progress updates during compilation
428
+ - Website publisher streams build status
429
+ - Can be exposed at API level for real-time client updates
430
+ - `HTTP_Observable_Publisher` already handles SSE transport
327
431
 
328
432
  ### Complexity Areas
329
433
  - **Bundling System**: Multi-stage CSS/JS processing
@@ -99,6 +99,122 @@ server.use(middleware: Function): void
99
99
  **Parameters:**
100
100
  - `middleware` (Function): Express-style middleware function
101
101
 
102
+ ## Port Utilities
103
+
104
+ The `port-utils` module provides automatic port selection to avoid conflicts.
105
+
106
+ ### get_free_port(options)
107
+
108
+ Find a free port on the system.
109
+
110
+ **Signature:**
111
+ ```javascript
112
+ get_free_port(options?: PortOptions): Promise<number>
113
+ ```
114
+
115
+ **Parameters:**
116
+ - `options.host` (string, optional): Host to check (default: '127.0.0.1')
117
+ - `options.startPort` (number, optional): Starting port to try (default: 0 = OS chooses)
118
+ - `options.endPort` (number, optional): Maximum port to try (default: 65535)
119
+
120
+ **Returns:** Promise resolving to an available port number
121
+
122
+ **Example:**
123
+ ```javascript
124
+ const { get_free_port } = require('jsgui3-server');
125
+
126
+ const port = await get_free_port();
127
+ console.log(`Using port: ${port}`);
128
+
129
+ // Or with options
130
+ const port = await get_free_port({ startPort: 8080 });
131
+ ```
132
+
133
+ ### is_port_available(port, host)
134
+
135
+ Check if a specific port is available.
136
+
137
+ **Signature:**
138
+ ```javascript
139
+ is_port_available(port: number, host?: string): Promise<boolean>
140
+ ```
141
+
142
+ **Parameters:**
143
+ - `port` (number): Port to check
144
+ - `host` (string, optional): Host to check (default: '127.0.0.1')
145
+
146
+ **Returns:** Promise resolving to `true` if available, `false` if in use
147
+
148
+ **Example:**
149
+ ```javascript
150
+ const { is_port_available } = require('jsgui3-server');
151
+
152
+ if (await is_port_available(8080)) {
153
+ console.log('Port 8080 is free');
154
+ }
155
+ ```
156
+
157
+ ### get_free_ports(count, options)
158
+
159
+ Find multiple free ports.
160
+
161
+ **Signature:**
162
+ ```javascript
163
+ get_free_ports(count: number, options?: PortOptions): Promise<number[]>
164
+ ```
165
+
166
+ **Parameters:**
167
+ - `count` (number): Number of ports to find
168
+ - `options` (PortOptions, optional): Same as `get_free_port`
169
+
170
+ **Returns:** Promise resolving to array of available port numbers
171
+
172
+ ### get_port_or_free(preferred_port, host)
173
+
174
+ Get a specific port if available, otherwise find a free one.
175
+
176
+ **Signature:**
177
+ ```javascript
178
+ get_port_or_free(preferred_port: number, host?: string): Promise<number>
179
+ ```
180
+
181
+ **Parameters:**
182
+ - `preferred_port` (number): Preferred port (0 = auto-select)
183
+ - `host` (string, optional): Host to check (default: '127.0.0.1')
184
+
185
+ **Returns:** Promise resolving to the preferred port if available, or a free port
186
+
187
+ **Example:**
188
+ ```javascript
189
+ const { get_port_or_free } = require('jsgui3-server');
190
+
191
+ // Try 8080, fall back to any free port
192
+ const port = await get_port_or_free(8080);
193
+ ```
194
+
195
+ ### Auto-Port in Server.serve()
196
+
197
+ The `Server.serve()` API supports automatic port selection:
198
+
199
+ ```javascript
200
+ const Server = require('jsgui3-server');
201
+
202
+ // Auto-select a free port
203
+ Server.serve({
204
+ Ctrl: MyControl,
205
+ port: 'auto' // or port: 0
206
+ }).then(server => {
207
+ console.log(`Running on port ${server.port}`);
208
+ });
209
+
210
+ // Or use autoPort option
211
+ Server.serve({
212
+ Ctrl: MyControl,
213
+ autoPort: true,
214
+ port: 8080 // Will fall back to free port if 8080 is in use
215
+ });
216
+ ```
217
+
102
218
  ## Control Classes
103
219
 
104
220
  ### Active_HTML_Document
@@ -155,6 +155,24 @@ const button = new controls.Button({
155
155
  });
156
156
  ```
157
157
 
158
+ > **⚠️ Important: Text Content Patterns**
159
+ >
160
+ > Different controls handle text content differently:
161
+ >
162
+ > **Composite controls** (Button, Checkbox, etc.) accept `text` in spec:
163
+ > ```javascript
164
+ > const button = new controls.Button({ context, text: 'Click Me' }); // ✅ Works
165
+ > ```
166
+ >
167
+ > **HTML element controls** (div, span, h2, etc.) require `.add()` method:
168
+ > ```javascript
169
+ > const title = new controls.h2({ context });
170
+ > title.add('My Heading'); // ✅ Correct
171
+ > // title.text = 'My Heading'; // ❌ Won't render
172
+ > ```
173
+ >
174
+ > See [Text Content](#text-content-in-controls) section for details.
175
+
158
176
  #### Text_Input
159
177
 
160
178
  **Purpose:** Text input field control.
@@ -408,6 +426,115 @@ if (this.body.has_class('active')) {
408
426
  }
409
427
  ```
410
428
 
429
+ ## Text Content in Controls
430
+
431
+ ### The `.add()` Method (For HTML Elements)
432
+
433
+ For basic HTML element controls (`div`, `span`, `h2`, `p`, etc.), use the `.add()` method to add text content:
434
+
435
+ ```javascript
436
+ // ✅ Correct: Use .add() for HTML elements
437
+ const title = new controls.h2({ context });
438
+ title.add('My Page Title');
439
+ container.add(title);
440
+
441
+ const paragraph = new controls.div({ context, 'class': 'content' });
442
+ paragraph.add('This is the text content.');
443
+ container.add(paragraph);
444
+
445
+ const label = new controls.span({ context });
446
+ label.add('Label: ');
447
+ container.add(label);
448
+ ```
449
+
450
+ ### The `text` Property (For Composite Controls)
451
+
452
+ Some composite controls like `Button`, `Checkbox`, and custom controls explicitly handle the `text` property:
453
+
454
+ ```javascript
455
+ // ✅ Correct: Button handles text property
456
+ const button = new controls.Button({
457
+ context,
458
+ text: 'Submit Form'
459
+ });
460
+
461
+ // ✅ Checkbox uses label.text
462
+ const checkbox = new controls.Checkbox({
463
+ context,
464
+ label: { text: 'Accept terms' }
465
+ });
466
+ ```
467
+
468
+ ### Common Mistake: Text Not Rendering
469
+
470
+ ```javascript
471
+ // ❌ WRONG: text property won't render for div/h2/span
472
+ const title = new controls.h2({
473
+ context,
474
+ text: 'This will NOT appear' // Won't render!
475
+ });
476
+
477
+ // ❌ WRONG: .text assignment won't render
478
+ const div = new controls.div({ context });
479
+ div.text = 'This also won\'t appear'; // Won't render!
480
+
481
+ // ✅ CORRECT: Use .add() method
482
+ const title = new controls.h2({ context });
483
+ title.add('This WILL appear'); // ✅ Renders correctly
484
+ ```
485
+
486
+ ### Why This Pattern Exists
487
+
488
+ JSGUI3 follows the DOM model where text is a child node, not a property. The `.add()` method creates a `Text_Node` child that renders properly both server-side and client-side.
489
+
490
+ Composite controls like `Button` have a `compose_button()` method that internally calls `this.add(this.text)`, which is why they work differently.
491
+
492
+ ### Setting Element IDs
493
+
494
+ To set an element's ID attribute for client-side access:
495
+
496
+ ```javascript
497
+ // ✅ Correct: Use dom.attributes.id
498
+ const status_div = new controls.div({ context });
499
+ status_div.dom.attributes.id = 'status-display';
500
+ status_div.add('Ready');
501
+ container.add(status_div);
502
+
503
+ // In activate(), access via getElementById:
504
+ activate() {
505
+ if (!this.__active) {
506
+ super.activate();
507
+ const status = document.getElementById('status-display');
508
+ status.textContent = 'Active'; // Update via DOM
509
+ }
510
+ }
511
+ ```
512
+
513
+ ### Control Naming Conventions
514
+
515
+ JSGUI3 controls follow specific naming patterns:
516
+
517
+ | Type | Naming | Examples |
518
+ |------|--------|----------|
519
+ | HTML elements | lowercase | `controls.div`, `controls.span`, `controls.h2`, `controls.button` (native) |
520
+ | Composite controls | PascalCase | `controls.Button`, `controls.Window`, `controls.Checkbox`, `controls.Panel` |
521
+ | Custom controls | PascalCase | `controls.My_Custom_Control`, `controls.Dashboard` |
522
+
523
+ ```javascript
524
+ // HTML elements (lowercase)
525
+ const div = new controls.div({ context });
526
+ const span = new controls.span({ context });
527
+ const h1 = new controls.h1({ context });
528
+
529
+ // Composite controls (PascalCase)
530
+ const button = new controls.Button({ context, text: 'Click' });
531
+ const window = new controls.Window({ context, title: 'My Window' });
532
+ const checkbox = new controls.Checkbox({ context });
533
+ ```
534
+
535
+ > **Note:** `controls.button` (lowercase) creates a native `<button>` element without Button class features.
536
+ > `controls.Button` (PascalCase) creates the full Button control with text handling and styling.
537
+
411
538
  ### CSS Extraction and Bundling
412
539
 
413
540
  CSS is automatically extracted from control classes and bundled by the server: