mithril-materialized 2.0.0-beta.5 → 2.0.0-beta.6
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/dist/advanced.css +1888 -0
- package/dist/breadcrumb.d.ts +53 -0
- package/dist/components.css +2310 -0
- package/dist/core.css +3402 -0
- package/dist/file-upload.d.ts +34 -0
- package/dist/forms.css +2284 -0
- package/dist/index.css +1262 -83
- package/dist/index.d.ts +5 -0
- package/dist/index.esm.js +864 -17
- package/dist/index.js +875 -16
- package/dist/index.min.css +2 -2
- package/dist/index.umd.js +875 -16
- package/dist/pickers.css +487 -0
- package/dist/sidenav.d.ts +76 -0
- package/dist/theme-switcher.d.ts +49 -0
- package/dist/utilities.css +3197 -0
- package/dist/wizard.d.ts +58 -0
- package/package.json +11 -5
- package/sass/components/_breadcrumb.scss +248 -0
- package/sass/components/_buttons.scss +3 -3
- package/sass/components/_collapsible.scss +8 -8
- package/sass/components/_datepicker.scss +17 -15
- package/sass/components/_file-upload.scss +228 -0
- package/sass/components/_global.scss +7 -5
- package/sass/components/_modal.scss +5 -2
- package/sass/components/_navbar.scss +13 -5
- package/sass/components/_sidenav.scss +164 -7
- package/sass/components/_tabs.scss +5 -4
- package/sass/components/_theme-switcher.scss +120 -0
- package/sass/components/_theme-variables.scss +187 -0
- package/sass/components/_timepicker.scss +5 -5
- package/sass/components/_wizard.scss +416 -0
- package/sass/components/forms/_input-fields.scss +34 -12
- package/sass/components/forms/_radio-buttons.scss +10 -10
- package/sass/components/forms/_switches.scss +6 -6
- package/sass/materialize.scss +7 -0
package/dist/index.esm.js
CHANGED
|
@@ -1158,23 +1158,8 @@ const CollapsibleItem = () => {
|
|
|
1158
1158
|
header || iconName
|
|
1159
1159
|
? m('.collapsible-header', {
|
|
1160
1160
|
onclick: onToggle,
|
|
1161
|
-
style: {
|
|
1162
|
-
cursor: 'pointer',
|
|
1163
|
-
padding: '1rem',
|
|
1164
|
-
backgroundColor: '#fff',
|
|
1165
|
-
borderBottom: '1px solid #ddd',
|
|
1166
|
-
display: 'flex',
|
|
1167
|
-
alignItems: 'center',
|
|
1168
|
-
transition: 'background-color 0.2s ease',
|
|
1169
|
-
},
|
|
1170
|
-
onmouseover: (e) => {
|
|
1171
|
-
e.target.style.backgroundColor = '#f5f5f5';
|
|
1172
|
-
},
|
|
1173
|
-
onmouseleave: (e) => {
|
|
1174
|
-
e.target.style.backgroundColor = '#fff';
|
|
1175
|
-
},
|
|
1176
1161
|
}, [
|
|
1177
|
-
iconName ? m('i.material-icons',
|
|
1162
|
+
iconName ? m('i.material-icons', iconName) : undefined,
|
|
1178
1163
|
header ? (typeof header === 'string' ? m('span', header) : header) : undefined,
|
|
1179
1164
|
])
|
|
1180
1165
|
: undefined,
|
|
@@ -5339,4 +5324,866 @@ const initTooltips = (selector = '[data-tooltip]', options = {}) => {
|
|
|
5339
5324
|
return tooltips;
|
|
5340
5325
|
};
|
|
5341
5326
|
|
|
5342
|
-
|
|
5327
|
+
/**
|
|
5328
|
+
* Theme switching utilities and component
|
|
5329
|
+
*/
|
|
5330
|
+
class ThemeManager {
|
|
5331
|
+
/**
|
|
5332
|
+
* Set the theme for the entire application
|
|
5333
|
+
*/
|
|
5334
|
+
static setTheme(theme) {
|
|
5335
|
+
this.currentTheme = theme;
|
|
5336
|
+
const root = document.documentElement;
|
|
5337
|
+
if (theme === 'auto') {
|
|
5338
|
+
// Remove explicit theme, let CSS media query handle it
|
|
5339
|
+
root.removeAttribute('data-theme');
|
|
5340
|
+
}
|
|
5341
|
+
else {
|
|
5342
|
+
// Set explicit theme
|
|
5343
|
+
root.setAttribute('data-theme', theme);
|
|
5344
|
+
}
|
|
5345
|
+
// Store preference in localStorage
|
|
5346
|
+
try {
|
|
5347
|
+
localStorage.setItem('mm-theme', theme);
|
|
5348
|
+
}
|
|
5349
|
+
catch (e) {
|
|
5350
|
+
// localStorage might not be available
|
|
5351
|
+
}
|
|
5352
|
+
}
|
|
5353
|
+
/**
|
|
5354
|
+
* Get the current theme
|
|
5355
|
+
*/
|
|
5356
|
+
static getTheme() {
|
|
5357
|
+
return this.currentTheme;
|
|
5358
|
+
}
|
|
5359
|
+
/**
|
|
5360
|
+
* Get the effective theme (resolves 'auto' to actual theme)
|
|
5361
|
+
*/
|
|
5362
|
+
static getEffectiveTheme() {
|
|
5363
|
+
if (this.currentTheme !== 'auto') {
|
|
5364
|
+
return this.currentTheme;
|
|
5365
|
+
}
|
|
5366
|
+
// Check CSS media query for auto mode
|
|
5367
|
+
if (typeof window !== 'undefined' && window.matchMedia) {
|
|
5368
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
5369
|
+
}
|
|
5370
|
+
return 'light';
|
|
5371
|
+
}
|
|
5372
|
+
/**
|
|
5373
|
+
* Initialize theme from localStorage or system preference
|
|
5374
|
+
*/
|
|
5375
|
+
static initialize() {
|
|
5376
|
+
let savedTheme = 'auto';
|
|
5377
|
+
try {
|
|
5378
|
+
const stored = localStorage.getItem('mm-theme');
|
|
5379
|
+
if (stored && ['light', 'dark', 'auto'].includes(stored)) {
|
|
5380
|
+
savedTheme = stored;
|
|
5381
|
+
}
|
|
5382
|
+
}
|
|
5383
|
+
catch (e) {
|
|
5384
|
+
// localStorage might not be available
|
|
5385
|
+
}
|
|
5386
|
+
this.setTheme(savedTheme);
|
|
5387
|
+
}
|
|
5388
|
+
/**
|
|
5389
|
+
* Toggle between light and dark themes
|
|
5390
|
+
*/
|
|
5391
|
+
static toggle() {
|
|
5392
|
+
const current = this.getEffectiveTheme();
|
|
5393
|
+
this.setTheme(current === 'light' ? 'dark' : 'light');
|
|
5394
|
+
}
|
|
5395
|
+
}
|
|
5396
|
+
ThemeManager.currentTheme = 'auto';
|
|
5397
|
+
/**
|
|
5398
|
+
* Theme Switcher Component
|
|
5399
|
+
* Provides UI controls for changing themes
|
|
5400
|
+
*/
|
|
5401
|
+
const ThemeSwitcher = () => {
|
|
5402
|
+
return {
|
|
5403
|
+
oninit: () => {
|
|
5404
|
+
// Initialize theme manager if not already done
|
|
5405
|
+
if (typeof window !== 'undefined') {
|
|
5406
|
+
ThemeManager.initialize();
|
|
5407
|
+
}
|
|
5408
|
+
},
|
|
5409
|
+
view: ({ attrs }) => {
|
|
5410
|
+
const { theme = ThemeManager.getTheme(), onThemeChange, showLabels = true, className = '' } = attrs;
|
|
5411
|
+
const handleThemeChange = (newTheme) => {
|
|
5412
|
+
ThemeManager.setTheme(newTheme);
|
|
5413
|
+
if (onThemeChange) {
|
|
5414
|
+
onThemeChange(newTheme);
|
|
5415
|
+
}
|
|
5416
|
+
};
|
|
5417
|
+
return m('.theme-switcher', { class: className }, [
|
|
5418
|
+
showLabels && m('span.theme-switcher-label', 'Theme:'),
|
|
5419
|
+
m('.theme-switcher-buttons', [
|
|
5420
|
+
m('button.btn-flat', {
|
|
5421
|
+
class: theme === 'light' ? 'active' : '',
|
|
5422
|
+
onclick: () => handleThemeChange('light'),
|
|
5423
|
+
title: 'Light theme'
|
|
5424
|
+
}, [
|
|
5425
|
+
m('i.material-icons', 'light_mode'),
|
|
5426
|
+
showLabels && m('span', 'Light')
|
|
5427
|
+
]),
|
|
5428
|
+
m('button.btn-flat', {
|
|
5429
|
+
class: theme === 'auto' ? 'active' : '',
|
|
5430
|
+
onclick: () => handleThemeChange('auto'),
|
|
5431
|
+
title: 'Auto theme (system preference)'
|
|
5432
|
+
}, [
|
|
5433
|
+
m('i.material-icons', 'brightness_auto'),
|
|
5434
|
+
showLabels && m('span', 'Auto')
|
|
5435
|
+
]),
|
|
5436
|
+
m('button.btn-flat', {
|
|
5437
|
+
class: theme === 'dark' ? 'active' : '',
|
|
5438
|
+
onclick: () => handleThemeChange('dark'),
|
|
5439
|
+
title: 'Dark theme'
|
|
5440
|
+
}, [
|
|
5441
|
+
m('i.material-icons', 'dark_mode'),
|
|
5442
|
+
showLabels && m('span', 'Dark')
|
|
5443
|
+
])
|
|
5444
|
+
])
|
|
5445
|
+
]);
|
|
5446
|
+
}
|
|
5447
|
+
};
|
|
5448
|
+
};
|
|
5449
|
+
/**
|
|
5450
|
+
* Simple theme toggle button (just switches between light/dark)
|
|
5451
|
+
*/
|
|
5452
|
+
const ThemeToggle = () => {
|
|
5453
|
+
return {
|
|
5454
|
+
oninit: () => {
|
|
5455
|
+
// Initialize theme manager if not already done
|
|
5456
|
+
if (typeof window !== 'undefined') {
|
|
5457
|
+
ThemeManager.initialize();
|
|
5458
|
+
}
|
|
5459
|
+
},
|
|
5460
|
+
view: ({ attrs }) => {
|
|
5461
|
+
const currentTheme = ThemeManager.getEffectiveTheme();
|
|
5462
|
+
return m('button.btn-flat.theme-toggle', {
|
|
5463
|
+
class: attrs.className || '',
|
|
5464
|
+
onclick: () => {
|
|
5465
|
+
ThemeManager.toggle();
|
|
5466
|
+
m.redraw();
|
|
5467
|
+
},
|
|
5468
|
+
title: `Switch to ${currentTheme === 'light' ? 'dark' : 'light'} theme`,
|
|
5469
|
+
style: 'margin: 0; height: 64px; line-height: 64px; border-radius: 0; min-width: 64px; padding: 0;'
|
|
5470
|
+
}, [
|
|
5471
|
+
m('i.material-icons', {
|
|
5472
|
+
style: 'color: inherit; font-size: 24px;'
|
|
5473
|
+
}, currentTheme === 'light' ? 'dark_mode' : 'light_mode')
|
|
5474
|
+
]);
|
|
5475
|
+
}
|
|
5476
|
+
};
|
|
5477
|
+
};
|
|
5478
|
+
|
|
5479
|
+
/**
|
|
5480
|
+
* File Upload Component with Drag and Drop
|
|
5481
|
+
* Supports multiple files, file type validation, size limits, and image preview
|
|
5482
|
+
*/
|
|
5483
|
+
const FileUpload = () => {
|
|
5484
|
+
let state;
|
|
5485
|
+
const validateFile = (file, attrs) => {
|
|
5486
|
+
// Check file size
|
|
5487
|
+
if (attrs.maxSize && file.size > attrs.maxSize) {
|
|
5488
|
+
const maxSizeMB = (attrs.maxSize / (1024 * 1024)).toFixed(1);
|
|
5489
|
+
return `File size exceeds ${maxSizeMB}MB limit`;
|
|
5490
|
+
}
|
|
5491
|
+
// Check file type
|
|
5492
|
+
if (attrs.accept) {
|
|
5493
|
+
const acceptedTypes = attrs.accept.split(',').map(type => type.trim());
|
|
5494
|
+
const isAccepted = acceptedTypes.some(acceptedType => {
|
|
5495
|
+
if (acceptedType.startsWith('.')) {
|
|
5496
|
+
// Extension check
|
|
5497
|
+
return file.name.toLowerCase().endsWith(acceptedType.toLowerCase());
|
|
5498
|
+
}
|
|
5499
|
+
else {
|
|
5500
|
+
// MIME type check
|
|
5501
|
+
return file.type.match(acceptedType.replace('*', '.*'));
|
|
5502
|
+
}
|
|
5503
|
+
});
|
|
5504
|
+
if (!isAccepted) {
|
|
5505
|
+
return `File type not accepted. Accepted: ${attrs.accept}`;
|
|
5506
|
+
}
|
|
5507
|
+
}
|
|
5508
|
+
return null;
|
|
5509
|
+
};
|
|
5510
|
+
const createFilePreview = (file) => {
|
|
5511
|
+
if (file.type.startsWith('image/')) {
|
|
5512
|
+
const reader = new FileReader();
|
|
5513
|
+
reader.onload = (e) => {
|
|
5514
|
+
var _a;
|
|
5515
|
+
file.preview = (_a = e.target) === null || _a === void 0 ? void 0 : _a.result;
|
|
5516
|
+
m.redraw();
|
|
5517
|
+
};
|
|
5518
|
+
reader.readAsDataURL(file);
|
|
5519
|
+
}
|
|
5520
|
+
};
|
|
5521
|
+
const handleFiles = (fileList, attrs) => {
|
|
5522
|
+
const newFiles = Array.from(fileList);
|
|
5523
|
+
const validFiles = [];
|
|
5524
|
+
// Validate each file
|
|
5525
|
+
for (const file of newFiles) {
|
|
5526
|
+
const error = validateFile(file, attrs);
|
|
5527
|
+
if (error) {
|
|
5528
|
+
file.uploadError = error;
|
|
5529
|
+
}
|
|
5530
|
+
else {
|
|
5531
|
+
validFiles.push(file);
|
|
5532
|
+
if (attrs.showPreview) {
|
|
5533
|
+
createFilePreview(file);
|
|
5534
|
+
}
|
|
5535
|
+
}
|
|
5536
|
+
}
|
|
5537
|
+
// Check max files limit
|
|
5538
|
+
if (attrs.maxFiles) {
|
|
5539
|
+
const totalFiles = state.files.length + validFiles.length;
|
|
5540
|
+
if (totalFiles > attrs.maxFiles) {
|
|
5541
|
+
const allowedCount = attrs.maxFiles - state.files.length;
|
|
5542
|
+
validFiles.splice(allowedCount);
|
|
5543
|
+
}
|
|
5544
|
+
}
|
|
5545
|
+
// Add valid files to state
|
|
5546
|
+
if (attrs.multiple) {
|
|
5547
|
+
state.files = [...state.files, ...validFiles];
|
|
5548
|
+
}
|
|
5549
|
+
else {
|
|
5550
|
+
state.files = validFiles.slice(0, 1);
|
|
5551
|
+
}
|
|
5552
|
+
// Notify parent component
|
|
5553
|
+
if (attrs.onFilesSelected) {
|
|
5554
|
+
attrs.onFilesSelected(state.files.filter(f => !f.uploadError));
|
|
5555
|
+
}
|
|
5556
|
+
};
|
|
5557
|
+
const removeFile = (fileToRemove, attrs) => {
|
|
5558
|
+
state.files = state.files.filter(file => file !== fileToRemove);
|
|
5559
|
+
if (attrs.onFileRemoved) {
|
|
5560
|
+
attrs.onFileRemoved(fileToRemove);
|
|
5561
|
+
}
|
|
5562
|
+
};
|
|
5563
|
+
const formatFileSize = (bytes) => {
|
|
5564
|
+
if (bytes === 0)
|
|
5565
|
+
return '0 B';
|
|
5566
|
+
const k = 1024;
|
|
5567
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
5568
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
5569
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
|
|
5570
|
+
};
|
|
5571
|
+
return {
|
|
5572
|
+
oninit: () => {
|
|
5573
|
+
state = {
|
|
5574
|
+
id: uniqueId(),
|
|
5575
|
+
files: [],
|
|
5576
|
+
isDragOver: false,
|
|
5577
|
+
isUploading: false
|
|
5578
|
+
};
|
|
5579
|
+
},
|
|
5580
|
+
view: ({ attrs }) => {
|
|
5581
|
+
const { accept, multiple = false, disabled = false, label = 'Choose files or drag them here', helperText, showPreview = true, className = '', error } = attrs;
|
|
5582
|
+
return m('.file-upload-container', { class: className }, [
|
|
5583
|
+
// Upload area
|
|
5584
|
+
m('.file-upload-area', {
|
|
5585
|
+
class: [
|
|
5586
|
+
state.isDragOver ? 'drag-over' : '',
|
|
5587
|
+
disabled ? 'disabled' : '',
|
|
5588
|
+
error ? 'error' : '',
|
|
5589
|
+
state.files.length > 0 ? 'has-files' : ''
|
|
5590
|
+
].filter(Boolean).join(' '),
|
|
5591
|
+
ondragover: (e) => {
|
|
5592
|
+
if (disabled)
|
|
5593
|
+
return;
|
|
5594
|
+
e.preventDefault();
|
|
5595
|
+
e.stopPropagation();
|
|
5596
|
+
state.isDragOver = true;
|
|
5597
|
+
},
|
|
5598
|
+
ondragleave: (e) => {
|
|
5599
|
+
if (disabled)
|
|
5600
|
+
return;
|
|
5601
|
+
e.preventDefault();
|
|
5602
|
+
e.stopPropagation();
|
|
5603
|
+
state.isDragOver = false;
|
|
5604
|
+
},
|
|
5605
|
+
ondrop: (e) => {
|
|
5606
|
+
var _a;
|
|
5607
|
+
if (disabled)
|
|
5608
|
+
return;
|
|
5609
|
+
e.preventDefault();
|
|
5610
|
+
e.stopPropagation();
|
|
5611
|
+
state.isDragOver = false;
|
|
5612
|
+
if ((_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files) {
|
|
5613
|
+
handleFiles(e.dataTransfer.files, attrs);
|
|
5614
|
+
}
|
|
5615
|
+
},
|
|
5616
|
+
onclick: () => {
|
|
5617
|
+
if (disabled)
|
|
5618
|
+
return;
|
|
5619
|
+
const input = document.getElementById(state.id);
|
|
5620
|
+
input === null || input === void 0 ? void 0 : input.click();
|
|
5621
|
+
}
|
|
5622
|
+
}, [
|
|
5623
|
+
m('input[type="file"]', {
|
|
5624
|
+
id: state.id,
|
|
5625
|
+
accept,
|
|
5626
|
+
multiple,
|
|
5627
|
+
disabled,
|
|
5628
|
+
style: { display: 'none' },
|
|
5629
|
+
onchange: (e) => {
|
|
5630
|
+
const target = e.target;
|
|
5631
|
+
if (target.files) {
|
|
5632
|
+
handleFiles(target.files, attrs);
|
|
5633
|
+
}
|
|
5634
|
+
}
|
|
5635
|
+
}),
|
|
5636
|
+
m('.file-upload-content', [
|
|
5637
|
+
m('i.material-icons.file-upload-icon', 'cloud_upload'),
|
|
5638
|
+
m('p.file-upload-label', label),
|
|
5639
|
+
helperText && m('p.file-upload-helper', helperText),
|
|
5640
|
+
accept && m('p.file-upload-types', `Accepted: ${accept}`)
|
|
5641
|
+
])
|
|
5642
|
+
]),
|
|
5643
|
+
// Error message
|
|
5644
|
+
error && m('.file-upload-error', error),
|
|
5645
|
+
// File list
|
|
5646
|
+
state.files.length > 0 && m('.file-upload-list', [
|
|
5647
|
+
m('h6', 'Selected Files:'),
|
|
5648
|
+
state.files.map(file => m('.file-upload-item', { key: file.name + file.size }, [
|
|
5649
|
+
// Preview thumbnail
|
|
5650
|
+
showPreview && file.preview && m('.file-preview', [
|
|
5651
|
+
m('img', { src: file.preview, alt: file.name })
|
|
5652
|
+
]),
|
|
5653
|
+
// File info
|
|
5654
|
+
m('.file-info', [
|
|
5655
|
+
m('.file-name', file.name),
|
|
5656
|
+
m('.file-details', [
|
|
5657
|
+
m('span.file-size', formatFileSize(file.size)),
|
|
5658
|
+
file.type && m('span.file-type', file.type)
|
|
5659
|
+
]),
|
|
5660
|
+
// Progress bar (if uploading)
|
|
5661
|
+
file.uploadProgress !== undefined && m('.file-progress', [
|
|
5662
|
+
m('.progress', [
|
|
5663
|
+
m('.determinate', {
|
|
5664
|
+
style: { width: `${file.uploadProgress}%` }
|
|
5665
|
+
})
|
|
5666
|
+
])
|
|
5667
|
+
]),
|
|
5668
|
+
// Error message
|
|
5669
|
+
file.uploadError && m('.file-error', file.uploadError)
|
|
5670
|
+
]),
|
|
5671
|
+
// Remove button
|
|
5672
|
+
m('button.btn-flat.file-remove', {
|
|
5673
|
+
onclick: (e) => {
|
|
5674
|
+
e.stopPropagation();
|
|
5675
|
+
removeFile(file, attrs);
|
|
5676
|
+
},
|
|
5677
|
+
title: 'Remove file'
|
|
5678
|
+
}, [
|
|
5679
|
+
m('i.material-icons', 'close')
|
|
5680
|
+
])
|
|
5681
|
+
]))
|
|
5682
|
+
])
|
|
5683
|
+
]);
|
|
5684
|
+
}
|
|
5685
|
+
};
|
|
5686
|
+
};
|
|
5687
|
+
|
|
5688
|
+
/**
|
|
5689
|
+
* Sidenav Component
|
|
5690
|
+
* A responsive navigation drawer that slides in from the side
|
|
5691
|
+
*/
|
|
5692
|
+
const Sidenav = () => {
|
|
5693
|
+
let state;
|
|
5694
|
+
const handleBackdropClick = (attrs) => {
|
|
5695
|
+
if (attrs.closeOnBackdropClick !== false && attrs.onToggle) {
|
|
5696
|
+
attrs.onToggle(false);
|
|
5697
|
+
}
|
|
5698
|
+
};
|
|
5699
|
+
const handleEscapeKey = (e, attrs) => {
|
|
5700
|
+
if (e.key === 'Escape' && attrs.closeOnEscape !== false && attrs.onToggle) {
|
|
5701
|
+
attrs.onToggle(false);
|
|
5702
|
+
}
|
|
5703
|
+
};
|
|
5704
|
+
const setBodyOverflow = (isOpen, mode) => {
|
|
5705
|
+
if (typeof document !== 'undefined') {
|
|
5706
|
+
document.body.style.overflow = isOpen && mode === 'overlay' ? 'hidden' : '';
|
|
5707
|
+
}
|
|
5708
|
+
};
|
|
5709
|
+
return {
|
|
5710
|
+
oninit: ({ attrs }) => {
|
|
5711
|
+
state = {
|
|
5712
|
+
id: attrs.id || uniqueId(),
|
|
5713
|
+
isOpen: attrs.isOpen || false,
|
|
5714
|
+
isAnimating: false
|
|
5715
|
+
};
|
|
5716
|
+
// Set up keyboard listener
|
|
5717
|
+
if (typeof document !== 'undefined' && attrs.closeOnEscape !== false) {
|
|
5718
|
+
document.addEventListener('keydown', (e) => handleEscapeKey(e, attrs));
|
|
5719
|
+
}
|
|
5720
|
+
},
|
|
5721
|
+
onbeforeupdate: ({ attrs }) => {
|
|
5722
|
+
const wasOpen = state.isOpen;
|
|
5723
|
+
const isOpen = attrs.isOpen || false;
|
|
5724
|
+
if (wasOpen !== isOpen) {
|
|
5725
|
+
state.isOpen = isOpen;
|
|
5726
|
+
state.isAnimating = true;
|
|
5727
|
+
setBodyOverflow(isOpen, attrs.mode || 'overlay');
|
|
5728
|
+
// Clear animation state after animation completes
|
|
5729
|
+
setTimeout(() => {
|
|
5730
|
+
state.isAnimating = false;
|
|
5731
|
+
m.redraw();
|
|
5732
|
+
}, attrs.animationDuration || 300);
|
|
5733
|
+
}
|
|
5734
|
+
},
|
|
5735
|
+
onremove: ({ attrs }) => {
|
|
5736
|
+
// Clean up
|
|
5737
|
+
setBodyOverflow(false, attrs.mode || 'overlay');
|
|
5738
|
+
if (typeof document !== 'undefined' && attrs.closeOnEscape !== false) {
|
|
5739
|
+
document.removeEventListener('keydown', (e) => handleEscapeKey(e, attrs));
|
|
5740
|
+
}
|
|
5741
|
+
},
|
|
5742
|
+
view: ({ attrs, children }) => {
|
|
5743
|
+
const { position = 'left', mode = 'overlay', width = 300, className = '', showBackdrop = true, animationDuration = 300, fixed = false } = attrs;
|
|
5744
|
+
const isOpen = state.isOpen;
|
|
5745
|
+
return [
|
|
5746
|
+
// Backdrop (using existing materialize class)
|
|
5747
|
+
showBackdrop && mode === 'overlay' && m('.sidenav-overlay', {
|
|
5748
|
+
style: {
|
|
5749
|
+
display: isOpen ? 'block' : 'none',
|
|
5750
|
+
opacity: isOpen ? '1' : '0'
|
|
5751
|
+
},
|
|
5752
|
+
onclick: () => handleBackdropClick(attrs)
|
|
5753
|
+
}),
|
|
5754
|
+
// Sidenav (using existing materialize structure)
|
|
5755
|
+
m('ul.sidenav', {
|
|
5756
|
+
id: state.id,
|
|
5757
|
+
class: [
|
|
5758
|
+
position === 'right' ? 'right-aligned' : '',
|
|
5759
|
+
fixed ? 'sidenav-fixed' : '',
|
|
5760
|
+
className
|
|
5761
|
+
].filter(Boolean).join(' '),
|
|
5762
|
+
style: {
|
|
5763
|
+
width: `${width}px`,
|
|
5764
|
+
transform: isOpen ? 'translateX(0)' :
|
|
5765
|
+
position === 'left' ? 'translateX(-105%)' : 'translateX(105%)',
|
|
5766
|
+
'transition-duration': `${animationDuration}ms`
|
|
5767
|
+
}
|
|
5768
|
+
}, children)
|
|
5769
|
+
];
|
|
5770
|
+
}
|
|
5771
|
+
};
|
|
5772
|
+
};
|
|
5773
|
+
/**
|
|
5774
|
+
* Sidenav Item Component
|
|
5775
|
+
* Individual items for the sidenav menu
|
|
5776
|
+
*/
|
|
5777
|
+
const SidenavItem = () => {
|
|
5778
|
+
return {
|
|
5779
|
+
view: ({ attrs, children }) => {
|
|
5780
|
+
const { text, icon, active = false, disabled = false, onclick, href, className = '', divider = false, subheader = false } = attrs;
|
|
5781
|
+
if (divider) {
|
|
5782
|
+
return m('li.divider');
|
|
5783
|
+
}
|
|
5784
|
+
if (subheader) {
|
|
5785
|
+
return m('li.subheader', text || children);
|
|
5786
|
+
}
|
|
5787
|
+
const itemClasses = [
|
|
5788
|
+
active ? 'active' : '',
|
|
5789
|
+
disabled ? 'disabled' : '',
|
|
5790
|
+
className
|
|
5791
|
+
].filter(Boolean).join(' ');
|
|
5792
|
+
const content = [
|
|
5793
|
+
icon && m('i.material-icons', icon),
|
|
5794
|
+
text || children
|
|
5795
|
+
];
|
|
5796
|
+
if (href && !disabled) {
|
|
5797
|
+
return m('li', { class: itemClasses }, [
|
|
5798
|
+
m('a', {
|
|
5799
|
+
href,
|
|
5800
|
+
onclick: disabled ? undefined : onclick
|
|
5801
|
+
}, content)
|
|
5802
|
+
]);
|
|
5803
|
+
}
|
|
5804
|
+
return m('li', { class: itemClasses }, [
|
|
5805
|
+
m('a', {
|
|
5806
|
+
onclick: disabled ? undefined : onclick,
|
|
5807
|
+
href: '#!'
|
|
5808
|
+
}, content)
|
|
5809
|
+
]);
|
|
5810
|
+
}
|
|
5811
|
+
};
|
|
5812
|
+
};
|
|
5813
|
+
/**
|
|
5814
|
+
* Sidenav utilities for programmatic control
|
|
5815
|
+
*/
|
|
5816
|
+
class SidenavManager {
|
|
5817
|
+
/**
|
|
5818
|
+
* Open a sidenav by ID
|
|
5819
|
+
*/
|
|
5820
|
+
static open(id) {
|
|
5821
|
+
const element = document.getElementById(id);
|
|
5822
|
+
if (element) {
|
|
5823
|
+
element.classList.add('open');
|
|
5824
|
+
element.classList.remove('closed');
|
|
5825
|
+
}
|
|
5826
|
+
}
|
|
5827
|
+
/**
|
|
5828
|
+
* Close a sidenav by ID
|
|
5829
|
+
*/
|
|
5830
|
+
static close(id) {
|
|
5831
|
+
const element = document.getElementById(id);
|
|
5832
|
+
if (element) {
|
|
5833
|
+
element.classList.remove('open');
|
|
5834
|
+
element.classList.add('closed');
|
|
5835
|
+
}
|
|
5836
|
+
}
|
|
5837
|
+
/**
|
|
5838
|
+
* Toggle a sidenav by ID
|
|
5839
|
+
*/
|
|
5840
|
+
static toggle(id) {
|
|
5841
|
+
const element = document.getElementById(id);
|
|
5842
|
+
if (element) {
|
|
5843
|
+
const isOpen = element.classList.contains('open');
|
|
5844
|
+
if (isOpen) {
|
|
5845
|
+
this.close(id);
|
|
5846
|
+
}
|
|
5847
|
+
else {
|
|
5848
|
+
this.open(id);
|
|
5849
|
+
}
|
|
5850
|
+
}
|
|
5851
|
+
}
|
|
5852
|
+
}
|
|
5853
|
+
|
|
5854
|
+
/**
|
|
5855
|
+
* Breadcrumb Component
|
|
5856
|
+
* Displays a navigation path showing the user's location within a site hierarchy
|
|
5857
|
+
*/
|
|
5858
|
+
const Breadcrumb = () => {
|
|
5859
|
+
return {
|
|
5860
|
+
view: ({ attrs }) => {
|
|
5861
|
+
const { items = [], separator = 'chevron_right', className = '', showIcons = false, maxItems, showHome = false } = attrs;
|
|
5862
|
+
if (items.length === 0) {
|
|
5863
|
+
return null;
|
|
5864
|
+
}
|
|
5865
|
+
let displayItems = [...items];
|
|
5866
|
+
// Handle max items with ellipsis
|
|
5867
|
+
if (maxItems && items.length > maxItems) {
|
|
5868
|
+
const firstItem = items[0];
|
|
5869
|
+
const lastItems = items.slice(-(maxItems - 2));
|
|
5870
|
+
displayItems = [
|
|
5871
|
+
firstItem,
|
|
5872
|
+
{ text: '...', disabled: true, className: 'breadcrumb-ellipsis' },
|
|
5873
|
+
...lastItems
|
|
5874
|
+
];
|
|
5875
|
+
}
|
|
5876
|
+
return m('nav.breadcrumb', { class: className }, [
|
|
5877
|
+
m('ol.breadcrumb-list', displayItems.map((item, index) => {
|
|
5878
|
+
const isLast = index === displayItems.length - 1;
|
|
5879
|
+
const isFirst = index === 0;
|
|
5880
|
+
return [
|
|
5881
|
+
// Breadcrumb item
|
|
5882
|
+
m('li.breadcrumb-item', {
|
|
5883
|
+
class: [
|
|
5884
|
+
item.active || isLast ? 'active' : '',
|
|
5885
|
+
item.disabled ? 'disabled' : '',
|
|
5886
|
+
item.className || ''
|
|
5887
|
+
].filter(Boolean).join(' ')
|
|
5888
|
+
}, [
|
|
5889
|
+
item.href && !item.disabled && !isLast ?
|
|
5890
|
+
// Link item
|
|
5891
|
+
m('a.breadcrumb-link', {
|
|
5892
|
+
href: item.href,
|
|
5893
|
+
onclick: item.onclick
|
|
5894
|
+
}, [
|
|
5895
|
+
(showIcons && item.icon) && m('i.material-icons.breadcrumb-icon', item.icon),
|
|
5896
|
+
(showHome && isFirst && !item.icon) && m('i.material-icons.breadcrumb-icon', 'home'),
|
|
5897
|
+
m('span.breadcrumb-text', item.text)
|
|
5898
|
+
]) :
|
|
5899
|
+
// Text item (active or disabled)
|
|
5900
|
+
m('span.breadcrumb-text', {
|
|
5901
|
+
onclick: item.disabled ? undefined : item.onclick
|
|
5902
|
+
}, [
|
|
5903
|
+
(showIcons && item.icon) && m('i.material-icons.breadcrumb-icon', item.icon),
|
|
5904
|
+
(showHome && isFirst && !item.icon) && m('i.material-icons.breadcrumb-icon', 'home'),
|
|
5905
|
+
item.text
|
|
5906
|
+
])
|
|
5907
|
+
]),
|
|
5908
|
+
// Separator (except for last item)
|
|
5909
|
+
!isLast && m('li.breadcrumb-separator', [
|
|
5910
|
+
m('i.material-icons', separator)
|
|
5911
|
+
])
|
|
5912
|
+
];
|
|
5913
|
+
}).reduce((acc, val) => acc.concat(val), []))
|
|
5914
|
+
]);
|
|
5915
|
+
}
|
|
5916
|
+
};
|
|
5917
|
+
};
|
|
5918
|
+
/**
|
|
5919
|
+
* Simple Breadcrumb utility for common use cases
|
|
5920
|
+
*/
|
|
5921
|
+
const createBreadcrumb = (path, basePath = '/') => {
|
|
5922
|
+
const segments = path.split('/').filter(Boolean);
|
|
5923
|
+
const items = [];
|
|
5924
|
+
// Add home item
|
|
5925
|
+
items.push({
|
|
5926
|
+
text: 'Home',
|
|
5927
|
+
href: basePath,
|
|
5928
|
+
icon: 'home'
|
|
5929
|
+
});
|
|
5930
|
+
// Add path segments
|
|
5931
|
+
let currentPath = basePath;
|
|
5932
|
+
segments.forEach((segment, index) => {
|
|
5933
|
+
currentPath += (currentPath.endsWith('/') ? '' : '/') + segment;
|
|
5934
|
+
const isLast = index === segments.length - 1;
|
|
5935
|
+
items.push({
|
|
5936
|
+
text: segment.charAt(0).toUpperCase() + segment.slice(1).replace(/-/g, ' '),
|
|
5937
|
+
href: isLast ? undefined : currentPath,
|
|
5938
|
+
active: isLast
|
|
5939
|
+
});
|
|
5940
|
+
});
|
|
5941
|
+
return items;
|
|
5942
|
+
};
|
|
5943
|
+
/**
|
|
5944
|
+
* Breadcrumb utilities
|
|
5945
|
+
*/
|
|
5946
|
+
class BreadcrumbManager {
|
|
5947
|
+
/**
|
|
5948
|
+
* Create breadcrumb items from a route path
|
|
5949
|
+
*/
|
|
5950
|
+
static fromRoute(route, routeConfig = {}) {
|
|
5951
|
+
const segments = route.split('/').filter(Boolean);
|
|
5952
|
+
const items = [];
|
|
5953
|
+
// Add home
|
|
5954
|
+
items.push({
|
|
5955
|
+
text: 'Home',
|
|
5956
|
+
href: '/',
|
|
5957
|
+
icon: 'home'
|
|
5958
|
+
});
|
|
5959
|
+
let currentPath = '';
|
|
5960
|
+
segments.forEach((segment, index) => {
|
|
5961
|
+
currentPath += '/' + segment;
|
|
5962
|
+
const isLast = index === segments.length - 1;
|
|
5963
|
+
// Use custom text from config or format segment
|
|
5964
|
+
const text = routeConfig[currentPath] ||
|
|
5965
|
+
segment.charAt(0).toUpperCase() + segment.slice(1).replace(/-/g, ' ');
|
|
5966
|
+
items.push({
|
|
5967
|
+
text,
|
|
5968
|
+
href: isLast ? undefined : currentPath,
|
|
5969
|
+
active: isLast
|
|
5970
|
+
});
|
|
5971
|
+
});
|
|
5972
|
+
return items;
|
|
5973
|
+
}
|
|
5974
|
+
/**
|
|
5975
|
+
* Create breadcrumb items from a hierarchical object
|
|
5976
|
+
*/
|
|
5977
|
+
static fromHierarchy(hierarchy, textKey = 'name', pathKey = 'path') {
|
|
5978
|
+
return hierarchy.map((item, index) => ({
|
|
5979
|
+
text: item[textKey],
|
|
5980
|
+
href: index === hierarchy.length - 1 ? undefined : item[pathKey],
|
|
5981
|
+
active: index === hierarchy.length - 1
|
|
5982
|
+
}));
|
|
5983
|
+
}
|
|
5984
|
+
}
|
|
5985
|
+
|
|
5986
|
+
/**
|
|
5987
|
+
* Wizard/Stepper Component
|
|
5988
|
+
* A multi-step interface for guiding users through a process
|
|
5989
|
+
*/
|
|
5990
|
+
const Wizard = () => {
|
|
5991
|
+
let state;
|
|
5992
|
+
const validateStep = async (stepIndex, steps) => {
|
|
5993
|
+
const step = steps[stepIndex];
|
|
5994
|
+
if (!step || !step.validate)
|
|
5995
|
+
return true;
|
|
5996
|
+
state.isValidating = true;
|
|
5997
|
+
try {
|
|
5998
|
+
const isValid = await step.validate();
|
|
5999
|
+
if (isValid) {
|
|
6000
|
+
state.completedSteps.add(stepIndex);
|
|
6001
|
+
state.errorSteps.delete(stepIndex);
|
|
6002
|
+
}
|
|
6003
|
+
else {
|
|
6004
|
+
state.errorSteps.add(stepIndex);
|
|
6005
|
+
state.completedSteps.delete(stepIndex);
|
|
6006
|
+
}
|
|
6007
|
+
return isValid;
|
|
6008
|
+
}
|
|
6009
|
+
catch (error) {
|
|
6010
|
+
state.errorSteps.add(stepIndex);
|
|
6011
|
+
state.completedSteps.delete(stepIndex);
|
|
6012
|
+
return false;
|
|
6013
|
+
}
|
|
6014
|
+
finally {
|
|
6015
|
+
state.isValidating = false;
|
|
6016
|
+
m.redraw();
|
|
6017
|
+
}
|
|
6018
|
+
};
|
|
6019
|
+
const goToStep = async (stepIndex, attrs) => {
|
|
6020
|
+
const { linear = true, onStepChange, steps } = attrs;
|
|
6021
|
+
if (stepIndex < 0 || stepIndex >= steps.length)
|
|
6022
|
+
return false;
|
|
6023
|
+
// Check if step is disabled
|
|
6024
|
+
if (steps[stepIndex].disabled)
|
|
6025
|
+
return false;
|
|
6026
|
+
// In linear mode, validate all previous steps
|
|
6027
|
+
if (linear && stepIndex > state.currentStep) {
|
|
6028
|
+
for (let i = state.currentStep; i < stepIndex; i++) {
|
|
6029
|
+
const isValid = await validateStep(i, steps);
|
|
6030
|
+
if (!isValid && !steps[i].optional) {
|
|
6031
|
+
return false;
|
|
6032
|
+
}
|
|
6033
|
+
}
|
|
6034
|
+
}
|
|
6035
|
+
// Validate current step before moving forward
|
|
6036
|
+
if (stepIndex > state.currentStep) {
|
|
6037
|
+
const isValid = await validateStep(state.currentStep, steps);
|
|
6038
|
+
if (!isValid && !steps[state.currentStep].optional) {
|
|
6039
|
+
return false;
|
|
6040
|
+
}
|
|
6041
|
+
}
|
|
6042
|
+
const oldStep = state.currentStep;
|
|
6043
|
+
state.currentStep = stepIndex;
|
|
6044
|
+
// Always call onStepChange when step changes
|
|
6045
|
+
if (onStepChange && oldStep !== stepIndex) {
|
|
6046
|
+
onStepChange(stepIndex, steps[stepIndex].id || `step-${stepIndex}`);
|
|
6047
|
+
}
|
|
6048
|
+
// Force redraw to update UI
|
|
6049
|
+
m.redraw();
|
|
6050
|
+
return true;
|
|
6051
|
+
};
|
|
6052
|
+
const nextStep = async (attrs) => {
|
|
6053
|
+
const { steps } = attrs;
|
|
6054
|
+
// Check if we're on the last step
|
|
6055
|
+
if (state.currentStep === steps.length - 1) {
|
|
6056
|
+
// This is the complete action
|
|
6057
|
+
if (attrs.onComplete) {
|
|
6058
|
+
attrs.onComplete();
|
|
6059
|
+
}
|
|
6060
|
+
return;
|
|
6061
|
+
}
|
|
6062
|
+
// Try to move to next step
|
|
6063
|
+
await goToStep(state.currentStep + 1, attrs);
|
|
6064
|
+
};
|
|
6065
|
+
const previousStep = (attrs) => {
|
|
6066
|
+
goToStep(state.currentStep - 1, attrs);
|
|
6067
|
+
};
|
|
6068
|
+
const skipStep = (attrs) => {
|
|
6069
|
+
const { steps } = attrs;
|
|
6070
|
+
const currentStepData = steps[state.currentStep];
|
|
6071
|
+
if (currentStepData && currentStepData.optional) {
|
|
6072
|
+
goToStep(state.currentStep + 1, attrs);
|
|
6073
|
+
}
|
|
6074
|
+
};
|
|
6075
|
+
return {
|
|
6076
|
+
oninit: ({ attrs }) => {
|
|
6077
|
+
state = {
|
|
6078
|
+
id: uniqueId(),
|
|
6079
|
+
currentStep: attrs.currentStep || 0,
|
|
6080
|
+
isValidating: false,
|
|
6081
|
+
completedSteps: new Set(),
|
|
6082
|
+
errorSteps: new Set()
|
|
6083
|
+
};
|
|
6084
|
+
},
|
|
6085
|
+
onbeforeupdate: ({ attrs }) => {
|
|
6086
|
+
// Sync external currentStep changes
|
|
6087
|
+
if (typeof attrs.currentStep === 'number' && attrs.currentStep !== state.currentStep) {
|
|
6088
|
+
state.currentStep = Math.max(0, attrs.currentStep);
|
|
6089
|
+
}
|
|
6090
|
+
},
|
|
6091
|
+
view: ({ attrs }) => {
|
|
6092
|
+
const { steps, showStepNumbers = true, className = '', showNavigation = true, labels = {}, orientation = 'horizontal', allowHeaderNavigation = false } = attrs;
|
|
6093
|
+
// Ensure currentStep is within bounds
|
|
6094
|
+
if (state.currentStep >= steps.length) {
|
|
6095
|
+
state.currentStep = Math.max(0, steps.length - 1);
|
|
6096
|
+
}
|
|
6097
|
+
const currentStepData = steps[state.currentStep];
|
|
6098
|
+
const isFirstStep = state.currentStep === 0;
|
|
6099
|
+
const isLastStep = state.currentStep === steps.length - 1;
|
|
6100
|
+
const activeContent = (currentStepData === null || currentStepData === void 0 ? void 0 : currentStepData.vnode) ? currentStepData.vnode() : null;
|
|
6101
|
+
return m('.wizard', { class: `${orientation} ${className}` }, [
|
|
6102
|
+
// Step indicator
|
|
6103
|
+
m('.wizard-header', [
|
|
6104
|
+
m('.wizard-steps', steps.map((step, index) => {
|
|
6105
|
+
const isActive = index === state.currentStep;
|
|
6106
|
+
const isCompleted = state.completedSteps.has(index);
|
|
6107
|
+
const hasError = state.errorSteps.has(index);
|
|
6108
|
+
return m('.wizard-step', {
|
|
6109
|
+
class: [
|
|
6110
|
+
isActive ? 'active' : '',
|
|
6111
|
+
isCompleted ? 'completed' : '',
|
|
6112
|
+
hasError ? 'error' : '',
|
|
6113
|
+
step.disabled ? 'disabled' : '',
|
|
6114
|
+
step.optional ? 'optional' : ''
|
|
6115
|
+
].filter(Boolean).join(' '),
|
|
6116
|
+
onclick: allowHeaderNavigation && !step.disabled ?
|
|
6117
|
+
() => goToStep(index, attrs) : undefined
|
|
6118
|
+
}, [
|
|
6119
|
+
// Step number/icon
|
|
6120
|
+
m('.wizard-step-indicator', [
|
|
6121
|
+
isCompleted ?
|
|
6122
|
+
m('i.material-icons', 'check') :
|
|
6123
|
+
hasError ?
|
|
6124
|
+
m('i.material-icons', 'error') :
|
|
6125
|
+
step.icon ?
|
|
6126
|
+
m('i.material-icons', step.icon) :
|
|
6127
|
+
showStepNumbers ?
|
|
6128
|
+
m('span.wizard-step-number', index + 1) :
|
|
6129
|
+
null
|
|
6130
|
+
]),
|
|
6131
|
+
// Step content
|
|
6132
|
+
m('.wizard-step-content', [
|
|
6133
|
+
m('.wizard-step-title', step.title),
|
|
6134
|
+
step.subtitle && m('.wizard-step-subtitle', step.subtitle),
|
|
6135
|
+
step.optional && m('.wizard-step-optional', labels.optional || 'Optional')
|
|
6136
|
+
]),
|
|
6137
|
+
// Connector line (except for last step in horizontal mode)
|
|
6138
|
+
orientation === 'horizontal' && index < steps.length - 1 &&
|
|
6139
|
+
m('.wizard-step-connector')
|
|
6140
|
+
]);
|
|
6141
|
+
}))
|
|
6142
|
+
]),
|
|
6143
|
+
// Step content
|
|
6144
|
+
m('.wizard-body', [
|
|
6145
|
+
activeContent && m('.wizard-step-panel', {
|
|
6146
|
+
key: (currentStepData === null || currentStepData === void 0 ? void 0 : currentStepData.id) || `step-${state.currentStep}`
|
|
6147
|
+
}, activeContent)
|
|
6148
|
+
]),
|
|
6149
|
+
// Navigation
|
|
6150
|
+
showNavigation && m('.wizard-footer', [
|
|
6151
|
+
m('.wizard-navigation', [
|
|
6152
|
+
// Previous button
|
|
6153
|
+
!isFirstStep && m('button.btn-flat.wizard-btn-previous', {
|
|
6154
|
+
onclick: () => previousStep(attrs),
|
|
6155
|
+
disabled: state.isValidating
|
|
6156
|
+
}, labels.previous || 'Previous'),
|
|
6157
|
+
// Skip button (for optional steps)
|
|
6158
|
+
currentStepData && currentStepData.optional && !isLastStep &&
|
|
6159
|
+
m('button.btn-flat.wizard-btn-skip', {
|
|
6160
|
+
onclick: () => skipStep(attrs),
|
|
6161
|
+
disabled: state.isValidating
|
|
6162
|
+
}, labels.skip || 'Skip'),
|
|
6163
|
+
// Next/Complete button
|
|
6164
|
+
m('button.btn.wizard-btn-next', {
|
|
6165
|
+
onclick: () => nextStep(attrs),
|
|
6166
|
+
disabled: state.isValidating,
|
|
6167
|
+
class: isLastStep ? 'wizard-btn-complete' : ''
|
|
6168
|
+
}, [
|
|
6169
|
+
state.isValidating && m('i.material-icons.left', 'hourglass_empty'),
|
|
6170
|
+
isLastStep ? (labels.complete || 'Complete') : (labels.next || 'Next')
|
|
6171
|
+
])
|
|
6172
|
+
])
|
|
6173
|
+
])
|
|
6174
|
+
]);
|
|
6175
|
+
}
|
|
6176
|
+
};
|
|
6177
|
+
};
|
|
6178
|
+
/**
|
|
6179
|
+
* Simple linear stepper for forms
|
|
6180
|
+
*/
|
|
6181
|
+
const Stepper = () => {
|
|
6182
|
+
return {
|
|
6183
|
+
view: ({ attrs }) => {
|
|
6184
|
+
return m(Wizard, Object.assign(Object.assign({}, attrs), { linear: true, showNavigation: false, allowHeaderNavigation: false, orientation: 'horizontal' }));
|
|
6185
|
+
}
|
|
6186
|
+
};
|
|
6187
|
+
};
|
|
6188
|
+
|
|
6189
|
+
export { AnchorItem, Autocomplete, Breadcrumb, BreadcrumbManager, Button, ButtonFactory, Carousel, CharacterCounter, Chips, CodeBlock, Collapsible, CollapsibleItem, Collection, CollectionMode, ColorInput, DatePicker, Dropdown, EmailInput, FileInput, FileUpload, FlatButton, FloatingActionButton, HelperText, Icon, InputCheckbox, Label, LargeButton, ListItem, Mandatory, MaterialBox, ModalPanel, NumberInput, Options, Pagination, Parallax, PasswordInput, Pushpin, PushpinComponent, RadioButton, RadioButtons, RangeInput, RoundIconButton, SearchSelect, SecondaryContent, Select, Sidenav, SidenavItem, SidenavManager, SmallButton, Stepper, SubmitButton, Switch, Tabs, TextArea, TextInput, ThemeManager, ThemeSwitcher, ThemeToggle, TimePicker, Toast, ToastComponent, Tooltip, TooltipComponent, UrlInput, Wizard, createBreadcrumb, getDropdownStyles, initPushpins, initTooltips, isNumeric, padLeft, range, toast, uniqueId, uuid4 };
|