juxscript 1.0.55 → 1.0.57

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.
@@ -176,109 +176,9 @@ export class Dropdown extends BaseComponent<DropdownState> {
176
176
 
177
177
  container.appendChild(wrapper);
178
178
  this._dropdown = wrapper;
179
- this._injectDropdownStyles();
180
179
 
181
180
  return this;
182
181
  }
183
-
184
- private _injectDropdownStyles(): void {
185
- const styleId = 'jux-dropdown-styles';
186
- if (document.getElementById(styleId)) return;
187
-
188
- const style = document.createElement('style');
189
- style.id = styleId;
190
- style.textContent = `
191
- .jux-dropdown {
192
- position: relative;
193
- display: inline-block;
194
- }
195
-
196
- .jux-dropdown-trigger {
197
- padding: 8px 16px;
198
- background: #3b82f6;
199
- color: white;
200
- border: none;
201
- border-radius: 6px;
202
- font-size: 14px;
203
- cursor: pointer;
204
- transition: background 0.2s;
205
- }
206
-
207
- .jux-dropdown-trigger:hover {
208
- background: #2563eb;
209
- }
210
-
211
- .jux-dropdown-menu {
212
- position: absolute;
213
- background: white;
214
- border: 1px solid #e5e7eb;
215
- border-radius: 6px;
216
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
217
- min-width: 200px;
218
- z-index: 1000;
219
- margin-top: 4px;
220
- }
221
-
222
- .jux-dropdown-bottom-left {
223
- left: 0;
224
- top: 100%;
225
- }
226
-
227
- .jux-dropdown-bottom-right {
228
- right: 0;
229
- top: 100%;
230
- }
231
-
232
- .jux-dropdown-top-left {
233
- left: 0;
234
- bottom: 100%;
235
- margin-bottom: 4px;
236
- }
237
-
238
- .jux-dropdown-top-right {
239
- right: 0;
240
- bottom: 100%;
241
- margin-bottom: 4px;
242
- }
243
-
244
- .jux-dropdown-item {
245
- display: flex;
246
- align-items: center;
247
- gap: 8px;
248
- width: 100%;
249
- padding: 10px 16px;
250
- border: none;
251
- background: none;
252
- text-align: left;
253
- cursor: pointer;
254
- transition: background 0.2s;
255
- font-size: 14px;
256
- }
257
-
258
- .jux-dropdown-item:hover {
259
- background: #f3f4f6;
260
- }
261
-
262
- .jux-dropdown-item:first-child {
263
- border-radius: 6px 6px 0 0;
264
- }
265
-
266
- .jux-dropdown-item:last-child {
267
- border-radius: 0 0 6px 6px;
268
- }
269
-
270
- .jux-dropdown-divider {
271
- height: 1px;
272
- background: #e5e7eb;
273
- margin: 4px 0;
274
- }
275
-
276
- .jux-dropdown-icon {
277
- font-size: 16px;
278
- }
279
- `;
280
- document.head.appendChild(style);
281
- }
282
182
  }
283
183
 
