juxscript 1.1.3 → 1.1.4
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/machinery/build3.js +7 -91
- package/machinery/compiler3.js +3 -209
- package/package.json +19 -5
- package/lib/components/alert.ts +0 -200
- package/lib/components/app.ts +0 -247
- package/lib/components/badge.ts +0 -101
- package/lib/components/base/BaseComponent.ts +0 -421
- package/lib/components/base/FormInput.ts +0 -227
- package/lib/components/button.ts +0 -178
- package/lib/components/card.ts +0 -173
- package/lib/components/chart.ts +0 -231
- package/lib/components/checkbox.ts +0 -242
- package/lib/components/code.ts +0 -123
- package/lib/components/container.ts +0 -140
- package/lib/components/data.ts +0 -135
- package/lib/components/datepicker.ts +0 -234
- package/lib/components/dialog.ts +0 -172
- package/lib/components/divider.ts +0 -100
- package/lib/components/dropdown.ts +0 -186
- package/lib/components/element.ts +0 -267
- package/lib/components/fileupload.ts +0 -309
- package/lib/components/grid.ts +0 -291
- package/lib/components/guard.ts +0 -92
- package/lib/components/heading.ts +0 -96
- package/lib/components/helpers.ts +0 -41
- package/lib/components/hero.ts +0 -224
- package/lib/components/icon.ts +0 -178
- package/lib/components/icons.ts +0 -464
- package/lib/components/include.ts +0 -410
- package/lib/components/input.ts +0 -457
- package/lib/components/list.ts +0 -419
- package/lib/components/loading.ts +0 -100
- package/lib/components/menu.ts +0 -275
- package/lib/components/modal.ts +0 -284
- package/lib/components/nav.ts +0 -257
- package/lib/components/paragraph.ts +0 -97
- package/lib/components/progress.ts +0 -159
- package/lib/components/radio.ts +0 -278
- package/lib/components/req.ts +0 -303
- package/lib/components/script.ts +0 -41
- package/lib/components/select.ts +0 -252
- package/lib/components/sidebar.ts +0 -275
- package/lib/components/style.ts +0 -41
- package/lib/components/switch.ts +0 -246
- package/lib/components/table.ts +0 -1249
- package/lib/components/tabs.ts +0 -250
- package/lib/components/theme-toggle.ts +0 -293
- package/lib/components/tooltip.ts +0 -144
- package/lib/components/view.ts +0 -190
- package/lib/components/write.ts +0 -272
- package/lib/layouts/default.css +0 -260
- package/lib/layouts/figma.css +0 -334
- package/lib/reactivity/state.ts +0 -78
- package/lib/utils/fetch.ts +0 -553
- package/machinery/ast.js +0 -347
- package/machinery/build.js +0 -466
- package/machinery/bundleAssets.js +0 -0
- package/machinery/bundleJux.js +0 -0
- package/machinery/bundleVendors.js +0 -0
- package/machinery/doc-generator.js +0 -136
- package/machinery/imports.js +0 -155
- package/machinery/ts-shim.js +0 -46
- package/machinery/validators/file-validator.js +0 -123
package/lib/components/grid.ts
DELETED
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
import { BaseComponent } from './base/BaseComponent.js';
|
|
2
|
-
|
|
3
|
-
// Event definitions - Grid is layout-only, no interactive events
|
|
4
|
-
const TRIGGER_EVENTS = [] as const;
|
|
5
|
-
const CALLBACK_EVENTS = [] as const;
|
|
6
|
-
|
|
7
|
-
export interface GridRowConfig {
|
|
8
|
-
height?: string;
|
|
9
|
-
style?: string;
|
|
10
|
-
class?: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface GridColumnConfig {
|
|
14
|
-
width?: string;
|
|
15
|
-
style?: string;
|
|
16
|
-
class?: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface GridItemConfig {
|
|
20
|
-
target: string; // e.g., "#Dashboard-0-1"
|
|
21
|
-
text?: string;
|
|
22
|
-
html?: string;
|
|
23
|
-
component?: any; // Jux component instance
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface GridCreateConfig {
|
|
27
|
-
columns?: GridColumnConfig[] | number;
|
|
28
|
-
rows?: GridRowConfig[] | number;
|
|
29
|
-
items?: GridItemConfig[];
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface GridOptions {
|
|
33
|
-
columns?: GridColumnConfig[] | number;
|
|
34
|
-
rows?: GridRowConfig[] | number;
|
|
35
|
-
width?: string;
|
|
36
|
-
height?: string;
|
|
37
|
-
gap?: string;
|
|
38
|
-
style?: string;
|
|
39
|
-
class?: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
type GridState = {
|
|
43
|
-
rows: GridRowConfig[];
|
|
44
|
-
columns: GridColumnConfig[];
|
|
45
|
-
boundary: {
|
|
46
|
-
width: string;
|
|
47
|
-
height: string;
|
|
48
|
-
};
|
|
49
|
-
gap: string;
|
|
50
|
-
cells: Map<string, HTMLElement>;
|
|
51
|
-
style: string;
|
|
52
|
-
class: string;
|
|
53
|
-
gridder: boolean; // ✅ ADD: Enable blueprint visualization
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
export class Grid extends BaseComponent<GridState> {
|
|
57
|
-
constructor(id: string, options: GridOptions = {}) {
|
|
58
|
-
// Normalize columns/rows to config arrays
|
|
59
|
-
const columnsConfig = normalizeTrackConfig(options.columns || 1);
|
|
60
|
-
const rowsConfig = normalizeTrackConfig(options.rows || 1);
|
|
61
|
-
|
|
62
|
-
super(id, {
|
|
63
|
-
rows: rowsConfig,
|
|
64
|
-
columns: columnsConfig,
|
|
65
|
-
boundary: {
|
|
66
|
-
width: options.width ?? '', // ✅ CHANGE: Empty = inherit parent
|
|
67
|
-
height: options.height ?? '' // ✅ CHANGE: Empty = inherit parent
|
|
68
|
-
},
|
|
69
|
-
gap: options.gap ?? '0',
|
|
70
|
-
cells: new Map(),
|
|
71
|
-
style: options.style ?? '',
|
|
72
|
-
class: options.class ?? '',
|
|
73
|
-
gridder: false
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
protected getTriggerEvents(): readonly string[] {
|
|
78
|
-
return TRIGGER_EVENTS;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
protected getCallbackEvents(): readonly string[] {
|
|
82
|
-
return CALLBACK_EVENTS;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
86
|
-
* PROPS ACCESSOR - Inherited from BaseComponent
|
|
87
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
88
|
-
|
|
89
|
-
// ✅ Already available via BaseComponent.props getter
|
|
90
|
-
// Access: grid.props.rows, grid.props.columns, grid.props.gap, etc.
|
|
91
|
-
|
|
92
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
93
|
-
* FLUENT API - The Blueprint (Setters)
|
|
94
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
95
|
-
|
|
96
|
-
width(value: string): this {
|
|
97
|
-
this.state.boundary.width = value;
|
|
98
|
-
return this;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
height(value: string): this {
|
|
102
|
-
this.state.boundary.height = value;
|
|
103
|
-
return this;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
gap(value: string): this {
|
|
107
|
-
this.state.gap = value;
|
|
108
|
-
return this;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Define rows (SETTER)
|
|
113
|
-
* @param config - Number (creates N equal rows) or Array of row configs
|
|
114
|
-
*/
|
|
115
|
-
rows(config: GridRowConfig[] | number): this {
|
|
116
|
-
this.state.rows = normalizeTrackConfig(config);
|
|
117
|
-
return this;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Define columns (SETTER)
|
|
122
|
-
* @param config - Number (creates N equal columns) or Array of column configs
|
|
123
|
-
*/
|
|
124
|
-
columns(config: GridColumnConfig[] | number): this {
|
|
125
|
-
this.state.columns = normalizeTrackConfig(config);
|
|
126
|
-
return this;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Get the cell ID for a specific coordinate
|
|
131
|
-
*/
|
|
132
|
-
getCellId(row: number, col: number): string {
|
|
133
|
-
return `${this._id}-${row}-${col}`;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Get the DOM element for a specific cell
|
|
138
|
-
*/
|
|
139
|
-
getCell(row: number, col: number): HTMLElement | undefined {
|
|
140
|
-
const cellId = this.getCellId(row, col);
|
|
141
|
-
return this.state.cells.get(cellId);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* ✅ Enable blueprint/wireframe visualization
|
|
146
|
-
* Shows grid structure, cell coordinates, and geometric borders
|
|
147
|
-
*/
|
|
148
|
-
gridder(value: boolean = true): this {
|
|
149
|
-
this.state.gridder = value;
|
|
150
|
-
return this;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
154
|
-
* ORCHESTRATION - The Execution
|
|
155
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Pattern B: The Static Orchestration
|
|
159
|
-
* Creates the grid and populates it with items in one operation
|
|
160
|
-
*/
|
|
161
|
-
create(config: GridCreateConfig): this {
|
|
162
|
-
// Apply configuration
|
|
163
|
-
if (config.columns) {
|
|
164
|
-
this.columns(config.columns);
|
|
165
|
-
}
|
|
166
|
-
if (config.rows) {
|
|
167
|
-
this.rows(config.rows);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Render the grid structure
|
|
171
|
-
this.render();
|
|
172
|
-
|
|
173
|
-
// Populate items
|
|
174
|
-
if (config.items) {
|
|
175
|
-
config.items.forEach(item => {
|
|
176
|
-
const targetId = item.target.replace(/^#/, '');
|
|
177
|
-
const cell = document.getElementById(targetId);
|
|
178
|
-
|
|
179
|
-
if (!cell) {
|
|
180
|
-
console.warn(`[Grid] Cell not found: ${item.target}`);
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
if (item.component) {
|
|
185
|
-
// Render Jux component
|
|
186
|
-
item.component.render(`#${targetId}`);
|
|
187
|
-
} else if (item.html) {
|
|
188
|
-
cell.innerHTML = item.html;
|
|
189
|
-
} else if (item.text) {
|
|
190
|
-
cell.textContent = item.text;
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return this;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
199
|
-
* RENDER
|
|
200
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
201
|
-
|
|
202
|
-
render(targetId?: string): this {
|
|
203
|
-
const container = this._setupContainer(targetId);
|
|
204
|
-
|
|
205
|
-
const { rows, columns, boundary, gap, style, class: className, gridder } = this.state;
|
|
206
|
-
|
|
207
|
-
// Build grid container
|
|
208
|
-
const grid = document.createElement('div');
|
|
209
|
-
grid.className = 'jux-grid';
|
|
210
|
-
grid.id = this._id;
|
|
211
|
-
if (gridder) grid.classList.add('jux-grid-gridder');
|
|
212
|
-
if (className) grid.className += ` ${className}`;
|
|
213
|
-
|
|
214
|
-
// Apply grid styles
|
|
215
|
-
const gridTemplateRows = rows.map(r => r.height || '1fr').join(' ');
|
|
216
|
-
const gridTemplateColumns = columns.map(c => c.width || '1fr').join(' ');
|
|
217
|
-
|
|
218
|
-
const gridStyle = `
|
|
219
|
-
display: grid;
|
|
220
|
-
grid-template-rows: ${gridTemplateRows};
|
|
221
|
-
grid-template-columns: ${gridTemplateColumns};
|
|
222
|
-
gap: ${gap};
|
|
223
|
-
${boundary.width ? `width: ${boundary.width};` : ''} /* ✅ CHANGE: Only apply if set */
|
|
224
|
-
${boundary.height ? `height: ${boundary.height};` : ''} /* ✅ CHANGE: Only apply if set */
|
|
225
|
-
${style}
|
|
226
|
-
`;
|
|
227
|
-
|
|
228
|
-
grid.setAttribute('style', gridStyle.trim());
|
|
229
|
-
|
|
230
|
-
// Generate cells with coordinate-based IDs
|
|
231
|
-
this.state.cells.clear();
|
|
232
|
-
|
|
233
|
-
rows.forEach((row, rowIndex) => {
|
|
234
|
-
columns.forEach((col, colIndex) => {
|
|
235
|
-
const cell = document.createElement('div');
|
|
236
|
-
const cellId = this.getCellId(rowIndex, colIndex);
|
|
237
|
-
|
|
238
|
-
cell.id = cellId;
|
|
239
|
-
cell.className = 'jux-grid-cell';
|
|
240
|
-
cell.setAttribute('data-row', String(rowIndex));
|
|
241
|
-
cell.setAttribute('data-col', String(colIndex));
|
|
242
|
-
|
|
243
|
-
// ✅ CHANGE: Use title attribute instead of DOM element
|
|
244
|
-
if (gridder) {
|
|
245
|
-
cell.setAttribute('title', `Cell [${rowIndex},${colIndex}] — #${cellId}`);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Apply row-specific styles
|
|
249
|
-
if (row.style) {
|
|
250
|
-
cell.setAttribute('style', (cell.getAttribute('style') || '') + row.style);
|
|
251
|
-
}
|
|
252
|
-
if (row.class) {
|
|
253
|
-
cell.className += ` ${row.class}`;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Apply column-specific styles
|
|
257
|
-
if (col.style) {
|
|
258
|
-
cell.setAttribute('style', (cell.getAttribute('style') || '') + col.style);
|
|
259
|
-
}
|
|
260
|
-
if (col.class) {
|
|
261
|
-
cell.className += ` ${col.class}`;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
this.state.cells.set(cellId, cell);
|
|
265
|
-
grid.appendChild(cell);
|
|
266
|
-
});
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
this._wireStandardEvents(grid);
|
|
270
|
-
|
|
271
|
-
container.appendChild(grid);
|
|
272
|
-
return this;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Normalize track configuration to array format
|
|
278
|
-
*/
|
|
279
|
-
function normalizeTrackConfig(config: GridRowConfig[] | GridColumnConfig[] | number): any[] {
|
|
280
|
-
if (typeof config === 'number') {
|
|
281
|
-
return Array(config).fill({});
|
|
282
|
-
}
|
|
283
|
-
return config;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Factory function
|
|
288
|
-
*/
|
|
289
|
-
export function grid(id: string, options: GridOptions = {}): Grid {
|
|
290
|
-
return new Grid(id, options);
|
|
291
|
-
}
|
package/lib/components/guard.ts
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { BaseComponent } from './base/BaseComponent.js';
|
|
2
|
-
import { State } from '../reactivity/state.js';
|
|
3
|
-
|
|
4
|
-
// Extend Window interface to include Jux navigation hooks
|
|
5
|
-
declare global {
|
|
6
|
-
interface Window {
|
|
7
|
-
juxBeforeNavigate?: (from: string, to: string) => boolean | string;
|
|
8
|
-
juxAfterNavigate?: (path: string) => void;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// Event definitions
|
|
13
|
-
const TRIGGER_EVENTS = [] as const;
|
|
14
|
-
const CALLBACK_EVENTS = ['blocked', 'allowed'] as const;
|
|
15
|
-
|
|
16
|
-
export interface GuardOptions {
|
|
17
|
-
authState?: State<boolean>; // Check if user is authenticated
|
|
18
|
-
loginPath?: string; // Where to redirect if blocked
|
|
19
|
-
protectedPaths?: string[]; // Paths that require auth
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
type GuardState = {
|
|
23
|
-
authState: State<boolean> | null;
|
|
24
|
-
loginPath: string;
|
|
25
|
-
protectedPaths: string[];
|
|
26
|
-
isActive: boolean;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* ⚠️ DEPRECATED: Guard component is no longer supported after removing global middleware.
|
|
31
|
-
*
|
|
32
|
-
* Recommended alternatives:
|
|
33
|
-
* 1. Server-side authentication (Express, FastAPI, Laravel)
|
|
34
|
-
* 2. Manual route checks in each view
|
|
35
|
-
* 3. Custom wrapper components
|
|
36
|
-
*
|
|
37
|
-
* This component will be removed in a future version.
|
|
38
|
-
*/
|
|
39
|
-
export class Guard extends BaseComponent<GuardState> {
|
|
40
|
-
constructor(id: string, options: GuardOptions = {}) {
|
|
41
|
-
super(id, {
|
|
42
|
-
authState: options.authState ?? null,
|
|
43
|
-
loginPath: options.loginPath ?? '/login',
|
|
44
|
-
protectedPaths: options.protectedPaths ?? [],
|
|
45
|
-
isActive: false
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
console.warn(
|
|
49
|
-
'[Jux Guard] DEPRECATED: Guard component no longer supported after middleware removal.\n' +
|
|
50
|
-
'Use server-side auth or manual checks instead.'
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
protected getTriggerEvents(): readonly string[] {
|
|
55
|
-
return TRIGGER_EVENTS;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
protected getCallbackEvents(): readonly string[] {
|
|
59
|
-
return CALLBACK_EVENTS;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
63
|
-
* FLUENT API (No-ops now)
|
|
64
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
65
|
-
|
|
66
|
-
requireAuth(authState: State<boolean>, loginPath?: string): this {
|
|
67
|
-
console.warn('[Jux Guard] DEPRECATED: requireAuth() has no effect');
|
|
68
|
-
return this;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
protect(...paths: string[]): this {
|
|
72
|
-
console.warn('[Jux Guard] DEPRECATED: protect() has no effect');
|
|
73
|
-
return this;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
77
|
-
* RENDER (No-op)
|
|
78
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
79
|
-
|
|
80
|
-
render(targetId?: string): this {
|
|
81
|
-
console.warn('[Jux Guard] DEPRECATED: Guard rendering has no effect');
|
|
82
|
-
return this;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
deactivate(): this {
|
|
86
|
-
return this;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export function guard(id: string, options?: GuardOptions): Guard {
|
|
91
|
-
return new Guard(id, options);
|
|
92
|
-
}
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { BaseComponent } from './base/BaseComponent.js';
|
|
2
|
-
|
|
3
|
-
// Event definitions
|
|
4
|
-
const TRIGGER_EVENTS = [] as const;
|
|
5
|
-
const CALLBACK_EVENTS = [] as const; // Headings are display-only, no events
|
|
6
|
-
|
|
7
|
-
export interface HeadingOptions {
|
|
8
|
-
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
9
|
-
content?: string;
|
|
10
|
-
class?: string;
|
|
11
|
-
style?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
type HeadingState = {
|
|
15
|
-
level: 1 | 2 | 3 | 4 | 5 | 6;
|
|
16
|
-
content: string;
|
|
17
|
-
class: string;
|
|
18
|
-
style: string;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export class Heading extends BaseComponent<HeadingState> {
|
|
22
|
-
constructor(id: string, options: HeadingOptions = {}) {
|
|
23
|
-
super(id, {
|
|
24
|
-
level: options.level ?? 1,
|
|
25
|
-
content: options.content ?? '',
|
|
26
|
-
class: options.class ?? '',
|
|
27
|
-
style: options.style ?? ''
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
protected getTriggerEvents(): readonly string[] {
|
|
32
|
-
return TRIGGER_EVENTS;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
protected getCallbackEvents(): readonly string[] {
|
|
36
|
-
return CALLBACK_EVENTS;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
40
|
-
* FLUENT API
|
|
41
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
42
|
-
|
|
43
|
-
// ✅ Inherited from BaseComponent:
|
|
44
|
-
// - style(), class()
|
|
45
|
-
// - bind(), sync(), renderTo()
|
|
46
|
-
// - All other base methods
|
|
47
|
-
|
|
48
|
-
level(value: 1 | 2 | 3 | 4 | 5 | 6): this {
|
|
49
|
-
this.state.level = value;
|
|
50
|
-
return this;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
content(value: string): this {
|
|
54
|
-
this.state.content = value;
|
|
55
|
-
return this;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/* ═════════════════════════════════════════════════════════════════
|
|
59
|
-
* RENDER
|
|
60
|
-
* ═════════════════════════════════════════════════════════════════ */
|
|
61
|
-
|
|
62
|
-
render(targetId?: string): this {
|
|
63
|
-
const container = this._setupContainer(targetId);
|
|
64
|
-
|
|
65
|
-
const { content, level, style, class: className } = this.state;
|
|
66
|
-
|
|
67
|
-
const heading = document.createElement(`h${level}`) as HTMLHeadingElement;
|
|
68
|
-
heading.className = `jux-heading jux-heading-${level}`;
|
|
69
|
-
heading.id = this._id;
|
|
70
|
-
heading.textContent = content;
|
|
71
|
-
if (className) heading.className += ` ${className}`;
|
|
72
|
-
if (style) heading.setAttribute('style', style);
|
|
73
|
-
|
|
74
|
-
this._wireStandardEvents(heading);
|
|
75
|
-
|
|
76
|
-
// Wire sync bindings
|
|
77
|
-
this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
|
|
78
|
-
if (property === 'content') {
|
|
79
|
-
const transform = toComponent || ((v: any) => String(v));
|
|
80
|
-
|
|
81
|
-
stateObj.subscribe((val: any) => {
|
|
82
|
-
const transformed = transform(val);
|
|
83
|
-
heading.textContent = transformed;
|
|
84
|
-
this.state.content = transformed;
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
container.appendChild(heading);
|
|
90
|
-
return this;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function heading(id: string, options: HeadingOptions = {}): Heading {
|
|
95
|
-
return new Heading(id, options);
|
|
96
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Component helper utilities
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Get or create a container element for a component
|
|
7
|
-
* Auto-creates if it doesn't exist and appends to appropriate parent
|
|
8
|
-
*/
|
|
9
|
-
export function getOrCreateContainer(id: string): HTMLElement {
|
|
10
|
-
if (typeof document === 'undefined') {
|
|
11
|
-
throw new Error('Document is not available');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
let container = document.getElementById(id);
|
|
15
|
-
|
|
16
|
-
// Container already exists, return it
|
|
17
|
-
if (container) {
|
|
18
|
-
return container;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Auto-create container if it doesn't exist
|
|
22
|
-
container = document.createElement('div');
|
|
23
|
-
container.id = id;
|
|
24
|
-
|
|
25
|
-
// Find appropriate parent - [data-jux-page] takes precedence, then #app, then body
|
|
26
|
-
const dataJuxPage = document.querySelector('[data-jux-page]') as HTMLElement;
|
|
27
|
-
const app = document.getElementById('app');
|
|
28
|
-
|
|
29
|
-
const parent: HTMLElement = (dataJuxPage || app || document.body) as HTMLElement;
|
|
30
|
-
|
|
31
|
-
// Log warning if falling back to body
|
|
32
|
-
if (!dataJuxPage && !app) {
|
|
33
|
-
console.warn(
|
|
34
|
-
`[Jux] Preferred container targets "[data-jux-page]" or "#app" not found. Creating container "#${id}" in fallback parent: body`,
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
parent.appendChild(container);
|
|
39
|
-
|
|
40
|
-
return container;
|
|
41
|
-
}
|