snow-flow 3.4.36 → 3.4.39
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/README.md +412 -287
- package/dist/cli/deploy-artifact.js +2 -2
- package/dist/mcp/servicenow-deployment-mcp.js +1 -1
- package/dist/mcp/servicenow-mcp-server.js +2 -2
- package/dist/queen/agent-factory.js +134 -52
- package/dist/queen/servicenow-queen.d.ts +127 -2
- package/dist/queen/servicenow-queen.js +978 -618
- package/dist/services/widget-deployment-service.d.ts +1 -1
- package/dist/services/widget-deployment-service.js +1 -1
- package/dist/templates/claude-md-template.d.ts +1 -1
- package/dist/templates/claude-md-template.js +2 -2
- package/dist/types/servicenow.types.d.ts +1 -1
- package/dist/utils/dependency-detector.d.ts +1 -1
- package/dist/utils/dependency-detector.js +1 -1
- package/dist/utils/servicenow-client.d.ts +1 -1
- package/dist/utils/servicenow-client.js +4 -8
- package/package.json +1 -1
- package/website/components/README.md +419 -0
- package/website/components/code-display/CodeDisplay.css +583 -0
- package/website/components/code-display/CodeDisplay.html +200 -0
- package/website/components/code-display/CodeDisplay.js +375 -0
- package/website/components/code-display/CodeDisplay.jsx +268 -0
- package/website/components/demo/ComponentLibraryDemo.html +845 -0
- package/website/components/feature-cards/FeatureCards.css +573 -0
- package/website/components/feature-cards/FeatureCards.html +247 -0
- package/website/components/feature-cards/FeatureCards.js +382 -0
- package/website/components/feature-cards/FeatureCards.jsx +235 -0
- package/website/components/hero/Hero.css +558 -0
- package/website/components/hero/Hero.html +98 -0
- package/website/components/hero/Hero.js +415 -0
- package/website/components/hero/Hero.jsx +214 -0
- package/website/components/interactive/InteractiveElements.css +776 -0
- package/website/components/interactive/InteractiveElements.html +283 -0
- package/website/components/interactive/InteractiveElements.js +489 -0
- package/website/components/interactive/InteractiveElements.jsx +444 -0
- package/website/components/layout/LayoutComponents.css +697 -0
- package/website/components/layout/LayoutComponents.html +374 -0
- package/website/components/layout/LayoutComponents.js +447 -0
- package/website/components/layout/LayoutComponents.jsx +379 -0
- package/website/components/navigation/Navigation.css +383 -0
- package/website/components/navigation/Navigation.html +89 -0
- package/website/components/navigation/Navigation.js +248 -0
- package/website/components/navigation/Navigation.jsx +124 -0
- package/website/css/animations.css +854 -0
- package/website/css/style.css +916 -948
- package/website/index.html +394 -424
- package/website/js/animations.js +707 -0
- package/website/js/main.js +310 -383
- package/website/mcp-servers.html +310 -0
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
// Snow-Flow Layout Components JavaScript
|
|
2
|
+
|
|
3
|
+
class SnowFlowLayoutComponents {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
this.config = {
|
|
6
|
+
selector: options.selector || '.sf-layout-demo',
|
|
7
|
+
|
|
8
|
+
// Feature toggles
|
|
9
|
+
enableDarkMode: options.enableDarkMode || false,
|
|
10
|
+
enableAnimations: options.enableAnimations !== false,
|
|
11
|
+
|
|
12
|
+
// State
|
|
13
|
+
darkMode: false
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
this.elements = {
|
|
17
|
+
container: document.querySelector(this.config.selector)
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
this.init();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
init() {
|
|
24
|
+
if (!this.elements.container) {
|
|
25
|
+
console.warn('SnowFlowLayoutComponents: Container not found');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
this.setupResponsiveObserver();
|
|
30
|
+
this.setupIntersectionObserver();
|
|
31
|
+
this.setupUtilities();
|
|
32
|
+
this.addDemoInteractions();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* ============================================================================
|
|
36
|
+
Responsive Observer
|
|
37
|
+
============================================================================ */
|
|
38
|
+
|
|
39
|
+
setupResponsiveObserver() {
|
|
40
|
+
// Add responsive classes based on viewport width
|
|
41
|
+
const updateResponsiveClasses = () => {
|
|
42
|
+
const width = window.innerWidth;
|
|
43
|
+
const body = document.body;
|
|
44
|
+
|
|
45
|
+
// Remove existing responsive classes
|
|
46
|
+
body.classList.remove('sf-sm', 'sf-md', 'sf-lg', 'sf-xl');
|
|
47
|
+
|
|
48
|
+
// Add appropriate responsive class
|
|
49
|
+
if (width >= 1280) {
|
|
50
|
+
body.classList.add('sf-xl');
|
|
51
|
+
} else if (width >= 1024) {
|
|
52
|
+
body.classList.add('sf-lg');
|
|
53
|
+
} else if (width >= 768) {
|
|
54
|
+
body.classList.add('sf-md');
|
|
55
|
+
} else if (width >= 640) {
|
|
56
|
+
body.classList.add('sf-sm');
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Initial call
|
|
61
|
+
updateResponsiveClasses();
|
|
62
|
+
|
|
63
|
+
// Update on resize with debouncing
|
|
64
|
+
let resizeTimeout;
|
|
65
|
+
window.addEventListener('resize', () => {
|
|
66
|
+
clearTimeout(resizeTimeout);
|
|
67
|
+
resizeTimeout = setTimeout(updateResponsiveClasses, 150);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* ============================================================================
|
|
72
|
+
Intersection Observer for Animations
|
|
73
|
+
============================================================================ */
|
|
74
|
+
|
|
75
|
+
setupIntersectionObserver() {
|
|
76
|
+
if (!this.config.enableAnimations) return;
|
|
77
|
+
|
|
78
|
+
const observerOptions = {
|
|
79
|
+
threshold: 0.1,
|
|
80
|
+
rootMargin: '0px 0px -50px 0px'
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const observer = new IntersectionObserver((entries) => {
|
|
84
|
+
entries.forEach(entry => {
|
|
85
|
+
if (entry.isIntersecting) {
|
|
86
|
+
this.animateElement(entry.target);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}, observerOptions);
|
|
90
|
+
|
|
91
|
+
// Observe all cards and sections
|
|
92
|
+
const elementsToObserve = this.elements.container.querySelectorAll(
|
|
93
|
+
'.sf-card, .sf-section, .sf-demo-title'
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
elementsToObserve.forEach(element => {
|
|
97
|
+
// Add initial state
|
|
98
|
+
element.style.opacity = '0';
|
|
99
|
+
element.style.transform = 'translateY(20px)';
|
|
100
|
+
element.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
|
|
101
|
+
|
|
102
|
+
observer.observe(element);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
animateElement(element) {
|
|
107
|
+
element.style.opacity = '1';
|
|
108
|
+
element.style.transform = 'translateY(0)';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* ============================================================================
|
|
112
|
+
Utility Functions
|
|
113
|
+
============================================================================ */
|
|
114
|
+
|
|
115
|
+
setupUtilities() {
|
|
116
|
+
// Add utility methods for dynamic class management
|
|
117
|
+
this.addUtilityMethods();
|
|
118
|
+
|
|
119
|
+
// Setup dark mode if enabled
|
|
120
|
+
if (this.config.enableDarkMode) {
|
|
121
|
+
this.setupDarkMode();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
addUtilityMethods() {
|
|
126
|
+
// Method to toggle responsive grid columns
|
|
127
|
+
window.snowFlowUtils = {
|
|
128
|
+
setGridColumns: (element, columns) => {
|
|
129
|
+
if (typeof element === 'string') {
|
|
130
|
+
element = document.querySelector(element);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (element && element.classList.contains('sf-grid')) {
|
|
134
|
+
element.style.gridTemplateColumns = typeof columns === 'number'
|
|
135
|
+
? `repeat(${columns}, 1fr)`
|
|
136
|
+
: columns;
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
setFlexDirection: (element, direction) => {
|
|
141
|
+
if (typeof element === 'string') {
|
|
142
|
+
element = document.querySelector(element);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (element && element.classList.contains('sf-flex')) {
|
|
146
|
+
element.className = element.className.replace(/sf-flex--\w+/g, '');
|
|
147
|
+
element.classList.add(`sf-flex--${direction}`);
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
toggleCardHover: (element) => {
|
|
152
|
+
if (typeof element === 'string') {
|
|
153
|
+
element = document.querySelector(element);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (element && element.classList.contains('sf-card')) {
|
|
157
|
+
element.classList.toggle('sf-card--hover');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
setupDarkMode() {
|
|
164
|
+
// Create dark mode toggle button
|
|
165
|
+
const toggleButton = document.createElement('button');
|
|
166
|
+
toggleButton.textContent = '🌙';
|
|
167
|
+
toggleButton.className = 'sf-dark-mode-toggle';
|
|
168
|
+
toggleButton.style.cssText = `
|
|
169
|
+
position: fixed;
|
|
170
|
+
top: 20px;
|
|
171
|
+
right: 20px;
|
|
172
|
+
z-index: 1000;
|
|
173
|
+
background: var(--sf-gradient-primary);
|
|
174
|
+
color: white;
|
|
175
|
+
border: none;
|
|
176
|
+
border-radius: 50%;
|
|
177
|
+
width: 50px;
|
|
178
|
+
height: 50px;
|
|
179
|
+
font-size: 1.2rem;
|
|
180
|
+
cursor: pointer;
|
|
181
|
+
box-shadow: var(--sf-shadow-lg);
|
|
182
|
+
transition: var(--sf-transition-normal);
|
|
183
|
+
`;
|
|
184
|
+
|
|
185
|
+
toggleButton.addEventListener('click', () => this.toggleDarkMode());
|
|
186
|
+
document.body.appendChild(toggleButton);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
toggleDarkMode() {
|
|
190
|
+
this.config.darkMode = !this.config.darkMode;
|
|
191
|
+
|
|
192
|
+
if (this.config.darkMode) {
|
|
193
|
+
this.elements.container.classList.add('sf-dark-mode');
|
|
194
|
+
document.querySelector('.sf-dark-mode-toggle').textContent = '☀️';
|
|
195
|
+
} else {
|
|
196
|
+
this.elements.container.classList.remove('sf-dark-mode');
|
|
197
|
+
document.querySelector('.sf-dark-mode-toggle').textContent = '🌙';
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/* ============================================================================
|
|
202
|
+
Demo Interactions
|
|
203
|
+
============================================================================ */
|
|
204
|
+
|
|
205
|
+
addDemoInteractions() {
|
|
206
|
+
// Add click handlers to demonstrate hover effects
|
|
207
|
+
const hoverCards = this.elements.container.querySelectorAll('.sf-card--hover');
|
|
208
|
+
hoverCards.forEach(card => {
|
|
209
|
+
card.addEventListener('click', () => {
|
|
210
|
+
this.showCardClickFeedback(card);
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// Add grid column adjustment demo
|
|
215
|
+
this.addGridAdjustmentDemo();
|
|
216
|
+
|
|
217
|
+
// Add responsive demonstration
|
|
218
|
+
this.addResponsiveDemo();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
showCardClickFeedback(card) {
|
|
222
|
+
const originalTransform = card.style.transform;
|
|
223
|
+
|
|
224
|
+
card.style.transform = 'scale(0.98)';
|
|
225
|
+
card.style.transition = 'transform 0.1s ease';
|
|
226
|
+
|
|
227
|
+
setTimeout(() => {
|
|
228
|
+
card.style.transform = originalTransform;
|
|
229
|
+
card.style.transition = '';
|
|
230
|
+
}, 100);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
addGridAdjustmentDemo() {
|
|
234
|
+
// Find the first responsive grid and add controls
|
|
235
|
+
const firstGrid = this.elements.container.querySelector('.sf-grid--responsive');
|
|
236
|
+
if (!firstGrid) return;
|
|
237
|
+
|
|
238
|
+
// Create control panel
|
|
239
|
+
const controls = document.createElement('div');
|
|
240
|
+
controls.className = 'sf-grid-controls';
|
|
241
|
+
controls.style.cssText = `
|
|
242
|
+
margin-top: 1rem;
|
|
243
|
+
padding: 1rem;
|
|
244
|
+
background: var(--sf-bg-secondary);
|
|
245
|
+
border-radius: var(--sf-radius-md);
|
|
246
|
+
display: flex;
|
|
247
|
+
gap: 0.5rem;
|
|
248
|
+
flex-wrap: wrap;
|
|
249
|
+
align-items: center;
|
|
250
|
+
`;
|
|
251
|
+
|
|
252
|
+
controls.innerHTML = `
|
|
253
|
+
<span style="font-weight: 600; margin-right: 0.5rem;">Grid columns:</span>
|
|
254
|
+
<button class="sf-grid-btn" data-columns="1">1</button>
|
|
255
|
+
<button class="sf-grid-btn" data-columns="2">2</button>
|
|
256
|
+
<button class="sf-grid-btn" data-columns="3">3</button>
|
|
257
|
+
<button class="sf-grid-btn" data-columns="4">4</button>
|
|
258
|
+
<button class="sf-grid-btn" data-columns="auto">Auto</button>
|
|
259
|
+
`;
|
|
260
|
+
|
|
261
|
+
// Style control buttons
|
|
262
|
+
const buttons = controls.querySelectorAll('.sf-grid-btn');
|
|
263
|
+
buttons.forEach(btn => {
|
|
264
|
+
btn.style.cssText = `
|
|
265
|
+
padding: 0.5rem 1rem;
|
|
266
|
+
border: 1px solid var(--sf-border-light);
|
|
267
|
+
background: white;
|
|
268
|
+
border-radius: var(--sf-radius-sm);
|
|
269
|
+
cursor: pointer;
|
|
270
|
+
transition: var(--sf-transition-fast);
|
|
271
|
+
`;
|
|
272
|
+
|
|
273
|
+
btn.addEventListener('click', () => {
|
|
274
|
+
const columns = btn.getAttribute('data-columns');
|
|
275
|
+
|
|
276
|
+
// Remove active class from all buttons
|
|
277
|
+
buttons.forEach(b => b.classList.remove('active'));
|
|
278
|
+
btn.classList.add('active');
|
|
279
|
+
|
|
280
|
+
// Update grid
|
|
281
|
+
if (columns === 'auto') {
|
|
282
|
+
firstGrid.style.gridTemplateColumns = 'repeat(auto-fit, minmax(250px, 1fr))';
|
|
283
|
+
} else {
|
|
284
|
+
firstGrid.style.gridTemplateColumns = `repeat(${columns}, 1fr)`;
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
btn.addEventListener('mouseenter', () => {
|
|
289
|
+
btn.style.background = 'var(--sf-bg-tertiary)';
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
btn.addEventListener('mouseleave', () => {
|
|
293
|
+
if (!btn.classList.contains('active')) {
|
|
294
|
+
btn.style.background = 'white';
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// Add active styling
|
|
300
|
+
const activeStyle = document.createElement('style');
|
|
301
|
+
activeStyle.textContent = `
|
|
302
|
+
.sf-grid-btn.active {
|
|
303
|
+
background: var(--sf-gradient-primary) !important;
|
|
304
|
+
color: white !important;
|
|
305
|
+
border-color: transparent !important;
|
|
306
|
+
}
|
|
307
|
+
`;
|
|
308
|
+
document.head.appendChild(activeStyle);
|
|
309
|
+
|
|
310
|
+
// Insert controls after the first grid
|
|
311
|
+
firstGrid.parentNode.insertBefore(controls, firstGrid.nextSibling);
|
|
312
|
+
|
|
313
|
+
// Set initial active state
|
|
314
|
+
buttons[buttons.length - 1].classList.add('active'); // Auto button
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
addResponsiveDemo() {
|
|
318
|
+
// Add a resize indicator
|
|
319
|
+
const indicator = document.createElement('div');
|
|
320
|
+
indicator.className = 'sf-responsive-indicator';
|
|
321
|
+
indicator.style.cssText = `
|
|
322
|
+
position: fixed;
|
|
323
|
+
bottom: 20px;
|
|
324
|
+
left: 20px;
|
|
325
|
+
background: var(--sf-gradient-primary);
|
|
326
|
+
color: white;
|
|
327
|
+
padding: 0.5rem 1rem;
|
|
328
|
+
border-radius: var(--sf-radius-md);
|
|
329
|
+
font-size: 0.9rem;
|
|
330
|
+
font-weight: 600;
|
|
331
|
+
z-index: 1000;
|
|
332
|
+
transition: var(--sf-transition-normal);
|
|
333
|
+
opacity: 0;
|
|
334
|
+
transform: translateY(20px);
|
|
335
|
+
`;
|
|
336
|
+
|
|
337
|
+
document.body.appendChild(indicator);
|
|
338
|
+
|
|
339
|
+
const updateIndicator = () => {
|
|
340
|
+
const width = window.innerWidth;
|
|
341
|
+
let breakpoint = 'XS';
|
|
342
|
+
|
|
343
|
+
if (width >= 1280) breakpoint = 'XL';
|
|
344
|
+
else if (width >= 1024) breakpoint = 'LG';
|
|
345
|
+
else if (width >= 768) breakpoint = 'MD';
|
|
346
|
+
else if (width >= 640) breakpoint = 'SM';
|
|
347
|
+
|
|
348
|
+
indicator.textContent = `${breakpoint}: ${width}px`;
|
|
349
|
+
indicator.style.opacity = '1';
|
|
350
|
+
indicator.style.transform = 'translateY(0)';
|
|
351
|
+
|
|
352
|
+
// Hide after 2 seconds
|
|
353
|
+
clearTimeout(indicator.hideTimeout);
|
|
354
|
+
indicator.hideTimeout = setTimeout(() => {
|
|
355
|
+
indicator.style.opacity = '0';
|
|
356
|
+
indicator.style.transform = 'translateY(20px)';
|
|
357
|
+
}, 2000);
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
// Show indicator on resize
|
|
361
|
+
window.addEventListener('resize', updateIndicator);
|
|
362
|
+
|
|
363
|
+
// Show initially
|
|
364
|
+
setTimeout(updateIndicator, 1000);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/* ============================================================================
|
|
368
|
+
Public API Methods
|
|
369
|
+
============================================================================ */
|
|
370
|
+
|
|
371
|
+
// Method to programmatically add components
|
|
372
|
+
addComponent(type, config = {}) {
|
|
373
|
+
// Factory method for creating layout components
|
|
374
|
+
const components = {
|
|
375
|
+
card: (config) => {
|
|
376
|
+
const card = document.createElement('div');
|
|
377
|
+
card.className = `sf-card sf-card--elevation-${config.elevation || 'medium'} sf-card--padding-${config.padding || 'medium'}`;
|
|
378
|
+
if (config.content) card.innerHTML = config.content;
|
|
379
|
+
return card;
|
|
380
|
+
},
|
|
381
|
+
|
|
382
|
+
container: (config) => {
|
|
383
|
+
const container = document.createElement('div');
|
|
384
|
+
container.className = `sf-container sf-container--${config.padding || 'medium'}`;
|
|
385
|
+
if (config.maxWidth) container.style.maxWidth = config.maxWidth;
|
|
386
|
+
if (config.content) container.innerHTML = config.content;
|
|
387
|
+
return container;
|
|
388
|
+
},
|
|
389
|
+
|
|
390
|
+
grid: (config) => {
|
|
391
|
+
const grid = document.createElement('div');
|
|
392
|
+
grid.className = `sf-grid sf-grid--gap-${config.gap || 'medium'}`;
|
|
393
|
+
if (config.columns) {
|
|
394
|
+
grid.style.gridTemplateColumns = typeof config.columns === 'number'
|
|
395
|
+
? `repeat(${config.columns}, 1fr)`
|
|
396
|
+
: config.columns;
|
|
397
|
+
}
|
|
398
|
+
return grid;
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
return components[type] ? components[type](config) : null;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Method to update component styles
|
|
406
|
+
updateComponent(element, styles) {
|
|
407
|
+
if (typeof element === 'string') {
|
|
408
|
+
element = document.querySelector(element);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
Object.assign(element.style, styles);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Cleanup method
|
|
415
|
+
destroy() {
|
|
416
|
+
// Remove event listeners and clean up
|
|
417
|
+
const toggleButton = document.querySelector('.sf-dark-mode-toggle');
|
|
418
|
+
if (toggleButton) {
|
|
419
|
+
toggleButton.remove();
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const indicator = document.querySelector('.sf-responsive-indicator');
|
|
423
|
+
if (indicator) {
|
|
424
|
+
indicator.remove();
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Auto-initialize on DOM content loaded
|
|
430
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
431
|
+
// Check if layout demo exists before initializing
|
|
432
|
+
const layoutDemo = document.querySelector('.sf-layout-demo');
|
|
433
|
+
if (layoutDemo) {
|
|
434
|
+
window.snowFlowLayout = new SnowFlowLayoutComponents({
|
|
435
|
+
enableDarkMode: true,
|
|
436
|
+
enableAnimations: true
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
// Export for module usage
|
|
442
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
443
|
+
module.exports = SnowFlowLayoutComponents;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Global access
|
|
447
|
+
window.SnowFlowLayoutComponents = SnowFlowLayoutComponents;
|