284
184
  export function dropdown(id: string, options: DropdownOptions = {}): Dropdown {
@@ -212,68 +212,8 @@ export class Element extends BaseComponent<ElementState> {
212
212
  container.appendChild(element);
213
213
  this._element = element;
214
214
 
215
- // Inject base semantic styles if this is a semantic element
216
- this._injectSemanticStyles();
217
-
218
215
  return this;
219
216
  }
220
-
221
- private _injectSemanticStyles(): void {
222
- const styleId = 'jux-semantic-styles';
223
- if (document.getElementById(styleId)) return;
224
-
225
- const style = document.createElement('style');
226
- style.id = styleId;
227
- style.textContent = `
228
- /* Jux Semantic Element Base Styles */
229
- .jux-header {
230
- display: block;
231
- width: 100%;
232
- background: var(--jux-header-bg, #ffffff);
233
- border-bottom: 1px solid var(--jux-border-color, #e5e7eb);
234
- padding: var(--jux-header-padding, 1rem 2rem);
235
- position: sticky;
236
- top: 0;
237
- z-index: 1000;
238
- }
239
-
240
- .jux-footer {
241
- display: block;
242
- width: 100%;
243
- background: var(--jux-footer-bg, #f9fafb);
244
- border-top: 1px solid var(--jux-border-color, #e5e7eb);
245
- padding: var(--jux-footer-padding, 2rem);
246
- margin-top: auto;
247
- }
248
-
249
- .jux-main {
250
- display: block;
251
- flex: 1;
252
- width: 100%;
253
- padding: var(--jux-main-padding, 2rem);
254
- min-height: calc(100vh - 200px);
255
- }
256
-
257
- .jux-aside {
258
- display: block;
259
- background: var(--jux-aside-bg, #f9fafb);
260
- border-right: 1px solid var(--jux-border-color, #e5e7eb);
261
- padding: var(--jux-aside-padding, 1.5rem);
262
- }
263
-
264
- .jux-section {
265
- display: block;
266
- margin-bottom: var(--jux-section-margin, 2rem);
267
- }
268
-
269
- .jux-article {
270
- display: block;
271
- max-width: var(--jux-article-max-width, 65ch);
272
- margin: 0 auto;
273
- }
274
- `;
275
- document.head.appendChild(style);
276
- }
277
217
  }
278
218
 
279
219
  export function element(id: string, options: ElementOptions = {}): Element {
@@ -276,15 +276,6 @@ export class FileUpload extends FormInput<FileUploadState> {
276
276
  }
277
277
 
278
278
  container.appendChild(wrapper);
279
- this._injectFileUploadStyles();
280
- this._injectFormStyles();
281
-
282
- requestAnimationFrame(() => {
283
- if ((window as any).lucide) {
284
- (window as any).lucide.createIcons();
285
- }
286
- });
287
-
288
279
  return this;
289
280
  }
290
281
 
@@ -311,64 +302,6 @@ export class FileUpload extends FormInput<FileUploadState> {
311
302
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
312
303
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
313
304
  }
314
-
315
- private _injectFileUploadStyles(): void {
316
- const styleId = 'jux-fileupload-styles';
317
- if (document.getElementById(styleId)) return;
318
-
319
- const style = document.createElement('style');
320
- style.id = styleId;
321
- style.textContent = `
322
- .jux-fileupload-input {
323
- display: none;
324
- }
325
-
326
- .jux-fileupload-button-container {
327
- display: inline-flex;
328
- align-items: center;
329
- gap: 8px;
330
- }
331
-
332
- .jux-fileupload-icon svg {
333
- width: 18px;
334
- height: 18px;
335
- }
336
-
337
- .jux-fileupload-button {
338
- padding: 8px 16px;
339
- background: #3b82f6;
340
- color: white;
341
- border: none;
342
- border-radius: 6px;
343
- font-size: 14px;
344
- cursor: pointer;
345
- transition: background 0.2s;
346
- }
347
-
348
- .jux-fileupload-button:hover:not(:disabled) {
349
- background: #2563eb;
350
- }
351
-
352
- .jux-fileupload-button:disabled {
353
- background: #9ca3af;
354
- cursor: not-allowed;
355
- }
356
-
357
- .jux-fileupload-list {
358
- margin-top: 12px;
359
- font-size: 14px;
360
- color: #6b7280;
361
- }
362
-
363
- .jux-fileupload-item {
364
- padding: 8px;
365
- background: #f3f4f6;
366
- border-radius: 4px;
367
- margin-bottom: 4px;
368
- }
369
- `;
370
- document.head.appendChild(style);
371
- }
372
305
  }
373
306
 
