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.js
CHANGED
|
@@ -2853,20 +2853,40 @@ const TextArea = () => {
|
|
|
2853
2853
|
state.height = undefined;
|
|
2854
2854
|
}
|
|
2855
2855
|
};
|
|
2856
|
-
const isControlled = (attrs) => attrs.value !== undefined && attrs.oninput !== undefined;
|
|
2856
|
+
const isControlled = (attrs) => attrs.value !== undefined && (attrs.oninput !== undefined || attrs.onchange !== undefined);
|
|
2857
2857
|
return {
|
|
2858
2858
|
oninit: ({ attrs }) => {
|
|
2859
|
+
const controlled = isControlled(attrs);
|
|
2860
|
+
const isNonInteractive = attrs.readonly || attrs.disabled;
|
|
2861
|
+
// Warn developer for improper controlled usage
|
|
2862
|
+
if (attrs.value !== undefined && !controlled && !isNonInteractive) {
|
|
2863
|
+
console.warn(`TextArea received 'value' prop without 'oninput' or 'onchange' handler. ` +
|
|
2864
|
+
`Use 'defaultValue' for uncontrolled components or add an event handler for controlled components.`);
|
|
2865
|
+
}
|
|
2859
2866
|
// Initialize internal value for uncontrolled mode
|
|
2860
|
-
if (!
|
|
2867
|
+
if (!controlled) {
|
|
2861
2868
|
state.internalValue = attrs.defaultValue || '';
|
|
2862
2869
|
}
|
|
2863
2870
|
},
|
|
2864
2871
|
onremove: () => {
|
|
2865
2872
|
},
|
|
2866
2873
|
view: ({ attrs }) => {
|
|
2874
|
+
var _a, _b, _c, _d;
|
|
2867
2875
|
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"]);
|
|
2868
2876
|
const controlled = isControlled(attrs);
|
|
2869
|
-
const
|
|
2877
|
+
const isNonInteractive = attrs.readonly || attrs.disabled;
|
|
2878
|
+
let currentValue;
|
|
2879
|
+
if (controlled) {
|
|
2880
|
+
currentValue = value || '';
|
|
2881
|
+
}
|
|
2882
|
+
else if (isNonInteractive) {
|
|
2883
|
+
// Non-interactive components: prefer defaultValue, fallback to value
|
|
2884
|
+
currentValue = (_b = (_a = attrs.defaultValue) !== null && _a !== void 0 ? _a : value) !== null && _b !== void 0 ? _b : '';
|
|
2885
|
+
}
|
|
2886
|
+
else {
|
|
2887
|
+
// Interactive uncontrolled: use internal state
|
|
2888
|
+
currentValue = (_d = (_c = state.internalValue) !== null && _c !== void 0 ? _c : attrs.defaultValue) !== null && _d !== void 0 ? _d : '';
|
|
2889
|
+
}
|
|
2870
2890
|
return [
|
|
2871
2891
|
// Hidden div for height measurement - positioned outside the input-field
|
|
2872
2892
|
m('.hiddendiv', {
|
|
@@ -2997,7 +3017,8 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
2997
3017
|
isDragging: false,
|
|
2998
3018
|
activeThumb: null,
|
|
2999
3019
|
};
|
|
3000
|
-
const isControlled = (attrs) => 'value' in attrs && typeof attrs.value !== 'undefined' &&
|
|
3020
|
+
const isControlled = (attrs) => 'value' in attrs && typeof attrs.value !== 'undefined' &&
|
|
3021
|
+
(typeof attrs.oninput === 'function' || typeof attrs.onchange === 'function');
|
|
3001
3022
|
const getValue = (target) => {
|
|
3002
3023
|
const val = target.value;
|
|
3003
3024
|
return (val ? (type === 'number' || type === 'range' ? +val : val) : val);
|
|
@@ -3043,8 +3064,15 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
3043
3064
|
// Range slider rendering functions are now in separate module
|
|
3044
3065
|
return {
|
|
3045
3066
|
oninit: ({ attrs }) => {
|
|
3067
|
+
const controlled = isControlled(attrs);
|
|
3068
|
+
const isNonInteractive = attrs.readonly || attrs.disabled;
|
|
3069
|
+
// Warn developer for improper controlled usage
|
|
3070
|
+
if (attrs.value !== undefined && !controlled && !isNonInteractive) {
|
|
3071
|
+
console.warn(`${type} input received 'value' prop without 'oninput' or 'onchange' handler. ` +
|
|
3072
|
+
`Use 'defaultValue' for uncontrolled components or add an event handler for controlled components.`);
|
|
3073
|
+
}
|
|
3046
3074
|
// Initialize internal value if not in controlled mode
|
|
3047
|
-
if (!
|
|
3075
|
+
if (!controlled) {
|
|
3048
3076
|
const isNumeric = ['number', 'range'].includes(type);
|
|
3049
3077
|
if (attrs.defaultValue !== undefined) {
|
|
3050
3078
|
if (isNumeric) {
|
|
@@ -3060,7 +3088,7 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
3060
3088
|
}
|
|
3061
3089
|
},
|
|
3062
3090
|
view: ({ attrs }) => {
|
|
3063
|
-
var _a, _b;
|
|
3091
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3064
3092
|
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"]);
|
|
3065
3093
|
// const attributes = toAttrs(params);
|
|
3066
3094
|
const cn = [newRow ? 'clear' : '', defaultClass, className].filter(Boolean).join(' ').trim() || undefined;
|
|
@@ -3080,7 +3108,19 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
3080
3108
|
}
|
|
3081
3109
|
const isNumeric = ['number', 'range'].includes(type);
|
|
3082
3110
|
const controlled = isControlled(attrs);
|
|
3083
|
-
const
|
|
3111
|
+
const isNonInteractive = attrs.readonly || attrs.disabled;
|
|
3112
|
+
let value;
|
|
3113
|
+
if (controlled) {
|
|
3114
|
+
value = attrs.value;
|
|
3115
|
+
}
|
|
3116
|
+
else if (isNonInteractive) {
|
|
3117
|
+
// Non-interactive components: prefer defaultValue, fallback to value
|
|
3118
|
+
value = ((_c = (_b = attrs.defaultValue) !== null && _b !== void 0 ? _b : attrs.value) !== null && _c !== void 0 ? _c : (isNumeric ? 0 : ''));
|
|
3119
|
+
}
|
|
3120
|
+
else {
|
|
3121
|
+
// Interactive uncontrolled: use internal state
|
|
3122
|
+
value = ((_e = (_d = state.internalValue) !== null && _d !== void 0 ? _d : attrs.defaultValue) !== null && _e !== void 0 ? _e : (isNumeric ? 0 : ''));
|
|
3123
|
+
}
|
|
3084
3124
|
const rangeType = type === 'range' && !attrs.minmax;
|
|
3085
3125
|
return m('.input-field', { className: cn, style }, [
|
|
3086
3126
|
iconName ? m('i.material-icons.prefix', iconName) : undefined,
|
|
@@ -3246,7 +3286,7 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
3246
3286
|
}
|
|
3247
3287
|
} })),
|
|
3248
3288
|
// Clear button - only for text inputs with canClear enabled and has content
|
|
3249
|
-
canClear && type === 'text' && ((
|
|
3289
|
+
canClear && type === 'text' && ((_f = state.inputElement) === null || _f === void 0 ? void 0 : _f.value)
|
|
3250
3290
|
? m(MaterialIcon, {
|
|
3251
3291
|
name: 'close',
|
|
3252
3292
|
className: 'input-clear-btn',
|
|
@@ -5643,17 +5683,35 @@ const RadioButtons = () => {
|
|
|
5643
5683
|
return {
|
|
5644
5684
|
oninit: ({ attrs }) => {
|
|
5645
5685
|
state.componentId = attrs.id || uniqueId();
|
|
5686
|
+
const controlled = isControlled(attrs);
|
|
5687
|
+
// Warn developer for improper controlled usage
|
|
5688
|
+
if (attrs.checkedId !== undefined && !controlled && !attrs.disabled) {
|
|
5689
|
+
console.warn(`RadioButtons component received 'checkedId' prop without 'onchange' handler. ` +
|
|
5690
|
+
`Use 'defaultCheckedId' for uncontrolled components or add 'onchange' for controlled components.`);
|
|
5691
|
+
}
|
|
5646
5692
|
// Initialize internal state for uncontrolled mode
|
|
5647
|
-
if (!
|
|
5693
|
+
if (!controlled) {
|
|
5648
5694
|
state.internalCheckedId = attrs.defaultCheckedId;
|
|
5649
5695
|
}
|
|
5650
5696
|
},
|
|
5651
5697
|
view: ({ attrs }) => {
|
|
5698
|
+
var _a, _b;
|
|
5652
5699
|
const { checkedId, newRow, className = 'col s12', label = '', disabled, description, options, isMandatory, checkboxClass, layout = 'vertical', onchange, } = attrs;
|
|
5653
5700
|
const { groupId, componentId } = state;
|
|
5654
5701
|
const controlled = isControlled(attrs);
|
|
5655
5702
|
// Get current checked ID from props or internal state
|
|
5656
|
-
|
|
5703
|
+
let currentCheckedId;
|
|
5704
|
+
if (controlled) {
|
|
5705
|
+
currentCheckedId = checkedId;
|
|
5706
|
+
}
|
|
5707
|
+
else if (disabled) {
|
|
5708
|
+
// Non-interactive components: prefer defaultCheckedId, fallback to checkedId
|
|
5709
|
+
currentCheckedId = (_a = attrs.defaultCheckedId) !== null && _a !== void 0 ? _a : checkedId;
|
|
5710
|
+
}
|
|
5711
|
+
else {
|
|
5712
|
+
// Interactive uncontrolled: use internal state
|
|
5713
|
+
currentCheckedId = (_b = state.internalCheckedId) !== null && _b !== void 0 ? _b : attrs.defaultCheckedId;
|
|
5714
|
+
}
|
|
5657
5715
|
const handleChange = (id) => {
|
|
5658
5716
|
// Update internal state for uncontrolled mode
|
|
5659
5717
|
if (!controlled) {
|
|
@@ -5783,8 +5841,14 @@ const Select = () => {
|
|
|
5783
5841
|
return {
|
|
5784
5842
|
oninit: ({ attrs }) => {
|
|
5785
5843
|
state.id = attrs.id || uniqueId();
|
|
5844
|
+
const controlled = isControlled(attrs);
|
|
5845
|
+
// Warn developer for improper controlled usage
|
|
5846
|
+
if (attrs.checkedId !== undefined && !controlled && !attrs.disabled) {
|
|
5847
|
+
console.warn(`Select component received 'checkedId' prop without 'onchange' handler. ` +
|
|
5848
|
+
`Use 'defaultCheckedId' for uncontrolled components or add 'onchange' for controlled components.`);
|
|
5849
|
+
}
|
|
5786
5850
|
// Initialize internal state for uncontrolled mode
|
|
5787
|
-
if (!
|
|
5851
|
+
if (!controlled) {
|
|
5788
5852
|
const defaultIds = attrs.defaultCheckedId !== undefined
|
|
5789
5853
|
? Array.isArray(attrs.defaultCheckedId)
|
|
5790
5854
|
? attrs.defaultCheckedId
|
|
@@ -5800,16 +5864,32 @@ const Select = () => {
|
|
|
5800
5864
|
document.removeEventListener('click', closeDropdown);
|
|
5801
5865
|
},
|
|
5802
5866
|
view: ({ attrs }) => {
|
|
5867
|
+
var _a;
|
|
5803
5868
|
const controlled = isControlled(attrs);
|
|
5869
|
+
const { disabled } = attrs;
|
|
5804
5870
|
// Get selected IDs from props or internal state
|
|
5805
|
-
|
|
5806
|
-
|
|
5871
|
+
let selectedIds;
|
|
5872
|
+
if (controlled) {
|
|
5873
|
+
selectedIds = attrs.checkedId !== undefined
|
|
5807
5874
|
? Array.isArray(attrs.checkedId)
|
|
5808
5875
|
? attrs.checkedId
|
|
5809
5876
|
: [attrs.checkedId]
|
|
5810
|
-
: []
|
|
5811
|
-
|
|
5812
|
-
|
|
5877
|
+
: [];
|
|
5878
|
+
}
|
|
5879
|
+
else if (disabled) {
|
|
5880
|
+
// Non-interactive components: prefer defaultCheckedId, fallback to checkedId
|
|
5881
|
+
const fallbackId = (_a = attrs.defaultCheckedId) !== null && _a !== void 0 ? _a : attrs.checkedId;
|
|
5882
|
+
selectedIds = fallbackId !== undefined
|
|
5883
|
+
? Array.isArray(fallbackId)
|
|
5884
|
+
? fallbackId
|
|
5885
|
+
: [fallbackId]
|
|
5886
|
+
: [];
|
|
5887
|
+
}
|
|
5888
|
+
else {
|
|
5889
|
+
// Interactive uncontrolled: use internal state
|
|
5890
|
+
selectedIds = state.internalSelectedIds;
|
|
5891
|
+
}
|
|
5892
|
+
const { newRow, className = 'col s12', key, options, multiple = false, label, helperText, placeholder = '', isMandatory, iconName, style, } = attrs;
|
|
5813
5893
|
const finalClassName = newRow ? `${className} clear` : className;
|
|
5814
5894
|
const selectedOptions = options.filter((opt) => isSelected(opt.id, selectedIds));
|
|
5815
5895
|
return m('.input-field.select-space', {
|
|
@@ -8546,6 +8626,269 @@ const ImageList = () => {
|
|
|
8546
8626
|
};
|
|
8547
8627
|
};
|
|
8548
8628
|
|
|
8629
|
+
/** Default star icons */
|
|
8630
|
+
const DEFAULT_ICONS = {
|
|
8631
|
+
filled: '★',
|
|
8632
|
+
empty: '☆',
|
|
8633
|
+
half: '☆', // We'll handle half-fill with CSS
|
|
8634
|
+
};
|
|
8635
|
+
/** Create a Rating component */
|
|
8636
|
+
const Rating = () => {
|
|
8637
|
+
const state = {
|
|
8638
|
+
id: uniqueId(),
|
|
8639
|
+
internalValue: 0,
|
|
8640
|
+
hoverValue: null,
|
|
8641
|
+
isHovering: false,
|
|
8642
|
+
isFocused: false,
|
|
8643
|
+
};
|
|
8644
|
+
const isControlled = (attrs) => typeof attrs.value !== 'undefined' && typeof attrs.onchange === 'function';
|
|
8645
|
+
const getCurrentValue = (attrs) => {
|
|
8646
|
+
var _a, _b, _c, _d;
|
|
8647
|
+
const controlled = isControlled(attrs);
|
|
8648
|
+
const isNonInteractive = attrs.readonly || attrs.disabled;
|
|
8649
|
+
if (controlled) {
|
|
8650
|
+
return attrs.value || 0;
|
|
8651
|
+
}
|
|
8652
|
+
// Non-interactive components: prefer defaultValue, fallback to value
|
|
8653
|
+
if (isNonInteractive) {
|
|
8654
|
+
return (_b = (_a = attrs.defaultValue) !== null && _a !== void 0 ? _a : attrs.value) !== null && _b !== void 0 ? _b : 0;
|
|
8655
|
+
}
|
|
8656
|
+
// Interactive uncontrolled: use internal state (user can change it)
|
|
8657
|
+
return (_d = (_c = state.internalValue) !== null && _c !== void 0 ? _c : attrs.defaultValue) !== null && _d !== void 0 ? _d : 0;
|
|
8658
|
+
};
|
|
8659
|
+
const getDisplayValue = (attrs) => state.isHovering && state.hoverValue !== null ? state.hoverValue : getCurrentValue(attrs);
|
|
8660
|
+
const getLabelText = (value, max, getLabelFn) => {
|
|
8661
|
+
if (getLabelFn) {
|
|
8662
|
+
return getLabelFn(value, max);
|
|
8663
|
+
}
|
|
8664
|
+
if (value === 0) {
|
|
8665
|
+
return `No rating`;
|
|
8666
|
+
}
|
|
8667
|
+
if (value === 1) {
|
|
8668
|
+
return `1 star out of ${max}`;
|
|
8669
|
+
}
|
|
8670
|
+
return `${value} stars out of ${max}`;
|
|
8671
|
+
};
|
|
8672
|
+
const getSizeClass = (size = 'medium') => {
|
|
8673
|
+
switch (size) {
|
|
8674
|
+
case 'small':
|
|
8675
|
+
return 'rating--small';
|
|
8676
|
+
case 'large':
|
|
8677
|
+
return 'rating--large';
|
|
8678
|
+
default:
|
|
8679
|
+
return 'rating--medium';
|
|
8680
|
+
}
|
|
8681
|
+
};
|
|
8682
|
+
const getDensityClass = (density = 'standard') => {
|
|
8683
|
+
switch (density) {
|
|
8684
|
+
case 'compact':
|
|
8685
|
+
return 'rating--compact';
|
|
8686
|
+
case 'comfortable':
|
|
8687
|
+
return 'rating--comfortable';
|
|
8688
|
+
default:
|
|
8689
|
+
return 'rating--standard';
|
|
8690
|
+
}
|
|
8691
|
+
};
|
|
8692
|
+
const handleItemClick = (attrs, clickValue) => {
|
|
8693
|
+
var _a;
|
|
8694
|
+
if (attrs.readonly || attrs.disabled)
|
|
8695
|
+
return;
|
|
8696
|
+
const currentValue = getCurrentValue(attrs);
|
|
8697
|
+
const newValue = attrs.clearable && currentValue === clickValue ? 0 : clickValue;
|
|
8698
|
+
if (!isControlled(attrs)) {
|
|
8699
|
+
state.internalValue = newValue;
|
|
8700
|
+
}
|
|
8701
|
+
(_a = attrs.onchange) === null || _a === void 0 ? void 0 : _a.call(attrs, newValue);
|
|
8702
|
+
};
|
|
8703
|
+
const handleItemHover = (attrs, hoverValue) => {
|
|
8704
|
+
var _a;
|
|
8705
|
+
if (attrs.readonly || attrs.disabled)
|
|
8706
|
+
return;
|
|
8707
|
+
state.hoverValue = hoverValue;
|
|
8708
|
+
state.isHovering = true;
|
|
8709
|
+
(_a = attrs.onmouseover) === null || _a === void 0 ? void 0 : _a.call(attrs, hoverValue);
|
|
8710
|
+
};
|
|
8711
|
+
const handleMouseLeave = (attrs) => {
|
|
8712
|
+
if (attrs.readonly || attrs.disabled)
|
|
8713
|
+
return;
|
|
8714
|
+
state.isHovering = false;
|
|
8715
|
+
state.hoverValue = null;
|
|
8716
|
+
};
|
|
8717
|
+
const handleKeyDown = (attrs, e) => {
|
|
8718
|
+
var _a;
|
|
8719
|
+
if (attrs.readonly || attrs.disabled)
|
|
8720
|
+
return;
|
|
8721
|
+
const max = attrs.max || 5;
|
|
8722
|
+
const step = attrs.step || 1;
|
|
8723
|
+
const currentValue = getCurrentValue(attrs);
|
|
8724
|
+
let newValue = currentValue;
|
|
8725
|
+
switch (e.key) {
|
|
8726
|
+
case 'ArrowRight':
|
|
8727
|
+
case 'ArrowUp':
|
|
8728
|
+
e.preventDefault();
|
|
8729
|
+
newValue = Math.min(max, currentValue + step);
|
|
8730
|
+
break;
|
|
8731
|
+
case 'ArrowLeft':
|
|
8732
|
+
case 'ArrowDown':
|
|
8733
|
+
e.preventDefault();
|
|
8734
|
+
newValue = Math.max(0, currentValue - step);
|
|
8735
|
+
break;
|
|
8736
|
+
case 'Home':
|
|
8737
|
+
e.preventDefault();
|
|
8738
|
+
newValue = attrs.clearable ? 0 : step;
|
|
8739
|
+
break;
|
|
8740
|
+
case 'End':
|
|
8741
|
+
e.preventDefault();
|
|
8742
|
+
newValue = max;
|
|
8743
|
+
break;
|
|
8744
|
+
case ' ':
|
|
8745
|
+
case 'Enter':
|
|
8746
|
+
e.preventDefault();
|
|
8747
|
+
// If focused and not hovering, increment by step
|
|
8748
|
+
if (!state.isHovering) {
|
|
8749
|
+
newValue = currentValue + step > max ? (attrs.clearable ? 0 : step) : currentValue + step;
|
|
8750
|
+
}
|
|
8751
|
+
break;
|
|
8752
|
+
case 'Escape':
|
|
8753
|
+
if (attrs.clearable) {
|
|
8754
|
+
e.preventDefault();
|
|
8755
|
+
newValue = 0;
|
|
8756
|
+
}
|
|
8757
|
+
break;
|
|
8758
|
+
default:
|
|
8759
|
+
return;
|
|
8760
|
+
}
|
|
8761
|
+
if (newValue !== currentValue) {
|
|
8762
|
+
if (!isControlled(attrs)) {
|
|
8763
|
+
state.internalValue = newValue;
|
|
8764
|
+
}
|
|
8765
|
+
(_a = attrs.onchange) === null || _a === void 0 ? void 0 : _a.call(attrs, newValue);
|
|
8766
|
+
}
|
|
8767
|
+
};
|
|
8768
|
+
const RatingItem = () => {
|
|
8769
|
+
return {
|
|
8770
|
+
view: ({ attrs }) => {
|
|
8771
|
+
const { index, displayValue, step, icons, allowHalfSteps, disabled, onclick, onmouseover } = attrs;
|
|
8772
|
+
const itemValue = (index + 1) * step;
|
|
8773
|
+
// Calculate fill state based on displayValue vs itemValue
|
|
8774
|
+
const diff = displayValue - itemValue;
|
|
8775
|
+
const fillState = diff >= 0 ? 'full' : allowHalfSteps && diff >= -step / 2 ? 'half' : 'empty';
|
|
8776
|
+
return m('.rating__item', {
|
|
8777
|
+
className: [
|
|
8778
|
+
fillState === 'full' ? 'rating__item--filled' : '',
|
|
8779
|
+
fillState === 'half' ? 'rating__item--half' : '',
|
|
8780
|
+
fillState !== 'empty' ? 'rating__item--active' : '',
|
|
8781
|
+
disabled ? 'rating__item--disabled' : '',
|
|
8782
|
+
]
|
|
8783
|
+
.filter(Boolean)
|
|
8784
|
+
.join(' '),
|
|
8785
|
+
onclick,
|
|
8786
|
+
onmouseover,
|
|
8787
|
+
}, [
|
|
8788
|
+
// Empty icon (background)
|
|
8789
|
+
m('.rating__icon.rating__icon--empty', { 'aria-hidden': 'true' }, typeof icons.empty === 'string' ? icons.empty : m(icons.empty)),
|
|
8790
|
+
// Filled icon (foreground)
|
|
8791
|
+
m('.rating__icon.rating__icon--filled', {
|
|
8792
|
+
'aria-hidden': 'true',
|
|
8793
|
+
style: {
|
|
8794
|
+
clipPath: fillState === 'half' ? 'inset(0 50% 0 0)' : undefined,
|
|
8795
|
+
},
|
|
8796
|
+
}, typeof icons.filled === 'string' ? icons.filled : m(icons.filled)),
|
|
8797
|
+
]);
|
|
8798
|
+
},
|
|
8799
|
+
};
|
|
8800
|
+
};
|
|
8801
|
+
return {
|
|
8802
|
+
oninit: ({ attrs }) => {
|
|
8803
|
+
const controlled = isControlled(attrs);
|
|
8804
|
+
const isNonInteractive = attrs.readonly || attrs.disabled;
|
|
8805
|
+
// Warn developer for improper controlled usage
|
|
8806
|
+
if (attrs.value !== undefined && !controlled && !isNonInteractive) {
|
|
8807
|
+
console.warn(`Rating component received 'value' prop without 'onchange' handler. ` +
|
|
8808
|
+
`Use 'defaultValue' for uncontrolled components or add 'onchange' for controlled components.`);
|
|
8809
|
+
}
|
|
8810
|
+
if (!controlled) {
|
|
8811
|
+
state.internalValue = attrs.defaultValue || 0;
|
|
8812
|
+
}
|
|
8813
|
+
},
|
|
8814
|
+
view: ({ attrs }) => {
|
|
8815
|
+
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"]);
|
|
8816
|
+
const currentValue = getCurrentValue(attrs);
|
|
8817
|
+
const displayValue = getDisplayValue(attrs);
|
|
8818
|
+
const itemCount = Math.ceil(max / step);
|
|
8819
|
+
return m('.rating', {
|
|
8820
|
+
className: [
|
|
8821
|
+
'rating',
|
|
8822
|
+
getSizeClass(size),
|
|
8823
|
+
getDensityClass(density),
|
|
8824
|
+
readonly ? 'rating--read-only' : '',
|
|
8825
|
+
disabled ? 'rating--disabled' : '',
|
|
8826
|
+
state.isFocused ? 'rating--focused' : '',
|
|
8827
|
+
className,
|
|
8828
|
+
]
|
|
8829
|
+
.filter(Boolean)
|
|
8830
|
+
.join(' '),
|
|
8831
|
+
style,
|
|
8832
|
+
id,
|
|
8833
|
+
role: readonly ? 'img' : 'slider',
|
|
8834
|
+
tabindex: readonly || disabled ? -1 : 0,
|
|
8835
|
+
'aria-valuemin': 0,
|
|
8836
|
+
'aria-valuemax': max,
|
|
8837
|
+
'aria-valuenow': currentValue,
|
|
8838
|
+
'aria-valuetext': getLabelText(currentValue, max, attrs.getLabelText),
|
|
8839
|
+
'aria-label': ariaAttrs['aria-label'] ||
|
|
8840
|
+
attrs.ariaLabel ||
|
|
8841
|
+
`Rating: ${getLabelText(currentValue, max, attrs.getLabelText)}`,
|
|
8842
|
+
'aria-labelledby': ariaAttrs['aria-labelledby'],
|
|
8843
|
+
'aria-readonly': readonly,
|
|
8844
|
+
'aria-disabled': disabled,
|
|
8845
|
+
onkeydown: (e) => handleKeyDown(attrs, e),
|
|
8846
|
+
onfocus: () => {
|
|
8847
|
+
state.isFocused = true;
|
|
8848
|
+
},
|
|
8849
|
+
onblur: () => {
|
|
8850
|
+
state.isFocused = false;
|
|
8851
|
+
handleMouseLeave(attrs);
|
|
8852
|
+
},
|
|
8853
|
+
onmouseleave: () => handleMouseLeave(attrs),
|
|
8854
|
+
}, [
|
|
8855
|
+
// Hidden input for form submission
|
|
8856
|
+
name &&
|
|
8857
|
+
m('input', {
|
|
8858
|
+
type: 'hidden',
|
|
8859
|
+
name,
|
|
8860
|
+
value: currentValue,
|
|
8861
|
+
}),
|
|
8862
|
+
// Rating items
|
|
8863
|
+
m('.rating__items', {
|
|
8864
|
+
className: 'rating__items',
|
|
8865
|
+
},
|
|
8866
|
+
// Array.from({ length: itemCount }, (_, i) => renderRatingItem(attrs, i))
|
|
8867
|
+
[...Array(itemCount)].map((_, i) => {
|
|
8868
|
+
const itemValue = (i + 1) * step;
|
|
8869
|
+
return m(RatingItem, {
|
|
8870
|
+
key: `rating-item-${i}`,
|
|
8871
|
+
index: i,
|
|
8872
|
+
displayValue: displayValue,
|
|
8873
|
+
step,
|
|
8874
|
+
icons: Object.assign(Object.assign({}, DEFAULT_ICONS), attrs.icon),
|
|
8875
|
+
allowHalfSteps: attrs.allowHalfSteps,
|
|
8876
|
+
disabled: attrs.disabled,
|
|
8877
|
+
onclick: () => handleItemClick(attrs, itemValue),
|
|
8878
|
+
onmouseover: () => handleItemHover(attrs, itemValue),
|
|
8879
|
+
});
|
|
8880
|
+
})),
|
|
8881
|
+
// Screen reader text
|
|
8882
|
+
m('.rating__sr-only', {
|
|
8883
|
+
className: 'rating__sr-only',
|
|
8884
|
+
'aria-live': 'polite',
|
|
8885
|
+
'aria-atomic': 'true',
|
|
8886
|
+
}, getLabelText(displayValue, max, attrs.getLabelText)),
|
|
8887
|
+
]);
|
|
8888
|
+
},
|
|
8889
|
+
};
|
|
8890
|
+
};
|
|
8891
|
+
|
|
8549
8892
|
/**
|
|
8550
8893
|
* @fileoverview Core TypeScript utility types for mithril-materialized library
|
|
8551
8894
|
* These types improve type safety and developer experience across all components
|
|
@@ -8614,6 +8957,7 @@ exports.PushpinComponent = PushpinComponent;
|
|
|
8614
8957
|
exports.RadioButton = RadioButton;
|
|
8615
8958
|
exports.RadioButtons = RadioButtons;
|
|
8616
8959
|
exports.RangeInput = RangeInput;
|
|
8960
|
+
exports.Rating = Rating;
|
|
8617
8961
|
exports.RoundIconButton = RoundIconButton;
|
|
8618
8962
|
exports.SearchSelect = SearchSelect;
|
|
8619
8963
|
exports.SecondaryContent = SecondaryContent;
|