mithril-materialized 3.3.7 → 3.4.0
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/button.d.ts +1 -0
- package/dist/components.css +22 -0
- package/dist/forms.css +8 -0
- package/dist/index.css +22 -0
- package/dist/index.esm.js +270 -89
- package/dist/index.js +270 -88
- package/dist/index.min.css +2 -2
- package/dist/index.umd.js +270 -88
- package/dist/waves.d.ts +16 -0
- package/package.json +1 -1
- package/sass/components/_buttons.scss +21 -0
- package/sass/components/_theme-switcher.scss +10 -0
package/dist/index.umd.js
CHANGED
|
@@ -436,6 +436,103 @@
|
|
|
436
436
|
},
|
|
437
437
|
});
|
|
438
438
|
|
|
439
|
+
/*!
|
|
440
|
+
* Waves Effect for Mithril Materialized
|
|
441
|
+
* Based on Waves v0.6.4 by Alfiana E. Sibuea
|
|
442
|
+
* Adapted for TypeScript and Mithril integration
|
|
443
|
+
*/
|
|
444
|
+
class WavesEffect {
|
|
445
|
+
static offset(elem) {
|
|
446
|
+
const rect = elem.getBoundingClientRect();
|
|
447
|
+
return {
|
|
448
|
+
top: rect.top + window.pageYOffset,
|
|
449
|
+
left: rect.left + window.pageXOffset
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
static createRipple(e, element) {
|
|
453
|
+
// Disable right click
|
|
454
|
+
if (e.button === 2) {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
// Create ripple element
|
|
458
|
+
const ripple = document.createElement('div');
|
|
459
|
+
ripple.className = 'waves-ripple';
|
|
460
|
+
// Get click position relative to element
|
|
461
|
+
const pos = this.offset(element);
|
|
462
|
+
const relativeY = e.pageY - pos.top;
|
|
463
|
+
const relativeX = e.pageX - pos.left;
|
|
464
|
+
// Calculate scale based on element size
|
|
465
|
+
const scale = (element.clientWidth / 100) * 10;
|
|
466
|
+
// Set initial ripple position and style
|
|
467
|
+
ripple.style.cssText = `
|
|
468
|
+
top: ${relativeY}px;
|
|
469
|
+
left: ${relativeX}px;
|
|
470
|
+
transform: scale(0);
|
|
471
|
+
opacity: 1;
|
|
472
|
+
`;
|
|
473
|
+
// Add ripple to element
|
|
474
|
+
element.appendChild(ripple);
|
|
475
|
+
// Force reflow and animate
|
|
476
|
+
ripple.offsetHeight;
|
|
477
|
+
ripple.style.transform = `scale(${scale})`;
|
|
478
|
+
ripple.style.opacity = '1';
|
|
479
|
+
// Store reference for cleanup
|
|
480
|
+
ripple.setAttribute('data-created', Date.now().toString());
|
|
481
|
+
}
|
|
482
|
+
static removeRipples(element) {
|
|
483
|
+
const ripples = element.querySelectorAll('.waves-ripple');
|
|
484
|
+
ripples.forEach((ripple) => {
|
|
485
|
+
const created = parseInt(ripple.getAttribute('data-created') || '0');
|
|
486
|
+
const age = Date.now() - created;
|
|
487
|
+
const fadeOut = () => {
|
|
488
|
+
ripple.style.opacity = '0';
|
|
489
|
+
setTimeout(() => {
|
|
490
|
+
if (ripple.parentNode) {
|
|
491
|
+
ripple.parentNode.removeChild(ripple);
|
|
492
|
+
}
|
|
493
|
+
}, this.duration);
|
|
494
|
+
};
|
|
495
|
+
if (age >= 350) {
|
|
496
|
+
fadeOut();
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
setTimeout(fadeOut, 350 - age);
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
WavesEffect.duration = 750;
|
|
505
|
+
WavesEffect.onMouseDown = (e) => {
|
|
506
|
+
const element = e.currentTarget;
|
|
507
|
+
if (element && element.classList.contains('waves-effect')) {
|
|
508
|
+
WavesEffect.createRipple(e, element);
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
WavesEffect.onMouseUp = (e) => {
|
|
512
|
+
const element = e.currentTarget;
|
|
513
|
+
if (element && element.classList.contains('waves-effect')) {
|
|
514
|
+
WavesEffect.removeRipples(element);
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
WavesEffect.onMouseLeave = (e) => {
|
|
518
|
+
const element = e.currentTarget;
|
|
519
|
+
if (element && element.classList.contains('waves-effect')) {
|
|
520
|
+
WavesEffect.removeRipples(element);
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
WavesEffect.onTouchStart = (e) => {
|
|
524
|
+
const element = e.currentTarget;
|
|
525
|
+
if (element && element.classList.contains('waves-effect')) {
|
|
526
|
+
WavesEffect.createRipple(e, element);
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
WavesEffect.onTouchEnd = (e) => {
|
|
530
|
+
const element = e.currentTarget;
|
|
531
|
+
if (element && element.classList.contains('waves-effect')) {
|
|
532
|
+
WavesEffect.removeRipples(element);
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
|
|
439
536
|
/**
|
|
440
537
|
* A factory to create new buttons.
|
|
441
538
|
*
|
|
@@ -449,13 +546,18 @@
|
|
|
449
546
|
iconName, iconClass, label, className, variant } = attrs, params = __rest(attrs, ["tooltip", "tooltipPosition", "tooltipPostion", "iconName", "iconClass", "label", "className", "variant"]);
|
|
450
547
|
// Use variant or fallback to factory type
|
|
451
548
|
const buttonType = variant || type || 'button';
|
|
452
|
-
const cn = [tooltip ? 'tooltipped' : '', defaultClassNames, className]
|
|
453
|
-
.filter(Boolean)
|
|
454
|
-
.join(' ')
|
|
455
|
-
.trim();
|
|
549
|
+
const cn = [tooltip ? 'tooltipped' : '', defaultClassNames, className].filter(Boolean).join(' ').trim();
|
|
456
550
|
// Use tooltipPosition if available, fallback to legacy tooltipPostion
|
|
457
551
|
const position = tooltipPosition || tooltipPostion || 'top';
|
|
458
|
-
|
|
552
|
+
// Add waves effect event handlers if waves-effect class is present
|
|
553
|
+
const wavesHandlers = cn.includes('waves-effect') ? {
|
|
554
|
+
onmousedown: WavesEffect.onMouseDown,
|
|
555
|
+
onmouseup: WavesEffect.onMouseUp,
|
|
556
|
+
onmouseleave: WavesEffect.onMouseLeave,
|
|
557
|
+
ontouchstart: WavesEffect.onTouchStart,
|
|
558
|
+
ontouchend: WavesEffect.onTouchEnd
|
|
559
|
+
} : {};
|
|
560
|
+
return m(element, Object.assign(Object.assign(Object.assign({}, params), wavesHandlers), { className: cn, 'data-position': tooltip ? position : undefined, 'data-tooltip': tooltip || undefined, type: buttonType }), iconName ? m(Icon, { iconName, className: iconClass || 'left' }) : undefined, label ? label : undefined);
|
|
459
561
|
},
|
|
460
562
|
};
|
|
461
563
|
};
|
|
@@ -464,6 +566,7 @@
|
|
|
464
566
|
const LargeButton = ButtonFactory('a', 'waves-effect waves-light btn-large', 'button');
|
|
465
567
|
const SmallButton = ButtonFactory('a', 'waves-effect waves-light btn-small', 'button');
|
|
466
568
|
const FlatButton = ButtonFactory('a', 'waves-effect waves-teal btn-flat', 'button');
|
|
569
|
+
const IconButton = ButtonFactory('button', 'btn-flat btn-icon waves-effect waves-teal', 'button');
|
|
467
570
|
const RoundIconButton = ButtonFactory('button', 'btn-floating btn-large waves-effect waves-light', 'button');
|
|
468
571
|
const SubmitButton = ButtonFactory('button', 'btn waves-effect waves-light', 'submit');
|
|
469
572
|
|
|
@@ -900,7 +1003,7 @@
|
|
|
900
1003
|
};
|
|
901
1004
|
const rotation = (_a = rotationMap[direction]) !== null && _a !== void 0 ? _a : 0;
|
|
902
1005
|
const transform = rotation ? `rotate(${rotation}deg)` : undefined;
|
|
903
|
-
return m('svg', Object.assign(Object.assign({}, props), { style: Object.assign({ transform }, style), height: '
|
|
1006
|
+
return m('svg', Object.assign(Object.assign({}, props), { style: Object.assign({ transform }, style), height: '24px', width: '24px', viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' }), iconPaths[name].map((d) => m('path', {
|
|
904
1007
|
d,
|
|
905
1008
|
fill: d.includes('M0 0h24v24H0z') ? 'none' : 'currentColor',
|
|
906
1009
|
})));
|
|
@@ -2815,6 +2918,7 @@
|
|
|
2815
2918
|
height: undefined,
|
|
2816
2919
|
active: false,
|
|
2817
2920
|
textarea: undefined,
|
|
2921
|
+
hiddenDiv: undefined,
|
|
2818
2922
|
internalValue: '',
|
|
2819
2923
|
};
|
|
2820
2924
|
const updateHeight = (textarea, hiddenDiv) => {
|
|
@@ -2911,13 +3015,13 @@
|
|
|
2911
3015
|
overflowWrap: 'break-word',
|
|
2912
3016
|
},
|
|
2913
3017
|
oncreate: ({ dom }) => {
|
|
2914
|
-
const hiddenDiv = dom;
|
|
3018
|
+
const hiddenDiv = state.hiddenDiv = dom;
|
|
2915
3019
|
if (state.textarea) {
|
|
2916
3020
|
updateHeight(state.textarea, hiddenDiv);
|
|
2917
3021
|
}
|
|
2918
3022
|
},
|
|
2919
3023
|
onupdate: ({ dom }) => {
|
|
2920
|
-
const hiddenDiv = dom;
|
|
3024
|
+
const hiddenDiv = state.hiddenDiv = dom;
|
|
2921
3025
|
if (state.textarea) {
|
|
2922
3026
|
updateHeight(state.textarea, hiddenDiv);
|
|
2923
3027
|
}
|
|
@@ -2942,7 +3046,10 @@
|
|
|
2942
3046
|
const textarea = dom;
|
|
2943
3047
|
if (state.height)
|
|
2944
3048
|
textarea.style.height = state.height;
|
|
2945
|
-
//
|
|
3049
|
+
// Trigger height recalculation when value changes programmatically
|
|
3050
|
+
if (state.hiddenDiv) {
|
|
3051
|
+
updateHeight(textarea, state.hiddenDiv);
|
|
3052
|
+
}
|
|
2946
3053
|
}, onfocus: () => {
|
|
2947
3054
|
state.active = true;
|
|
2948
3055
|
}, oninput: (e) => {
|
|
@@ -3102,9 +3209,6 @@
|
|
|
3102
3209
|
const { className = 'col s12', dataError, dataSuccess, helperText, iconName, id = state.id, placeholder, isMandatory, label, maxLength, newRow, oninput, onchange, onkeydown, onkeypress, onkeyup, style, validate, canClear } = attrs, params = __rest(attrs, ["className", "dataError", "dataSuccess", "helperText", "iconName", "id", "placeholder", "isMandatory", "label", "maxLength", "newRow", "oninput", "onchange", "onkeydown", "onkeypress", "onkeyup", "style", "validate", "canClear"]);
|
|
3103
3210
|
// const attributes = toAttrs(params);
|
|
3104
3211
|
const cn = [newRow ? 'clear' : '', defaultClass, className].filter(Boolean).join(' ').trim() || undefined;
|
|
3105
|
-
const isActive = state.active || ((_a = state.inputElement) === null || _a === void 0 ? void 0 : _a.value) || placeholder || type === 'color' || type === 'range'
|
|
3106
|
-
? true
|
|
3107
|
-
: false;
|
|
3108
3212
|
// Special rendering for minmax range sliders
|
|
3109
3213
|
if (type === 'range' && (attrs.minmax || attrs.valueDisplay)) {
|
|
3110
3214
|
return m(attrs.minmax ? DoubleRangeSlider : SingleRangeSlider, Object.assign(Object.assign({}, attrs), { state,
|
|
@@ -3125,12 +3229,15 @@
|
|
|
3125
3229
|
}
|
|
3126
3230
|
else if (isNonInteractive) {
|
|
3127
3231
|
// Non-interactive components: prefer defaultValue, fallback to value
|
|
3128
|
-
value = ((
|
|
3232
|
+
value = ((_b = (_a = attrs.defaultValue) !== null && _a !== void 0 ? _a : attrs.value) !== null && _b !== void 0 ? _b : (isNumeric ? 0 : ''));
|
|
3129
3233
|
}
|
|
3130
3234
|
else {
|
|
3131
3235
|
// Interactive uncontrolled: use internal state
|
|
3132
|
-
value = ((
|
|
3236
|
+
value = ((_d = (_c = state.internalValue) !== null && _c !== void 0 ? _c : attrs.defaultValue) !== null && _d !== void 0 ? _d : (isNumeric ? 0 : ''));
|
|
3133
3237
|
}
|
|
3238
|
+
const isActive = state.active || ((_e = state.inputElement) === null || _e === void 0 ? void 0 : _e.value) || value || placeholder || type === 'color' || type === 'range'
|
|
3239
|
+
? true
|
|
3240
|
+
: false;
|
|
3134
3241
|
const rangeType = type === 'range' && !attrs.minmax;
|
|
3135
3242
|
return m('.input-field', { className: cn, style }, [
|
|
3136
3243
|
iconName ? m('i.material-icons.prefix', iconName) : undefined,
|
|
@@ -4344,12 +4451,17 @@
|
|
|
4344
4451
|
}
|
|
4345
4452
|
: undefined,
|
|
4346
4453
|
}, [
|
|
4347
|
-
m('a.btn-floating.btn-large', {
|
|
4454
|
+
m('a.btn-floating.btn-large.waves-effect.waves-light', {
|
|
4348
4455
|
className,
|
|
4456
|
+
onmousedown: WavesEffect.onMouseDown,
|
|
4457
|
+
onmouseup: WavesEffect.onMouseUp,
|
|
4458
|
+
onmouseleave: WavesEffect.onMouseLeave,
|
|
4459
|
+
ontouchstart: WavesEffect.onTouchStart,
|
|
4460
|
+
ontouchend: WavesEffect.onTouchEnd,
|
|
4349
4461
|
}, m('i.material-icons', { className: iconClass }, iconName)),
|
|
4350
4462
|
buttons &&
|
|
4351
4463
|
buttons.length > 0 &&
|
|
4352
|
-
m('ul', buttons.map((button, index) => m('li', m(`a.btn-floating.${button.className || 'red'}`, {
|
|
4464
|
+
m('ul', buttons.map((button, index) => m('li', m(`a.btn-floating.waves-effect.waves-light.${button.className || 'red'}`, {
|
|
4353
4465
|
style: {
|
|
4354
4466
|
opacity: state.isOpen ? '1' : '0',
|
|
4355
4467
|
transform: state.isOpen ? 'scale(1)' : 'scale(0.4)',
|
|
@@ -4360,6 +4472,11 @@
|
|
|
4360
4472
|
if (button.onclick)
|
|
4361
4473
|
button.onclick(e);
|
|
4362
4474
|
},
|
|
4475
|
+
onmousedown: WavesEffect.onMouseDown,
|
|
4476
|
+
onmouseup: WavesEffect.onMouseUp,
|
|
4477
|
+
onmouseleave: WavesEffect.onMouseLeave,
|
|
4478
|
+
ontouchstart: WavesEffect.onTouchStart,
|
|
4479
|
+
ontouchend: WavesEffect.onTouchEnd,
|
|
4363
4480
|
}, m('i.material-icons', { className: button.iconClass }, button.iconName))))),
|
|
4364
4481
|
]));
|
|
4365
4482
|
},
|
|
@@ -5756,11 +5873,13 @@
|
|
|
5756
5873
|
const Select = () => {
|
|
5757
5874
|
const state = {
|
|
5758
5875
|
id: '',
|
|
5876
|
+
dropdownId: '',
|
|
5759
5877
|
isOpen: false,
|
|
5760
5878
|
focusedIndex: -1,
|
|
5761
5879
|
inputRef: null,
|
|
5762
5880
|
dropdownRef: null,
|
|
5763
5881
|
internalSelectedIds: [],
|
|
5882
|
+
isInsideModal: false,
|
|
5764
5883
|
};
|
|
5765
5884
|
const isControlled = (attrs) => attrs.checkedId !== undefined && attrs.onchange !== undefined;
|
|
5766
5885
|
const isSelected = (id, selectedIds) => {
|
|
@@ -5849,9 +5968,124 @@
|
|
|
5849
5968
|
m.redraw();
|
|
5850
5969
|
}
|
|
5851
5970
|
};
|
|
5971
|
+
const getPortalStyles = (inputRef) => {
|
|
5972
|
+
if (!inputRef)
|
|
5973
|
+
return {};
|
|
5974
|
+
const rect = inputRef.getBoundingClientRect();
|
|
5975
|
+
const viewportHeight = window.innerHeight;
|
|
5976
|
+
return {
|
|
5977
|
+
position: 'fixed',
|
|
5978
|
+
top: `${rect.bottom}px`,
|
|
5979
|
+
left: `${rect.left}px`,
|
|
5980
|
+
width: `${rect.width}px`,
|
|
5981
|
+
zIndex: 10000, // Higher than modal z-index
|
|
5982
|
+
maxHeight: `${viewportHeight - rect.bottom - 20}px`, // Leave 20px margin from bottom
|
|
5983
|
+
};
|
|
5984
|
+
};
|
|
5985
|
+
const renderDropdownContent = (attrs, selectedIds, multiple, placeholder) => [
|
|
5986
|
+
placeholder && m('li.disabled', { tabindex: 0 }, m('span', placeholder)),
|
|
5987
|
+
// Render ungrouped options first
|
|
5988
|
+
attrs.options
|
|
5989
|
+
.filter((option) => !option.group)
|
|
5990
|
+
.map((option) => m('li', Object.assign({ key: option.id, class: option.disabled
|
|
5991
|
+
? 'disabled'
|
|
5992
|
+
: state.focusedIndex === attrs.options.indexOf(option)
|
|
5993
|
+
? 'focused'
|
|
5994
|
+
: '' }, (option.disabled
|
|
5995
|
+
? {}
|
|
5996
|
+
: {
|
|
5997
|
+
onclick: (e) => {
|
|
5998
|
+
e.stopPropagation();
|
|
5999
|
+
toggleOption(option.id, multiple, attrs);
|
|
6000
|
+
},
|
|
6001
|
+
})), [
|
|
6002
|
+
option.img && m('img', { src: option.img, alt: option.label }),
|
|
6003
|
+
m('span', [
|
|
6004
|
+
multiple
|
|
6005
|
+
? m('label', { for: option.id }, m('input', {
|
|
6006
|
+
id: option.id,
|
|
6007
|
+
type: 'checkbox',
|
|
6008
|
+
checked: selectedIds.includes(option.id),
|
|
6009
|
+
disabled: option.disabled ? true : undefined,
|
|
6010
|
+
onclick: (e) => {
|
|
6011
|
+
e.stopPropagation();
|
|
6012
|
+
},
|
|
6013
|
+
}), m('span', option.label))
|
|
6014
|
+
: m('span', option.label),
|
|
6015
|
+
].filter(Boolean)),
|
|
6016
|
+
])),
|
|
6017
|
+
// Render grouped options
|
|
6018
|
+
Object.entries(attrs.options
|
|
6019
|
+
.filter((option) => option.group)
|
|
6020
|
+
.reduce((groups, option) => {
|
|
6021
|
+
const group = option.group;
|
|
6022
|
+
if (!groups[group])
|
|
6023
|
+
groups[group] = [];
|
|
6024
|
+
groups[group].push(option);
|
|
6025
|
+
return groups;
|
|
6026
|
+
}, {}))
|
|
6027
|
+
.map(([groupName, groupOptions]) => [
|
|
6028
|
+
m('li.optgroup', { key: `group-${groupName}`, tabindex: 0 }, m('span', groupName)),
|
|
6029
|
+
...groupOptions.map((option) => m('li', Object.assign({ key: option.id, class: `optgroup-option${option.disabled ? ' disabled' : ''}${isSelected(option.id, selectedIds) ? ' selected' : ''}${state.focusedIndex === attrs.options.indexOf(option) ? ' focused' : ''}` }, (option.disabled
|
|
6030
|
+
? {}
|
|
6031
|
+
: {
|
|
6032
|
+
onclick: (e) => {
|
|
6033
|
+
e.stopPropagation();
|
|
6034
|
+
toggleOption(option.id, multiple, attrs);
|
|
6035
|
+
},
|
|
6036
|
+
})), [
|
|
6037
|
+
option.img && m('img', { src: option.img, alt: option.label }),
|
|
6038
|
+
m('span', [
|
|
6039
|
+
multiple
|
|
6040
|
+
? m('label', { for: option.id }, m('input', {
|
|
6041
|
+
id: option.id,
|
|
6042
|
+
type: 'checkbox',
|
|
6043
|
+
checked: selectedIds.includes(option.id),
|
|
6044
|
+
disabled: option.disabled ? true : undefined,
|
|
6045
|
+
onclick: (e) => {
|
|
6046
|
+
e.stopPropagation();
|
|
6047
|
+
},
|
|
6048
|
+
}), m('span', option.label))
|
|
6049
|
+
: m('span', option.label),
|
|
6050
|
+
].filter(Boolean)),
|
|
6051
|
+
])),
|
|
6052
|
+
])
|
|
6053
|
+
.reduce((acc, val) => acc.concat(val), []),
|
|
6054
|
+
];
|
|
6055
|
+
const updatePortalDropdown = (attrs, selectedIds, multiple, placeholder) => {
|
|
6056
|
+
var _a;
|
|
6057
|
+
if (!state.isInsideModal)
|
|
6058
|
+
return;
|
|
6059
|
+
let portalElement = document.getElementById(state.dropdownId);
|
|
6060
|
+
if (!state.isOpen) {
|
|
6061
|
+
// Clean up portal when dropdown is closed
|
|
6062
|
+
if (portalElement) {
|
|
6063
|
+
m.render(portalElement, []);
|
|
6064
|
+
(_a = portalElement.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(portalElement);
|
|
6065
|
+
}
|
|
6066
|
+
return;
|
|
6067
|
+
}
|
|
6068
|
+
if (!portalElement) {
|
|
6069
|
+
portalElement = document.createElement('div');
|
|
6070
|
+
portalElement.id = state.dropdownId;
|
|
6071
|
+
document.body.appendChild(portalElement);
|
|
6072
|
+
}
|
|
6073
|
+
const dropdownVnode = m('ul.dropdown-content.select-dropdown', {
|
|
6074
|
+
tabindex: 0,
|
|
6075
|
+
style: getPortalStyles(state.inputRef),
|
|
6076
|
+
oncreate: ({ dom }) => {
|
|
6077
|
+
state.dropdownRef = dom;
|
|
6078
|
+
},
|
|
6079
|
+
onremove: () => {
|
|
6080
|
+
state.dropdownRef = null;
|
|
6081
|
+
},
|
|
6082
|
+
}, renderDropdownContent(attrs, selectedIds, multiple, placeholder));
|
|
6083
|
+
m.render(portalElement, dropdownVnode);
|
|
6084
|
+
};
|
|
5852
6085
|
return {
|
|
5853
6086
|
oninit: ({ attrs }) => {
|
|
5854
6087
|
state.id = attrs.id || uniqueId();
|
|
6088
|
+
state.dropdownId = `${state.id}-dropdown`;
|
|
5855
6089
|
const controlled = isControlled(attrs);
|
|
5856
6090
|
// Warn developer for improper controlled usage
|
|
5857
6091
|
if (attrs.checkedId !== undefined && !controlled && !attrs.disabled) {
|
|
@@ -5870,9 +6104,20 @@
|
|
|
5870
6104
|
// Add global click listener to close dropdown
|
|
5871
6105
|
document.addEventListener('click', closeDropdown);
|
|
5872
6106
|
},
|
|
6107
|
+
oncreate: ({ dom }) => {
|
|
6108
|
+
// Detect if component is inside a modal
|
|
6109
|
+
state.isInsideModal = !!dom.closest('.modal');
|
|
6110
|
+
},
|
|
5873
6111
|
onremove: () => {
|
|
5874
6112
|
// Cleanup global listener
|
|
5875
6113
|
document.removeEventListener('click', closeDropdown);
|
|
6114
|
+
// Cleanup portaled dropdown if it exists
|
|
6115
|
+
if (state.isInsideModal && state.dropdownRef) {
|
|
6116
|
+
const portalElement = document.getElementById(state.dropdownId);
|
|
6117
|
+
if (portalElement && portalElement.parentNode) {
|
|
6118
|
+
portalElement.parentNode.removeChild(portalElement);
|
|
6119
|
+
}
|
|
6120
|
+
}
|
|
5876
6121
|
},
|
|
5877
6122
|
view: ({ attrs }) => {
|
|
5878
6123
|
var _a;
|
|
@@ -5896,6 +6141,10 @@
|
|
|
5896
6141
|
const { newRow, className = 'col s12', key, options, multiple = false, label, helperText, placeholder = '', isMandatory, iconName, style, } = attrs;
|
|
5897
6142
|
const finalClassName = newRow ? `${className} clear` : className;
|
|
5898
6143
|
const selectedOptions = options.filter((opt) => isSelected(opt.id, selectedIds));
|
|
6144
|
+
// Update portal dropdown when inside modal
|
|
6145
|
+
if (state.isInsideModal) {
|
|
6146
|
+
updatePortalDropdown(attrs, selectedIds, multiple, placeholder);
|
|
6147
|
+
}
|
|
5899
6148
|
return m('.input-field.select-space', {
|
|
5900
6149
|
className: finalClassName,
|
|
5901
6150
|
key,
|
|
@@ -5908,6 +6157,7 @@
|
|
|
5908
6157
|
tabindex: disabled ? -1 : 0,
|
|
5909
6158
|
'aria-expanded': state.isOpen ? 'true' : 'false',
|
|
5910
6159
|
'aria-haspopup': 'listbox',
|
|
6160
|
+
'aria-controls': state.dropdownId,
|
|
5911
6161
|
role: 'combobox',
|
|
5912
6162
|
}, [
|
|
5913
6163
|
m('input[type=text][readonly=true].select-dropdown.dropdown-trigger', {
|
|
@@ -5924,8 +6174,8 @@
|
|
|
5924
6174
|
}
|
|
5925
6175
|
},
|
|
5926
6176
|
}),
|
|
5927
|
-
// Dropdown Menu
|
|
5928
|
-
state.isOpen &&
|
|
6177
|
+
// Dropdown Menu - render inline only when NOT inside modal
|
|
6178
|
+
state.isOpen && !state.isInsideModal &&
|
|
5929
6179
|
m('ul.dropdown-content.select-dropdown', {
|
|
5930
6180
|
tabindex: 0,
|
|
5931
6181
|
oncreate: ({ dom }) => {
|
|
@@ -5935,76 +6185,7 @@
|
|
|
5935
6185
|
state.dropdownRef = null;
|
|
5936
6186
|
},
|
|
5937
6187
|
style: getDropdownStyles(state.inputRef, true, options),
|
|
5938
|
-
},
|
|
5939
|
-
placeholder && m('li.disabled', { tabindex: 0 }, m('span', placeholder)),
|
|
5940
|
-
// Render ungrouped options first
|
|
5941
|
-
options
|
|
5942
|
-
.filter((option) => !option.group)
|
|
5943
|
-
.map((option) => m('li', Object.assign({ key: option.id, class: option.disabled
|
|
5944
|
-
? 'disabled'
|
|
5945
|
-
: state.focusedIndex === options.indexOf(option)
|
|
5946
|
-
? 'focused'
|
|
5947
|
-
: '' }, (option.disabled
|
|
5948
|
-
? {}
|
|
5949
|
-
: {
|
|
5950
|
-
onclick: (e) => {
|
|
5951
|
-
e.stopPropagation();
|
|
5952
|
-
toggleOption(option.id, multiple, attrs);
|
|
5953
|
-
},
|
|
5954
|
-
})), [
|
|
5955
|
-
option.img && m('img', { src: option.img, alt: option.label }),
|
|
5956
|
-
m('span', [
|
|
5957
|
-
multiple
|
|
5958
|
-
? m('label', { for: option.id }, m('input', {
|
|
5959
|
-
id: option.id,
|
|
5960
|
-
type: 'checkbox',
|
|
5961
|
-
checked: selectedIds.includes(option.id),
|
|
5962
|
-
disabled: option.disabled ? true : undefined,
|
|
5963
|
-
onclick: (e) => {
|
|
5964
|
-
e.stopPropagation();
|
|
5965
|
-
},
|
|
5966
|
-
}), m('span', option.label))
|
|
5967
|
-
: m('span', option.label),
|
|
5968
|
-
].filter(Boolean)),
|
|
5969
|
-
])),
|
|
5970
|
-
// Render grouped options
|
|
5971
|
-
Object.entries(options
|
|
5972
|
-
.filter((option) => option.group)
|
|
5973
|
-
.reduce((groups, option) => {
|
|
5974
|
-
const group = option.group;
|
|
5975
|
-
if (!groups[group])
|
|
5976
|
-
groups[group] = [];
|
|
5977
|
-
groups[group].push(option);
|
|
5978
|
-
return groups;
|
|
5979
|
-
}, {}))
|
|
5980
|
-
.map(([groupName, groupOptions]) => [
|
|
5981
|
-
m('li.optgroup', { key: `group-${groupName}`, tabindex: 0 }, m('span', groupName)),
|
|
5982
|
-
...groupOptions.map((option) => m('li', Object.assign({ key: option.id, class: `optgroup-option${option.disabled ? ' disabled' : ''}${isSelected(option.id, selectedIds) ? ' selected' : ''}${state.focusedIndex === options.indexOf(option) ? ' focused' : ''}` }, (option.disabled
|
|
5983
|
-
? {}
|
|
5984
|
-
: {
|
|
5985
|
-
onclick: (e) => {
|
|
5986
|
-
e.stopPropagation();
|
|
5987
|
-
toggleOption(option.id, multiple, attrs);
|
|
5988
|
-
},
|
|
5989
|
-
})), [
|
|
5990
|
-
option.img && m('img', { src: option.img, alt: option.label }),
|
|
5991
|
-
m('span', [
|
|
5992
|
-
multiple
|
|
5993
|
-
? m('label', { for: option.id }, m('input', {
|
|
5994
|
-
id: option.id,
|
|
5995
|
-
type: 'checkbox',
|
|
5996
|
-
checked: selectedIds.includes(option.id),
|
|
5997
|
-
disabled: option.disabled ? true : undefined,
|
|
5998
|
-
onclick: (e) => {
|
|
5999
|
-
e.stopPropagation();
|
|
6000
|
-
},
|
|
6001
|
-
}), m('span', option.label))
|
|
6002
|
-
: m('span', option.label),
|
|
6003
|
-
].filter(Boolean)),
|
|
6004
|
-
])),
|
|
6005
|
-
])
|
|
6006
|
-
.reduce((acc, val) => acc.concat(val), []),
|
|
6007
|
-
]),
|
|
6188
|
+
}, renderDropdownContent(attrs, selectedIds, multiple, placeholder)),
|
|
6008
6189
|
m(MaterialIcon, {
|
|
6009
6190
|
name: 'caret',
|
|
6010
6191
|
direction: 'down',
|
|
@@ -8949,6 +9130,7 @@
|
|
|
8949
9130
|
exports.FloatingActionButton = FloatingActionButton;
|
|
8950
9131
|
exports.HelperText = HelperText;
|
|
8951
9132
|
exports.Icon = Icon;
|
|
9133
|
+
exports.IconButton = IconButton;
|
|
8952
9134
|
exports.ImageList = ImageList;
|
|
8953
9135
|
exports.InputCheckbox = InputCheckbox;
|
|
8954
9136
|
exports.Label = Label;
|
package/dist/waves.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Waves Effect for Mithril Materialized
|
|
3
|
+
* Based on Waves v0.6.4 by Alfiana E. Sibuea
|
|
4
|
+
* Adapted for TypeScript and Mithril integration
|
|
5
|
+
*/
|
|
6
|
+
export declare class WavesEffect {
|
|
7
|
+
private static duration;
|
|
8
|
+
private static offset;
|
|
9
|
+
private static createRipple;
|
|
10
|
+
private static removeRipples;
|
|
11
|
+
static onMouseDown: (e: MouseEvent) => void;
|
|
12
|
+
static onMouseUp: (e: MouseEvent) => void;
|
|
13
|
+
static onMouseLeave: (e: MouseEvent) => void;
|
|
14
|
+
static onTouchStart: (e: TouchEvent) => void;
|
|
15
|
+
static onTouchEnd: (e: TouchEvent) => void;
|
|
16
|
+
}
|
package/package.json
CHANGED
|
@@ -325,3 +325,24 @@ button.btn-floating {
|
|
|
325
325
|
.btn-block {
|
|
326
326
|
display: block;
|
|
327
327
|
}
|
|
328
|
+
|
|
329
|
+
// Icon button - compact flat button for icons only
|
|
330
|
+
.btn-flat.btn-icon {
|
|
331
|
+
min-width: auto;
|
|
332
|
+
padding: 0 8px;
|
|
333
|
+
width: auto;
|
|
334
|
+
line-height: variables.$button-height;
|
|
335
|
+
background-color: transparent !important;
|
|
336
|
+
|
|
337
|
+
i {
|
|
338
|
+
margin: 0;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Ensure background stays transparent in all states
|
|
342
|
+
&:hover,
|
|
343
|
+
&:focus,
|
|
344
|
+
&:active,
|
|
345
|
+
&.active {
|
|
346
|
+
background-color: transparent !important;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
@@ -53,6 +53,12 @@
|
|
|
53
53
|
.material-icons {
|
|
54
54
|
font-size: 1rem;
|
|
55
55
|
}
|
|
56
|
+
|
|
57
|
+
svg {
|
|
58
|
+
width: 1rem !important;
|
|
59
|
+
height: 1rem !important;
|
|
60
|
+
flex-shrink: 0;
|
|
61
|
+
}
|
|
56
62
|
|
|
57
63
|
span {
|
|
58
64
|
font-size: 0.75rem;
|
|
@@ -84,6 +90,10 @@
|
|
|
84
90
|
.material-icons {
|
|
85
91
|
font-size: 1.25rem;
|
|
86
92
|
}
|
|
93
|
+
|
|
94
|
+
svg {
|
|
95
|
+
flex-shrink: 0;
|
|
96
|
+
}
|
|
87
97
|
}
|
|
88
98
|
|
|
89
99
|
// Navbar theme toggle specific styles
|