mithril-materialized 3.12.0 → 3.14.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/advanced.css +5 -0
- package/dist/button.d.ts +9 -0
- package/dist/collection.d.ts +2 -2
- package/dist/components.css +5 -0
- package/dist/core.css +5 -0
- package/dist/forms.css +5 -0
- package/dist/index.css +460 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +382 -85
- package/dist/index.js +383 -84
- package/dist/index.min.css +2 -2
- package/dist/index.umd.js +383 -84
- package/dist/likert-scale.d.ts +70 -0
- package/dist/material-icon.d.ts +2 -1
- package/dist/utilities.css +5 -0
- package/package.json +1 -1
- package/sass/components/_global.scss +7 -0
- package/sass/components/_likert-scale.scss +610 -0
- package/sass/materialize.scss +1 -1
package/dist/index.umd.js
CHANGED
|
@@ -622,6 +622,85 @@
|
|
|
622
622
|
},
|
|
623
623
|
});
|
|
624
624
|
|
|
625
|
+
const iconPaths = {
|
|
626
|
+
caret: [
|
|
627
|
+
'M7 10l5 5 5-5z', // arrow
|
|
628
|
+
'M0 0h24v24H0z', // background
|
|
629
|
+
],
|
|
630
|
+
close: [
|
|
631
|
+
'M18.3 5.71a1 1 0 0 0-1.41 0L12 10.59 7.11 5.7A1 1 0 0 0 5.7 7.11L10.59 12l-4.89 4.89a1 1 0 1 0 1.41 1.41L12 13.41l4.89 4.89a1 1 0 0 0 1.41-1.41L13.41 12l4.89-4.89a1 1 0 0 0 0-1.4z',
|
|
632
|
+
'M0 0h24v24H0z',
|
|
633
|
+
],
|
|
634
|
+
chevron: [
|
|
635
|
+
'M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z', // chevron down
|
|
636
|
+
'M0 0h24v24H0z', // background
|
|
637
|
+
],
|
|
638
|
+
chevron_left: [
|
|
639
|
+
'M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z', // chevron left
|
|
640
|
+
'M0 0h24v24H0z', // background
|
|
641
|
+
],
|
|
642
|
+
chevron_right: [
|
|
643
|
+
'M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z', // chevron right
|
|
644
|
+
'M0 0h24v24H0z', // background
|
|
645
|
+
],
|
|
646
|
+
menu: [
|
|
647
|
+
'M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z', // hamburger menu
|
|
648
|
+
'M0 0h24v24H0z', // background
|
|
649
|
+
],
|
|
650
|
+
expand: [
|
|
651
|
+
'M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z', // plus
|
|
652
|
+
'M0 0h24v24H0z', // background
|
|
653
|
+
],
|
|
654
|
+
collapse: [
|
|
655
|
+
'M19 13H5v-2h14v2z', // minus
|
|
656
|
+
'M0 0h24v24H0z', // background
|
|
657
|
+
],
|
|
658
|
+
check: [
|
|
659
|
+
'M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z', // checkmark
|
|
660
|
+
'M0 0h24v24H0z', // background
|
|
661
|
+
],
|
|
662
|
+
radio_checked: [
|
|
663
|
+
'M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z', // radio button checked
|
|
664
|
+
'M0 0h24v24H0z', // background
|
|
665
|
+
],
|
|
666
|
+
radio_unchecked: [
|
|
667
|
+
'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z', // radio button unchecked
|
|
668
|
+
'M0 0h24v24H0z', // background
|
|
669
|
+
],
|
|
670
|
+
light_mode: [
|
|
671
|
+
'M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5M2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1m18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1M11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1m0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1M5.99 4.58a.996.996 0 0 0-1.41 0 .996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41zm12.4 12.4a.996.996 0 0 0-1.41 0 .996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0a.996.996 0 0 0 0-1.41zm1.06-11a.996.996 0 0 0 0-1.41.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0zM7.05 18.4a.996.996 0 0 0 0-1.41.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0z',
|
|
672
|
+
'M0 0h24v24H0z', // background
|
|
673
|
+
],
|
|
674
|
+
dark_mode: [
|
|
675
|
+
'M12 3a9 9 0 1 0 9 9c0-.46-.04-.92-.1-1.36a5.39 5.39 0 0 1-4.4 2.26 5.4 5.4 0 0 1-3.14-9.8c-.44-.06-.9-.1-1.36-.1z',
|
|
676
|
+
'M0 0h24v24H0z', // background
|
|
677
|
+
],
|
|
678
|
+
delete: [
|
|
679
|
+
'M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z',
|
|
680
|
+
'M0 0h24v24H0z', // background
|
|
681
|
+
],
|
|
682
|
+
};
|
|
683
|
+
const MaterialIcon = () => {
|
|
684
|
+
return {
|
|
685
|
+
view: ({ attrs }) => {
|
|
686
|
+
var _a;
|
|
687
|
+
const { name, direction = 'down', style } = attrs, props = __rest(attrs, ["name", "direction", "style"]);
|
|
688
|
+
const rotationMap = {
|
|
689
|
+
down: 0,
|
|
690
|
+
up: 180,
|
|
691
|
+
left: 90,
|
|
692
|
+
right: -90,
|
|
693
|
+
};
|
|
694
|
+
const rotation = (_a = rotationMap[direction]) !== null && _a !== void 0 ? _a : 0;
|
|
695
|
+
const transform = rotation ? `rotate(${rotation}deg)` : undefined;
|
|
696
|
+
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', {
|
|
697
|
+
d,
|
|
698
|
+
fill: d.includes('M0 0h24v24H0z') ? 'none' : 'currentColor',
|
|
699
|
+
})));
|
|
700
|
+
},
|
|
701
|
+
};
|
|
702
|
+
};
|
|
703
|
+
|
|
625
704
|
/*!
|
|
626
705
|
* Waves Effect for Mithril Materialized
|
|
627
706
|
* Based on Waves v0.6.4 by Alfiana E. Sibuea
|
|
@@ -727,7 +806,7 @@
|
|
|
727
806
|
const ButtonFactory = (element, defaultClassNames, type = '') => {
|
|
728
807
|
return () => {
|
|
729
808
|
return {
|
|
730
|
-
view: ({ attrs }) => {
|
|
809
|
+
view: ({ attrs, children }) => {
|
|
731
810
|
const { tooltip, tooltipPosition, tooltipPostion, // Keep for backwards compatibility
|
|
732
811
|
iconName, iconClass, label, className, variant } = attrs, params = __rest(attrs, ["tooltip", "tooltipPosition", "tooltipPostion", "iconName", "iconClass", "label", "className", "variant"]);
|
|
733
812
|
// Use variant or fallback to factory type
|
|
@@ -743,7 +822,7 @@
|
|
|
743
822
|
ontouchstart: WavesEffect.onTouchStart,
|
|
744
823
|
ontouchend: WavesEffect.onTouchEnd
|
|
745
824
|
} : {};
|
|
746
|
-
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);
|
|
825
|
+
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, children);
|
|
747
826
|
},
|
|
748
827
|
};
|
|
749
828
|
};
|
|
@@ -755,6 +834,54 @@
|
|
|
755
834
|
const IconButton = ButtonFactory('button', 'btn-flat btn-icon waves-effect waves-teal', 'button');
|
|
756
835
|
const RoundIconButton = ButtonFactory('button', 'btn-floating btn-large waves-effect waves-light', 'button');
|
|
757
836
|
const SubmitButton = ButtonFactory('button', 'btn waves-effect waves-light', 'submit');
|
|
837
|
+
const RaisedIconButton = ButtonFactory('button', 'btn waves-effect waves-light', 'button');
|
|
838
|
+
const ConfirmButton = () => {
|
|
839
|
+
let isConfirming = false;
|
|
840
|
+
let isBlocked = false;
|
|
841
|
+
let timeoutId;
|
|
842
|
+
let blockTimeoutId;
|
|
843
|
+
const reset = () => {
|
|
844
|
+
isConfirming = false;
|
|
845
|
+
isBlocked = false;
|
|
846
|
+
m.redraw();
|
|
847
|
+
};
|
|
848
|
+
const unblock = () => {
|
|
849
|
+
isBlocked = false;
|
|
850
|
+
};
|
|
851
|
+
return {
|
|
852
|
+
onremove: () => {
|
|
853
|
+
window.clearTimeout(timeoutId);
|
|
854
|
+
window.clearTimeout(blockTimeoutId);
|
|
855
|
+
},
|
|
856
|
+
view: ({ attrs }) => {
|
|
857
|
+
const { iconName = 'delete', confirmIconName = 'check', confirmColor = 'red', timeout = 3000, clickDelay = 500, onFirstClick, onclick } = attrs, props = __rest(attrs, ["iconName", "confirmIconName", "confirmColor", "timeout", "clickDelay", "onFirstClick", "onclick"]);
|
|
858
|
+
const handleClick = (e) => {
|
|
859
|
+
e.preventDefault();
|
|
860
|
+
if (isBlocked)
|
|
861
|
+
return;
|
|
862
|
+
if (isConfirming) {
|
|
863
|
+
window.clearTimeout(timeoutId);
|
|
864
|
+
window.clearTimeout(blockTimeoutId); // Clean up safety
|
|
865
|
+
isConfirming = false;
|
|
866
|
+
onclick === null || onclick === void 0 ? void 0 : onclick(e);
|
|
867
|
+
}
|
|
868
|
+
else {
|
|
869
|
+
isConfirming = true;
|
|
870
|
+
isBlocked = true;
|
|
871
|
+
onFirstClick === null || onFirstClick === void 0 ? void 0 : onFirstClick();
|
|
872
|
+
timeoutId = window.setTimeout(reset, timeout);
|
|
873
|
+
blockTimeoutId = window.setTimeout(unblock, clickDelay);
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
const cn = isConfirming ? confirmColor : 'red-text';
|
|
877
|
+
const commonProps = Object.assign(Object.assign({}, props), { className: `${props.className || ''} ${cn}`, style: Object.assign(Object.assign(Object.assign({}, props.style), { display: 'flex', alignItems: 'center', justifyContent: 'center' }), (isConfirming ? { padding: '0 8px', width: 'auto', minWidth: 'auto' } : {})), onclick: handleClick });
|
|
878
|
+
if (isConfirming) {
|
|
879
|
+
return m(RaisedIconButton, commonProps, m(MaterialIcon, { name: confirmIconName }));
|
|
880
|
+
}
|
|
881
|
+
return m(IconButton, commonProps, m(MaterialIcon, { name: iconName }));
|
|
882
|
+
},
|
|
883
|
+
};
|
|
884
|
+
};
|
|
758
885
|
|
|
759
886
|
/**
|
|
760
887
|
* Materialize CSS Carousel component with dynamic positioning
|
|
@@ -1146,81 +1273,6 @@
|
|
|
1146
1273
|
};
|
|
1147
1274
|
};
|
|
1148
1275
|
|
|
1149
|
-
const iconPaths = {
|
|
1150
|
-
caret: [
|
|
1151
|
-
'M7 10l5 5 5-5z', // arrow
|
|
1152
|
-
'M0 0h24v24H0z', // background
|
|
1153
|
-
],
|
|
1154
|
-
close: [
|
|
1155
|
-
'M18.3 5.71a1 1 0 0 0-1.41 0L12 10.59 7.11 5.7A1 1 0 0 0 5.7 7.11L10.59 12l-4.89 4.89a1 1 0 1 0 1.41 1.41L12 13.41l4.89 4.89a1 1 0 0 0 1.41-1.41L13.41 12l4.89-4.89a1 1 0 0 0 0-1.4z',
|
|
1156
|
-
'M0 0h24v24H0z',
|
|
1157
|
-
],
|
|
1158
|
-
chevron: [
|
|
1159
|
-
'M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z', // chevron down
|
|
1160
|
-
'M0 0h24v24H0z', // background
|
|
1161
|
-
],
|
|
1162
|
-
chevron_left: [
|
|
1163
|
-
'M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z', // chevron left
|
|
1164
|
-
'M0 0h24v24H0z', // background
|
|
1165
|
-
],
|
|
1166
|
-
chevron_right: [
|
|
1167
|
-
'M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z', // chevron right
|
|
1168
|
-
'M0 0h24v24H0z', // background
|
|
1169
|
-
],
|
|
1170
|
-
menu: [
|
|
1171
|
-
'M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z', // hamburger menu
|
|
1172
|
-
'M0 0h24v24H0z', // background
|
|
1173
|
-
],
|
|
1174
|
-
expand: [
|
|
1175
|
-
'M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z', // plus
|
|
1176
|
-
'M0 0h24v24H0z', // background
|
|
1177
|
-
],
|
|
1178
|
-
collapse: [
|
|
1179
|
-
'M19 13H5v-2h14v2z', // minus
|
|
1180
|
-
'M0 0h24v24H0z', // background
|
|
1181
|
-
],
|
|
1182
|
-
check: [
|
|
1183
|
-
'M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z', // checkmark
|
|
1184
|
-
'M0 0h24v24H0z', // background
|
|
1185
|
-
],
|
|
1186
|
-
radio_checked: [
|
|
1187
|
-
'M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z', // radio button checked
|
|
1188
|
-
'M0 0h24v24H0z', // background
|
|
1189
|
-
],
|
|
1190
|
-
radio_unchecked: [
|
|
1191
|
-
'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z', // radio button unchecked
|
|
1192
|
-
'M0 0h24v24H0z', // background
|
|
1193
|
-
],
|
|
1194
|
-
light_mode: [
|
|
1195
|
-
'M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5M2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1m18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1M11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1m0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1M5.99 4.58a.996.996 0 0 0-1.41 0 .996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41zm12.4 12.4a.996.996 0 0 0-1.41 0 .996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0a.996.996 0 0 0 0-1.41zm1.06-11a.996.996 0 0 0 0-1.41.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0zM7.05 18.4a.996.996 0 0 0 0-1.41.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0z',
|
|
1196
|
-
'M0 0h24v24H0z', // background
|
|
1197
|
-
],
|
|
1198
|
-
dark_mode: [
|
|
1199
|
-
'M12 3a9 9 0 1 0 9 9c0-.46-.04-.92-.1-1.36a5.39 5.39 0 0 1-4.4 2.26 5.4 5.4 0 0 1-3.14-9.8c-.44-.06-.9-.1-1.36-.1z',
|
|
1200
|
-
'M0 0h24v24H0z', // background
|
|
1201
|
-
],
|
|
1202
|
-
};
|
|
1203
|
-
const MaterialIcon = () => {
|
|
1204
|
-
return {
|
|
1205
|
-
view: ({ attrs }) => {
|
|
1206
|
-
var _a;
|
|
1207
|
-
const { name, direction = 'down', style } = attrs, props = __rest(attrs, ["name", "direction", "style"]);
|
|
1208
|
-
const rotationMap = {
|
|
1209
|
-
down: 0,
|
|
1210
|
-
up: 180,
|
|
1211
|
-
left: 90,
|
|
1212
|
-
right: -90,
|
|
1213
|
-
};
|
|
1214
|
-
const rotation = (_a = rotationMap[direction]) !== null && _a !== void 0 ? _a : 0;
|
|
1215
|
-
const transform = rotation ? `rotate(${rotation}deg)` : undefined;
|
|
1216
|
-
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', {
|
|
1217
|
-
d,
|
|
1218
|
-
fill: d.includes('M0 0h24v24H0z') ? 'none' : 'currentColor',
|
|
1219
|
-
})));
|
|
1220
|
-
},
|
|
1221
|
-
};
|
|
1222
|
-
};
|
|
1223
|
-
|
|
1224
1276
|
const Chips = () => {
|
|
1225
1277
|
const state = {
|
|
1226
1278
|
chipsData: [],
|
|
@@ -1639,7 +1691,7 @@
|
|
|
1639
1691
|
const ListItem = () => {
|
|
1640
1692
|
return {
|
|
1641
1693
|
view: ({ attrs: { item, mode } }) => {
|
|
1642
|
-
const { title, content
|
|
1694
|
+
const { title, content, active, iconName, avatar, className, onclick } = item;
|
|
1643
1695
|
return mode === exports.CollectionMode.AVATAR
|
|
1644
1696
|
? m('li.collection-item.avatar', {
|
|
1645
1697
|
className: active ? 'active' : '',
|
|
@@ -1649,12 +1701,21 @@
|
|
|
1649
1701
|
? m('img.circle', { src: avatar })
|
|
1650
1702
|
: m('i.material-icons.circle', { className }, avatar),
|
|
1651
1703
|
m('span.title', title),
|
|
1652
|
-
m('p', m.trust(content)),
|
|
1653
|
-
m(SecondaryContent, item),
|
|
1654
|
-
])
|
|
1704
|
+
content ? (typeof content === 'string' ? m('p', m.trust(content)) : m('p', content)) : undefined,
|
|
1705
|
+
iconName ? m(SecondaryContent, item) : undefined,
|
|
1706
|
+
].filter(Boolean))
|
|
1655
1707
|
: m('li.collection-item', {
|
|
1656
1708
|
className: active ? 'active' : '',
|
|
1657
|
-
|
|
1709
|
+
onclick: onclick ? () => onclick(item) : undefined,
|
|
1710
|
+
}, content
|
|
1711
|
+
? m('div', [
|
|
1712
|
+
m('div', title),
|
|
1713
|
+
typeof content === 'string' ? m('p.secondary-text', content) : content,
|
|
1714
|
+
iconName ? m(SecondaryContent, item) : undefined,
|
|
1715
|
+
].filter(Boolean))
|
|
1716
|
+
: iconName
|
|
1717
|
+
? m('div', [title, m(SecondaryContent, item)])
|
|
1718
|
+
: title);
|
|
1658
1719
|
},
|
|
1659
1720
|
};
|
|
1660
1721
|
};
|
|
@@ -10755,12 +10816,12 @@
|
|
|
10755
10816
|
const RatingItem = () => {
|
|
10756
10817
|
return {
|
|
10757
10818
|
view: ({ attrs }) => {
|
|
10758
|
-
const { index, displayValue, step, icons, allowHalfSteps, disabled, onclick, onmouseover } = attrs;
|
|
10819
|
+
const { index, displayValue, step, icons, allowHalfSteps, disabled, showTooltip, tooltipLabel, onclick, onmouseover, } = attrs;
|
|
10759
10820
|
const itemValue = (index + 1) * step;
|
|
10760
10821
|
// Calculate fill state based on displayValue vs itemValue
|
|
10761
10822
|
const diff = displayValue - itemValue;
|
|
10762
10823
|
const fillState = diff >= 0 ? 'full' : allowHalfSteps && diff >= -step / 2 ? 'half' : 'empty';
|
|
10763
|
-
return m('.rating__item', {
|
|
10824
|
+
return m('.rating__item.no-select', {
|
|
10764
10825
|
className: [
|
|
10765
10826
|
fillState === 'full' ? 'rating__item--filled' : '',
|
|
10766
10827
|
fillState === 'half' ? 'rating__item--half' : '',
|
|
@@ -10781,6 +10842,8 @@
|
|
|
10781
10842
|
clipPath: fillState === 'half' ? 'inset(0 50% 0 0)' : undefined,
|
|
10782
10843
|
},
|
|
10783
10844
|
}, typeof icons.filled === 'string' ? icons.filled : m(icons.filled)),
|
|
10845
|
+
// Tooltip
|
|
10846
|
+
showTooltip && tooltipLabel && m('.rating__tooltip', tooltipLabel),
|
|
10784
10847
|
]);
|
|
10785
10848
|
},
|
|
10786
10849
|
};
|
|
@@ -10852,6 +10915,7 @@
|
|
|
10852
10915
|
},
|
|
10853
10916
|
// Array.from({ length: itemCount }, (_, i) => renderRatingItem(attrs, i))
|
|
10854
10917
|
[...Array(itemCount)].map((_, i) => {
|
|
10918
|
+
var _a;
|
|
10855
10919
|
const itemValue = (i + 1) * step;
|
|
10856
10920
|
return m(RatingItem, {
|
|
10857
10921
|
key: `rating-item-${i}`,
|
|
@@ -10861,6 +10925,8 @@
|
|
|
10861
10925
|
icons: Object.assign(Object.assign({}, DEFAULT_ICONS), attrs.icon),
|
|
10862
10926
|
allowHalfSteps: attrs.allowHalfSteps,
|
|
10863
10927
|
disabled: attrs.disabled,
|
|
10928
|
+
showTooltip: attrs.showTooltips,
|
|
10929
|
+
tooltipLabel: (_a = attrs.tooltipLabels) === null || _a === void 0 ? void 0 : _a[i],
|
|
10864
10930
|
onclick: () => handleItemClick(attrs, itemValue),
|
|
10865
10931
|
onmouseover: () => handleItemHover(attrs, itemValue),
|
|
10866
10932
|
});
|
|
@@ -10876,6 +10942,237 @@
|
|
|
10876
10942
|
};
|
|
10877
10943
|
};
|
|
10878
10944
|
|
|
10945
|
+
/** Create a LikertScale component */
|
|
10946
|
+
const LikertScale = () => {
|
|
10947
|
+
const state = {
|
|
10948
|
+
id: uniqueId(),
|
|
10949
|
+
groupId: uniqueId(),
|
|
10950
|
+
internalValue: undefined,
|
|
10951
|
+
isFocused: false,
|
|
10952
|
+
};
|
|
10953
|
+
const isControlled = (attrs) => typeof attrs.value !== 'undefined' && typeof attrs.onchange === 'function';
|
|
10954
|
+
const getCurrentValue = (attrs) => {
|
|
10955
|
+
var _a, _b;
|
|
10956
|
+
const controlled = isControlled(attrs);
|
|
10957
|
+
const isNonInteractive = attrs.readonly || attrs.disabled;
|
|
10958
|
+
if (controlled) {
|
|
10959
|
+
return attrs.value;
|
|
10960
|
+
}
|
|
10961
|
+
// Non-interactive components: prefer defaultValue, fallback to value
|
|
10962
|
+
if (isNonInteractive) {
|
|
10963
|
+
return (_a = attrs.defaultValue) !== null && _a !== void 0 ? _a : attrs.value;
|
|
10964
|
+
}
|
|
10965
|
+
// Interactive uncontrolled: use internal state (user can change it)
|
|
10966
|
+
return (_b = state.internalValue) !== null && _b !== void 0 ? _b : attrs.defaultValue;
|
|
10967
|
+
};
|
|
10968
|
+
const getLabelText = (value, min, max, getLabelFn) => {
|
|
10969
|
+
if (getLabelFn && value !== undefined) {
|
|
10970
|
+
return getLabelFn(value, min, max);
|
|
10971
|
+
}
|
|
10972
|
+
if (value === undefined) {
|
|
10973
|
+
return `No selection, please choose a value between ${min} and ${max}`;
|
|
10974
|
+
}
|
|
10975
|
+
return `Selected ${value} out of ${min} to ${max}`;
|
|
10976
|
+
};
|
|
10977
|
+
const getSizeClass = (size = 'medium') => {
|
|
10978
|
+
switch (size) {
|
|
10979
|
+
case 'small':
|
|
10980
|
+
return 'likert-scale--small';
|
|
10981
|
+
case 'large':
|
|
10982
|
+
return 'likert-scale--large';
|
|
10983
|
+
default:
|
|
10984
|
+
return 'likert-scale--medium';
|
|
10985
|
+
}
|
|
10986
|
+
};
|
|
10987
|
+
const getDensityClass = (density = 'standard') => {
|
|
10988
|
+
switch (density) {
|
|
10989
|
+
case 'compact':
|
|
10990
|
+
return 'likert-scale--compact';
|
|
10991
|
+
case 'comfortable':
|
|
10992
|
+
return 'likert-scale--comfortable';
|
|
10993
|
+
default:
|
|
10994
|
+
return 'likert-scale--standard';
|
|
10995
|
+
}
|
|
10996
|
+
};
|
|
10997
|
+
const getLayoutClass = (layout = 'responsive') => {
|
|
10998
|
+
switch (layout) {
|
|
10999
|
+
case 'horizontal':
|
|
11000
|
+
return 'likert-scale--horizontal';
|
|
11001
|
+
case 'vertical':
|
|
11002
|
+
return 'likert-scale--vertical';
|
|
11003
|
+
default:
|
|
11004
|
+
return 'likert-scale--responsive';
|
|
11005
|
+
}
|
|
11006
|
+
};
|
|
11007
|
+
const handleChange = (attrs, newValue) => {
|
|
11008
|
+
var _a;
|
|
11009
|
+
if (attrs.readonly || attrs.disabled)
|
|
11010
|
+
return;
|
|
11011
|
+
if (!isControlled(attrs)) {
|
|
11012
|
+
state.internalValue = newValue;
|
|
11013
|
+
}
|
|
11014
|
+
(_a = attrs.onchange) === null || _a === void 0 ? void 0 : _a.call(attrs, newValue);
|
|
11015
|
+
};
|
|
11016
|
+
const handleKeyDown = (attrs, e) => {
|
|
11017
|
+
if (attrs.readonly || attrs.disabled)
|
|
11018
|
+
return;
|
|
11019
|
+
const min = attrs.min || 1;
|
|
11020
|
+
const max = attrs.max || 5;
|
|
11021
|
+
const step = attrs.step || 1;
|
|
11022
|
+
const currentValue = getCurrentValue(attrs);
|
|
11023
|
+
let newValue = currentValue;
|
|
11024
|
+
switch (e.key) {
|
|
11025
|
+
case 'ArrowRight':
|
|
11026
|
+
case 'ArrowUp':
|
|
11027
|
+
e.preventDefault();
|
|
11028
|
+
newValue = currentValue !== undefined ? Math.min(max, currentValue + step) : min;
|
|
11029
|
+
break;
|
|
11030
|
+
case 'ArrowLeft':
|
|
11031
|
+
case 'ArrowDown':
|
|
11032
|
+
e.preventDefault();
|
|
11033
|
+
newValue = currentValue !== undefined ? Math.max(min, currentValue - step) : min;
|
|
11034
|
+
break;
|
|
11035
|
+
case 'Home':
|
|
11036
|
+
e.preventDefault();
|
|
11037
|
+
newValue = min;
|
|
11038
|
+
break;
|
|
11039
|
+
case 'End':
|
|
11040
|
+
e.preventDefault();
|
|
11041
|
+
newValue = max;
|
|
11042
|
+
break;
|
|
11043
|
+
default:
|
|
11044
|
+
return;
|
|
11045
|
+
}
|
|
11046
|
+
if (newValue !== currentValue) {
|
|
11047
|
+
handleChange(attrs, newValue);
|
|
11048
|
+
}
|
|
11049
|
+
};
|
|
11050
|
+
const LikertScaleItem = () => {
|
|
11051
|
+
return {
|
|
11052
|
+
view: ({ attrs }) => {
|
|
11053
|
+
const { value, currentValue, showNumber, showTooltip, tooltipLabel, groupId, name, disabled, readonly, onchange, } = attrs;
|
|
11054
|
+
const radioId = `${groupId}-${value}`;
|
|
11055
|
+
const isChecked = currentValue === value;
|
|
11056
|
+
return m('.likert-scale__item.no-select', {
|
|
11057
|
+
className: [
|
|
11058
|
+
isChecked ? 'likert-scale__item--checked' : '',
|
|
11059
|
+
disabled ? 'likert-scale__item--disabled' : '',
|
|
11060
|
+
readonly ? 'likert-scale__item--readonly' : '',
|
|
11061
|
+
]
|
|
11062
|
+
.filter(Boolean)
|
|
11063
|
+
.join(' '),
|
|
11064
|
+
}, [
|
|
11065
|
+
// Number label (optional)
|
|
11066
|
+
showNumber && m('.likert-scale__number', value),
|
|
11067
|
+
// Radio button input
|
|
11068
|
+
m('input[type=radio].likert-scale__input', {
|
|
11069
|
+
id: radioId,
|
|
11070
|
+
name: name || groupId,
|
|
11071
|
+
value: value,
|
|
11072
|
+
checked: isChecked,
|
|
11073
|
+
disabled: disabled || readonly,
|
|
11074
|
+
onchange: () => onchange(value),
|
|
11075
|
+
}),
|
|
11076
|
+
// Label for radio button
|
|
11077
|
+
m('label.likert-scale__label', {
|
|
11078
|
+
for: radioId,
|
|
11079
|
+
}),
|
|
11080
|
+
// Tooltip (optional)
|
|
11081
|
+
showTooltip && tooltipLabel && m('.likert-scale__tooltip', tooltipLabel),
|
|
11082
|
+
]);
|
|
11083
|
+
},
|
|
11084
|
+
};
|
|
11085
|
+
};
|
|
11086
|
+
return {
|
|
11087
|
+
oninit: ({ attrs }) => {
|
|
11088
|
+
const controlled = isControlled(attrs);
|
|
11089
|
+
const isNonInteractive = attrs.readonly || attrs.disabled;
|
|
11090
|
+
// Warn developer for improper controlled usage
|
|
11091
|
+
if (attrs.value !== undefined && !controlled && !isNonInteractive) {
|
|
11092
|
+
console.warn(`LikertScale component received 'value' prop without 'onchange' handler. ` +
|
|
11093
|
+
`Use 'defaultValue' for uncontrolled components or add 'onchange' for controlled components.`);
|
|
11094
|
+
}
|
|
11095
|
+
if (!controlled) {
|
|
11096
|
+
state.internalValue = attrs.defaultValue;
|
|
11097
|
+
}
|
|
11098
|
+
},
|
|
11099
|
+
view: ({ attrs }) => {
|
|
11100
|
+
const { min = 1, max = 5, step = 1, size = 'medium', density = 'standard', layout = 'responsive', className = '', style = {}, readonly = false, disabled = false, id = state.id, name, label, description, isMandatory, startLabel, middleLabel, endLabel, showNumbers = false, showTooltips = false, tooltipLabels, alignLabels = false } = attrs, ariaAttrs = __rest(attrs, ["min", "max", "step", "size", "density", "layout", "className", "style", "readonly", "disabled", "id", "name", "label", "description", "isMandatory", "startLabel", "middleLabel", "endLabel", "showNumbers", "showTooltips", "tooltipLabels", "alignLabels"]);
|
|
11101
|
+
const currentValue = getCurrentValue(attrs);
|
|
11102
|
+
const itemCount = Math.floor((max - min) / step) + 1;
|
|
11103
|
+
// Generate scale values
|
|
11104
|
+
const scaleValues = Array.from({ length: itemCount }, (_, i) => min + i * step);
|
|
11105
|
+
return m('.likert-scale', {
|
|
11106
|
+
className: [
|
|
11107
|
+
'likert-scale',
|
|
11108
|
+
getSizeClass(size),
|
|
11109
|
+
getDensityClass(density),
|
|
11110
|
+
getLayoutClass(layout),
|
|
11111
|
+
readonly ? 'likert-scale--readonly' : '',
|
|
11112
|
+
disabled ? 'likert-scale--disabled' : '',
|
|
11113
|
+
state.isFocused ? 'likert-scale--focused' : '',
|
|
11114
|
+
alignLabels ? 'likert-scale--aligned' : '',
|
|
11115
|
+
className,
|
|
11116
|
+
]
|
|
11117
|
+
.filter(Boolean)
|
|
11118
|
+
.join(' '),
|
|
11119
|
+
style,
|
|
11120
|
+
id,
|
|
11121
|
+
role: 'radiogroup',
|
|
11122
|
+
'aria-label': ariaAttrs['aria-label'] || attrs.ariaLabel || label || `Rating scale from ${min} to ${max}`,
|
|
11123
|
+
'aria-labelledby': ariaAttrs['aria-labelledby'],
|
|
11124
|
+
'aria-readonly': readonly,
|
|
11125
|
+
'aria-disabled': disabled,
|
|
11126
|
+
onkeydown: (e) => handleKeyDown(attrs, e),
|
|
11127
|
+
onfocus: () => {
|
|
11128
|
+
state.isFocused = true;
|
|
11129
|
+
},
|
|
11130
|
+
onblur: () => {
|
|
11131
|
+
state.isFocused = false;
|
|
11132
|
+
},
|
|
11133
|
+
tabindex: readonly || disabled ? -1 : 0,
|
|
11134
|
+
}, [
|
|
11135
|
+
// Label section (only text label, not the description)
|
|
11136
|
+
label &&
|
|
11137
|
+
m('.likert-scale__question-label', [
|
|
11138
|
+
m('span', label + (isMandatory ? ' *' : '')),
|
|
11139
|
+
description && m('.likert-scale__description', m.trust(description)),
|
|
11140
|
+
]),
|
|
11141
|
+
// Scale section container
|
|
11142
|
+
m('.likert-scale__scale-container', [
|
|
11143
|
+
// Scale items with numbers
|
|
11144
|
+
m('.likert-scale__scale', scaleValues.map((value) => m(LikertScaleItem, {
|
|
11145
|
+
key: `likert-item-${value}`,
|
|
11146
|
+
value,
|
|
11147
|
+
currentValue,
|
|
11148
|
+
showNumber: showNumbers,
|
|
11149
|
+
showTooltip: showTooltips,
|
|
11150
|
+
tooltipLabel: tooltipLabels === null || tooltipLabels === void 0 ? void 0 : tooltipLabels[value - min],
|
|
11151
|
+
groupId: state.groupId,
|
|
11152
|
+
name,
|
|
11153
|
+
disabled,
|
|
11154
|
+
readonly,
|
|
11155
|
+
onchange: (v) => handleChange(attrs, v),
|
|
11156
|
+
}))),
|
|
11157
|
+
// Scale anchors
|
|
11158
|
+
(startLabel || middleLabel || endLabel) &&
|
|
11159
|
+
m('.likert-scale__anchors', [
|
|
11160
|
+
startLabel && m('.likert-scale__anchor.likert-scale__anchor--start', startLabel),
|
|
11161
|
+
middleLabel && m('.likert-scale__anchor.likert-scale__anchor--middle', middleLabel),
|
|
11162
|
+
endLabel && m('.likert-scale__anchor.likert-scale__anchor--end', endLabel),
|
|
11163
|
+
]),
|
|
11164
|
+
]),
|
|
11165
|
+
// Screen reader text
|
|
11166
|
+
m('.likert-scale__sr-only', {
|
|
11167
|
+
className: 'likert-scale__sr-only',
|
|
11168
|
+
'aria-live': 'polite',
|
|
11169
|
+
'aria-atomic': 'true',
|
|
11170
|
+
}, getLabelText(currentValue, min, max, attrs.getLabelText)),
|
|
11171
|
+
]);
|
|
11172
|
+
},
|
|
11173
|
+
};
|
|
11174
|
+
};
|
|
11175
|
+
|
|
10879
11176
|
/**
|
|
10880
11177
|
* ToggleButton component.
|
|
10881
11178
|
*
|
|
@@ -11210,6 +11507,7 @@
|
|
|
11210
11507
|
exports.CollapsibleItem = CollapsibleItem;
|
|
11211
11508
|
exports.Collection = Collection;
|
|
11212
11509
|
exports.ColorInput = ColorInput;
|
|
11510
|
+
exports.ConfirmButton = ConfirmButton;
|
|
11213
11511
|
exports.DataTable = DataTable;
|
|
11214
11512
|
exports.DatePicker = DatePicker;
|
|
11215
11513
|
exports.DigitalClock = DigitalClock;
|
|
@@ -11227,6 +11525,7 @@
|
|
|
11227
11525
|
exports.InputCheckbox = InputCheckbox;
|
|
11228
11526
|
exports.Label = Label;
|
|
11229
11527
|
exports.LargeButton = LargeButton;
|
|
11528
|
+
exports.LikertScale = LikertScale;
|
|
11230
11529
|
exports.LinearProgress = LinearProgress;
|
|
11231
11530
|
exports.ListItem = ListItem;
|
|
11232
11531
|
exports.Mandatory = Mandatory;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { FactoryComponent, Attributes } from 'mithril';
|
|
2
|
+
/** Likert scale component size options */
|
|
3
|
+
export type LikertScaleSize = 'small' | 'medium' | 'large';
|
|
4
|
+
/** Likert scale component density options */
|
|
5
|
+
export type LikertScaleDensity = 'compact' | 'standard' | 'comfortable';
|
|
6
|
+
/** Likert scale layout options */
|
|
7
|
+
export type LikertScaleLayout = 'horizontal' | 'vertical' | 'responsive';
|
|
8
|
+
/** Likert scale component attributes */
|
|
9
|
+
export interface LikertScaleAttrs<T extends number = number> extends Attributes {
|
|
10
|
+
/** Minimum scale value (default: 1) */
|
|
11
|
+
min?: number;
|
|
12
|
+
/** Maximum scale value (default: 5) */
|
|
13
|
+
max?: number;
|
|
14
|
+
/** Step size for scale increments (default: 1) */
|
|
15
|
+
step?: number;
|
|
16
|
+
/** Current value for controlled mode */
|
|
17
|
+
value?: T;
|
|
18
|
+
/** Initial value for uncontrolled mode */
|
|
19
|
+
defaultValue?: T;
|
|
20
|
+
/** Callback when value changes */
|
|
21
|
+
onchange?: (value: T) => void;
|
|
22
|
+
/** Question/prompt text */
|
|
23
|
+
label?: string;
|
|
24
|
+
/** Helper text description */
|
|
25
|
+
description?: string;
|
|
26
|
+
/** Anchor label for minimum value (e.g., "Very Unhappy") */
|
|
27
|
+
startLabel?: string;
|
|
28
|
+
/** Anchor label for middle value (optional, e.g., "Neutral") */
|
|
29
|
+
middleLabel?: string;
|
|
30
|
+
/** Anchor label for maximum value (e.g., "Very Happy") */
|
|
31
|
+
endLabel?: string;
|
|
32
|
+
/** Whether to display numeric values (default: false) */
|
|
33
|
+
showNumbers?: boolean;
|
|
34
|
+
/** Whether to show tooltips on hover (default: false) */
|
|
35
|
+
showTooltips?: boolean;
|
|
36
|
+
/** Custom tooltip labels for each value */
|
|
37
|
+
tooltipLabels?: string[];
|
|
38
|
+
/** Density variant (default: 'standard') */
|
|
39
|
+
density?: LikertScaleDensity;
|
|
40
|
+
/** Size variant (default: 'medium') */
|
|
41
|
+
size?: LikertScaleSize;
|
|
42
|
+
/** Layout mode (default: 'responsive' = horizontal on desktop, vertical on mobile) */
|
|
43
|
+
layout?: LikertScaleLayout;
|
|
44
|
+
/** HTML ID for the component */
|
|
45
|
+
id?: string;
|
|
46
|
+
/** Name for form submission */
|
|
47
|
+
name?: string;
|
|
48
|
+
/** Whether the component is disabled */
|
|
49
|
+
disabled?: boolean;
|
|
50
|
+
/** Whether the component is read-only */
|
|
51
|
+
readonly?: boolean;
|
|
52
|
+
/** If true, add a mandatory '*' after the label */
|
|
53
|
+
isMandatory?: boolean;
|
|
54
|
+
/** ARIA label for the component */
|
|
55
|
+
'aria-label'?: string;
|
|
56
|
+
/** ARIA label for the component (camelCase alternative) */
|
|
57
|
+
ariaLabel?: string;
|
|
58
|
+
/** ARIA labelledby reference */
|
|
59
|
+
'aria-labelledby'?: string;
|
|
60
|
+
/** Function to get label text for accessibility */
|
|
61
|
+
getLabelText?: (value: number, min: number, max: number) => string;
|
|
62
|
+
/** Class name for the container */
|
|
63
|
+
className?: string;
|
|
64
|
+
/** Additional CSS styles */
|
|
65
|
+
style?: any;
|
|
66
|
+
/** Use CSS grid for label/scale alignment in multi-question surveys (default: false) */
|
|
67
|
+
alignLabels?: boolean;
|
|
68
|
+
}
|
|
69
|
+
/** Create a LikertScale component */
|
|
70
|
+
export declare const LikertScale: FactoryComponent<LikertScaleAttrs>;
|
package/dist/material-icon.d.ts
CHANGED
|
@@ -13,8 +13,9 @@ declare const iconPaths: {
|
|
|
13
13
|
readonly radio_unchecked: readonly ["M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z", "M0 0h24v24H0z"];
|
|
14
14
|
readonly light_mode: readonly ["M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5M2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1m18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1M11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1m0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1M5.99 4.58a.996.996 0 0 0-1.41 0 .996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41zm12.4 12.4a.996.996 0 0 0-1.41 0 .996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0a.996.996 0 0 0 0-1.41zm1.06-11a.996.996 0 0 0 0-1.41.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0zM7.05 18.4a.996.996 0 0 0 0-1.41.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0z", "M0 0h24v24H0z"];
|
|
15
15
|
readonly dark_mode: readonly ["M12 3a9 9 0 1 0 9 9c0-.46-.04-.92-.1-1.36a5.39 5.39 0 0 1-4.4 2.26 5.4 5.4 0 0 1-3.14-9.8c-.44-.06-.9-.1-1.36-.1z", "M0 0h24v24H0z"];
|
|
16
|
+
readonly delete: readonly ["M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z", "M0 0h24v24H0z"];
|
|
16
17
|
};
|
|
17
|
-
type IconName = keyof typeof iconPaths;
|
|
18
|
+
export type IconName = keyof typeof iconPaths;
|
|
18
19
|
export interface MaterialIconAttrs extends Attributes {
|
|
19
20
|
name: IconName;
|
|
20
21
|
direction?: 'up' | 'down' | 'left' | 'right';
|
package/dist/utilities.css
CHANGED
|
@@ -2778,6 +2778,11 @@ td, th {
|
|
|
2778
2778
|
.collection .collection-item.active .secondary-content {
|
|
2779
2779
|
color: var(--mm-text-on-primary, #fff);
|
|
2780
2780
|
}
|
|
2781
|
+
.collection .collection-item .secondary-text {
|
|
2782
|
+
color: var(--mm-text-secondary, rgba(0, 0, 0, 0.54));
|
|
2783
|
+
font-size: 0.9rem;
|
|
2784
|
+
margin-top: 4px;
|
|
2785
|
+
}
|
|
2781
2786
|
.collection a.collection-item {
|
|
2782
2787
|
display: block;
|
|
2783
2788
|
transition: 0.25s;
|