mithril-materialized 3.2.1 → 3.2.2
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/core.css +3 -0
- package/dist/forms.css +3 -0
- package/dist/index.css +3 -0
- package/dist/index.esm.js +156 -92
- package/dist/index.js +156 -92
- package/dist/index.min.css +1 -1
- package/dist/index.umd.js +156 -92
- package/package.json +5 -5
- package/sass/components/forms/_input-fields.scss +3 -0
package/dist/core.css
CHANGED
package/dist/forms.css
CHANGED
package/dist/index.css
CHANGED
package/dist/index.esm.js
CHANGED
|
@@ -2789,10 +2789,6 @@ const CharacterCounter = () => {
|
|
|
2789
2789
|
return m('span.character-counter', {
|
|
2790
2790
|
style: {
|
|
2791
2791
|
color: isOverLimit ? '#F44336' : '#9e9e9e',
|
|
2792
|
-
fontSize: '12px',
|
|
2793
|
-
display: 'block',
|
|
2794
|
-
textAlign: 'right',
|
|
2795
|
-
marginTop: '8px',
|
|
2796
2792
|
},
|
|
2797
2793
|
}, `${currentLength}/${maxLength}`);
|
|
2798
2794
|
},
|
|
@@ -2809,10 +2805,51 @@ const TextArea = () => {
|
|
|
2809
2805
|
textarea: undefined,
|
|
2810
2806
|
internalValue: '',
|
|
2811
2807
|
};
|
|
2812
|
-
const updateHeight = (textarea) => {
|
|
2813
|
-
textarea
|
|
2814
|
-
|
|
2815
|
-
|
|
2808
|
+
const updateHeight = (textarea, hiddenDiv) => {
|
|
2809
|
+
if (!textarea || !hiddenDiv)
|
|
2810
|
+
return;
|
|
2811
|
+
// Copy font properties from textarea to hidden div
|
|
2812
|
+
const computedStyle = window.getComputedStyle(textarea);
|
|
2813
|
+
hiddenDiv.style.fontFamily = computedStyle.fontFamily;
|
|
2814
|
+
hiddenDiv.style.fontSize = computedStyle.fontSize;
|
|
2815
|
+
hiddenDiv.style.lineHeight = computedStyle.lineHeight;
|
|
2816
|
+
// Copy padding from textarea (important for accurate measurement)
|
|
2817
|
+
hiddenDiv.style.paddingTop = computedStyle.paddingTop;
|
|
2818
|
+
hiddenDiv.style.paddingRight = computedStyle.paddingRight;
|
|
2819
|
+
hiddenDiv.style.paddingBottom = computedStyle.paddingBottom;
|
|
2820
|
+
hiddenDiv.style.paddingLeft = computedStyle.paddingLeft;
|
|
2821
|
+
// Handle text wrapping
|
|
2822
|
+
if (textarea.getAttribute('wrap') === 'off') {
|
|
2823
|
+
hiddenDiv.style.overflowWrap = 'normal';
|
|
2824
|
+
hiddenDiv.style.whiteSpace = 'pre';
|
|
2825
|
+
}
|
|
2826
|
+
else {
|
|
2827
|
+
hiddenDiv.style.overflowWrap = 'break-word';
|
|
2828
|
+
hiddenDiv.style.whiteSpace = 'pre-wrap';
|
|
2829
|
+
}
|
|
2830
|
+
// Set content with extra newline for measurement
|
|
2831
|
+
hiddenDiv.textContent = textarea.value + '\n';
|
|
2832
|
+
const content = hiddenDiv.innerHTML.replace(/\n/g, '<br>');
|
|
2833
|
+
hiddenDiv.innerHTML = content;
|
|
2834
|
+
// Set width to match textarea
|
|
2835
|
+
if (textarea.offsetWidth > 0) {
|
|
2836
|
+
hiddenDiv.style.width = textarea.offsetWidth + 'px';
|
|
2837
|
+
}
|
|
2838
|
+
else {
|
|
2839
|
+
hiddenDiv.style.width = window.innerWidth / 2 + 'px';
|
|
2840
|
+
}
|
|
2841
|
+
// Get the original/natural height of the textarea
|
|
2842
|
+
const originalHeight = textarea.offsetHeight;
|
|
2843
|
+
const measuredHeight = hiddenDiv.offsetHeight;
|
|
2844
|
+
// Key logic: Only set custom height when content requires MORE space than original height
|
|
2845
|
+
// This matches the Materialize CSS reference behavior
|
|
2846
|
+
if (originalHeight <= measuredHeight) {
|
|
2847
|
+
state.height = measuredHeight + 'px';
|
|
2848
|
+
}
|
|
2849
|
+
else {
|
|
2850
|
+
// Single line content or content that fits in original height - let CSS handle it
|
|
2851
|
+
state.height = undefined;
|
|
2852
|
+
}
|
|
2816
2853
|
};
|
|
2817
2854
|
const isControlled = (attrs) => attrs.value !== undefined && attrs.oninput !== undefined;
|
|
2818
2855
|
return {
|
|
@@ -2828,92 +2865,117 @@ const TextArea = () => {
|
|
|
2828
2865
|
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"]);
|
|
2829
2866
|
const controlled = isControlled(attrs);
|
|
2830
2867
|
const currentValue = controlled ? value || '' : state.internalValue;
|
|
2831
|
-
return
|
|
2832
|
-
|
|
2833
|
-
m('
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
const textarea = dom;
|
|
2849
|
-
if (state.height)
|
|
2850
|
-
textarea.style.height = state.height;
|
|
2851
|
-
// No need to manually sync in onupdate since value attribute handles it
|
|
2852
|
-
}, onfocus: () => {
|
|
2853
|
-
state.active = true;
|
|
2854
|
-
}, oninput: (e) => {
|
|
2855
|
-
state.active = true;
|
|
2856
|
-
state.hasInteracted = false;
|
|
2857
|
-
const target = e.target;
|
|
2858
|
-
// Update height for auto-resize
|
|
2859
|
-
updateHeight(target);
|
|
2860
|
-
// Update character count
|
|
2861
|
-
if (maxLength) {
|
|
2862
|
-
state.currentLength = target.value.length;
|
|
2863
|
-
state.hasInteracted = target.value.length > 0;
|
|
2864
|
-
}
|
|
2865
|
-
// Update internal state for uncontrolled mode
|
|
2866
|
-
if (!controlled) {
|
|
2867
|
-
state.internalValue = target.value;
|
|
2868
|
-
}
|
|
2869
|
-
// Call oninput handler
|
|
2870
|
-
if (oninput) {
|
|
2871
|
-
oninput(target.value);
|
|
2872
|
-
}
|
|
2873
|
-
}, onblur: (e) => {
|
|
2874
|
-
state.active = false;
|
|
2875
|
-
// const target = e.target as HTMLTextAreaElement;
|
|
2876
|
-
state.hasInteracted = true;
|
|
2877
|
-
// Call original onblur if provided
|
|
2878
|
-
if (onblur) {
|
|
2879
|
-
onblur(e);
|
|
2880
|
-
}
|
|
2881
|
-
if (onchange && state.textarea) {
|
|
2882
|
-
onchange(state.textarea.value);
|
|
2883
|
-
}
|
|
2884
|
-
}, onkeyup: onkeyup
|
|
2885
|
-
? (ev) => {
|
|
2886
|
-
onkeyup(ev, ev.target.value);
|
|
2887
|
-
}
|
|
2888
|
-
: undefined, onkeydown: onkeydown
|
|
2889
|
-
? (ev) => {
|
|
2890
|
-
onkeydown(ev, ev.target.value);
|
|
2868
|
+
return [
|
|
2869
|
+
// Hidden div for height measurement - positioned outside the input-field
|
|
2870
|
+
m('.hiddendiv', {
|
|
2871
|
+
style: {
|
|
2872
|
+
visibility: 'hidden',
|
|
2873
|
+
position: 'absolute',
|
|
2874
|
+
top: '0',
|
|
2875
|
+
left: '0',
|
|
2876
|
+
zIndex: '-1',
|
|
2877
|
+
whiteSpace: 'pre-wrap',
|
|
2878
|
+
wordWrap: 'break-word',
|
|
2879
|
+
overflowWrap: 'break-word',
|
|
2880
|
+
},
|
|
2881
|
+
oncreate: ({ dom }) => {
|
|
2882
|
+
const hiddenDiv = dom;
|
|
2883
|
+
if (state.textarea) {
|
|
2884
|
+
updateHeight(state.textarea, hiddenDiv);
|
|
2891
2885
|
}
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2886
|
+
},
|
|
2887
|
+
onupdate: ({ dom }) => {
|
|
2888
|
+
const hiddenDiv = dom;
|
|
2889
|
+
if (state.textarea) {
|
|
2890
|
+
updateHeight(state.textarea, hiddenDiv);
|
|
2895
2891
|
}
|
|
2896
|
-
|
|
2897
|
-
m(Label, {
|
|
2898
|
-
label,
|
|
2899
|
-
id,
|
|
2900
|
-
isMandatory,
|
|
2901
|
-
isActive: currentValue || placeholder || state.active,
|
|
2902
|
-
initialValue: currentValue !== '',
|
|
2903
|
-
}),
|
|
2904
|
-
m(HelperText, {
|
|
2905
|
-
helperText,
|
|
2906
|
-
dataError: state.hasInteracted && attrs.dataError ? attrs.dataError : undefined,
|
|
2907
|
-
dataSuccess: state.hasInteracted && attrs.dataSuccess ? attrs.dataSuccess : undefined,
|
|
2892
|
+
},
|
|
2908
2893
|
}),
|
|
2909
|
-
|
|
2910
|
-
? m(
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2894
|
+
m('.input-field', { className, style }, [
|
|
2895
|
+
iconName ? m('i.material-icons.prefix', iconName) : '',
|
|
2896
|
+
m('textarea.materialize-textarea', Object.assign(Object.assign({}, params), { id, tabindex: 0, value: controlled ? currentValue : undefined, style: {
|
|
2897
|
+
height: state.height,
|
|
2898
|
+
}, oncreate: ({ dom }) => {
|
|
2899
|
+
const textarea = (state.textarea = dom);
|
|
2900
|
+
// For uncontrolled mode, set initial value only
|
|
2901
|
+
if (!controlled && attrs.defaultValue !== undefined) {
|
|
2902
|
+
textarea.value = String(attrs.defaultValue);
|
|
2903
|
+
}
|
|
2904
|
+
// Height will be calculated by hidden div
|
|
2905
|
+
// Update character count state for counter component
|
|
2906
|
+
if (maxLength) {
|
|
2907
|
+
state.currentLength = textarea.value.length;
|
|
2908
|
+
}
|
|
2909
|
+
}, onupdate: ({ dom }) => {
|
|
2910
|
+
const textarea = dom;
|
|
2911
|
+
if (state.height)
|
|
2912
|
+
textarea.style.height = state.height;
|
|
2913
|
+
// No need to manually sync in onupdate since value attribute handles it
|
|
2914
|
+
}, onfocus: () => {
|
|
2915
|
+
state.active = true;
|
|
2916
|
+
}, oninput: (e) => {
|
|
2917
|
+
state.active = true;
|
|
2918
|
+
state.hasInteracted = false;
|
|
2919
|
+
const target = e.target;
|
|
2920
|
+
// Height will be recalculated by hidden div on next update
|
|
2921
|
+
// Update character count
|
|
2922
|
+
if (maxLength) {
|
|
2923
|
+
state.currentLength = target.value.length;
|
|
2924
|
+
state.hasInteracted = target.value.length > 0;
|
|
2925
|
+
}
|
|
2926
|
+
// Update internal state for uncontrolled mode
|
|
2927
|
+
if (!controlled) {
|
|
2928
|
+
state.internalValue = target.value;
|
|
2929
|
+
}
|
|
2930
|
+
// Call oninput handler
|
|
2931
|
+
if (oninput) {
|
|
2932
|
+
oninput(target.value);
|
|
2933
|
+
}
|
|
2934
|
+
}, onblur: (e) => {
|
|
2935
|
+
state.active = false;
|
|
2936
|
+
// const target = e.target as HTMLTextAreaElement;
|
|
2937
|
+
state.hasInteracted = true;
|
|
2938
|
+
// Call original onblur if provided
|
|
2939
|
+
if (onblur) {
|
|
2940
|
+
onblur(e);
|
|
2941
|
+
}
|
|
2942
|
+
if (onchange && state.textarea) {
|
|
2943
|
+
onchange(state.textarea.value);
|
|
2944
|
+
}
|
|
2945
|
+
}, onkeyup: onkeyup
|
|
2946
|
+
? (ev) => {
|
|
2947
|
+
onkeyup(ev, ev.target.value);
|
|
2948
|
+
}
|
|
2949
|
+
: undefined, onkeydown: onkeydown
|
|
2950
|
+
? (ev) => {
|
|
2951
|
+
onkeydown(ev, ev.target.value);
|
|
2952
|
+
}
|
|
2953
|
+
: undefined, onkeypress: onkeypress
|
|
2954
|
+
? (ev) => {
|
|
2955
|
+
onkeypress(ev, ev.target.value);
|
|
2956
|
+
}
|
|
2957
|
+
: undefined })),
|
|
2958
|
+
m(Label, {
|
|
2959
|
+
label,
|
|
2960
|
+
id,
|
|
2961
|
+
isMandatory,
|
|
2962
|
+
isActive: currentValue || placeholder || state.active,
|
|
2963
|
+
initialValue: currentValue !== '',
|
|
2964
|
+
}),
|
|
2965
|
+
m(HelperText, {
|
|
2966
|
+
helperText,
|
|
2967
|
+
dataError: state.hasInteracted && attrs.dataError ? attrs.dataError : undefined,
|
|
2968
|
+
dataSuccess: state.hasInteracted && attrs.dataSuccess ? attrs.dataSuccess : undefined,
|
|
2969
|
+
}),
|
|
2970
|
+
maxLength
|
|
2971
|
+
? m(CharacterCounter, {
|
|
2972
|
+
currentLength: state.currentLength,
|
|
2973
|
+
maxLength,
|
|
2974
|
+
show: state.currentLength > 0,
|
|
2975
|
+
})
|
|
2976
|
+
: undefined,
|
|
2977
|
+
]),
|
|
2978
|
+
];
|
|
2917
2979
|
},
|
|
2918
2980
|
};
|
|
2919
2981
|
};
|
|
@@ -3085,7 +3147,9 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
3085
3147
|
state.isValid = true;
|
|
3086
3148
|
}
|
|
3087
3149
|
}
|
|
3088
|
-
else if ((type === 'email' || type === 'url') &&
|
|
3150
|
+
else if ((type === 'email' || type === 'url') &&
|
|
3151
|
+
target.classList.contains('invalid') &&
|
|
3152
|
+
target.value.length > 0) {
|
|
3089
3153
|
// Clear native validation errors if user is typing and input becomes valid
|
|
3090
3154
|
if (target.validity.valid) {
|
|
3091
3155
|
target.classList.remove('invalid');
|
package/dist/index.js
CHANGED
|
@@ -2791,10 +2791,6 @@ const CharacterCounter = () => {
|
|
|
2791
2791
|
return m('span.character-counter', {
|
|
2792
2792
|
style: {
|
|
2793
2793
|
color: isOverLimit ? '#F44336' : '#9e9e9e',
|
|
2794
|
-
fontSize: '12px',
|
|
2795
|
-
display: 'block',
|
|
2796
|
-
textAlign: 'right',
|
|
2797
|
-
marginTop: '8px',
|
|
2798
2794
|
},
|
|
2799
2795
|
}, `${currentLength}/${maxLength}`);
|
|
2800
2796
|
},
|
|
@@ -2811,10 +2807,51 @@ const TextArea = () => {
|
|
|
2811
2807
|
textarea: undefined,
|
|
2812
2808
|
internalValue: '',
|
|
2813
2809
|
};
|
|
2814
|
-
const updateHeight = (textarea) => {
|
|
2815
|
-
textarea
|
|
2816
|
-
|
|
2817
|
-
|
|
2810
|
+
const updateHeight = (textarea, hiddenDiv) => {
|
|
2811
|
+
if (!textarea || !hiddenDiv)
|
|
2812
|
+
return;
|
|
2813
|
+
// Copy font properties from textarea to hidden div
|
|
2814
|
+
const computedStyle = window.getComputedStyle(textarea);
|
|
2815
|
+
hiddenDiv.style.fontFamily = computedStyle.fontFamily;
|
|
2816
|
+
hiddenDiv.style.fontSize = computedStyle.fontSize;
|
|
2817
|
+
hiddenDiv.style.lineHeight = computedStyle.lineHeight;
|
|
2818
|
+
// Copy padding from textarea (important for accurate measurement)
|
|
2819
|
+
hiddenDiv.style.paddingTop = computedStyle.paddingTop;
|
|
2820
|
+
hiddenDiv.style.paddingRight = computedStyle.paddingRight;
|
|
2821
|
+
hiddenDiv.style.paddingBottom = computedStyle.paddingBottom;
|
|
2822
|
+
hiddenDiv.style.paddingLeft = computedStyle.paddingLeft;
|
|
2823
|
+
// Handle text wrapping
|
|
2824
|
+
if (textarea.getAttribute('wrap') === 'off') {
|
|
2825
|
+
hiddenDiv.style.overflowWrap = 'normal';
|
|
2826
|
+
hiddenDiv.style.whiteSpace = 'pre';
|
|
2827
|
+
}
|
|
2828
|
+
else {
|
|
2829
|
+
hiddenDiv.style.overflowWrap = 'break-word';
|
|
2830
|
+
hiddenDiv.style.whiteSpace = 'pre-wrap';
|
|
2831
|
+
}
|
|
2832
|
+
// Set content with extra newline for measurement
|
|
2833
|
+
hiddenDiv.textContent = textarea.value + '\n';
|
|
2834
|
+
const content = hiddenDiv.innerHTML.replace(/\n/g, '<br>');
|
|
2835
|
+
hiddenDiv.innerHTML = content;
|
|
2836
|
+
// Set width to match textarea
|
|
2837
|
+
if (textarea.offsetWidth > 0) {
|
|
2838
|
+
hiddenDiv.style.width = textarea.offsetWidth + 'px';
|
|
2839
|
+
}
|
|
2840
|
+
else {
|
|
2841
|
+
hiddenDiv.style.width = window.innerWidth / 2 + 'px';
|
|
2842
|
+
}
|
|
2843
|
+
// Get the original/natural height of the textarea
|
|
2844
|
+
const originalHeight = textarea.offsetHeight;
|
|
2845
|
+
const measuredHeight = hiddenDiv.offsetHeight;
|
|
2846
|
+
// Key logic: Only set custom height when content requires MORE space than original height
|
|
2847
|
+
// This matches the Materialize CSS reference behavior
|
|
2848
|
+
if (originalHeight <= measuredHeight) {
|
|
2849
|
+
state.height = measuredHeight + 'px';
|
|
2850
|
+
}
|
|
2851
|
+
else {
|
|
2852
|
+
// Single line content or content that fits in original height - let CSS handle it
|
|
2853
|
+
state.height = undefined;
|
|
2854
|
+
}
|
|
2818
2855
|
};
|
|
2819
2856
|
const isControlled = (attrs) => attrs.value !== undefined && attrs.oninput !== undefined;
|
|
2820
2857
|
return {
|
|
@@ -2830,92 +2867,117 @@ const TextArea = () => {
|
|
|
2830
2867
|
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"]);
|
|
2831
2868
|
const controlled = isControlled(attrs);
|
|
2832
2869
|
const currentValue = controlled ? value || '' : state.internalValue;
|
|
2833
|
-
return
|
|
2834
|
-
|
|
2835
|
-
m('
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
const textarea = dom;
|
|
2851
|
-
if (state.height)
|
|
2852
|
-
textarea.style.height = state.height;
|
|
2853
|
-
// No need to manually sync in onupdate since value attribute handles it
|
|
2854
|
-
}, onfocus: () => {
|
|
2855
|
-
state.active = true;
|
|
2856
|
-
}, oninput: (e) => {
|
|
2857
|
-
state.active = true;
|
|
2858
|
-
state.hasInteracted = false;
|
|
2859
|
-
const target = e.target;
|
|
2860
|
-
// Update height for auto-resize
|
|
2861
|
-
updateHeight(target);
|
|
2862
|
-
// Update character count
|
|
2863
|
-
if (maxLength) {
|
|
2864
|
-
state.currentLength = target.value.length;
|
|
2865
|
-
state.hasInteracted = target.value.length > 0;
|
|
2866
|
-
}
|
|
2867
|
-
// Update internal state for uncontrolled mode
|
|
2868
|
-
if (!controlled) {
|
|
2869
|
-
state.internalValue = target.value;
|
|
2870
|
-
}
|
|
2871
|
-
// Call oninput handler
|
|
2872
|
-
if (oninput) {
|
|
2873
|
-
oninput(target.value);
|
|
2874
|
-
}
|
|
2875
|
-
}, onblur: (e) => {
|
|
2876
|
-
state.active = false;
|
|
2877
|
-
// const target = e.target as HTMLTextAreaElement;
|
|
2878
|
-
state.hasInteracted = true;
|
|
2879
|
-
// Call original onblur if provided
|
|
2880
|
-
if (onblur) {
|
|
2881
|
-
onblur(e);
|
|
2882
|
-
}
|
|
2883
|
-
if (onchange && state.textarea) {
|
|
2884
|
-
onchange(state.textarea.value);
|
|
2885
|
-
}
|
|
2886
|
-
}, onkeyup: onkeyup
|
|
2887
|
-
? (ev) => {
|
|
2888
|
-
onkeyup(ev, ev.target.value);
|
|
2889
|
-
}
|
|
2890
|
-
: undefined, onkeydown: onkeydown
|
|
2891
|
-
? (ev) => {
|
|
2892
|
-
onkeydown(ev, ev.target.value);
|
|
2870
|
+
return [
|
|
2871
|
+
// Hidden div for height measurement - positioned outside the input-field
|
|
2872
|
+
m('.hiddendiv', {
|
|
2873
|
+
style: {
|
|
2874
|
+
visibility: 'hidden',
|
|
2875
|
+
position: 'absolute',
|
|
2876
|
+
top: '0',
|
|
2877
|
+
left: '0',
|
|
2878
|
+
zIndex: '-1',
|
|
2879
|
+
whiteSpace: 'pre-wrap',
|
|
2880
|
+
wordWrap: 'break-word',
|
|
2881
|
+
overflowWrap: 'break-word',
|
|
2882
|
+
},
|
|
2883
|
+
oncreate: ({ dom }) => {
|
|
2884
|
+
const hiddenDiv = dom;
|
|
2885
|
+
if (state.textarea) {
|
|
2886
|
+
updateHeight(state.textarea, hiddenDiv);
|
|
2893
2887
|
}
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2888
|
+
},
|
|
2889
|
+
onupdate: ({ dom }) => {
|
|
2890
|
+
const hiddenDiv = dom;
|
|
2891
|
+
if (state.textarea) {
|
|
2892
|
+
updateHeight(state.textarea, hiddenDiv);
|
|
2897
2893
|
}
|
|
2898
|
-
|
|
2899
|
-
m(Label, {
|
|
2900
|
-
label,
|
|
2901
|
-
id,
|
|
2902
|
-
isMandatory,
|
|
2903
|
-
isActive: currentValue || placeholder || state.active,
|
|
2904
|
-
initialValue: currentValue !== '',
|
|
2905
|
-
}),
|
|
2906
|
-
m(HelperText, {
|
|
2907
|
-
helperText,
|
|
2908
|
-
dataError: state.hasInteracted && attrs.dataError ? attrs.dataError : undefined,
|
|
2909
|
-
dataSuccess: state.hasInteracted && attrs.dataSuccess ? attrs.dataSuccess : undefined,
|
|
2894
|
+
},
|
|
2910
2895
|
}),
|
|
2911
|
-
|
|
2912
|
-
? m(
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2896
|
+
m('.input-field', { className, style }, [
|
|
2897
|
+
iconName ? m('i.material-icons.prefix', iconName) : '',
|
|
2898
|
+
m('textarea.materialize-textarea', Object.assign(Object.assign({}, params), { id, tabindex: 0, value: controlled ? currentValue : undefined, style: {
|
|
2899
|
+
height: state.height,
|
|
2900
|
+
}, oncreate: ({ dom }) => {
|
|
2901
|
+
const textarea = (state.textarea = dom);
|
|
2902
|
+
// For uncontrolled mode, set initial value only
|
|
2903
|
+
if (!controlled && attrs.defaultValue !== undefined) {
|
|
2904
|
+
textarea.value = String(attrs.defaultValue);
|
|
2905
|
+
}
|
|
2906
|
+
// Height will be calculated by hidden div
|
|
2907
|
+
// Update character count state for counter component
|
|
2908
|
+
if (maxLength) {
|
|
2909
|
+
state.currentLength = textarea.value.length;
|
|
2910
|
+
}
|
|
2911
|
+
}, onupdate: ({ dom }) => {
|
|
2912
|
+
const textarea = dom;
|
|
2913
|
+
if (state.height)
|
|
2914
|
+
textarea.style.height = state.height;
|
|
2915
|
+
// No need to manually sync in onupdate since value attribute handles it
|
|
2916
|
+
}, onfocus: () => {
|
|
2917
|
+
state.active = true;
|
|
2918
|
+
}, oninput: (e) => {
|
|
2919
|
+
state.active = true;
|
|
2920
|
+
state.hasInteracted = false;
|
|
2921
|
+
const target = e.target;
|
|
2922
|
+
// Height will be recalculated by hidden div on next update
|
|
2923
|
+
// Update character count
|
|
2924
|
+
if (maxLength) {
|
|
2925
|
+
state.currentLength = target.value.length;
|
|
2926
|
+
state.hasInteracted = target.value.length > 0;
|
|
2927
|
+
}
|
|
2928
|
+
// Update internal state for uncontrolled mode
|
|
2929
|
+
if (!controlled) {
|
|
2930
|
+
state.internalValue = target.value;
|
|
2931
|
+
}
|
|
2932
|
+
// Call oninput handler
|
|
2933
|
+
if (oninput) {
|
|
2934
|
+
oninput(target.value);
|
|
2935
|
+
}
|
|
2936
|
+
}, onblur: (e) => {
|
|
2937
|
+
state.active = false;
|
|
2938
|
+
// const target = e.target as HTMLTextAreaElement;
|
|
2939
|
+
state.hasInteracted = true;
|
|
2940
|
+
// Call original onblur if provided
|
|
2941
|
+
if (onblur) {
|
|
2942
|
+
onblur(e);
|
|
2943
|
+
}
|
|
2944
|
+
if (onchange && state.textarea) {
|
|
2945
|
+
onchange(state.textarea.value);
|
|
2946
|
+
}
|
|
2947
|
+
}, onkeyup: onkeyup
|
|
2948
|
+
? (ev) => {
|
|
2949
|
+
onkeyup(ev, ev.target.value);
|
|
2950
|
+
}
|
|
2951
|
+
: undefined, onkeydown: onkeydown
|
|
2952
|
+
? (ev) => {
|
|
2953
|
+
onkeydown(ev, ev.target.value);
|
|
2954
|
+
}
|
|
2955
|
+
: undefined, onkeypress: onkeypress
|
|
2956
|
+
? (ev) => {
|
|
2957
|
+
onkeypress(ev, ev.target.value);
|
|
2958
|
+
}
|
|
2959
|
+
: undefined })),
|
|
2960
|
+
m(Label, {
|
|
2961
|
+
label,
|
|
2962
|
+
id,
|
|
2963
|
+
isMandatory,
|
|
2964
|
+
isActive: currentValue || placeholder || state.active,
|
|
2965
|
+
initialValue: currentValue !== '',
|
|
2966
|
+
}),
|
|
2967
|
+
m(HelperText, {
|
|
2968
|
+
helperText,
|
|
2969
|
+
dataError: state.hasInteracted && attrs.dataError ? attrs.dataError : undefined,
|
|
2970
|
+
dataSuccess: state.hasInteracted && attrs.dataSuccess ? attrs.dataSuccess : undefined,
|
|
2971
|
+
}),
|
|
2972
|
+
maxLength
|
|
2973
|
+
? m(CharacterCounter, {
|
|
2974
|
+
currentLength: state.currentLength,
|
|
2975
|
+
maxLength,
|
|
2976
|
+
show: state.currentLength > 0,
|
|
2977
|
+
})
|
|
2978
|
+
: undefined,
|
|
2979
|
+
]),
|
|
2980
|
+
];
|
|
2919
2981
|
},
|
|
2920
2982
|
};
|
|
2921
2983
|
};
|
|
@@ -3087,7 +3149,9 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
3087
3149
|
state.isValid = true;
|
|
3088
3150
|
}
|
|
3089
3151
|
}
|
|
3090
|
-
else if ((type === 'email' || type === 'url') &&
|
|
3152
|
+
else if ((type === 'email' || type === 'url') &&
|
|
3153
|
+
target.classList.contains('invalid') &&
|
|
3154
|
+
target.value.length > 0) {
|
|
3091
3155
|
// Clear native validation errors if user is typing and input becomes valid
|
|
3092
3156
|
if (target.validity.valid) {
|
|
3093
3157
|
target.classList.remove('invalid');
|