juxscript 1.1.108 → 1.1.109

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.
@@ -1,61 +1,47 @@
1
1
  import { BaseComponent, BaseState } from '../base/BaseComponent.js';
2
+ import { applyLayoutExtensions, LayoutExtensions } from '../base/LayoutExtensions.js';
2
3
 
3
4
  // Event definitions
4
5
  const TRIGGER_EVENTS = [] as const;
5
6
  const CALLBACK_EVENTS = [] as const;
6
7
 
7
8
  export interface StackOptions {
8
- spacing?: 'none' | 'tight' | 'default' | 'loose';
9
+ spacing?: 'none' | 'tight' | 'normal' | 'loose';
9
10
  align?: 'start' | 'center' | 'end' | 'stretch';
10
11
  justify?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly';
11
12
  divider?: boolean;
12
13
  responsive?: boolean;
13
- class?: string;
14
- style?: string;
15
14
  }
16
15
 
17
- export interface ChildStyleFunction {
18
- (index: number): string;
19
- }
20
-
21
- interface StackState extends BaseState {
16
+ export interface StackState extends BaseState {
22
17
  spacing: string;
23
- align?: string;
24
- justify?: string;
18
+ align: string;
19
+ justify: string;
25
20
  divider: boolean;
26
21
  responsive: boolean;
27
- children: Array<any>;
28
- childStyles?: ChildStyleFunction | string[];
29
22
  }
30
23
 
31
- /**
32
- * BaseStack - Foundation for all stack layout components
33
- */
34
24
  export abstract class BaseStack extends BaseComponent<StackState> {
35
25
  protected abstract baseClassName: string;
36
- private _inlineStyles: Map<string, string> = new Map();
37
- public _container: HTMLElement | null = null; // ✅ Make public for nesting
38
-
39
- constructor(id: string, children: Record<string, any> | any[], options: StackOptions = {}) {
40
- const childArray = Array.isArray(children)
41
- ? children
42
- : Object.values(children);
26
+ protected _container: HTMLElement | null = null;
27
+ protected _childStyleFunction: ((index: number) => string) | null = null;
43
28
 
29
+ constructor(id: string, protected children: Record<string, any> | any[], options: StackOptions = {}) {
44
30
  super(id, {
45
31
  visible: true,
46
32
  disabled: false,
47
33
  loading: false,
48
- class: options.class ?? '',
49
- style: options.style ?? '',
34
+ class: '',
35
+ style: '',
50
36
  attributes: {},
51
- spacing: options.spacing ?? 'default',
52
- align: options.align,
53
- justify: options.justify,
54
- divider: options.divider ?? false,
55
- responsive: options.responsive ?? false,
56
- children: childArray,
57
- childStyles: undefined
37
+ spacing: options.spacing || 'normal',
38
+ align: options.align || 'start',
39
+ justify: options.justify || 'start',
40
+ divider: options.divider || false,
41
+ responsive: options.responsive || false
58
42
  });
43
+
44
+ // ✅ Layout extensions are automatically applied in BaseComponent constructor
59
45
  }
60
46
 
61
47
  protected getTriggerEvents(): readonly string[] {
@@ -70,139 +56,83 @@ export abstract class BaseStack extends BaseComponent<StackState> {
70
56
  * FLUENT LAYOUT API
71
57
  * ═════════════════════════════════════════════════════════════════ */
72
58
 
73
- spacing(value: 'none' | 'tight' | 'default' | 'loose'): this {
59
+ spacing(value: 'none' | 'tight' | 'normal' | 'loose'): this {
74
60
  this.state.spacing = value;
61
+ if (this._container) {
62
+ this._container.className = this.buildClasses();
63
+ }
75
64
  return this;
76
65
  }
77
66
 
78
67
  align(value: 'start' | 'center' | 'end' | 'stretch'): this {
79
68
  this.state.align = value;
69
+ if (this._container) {
70
+ this._container.className = this.buildClasses();
71
+ }
80
72
  return this;
81
73
  }
82
74
 
83
75
  justify(value: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'): this {
84
76
  this.state.justify = value;
77
+ if (this._container) {
78
+ this._container.className = this.buildClasses();
79
+ }
85
80
  return this;
86
81
  }
87
82
 
88
- divider(value: boolean = true): this {
83
+ divider(value: boolean): this {
89
84
  this.state.divider = value;
85
+ if (this._container) {
86
+ this._container.className = this.buildClasses();
87
+ }
90
88
  return this;
91
89
  }
92
90
 
93
- responsive(value: boolean = true): this {
91
+ responsive(value: boolean): this {
94
92
  this.state.responsive = value;
93
+ if (this._container) {
94
+ this._container.className = this.buildClasses();
95
+ }
95
96
  return this;
96
97
  }
97
98
 
98
99
  /* ═════════════════════════════════════════════════════════════════
99
- * FLUENT STYLE API
100
+ * CHILD STYLING
100
101
  * ═════════════════════════════════════════════════════════════════ */
101
102
 
102
- private _addStyle(property: string, value: string): this {
103
- this._inlineStyles.set(property, value);
104
- this._updateStyleAttribute();
103
+ childStyle(fn: (index: number) => string): this {
104
+ this._childStyleFunction = fn;
105
105
  return this;
106
106
  }
107
107
 
108
- private _updateStyleAttribute(): void {
109
- const styleString = Array.from(this._inlineStyles.entries())
110
- .map(([prop, val]) => `${prop}: ${val}`)
111
- .join('; ');
112
-
113
- this.state.style = styleString;
114
- }
115
-
116
- padding(value: string): this { return this._addStyle('padding', value); }
117
- margin(value: string): this { return this._addStyle('margin', value); }
118
- border(value: string): this { return this._addStyle('border', value); }
119
- borderRadius(value: string): this { return this._addStyle('border-radius', value); }
120
- width(value: string): this { return this._addStyle('width', value); }
121
- height(value: string): this { return this._addStyle('height', value); }
122
- minWidth(value: string): this { return this._addStyle('min-width', value); }
123
- maxWidth(value: string): this { return this._addStyle('max-width', value); }
124
- minHeight(value: string): this { return this._addStyle('min-height', value); }
125
- maxHeight(value: string): this { return this._addStyle('max-height', value); }
126
- background(value: string): this { return this._addStyle('background', value); }
127
- backgroundColor(value: string): this { return this._addStyle('background-color', value); }
128
- boxShadow(value: string): this { return this._addStyle('box-shadow', value); }
129
- opacity(value: string | number): this { return this._addStyle('opacity', String(value)); }
130
- position(value: string): this { return this._addStyle('position', value); }
131
- top(value: string): this { return this._addStyle('top', value); }
132
- right(value: string): this { return this._addStyle('right', value); }
133
- bottom(value: string): this { return this._addStyle('bottom', value); }
134
- left(value: string): this { return this._addStyle('left', value); }
135
- zIndex(value: string | number): this { return this._addStyle('z-index', String(value)); }
136
- overflow(value: string): this { return this._addStyle('overflow', value); }
137
- overflowX(value: string): this { return this._addStyle('overflow-x', value); }
138
- overflowY(value: string): this { return this._addStyle('overflow-y', value); }
139
- display(value: string): this { return this._addStyle('display', value); }
140
- cursor(value: string): this { return this._addStyle('cursor', value); }
141
- transform(value: string): this { return this._addStyle('transform', value); }
142
- transformOrigin(value: string): this { return this._addStyle('transform-origin', value); }
143
- transition(value: string): this { return this._addStyle('transition', value); }
144
- animation(value: string): this { return this._addStyle('animation', value); }
108
+ protected getChildStyle(index: number): string {
109
+ return this._childStyleFunction ? this._childStyleFunction(index) : '';
110
+ }
145
111
 
146
112
  /* ═════════════════════════════════════════════════════════════════
147
- * PROGRESSIVE CHILD STYLING
113
+ * Z-STACK SPECIFIC EFFECTS
148
114
  * ═════════════════════════════════════════════════════════════════ */
149
115
 
150
- childStyle(stylesOrFunction: string[] | ChildStyleFunction): this {
151
- this.state.childStyles = stylesOrFunction;
116
+ fade(topOpacity: number = 1, step: number = 0.2): this {
117
+ this._childStyleFunction = (index) => `opacity: ${Math.max(0, topOpacity - index * step)};`;
152
118
  return this;
153
119
  }
154
120
 
155
- cascade(baseOffset: number = 20, axis: 'x' | 'y' | 'both' | 'horizontal' | 'vertical' | 'xy' = 'both'): this {
156
- this.state.childStyles = (index: number) => {
157
- const offset = baseOffset * index;
158
- if (axis === 'horizontal' || axis === 'x') {
159
- return `margin-left: ${offset}px;`;
160
- } else if (axis === 'vertical' || axis === 'y') {
161
- return `margin-top: ${offset}px;`;
121
+ cascade(offset: number = 20, direction: 'horizontal' | 'vertical' | 'both' = 'both'): this {
122
+ this._childStyleFunction = (index) => {
123
+ if (direction === 'horizontal') {
124
+ return `margin-left: ${index * offset}px;`;
125
+ } else if (direction === 'vertical') {
126
+ return `margin-top: ${index * offset}px;`;
162
127
  } else {
163
- return `margin-left: ${offset}px; margin-top: ${offset}px;`;
128
+ return `margin-left: ${index * offset}px; margin-top: ${index * offset}px;`;
164
129
  }
165
130
  };
166
131
  return this;
167
132
  }
168
133
 
169
- fan(angle: number = 5, origin: string = 'bottom center'): this {
170
- this.state.childStyles = (index: number) => {
171
- const rotation = angle * index;
172
- return `transform: rotate(${rotation}deg); transform-origin: ${origin};`;
173
- };
174
- return this;
175
- }
176
-
177
- scaleProgressive(startScale: number = 1, step: number = 0.05, origin: string = 'center'): this {
178
- this.state.childStyles = (index: number) => {
179
- const scale = startScale - (step * index);
180
- return `transform: scale(${scale}); transform-origin: ${origin};`;
181
- };
182
- return this;
183
- }
184
-
185
- fade(startOpacity: number = 1, step: number = 0.15): this {
186
- this.state.childStyles = (index: number) => {
187
- const opacity = Math.max(0.1, startOpacity - (step * index));
188
- return `opacity: ${opacity};`;
189
- };
190
- return this;
191
- }
192
-
193
- blur(startBlur: number = 0, step: number = 2): this {
194
- this.state.childStyles = (index: number) => {
195
- const blur = startBlur + (step * index);
196
- return `filter: blur(${blur}px);`;
197
- };
198
- return this;
199
- }
200
-
201
- stagger(baseDelay: number = 100): this {
202
- this.state.childStyles = (index: number) => {
203
- const delay = baseDelay * index;
204
- return `animation-delay: ${delay}ms;`;
205
- };
134
+ scaleProgressive(topScale: number = 1, step: number = 0.1): this {
135
+ this._childStyleFunction = (index) => `transform: scale(${Math.max(0.1, topScale - index * step)});`;
206
136
  return this;
207
137
  }
208
138
 
@@ -210,10 +140,7 @@ export abstract class BaseStack extends BaseComponent<StackState> {
210
140
  * ANIMATION API (Fluent)
211
141
  * ═════════════════════════════════════════════════════════════════ */
212
142
 
213
- /* ─────────────────────────────────────────────────────────────────
214
- * Stack-Level Animations (Animate the container)
215
- * ───────────────────────────────────────────────────────────────── */
216
-
143
+ /* Stack-Level Animations */
217
144
  fadeIn(): this {
218
145
  return this.addClass('jux-stack-fade-in');
219
146
  }
@@ -254,10 +181,7 @@ export abstract class BaseStack extends BaseComponent<StackState> {
254
181
  return this.addClass('jux-stack-glow');
255
182
  }
256
183
 
257
- /* ─────────────────────────────────────────────────────────────────
258
- * Item-Level Animations (Animate the children)
259
- * ───────────────────────────────────────────────────────────────── */
260
-
184
+ /* Item-Level Animations */
261
185
  fadeInItems(): this {
262
186
  return this.addClass('jux-stack-fade-in-items');
263
187
  }
@@ -298,10 +222,7 @@ export abstract class BaseStack extends BaseComponent<StackState> {
298
222
  return this.addClass('jux-stack-glow-items');
299
223
  }
300
224
 
301
- /* ─────────────────────────────────────────────────────────────────
302
- * Speed Modifiers (Control animation duration)
303
- * ───────────────────────────────────────────────────────────────── */
304
-
225
+ /* Speed Modifiers */
305
226
  instant(): this {
306
227
  return this.addClass('jux-stack-instant');
307
228
  }
@@ -322,10 +243,7 @@ export abstract class BaseStack extends BaseComponent<StackState> {
322
243
  return this.addClass('jux-stack-slower');
323
244
  }
324
245
 
325
- /* ─────────────────────────────────────────────────────────────────
326
- * Timing Functions (Control animation easing)
327
- * ───────────────────────────────────────────────────────────────── */
328
-
246
+ /* Timing Functions */
329
247
  linear(): this {
330
248
  return this.addClass('jux-stack-linear');
331
249
  }
@@ -354,18 +272,12 @@ export abstract class BaseStack extends BaseComponent<StackState> {
354
272
  return this.addClass('jux-stack-elastic-timing');
355
273
  }
356
274
 
357
- /* ─────────────────────────────────────────────────────────────────
358
- * Delay Control
359
- * ───────────────────────────────────────────────────────────────── */
360
-
275
+ /* Delay Control */
361
276
  delay(ms: 100 | 200 | 300 | 500 | 1000): this {
362
277
  return this.addClass(`jux-stack-delay-${ms}`);
363
278
  }
364
279
 
365
- /* ─────────────────────────────────────────────────────────────────
366
- * Stagger & Interactive
367
- * ───────────────────────────────────────────────────────────────── */
368
-
280
+ /* Stagger & Interactive */
369
281
  staggered(): this {
370
282
  return this.addClass('jux-stack-stagger');
371
283
  }
@@ -382,10 +294,7 @@ export abstract class BaseStack extends BaseComponent<StackState> {
382
294
  return this.addClass('jux-stack-smooth-items');
383
295
  }
384
296
 
385
- /* ─────────────────────────────────────────────────────────────────
386
- * Convenience Combos
387
- * ───────────────────────────────────────────────────────────────── */
388
-
297
+ /* Convenience Combos */
389
298
  animateStagger(animation: 'fade' | 'slide' | 'scale' | 'bounce' = 'fade', direction?: 'up' | 'down' | 'left' | 'right'): this {
390
299
  if (animation === 'slide' && direction) {
391
300
  this.slideIn(direction);
@@ -400,23 +309,23 @@ export abstract class BaseStack extends BaseComponent<StackState> {
400
309
  }
401
310
 
402
311
  /* ═════════════════════════════════════════════════════════════════
403
- * RENDER HELPERS
312
+ * RENDER
404
313
  * ═════════════════════════════════════════════════════════════════ */
405
314
 
406
315
  protected buildClasses(): string {
407
- const { spacing, align, justify, divider, responsive } = this.state;
316
+ const { spacing, align, justify, divider, responsive, class: userClass } = this.state;
408
317
 
409
318
  const classes = [this.baseClassName];
410
319
 
411
- if (spacing !== 'default') {
320
+ if (spacing !== 'normal') {
412
321
  classes.push(`${this.baseClassName}-${spacing}`);
413
322
  }
414
323
 
415
- if (align) {
324
+ if (align !== 'start') {
416
325
  classes.push(`jux-stack-${align}`);
417
326
  }
418
327
 
419
- if (justify) {
328
+ if (justify !== 'start') {
420
329
  classes.push(`jux-stack-justify-${justify}`);
421
330
  }
422
331
 
@@ -428,8 +337,8 @@ export abstract class BaseStack extends BaseComponent<StackState> {
428
337
  classes.push(`${this.baseClassName}-responsive`);
429
338
  }
430
339
 
431
- if (this.state.class) {
432
- classes.push(this.state.class);
340
+ if (userClass) {
341
+ classes.push(userClass);
433
342
  }
434
343
 
435
344
  return classes.join(' ');
@@ -442,13 +351,13 @@ export abstract class BaseStack extends BaseComponent<StackState> {
442
351
  if (child && typeof child === 'object' && '_container' in child && child._container instanceof HTMLElement) {
443
352
  childElement = child._container;
444
353
  }
445
- // ✅ Priority 2: Check if it's a JUX Component (has render method and container property)
354
+ // ✅ Priority 2: Check if it's a JUX Component (has render method)
446
355
  else if (child && typeof child === 'object' && typeof child.render === 'function') {
447
356
  // Create temporary container to render into
448
357
  const tempContainer = document.createElement('div');
449
- tempContainer.style.display = 'contents'; // Don't add extra wrapper
358
+ tempContainer.style.display = 'contents';
450
359
 
451
- // Render the component into temp container
360
+ // Render the component
452
361
  child.render(tempContainer);
453
362
 
454
363
  // Extract the rendered element
@@ -460,7 +369,7 @@ export abstract class BaseStack extends BaseComponent<StackState> {
460
369
  childElement = tempContainer;
461
370
  }
462
371
  }
463
- // ✅ Priority 3: Check if it's already a DOM element
372
+ // ✅ Priority 3: Already a DOM element
464
373
  else if (child instanceof HTMLElement) {
465
374
  childElement = child;
466
375
  }
@@ -485,54 +394,39 @@ export abstract class BaseStack extends BaseComponent<StackState> {
485
394
  return childElement;
486
395
  }
487
396
 
488
- private getChildStyle(index: number): string {
489
- const { childStyles } = this.state;
490
-
491
- if (!childStyles) return '';
492
-
493
- if (typeof childStyles === 'function') {
494
- return childStyles(index);
495
- }
496
-
497
- if (Array.isArray(childStyles)) {
498
- return childStyles[index] || '';
499
- }
500
-
501
- return '';
502
- }
503
-
504
- /* ═════════════════════════════════════════════════════════════════
505
- * RENDER
506
- * ═════════════════════════════════════════════════════════════════ */
507
-
508
397
  render(targetId?: string | HTMLElement | BaseComponent<any>): this {
509
398
  const container = this._setupContainer(targetId);
510
399
 
511
- const wrapper = document.createElement('div');
512
- wrapper.className = this.buildClasses();
513
- wrapper.id = this._id;
400
+ const stackDiv = document.createElement('div');
401
+ stackDiv.id = this._id;
402
+ stackDiv.className = this.buildClasses();
514
403
 
515
404
  if (this.state.style) {
516
- wrapper.setAttribute('style', this.state.style);
405
+ stackDiv.setAttribute('style', this.state.style);
517
406
  }
518
407
 
519
- // Render all children
520
- this.state.children.forEach((child, index) => {
408
+ // Handle both array and object children
409
+ const childArray = Array.isArray(this.children)
410
+ ? this.children
411
+ : Object.values(this.children);
412
+
413
+ childArray.forEach((child, index) => {
521
414
  const childEl = this.renderChild(child, index);
522
- wrapper.appendChild(childEl);
415
+ stackDiv.appendChild(childEl);
523
416
  });
524
417
 
525
- this._wireStandardEvents(wrapper);
526
-
527
- // ✅ Store wrapper as _container for nesting
528
- this._container = wrapper;
418
+ this._wireStandardEvents(stackDiv);
529
419
 
530
- container.appendChild(wrapper);
420
+ container.appendChild(stackDiv);
421
+ this._container = stackDiv;
531
422
 
532
423
  return this;
533
424
  }
534
425
 
535
426
  update(prop: string, value: any): void {
536
- // Stack components are typically static
427
+ // Stacks don't need reactive updates
537
428
  }
538
429
  }
430
+
431
+ // ✅ Type assertion for LayoutExtensions
432
+ export interface BaseStack extends LayoutExtensions { }