374
307
  export function fileupload(id: string, options: FileUploadOptions = {}): FileUpload {
@@ -7,10 +7,13 @@ const CALLBACK_EVENTS = ['ctaClick'] as const; // ✅ When CTA button is clicke
7
7
  export interface HeroOptions {
8
8
  title?: string;
9
9
  subtitle?: string;
10
- cta?: string;
10
+ content?: string; // ✅ ADD: Generates jux-hero-body div
11
+ cta?: string; // ✅ KEEP: Generates jux-hero-cta anchor
11
12
  ctaLink?: string;
12
13
  backgroundImage?: string;
14
+ backgroundOverlay?: boolean; // ✅ ADD: Generates jux-hero-overlay div
13
15
  variant?: 'default' | 'centered' | 'split';
16
+ centered?: boolean; // ✅ ADD: Affects container class
14
17
  style?: string;
15
18
  class?: string;
16
19
  }
@@ -18,13 +21,13 @@ export interface HeroOptions {
18
21
  type HeroState = {
19
22
  title: string;
20
23
  subtitle: string;
24
+ content: string; // ✅ ADD: For jux-hero-body
21
25
  cta: string;
22
26
  ctaLink: string;
23
27
  backgroundImage: string;
28
+ backgroundOverlay: boolean; // ✅ ADD: For overlay div
24
29
  variant: string;
25
- content: string;
26
- backgroundOverlay: boolean;
27
- centered: boolean;
30
+ centered: boolean; // ✅ ADD: For layout variant
28
31
  style: string;
29
32
  class: string;
30
33
  };
@@ -34,13 +37,13 @@ export class Hero extends BaseComponent<HeroState> {
34
37
  super(id, {
35
38
  title: options.title ?? '',
36
39
  subtitle: options.subtitle ?? '',
40
+ content: options.content ?? '', // ✅ ADD
37
41
  cta: options.cta ?? '',
38
42
  ctaLink: options.ctaLink ?? '#',
39
43
  backgroundImage: options.backgroundImage ?? '',
44
+ backgroundOverlay: options.backgroundOverlay ?? false, // ✅ ADD
40
45
  variant: options.variant ?? 'default',
41
- content: '',
42
- backgroundOverlay: false,
43
- centered: false,
46
+ centered: options.centered ?? false, // ✅ ADD
44
47
  style: options.style ?? '',
45
48
  class: options.class ?? ''
46
49
  });
@@ -58,8 +61,6 @@ export class Hero extends BaseComponent<HeroState> {
58
61
  * FLUENT API
59
62
  * ═════════════════════════════════════════════════════════════════ */
60
63
 
61
- // ✅ Inherited from BaseComponent
62
-
63
64
  title(value: string): this {
64
65
  this.state.title = value;
65
66
  return this;
@@ -70,6 +71,11 @@ export class Hero extends BaseComponent<HeroState> {
70
71
  return this;
71
72
  }
72
73
 
74
+ content(value: string): this { // ✅ ADD: Fluent method for content
75
+ this.state.content = value;
76
+ return this;
77
+ }
78
+
73
79
  cta(value: string): this {
74
80
  this.state.cta = value;
75
81
  return this;
@@ -85,11 +91,21 @@ export class Hero extends BaseComponent<HeroState> {
85
91
  return this;
86
92
  }
87
93
 
94
+ backgroundOverlay(value: boolean): this { // ✅ ADD: Fluent method for overlay
95
+ this.state.backgroundOverlay = value;
96
+ return this;
97
+ }
98
+
88
99
  variant(value: string): this {
89
100
  this.state.variant = value;
90
101
  return this;
91
102
  }
92
103
 
104
+ centered(value: boolean): this { // ✅ ADD: Fluent method for centered
105
+ this.state.centered = value;
106
+ return this;
107
+ }
108
+
93
109
  /* ═════════════════════════════════════════════════════════════════
94
110
  * RENDER
95
111
  * ═════════════════════════════════════════════════════════════════ */
@@ -341,7 +341,7 @@ export class Input extends FormInput<InputState> {
341
341
  }
342
342
 
343
343
  container.appendChild(wrapper);
344
- this._injectFormStyles();
344
+
345
345
 
346
346
  requestAnimationFrame(() => {
347
347
  if ((window as any).lucide) {
@@ -409,139 +409,9 @@ export class List extends BaseComponent<ListState> {
409
409
  });
410
410
 
411
411
  container.appendChild(wrapper);
412
- this._injectListStyles();
413
-
414
- requestAnimationFrame(() => {
415
- if ((window as any).lucide) {
416
- (window as any).lucide.createIcons();
417
- }
418
- });
419
412
 
420
413
  return this;
421
414
  }
422
-
423
- private _injectListStyles(): void {
424
- const styleId = 'jux-list-styles';
425
- if (document.getElementById(styleId)) return;
426
-
427
- const style = document.createElement('style');
428
- style.id = styleId;
429
- style.textContent = `
430
- .jux-list-wrapper {
431
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
432
- }
433
-
434
- .jux-list-header {
435
- font-size: 18px;
436
- font-weight: 600;
437
- margin-bottom: 12px;
438
- color: #1f2937;
439
- }
440
-
441
- .jux-list {
442
- list-style: none;
443
- padding: 0;
444
- margin: 0;
445
- }
446
-
447
- .jux-list-ordered {
448
- list-style: decimal;
449
- padding-left: 20px;
450
- }
451
-
452
- .jux-list-item {
453
- position: relative;
454
- padding: 12px 16px;
455
- transition: all 0.2s;
456
- cursor: default;
457
- }
458
-
459
- .jux-list-item-hoverable:not(.jux-list-item-disabled) {
460
- cursor: pointer;
461
- }
462
-
463
- .jux-list-item-hoverable:not(.jux-list-item-disabled):hover {
464
- background: #f3f4f6;
465
- }
466
-
467
- .jux-list-item-content {
468
- display: flex;
469
- align-items: center;
470
- gap: 12px;
471
- }
472
-
473
- .jux-list-item-icon {
474
- flex-shrink: 0;
475
- display: flex;
476
- align-items: center;
477
- }
478
-
479
- .jux-list-item-icon svg {
480
- width: 20px;
481
- height: 20px;
482
- }
483
-
484
- .jux-list-item-text {
485
- flex: 1;
486
- }
487
-
488
- .jux-list-item-title {
489
- font-size: 14px;
490
- font-weight: 500;
491
- color: #1f2937;
492
- margin-bottom: 2px;
493
- }
494
-
495
- .jux-list-item-body {
496
- font-size: 13px;
497
- color: #6b7280;
498
- line-height: 1.4;
499
- }
500
-
501
- .jux-list-item-metadata {
502
- flex-shrink: 0;
503
- font-size: 12px;
504
- color: #9ca3af;
505
- }
506
-
507
- .jux-list-item-selected {
508
- background: #dbeafe !important;
509
- border-left: 3px solid #3b82f6;
510
- }
511
-
512
- .jux-list-item-striped {
513
- background: #f9fafb;
514
- }
515
-
516
- .jux-list-item-bordered {
517
- border: 1px solid #e5e7eb;
518
- border-radius: 6px;
519
- margin-bottom: 4px;
520
- }
521
-
522
- .jux-list-item-disabled {
523
- opacity: 0.5;
524
- cursor: not-allowed;
525
- }
526
-
527
- .jux-list-item-success {
528
- border-left: 3px solid #10b981;
529
- }
530
-
531
- .jux-list-item-warning {
532
- border-left: 3px solid #f59e0b;
533
- }
534
-
535
- .jux-list-item-error {
536
- border-left: 3px solid #ef4444;
537
- }
538
-
539
- .jux-list-item-info {
540
- border-left: 3px solid #3b82f6;
541
- }
542
- `;
543
- document.head.appendChild(style);
544
- }
545
415
  }
546
416
 
547
417
  export function list(id: string, options: ListOptions = {}): List {
@@ -90,103 +90,9 @@ export class Loading extends BaseComponent<LoadingState> {
90
90
  this._wireStandardEvents(loading);
91
91
 
92
92
  container.appendChild(loading);
93
- this._injectLoadingStyles();
94
93
 
95
94
  return this;
96
95
  }
97
-
98
- private _injectLoadingStyles(): void {
99
- const styleId = 'jux-loading-styles';
100
- if (document.getElementById(styleId)) return;
101
-
102
- const style = document.createElement('style');
103
- style.id = styleId;
104
- style.textContent = `
105
- .jux-loading {
106
- display: inline-flex;
107
- align-items: center;
108
- justify-content: center;
109
- gap: 4px;
110
- }
111
-
112
- .jux-loading-sm { width: 20px; height: 20px; }
113
- .jux-loading-md { width: 40px; height: 40px; }
114
- .jux-loading-lg { width: 60px; height: 60px; }
115
-
116
- /* Spinner */
117
- .jux-loading-spinner {
118
- width: 30px;
119
- height: 30px;
120
- border: 2px solid #e5e7eb;
121
- border-top-color: #3b82f6;
122
- border-radius: 50%;
123
- animation: jux-spin 0.8s linear infinite;
124
- }
125
-
126
- .jux-loading-sm .jux-loading-spinner {
127
- border-width: 2px;
128
- }
129
-
130
- .jux-loading-md .jux-loading-spinner {
131
- border-width: 3px;
132
- }
133
-
134
- .jux-loading-lg .jux-loading-spinner {
135
- border-width: 4px;
136
- }
137
-
138
- @keyframes jux-spin {
139
- to { transform: rotate(360deg); }
140
- }
141
-
142
- /* Dots */
143
- .jux-loading-dot {
144
- width: 8px;
145
- height: 8px;
146
- background: #3b82f6;
147
- border-radius: 50%;
148
- animation: jux-bounce 1.4s infinite ease-in-out both;
149
- }
150
-
151
- .jux-loading-sm .jux-loading-dot {
152
- width: 5px;
153
- height: 5px;
154
- }
155
-
156
- .jux-loading-md .jux-loading-dot {
157
- width: 8px;
158
- height: 8px;
159
- }
160
-
161
- .jux-loading-lg .jux-loading-dot {
162
- width: 12px;
163
- height: 12px;
164
- }
165
-
166
- .jux-loading-dot:nth-child(1) { animation-delay: -0.32s; }
167
- .jux-loading-dot:nth-child(2) { animation-delay: -0.16s; }
168
-
169
- @keyframes jux-bounce {
170
- 0%, 80%, 100% { transform: scale(0); }
171
- 40% { transform: scale(1); }
172
- }
173
-
174
- /* Pulse */
175
- .jux-loading-pulse {
176
- width: 100%;
177
- height: 100%;
178
- background: #3b82f6;
179
- border-radius: 50%;
180
- animation: jux-pulse 1.5s ease-in-out infinite;
181
- }
182
-
183
- @keyframes jux-pulse {
184
- 0%, 100% { opacity: 1; transform: scale(0.8); }
185
- 50% { opacity: 0.5; transform: scale(1.2); }
186
- }
187
- `;
188
- document.head.appendChild(style);
189
- }
190
96
  }
191
97
 
192
98
  export function loading(id: string, options: LoadingOptions = {}): Loading {
@@ -129,64 +129,9 @@ export class Progress extends BaseComponent<ProgressState> {
129
129
  });
130
130
 
131
131
  container.appendChild(wrapper);
132
- this._injectProgressStyles();
133
132
 
134
133
  return this;
135
134
  }
136
-
137
- private _injectProgressStyles(): void {
138
- const styleId = 'jux-progress-styles';
139
- if (document.getElementById(styleId)) return;
140
-
141
- const style = document.createElement('style');
142
- style.id = styleId;
143
- style.textContent = `
144
- .jux-progress {
145
- width: 100%;
146
- margin-bottom: 1rem;
147
- }
148
-
149
- .jux-progress-track {
150
- width: 100%;
151
- height: 1.5rem;
152
- background-color: #e5e7eb;
153
- border-radius: 0.5rem;
154
- overflow: hidden;
155
- }
156
-
157
- .jux-progress-bar {
158
- height: 100%;
159
- display: flex;
160
- align-items: center;
161
- justify-content: center;
162
- color: white;
163
- font-size: 0.75rem;
164
- font-weight: 600;
165
- transition: width 0.3s ease;
166
- }
167
-
168
- .jux-progress-bar-default {
169
- background-color: #3b82f6;
170
- }
171
-
172
- .jux-progress-bar-success {
173
- background-color: #10b981;
174
- }
175
-
176
- .jux-progress-bar-warning {
177
- background-color: #f59e0b;
178
- }
179
-
180
- .jux-progress-bar-error {
181
- background-color: #ef4444;
182
- }
183
-
184
- .jux-progress-label {
185
- padding: 0 0.5rem;
186
- }
187
- `;
188
- document.head.appendChild(style);
189
- }
190
135
  }
191
136
 
192
137
  export function progress(id: string, options: ProgressOptions = {}): Progress {