mithril-materialized 3.2.2 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -27
- package/dist/advanced.css +2 -2
- package/dist/components.css +241 -3
- package/dist/core.css +3 -3
- package/dist/forms.css +3 -3
- package/dist/index.css +242 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +360 -17
- package/dist/index.js +360 -16
- package/dist/index.min.css +2 -2
- package/dist/index.umd.js +360 -16
- package/dist/rating.d.ts +65 -0
- package/dist/switch.d.ts +2 -2
- package/dist/utilities.css +2 -2
- package/package.json +1 -1
- package/sass/components/_datatable.scss +1 -1
- package/sass/components/_rating.scss +341 -0
- package/sass/components/_theme-variables.scss +9 -0
- package/sass/components/_variables.scss +2 -1
- package/sass/components/forms/_input-fields.scss +1 -1
- package/sass/materialize.scss +2 -1
package/dist/index.esm.js
CHANGED
|
@@ -2851,20 +2851,40 @@ const TextArea = () => {
|
|
|
2851
2851
|
state.height = undefined;
|
|
2852
2852
|
}
|
|
2853
2853
|
};
|
|
2854
|
-
const isControlled = (attrs) => attrs.value !== undefined && attrs.oninput !== undefined;
|
|
2854
|
+
const isControlled = (attrs) => attrs.value !== undefined && (attrs.oninput !== undefined || attrs.onchange !== undefined);
|
|
2855
2855
|
return {
|
|
2856
2856
|
oninit: ({ attrs }) => {
|
|
2857
|
+
const controlled = isControlled(attrs);
|
|
2858
|
+
const isNonInteractive = attrs.readonly || attrs.disabled;
|
|
2859
|
+
// Warn developer for improper controlled usage
|
|
2860
|
+
if (attrs.value !== undefined && !controlled && !isNonInteractive) {
|
|
2861
|
+
console.warn(`TextArea received 'value' prop without 'oninput' or 'onchange' handler. ` +
|
|
2862
|
+
`Use 'defaultValue' for uncontrolled components or add an event handler for controlled components.`);
|
|
2863
|
+
}
|
|
2857
2864
|
// Initialize internal value for uncontrolled mode
|
|
2858
|
-
if (!
|
|
2865
|
+
if (!controlled) {
|
|
2859
2866
|
state.internalValue = attrs.defaultValue || '';
|
|
2860
2867
|
}
|
|
2861
2868
|
},
|
|
2862
2869
|
onremove: () => {
|
|
2863
2870
|
},
|
|
2864
2871
|
view: ({ attrs }) => {
|
|
2872
|
+
var _a, _b, _c, _d;
|
|
2865
2873
|
const { className = 'col s12', helperText, iconName, id = state.id, value, placeholder, isMandatory, label, maxLength, oninput, onchange, onkeydown, onkeypress, onkeyup, onblur, style } = attrs, params = __rest(attrs, ["className", "helperText", "iconName", "id", "value", "placeholder", "isMandatory", "label", "maxLength", "oninput", "onchange", "onkeydown", "onkeypress", "onkeyup", "onblur", "style"]);
|
|
2866
2874
|
const controlled = isControlled(attrs);
|
|
2867
|
-
const
|
|
2875
|
+
const isNonInteractive = attrs.readonly || attrs.disabled;
|
|
2876
|
+
let currentValue;
|
|
2877
|
+
if (controlled) {
|
|
2878
|
+
currentValue = value || '';
|
|
2879
|
+
}
|
|
2880
|
+
else if (isNonInteractive) {
|
|
2881
|
+
// Non-interactive components: prefer defaultValue, fallback to value
|
|
2882
|
+
currentValue = (_b = (_a = attrs.defaultValue) !== null && _a !== void 0 ? _a : value) !== null && _b !== void 0 ? _b : '';
|
|
2883
|
+
}
|
|
2884
|
+
else {
|
|
2885
|
+
// Interactive uncontrolled: use internal state
|
|
2886
|
+
currentValue = (_d = (_c = state.internalValue) !== null && _c !== void 0 ? _c : attrs.defaultValue) !== null && _d !== void 0 ? _d : '';
|
|
2887
|
+
}
|
|
2868
2888
|
return [
|
|
2869
2889
|
// Hidden div for height measurement - positioned outside the input-field
|
|
2870
2890
|
m('.hiddendiv', {
|
|
@@ -2995,7 +3015,8 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
2995
3015
|
isDragging: false,
|
|
2996
3016
|
activeThumb: null,
|
|
2997
3017
|
};
|
|
2998
|
-
const isControlled = (attrs) => 'value' in attrs && typeof attrs.value !== 'undefined' &&
|
|
3018
|
+
const isControlled = (attrs) => 'value' in attrs && typeof attrs.value !== 'undefined' &&
|
|
3019
|
+
(typeof attrs.oninput === 'function' || typeof attrs.onchange === 'function');
|
|
2999
3020
|
const getValue = (target) => {
|
|
3000
3021
|
const val = target.value;
|
|
3001
3022
|
return (val ? (type === 'number' || type === 'range' ? +val : val) : val);
|
|
@@ -3041,8 +3062,15 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
3041
3062
|
// Range slider rendering functions are now in separate module
|
|
3042
3063
|
return {
|
|
3043
3064
|
oninit: ({ attrs }) => {
|
|
3065
|
+
const controlled = isControlled(attrs);
|
|
3066
|
+
const isNonInteractive = attrs.readonly || attrs.disabled;
|
|
3067
|
+
// Warn developer for improper controlled usage
|
|
3068
|
+
if (attrs.value !== undefined && !controlled && !isNonInteractive) {
|
|
3069
|
+
console.warn(`${type} input received 'value' prop without 'oninput' or 'onchange' handler. ` +
|
|
3070
|
+
`Use 'defaultValue' for uncontrolled components or add an event handler for controlled components.`);
|
|
3071
|
+
}
|
|
3044
3072
|
// Initialize internal value if not in controlled mode
|
|
3045
|
-
if (!
|
|
3073
|
+
if (!controlled) {
|
|
3046
3074
|
const isNumeric = ['number', 'range'].includes(type);
|
|
3047
3075
|
if (attrs.defaultValue !== undefined) {
|
|
3048
3076
|
if (isNumeric) {
|
|
@@ -3058,7 +3086,7 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
3058
3086
|
}
|
|
3059
3087
|
},
|
|
3060
3088
|
view: ({ attrs }) => {
|
|
3061
|
-
var _a, _b;
|
|
3089
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3062
3090
|
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"]);
|
|
3063
3091
|
// const attributes = toAttrs(params);
|
|
3064
3092
|
const cn = [newRow ? 'clear' : '', defaultClass, className].filter(Boolean).join(' ').trim() || undefined;
|
|
@@ -3078,7 +3106,19 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
3078
3106
|
}
|
|
3079
3107
|
const isNumeric = ['number', 'range'].includes(type);
|
|
3080
3108
|
const controlled = isControlled(attrs);
|
|
3081
|
-
const
|
|
3109
|
+
const isNonInteractive = attrs.readonly || attrs.disabled;
|
|
3110
|
+
let value;
|
|
3111
|
+
if (controlled) {
|
|
3112
|
+
value = attrs.value;
|
|
3113
|
+
}
|
|
3114
|
+
else if (isNonInteractive) {
|
|
3115
|
+
// Non-interactive components: prefer defaultValue, fallback to value
|
|
3116
|
+
value = ((_c = (_b = attrs.defaultValue) !== null && _b !== void 0 ? _b : attrs.value) !== null && _c !== void 0 ? _c : (isNumeric ? 0 : ''));
|
|
3117
|
+
}
|
|
3118
|
+
else {
|
|
3119
|
+
// Interactive uncontrolled: use internal state
|
|
3120
|
+
value = ((_e = (_d = state.internalValue) !== null && _d !== void 0 ? _d : attrs.defaultValue) !== null && _e !== void 0 ? _e : (isNumeric ? 0 : ''));
|
|
3121
|
+
}
|
|
3082
3122
|
const rangeType = type === 'range' && !attrs.minmax;
|
|
3083
3123
|
return m('.input-field', { className: cn, style }, [
|
|
3084
3124
|
iconName ? m('i.material-icons.prefix', iconName) : undefined,
|
|
@@ -3244,7 +3284,7 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
3244
3284
|
}
|
|
3245
3285
|
} })),
|
|
3246
3286
|
// Clear button - only for text inputs with canClear enabled and has content
|
|
3247
|
-
canClear && type === 'text' && ((
|
|
3287
|
+
canClear && type === 'text' && ((_f = state.inputElement) === null || _f === void 0 ? void 0 : _f.value)
|
|
3248
3288
|
? m(MaterialIcon, {
|
|
3249
3289
|
name: 'close',
|
|
3250
3290
|
className: 'input-clear-btn',
|
|
@@ -5641,17 +5681,35 @@ const RadioButtons = () => {
|
|
|
5641
5681
|
return {
|
|
5642
5682
|
oninit: ({ attrs }) => {
|
|
5643
5683
|
state.componentId = attrs.id || uniqueId();
|
|
5684
|
+
const controlled = isControlled(attrs);
|
|
5685
|
+
// Warn developer for improper controlled usage
|
|
5686
|
+
if (attrs.checkedId !== undefined && !controlled && !attrs.disabled) {
|
|
5687
|
+
console.warn(`RadioButtons component received 'checkedId' prop without 'onchange' handler. ` +
|
|
5688
|
+
`Use 'defaultCheckedId' for uncontrolled components or add 'onchange' for controlled components.`);
|
|
5689
|
+
}
|
|
5644
5690
|
// Initialize internal state for uncontrolled mode
|
|
5645
|
-
if (!
|
|
5691
|
+
if (!controlled) {
|
|
5646
5692
|
state.internalCheckedId = attrs.defaultCheckedId;
|
|
5647
5693
|
}
|
|
5648
5694
|
},
|
|
5649
5695
|
view: ({ attrs }) => {
|
|
5696
|
+
var _a, _b;
|
|
5650
5697
|
const { checkedId, newRow, className = 'col s12', label = '', disabled, description, options, isMandatory, checkboxClass, layout = 'vertical', onchange, } = attrs;
|
|
5651
5698
|
const { groupId, componentId } = state;
|
|
5652
5699
|
const controlled = isControlled(attrs);
|
|
5653
5700
|
// Get current checked ID from props or internal state
|
|
5654
|
-
|
|
5701
|
+
let currentCheckedId;
|
|
5702
|
+
if (controlled) {
|
|
5703
|
+
currentCheckedId = checkedId;
|
|
5704
|
+
}
|
|
5705
|
+
else if (disabled) {
|
|
5706
|
+
// Non-interactive components: prefer defaultCheckedId, fallback to checkedId
|
|
5707
|
+
currentCheckedId = (_a = attrs.defaultCheckedId) !== null && _a !== void 0 ? _a : checkedId;
|
|
5708
|
+
}
|
|
5709
|
+
else {
|
|
5710
|
+
// Interactive uncontrolled: use internal state
|
|
5711
|
+
currentCheckedId = (_b = state.internalCheckedId) !== null && _b !== void 0 ? _b : attrs.defaultCheckedId;
|
|
5712
|
+
}
|
|
5655
5713
|
const handleChange = (id) => {
|
|
5656
5714
|
// Update internal state for uncontrolled mode
|
|
5657
5715
|
if (!controlled) {
|
|
@@ -5781,8 +5839,14 @@ const Select = () => {
|
|
|
5781
5839
|
return {
|
|
5782
5840
|
oninit: ({ attrs }) => {
|
|
5783
5841
|
state.id = attrs.id || uniqueId();
|
|
5842
|
+
const controlled = isControlled(attrs);
|
|
5843
|
+
// Warn developer for improper controlled usage
|
|
5844
|
+
if (attrs.checkedId !== undefined && !controlled && !attrs.disabled) {
|
|
5845
|
+
console.warn(`Select component received 'checkedId' prop without 'onchange' handler. ` +
|
|
5846
|
+
`Use 'defaultCheckedId' for uncontrolled components or add 'onchange' for controlled components.`);
|
|
5847
|
+
}
|
|
5784
5848
|
// Initialize internal state for uncontrolled mode
|
|
5785
|
-
if (!
|
|
5849
|
+
if (!controlled) {
|
|
5786
5850
|
const defaultIds = attrs.defaultCheckedId !== undefined
|
|
5787
5851
|
? Array.isArray(attrs.defaultCheckedId)
|
|
5788
5852
|
? attrs.defaultCheckedId
|
|
@@ -5798,16 +5862,32 @@ const Select = () => {
|
|
|
5798
5862
|
document.removeEventListener('click', closeDropdown);
|
|
5799
5863
|
},
|
|
5800
5864
|
view: ({ attrs }) => {
|
|
5865
|
+
var _a;
|
|
5801
5866
|
const controlled = isControlled(attrs);
|
|
5867
|
+
const { disabled } = attrs;
|
|
5802
5868
|
// Get selected IDs from props or internal state
|
|
5803
|
-
|
|
5804
|
-
|
|
5869
|
+
let selectedIds;
|
|
5870
|
+
if (controlled) {
|
|
5871
|
+
selectedIds = attrs.checkedId !== undefined
|
|
5805
5872
|
? Array.isArray(attrs.checkedId)
|
|
5806
5873
|
? attrs.checkedId
|
|
5807
5874
|
: [attrs.checkedId]
|
|
5808
|
-
: []
|
|
5809
|
-
|
|
5810
|
-
|
|
5875
|
+
: [];
|
|
5876
|
+
}
|
|
5877
|
+
else if (disabled) {
|
|
5878
|
+
// Non-interactive components: prefer defaultCheckedId, fallback to checkedId
|
|
5879
|
+
const fallbackId = (_a = attrs.defaultCheckedId) !== null && _a !== void 0 ? _a : attrs.checkedId;
|
|
5880
|
+
selectedIds = fallbackId !== undefined
|
|
5881
|
+
? Array.isArray(fallbackId)
|
|
5882
|
+
? fallbackId
|
|
5883
|
+
: [fallbackId]
|
|
5884
|
+
: [];
|
|
5885
|
+
}
|
|
5886
|
+
else {
|
|
5887
|
+
// Interactive uncontrolled: use internal state
|
|
5888
|
+
selectedIds = state.internalSelectedIds;
|
|
5889
|
+
}
|
|
5890
|
+
const { newRow, className = 'col s12', key, options, multiple = false, label, helperText, placeholder = '', isMandatory, iconName, style, } = attrs;
|
|
5811
5891
|
const finalClassName = newRow ? `${className} clear` : className;
|
|
5812
5892
|
const selectedOptions = options.filter((opt) => isSelected(opt.id, selectedIds));
|
|
5813
5893
|
return m('.input-field.select-space', {
|
|
@@ -8544,6 +8624,269 @@ const ImageList = () => {
|
|
|
8544
8624
|
};
|
|
8545
8625
|
};
|
|
8546
8626
|
|
|
8627
|
+
/** Default star icons */
|
|
8628
|
+
const DEFAULT_ICONS = {
|
|
8629
|
+
filled: '★',
|
|
8630
|
+
empty: '☆',
|
|
8631
|
+
half: '☆', // We'll handle half-fill with CSS
|
|
8632
|
+
};
|
|
8633
|
+
/** Create a Rating component */
|
|
8634
|
+
const Rating = () => {
|
|
8635
|
+
const state = {
|
|
8636
|
+
id: uniqueId(),
|
|
8637
|
+
internalValue: 0,
|
|
8638
|
+
hoverValue: null,
|
|
8639
|
+
isHovering: false,
|
|
8640
|
+
isFocused: false,
|
|
8641
|
+
};
|
|
8642
|
+
const isControlled = (attrs) => typeof attrs.value !== 'undefined' && typeof attrs.onchange === 'function';
|
|
8643
|
+
const getCurrentValue = (attrs) => {
|
|
8644
|
+
var _a, _b, _c, _d;
|
|
8645
|
+
const controlled = isControlled(attrs);
|
|
8646
|
+
const isNonInteractive = attrs.readonly || attrs.disabled;
|
|
8647
|
+
if (controlled) {
|
|
8648
|
+
return attrs.value || 0;
|
|
8649
|
+
}
|
|
8650
|
+
// Non-interactive components: prefer defaultValue, fallback to value
|
|
8651
|
+
if (isNonInteractive) {
|
|
8652
|
+
return (_b = (_a = attrs.defaultValue) !== null && _a !== void 0 ? _a : attrs.value) !== null && _b !== void 0 ? _b : 0;
|
|
8653
|
+
}
|
|
8654
|
+
// Interactive uncontrolled: use internal state (user can change it)
|
|
8655
|
+
return (_d = (_c = state.internalValue) !== null && _c !== void 0 ? _c : attrs.defaultValue) !== null && _d !== void 0 ? _d : 0;
|
|
8656
|
+
};
|
|
8657
|
+
const getDisplayValue = (attrs) => state.isHovering && state.hoverValue !== null ? state.hoverValue : getCurrentValue(attrs);
|
|
8658
|
+
const getLabelText = (value, max, getLabelFn) => {
|
|
8659
|
+
if (getLabelFn) {
|
|
8660
|
+
return getLabelFn(value, max);
|
|
8661
|
+
}
|
|
8662
|
+
if (value === 0) {
|
|
8663
|
+
return `No rating`;
|
|
8664
|
+
}
|
|
8665
|
+
if (value === 1) {
|
|
8666
|
+
return `1 star out of ${max}`;
|
|
8667
|
+
}
|
|
8668
|
+
return `${value} stars out of ${max}`;
|
|
8669
|
+
};
|
|
8670
|
+
const getSizeClass = (size = 'medium') => {
|
|
8671
|
+
switch (size) {
|
|
8672
|
+
case 'small':
|
|
8673
|
+
return 'rating--small';
|
|
8674
|
+
case 'large':
|
|
8675
|
+
return 'rating--large';
|
|
8676
|
+
default:
|
|
8677
|
+
return 'rating--medium';
|
|
8678
|
+
}
|
|
8679
|
+
};
|
|
8680
|
+
const getDensityClass = (density = 'standard') => {
|
|
8681
|
+
switch (density) {
|
|
8682
|
+
case 'compact':
|
|
8683
|
+
return 'rating--compact';
|
|
8684
|
+
case 'comfortable':
|
|
8685
|
+
return 'rating--comfortable';
|
|
8686
|
+
default:
|
|
8687
|
+
return 'rating--standard';
|
|
8688
|
+
}
|
|
8689
|
+
};
|
|
8690
|
+
const handleItemClick = (attrs, clickValue) => {
|
|
8691
|
+
var _a;
|
|
8692
|
+
if (attrs.readonly || attrs.disabled)
|
|
8693
|
+
return;
|
|
8694
|
+
const currentValue = getCurrentValue(attrs);
|
|
8695
|
+
const newValue = attrs.clearable && currentValue === clickValue ? 0 : clickValue;
|
|
8696
|
+
if (!isControlled(attrs)) {
|
|
8697
|
+
state.internalValue = newValue;
|
|
8698
|
+
}
|
|
8699
|
+
(_a = attrs.onchange) === null || _a === void 0 ? void 0 : _a.call(attrs, newValue);
|
|
8700
|
+
};
|
|
8701
|
+
const handleItemHover = (attrs, hoverValue) => {
|
|
8702
|
+
var _a;
|
|
8703
|
+
if (attrs.readonly || attrs.disabled)
|
|
8704
|
+
return;
|
|
8705
|
+
state.hoverValue = hoverValue;
|
|
8706
|
+
state.isHovering = true;
|
|
8707
|
+
(_a = attrs.onmouseover) === null || _a === void 0 ? void 0 : _a.call(attrs, hoverValue);
|
|
8708
|
+
};
|
|
8709
|
+
const handleMouseLeave = (attrs) => {
|
|
8710
|
+
if (attrs.readonly || attrs.disabled)
|
|
8711
|
+
return;
|
|
8712
|
+
state.isHovering = false;
|
|
8713
|
+
state.hoverValue = null;
|
|
8714
|
+
};
|
|
8715
|
+
const handleKeyDown = (attrs, e) => {
|
|
8716
|
+
var _a;
|
|
8717
|
+
if (attrs.readonly || attrs.disabled)
|
|
8718
|
+
return;
|
|
8719
|
+
const max = attrs.max || 5;
|
|
8720
|
+
const step = attrs.step || 1;
|
|
8721
|
+
const currentValue = getCurrentValue(attrs);
|
|
8722
|
+
let newValue = currentValue;
|
|
8723
|
+
switch (e.key) {
|
|
8724
|
+
case 'ArrowRight':
|
|
8725
|
+
case 'ArrowUp':
|
|
8726
|
+
e.preventDefault();
|
|
8727
|
+
newValue = Math.min(max, currentValue + step);
|
|
8728
|
+
break;
|
|
8729
|
+
case 'ArrowLeft':
|
|
8730
|
+
case 'ArrowDown':
|
|
8731
|
+
e.preventDefault();
|
|
8732
|
+
newValue = Math.max(0, currentValue - step);
|
|
8733
|
+
break;
|
|
8734
|
+
case 'Home':
|
|
8735
|
+
e.preventDefault();
|
|
8736
|
+
newValue = attrs.clearable ? 0 : step;
|
|
8737
|
+
break;
|
|
8738
|
+
case 'End':
|
|
8739
|
+
e.preventDefault();
|
|
8740
|
+
newValue = max;
|
|
8741
|
+
break;
|
|
8742
|
+
case ' ':
|
|
8743
|
+
case 'Enter':
|
|
8744
|
+
e.preventDefault();
|
|
8745
|
+
// If focused and not hovering, increment by step
|
|
8746
|
+
if (!state.isHovering) {
|
|
8747
|
+
newValue = currentValue + step > max ? (attrs.clearable ? 0 : step) : currentValue + step;
|
|
8748
|
+
}
|
|
8749
|
+
break;
|
|
8750
|
+
case 'Escape':
|
|
8751
|
+
if (attrs.clearable) {
|
|
8752
|
+
e.preventDefault();
|
|
8753
|
+
newValue = 0;
|
|
8754
|
+
}
|
|
8755
|
+
break;
|
|
8756
|
+
default:
|
|
8757
|
+
return;
|
|
8758
|
+
}
|
|
8759
|
+
if (newValue !== currentValue) {
|
|
8760
|
+
if (!isControlled(attrs)) {
|
|
8761
|
+
state.internalValue = newValue;
|
|
8762
|
+
}
|
|
8763
|
+
(_a = attrs.onchange) === null || _a === void 0 ? void 0 : _a.call(attrs, newValue);
|
|
8764
|
+
}
|
|
8765
|
+
};
|
|
8766
|
+
const RatingItem = () => {
|
|
8767
|
+
return {
|
|
8768
|
+
view: ({ attrs }) => {
|
|
8769
|
+
const { index, displayValue, step, icons, allowHalfSteps, disabled, onclick, onmouseover } = attrs;
|
|
8770
|
+
const itemValue = (index + 1) * step;
|
|
8771
|
+
// Calculate fill state based on displayValue vs itemValue
|
|
8772
|
+
const diff = displayValue - itemValue;
|
|
8773
|
+
const fillState = diff >= 0 ? 'full' : allowHalfSteps && diff >= -step / 2 ? 'half' : 'empty';
|
|
8774
|
+
return m('.rating__item', {
|
|
8775
|
+
className: [
|
|
8776
|
+
fillState === 'full' ? 'rating__item--filled' : '',
|
|
8777
|
+
fillState === 'half' ? 'rating__item--half' : '',
|
|
8778
|
+
fillState !== 'empty' ? 'rating__item--active' : '',
|
|
8779
|
+
disabled ? 'rating__item--disabled' : '',
|
|
8780
|
+
]
|
|
8781
|
+
.filter(Boolean)
|
|
8782
|
+
.join(' '),
|
|
8783
|
+
onclick,
|
|
8784
|
+
onmouseover,
|
|
8785
|
+
}, [
|
|
8786
|
+
// Empty icon (background)
|
|
8787
|
+
m('.rating__icon.rating__icon--empty', { 'aria-hidden': 'true' }, typeof icons.empty === 'string' ? icons.empty : m(icons.empty)),
|
|
8788
|
+
// Filled icon (foreground)
|
|
8789
|
+
m('.rating__icon.rating__icon--filled', {
|
|
8790
|
+
'aria-hidden': 'true',
|
|
8791
|
+
style: {
|
|
8792
|
+
clipPath: fillState === 'half' ? 'inset(0 50% 0 0)' : undefined,
|
|
8793
|
+
},
|
|
8794
|
+
}, typeof icons.filled === 'string' ? icons.filled : m(icons.filled)),
|
|
8795
|
+
]);
|
|
8796
|
+
},
|
|
8797
|
+
};
|
|
8798
|
+
};
|
|
8799
|
+
return {
|
|
8800
|
+
oninit: ({ attrs }) => {
|
|
8801
|
+
const controlled = isControlled(attrs);
|
|
8802
|
+
const isNonInteractive = attrs.readonly || attrs.disabled;
|
|
8803
|
+
// Warn developer for improper controlled usage
|
|
8804
|
+
if (attrs.value !== undefined && !controlled && !isNonInteractive) {
|
|
8805
|
+
console.warn(`Rating component received 'value' prop without 'onchange' handler. ` +
|
|
8806
|
+
`Use 'defaultValue' for uncontrolled components or add 'onchange' for controlled components.`);
|
|
8807
|
+
}
|
|
8808
|
+
if (!controlled) {
|
|
8809
|
+
state.internalValue = attrs.defaultValue || 0;
|
|
8810
|
+
}
|
|
8811
|
+
},
|
|
8812
|
+
view: ({ attrs }) => {
|
|
8813
|
+
const { max = 5, step = 1, size = 'medium', density = 'standard', className = '', style = {}, readonly: readonly = false, disabled = false, id = state.id, name } = attrs, ariaAttrs = __rest(attrs, ["max", "step", "size", "density", "className", "style", "readonly", "disabled", "id", "name"]);
|
|
8814
|
+
const currentValue = getCurrentValue(attrs);
|
|
8815
|
+
const displayValue = getDisplayValue(attrs);
|
|
8816
|
+
const itemCount = Math.ceil(max / step);
|
|
8817
|
+
return m('.rating', {
|
|
8818
|
+
className: [
|
|
8819
|
+
'rating',
|
|
8820
|
+
getSizeClass(size),
|
|
8821
|
+
getDensityClass(density),
|
|
8822
|
+
readonly ? 'rating--read-only' : '',
|
|
8823
|
+
disabled ? 'rating--disabled' : '',
|
|
8824
|
+
state.isFocused ? 'rating--focused' : '',
|
|
8825
|
+
className,
|
|
8826
|
+
]
|
|
8827
|
+
.filter(Boolean)
|
|
8828
|
+
.join(' '),
|
|
8829
|
+
style,
|
|
8830
|
+
id,
|
|
8831
|
+
role: readonly ? 'img' : 'slider',
|
|
8832
|
+
tabindex: readonly || disabled ? -1 : 0,
|
|
8833
|
+
'aria-valuemin': 0,
|
|
8834
|
+
'aria-valuemax': max,
|
|
8835
|
+
'aria-valuenow': currentValue,
|
|
8836
|
+
'aria-valuetext': getLabelText(currentValue, max, attrs.getLabelText),
|
|
8837
|
+
'aria-label': ariaAttrs['aria-label'] ||
|
|
8838
|
+
attrs.ariaLabel ||
|
|
8839
|
+
`Rating: ${getLabelText(currentValue, max, attrs.getLabelText)}`,
|
|
8840
|
+
'aria-labelledby': ariaAttrs['aria-labelledby'],
|
|
8841
|
+
'aria-readonly': readonly,
|
|
8842
|
+
'aria-disabled': disabled,
|
|
8843
|
+
onkeydown: (e) => handleKeyDown(attrs, e),
|
|
8844
|
+
onfocus: () => {
|
|
8845
|
+
state.isFocused = true;
|
|
8846
|
+
},
|
|
8847
|
+
onblur: () => {
|
|
8848
|
+
state.isFocused = false;
|
|
8849
|
+
handleMouseLeave(attrs);
|
|
8850
|
+
},
|
|
8851
|
+
onmouseleave: () => handleMouseLeave(attrs),
|
|
8852
|
+
}, [
|
|
8853
|
+
// Hidden input for form submission
|
|
8854
|
+
name &&
|
|
8855
|
+
m('input', {
|
|
8856
|
+
type: 'hidden',
|
|
8857
|
+
name,
|
|
8858
|
+
value: currentValue,
|
|
8859
|
+
}),
|
|
8860
|
+
// Rating items
|
|
8861
|
+
m('.rating__items', {
|
|
8862
|
+
className: 'rating__items',
|
|
8863
|
+
},
|
|
8864
|
+
// Array.from({ length: itemCount }, (_, i) => renderRatingItem(attrs, i))
|
|
8865
|
+
[...Array(itemCount)].map((_, i) => {
|
|
8866
|
+
const itemValue = (i + 1) * step;
|
|
8867
|
+
return m(RatingItem, {
|
|
8868
|
+
key: `rating-item-${i}`,
|
|
8869
|
+
index: i,
|
|
8870
|
+
displayValue: displayValue,
|
|
8871
|
+
step,
|
|
8872
|
+
icons: Object.assign(Object.assign({}, DEFAULT_ICONS), attrs.icon),
|
|
8873
|
+
allowHalfSteps: attrs.allowHalfSteps,
|
|
8874
|
+
disabled: attrs.disabled,
|
|
8875
|
+
onclick: () => handleItemClick(attrs, itemValue),
|
|
8876
|
+
onmouseover: () => handleItemHover(attrs, itemValue),
|
|
8877
|
+
});
|
|
8878
|
+
})),
|
|
8879
|
+
// Screen reader text
|
|
8880
|
+
m('.rating__sr-only', {
|
|
8881
|
+
className: 'rating__sr-only',
|
|
8882
|
+
'aria-live': 'polite',
|
|
8883
|
+
'aria-atomic': 'true',
|
|
8884
|
+
}, getLabelText(displayValue, max, attrs.getLabelText)),
|
|
8885
|
+
]);
|
|
8886
|
+
},
|
|
8887
|
+
};
|
|
8888
|
+
};
|
|
8889
|
+
|
|
8547
8890
|
/**
|
|
8548
8891
|
* @fileoverview Core TypeScript utility types for mithril-materialized library
|
|
8549
8892
|
* These types improve type safety and developer experience across all components
|
|
@@ -8565,4 +8908,4 @@ const isValidationError = (result) => !isValidationSuccess(result);
|
|
|
8565
8908
|
// ============================================================================
|
|
8566
8909
|
// All types are already exported via individual export declarations above
|
|
8567
8910
|
|
|
8568
|
-
export { AnchorItem, Autocomplete, Breadcrumb, BreadcrumbManager, Button, ButtonFactory, Carousel, CharacterCounter, Chips, CodeBlock, Collapsible, CollapsibleItem, Collection, CollectionMode, ColorInput, DataTable, DatePicker, DoubleRangeSlider, Dropdown, EmailInput, FileInput, FileUpload, FlatButton, FloatingActionButton, HelperText, Icon, ImageList, InputCheckbox, Label, LargeButton, ListItem, Mandatory, Masonry, MaterialBox, MaterialIcon, ModalPanel, NumberInput, Options, OptionsList, Pagination, PaginationControls, Parallax, PasswordInput, Pushpin, PushpinComponent, RadioButton, RadioButtons, RangeInput, RoundIconButton, SearchSelect, SecondaryContent, Select, Sidenav, SidenavItem, SidenavManager, SingleRangeSlider, SmallButton, Stepper, SubmitButton, Switch, Tabs, TextArea, TextInput, ThemeManager, ThemeSwitcher, ThemeToggle, TimePicker, Timeline, Toast, ToastComponent, Tooltip, TooltipComponent, TreeView, UrlInput, Wizard, createBreadcrumb, getDropdownStyles, initPushpins, initTooltips, isNumeric, isValidationError, isValidationSuccess, padLeft, range, toast, uniqueId, uuid4 };
|
|
8911
|
+
export { AnchorItem, Autocomplete, Breadcrumb, BreadcrumbManager, Button, ButtonFactory, Carousel, CharacterCounter, Chips, CodeBlock, Collapsible, CollapsibleItem, Collection, CollectionMode, ColorInput, DataTable, DatePicker, DoubleRangeSlider, Dropdown, EmailInput, FileInput, FileUpload, FlatButton, FloatingActionButton, HelperText, Icon, ImageList, InputCheckbox, Label, LargeButton, ListItem, Mandatory, Masonry, MaterialBox, MaterialIcon, ModalPanel, NumberInput, Options, OptionsList, Pagination, PaginationControls, Parallax, PasswordInput, Pushpin, PushpinComponent, RadioButton, RadioButtons, RangeInput, Rating, RoundIconButton, SearchSelect, SecondaryContent, Select, Sidenav, SidenavItem, SidenavManager, SingleRangeSlider, SmallButton, Stepper, SubmitButton, Switch, Tabs, TextArea, TextInput, ThemeManager, ThemeSwitcher, ThemeToggle, TimePicker, Timeline, Toast, ToastComponent, Tooltip, TooltipComponent, TreeView, UrlInput, Wizard, createBreadcrumb, getDropdownStyles, initPushpins, initTooltips, isNumeric, isValidationError, isValidationSuccess, padLeft, range, toast, uniqueId, uuid4 };
|