juxscript 1.1.82 → 1.1.87

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.
@@ -0,0 +1,373 @@
1
+ import { BaseComponent } from '../base/BaseComponent.js';
2
+ // Event definitions
3
+ const TRIGGER_EVENTS = [];
4
+ const CALLBACK_EVENTS = [];
5
+ /**
6
+ * BaseStack - Foundation for all stack layout components
7
+ * Provides common styling, child management, and progressive effects
8
+ */
9
+ export class BaseStack extends BaseComponent {
10
+ constructor(id, children, options = {}) {
11
+ // Convert children object to array, preserving order
12
+ const childArray = Array.isArray(children)
13
+ ? children
14
+ : Object.values(children);
15
+ super(id, {
16
+ visible: true,
17
+ disabled: false,
18
+ loading: false,
19
+ class: options.class ?? '',
20
+ style: options.style ?? '',
21
+ attributes: {},
22
+ spacing: options.spacing ?? 'default',
23
+ align: options.align,
24
+ justify: options.justify,
25
+ divider: options.divider ?? false,
26
+ responsive: options.responsive ?? false,
27
+ children: childArray,
28
+ childStyles: undefined
29
+ });
30
+ this._inlineStyles = new Map(); // ✅ Internal style storage
31
+ }
32
+ getTriggerEvents() {
33
+ return TRIGGER_EVENTS;
34
+ }
35
+ getCallbackEvents() {
36
+ return CALLBACK_EVENTS;
37
+ }
38
+ /* ═════════════════════════════════════════════════════════════════
39
+ * FLUENT LAYOUT API
40
+ * ═════════════════════════════════════════════════════════════════ */
41
+ spacing(value) {
42
+ this.state.spacing = value;
43
+ return this;
44
+ }
45
+ align(value) {
46
+ this.state.align = value;
47
+ return this;
48
+ }
49
+ justify(value) {
50
+ this.state.justify = value;
51
+ return this;
52
+ }
53
+ divider(value = true) {
54
+ this.state.divider = value;
55
+ return this;
56
+ }
57
+ responsive(value = true) {
58
+ this.state.responsive = value;
59
+ return this;
60
+ }
61
+ /* ═════════════════════════════════════════════════════════════════
62
+ * FLUENT STYLE API - Comprehensive CSS properties
63
+ * ═════════════════════════════════════════════════════════════════ */
64
+ /**
65
+ * Internal helper to add individual CSS properties
66
+ */
67
+ _addStyle(property, value) {
68
+ this._inlineStyles.set(property, value);
69
+ this._updateStyleAttribute();
70
+ return this;
71
+ }
72
+ /**
73
+ * Build and apply the complete style attribute
74
+ */
75
+ _updateStyleAttribute() {
76
+ const styleString = Array.from(this._inlineStyles.entries())
77
+ .map(([prop, val]) => `${prop}: ${val}`)
78
+ .join('; ');
79
+ this.state.style = styleString;
80
+ }
81
+ // Box Model
82
+ padding(value) {
83
+ return this._addStyle('padding', value);
84
+ }
85
+ margin(value) {
86
+ return this._addStyle('margin', value);
87
+ }
88
+ border(value) {
89
+ return this._addStyle('border', value);
90
+ }
91
+ borderRadius(value) {
92
+ return this._addStyle('border-radius', value);
93
+ }
94
+ // Sizing
95
+ width(value) {
96
+ return this._addStyle('width', value);
97
+ }
98
+ height(value) {
99
+ return this._addStyle('height', value);
100
+ }
101
+ minWidth(value) {
102
+ return this._addStyle('min-width', value);
103
+ }
104
+ maxWidth(value) {
105
+ return this._addStyle('max-width', value);
106
+ }
107
+ minHeight(value) {
108
+ return this._addStyle('min-height', value);
109
+ }
110
+ maxHeight(value) {
111
+ return this._addStyle('max-height', value);
112
+ }
113
+ // Visual
114
+ background(value) {
115
+ return this._addStyle('background', value);
116
+ }
117
+ backgroundColor(value) {
118
+ return this._addStyle('background-color', value);
119
+ }
120
+ boxShadow(value) {
121
+ return this._addStyle('box-shadow', value);
122
+ }
123
+ opacity(value) {
124
+ return this._addStyle('opacity', String(value));
125
+ }
126
+ // Positioning
127
+ position(value) {
128
+ return this._addStyle('position', value);
129
+ }
130
+ top(value) {
131
+ return this._addStyle('top', value);
132
+ }
133
+ right(value) {
134
+ return this._addStyle('right', value);
135
+ }
136
+ bottom(value) {
137
+ return this._addStyle('bottom', value);
138
+ }
139
+ left(value) {
140
+ return this._addStyle('left', value);
141
+ }
142
+ zIndex(value) {
143
+ return this._addStyle('z-index', String(value));
144
+ }
145
+ // Overflow
146
+ overflow(value) {
147
+ return this._addStyle('overflow', value);
148
+ }
149
+ overflowX(value) {
150
+ return this._addStyle('overflow-x', value);
151
+ }
152
+ overflowY(value) {
153
+ return this._addStyle('overflow-y', value);
154
+ }
155
+ // Display
156
+ display(value) {
157
+ return this._addStyle('display', value);
158
+ }
159
+ // Cursor
160
+ cursor(value) {
161
+ return this._addStyle('cursor', value);
162
+ }
163
+ // Transform
164
+ transform(value) {
165
+ return this._addStyle('transform', value);
166
+ }
167
+ transformOrigin(value) {
168
+ return this._addStyle('transform-origin', value);
169
+ }
170
+ // Transition & Animation
171
+ transition(value) {
172
+ return this._addStyle('transition', value);
173
+ }
174
+ animation(value) {
175
+ return this._addStyle('animation', value);
176
+ }
177
+ /* ═════════════════════════════════════════════════════════════════
178
+ * PROGRESSIVE CHILD STYLING
179
+ * ═════════════════════════════════════════════════════════════════ */
180
+ /**
181
+ * Apply custom styles to each child progressively
182
+ */
183
+ childStyle(stylesOrFunction) {
184
+ this.state.childStyles = stylesOrFunction;
185
+ return this;
186
+ }
187
+ /**
188
+ * Cascade effect - offset children progressively
189
+ */
190
+ cascade(baseOffset = 20, axis = 'both') {
191
+ this.state.childStyles = (index) => {
192
+ const offset = baseOffset * index;
193
+ if (axis === 'horizontal' || axis === 'x') {
194
+ return `margin-left: ${offset}px;`;
195
+ }
196
+ else if (axis === 'vertical' || axis === 'y') {
197
+ return `margin-top: ${offset}px;`;
198
+ }
199
+ else {
200
+ return `margin-left: ${offset}px; margin-top: ${offset}px;`;
201
+ }
202
+ };
203
+ return this;
204
+ }
205
+ /**
206
+ * Fan effect - rotate children progressively
207
+ */
208
+ fan(angle = 5, origin = 'bottom center') {
209
+ this.state.childStyles = (index) => {
210
+ const rotation = angle * index;
211
+ return `transform: rotate(${rotation}deg); transform-origin: ${origin};`;
212
+ };
213
+ return this;
214
+ }
215
+ /**
216
+ * Scale progression - shrink/grow children
217
+ */
218
+ scaleProgressive(startScale = 1, step = 0.05, origin = 'center') {
219
+ this.state.childStyles = (index) => {
220
+ const scale = startScale - (step * index);
221
+ return `transform: scale(${scale}); transform-origin: ${origin};`;
222
+ };
223
+ return this;
224
+ }
225
+ /**
226
+ * Fade effect - progressive opacity
227
+ */
228
+ fade(startOpacity = 1, step = 0.15) {
229
+ this.state.childStyles = (index) => {
230
+ const opacity = Math.max(0.1, startOpacity - (step * index));
231
+ return `opacity: ${opacity};`;
232
+ };
233
+ return this;
234
+ }
235
+ /**
236
+ * Blur effect - progressive blur
237
+ */
238
+ blur(startBlur = 0, step = 2) {
239
+ this.state.childStyles = (index) => {
240
+ const blur = startBlur + (step * index);
241
+ return `filter: blur(${blur}px);`;
242
+ };
243
+ return this;
244
+ }
245
+ /**
246
+ * Stagger animation delays
247
+ */
248
+ stagger(baseDelay = 100) {
249
+ this.state.childStyles = (index) => {
250
+ const delay = baseDelay * index;
251
+ return `animation-delay: ${delay}ms;`;
252
+ };
253
+ return this;
254
+ }
255
+ /* ═════════════════════════════════════════════════════════════════
256
+ * RENDER HELPERS
257
+ * ═════════════════════════════════════════════════════════════════ */
258
+ buildClasses() {
259
+ const { spacing, align, justify, divider, responsive } = this.state;
260
+ const classes = [this.baseClassName];
261
+ // Spacing modifier
262
+ if (spacing !== 'default') {
263
+ classes.push(`${this.baseClassName}-${spacing}`);
264
+ }
265
+ // Alignment
266
+ if (align) {
267
+ classes.push(`jux-stack-${align}`);
268
+ }
269
+ // Justification
270
+ if (justify) {
271
+ classes.push(`jux-stack-justify-${justify}`);
272
+ }
273
+ // Divider
274
+ if (divider) {
275
+ classes.push(`${this.baseClassName}-divider`);
276
+ }
277
+ // Responsive
278
+ if (responsive) {
279
+ classes.push(`${this.baseClassName}-responsive`);
280
+ }
281
+ // Custom classes
282
+ if (this.state.class) {
283
+ classes.push(this.state.class);
284
+ }
285
+ return classes.join(' ');
286
+ }
287
+ renderChild(child, index) {
288
+ // Already a string
289
+ if (typeof child === 'string') {
290
+ return this.wrapChildWithStyle(child, index);
291
+ }
292
+ // JUX component with render method
293
+ if (child && typeof child.render === 'function') {
294
+ // Create temporary container
295
+ const temp = document.createElement('div');
296
+ child.render(temp);
297
+ if (child.container) {
298
+ let html = child.container.outerHTML;
299
+ child.container = null; // Reset for reuse
300
+ return this.injectChildStyle(html, index);
301
+ }
302
+ }
303
+ // DOM element
304
+ if (child && child.outerHTML) {
305
+ return this.injectChildStyle(child.outerHTML, index);
306
+ }
307
+ // Object with render method that returns string/element
308
+ if (child && typeof child.render === 'function') {
309
+ const rendered = child.render();
310
+ if (typeof rendered === 'string') {
311
+ return this.wrapChildWithStyle(rendered, index);
312
+ }
313
+ if (rendered && rendered.outerHTML) {
314
+ return this.injectChildStyle(rendered.outerHTML, index);
315
+ }
316
+ }
317
+ // Fallback to string
318
+ return this.wrapChildWithStyle(String(child), index);
319
+ }
320
+ wrapChildWithStyle(html, index) {
321
+ const style = this.getChildStyle(index);
322
+ if (style) {
323
+ return `<div style="${style}">${html}</div>`;
324
+ }
325
+ return html;
326
+ }
327
+ injectChildStyle(html, index) {
328
+ const style = this.getChildStyle(index);
329
+ if (style) {
330
+ return html.replace(/^<(\w+)/, `<$1 style="${style}"`);
331
+ }
332
+ return html;
333
+ }
334
+ getChildStyle(index) {
335
+ const { childStyles } = this.state;
336
+ if (!childStyles)
337
+ return '';
338
+ if (typeof childStyles === 'function') {
339
+ return childStyles(index);
340
+ }
341
+ if (Array.isArray(childStyles)) {
342
+ return childStyles[index] || '';
343
+ }
344
+ return '';
345
+ }
346
+ /* ═════════════════════════════════════════════════════════════════
347
+ * RENDER
348
+ * ═════════════════════════════════════════════════════════════════ */
349
+ render(targetId) {
350
+ const container = this._setupContainer(targetId);
351
+ const wrapper = document.createElement('div');
352
+ wrapper.className = this.buildClasses();
353
+ wrapper.id = this._id;
354
+ if (this.state.style) {
355
+ wrapper.setAttribute('style', this.state.style);
356
+ }
357
+ // Render all children
358
+ this.state.children.forEach((child, index) => {
359
+ const childHtml = this.renderChild(child, index);
360
+ const tempDiv = document.createElement('div');
361
+ tempDiv.innerHTML = childHtml;
362
+ if (tempDiv.firstChild) {
363
+ wrapper.appendChild(tempDiv.firstChild);
364
+ }
365
+ });
366
+ this._wireStandardEvents(wrapper);
367
+ container.appendChild(wrapper);
368
+ return this;
369
+ }
370
+ update(prop, value) {
371
+ // Stack components are typically static
372
+ }
373
+ }