juxscript 1.1.63 → 1.1.65

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/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { alert } from './lib/components/alert.js';
2
2
  import { app } from './lib/components/app.js';
3
3
  import { badge } from './lib/components/badge.js';
4
+ import { blueprint } from './lib/components/blueprint.js';
4
5
  import { button } from './lib/components/button.js';
5
6
  import { card } from './lib/components/card.js';
6
7
  import { chart } from './lib/components/chart.js';
@@ -49,6 +50,7 @@ export declare const jux: {
49
50
  alert: typeof alert;
50
51
  app: typeof app;
51
52
  badge: typeof badge;
53
+ blueprint: typeof blueprint;
52
54
  button: typeof button;
53
55
  card: typeof card;
54
56
  chart: typeof chart;
package/index.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
package/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { alert } from './lib/components/alert.js';
2
2
  import { app } from './lib/components/app.js';
3
3
  import { badge } from './lib/components/badge.js';
4
+ import { blueprint } from './lib/components/blueprint.js';
4
5
  import { button } from './lib/components/button.js';
5
6
  import { card } from './lib/components/card.js';
6
7
  import { chart } from './lib/components/chart.js';
@@ -52,6 +53,7 @@ export const jux = {
52
53
  alert,
53
54
  app,
54
55
  badge,
56
+ blueprint,
55
57
  button,
56
58
  card,
57
59
  chart,
@@ -0,0 +1,47 @@
1
+ import { BaseComponent, BaseState } from './base/BaseComponent.js';
2
+ export interface BlueprintOptions {
3
+ componentId?: string;
4
+ showClasses?: boolean;
5
+ showIds?: boolean;
6
+ showTags?: boolean;
7
+ expandAll?: boolean;
8
+ theme?: 'light' | 'dark' | 'auto';
9
+ interactive?: boolean;
10
+ style?: string;
11
+ class?: string;
12
+ }
13
+ interface BlueprintState extends BaseState {
14
+ componentId: string;
15
+ showClasses: boolean;
16
+ showIds: boolean;
17
+ showTags: boolean;
18
+ expandAll: boolean;
19
+ theme: string;
20
+ interactive: boolean;
21
+ selectedNode: string | null;
22
+ hoveredNode: string | null;
23
+ }
24
+ export declare class Blueprint extends BaseComponent<BlueprintState> {
25
+ private _domStructure;
26
+ constructor(id: string, options?: BlueprintOptions);
27
+ protected getTriggerEvents(): readonly string[];
28
+ protected getCallbackEvents(): readonly string[];
29
+ componentId(value: string): this;
30
+ showClasses(value: boolean): this;
31
+ showIds(value: boolean): this;
32
+ showTags(value: boolean): this;
33
+ expandAll(value: boolean): this;
34
+ theme(value: 'light' | 'dark' | 'auto'): this;
35
+ interactive(value: boolean): this;
36
+ selectNode(path: string): this;
37
+ private _analyzeDOMStructure;
38
+ private _renderNode;
39
+ private _renderTree;
40
+ update(prop: string, value: any): void;
41
+ private _rebuildTree;
42
+ private _updateNodeStates;
43
+ render(targetId?: string | HTMLElement | BaseComponent<any>): this;
44
+ }
45
+ export declare function blueprint(id: string, options?: BlueprintOptions): Blueprint;
46
+ export {};
47
+ //# sourceMappingURL=blueprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blueprint.d.ts","sourceRoot":"","sources":["blueprint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAOnE,MAAM,WAAW,gBAAgB;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IAClC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,cAAe,SAAQ,SAAS;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAWD,qBAAa,SAAU,SAAQ,aAAa,CAAC,cAAc,CAAC;IACxD,OAAO,CAAC,aAAa,CAAiB;gBAE1B,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB;IAgBtD,SAAS,CAAC,gBAAgB,IAAI,SAAS,MAAM,EAAE;IAI/C,SAAS,CAAC,iBAAiB,IAAI,SAAS,MAAM,EAAE;IAQhD,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKhC,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAKjC,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAK7B,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAK9B,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAK/B,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI;IAK7C,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAKjC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAU9B,OAAO,CAAC,oBAAoB;IAmC5B,OAAO,CAAC,WAAW;IAyFnB,OAAO,CAAC,WAAW;IAwBnB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAiCtC,OAAO,CAAC,YAAY;IAmBpB,OAAO,CAAC,iBAAiB;IAiBzB,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI;CA8FrE;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS,CAE/E"}
@@ -0,0 +1,330 @@
1
+ import { BaseComponent } from './base/BaseComponent.js';
2
+ import { registry } from './registry.js';
3
+ // Event definitions
4
+ const TRIGGER_EVENTS = [];
5
+ const CALLBACK_EVENTS = ['select', 'hover'];
6
+ export class Blueprint extends BaseComponent {
7
+ constructor(id, options = {}) {
8
+ super(id, {
9
+ componentId: options.componentId ?? '',
10
+ showClasses: options.showClasses ?? true,
11
+ showIds: options.showIds ?? true,
12
+ showTags: options.showTags ?? true,
13
+ expandAll: options.expandAll ?? true,
14
+ theme: options.theme ?? 'auto',
15
+ interactive: options.interactive ?? true,
16
+ selectedNode: null,
17
+ hoveredNode: null,
18
+ style: options.style ?? '',
19
+ class: options.class ?? ''
20
+ });
21
+ this._domStructure = [];
22
+ }
23
+ getTriggerEvents() {
24
+ return TRIGGER_EVENTS;
25
+ }
26
+ getCallbackEvents() {
27
+ return CALLBACK_EVENTS;
28
+ }
29
+ /* ═════════════════════════════════════════════════════════════════
30
+ * FLUENT API
31
+ * ═════════════════════════════════════════════════════════════════ */
32
+ componentId(value) {
33
+ this.state.componentId = value;
34
+ return this;
35
+ }
36
+ showClasses(value) {
37
+ this.state.showClasses = value;
38
+ return this;
39
+ }
40
+ showIds(value) {
41
+ this.state.showIds = value;
42
+ return this;
43
+ }
44
+ showTags(value) {
45
+ this.state.showTags = value;
46
+ return this;
47
+ }
48
+ expandAll(value) {
49
+ this.state.expandAll = value;
50
+ return this;
51
+ }
52
+ theme(value) {
53
+ this.state.theme = value;
54
+ return this;
55
+ }
56
+ interactive(value) {
57
+ this.state.interactive = value;
58
+ return this;
59
+ }
60
+ selectNode(path) {
61
+ this.state.selectedNode = path;
62
+ this._triggerCallback('select', path);
63
+ return this;
64
+ }
65
+ /* ═════════════════════════════════════════════════════════════════
66
+ * DOM ANALYSIS
67
+ * ═════════════════════════════════════════════════════════════════ */
68
+ _analyzeDOMStructure(componentId) {
69
+ const component = registry.get(componentId);
70
+ if (!component || !component.container) {
71
+ return [];
72
+ }
73
+ const rootElement = component.container.querySelector(`#${componentId}`);
74
+ if (!rootElement) {
75
+ return [];
76
+ }
77
+ const extractNode = (element, depth = 0, path = '0') => {
78
+ const node = {
79
+ tag: element.tagName.toLowerCase(),
80
+ classes: Array.from(element.classList),
81
+ id: element.id || null,
82
+ depth,
83
+ path,
84
+ children: []
85
+ };
86
+ Array.from(element.children).forEach((child, index) => {
87
+ node.children.push(extractNode(child, depth + 1, `${path}.${index}`));
88
+ });
89
+ return node;
90
+ };
91
+ return [extractNode(rootElement)];
92
+ }
93
+ /* ═════════════════════════════════════════════════════════════════
94
+ * RENDER NODE
95
+ * ═════════════════════════════════════════════════════════════════ */
96
+ _renderNode(node, isLast = false, prefix = '') {
97
+ const { showClasses, showIds, showTags, interactive, selectedNode, hoveredNode } = this.state;
98
+ const nodeEl = document.createElement('div');
99
+ nodeEl.className = 'jux-blueprint-node';
100
+ nodeEl.dataset.path = node.path;
101
+ if (selectedNode === node.path) {
102
+ nodeEl.classList.add('jux-blueprint-node-selected');
103
+ }
104
+ if (hoveredNode === node.path) {
105
+ nodeEl.classList.add('jux-blueprint-node-hovered');
106
+ }
107
+ // Tree line
108
+ const lineEl = document.createElement('span');
109
+ lineEl.className = 'jux-blueprint-line';
110
+ const connector = isLast ? '└─' : '├─';
111
+ const indent = prefix + connector;
112
+ lineEl.textContent = indent;
113
+ nodeEl.appendChild(lineEl);
114
+ // Node content
115
+ const contentEl = document.createElement('span');
116
+ contentEl.className = 'jux-blueprint-content';
117
+ // Tag
118
+ if (showTags) {
119
+ const tagEl = document.createElement('span');
120
+ tagEl.className = 'jux-blueprint-tag';
121
+ tagEl.textContent = `<${node.tag}>`;
122
+ contentEl.appendChild(tagEl);
123
+ }
124
+ // ID
125
+ if (showIds && node.id) {
126
+ const idEl = document.createElement('span');
127
+ idEl.className = 'jux-blueprint-id';
128
+ idEl.textContent = `#${node.id}`;
129
+ contentEl.appendChild(idEl);
130
+ }
131
+ // Classes
132
+ if (showClasses && node.classes.length > 0) {
133
+ const classesEl = document.createElement('span');
134
+ classesEl.className = 'jux-blueprint-classes';
135
+ node.classes.forEach((cls, index) => {
136
+ const classEl = document.createElement('span');
137
+ classEl.className = 'jux-blueprint-class';
138
+ classEl.textContent = `.${cls}`;
139
+ classesEl.appendChild(classEl);
140
+ if (index < node.classes.length - 1) {
141
+ classesEl.appendChild(document.createTextNode(' '));
142
+ }
143
+ });
144
+ contentEl.appendChild(classesEl);
145
+ }
146
+ nodeEl.appendChild(contentEl);
147
+ // Interactive behavior
148
+ if (interactive) {
149
+ nodeEl.style.cursor = 'pointer';
150
+ nodeEl.addEventListener('click', (e) => {
151
+ e.stopPropagation();
152
+ this.state.selectedNode = node.path;
153
+ this._triggerCallback('select', node);
154
+ });
155
+ nodeEl.addEventListener('mouseenter', () => {
156
+ this.state.hoveredNode = node.path;
157
+ this._triggerCallback('hover', node);
158
+ });
159
+ nodeEl.addEventListener('mouseleave', () => {
160
+ if (this.state.hoveredNode === node.path) {
161
+ this.state.hoveredNode = null;
162
+ }
163
+ });
164
+ }
165
+ return nodeEl;
166
+ }
167
+ _renderTree(nodes, prefix = '') {
168
+ const treeEl = document.createElement('div');
169
+ treeEl.className = 'jux-blueprint-tree';
170
+ nodes.forEach((node, index) => {
171
+ const isLast = index === nodes.length - 1;
172
+ const nodeEl = this._renderNode(node, isLast, prefix);
173
+ treeEl.appendChild(nodeEl);
174
+ // Render children
175
+ if (node.children.length > 0) {
176
+ const childPrefix = prefix + (isLast ? ' ' : '│ ');
177
+ const childrenEl = this._renderTree(node.children, childPrefix);
178
+ treeEl.appendChild(childrenEl);
179
+ }
180
+ });
181
+ return treeEl;
182
+ }
183
+ /* ═════════════════════════════════════════════════════════════════
184
+ * REACTIVE UPDATE
185
+ * ═════════════════════════════════════════════════════════════════ */
186
+ update(prop, value) {
187
+ super.update(prop, value);
188
+ if (!this.container)
189
+ return;
190
+ const blueprint = this.container.querySelector(`#${this._id}`);
191
+ if (!blueprint)
192
+ return;
193
+ switch (prop) {
194
+ case 'componentId':
195
+ this._domStructure = this._analyzeDOMStructure(value);
196
+ this._rebuildTree();
197
+ break;
198
+ case 'showClasses':
199
+ case 'showIds':
200
+ case 'showTags':
201
+ case 'expandAll':
202
+ case 'interactive':
203
+ this._rebuildTree();
204
+ break;
205
+ case 'theme':
206
+ blueprint.dataset.theme = value;
207
+ break;
208
+ case 'selectedNode':
209
+ case 'hoveredNode':
210
+ this._updateNodeStates();
211
+ break;
212
+ }
213
+ }
214
+ _rebuildTree() {
215
+ if (!this.container)
216
+ return;
217
+ const treeContainer = this.container.querySelector('.jux-blueprint-tree-container');
218
+ if (!treeContainer)
219
+ return;
220
+ treeContainer.innerHTML = '';
221
+ if (this._domStructure.length > 0) {
222
+ const treeEl = this._renderTree(this._domStructure);
223
+ treeContainer.appendChild(treeEl);
224
+ }
225
+ else {
226
+ const emptyEl = document.createElement('div');
227
+ emptyEl.className = 'jux-blueprint-empty';
228
+ emptyEl.textContent = 'No component selected or component not found';
229
+ treeContainer.appendChild(emptyEl);
230
+ }
231
+ }
232
+ _updateNodeStates() {
233
+ if (!this.container)
234
+ return;
235
+ const nodes = this.container.querySelectorAll('.jux-blueprint-node');
236
+ nodes.forEach(node => {
237
+ const el = node;
238
+ const path = el.dataset.path;
239
+ el.classList.toggle('jux-blueprint-node-selected', path === this.state.selectedNode);
240
+ el.classList.toggle('jux-blueprint-node-hovered', path === this.state.hoveredNode);
241
+ });
242
+ }
243
+ /* ═════════════════════════════════════════════════════════════════
244
+ * RENDER
245
+ * ═════════════════════════════════════════════════════════════════ */
246
+ render(targetId) {
247
+ const container = this._setupContainer(targetId);
248
+ const { componentId, theme, style, class: className } = this.state;
249
+ // Analyze structure if componentId is provided
250
+ if (componentId) {
251
+ this._domStructure = this._analyzeDOMStructure(componentId);
252
+ }
253
+ // Create wrapper
254
+ const wrapper = document.createElement('div');
255
+ wrapper.className = 'jux-blueprint';
256
+ wrapper.id = this._id;
257
+ wrapper.dataset.theme = theme;
258
+ if (className)
259
+ wrapper.className += ` ${className}`;
260
+ if (style)
261
+ wrapper.setAttribute('style', style);
262
+ // Header
263
+ const header = document.createElement('div');
264
+ header.className = 'jux-blueprint-header';
265
+ const title = document.createElement('h3');
266
+ title.className = 'jux-blueprint-title';
267
+ title.textContent = componentId ? `Blueprint: ${componentId}` : 'Component Blueprint';
268
+ header.appendChild(title);
269
+ // Controls
270
+ const controls = document.createElement('div');
271
+ controls.className = 'jux-blueprint-controls';
272
+ const toggles = [
273
+ { prop: 'showTags', label: 'Tags' },
274
+ { prop: 'showIds', label: 'IDs' },
275
+ { prop: 'showClasses', label: 'Classes' }
276
+ ];
277
+ toggles.forEach(({ prop, label }) => {
278
+ const toggleEl = document.createElement('label');
279
+ toggleEl.className = 'jux-blueprint-toggle';
280
+ const checkbox = document.createElement('input');
281
+ checkbox.type = 'checkbox';
282
+ checkbox.checked = this.state[prop];
283
+ checkbox.addEventListener('change', () => {
284
+ this.state[prop] = checkbox.checked;
285
+ });
286
+ toggleEl.appendChild(checkbox);
287
+ toggleEl.appendChild(document.createTextNode(` ${label}`));
288
+ controls.appendChild(toggleEl);
289
+ });
290
+ header.appendChild(controls);
291
+ wrapper.appendChild(header);
292
+ // Tree container
293
+ const treeContainer = document.createElement('div');
294
+ treeContainer.className = 'jux-blueprint-tree-container';
295
+ if (this._domStructure.length > 0) {
296
+ const treeEl = this._renderTree(this._domStructure);
297
+ treeContainer.appendChild(treeEl);
298
+ }
299
+ else {
300
+ const emptyEl = document.createElement('div');
301
+ emptyEl.className = 'jux-blueprint-empty';
302
+ emptyEl.textContent = componentId
303
+ ? `Component "${componentId}" not found or not rendered`
304
+ : 'Set componentId to analyze a component';
305
+ treeContainer.appendChild(emptyEl);
306
+ }
307
+ wrapper.appendChild(treeContainer);
308
+ // Legend
309
+ const legend = document.createElement('div');
310
+ legend.className = 'jux-blueprint-legend';
311
+ legend.innerHTML = `
312
+ <span class="jux-blueprint-legend-item">
313
+ <span class="jux-blueprint-tag">&lt;tag&gt;</span> HTML Element
314
+ </span>
315
+ <span class="jux-blueprint-legend-item">
316
+ <span class="jux-blueprint-id">#id</span> Element ID
317
+ </span>
318
+ <span class="jux-blueprint-legend-item">
319
+ <span class="jux-blueprint-class">.class</span> CSS Class
320
+ </span>
321
+ `;
322
+ wrapper.appendChild(legend);
323
+ this._wireStandardEvents(wrapper);
324
+ container.appendChild(wrapper);
325
+ return this;
326
+ }
327
+ }
328
+ export function blueprint(id, options = {}) {
329
+ return new Blueprint(id, options);
330
+ }
@@ -0,0 +1,432 @@
1
+ import { BaseComponent, BaseState } from './base/BaseComponent.js';
2
+ import { registry } from './registry.js';
3
+
4
+ // Event definitions
5
+ const TRIGGER_EVENTS = [] as const;
6
+ const CALLBACK_EVENTS = ['select', 'hover'] as const;
7
+
8
+ export interface BlueprintOptions {
9
+ componentId?: string;
10
+ showClasses?: boolean;
11
+ showIds?: boolean;
12
+ showTags?: boolean;
13
+ expandAll?: boolean;
14
+ theme?: 'light' | 'dark' | 'auto';
15
+ interactive?: boolean;
16
+ style?: string;
17
+ class?: string;
18
+ }
19
+
20
+ interface BlueprintState extends BaseState {
21
+ componentId: string;
22
+ showClasses: boolean;
23
+ showIds: boolean;
24
+ showTags: boolean;
25
+ expandAll: boolean;
26
+ theme: string;
27
+ interactive: boolean;
28
+ selectedNode: string | null;
29
+ hoveredNode: string | null;
30
+ }
31
+
32
+ interface DOMNode {
33
+ tag: string;
34
+ classes: string[];
35
+ id: string | null;
36
+ depth: number;
37
+ path: string;
38
+ children: DOMNode[];
39
+ }
40
+
41
+ export class Blueprint extends BaseComponent<BlueprintState> {
42
+ private _domStructure: DOMNode[] = [];
43
+
44
+ constructor(id: string, options: BlueprintOptions = {}) {
45
+ super(id, {
46
+ componentId: options.componentId ?? '',
47
+ showClasses: options.showClasses ?? true,
48
+ showIds: options.showIds ?? true,
49
+ showTags: options.showTags ?? true,
50
+ expandAll: options.expandAll ?? true,
51
+ theme: options.theme ?? 'auto',
52
+ interactive: options.interactive ?? true,
53
+ selectedNode: null,
54
+ hoveredNode: null,
55
+ style: options.style ?? '',
56
+ class: options.class ?? ''
57
+ });
58
+ }
59
+
60
+ protected getTriggerEvents(): readonly string[] {
61
+ return TRIGGER_EVENTS;
62
+ }
63
+
64
+ protected getCallbackEvents(): readonly string[] {
65
+ return CALLBACK_EVENTS;
66
+ }
67
+
68
+ /* ═════════════════════════════════════════════════════════════════
69
+ * FLUENT API
70
+ * ═════════════════════════════════════════════════════════════════ */
71
+
72
+ componentId(value: string): this {
73
+ this.state.componentId = value;
74
+ return this;
75
+ }
76
+
77
+ showClasses(value: boolean): this {
78
+ this.state.showClasses = value;
79
+ return this;
80
+ }
81
+
82
+ showIds(value: boolean): this {
83
+ this.state.showIds = value;
84
+ return this;
85
+ }
86
+
87
+ showTags(value: boolean): this {
88
+ this.state.showTags = value;
89
+ return this;
90
+ }
91
+
92
+ expandAll(value: boolean): this {
93
+ this.state.expandAll = value;
94
+ return this;
95
+ }
96
+
97
+ theme(value: 'light' | 'dark' | 'auto'): this {
98
+ this.state.theme = value;
99
+ return this;
100
+ }
101
+
102
+ interactive(value: boolean): this {
103
+ this.state.interactive = value;
104
+ return this;
105
+ }
106
+
107
+ selectNode(path: string): this {
108
+ this.state.selectedNode = path;
109
+ this._triggerCallback('select', path);
110
+ return this;
111
+ }
112
+
113
+ /* ═════════════════════════════════════════════════════════════════
114
+ * DOM ANALYSIS
115
+ * ═════════════════════════════════════════════════════════════════ */
116
+
117
+ private _analyzeDOMStructure(componentId: string): DOMNode[] {
118
+ const component = registry.get(componentId);
119
+ if (!component || !component.container) {
120
+ return [];
121
+ }
122
+
123
+ const rootElement = component.container.querySelector(`#${componentId}`);
124
+ if (!rootElement) {
125
+ return [];
126
+ }
127
+
128
+ const extractNode = (element: Element, depth: number = 0, path: string = '0'): DOMNode => {
129
+ const node: DOMNode = {
130
+ tag: element.tagName.toLowerCase(),
131
+ classes: Array.from(element.classList),
132
+ id: element.id || null,
133
+ depth,
134
+ path,
135
+ children: []
136
+ };
137
+
138
+ Array.from(element.children).forEach((child, index) => {
139
+ node.children.push(extractNode(child, depth + 1, `${path}.${index}`));
140
+ });
141
+
142
+ return node;
143
+ };
144
+
145
+ return [extractNode(rootElement)];
146
+ }
147
+
148
+ /* ═════════════════════════════════════════════════════════════════
149
+ * RENDER NODE
150
+ * ═════════════════════════════════════════════════════════════════ */
151
+
152
+ private _renderNode(node: DOMNode, isLast: boolean = false, prefix: string = ''): HTMLElement {
153
+ const { showClasses, showIds, showTags, interactive, selectedNode, hoveredNode } = this.state;
154
+
155
+ const nodeEl = document.createElement('div');
156
+ nodeEl.className = 'jux-blueprint-node';
157
+ nodeEl.dataset.path = node.path;
158
+
159
+ if (selectedNode === node.path) {
160
+ nodeEl.classList.add('jux-blueprint-node-selected');
161
+ }
162
+ if (hoveredNode === node.path) {
163
+ nodeEl.classList.add('jux-blueprint-node-hovered');
164
+ }
165
+
166
+ // Tree line
167
+ const lineEl = document.createElement('span');
168
+ lineEl.className = 'jux-blueprint-line';
169
+
170
+ const connector = isLast ? '└─' : '├─';
171
+ const indent = prefix + connector;
172
+ lineEl.textContent = indent;
173
+ nodeEl.appendChild(lineEl);
174
+
175
+ // Node content
176
+ const contentEl = document.createElement('span');
177
+ contentEl.className = 'jux-blueprint-content';
178
+
179
+ // Tag
180
+ if (showTags) {
181
+ const tagEl = document.createElement('span');
182
+ tagEl.className = 'jux-blueprint-tag';
183
+ tagEl.textContent = `<${node.tag}>`;
184
+ contentEl.appendChild(tagEl);
185
+ }
186
+
187
+ // ID
188
+ if (showIds && node.id) {
189
+ const idEl = document.createElement('span');
190
+ idEl.className = 'jux-blueprint-id';
191
+ idEl.textContent = `#${node.id}`;
192
+ contentEl.appendChild(idEl);
193
+ }
194
+
195
+ // Classes
196
+ if (showClasses && node.classes.length > 0) {
197
+ const classesEl = document.createElement('span');
198
+ classesEl.className = 'jux-blueprint-classes';
199
+
200
+ node.classes.forEach((cls, index) => {
201
+ const classEl = document.createElement('span');
202
+ classEl.className = 'jux-blueprint-class';
203
+ classEl.textContent = `.${cls}`;
204
+ classesEl.appendChild(classEl);
205
+
206
+ if (index < node.classes.length - 1) {
207
+ classesEl.appendChild(document.createTextNode(' '));
208
+ }
209
+ });
210
+
211
+ contentEl.appendChild(classesEl);
212
+ }
213
+
214
+ nodeEl.appendChild(contentEl);
215
+
216
+ // Interactive behavior
217
+ if (interactive) {
218
+ nodeEl.style.cursor = 'pointer';
219
+
220
+ nodeEl.addEventListener('click', (e) => {
221
+ e.stopPropagation();
222
+ this.state.selectedNode = node.path;
223
+ this._triggerCallback('select', node);
224
+ });
225
+
226
+ nodeEl.addEventListener('mouseenter', () => {
227
+ this.state.hoveredNode = node.path;
228
+ this._triggerCallback('hover', node);
229
+ });
230
+
231
+ nodeEl.addEventListener('mouseleave', () => {
232
+ if (this.state.hoveredNode === node.path) {
233
+ this.state.hoveredNode = null;
234
+ }
235
+ });
236
+ }
237
+
238
+ return nodeEl;
239
+ }
240
+
241
+ private _renderTree(nodes: DOMNode[], prefix: string = ''): HTMLElement {
242
+ const treeEl = document.createElement('div');
243
+ treeEl.className = 'jux-blueprint-tree';
244
+
245
+ nodes.forEach((node, index) => {
246
+ const isLast = index === nodes.length - 1;
247
+ const nodeEl = this._renderNode(node, isLast, prefix);
248
+ treeEl.appendChild(nodeEl);
249
+
250
+ // Render children
251
+ if (node.children.length > 0) {
252
+ const childPrefix = prefix + (isLast ? ' ' : '│ ');
253
+ const childrenEl = this._renderTree(node.children, childPrefix);
254
+ treeEl.appendChild(childrenEl);
255
+ }
256
+ });
257
+
258
+ return treeEl;
259
+ }
260
+
261
+ /* ═════════════════════════════════════════════════════════════════
262
+ * REACTIVE UPDATE
263
+ * ═════════════════════════════════════════════════════════════════ */
264
+
265
+ update(prop: string, value: any): void {
266
+ super.update(prop, value);
267
+
268
+ if (!this.container) return;
269
+
270
+ const blueprint = this.container.querySelector(`#${this._id}`) as HTMLElement;
271
+ if (!blueprint) return;
272
+
273
+ switch (prop) {
274
+ case 'componentId':
275
+ this._domStructure = this._analyzeDOMStructure(value);
276
+ this._rebuildTree();
277
+ break;
278
+
279
+ case 'showClasses':
280
+ case 'showIds':
281
+ case 'showTags':
282
+ case 'expandAll':
283
+ case 'interactive':
284
+ this._rebuildTree();
285
+ break;
286
+
287
+ case 'theme':
288
+ blueprint.dataset.theme = value;
289
+ break;
290
+
291
+ case 'selectedNode':
292
+ case 'hoveredNode':
293
+ this._updateNodeStates();
294
+ break;
295
+ }
296
+ }
297
+
298
+ private _rebuildTree(): void {
299
+ if (!this.container) return;
300
+
301
+ const treeContainer = this.container.querySelector('.jux-blueprint-tree-container');
302
+ if (!treeContainer) return;
303
+
304
+ treeContainer.innerHTML = '';
305
+
306
+ if (this._domStructure.length > 0) {
307
+ const treeEl = this._renderTree(this._domStructure);
308
+ treeContainer.appendChild(treeEl);
309
+ } else {
310
+ const emptyEl = document.createElement('div');
311
+ emptyEl.className = 'jux-blueprint-empty';
312
+ emptyEl.textContent = 'No component selected or component not found';
313
+ treeContainer.appendChild(emptyEl);
314
+ }
315
+ }
316
+
317
+ private _updateNodeStates(): void {
318
+ if (!this.container) return;
319
+
320
+ const nodes = this.container.querySelectorAll('.jux-blueprint-node');
321
+ nodes.forEach(node => {
322
+ const el = node as HTMLElement;
323
+ const path = el.dataset.path;
324
+
325
+ el.classList.toggle('jux-blueprint-node-selected', path === this.state.selectedNode);
326
+ el.classList.toggle('jux-blueprint-node-hovered', path === this.state.hoveredNode);
327
+ });
328
+ }
329
+
330
+ /* ═════════════════════════════════════════════════════════════════
331
+ * RENDER
332
+ * ═════════════════════════════════════════════════════════════════ */
333
+
334
+ render(targetId?: string | HTMLElement | BaseComponent<any>): this {
335
+ const container = this._setupContainer(targetId);
336
+ const { componentId, theme, style, class: className } = this.state;
337
+
338
+ // Analyze structure if componentId is provided
339
+ if (componentId) {
340
+ this._domStructure = this._analyzeDOMStructure(componentId);
341
+ }
342
+
343
+ // Create wrapper
344
+ const wrapper = document.createElement('div');
345
+ wrapper.className = 'jux-blueprint';
346
+ wrapper.id = this._id;
347
+ wrapper.dataset.theme = theme;
348
+ if (className) wrapper.className += ` ${className}`;
349
+ if (style) wrapper.setAttribute('style', style);
350
+
351
+ // Header
352
+ const header = document.createElement('div');
353
+ header.className = 'jux-blueprint-header';
354
+
355
+ const title = document.createElement('h3');
356
+ title.className = 'jux-blueprint-title';
357
+ title.textContent = componentId ? `Blueprint: ${componentId}` : 'Component Blueprint';
358
+ header.appendChild(title);
359
+
360
+ // Controls
361
+ const controls = document.createElement('div');
362
+ controls.className = 'jux-blueprint-controls';
363
+
364
+ const toggles = [
365
+ { prop: 'showTags', label: 'Tags' },
366
+ { prop: 'showIds', label: 'IDs' },
367
+ { prop: 'showClasses', label: 'Classes' }
368
+ ];
369
+
370
+ toggles.forEach(({ prop, label }) => {
371
+ const toggleEl = document.createElement('label');
372
+ toggleEl.className = 'jux-blueprint-toggle';
373
+
374
+ const checkbox = document.createElement('input');
375
+ checkbox.type = 'checkbox';
376
+ checkbox.checked = (this.state as any)[prop];
377
+ checkbox.addEventListener('change', () => {
378
+ (this.state as any)[prop] = checkbox.checked;
379
+ });
380
+
381
+ toggleEl.appendChild(checkbox);
382
+ toggleEl.appendChild(document.createTextNode(` ${label}`));
383
+ controls.appendChild(toggleEl);
384
+ });
385
+
386
+ header.appendChild(controls);
387
+ wrapper.appendChild(header);
388
+
389
+ // Tree container
390
+ const treeContainer = document.createElement('div');
391
+ treeContainer.className = 'jux-blueprint-tree-container';
392
+
393
+ if (this._domStructure.length > 0) {
394
+ const treeEl = this._renderTree(this._domStructure);
395
+ treeContainer.appendChild(treeEl);
396
+ } else {
397
+ const emptyEl = document.createElement('div');
398
+ emptyEl.className = 'jux-blueprint-empty';
399
+ emptyEl.textContent = componentId
400
+ ? `Component "${componentId}" not found or not rendered`
401
+ : 'Set componentId to analyze a component';
402
+ treeContainer.appendChild(emptyEl);
403
+ }
404
+
405
+ wrapper.appendChild(treeContainer);
406
+
407
+ // Legend
408
+ const legend = document.createElement('div');
409
+ legend.className = 'jux-blueprint-legend';
410
+ legend.innerHTML = `
411
+ <span class="jux-blueprint-legend-item">
412
+ <span class="jux-blueprint-tag">&lt;tag&gt;</span> HTML Element
413
+ </span>
414
+ <span class="jux-blueprint-legend-item">
415
+ <span class="jux-blueprint-id">#id</span> Element ID
416
+ </span>
417
+ <span class="jux-blueprint-legend-item">
418
+ <span class="jux-blueprint-class">.class</span> CSS Class
419
+ </span>
420
+ `;
421
+ wrapper.appendChild(legend);
422
+
423
+ this._wireStandardEvents(wrapper);
424
+ container.appendChild(wrapper);
425
+
426
+ return this;
427
+ }
428
+ }
429
+
430
+ export function blueprint(id: string, options: BlueprintOptions = {}): Blueprint {
431
+ return new Blueprint(id, options);
432
+ }
@@ -3,6 +3,7 @@ import { BaseComponent } from './base/BaseComponent.js';
3
3
  * Container options
4
4
  */
5
5
  export interface ContainerOptions {
6
+ content?: string | BaseComponent<any> | Array<string | BaseComponent<any>>;
6
7
  class?: string;
7
8
  style?: string;
8
9
  direction?: 'row' | 'column';
@@ -14,6 +15,7 @@ export interface ContainerOptions {
14
15
  * Container state
15
16
  */
16
17
  type ContainerState = {
18
+ content: string | BaseComponent<any> | Array<string | BaseComponent<any>>;
17
19
  class: string;
18
20
  style: string;
19
21
  direction?: 'row' | 'column';
@@ -25,14 +27,29 @@ type ContainerState = {
25
27
  * Container component - a simple div container for grouping elements
26
28
  */
27
29
  export declare class Container extends BaseComponent<ContainerState> {
30
+ private _containerElement;
28
31
  constructor(id: string, options?: ContainerOptions);
29
32
  protected getTriggerEvents(): readonly string[];
30
33
  protected getCallbackEvents(): readonly string[];
31
34
  update(prop: string, value: any): void;
35
+ private _updateContent;
36
+ content(value: string | BaseComponent<any> | Array<string | BaseComponent<any>>): this;
32
37
  direction(value: 'row' | 'column'): this;
33
38
  gap(value: string | number): this;
34
39
  align(value: 'start' | 'center' | 'end' | 'stretch'): this;
35
40
  justify(value: 'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly'): this;
41
+ /**
42
+ * Add content to container (supports strings and BaseComponents)
43
+ */
44
+ addContent(content: string | BaseComponent<any> | Array<string | BaseComponent<any>>): this;
45
+ /**
46
+ * Clear all content from container
47
+ */
48
+ clearContent(): this;
49
+ /**
50
+ * Get the container element ID for rendering child components
51
+ */
52
+ contentId(): string;
36
53
  render(targetId?: string | HTMLElement | BaseComponent<any>): this;
37
54
  }
38
55
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAMxD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,eAAe,GAAG,cAAc,GAAG,cAAc,CAAC;CAC1F;AAED;;GAEG;AACH,KAAK,cAAc,GAAG;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;GAEG;AACH,qBAAa,SAAU,SAAQ,aAAa,CAAC,cAAc,CAAC;gBAC9C,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB;IAWtD,SAAS,CAAC,gBAAgB,IAAI,SAAS,MAAM,EAAE;IAI/C,SAAS,CAAC,iBAAiB,IAAI,SAAS,MAAM,EAAE;IAIhD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAgBtC,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,QAAQ,GAAG,IAAI;IAKxC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKjC,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,GAAG,IAAI;IAK1D,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,eAAe,GAAG,cAAc,GAAG,cAAc,GAAG,IAAI;IASpG,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI;CA2CnE;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS,CAE/E"}
1
+ {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAMxD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,eAAe,GAAG,cAAc,GAAG,cAAc,CAAC;CAC1F;AAED;;GAEG;AACH,KAAK,cAAc,GAAG;IACpB,OAAO,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;GAEG;AACH,qBAAa,SAAU,SAAQ,aAAa,CAAC,cAAc,CAAC;IAC1D,OAAO,CAAC,iBAAiB,CAA4B;gBAEzC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB;IAYtD,SAAS,CAAC,gBAAgB,IAAI,SAAS,MAAM,EAAE;IAI/C,SAAS,CAAC,iBAAiB,IAAI,SAAS,MAAM,EAAE;IAIhD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IA6BtC,OAAO,CAAC,cAAc;IAgCtB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI;IAKtF,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,QAAQ,GAAG,IAAI;IAKxC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKjC,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,GAAG,IAAI;IAK1D,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,eAAe,GAAG,cAAc,GAAG,cAAc,GAAG,IAAI;IAKpG;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI;IAuB3F;;OAEG;IACH,YAAY,IAAI,IAAI;IAOpB;;OAEG;IACH,SAAS,IAAI,MAAM;IAQnB,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI;CA4DnE;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS,CAE/E"}
@@ -8,6 +8,7 @@ const CALLBACK_EVENTS = ['click'];
8
8
  export class Container extends BaseComponent {
9
9
  constructor(id, options = {}) {
10
10
  super(id, {
11
+ content: options.content ?? [],
11
12
  class: options.class ?? '',
12
13
  style: options.style ?? '',
13
14
  direction: options.direction,
@@ -15,6 +16,7 @@ export class Container extends BaseComponent {
15
16
  align: options.align,
16
17
  justify: options.justify
17
18
  });
19
+ this._containerElement = null;
18
20
  }
19
21
  getTriggerEvents() {
20
22
  return TRIGGER_EVENTS;
@@ -23,7 +25,45 @@ export class Container extends BaseComponent {
23
25
  return CALLBACK_EVENTS;
24
26
  }
25
27
  update(prop, value) {
26
- // No reactive updates needed
28
+ super.update(prop, value);
29
+ if (!this._containerElement)
30
+ return;
31
+ switch (prop) {
32
+ case 'content':
33
+ this._updateContent(value);
34
+ break;
35
+ case 'direction':
36
+ this._containerElement.style.flexDirection = value;
37
+ break;
38
+ case 'gap':
39
+ const gapValue = typeof value === 'number' ? `${value}px` : value;
40
+ this._containerElement.style.gap = gapValue;
41
+ break;
42
+ case 'align':
43
+ this._containerElement.style.alignItems = value;
44
+ break;
45
+ case 'justify':
46
+ this._containerElement.style.justifyContent = value;
47
+ break;
48
+ }
49
+ }
50
+ _updateContent(value) {
51
+ if (!this._containerElement)
52
+ return;
53
+ this._containerElement.innerHTML = '';
54
+ const items = Array.isArray(value) ? value : [value];
55
+ items.forEach(item => {
56
+ if (typeof item === 'string') {
57
+ const tempDiv = document.createElement('div');
58
+ tempDiv.innerHTML = item;
59
+ while (tempDiv.firstChild) {
60
+ this._containerElement.appendChild(tempDiv.firstChild);
61
+ }
62
+ }
63
+ else if (item instanceof BaseComponent) {
64
+ item.render(this._containerElement);
65
+ }
66
+ });
27
67
  }
28
68
  /* -------------------------
29
69
  * Fluent API
@@ -35,6 +75,10 @@ export class Container extends BaseComponent {
35
75
  // - visible(), show(), hide()
36
76
  // - attr(), attrs(), removeAttr()
37
77
  // - disabled(), enable(), disable()
78
+ content(value) {
79
+ this.state.content = value;
80
+ return this;
81
+ }
38
82
  direction(value) {
39
83
  this.state.direction = value;
40
84
  return this;
@@ -51,14 +95,53 @@ export class Container extends BaseComponent {
51
95
  this.state.justify = value;
52
96
  return this;
53
97
  }
98
+ /**
99
+ * Add content to container (supports strings and BaseComponents)
100
+ */
101
+ addContent(content) {
102
+ if (!this._containerElement) {
103
+ console.warn('[Container] Container element not found');
104
+ return this;
105
+ }
106
+ const items = Array.isArray(content) ? content : [content];
107
+ items.forEach(item => {
108
+ if (typeof item === 'string') {
109
+ const tempDiv = document.createElement('div');
110
+ tempDiv.innerHTML = item;
111
+ while (tempDiv.firstChild) {
112
+ this._containerElement.appendChild(tempDiv.firstChild);
113
+ }
114
+ }
115
+ else if (item instanceof BaseComponent) {
116
+ item.render(this._containerElement);
117
+ }
118
+ });
119
+ return this;
120
+ }
121
+ /**
122
+ * Clear all content from container
123
+ */
124
+ clearContent() {
125
+ if (this._containerElement) {
126
+ this._containerElement.innerHTML = '';
127
+ }
128
+ return this;
129
+ }
130
+ /**
131
+ * Get the container element ID for rendering child components
132
+ */
133
+ contentId() {
134
+ return `${this._id}-content`;
135
+ }
54
136
  /* -------------------------
55
137
  * Render
56
138
  * ------------------------- */
57
139
  render(targetId) {
58
140
  const container = this._setupContainer(targetId);
59
- const { class: className, style, direction, gap, align, justify } = this.state;
141
+ const { content, class: className, style, direction, gap, align, justify } = this.state;
60
142
  const div = document.createElement('div');
61
143
  div.id = this._id;
144
+ this._containerElement = div;
62
145
  // Always include jux-container class, append custom classes
63
146
  div.className = className ? `jux-container ${className}` : 'jux-container';
64
147
  // Only apply flex styles if any flex properties are set
@@ -83,6 +166,22 @@ export class Container extends BaseComponent {
83
166
  if (computedStyle) {
84
167
  div.setAttribute('style', computedStyle);
85
168
  }
169
+ // Render initial content
170
+ if (content) {
171
+ const items = Array.isArray(content) ? content : [content];
172
+ items.forEach(item => {
173
+ if (typeof item === 'string') {
174
+ const tempDiv = document.createElement('div');
175
+ tempDiv.innerHTML = item;
176
+ while (tempDiv.firstChild) {
177
+ div.appendChild(tempDiv.firstChild);
178
+ }
179
+ }
180
+ else if (item instanceof BaseComponent) {
181
+ item.render(div);
182
+ }
183
+ });
184
+ }
86
185
  this._wireStandardEvents(div);
87
186
  container.appendChild(div);
88
187
  return this;
@@ -8,6 +8,7 @@ const CALLBACK_EVENTS = ['click'] as const;
8
8
  * Container options
9
9
  */
10
10
  export interface ContainerOptions {
11
+ content?: string | BaseComponent<any> | Array<string | BaseComponent<any>>;
11
12
  class?: string;
12
13
  style?: string;
13
14
  direction?: 'row' | 'column';
@@ -20,6 +21,7 @@ export interface ContainerOptions {
20
21
  * Container state
21
22
  */
22
23
  type ContainerState = {
24
+ content: string | BaseComponent<any> | Array<string | BaseComponent<any>>;
23
25
  class: string;
24
26
  style: string;
25
27
  direction?: 'row' | 'column';
@@ -32,8 +34,11 @@ type ContainerState = {
32
34
  * Container component - a simple div container for grouping elements
33
35
  */
34
36
  export class Container extends BaseComponent<ContainerState> {
37
+ private _containerElement: HTMLElement | null = null;
38
+
35
39
  constructor(id: string, options: ContainerOptions = {}) {
36
40
  super(id, {
41
+ content: options.content ?? [],
37
42
  class: options.class ?? '',
38
43
  style: options.style ?? '',
39
44
  direction: options.direction,
@@ -52,7 +57,52 @@ export class Container extends BaseComponent<ContainerState> {
52
57
  }
53
58
 
54
59
  update(prop: string, value: any): void {
55
- // No reactive updates needed
60
+ super.update(prop, value);
61
+
62
+ if (!this._containerElement) return;
63
+
64
+ switch (prop) {
65
+ case 'content':
66
+ this._updateContent(value);
67
+ break;
68
+
69
+ case 'direction':
70
+ this._containerElement.style.flexDirection = value;
71
+ break;
72
+
73
+ case 'gap':
74
+ const gapValue = typeof value === 'number' ? `${value}px` : value;
75
+ this._containerElement.style.gap = gapValue;
76
+ break;
77
+
78
+ case 'align':
79
+ this._containerElement.style.alignItems = value;
80
+ break;
81
+
82
+ case 'justify':
83
+ this._containerElement.style.justifyContent = value;
84
+ break;
85
+ }
86
+ }
87
+
88
+ private _updateContent(value: string | BaseComponent<any> | Array<string | BaseComponent<any>>): void {
89
+ if (!this._containerElement) return;
90
+
91
+ this._containerElement.innerHTML = '';
92
+
93
+ const items = Array.isArray(value) ? value : [value];
94
+
95
+ items.forEach(item => {
96
+ if (typeof item === 'string') {
97
+ const tempDiv = document.createElement('div');
98
+ tempDiv.innerHTML = item;
99
+ while (tempDiv.firstChild) {
100
+ this._containerElement!.appendChild(tempDiv.firstChild);
101
+ }
102
+ } else if (item instanceof BaseComponent) {
103
+ item.render(this._containerElement!);
104
+ }
105
+ });
56
106
  }
57
107
 
58
108
  /* -------------------------
@@ -67,6 +117,11 @@ export class Container extends BaseComponent<ContainerState> {
67
117
  // - attr(), attrs(), removeAttr()
68
118
  // - disabled(), enable(), disable()
69
119
 
120
+ content(value: string | BaseComponent<any> | Array<string | BaseComponent<any>>): this {
121
+ this.state.content = value;
122
+ return this;
123
+ }
124
+
70
125
  direction(value: 'row' | 'column'): this {
71
126
  this.state.direction = value;
72
127
  return this;
@@ -87,6 +142,49 @@ export class Container extends BaseComponent<ContainerState> {
87
142
  return this;
88
143
  }
89
144
 
145
+ /**
146
+ * Add content to container (supports strings and BaseComponents)
147
+ */
148
+ addContent(content: string | BaseComponent<any> | Array<string | BaseComponent<any>>): this {
149
+ if (!this._containerElement) {
150
+ console.warn('[Container] Container element not found');
151
+ return this;
152
+ }
153
+
154
+ const items = Array.isArray(content) ? content : [content];
155
+
156
+ items.forEach(item => {
157
+ if (typeof item === 'string') {
158
+ const tempDiv = document.createElement('div');
159
+ tempDiv.innerHTML = item;
160
+ while (tempDiv.firstChild) {
161
+ this._containerElement!.appendChild(tempDiv.firstChild);
162
+ }
163
+ } else if (item instanceof BaseComponent) {
164
+ item.render(this._containerElement!);
165
+ }
166
+ });
167
+
168
+ return this;
169
+ }
170
+
171
+ /**
172
+ * Clear all content from container
173
+ */
174
+ clearContent(): this {
175
+ if (this._containerElement) {
176
+ this._containerElement.innerHTML = '';
177
+ }
178
+ return this;
179
+ }
180
+
181
+ /**
182
+ * Get the container element ID for rendering child components
183
+ */
184
+ contentId(): string {
185
+ return `${this._id}-content`;
186
+ }
187
+
90
188
  /* -------------------------
91
189
  * Render
92
190
  * ------------------------- */
@@ -94,10 +192,11 @@ export class Container extends BaseComponent<ContainerState> {
94
192
  render(targetId?: string | HTMLElement | BaseComponent<any>): this {
95
193
  const container = this._setupContainer(targetId);
96
194
 
97
- const { class: className, style, direction, gap, align, justify } = this.state;
195
+ const { content, class: className, style, direction, gap, align, justify } = this.state;
98
196
 
99
197
  const div = document.createElement('div');
100
198
  div.id = this._id;
199
+ this._containerElement = div;
101
200
 
102
201
  // Always include jux-container class, append custom classes
103
202
  div.className = className ? `jux-container ${className}` : 'jux-container';
@@ -128,6 +227,22 @@ export class Container extends BaseComponent<ContainerState> {
128
227
  div.setAttribute('style', computedStyle);
129
228
  }
130
229
 
230
+ // Render initial content
231
+ if (content) {
232
+ const items = Array.isArray(content) ? content : [content];
233
+ items.forEach(item => {
234
+ if (typeof item === 'string') {
235
+ const tempDiv = document.createElement('div');
236
+ tempDiv.innerHTML = item;
237
+ while (tempDiv.firstChild) {
238
+ div.appendChild(tempDiv.firstChild);
239
+ }
240
+ } else if (item instanceof BaseComponent) {
241
+ item.render(div);
242
+ }
243
+ });
244
+ }
245
+
131
246
  this._wireStandardEvents(div);
132
247
 
133
248
  container.appendChild(div);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.1.63",
3
+ "version": "1.1.65",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "index.js",
@@ -47,7 +47,8 @@
47
47
  "build": "tsc",
48
48
  "dev": "tsc --watch",
49
49
  "prepublishOnly": "npm run build",
50
- "postpublish": "echo '✅ Published successfully. Verify with: npm info juxscript'"
50
+ "postpublish": "echo '✅ Published successfully. Verify with: npm info juxscript'",
51
+ "scan-css": "node scripts/scan-css-classes.js"
51
52
  },
52
53
  "dependencies": {
53
54
  "acorn": "^8.15.0",