juxscript 1.1.69 → 1.1.71
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/dom-structure-map.json +1 -1
- package/lib/components/blueprint.d.ts.map +1 -1
- package/lib/components/blueprint.ts +368 -368
- package/lib/components/include.d.ts +53 -87
- package/lib/components/include.d.ts.map +1 -1
- package/lib/components/include.js +136 -248
- package/lib/components/include.ts +149 -278
- package/lib/components/modal.d.ts +3 -2
- package/lib/components/modal.d.ts.map +1 -1
- package/lib/components/modal.js +20 -1
- package/lib/components/modal.ts +27 -3
- package/package.json +1 -1
|
@@ -1,210 +1,61 @@
|
|
|
1
|
-
|
|
2
1
|
/**
|
|
3
|
-
* Include -
|
|
4
|
-
*
|
|
2
|
+
* Include - Simplified resource injection for bundled and external resources
|
|
3
|
+
* Supports page-specific scoping and cleanup
|
|
5
4
|
*/
|
|
6
5
|
|
|
7
|
-
type
|
|
8
|
-
type IncludeLocation = 'head' | 'body-start' | 'body-end';
|
|
6
|
+
type ResourceType = 'css' | 'js' | 'module';
|
|
9
7
|
|
|
10
8
|
interface IncludeOptions {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
integrity?: string;
|
|
9
|
+
type?: ResourceType;
|
|
10
|
+
target?: string; // CSS selector for target container (default: 'head')
|
|
14
11
|
async?: boolean;
|
|
15
12
|
defer?: boolean;
|
|
16
|
-
|
|
13
|
+
crossOrigin?: 'anonymous' | 'use-credentials';
|
|
14
|
+
integrity?: string;
|
|
15
|
+
pageScoped?: boolean; // If true, tracks for cleanup
|
|
17
16
|
}
|
|
18
17
|
|
|
18
|
+
// Global registry for page-scoped resources
|
|
19
|
+
const scopedResources: Map<string, Set<HTMLElement>> = new Map();
|
|
20
|
+
|
|
19
21
|
export class Include {
|
|
20
22
|
private url: string;
|
|
21
|
-
private
|
|
22
|
-
private options: IncludeOptions = {};
|
|
23
|
+
private options: IncludeOptions;
|
|
23
24
|
private element: HTMLElement | null = null;
|
|
24
|
-
private
|
|
25
|
-
|
|
26
|
-
constructor(
|
|
27
|
-
this.url =
|
|
28
|
-
this.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
url.includes('jsdelivr.net/npm') ||
|
|
39
|
-
url.includes('unpkg.com') ||
|
|
40
|
-
url.includes('cdn.') ||
|
|
41
|
-
url.match(/\.(js|mjs)($|\?)/)) {
|
|
42
|
-
return 'script';
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (url.endsWith('.css')) return 'stylesheet';
|
|
46
|
-
if (url.endsWith('.json')) return 'json';
|
|
47
|
-
if (url.match(/\.(png|jpg|jpeg|gif|svg|webp)$/i)) return 'image';
|
|
48
|
-
if (url.match(/\.(woff|woff2|ttf|otf|eot)$/i)) return 'font';
|
|
49
|
-
|
|
50
|
-
// Default to script for extensionless URLs from CDN domains
|
|
51
|
-
if (!url.includes('.') || url.match(/^https?:\/\/cdn/)) {
|
|
52
|
-
return 'script';
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return 'preload';
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/* -------------------------
|
|
59
|
-
* Fluent Type Setters
|
|
60
|
-
* ------------------------- */
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Force treat as CSS stylesheet
|
|
64
|
-
* Use when URL doesn't have .css extension
|
|
65
|
-
*/
|
|
66
|
-
withCss(): this {
|
|
67
|
-
this.type = 'stylesheet';
|
|
68
|
-
this.explicitType = true; // Mark as explicit
|
|
69
|
-
return this;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Force treat as JavaScript
|
|
74
|
-
* Use when URL doesn't have .js extension (CDN scripts, etc.)
|
|
75
|
-
*
|
|
76
|
-
* @example
|
|
77
|
-
* jux.include('https://cdn.tailwindcss.com').withJs().render();
|
|
78
|
-
* jux.include('https://unpkg.com/alpine').withJs({ defer: true }).render();
|
|
79
|
-
*/
|
|
80
|
-
withJs(options?: { async?: boolean; defer?: boolean }): this {
|
|
81
|
-
this.type = 'script';
|
|
82
|
-
this.explicitType = true; // Mark as explicit
|
|
83
|
-
if (options?.async) this.options.async = true;
|
|
84
|
-
if (options?.defer) this.options.defer = true;
|
|
85
|
-
return this;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Force treat as ES module
|
|
90
|
-
* Use for module scripts
|
|
91
|
-
*/
|
|
92
|
-
withModule(): this {
|
|
93
|
-
this.type = 'module';
|
|
94
|
-
this.explicitType = true; // Mark as explicit
|
|
95
|
-
return this;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
withImage(): this {
|
|
99
|
-
this.type = 'image';
|
|
100
|
-
this.explicitType = true;
|
|
101
|
-
return this;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
withFont(): this {
|
|
105
|
-
this.type = 'font';
|
|
106
|
-
this.explicitType = true;
|
|
107
|
-
return this;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
withPreload(as?: string): this {
|
|
111
|
-
this.type = 'preload';
|
|
112
|
-
this.explicitType = true;
|
|
113
|
-
if (as) this.options.as = as;
|
|
114
|
-
return this;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
withPrefetch(): this {
|
|
118
|
-
this.type = 'prefetch';
|
|
119
|
-
this.explicitType = true;
|
|
120
|
-
return this;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
withJson(): this {
|
|
124
|
-
this.type = 'json';
|
|
125
|
-
this.explicitType = true;
|
|
126
|
-
return this;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/* -------------------------
|
|
130
|
-
* Convenience aliases for common patterns
|
|
131
|
-
* ------------------------- */
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Shorthand for .withJs()
|
|
135
|
-
* @example jux.include(url).asScript()
|
|
136
|
-
*/
|
|
137
|
-
asScript(options?: { async?: boolean; defer?: boolean }): this {
|
|
138
|
-
return this.withJs(options);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Shorthand for .withCss()
|
|
143
|
-
* @example jux.include(url).asStylesheet()
|
|
144
|
-
*/
|
|
145
|
-
asStylesheet(): this {
|
|
146
|
-
return this.withCss();
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/* -------------------------
|
|
150
|
-
* JSON Fetching
|
|
151
|
-
* ------------------------- */
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Fetch and parse JSON file
|
|
155
|
-
* Returns a Promise that resolves to the parsed JSON data
|
|
156
|
-
*
|
|
157
|
-
* Usage:
|
|
158
|
-
* const config = await jux.include('config.json').asJson();
|
|
159
|
-
* const data = await jux.include('/api/data').asJson();
|
|
160
|
-
*/
|
|
161
|
-
async asJson<T = any>(): Promise<T> {
|
|
162
|
-
try {
|
|
163
|
-
const response = await fetch(this.url);
|
|
164
|
-
|
|
165
|
-
if (!response.ok) {
|
|
166
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
25
|
+
private pageId: string | null = null;
|
|
26
|
+
|
|
27
|
+
constructor(url: string, options: IncludeOptions = {}) {
|
|
28
|
+
this.url = url;
|
|
29
|
+
this.options = options;
|
|
30
|
+
|
|
31
|
+
// Auto-detect type from extension if not provided
|
|
32
|
+
if (!options.type) {
|
|
33
|
+
if (url.endsWith('.css')) {
|
|
34
|
+
this.options.type = 'css';
|
|
35
|
+
} else if (url.endsWith('.mjs') || url.endsWith('.module.js')) {
|
|
36
|
+
this.options.type = 'module';
|
|
37
|
+
} else {
|
|
38
|
+
this.options.type = 'js';
|
|
167
39
|
}
|
|
168
|
-
|
|
169
|
-
const data = await response.json();
|
|
170
|
-
console.log(`✓ JSON loaded: ${this.url}`);
|
|
171
|
-
return data;
|
|
172
|
-
} catch (error: any) {
|
|
173
|
-
throw error;
|
|
174
40
|
}
|
|
175
41
|
}
|
|
176
42
|
|
|
177
|
-
/**
|
|
178
|
-
* Fetch JSON and execute callback with data
|
|
179
|
-
*
|
|
180
|
-
* Usage:
|
|
181
|
-
* jux.include('config.json').onJson(data => {
|
|
182
|
-
* console.log('Config:', data);
|
|
183
|
-
* });
|
|
184
|
-
*/
|
|
185
|
-
onJson<T = any>(callback: (data: T) => void): this {
|
|
186
|
-
this.asJson<T>().then(callback).catch(error => {
|
|
187
|
-
console.error('Failed to load JSON:', error);
|
|
188
|
-
});
|
|
189
|
-
return this;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
43
|
/* -------------------------
|
|
193
|
-
*
|
|
44
|
+
* Fluent API
|
|
194
45
|
* ------------------------- */
|
|
195
46
|
|
|
196
|
-
|
|
197
|
-
this.options =
|
|
47
|
+
css(): this {
|
|
48
|
+
this.options.type = 'css';
|
|
198
49
|
return this;
|
|
199
50
|
}
|
|
200
51
|
|
|
201
|
-
|
|
202
|
-
this.options.
|
|
52
|
+
js(): this {
|
|
53
|
+
this.options.type = 'js';
|
|
203
54
|
return this;
|
|
204
55
|
}
|
|
205
56
|
|
|
206
|
-
|
|
207
|
-
this.options.
|
|
57
|
+
module(): this {
|
|
58
|
+
this.options.type = 'module';
|
|
208
59
|
return this;
|
|
209
60
|
}
|
|
210
61
|
|
|
@@ -218,13 +69,28 @@ export class Include {
|
|
|
218
69
|
return this;
|
|
219
70
|
}
|
|
220
71
|
|
|
221
|
-
|
|
222
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Inject into specific container instead of <head>
|
|
74
|
+
* Useful for page-specific styles
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* jux.include('/css/page1.css').into('#page1-container');
|
|
78
|
+
*/
|
|
79
|
+
into(selector: string): this {
|
|
80
|
+
this.options.target = selector;
|
|
223
81
|
return this;
|
|
224
82
|
}
|
|
225
83
|
|
|
226
|
-
|
|
227
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Mark as page-scoped for automatic cleanup
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* jux.include('/css/dashboard.css').forPage('dashboard');
|
|
89
|
+
* // Later: Include.cleanupPage('dashboard');
|
|
90
|
+
*/
|
|
91
|
+
forPage(pageId: string): this {
|
|
92
|
+
this.pageId = pageId;
|
|
93
|
+
this.options.pageScoped = true;
|
|
228
94
|
return this;
|
|
229
95
|
}
|
|
230
96
|
|
|
@@ -235,50 +101,45 @@ export class Include {
|
|
|
235
101
|
render(): this {
|
|
236
102
|
if (typeof document === 'undefined') return this;
|
|
237
103
|
|
|
238
|
-
// Don't render JSON type (it's fetched via asJson() instead)
|
|
239
|
-
if (this.type === 'json') {
|
|
240
|
-
console.warn('Include: JSON files should be loaded with .asJson() instead of .render()');
|
|
241
|
-
return this;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
104
|
try {
|
|
245
|
-
|
|
105
|
+
// Check if already loaded
|
|
106
|
+
if (this.isAlreadyLoaded()) {
|
|
107
|
+
console.log(`⚠️ Resource already loaded: ${this.url}`);
|
|
108
|
+
return this;
|
|
109
|
+
}
|
|
246
110
|
|
|
111
|
+
// Create element based on type
|
|
247
112
|
let element: HTMLElement;
|
|
248
113
|
|
|
249
|
-
switch (this.type) {
|
|
250
|
-
case '
|
|
114
|
+
switch (this.options.type) {
|
|
115
|
+
case 'css':
|
|
251
116
|
element = this.createStylesheet();
|
|
252
117
|
break;
|
|
253
|
-
case '
|
|
118
|
+
case 'js':
|
|
254
119
|
case 'module':
|
|
255
120
|
element = this.createScript();
|
|
256
121
|
break;
|
|
257
|
-
case 'image':
|
|
258
|
-
case 'font':
|
|
259
|
-
case 'preload':
|
|
260
|
-
case 'prefetch':
|
|
261
|
-
element = this.createLink();
|
|
262
|
-
break;
|
|
263
122
|
default:
|
|
264
|
-
throw new Error(`Unknown
|
|
123
|
+
throw new Error(`Unknown resource type: ${this.options.type}`);
|
|
265
124
|
}
|
|
266
125
|
|
|
126
|
+
// Get target container
|
|
267
127
|
const container = this.getContainer();
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if (location === 'body-end') {
|
|
271
|
-
container.appendChild(element);
|
|
272
|
-
} else {
|
|
273
|
-
container.insertBefore(element, container.firstChild);
|
|
274
|
-
}
|
|
128
|
+
container.appendChild(element);
|
|
275
129
|
|
|
276
130
|
this.element = element;
|
|
277
131
|
|
|
278
|
-
//
|
|
279
|
-
|
|
280
|
-
|
|
132
|
+
// Register for page cleanup if needed
|
|
133
|
+
if (this.options.pageScoped && this.pageId) {
|
|
134
|
+
if (!scopedResources.has(this.pageId)) {
|
|
135
|
+
scopedResources.set(this.pageId, new Set());
|
|
136
|
+
}
|
|
137
|
+
scopedResources.get(this.pageId)!.add(element);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
console.log(`✓ Loaded ${this.options.type}: ${this.url}`);
|
|
281
141
|
} catch (error: any) {
|
|
142
|
+
console.error(`✗ Failed to load ${this.options.type}: ${this.url}`, error);
|
|
282
143
|
throw error;
|
|
283
144
|
}
|
|
284
145
|
|
|
@@ -293,12 +154,15 @@ export class Include {
|
|
|
293
154
|
const link = document.createElement('link');
|
|
294
155
|
link.rel = 'stylesheet';
|
|
295
156
|
link.href = this.url;
|
|
157
|
+
link.dataset.juxInclude = this.url;
|
|
296
158
|
|
|
297
159
|
if (this.options.crossOrigin) link.crossOrigin = this.options.crossOrigin;
|
|
298
160
|
if (this.options.integrity) link.integrity = this.options.integrity;
|
|
299
161
|
|
|
300
162
|
link.onload = () => console.log(`✓ Stylesheet loaded: ${this.url}`);
|
|
301
|
-
link.onerror = () =>
|
|
163
|
+
link.onerror = () => {
|
|
164
|
+
throw new Error(`Failed to load stylesheet: ${this.url}`);
|
|
165
|
+
};
|
|
302
166
|
|
|
303
167
|
return link;
|
|
304
168
|
}
|
|
@@ -306,66 +170,42 @@ export class Include {
|
|
|
306
170
|
private createScript(): HTMLScriptElement {
|
|
307
171
|
const script = document.createElement('script');
|
|
308
172
|
script.src = this.url;
|
|
173
|
+
script.dataset.juxInclude = this.url;
|
|
309
174
|
|
|
310
|
-
if (this.type === 'module') script.type = 'module';
|
|
175
|
+
if (this.options.type === 'module') script.type = 'module';
|
|
311
176
|
if (this.options.async) script.async = true;
|
|
312
177
|
if (this.options.defer) script.defer = true;
|
|
313
178
|
if (this.options.crossOrigin) script.crossOrigin = this.options.crossOrigin;
|
|
314
179
|
if (this.options.integrity) script.integrity = this.options.integrity;
|
|
315
180
|
|
|
316
181
|
script.onload = () => console.log(`✓ Script loaded: ${this.url}`);
|
|
317
|
-
script.onerror = () =>
|
|
182
|
+
script.onerror = () => {
|
|
183
|
+
throw new Error(`Failed to load script: ${this.url}`);
|
|
184
|
+
};
|
|
318
185
|
|
|
319
186
|
return script;
|
|
320
187
|
}
|
|
321
188
|
|
|
322
|
-
private createLink(): HTMLLinkElement {
|
|
323
|
-
const link = document.createElement('link');
|
|
324
|
-
|
|
325
|
-
// Set rel based on type
|
|
326
|
-
if (this.type === 'prefetch') {
|
|
327
|
-
link.rel = 'prefetch';
|
|
328
|
-
} else {
|
|
329
|
-
link.rel = 'preload';
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
link.href = this.url;
|
|
333
|
-
|
|
334
|
-
// Set 'as' attribute
|
|
335
|
-
if (this.type === 'image') {
|
|
336
|
-
link.as = 'image';
|
|
337
|
-
} else if (this.type === 'font') {
|
|
338
|
-
link.as = 'font';
|
|
339
|
-
link.crossOrigin = this.options.crossOrigin || 'anonymous';
|
|
340
|
-
} else if (this.options.as) {
|
|
341
|
-
link.as = this.options.as;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
if (this.options.crossOrigin && this.type !== 'font') {
|
|
345
|
-
link.crossOrigin = this.options.crossOrigin;
|
|
346
|
-
}
|
|
347
|
-
if (this.options.integrity) {
|
|
348
|
-
link.integrity = this.options.integrity;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
return link;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
189
|
/* -------------------------
|
|
355
190
|
* Helpers
|
|
356
191
|
* ------------------------- */
|
|
357
192
|
|
|
358
193
|
private getContainer(): HTMLElement {
|
|
359
|
-
|
|
360
|
-
|
|
194
|
+
if (this.options.target) {
|
|
195
|
+
const container = document.querySelector(this.options.target);
|
|
196
|
+
if (!container) {
|
|
197
|
+
throw new Error(`Target container not found: ${this.options.target}`);
|
|
198
|
+
}
|
|
199
|
+
return container as HTMLElement;
|
|
200
|
+
}
|
|
201
|
+
return document.head;
|
|
361
202
|
}
|
|
362
203
|
|
|
363
|
-
private
|
|
364
|
-
const
|
|
365
|
-
|
|
204
|
+
private isAlreadyLoaded(): boolean {
|
|
205
|
+
const selector = `[data-jux-include="${this.url}"]`;
|
|
206
|
+
return document.querySelector(selector) !== null;
|
|
366
207
|
}
|
|
367
208
|
|
|
368
|
-
|
|
369
209
|
remove(): this {
|
|
370
210
|
if (this.element?.parentNode) {
|
|
371
211
|
this.element.parentNode.removeChild(this.element);
|
|
@@ -373,38 +213,69 @@ export class Include {
|
|
|
373
213
|
}
|
|
374
214
|
return this;
|
|
375
215
|
}
|
|
216
|
+
|
|
217
|
+
/* -------------------------
|
|
218
|
+
* Static Page Cleanup
|
|
219
|
+
* ------------------------- */
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Remove all resources for a specific page
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* Include.cleanupPage('dashboard');
|
|
226
|
+
*/
|
|
227
|
+
static cleanupPage(pageId: string): void {
|
|
228
|
+
const resources = scopedResources.get(pageId);
|
|
229
|
+
if (!resources) return;
|
|
230
|
+
|
|
231
|
+
resources.forEach(element => {
|
|
232
|
+
element.parentNode?.removeChild(element);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
scopedResources.delete(pageId);
|
|
236
|
+
console.log(`✓ Cleaned up page resources: ${pageId}`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Remove all page-scoped resources
|
|
241
|
+
*/
|
|
242
|
+
static cleanupAll(): void {
|
|
243
|
+
scopedResources.forEach((resources, pageId) => {
|
|
244
|
+
resources.forEach(element => {
|
|
245
|
+
element.parentNode?.removeChild(element);
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
scopedResources.clear();
|
|
249
|
+
console.log('✓ Cleaned up all page-scoped resources');
|
|
250
|
+
}
|
|
376
251
|
}
|
|
377
252
|
|
|
378
253
|
/**
|
|
379
|
-
* Factory function -
|
|
254
|
+
* Factory function - simplified usage
|
|
380
255
|
*
|
|
381
256
|
* Usage:
|
|
382
|
-
* //
|
|
383
|
-
* jux.include('styles.css');
|
|
384
|
-
* jux.include('
|
|
257
|
+
* // Basic (auto-detects from extension)
|
|
258
|
+
* jux.include('/css/styles.css');
|
|
259
|
+
* jux.include('/js/app.js');
|
|
385
260
|
*
|
|
386
|
-
* //
|
|
387
|
-
* jux.include('
|
|
388
|
-
* jux.include('
|
|
389
|
-
* jux.include('https://unpkg.com/htmx.org').withJs({ defer: true });
|
|
261
|
+
* // Page-specific with cleanup
|
|
262
|
+
* jux.include('/css/dashboard.css').forPage('dashboard');
|
|
263
|
+
* jux.include('/js/dashboard.js').forPage('dashboard');
|
|
390
264
|
*
|
|
391
|
-
* //
|
|
392
|
-
*
|
|
265
|
+
* // Later cleanup:
|
|
266
|
+
* Include.cleanupPage('dashboard');
|
|
393
267
|
*
|
|
394
|
-
* //
|
|
395
|
-
* jux.include('
|
|
268
|
+
* // Inject into specific container
|
|
269
|
+
* jux.include('/css/widget.css').into('#widget-container');
|
|
270
|
+
*
|
|
271
|
+
* // External CDN
|
|
272
|
+
* jux.include('https://cdn.tailwindcss.com').js();
|
|
396
273
|
*
|
|
397
|
-
* //
|
|
398
|
-
*
|
|
399
|
-
* jux.include('data.json').onJson(data => console.log(data));
|
|
274
|
+
* // Module
|
|
275
|
+
* jux.include('/js/app.mjs').module();
|
|
400
276
|
*/
|
|
401
|
-
export function include(
|
|
402
|
-
const
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
if (imp['type'] !== 'json') {
|
|
406
|
-
imp.render();
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
return imp;
|
|
277
|
+
export function include(url: string, options?: IncludeOptions): Include {
|
|
278
|
+
const inc = new Include(url, options);
|
|
279
|
+
inc.render();
|
|
280
|
+
return inc;
|
|
410
281
|
}
|
|
@@ -9,7 +9,7 @@ export interface ModalOptions {
|
|
|
9
9
|
icon?: EmojiIconType | undefined;
|
|
10
10
|
close?: boolean;
|
|
11
11
|
backdropClose?: boolean;
|
|
12
|
-
position?: 'bottom' | 'center' | 'top' | 'fullscreen' | 'popover';
|
|
12
|
+
position?: 'bottom' | 'center' | 'top' | 'fullscreen' | 'popover' | 'popover-top' | 'popover-bottom' | 'popover-left' | 'popover-right';
|
|
13
13
|
size?: 'small' | 'medium' | 'large';
|
|
14
14
|
actions?: Array<{
|
|
15
15
|
label: string;
|
|
@@ -25,7 +25,7 @@ type ModalState = {
|
|
|
25
25
|
icon: EmojiIconType | undefined;
|
|
26
26
|
close: boolean;
|
|
27
27
|
backdropClose: boolean;
|
|
28
|
-
position?: 'bottom' | 'center' | 'top' | 'fullscreen' | 'popover';
|
|
28
|
+
position?: 'bottom' | 'center' | 'top' | 'fullscreen' | 'popover' | 'popover-top' | 'popover-bottom' | 'popover-left' | 'popover-right';
|
|
29
29
|
size: string;
|
|
30
30
|
open: boolean;
|
|
31
31
|
actions: Array<{
|
|
@@ -52,6 +52,7 @@ export declare class Modal extends BaseComponent<ModalState> {
|
|
|
52
52
|
close(value: boolean): this;
|
|
53
53
|
backdropClose(value: boolean): this;
|
|
54
54
|
size(value: 'small' | 'medium' | 'large'): this;
|
|
55
|
+
position(value: 'bottom' | 'center' | 'top' | 'fullscreen' | 'popover' | 'popover-top' | 'popover-bottom' | 'popover-left' | 'popover-right'): this;
|
|
55
56
|
actions(value: Array<{
|
|
56
57
|
label: string;
|
|
57
58
|
variant?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["modal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAOxD,MAAM,MAAM,aAAa,GAAG;IAE1B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,kBAAkB,GAAG,UAAU,GAAG,WAAW,GAAG,MAAM,CAAC;CAC9F,CAAA;AACD,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3E,IAAI,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,KAAK,GAAG,YAAY,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["modal.ts"],"names":[],"mappings":"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"}
|
package/lib/components/modal.js
CHANGED
|
@@ -58,6 +58,17 @@ export class Modal extends BaseComponent {
|
|
|
58
58
|
case 'size':
|
|
59
59
|
modal.className = modal.className.replace(/jux-modal-(small|medium|large)/, `jux-modal-${value}`);
|
|
60
60
|
break;
|
|
61
|
+
case 'position':
|
|
62
|
+
// Remove existing position classes
|
|
63
|
+
this._overlay.className = this._overlay.className
|
|
64
|
+
.split(' ')
|
|
65
|
+
.filter(c => !c.startsWith('jux-modal-position-'))
|
|
66
|
+
.join(' ');
|
|
67
|
+
// Add new position class
|
|
68
|
+
if (value) {
|
|
69
|
+
this._overlay.classList.add(`jux-modal-position-${value}`);
|
|
70
|
+
}
|
|
71
|
+
break;
|
|
61
72
|
case 'actions':
|
|
62
73
|
this._rebuildActions();
|
|
63
74
|
break;
|
|
@@ -189,6 +200,10 @@ export class Modal extends BaseComponent {
|
|
|
189
200
|
this.state.size = value;
|
|
190
201
|
return this;
|
|
191
202
|
}
|
|
203
|
+
position(value) {
|
|
204
|
+
this.state.position = value;
|
|
205
|
+
return this;
|
|
206
|
+
}
|
|
192
207
|
actions(value) {
|
|
193
208
|
this.state.actions = value;
|
|
194
209
|
return this;
|
|
@@ -275,12 +290,16 @@ export class Modal extends BaseComponent {
|
|
|
275
290
|
* ═════════════════════════════════════════════════════════════════ */
|
|
276
291
|
render(targetId) {
|
|
277
292
|
const container = this._setupContainer(targetId);
|
|
278
|
-
const { open, title, content, icon, size, close, backdropClose, actions, style, class: className } = this.state;
|
|
293
|
+
const { open, title, content, icon, size, position, close, backdropClose, actions, style, class: className } = this.state;
|
|
279
294
|
const hasOpenSync = this._syncBindings.some(b => b.property === 'open');
|
|
280
295
|
const overlay = document.createElement('div');
|
|
281
296
|
overlay.className = 'jux-modal-overlay';
|
|
282
297
|
overlay.id = this._id;
|
|
283
298
|
overlay.style.display = open ? 'flex' : 'none';
|
|
299
|
+
// Add position class
|
|
300
|
+
if (position) {
|
|
301
|
+
overlay.classList.add(`jux-modal-position-${position}`);
|
|
302
|
+
}
|
|
284
303
|
if (className)
|
|
285
304
|
overlay.className += ` ${className}`;
|
|
286
305
|
if (style)
|