juxscript 1.1.107 → 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,8 +140,7 @@ export abstract class BaseStack extends BaseComponent<StackState> {
210
140
  * ANIMATION API (Fluent)
211
141
  * ═════════════════════════════════════════════════════════════════ */
212
142
 
213
- /* Stack-Level Animations (Animate the container) */
214
-
143
+ /* Stack-Level Animations */
215
144
  fadeIn(): this {
216
145
  return this.addClass('jux-stack-fade-in');
217
146
  }
@@ -252,8 +181,7 @@ export abstract class BaseStack extends BaseComponent<StackState> {
252
181
  return this.addClass('jux-stack-glow');
253
182
  }
254
183
 
255
- /* Item-Level Animations (Animate the children) */
256
-
184
+ /* Item-Level Animations */
257
185
  fadeInItems(): this {
258
186
  return this.addClass('jux-stack-fade-in-items');
259
187
  }
@@ -294,14 +222,66 @@ export abstract class BaseStack extends BaseComponent<StackState> {
294
222
  return this.addClass('jux-stack-glow-items');
295
223
  }
296
224
 
297
- /* Stagger (Only works with item-level animations) */
225
+ /* Speed Modifiers */
226
+ instant(): this {
227
+ return this.addClass('jux-stack-instant');
228
+ }
229
+
230
+ fast(): this {
231
+ return this.addClass('jux-stack-fast');
232
+ }
233
+
234
+ normal(): this {
235
+ return this.addClass('jux-stack-normal');
236
+ }
237
+
238
+ slow(): this {
239
+ return this.addClass('jux-stack-slow');
240
+ }
298
241
 
242
+ slower(): this {
243
+ return this.addClass('jux-stack-slower');
244
+ }
245
+
246
+ /* Timing Functions */
247
+ linear(): this {
248
+ return this.addClass('jux-stack-linear');
249
+ }
250
+
251
+ ease(): this {
252
+ return this.addClass('jux-stack-ease');
253
+ }
254
+
255
+ easeIn(): this {
256
+ return this.addClass('jux-stack-ease-in');
257
+ }
258
+
259
+ easeOut(): this {
260
+ return this.addClass('jux-stack-ease-out');
261
+ }
262
+
263
+ easeInOut(): this {
264
+ return this.addClass('jux-stack-ease-in-out');
265
+ }
266
+
267
+ bounceTiming(): this {
268
+ return this.addClass('jux-stack-bounce-timing');
269
+ }
270
+
271
+ elasticTiming(): this {
272
+ return this.addClass('jux-stack-elastic-timing');
273
+ }
274
+
275
+ /* Delay Control */
276
+ delay(ms: 100 | 200 | 300 | 500 | 1000): this {
277
+ return this.addClass(`jux-stack-delay-${ms}`);
278
+ }
279
+
280
+ /* Stagger & Interactive */
299
281
  staggered(): this {
300
282
  return this.addClass('jux-stack-stagger');
301
283
  }
302
284
 
303
- /* Interactive & Utility */
304
-
305
285
  interactive(): this {
306
286
  return this.addClass('jux-stack-interactive');
307
287
  }
@@ -314,9 +294,7 @@ export abstract class BaseStack extends BaseComponent<StackState> {
314
294
  return this.addClass('jux-stack-smooth-items');
315
295
  }
316
296
 
317
- /**
318
- * Combine animation with stagger
319
- */
297
+ /* Convenience Combos */
320
298
  animateStagger(animation: 'fade' | 'slide' | 'scale' | 'bounce' = 'fade', direction?: 'up' | 'down' | 'left' | 'right'): this {
321
299
  if (animation === 'slide' && direction) {
322
300
  this.slideIn(direction);
@@ -331,23 +309,23 @@ export abstract class BaseStack extends BaseComponent<StackState> {
331
309
  }
332
310
 
333
311
  /* ═════════════════════════════════════════════════════════════════
334
- * RENDER HELPERS
312
+ * RENDER
335
313
  * ═════════════════════════════════════════════════════════════════ */
336
314
 
337
315
  protected buildClasses(): string {
338
- const { spacing, align, justify, divider, responsive } = this.state;
316
+ const { spacing, align, justify, divider, responsive, class: userClass } = this.state;
339
317
 
340
318
  const classes = [this.baseClassName];
341
319
 
342
- if (spacing !== 'default') {
320
+ if (spacing !== 'normal') {
343
321
  classes.push(`${this.baseClassName}-${spacing}`);
344
322
  }
345
323
 
346
- if (align) {
324
+ if (align !== 'start') {
347
325
  classes.push(`jux-stack-${align}`);
348
326
  }
349
327
 
350
- if (justify) {
328
+ if (justify !== 'start') {
351
329
  classes.push(`jux-stack-justify-${justify}`);
352
330
  }
353
331
 
@@ -359,8 +337,8 @@ export abstract class BaseStack extends BaseComponent<StackState> {
359
337
  classes.push(`${this.baseClassName}-responsive`);
360
338
  }
361
339
 
362
- if (this.state.class) {
363
- classes.push(this.state.class);
340
+ if (userClass) {
341
+ classes.push(userClass);
364
342
  }
365
343
 
366
344
  return classes.join(' ');
@@ -373,13 +351,13 @@ export abstract class BaseStack extends BaseComponent<StackState> {
373
351
  if (child && typeof child === 'object' && '_container' in child && child._container instanceof HTMLElement) {
374
352
  childElement = child._container;
375
353
  }
376
- // ✅ 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)
377
355
  else if (child && typeof child === 'object' && typeof child.render === 'function') {
378
356
  // Create temporary container to render into
379
357
  const tempContainer = document.createElement('div');
380
- tempContainer.style.display = 'contents'; // Don't add extra wrapper
358
+ tempContainer.style.display = 'contents';
381
359
 
382
- // Render the component into temp container
360
+ // Render the component
383
361
  child.render(tempContainer);
384
362
 
385
363
  // Extract the rendered element
@@ -391,7 +369,7 @@ export abstract class BaseStack extends BaseComponent<StackState> {
391
369
  childElement = tempContainer;
392
370
  }
393
371
  }
394
- // ✅ Priority 3: Check if it's already a DOM element
372
+ // ✅ Priority 3: Already a DOM element
395
373
  else if (child instanceof HTMLElement) {
396
374
  childElement = child;
397
375
  }
@@ -416,54 +394,39 @@ export abstract class BaseStack extends BaseComponent<StackState> {
416
394
  return childElement;
417
395
  }
418
396
 
419
- private getChildStyle(index: number): string {
420
- const { childStyles } = this.state;
421
-
422
- if (!childStyles) return '';
423
-
424
- if (typeof childStyles === 'function') {
425
- return childStyles(index);
426
- }
427
-
428
- if (Array.isArray(childStyles)) {
429
- return childStyles[index] || '';
430
- }
431
-
432
- return '';
433
- }
434
-
435
- /* ═════════════════════════════════════════════════════════════════
436
- * RENDER
437
- * ═════════════════════════════════════════════════════════════════ */
438
-
439
397
  render(targetId?: string | HTMLElement | BaseComponent<any>): this {
440
398
  const container = this._setupContainer(targetId);
441
399
 
442
- const wrapper = document.createElement('div');
443
- wrapper.className = this.buildClasses();
444
- wrapper.id = this._id;
400
+ const stackDiv = document.createElement('div');
401
+ stackDiv.id = this._id;
402
+ stackDiv.className = this.buildClasses();
445
403
 
446
404
  if (this.state.style) {
447
- wrapper.setAttribute('style', this.state.style);
405
+ stackDiv.setAttribute('style', this.state.style);
448
406
  }
449
407
 
450
- // Render all children
451
- 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) => {
452
414
  const childEl = this.renderChild(child, index);
453
- wrapper.appendChild(childEl);
415
+ stackDiv.appendChild(childEl);
454
416
  });
455
417
 
456
- this._wireStandardEvents(wrapper);
418
+ this._wireStandardEvents(stackDiv);
457
419
 
458
- // ✅ Store wrapper as _container for nesting
459
- this._container = wrapper;
460
-
461
- container.appendChild(wrapper);
420
+ container.appendChild(stackDiv);
421
+ this._container = stackDiv;
462
422
 
463
423
  return this;
464
424
  }
465
425
 
466
426
  update(prop: string, value: any): void {
467
- // Stack components are typically static
427
+ // Stacks don't need reactive updates
468
428
  }
469
429
  }
430
+
431
+ // ✅ Type assertion for LayoutExtensions
432
+ export interface BaseStack extends LayoutExtensions { }