mithril-materialized 3.3.6 → 3.3.8

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/index.esm.js CHANGED
@@ -2811,6 +2811,7 @@ const TextArea = () => {
2811
2811
  height: undefined,
2812
2812
  active: false,
2813
2813
  textarea: undefined,
2814
+ hiddenDiv: undefined,
2814
2815
  internalValue: '',
2815
2816
  };
2816
2817
  const updateHeight = (textarea, hiddenDiv) => {
@@ -2907,13 +2908,13 @@ const TextArea = () => {
2907
2908
  overflowWrap: 'break-word',
2908
2909
  },
2909
2910
  oncreate: ({ dom }) => {
2910
- const hiddenDiv = dom;
2911
+ const hiddenDiv = state.hiddenDiv = dom;
2911
2912
  if (state.textarea) {
2912
2913
  updateHeight(state.textarea, hiddenDiv);
2913
2914
  }
2914
2915
  },
2915
2916
  onupdate: ({ dom }) => {
2916
- const hiddenDiv = dom;
2917
+ const hiddenDiv = state.hiddenDiv = dom;
2917
2918
  if (state.textarea) {
2918
2919
  updateHeight(state.textarea, hiddenDiv);
2919
2920
  }
@@ -2938,7 +2939,10 @@ const TextArea = () => {
2938
2939
  const textarea = dom;
2939
2940
  if (state.height)
2940
2941
  textarea.style.height = state.height;
2941
- // No need to manually sync in onupdate since value attribute handles it
2942
+ // Trigger height recalculation when value changes programmatically
2943
+ if (state.hiddenDiv) {
2944
+ updateHeight(textarea, state.hiddenDiv);
2945
+ }
2942
2946
  }, onfocus: () => {
2943
2947
  state.active = true;
2944
2948
  }, oninput: (e) => {
@@ -3098,9 +3102,6 @@ const InputField = (type, defaultClass = '') => () => {
3098
3102
  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"]);
3099
3103
  // const attributes = toAttrs(params);
3100
3104
  const cn = [newRow ? 'clear' : '', defaultClass, className].filter(Boolean).join(' ').trim() || undefined;
3101
- const isActive = state.active || ((_a = state.inputElement) === null || _a === void 0 ? void 0 : _a.value) || placeholder || type === 'color' || type === 'range'
3102
- ? true
3103
- : false;
3104
3105
  // Special rendering for minmax range sliders
3105
3106
  if (type === 'range' && (attrs.minmax || attrs.valueDisplay)) {
3106
3107
  return m(attrs.minmax ? DoubleRangeSlider : SingleRangeSlider, Object.assign(Object.assign({}, attrs), { state,
@@ -3121,12 +3122,15 @@ const InputField = (type, defaultClass = '') => () => {
3121
3122
  }
3122
3123
  else if (isNonInteractive) {
3123
3124
  // Non-interactive components: prefer defaultValue, fallback to value
3124
- value = ((_c = (_b = attrs.defaultValue) !== null && _b !== void 0 ? _b : attrs.value) !== null && _c !== void 0 ? _c : (isNumeric ? 0 : ''));
3125
+ value = ((_b = (_a = attrs.defaultValue) !== null && _a !== void 0 ? _a : attrs.value) !== null && _b !== void 0 ? _b : (isNumeric ? 0 : ''));
3125
3126
  }
3126
3127
  else {
3127
3128
  // Interactive uncontrolled: use internal state
3128
- value = ((_e = (_d = state.internalValue) !== null && _d !== void 0 ? _d : attrs.defaultValue) !== null && _e !== void 0 ? _e : (isNumeric ? 0 : ''));
3129
+ value = ((_d = (_c = state.internalValue) !== null && _c !== void 0 ? _c : attrs.defaultValue) !== null && _d !== void 0 ? _d : (isNumeric ? 0 : ''));
3129
3130
  }
3131
+ const isActive = state.active || ((_e = state.inputElement) === null || _e === void 0 ? void 0 : _e.value) || value || placeholder || type === 'color' || type === 'range'
3132
+ ? true
3133
+ : false;
3130
3134
  const rangeType = type === 'range' && !attrs.minmax;
3131
3135
  return m('.input-field', { className: cn, style }, [
3132
3136
  iconName ? m('i.material-icons.prefix', iconName) : undefined,
@@ -5752,11 +5756,13 @@ const RadioButtons = () => {
5752
5756
  const Select = () => {
5753
5757
  const state = {
5754
5758
  id: '',
5759
+ dropdownId: '',
5755
5760
  isOpen: false,
5756
5761
  focusedIndex: -1,
5757
5762
  inputRef: null,
5758
5763
  dropdownRef: null,
5759
5764
  internalSelectedIds: [],
5765
+ isInsideModal: false,
5760
5766
  };
5761
5767
  const isControlled = (attrs) => attrs.checkedId !== undefined && attrs.onchange !== undefined;
5762
5768
  const isSelected = (id, selectedIds) => {
@@ -5845,9 +5851,124 @@ const Select = () => {
5845
5851
  m.redraw();
5846
5852
  }
5847
5853
  };
5854
+ const getPortalStyles = (inputRef) => {
5855
+ if (!inputRef)
5856
+ return {};
5857
+ const rect = inputRef.getBoundingClientRect();
5858
+ const viewportHeight = window.innerHeight;
5859
+ return {
5860
+ position: 'fixed',
5861
+ top: `${rect.bottom}px`,
5862
+ left: `${rect.left}px`,
5863
+ width: `${rect.width}px`,
5864
+ zIndex: 10000, // Higher than modal z-index
5865
+ maxHeight: `${viewportHeight - rect.bottom - 20}px`, // Leave 20px margin from bottom
5866
+ };
5867
+ };
5868
+ const renderDropdownContent = (attrs, selectedIds, multiple, placeholder) => [
5869
+ placeholder && m('li.disabled', { tabindex: 0 }, m('span', placeholder)),
5870
+ // Render ungrouped options first
5871
+ attrs.options
5872
+ .filter((option) => !option.group)
5873
+ .map((option) => m('li', Object.assign({ key: option.id, class: option.disabled
5874
+ ? 'disabled'
5875
+ : state.focusedIndex === attrs.options.indexOf(option)
5876
+ ? 'focused'
5877
+ : '' }, (option.disabled
5878
+ ? {}
5879
+ : {
5880
+ onclick: (e) => {
5881
+ e.stopPropagation();
5882
+ toggleOption(option.id, multiple, attrs);
5883
+ },
5884
+ })), [
5885
+ option.img && m('img', { src: option.img, alt: option.label }),
5886
+ m('span', [
5887
+ multiple
5888
+ ? m('label', { for: option.id }, m('input', {
5889
+ id: option.id,
5890
+ type: 'checkbox',
5891
+ checked: selectedIds.includes(option.id),
5892
+ disabled: option.disabled ? true : undefined,
5893
+ onclick: (e) => {
5894
+ e.stopPropagation();
5895
+ },
5896
+ }), m('span', option.label))
5897
+ : m('span', option.label),
5898
+ ].filter(Boolean)),
5899
+ ])),
5900
+ // Render grouped options
5901
+ Object.entries(attrs.options
5902
+ .filter((option) => option.group)
5903
+ .reduce((groups, option) => {
5904
+ const group = option.group;
5905
+ if (!groups[group])
5906
+ groups[group] = [];
5907
+ groups[group].push(option);
5908
+ return groups;
5909
+ }, {}))
5910
+ .map(([groupName, groupOptions]) => [
5911
+ m('li.optgroup', { key: `group-${groupName}`, tabindex: 0 }, m('span', groupName)),
5912
+ ...groupOptions.map((option) => m('li', Object.assign({ key: option.id, class: `optgroup-option${option.disabled ? ' disabled' : ''}${isSelected(option.id, selectedIds) ? ' selected' : ''}${state.focusedIndex === attrs.options.indexOf(option) ? ' focused' : ''}` }, (option.disabled
5913
+ ? {}
5914
+ : {
5915
+ onclick: (e) => {
5916
+ e.stopPropagation();
5917
+ toggleOption(option.id, multiple, attrs);
5918
+ },
5919
+ })), [
5920
+ option.img && m('img', { src: option.img, alt: option.label }),
5921
+ m('span', [
5922
+ multiple
5923
+ ? m('label', { for: option.id }, m('input', {
5924
+ id: option.id,
5925
+ type: 'checkbox',
5926
+ checked: selectedIds.includes(option.id),
5927
+ disabled: option.disabled ? true : undefined,
5928
+ onclick: (e) => {
5929
+ e.stopPropagation();
5930
+ },
5931
+ }), m('span', option.label))
5932
+ : m('span', option.label),
5933
+ ].filter(Boolean)),
5934
+ ])),
5935
+ ])
5936
+ .reduce((acc, val) => acc.concat(val), []),
5937
+ ];
5938
+ const updatePortalDropdown = (attrs, selectedIds, multiple, placeholder) => {
5939
+ var _a;
5940
+ if (!state.isInsideModal)
5941
+ return;
5942
+ let portalElement = document.getElementById(state.dropdownId);
5943
+ if (!state.isOpen) {
5944
+ // Clean up portal when dropdown is closed
5945
+ if (portalElement) {
5946
+ m.render(portalElement, []);
5947
+ (_a = portalElement.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(portalElement);
5948
+ }
5949
+ return;
5950
+ }
5951
+ if (!portalElement) {
5952
+ portalElement = document.createElement('div');
5953
+ portalElement.id = state.dropdownId;
5954
+ document.body.appendChild(portalElement);
5955
+ }
5956
+ const dropdownVnode = m('ul.dropdown-content.select-dropdown', {
5957
+ tabindex: 0,
5958
+ style: getPortalStyles(state.inputRef),
5959
+ oncreate: ({ dom }) => {
5960
+ state.dropdownRef = dom;
5961
+ },
5962
+ onremove: () => {
5963
+ state.dropdownRef = null;
5964
+ },
5965
+ }, renderDropdownContent(attrs, selectedIds, multiple, placeholder));
5966
+ m.render(portalElement, dropdownVnode);
5967
+ };
5848
5968
  return {
5849
5969
  oninit: ({ attrs }) => {
5850
5970
  state.id = attrs.id || uniqueId();
5971
+ state.dropdownId = `${state.id}-dropdown`;
5851
5972
  const controlled = isControlled(attrs);
5852
5973
  // Warn developer for improper controlled usage
5853
5974
  if (attrs.checkedId !== undefined && !controlled && !attrs.disabled) {
@@ -5866,9 +5987,20 @@ const Select = () => {
5866
5987
  // Add global click listener to close dropdown
5867
5988
  document.addEventListener('click', closeDropdown);
5868
5989
  },
5990
+ oncreate: ({ dom }) => {
5991
+ // Detect if component is inside a modal
5992
+ state.isInsideModal = !!dom.closest('.modal');
5993
+ },
5869
5994
  onremove: () => {
5870
5995
  // Cleanup global listener
5871
5996
  document.removeEventListener('click', closeDropdown);
5997
+ // Cleanup portaled dropdown if it exists
5998
+ if (state.isInsideModal && state.dropdownRef) {
5999
+ const portalElement = document.getElementById(state.dropdownId);
6000
+ if (portalElement && portalElement.parentNode) {
6001
+ portalElement.parentNode.removeChild(portalElement);
6002
+ }
6003
+ }
5872
6004
  },
5873
6005
  view: ({ attrs }) => {
5874
6006
  var _a;
@@ -5877,20 +6009,13 @@ const Select = () => {
5877
6009
  // Get selected IDs from props or internal state
5878
6010
  let selectedIds;
5879
6011
  if (controlled) {
5880
- selectedIds = attrs.checkedId !== undefined
5881
- ? Array.isArray(attrs.checkedId)
5882
- ? attrs.checkedId
5883
- : [attrs.checkedId]
5884
- : [];
6012
+ selectedIds =
6013
+ attrs.checkedId !== undefined ? (Array.isArray(attrs.checkedId) ? attrs.checkedId : [attrs.checkedId]) : [];
5885
6014
  }
5886
6015
  else if (disabled) {
5887
6016
  // Non-interactive components: prefer defaultCheckedId, fallback to checkedId
5888
6017
  const fallbackId = (_a = attrs.defaultCheckedId) !== null && _a !== void 0 ? _a : attrs.checkedId;
5889
- selectedIds = fallbackId !== undefined
5890
- ? Array.isArray(fallbackId)
5891
- ? fallbackId
5892
- : [fallbackId]
5893
- : [];
6018
+ selectedIds = fallbackId !== undefined ? (Array.isArray(fallbackId) ? fallbackId : [fallbackId]) : [];
5894
6019
  }
5895
6020
  else {
5896
6021
  // Interactive uncontrolled: use internal state
@@ -5899,6 +6024,10 @@ const Select = () => {
5899
6024
  const { newRow, className = 'col s12', key, options, multiple = false, label, helperText, placeholder = '', isMandatory, iconName, style, } = attrs;
5900
6025
  const finalClassName = newRow ? `${className} clear` : className;
5901
6026
  const selectedOptions = options.filter((opt) => isSelected(opt.id, selectedIds));
6027
+ // Update portal dropdown when inside modal
6028
+ if (state.isInsideModal) {
6029
+ updatePortalDropdown(attrs, selectedIds, multiple, placeholder);
6030
+ }
5902
6031
  return m('.input-field.select-space', {
5903
6032
  className: finalClassName,
5904
6033
  key,
@@ -5911,6 +6040,7 @@ const Select = () => {
5911
6040
  tabindex: disabled ? -1 : 0,
5912
6041
  'aria-expanded': state.isOpen ? 'true' : 'false',
5913
6042
  'aria-haspopup': 'listbox',
6043
+ 'aria-controls': state.dropdownId,
5914
6044
  role: 'combobox',
5915
6045
  }, [
5916
6046
  m('input[type=text][readonly=true].select-dropdown.dropdown-trigger', {
@@ -5927,8 +6057,8 @@ const Select = () => {
5927
6057
  }
5928
6058
  },
5929
6059
  }),
5930
- // Dropdown Menu
5931
- state.isOpen &&
6060
+ // Dropdown Menu - render inline only when NOT inside modal
6061
+ state.isOpen && !state.isInsideModal &&
5932
6062
  m('ul.dropdown-content.select-dropdown', {
5933
6063
  tabindex: 0,
5934
6064
  oncreate: ({ dom }) => {
@@ -5938,66 +6068,7 @@ const Select = () => {
5938
6068
  state.dropdownRef = null;
5939
6069
  },
5940
6070
  style: getDropdownStyles(state.inputRef, true, options),
5941
- }, [
5942
- placeholder && m('li.disabled', { tabindex: 0 }, m('span', placeholder)),
5943
- // Render ungrouped options first
5944
- options
5945
- .filter((option) => !option.group)
5946
- .map((option) => m('li', Object.assign({ key: option.id, class: option.disabled
5947
- ? 'disabled'
5948
- : state.focusedIndex === options.indexOf(option)
5949
- ? 'focused'
5950
- : '' }, (option.disabled
5951
- ? {}
5952
- : {
5953
- onclick: (e) => {
5954
- e.stopPropagation();
5955
- toggleOption(option.id, multiple, attrs);
5956
- },
5957
- })), m('span', multiple
5958
- ? m('label', { for: option.id }, m('input', {
5959
- id: option.id,
5960
- type: 'checkbox',
5961
- checked: selectedIds.includes(option.id),
5962
- disabled: option.disabled ? true : undefined,
5963
- onclick: (e) => {
5964
- e.stopPropagation();
5965
- },
5966
- }), m('span', option.label))
5967
- : option.label))),
5968
- // Render grouped options
5969
- Object.entries(options
5970
- .filter((option) => option.group)
5971
- .reduce((groups, option) => {
5972
- const group = option.group;
5973
- if (!groups[group])
5974
- groups[group] = [];
5975
- groups[group].push(option);
5976
- return groups;
5977
- }, {}))
5978
- .map(([groupName, groupOptions]) => [
5979
- m('li.optgroup', { key: `group-${groupName}`, tabindex: 0 }, m('span', groupName)),
5980
- ...groupOptions.map((option) => m('li', Object.assign({ key: option.id, class: `optgroup-option${option.disabled ? ' disabled' : ''}${isSelected(option.id, selectedIds) ? ' selected' : ''}${state.focusedIndex === options.indexOf(option) ? ' focused' : ''}` }, (option.disabled
5981
- ? {}
5982
- : {
5983
- onclick: (e) => {
5984
- e.stopPropagation();
5985
- toggleOption(option.id, multiple, attrs);
5986
- },
5987
- })), m('span', multiple
5988
- ? m('label', { for: option.id }, m('input', {
5989
- id: option.id,
5990
- type: 'checkbox',
5991
- checked: selectedIds.includes(option.id),
5992
- disabled: option.disabled ? true : undefined,
5993
- onclick: (e) => {
5994
- e.stopPropagation();
5995
- },
5996
- }), m('span', option.label))
5997
- : option.label))),
5998
- ])
5999
- .reduce((acc, val) => acc.concat(val), []),
6000
- ]),
6071
+ }, renderDropdownContent(attrs, selectedIds, multiple, placeholder)),
6001
6072
  m(MaterialIcon, {
6002
6073
  name: 'caret',
6003
6074
  direction: 'down',
package/dist/index.js CHANGED
@@ -2813,6 +2813,7 @@ const TextArea = () => {
2813
2813
  height: undefined,
2814
2814
  active: false,
2815
2815
  textarea: undefined,
2816
+ hiddenDiv: undefined,
2816
2817
  internalValue: '',
2817
2818
  };
2818
2819
  const updateHeight = (textarea, hiddenDiv) => {
@@ -2909,13 +2910,13 @@ const TextArea = () => {
2909
2910
  overflowWrap: 'break-word',
2910
2911
  },
2911
2912
  oncreate: ({ dom }) => {
2912
- const hiddenDiv = dom;
2913
+ const hiddenDiv = state.hiddenDiv = dom;
2913
2914
  if (state.textarea) {
2914
2915
  updateHeight(state.textarea, hiddenDiv);
2915
2916
  }
2916
2917
  },
2917
2918
  onupdate: ({ dom }) => {
2918
- const hiddenDiv = dom;
2919
+ const hiddenDiv = state.hiddenDiv = dom;
2919
2920
  if (state.textarea) {
2920
2921
  updateHeight(state.textarea, hiddenDiv);
2921
2922
  }
@@ -2940,7 +2941,10 @@ const TextArea = () => {
2940
2941
  const textarea = dom;
2941
2942
  if (state.height)
2942
2943
  textarea.style.height = state.height;
2943
- // No need to manually sync in onupdate since value attribute handles it
2944
+ // Trigger height recalculation when value changes programmatically
2945
+ if (state.hiddenDiv) {
2946
+ updateHeight(textarea, state.hiddenDiv);
2947
+ }
2944
2948
  }, onfocus: () => {
2945
2949
  state.active = true;
2946
2950
  }, oninput: (e) => {
@@ -3100,9 +3104,6 @@ const InputField = (type, defaultClass = '') => () => {
3100
3104
  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"]);
3101
3105
  // const attributes = toAttrs(params);
3102
3106
  const cn = [newRow ? 'clear' : '', defaultClass, className].filter(Boolean).join(' ').trim() || undefined;
3103
- const isActive = state.active || ((_a = state.inputElement) === null || _a === void 0 ? void 0 : _a.value) || placeholder || type === 'color' || type === 'range'
3104
- ? true
3105
- : false;
3106
3107
  // Special rendering for minmax range sliders
3107
3108
  if (type === 'range' && (attrs.minmax || attrs.valueDisplay)) {
3108
3109
  return m(attrs.minmax ? DoubleRangeSlider : SingleRangeSlider, Object.assign(Object.assign({}, attrs), { state,
@@ -3123,12 +3124,15 @@ const InputField = (type, defaultClass = '') => () => {
3123
3124
  }
3124
3125
  else if (isNonInteractive) {
3125
3126
  // Non-interactive components: prefer defaultValue, fallback to value
3126
- value = ((_c = (_b = attrs.defaultValue) !== null && _b !== void 0 ? _b : attrs.value) !== null && _c !== void 0 ? _c : (isNumeric ? 0 : ''));
3127
+ value = ((_b = (_a = attrs.defaultValue) !== null && _a !== void 0 ? _a : attrs.value) !== null && _b !== void 0 ? _b : (isNumeric ? 0 : ''));
3127
3128
  }
3128
3129
  else {
3129
3130
  // Interactive uncontrolled: use internal state
3130
- value = ((_e = (_d = state.internalValue) !== null && _d !== void 0 ? _d : attrs.defaultValue) !== null && _e !== void 0 ? _e : (isNumeric ? 0 : ''));
3131
+ value = ((_d = (_c = state.internalValue) !== null && _c !== void 0 ? _c : attrs.defaultValue) !== null && _d !== void 0 ? _d : (isNumeric ? 0 : ''));
3131
3132
  }
3133
+ const isActive = state.active || ((_e = state.inputElement) === null || _e === void 0 ? void 0 : _e.value) || value || placeholder || type === 'color' || type === 'range'
3134
+ ? true
3135
+ : false;
3132
3136
  const rangeType = type === 'range' && !attrs.minmax;
3133
3137
  return m('.input-field', { className: cn, style }, [
3134
3138
  iconName ? m('i.material-icons.prefix', iconName) : undefined,
@@ -5754,11 +5758,13 @@ const RadioButtons = () => {
5754
5758
  const Select = () => {
5755
5759
  const state = {
5756
5760
  id: '',
5761
+ dropdownId: '',
5757
5762
  isOpen: false,
5758
5763
  focusedIndex: -1,
5759
5764
  inputRef: null,
5760
5765
  dropdownRef: null,
5761
5766
  internalSelectedIds: [],
5767
+ isInsideModal: false,
5762
5768
  };
5763
5769
  const isControlled = (attrs) => attrs.checkedId !== undefined && attrs.onchange !== undefined;
5764
5770
  const isSelected = (id, selectedIds) => {
@@ -5847,9 +5853,124 @@ const Select = () => {
5847
5853
  m.redraw();
5848
5854
  }
5849
5855
  };
5856
+ const getPortalStyles = (inputRef) => {
5857
+ if (!inputRef)
5858
+ return {};
5859
+ const rect = inputRef.getBoundingClientRect();
5860
+ const viewportHeight = window.innerHeight;
5861
+ return {
5862
+ position: 'fixed',
5863
+ top: `${rect.bottom}px`,
5864
+ left: `${rect.left}px`,
5865
+ width: `${rect.width}px`,
5866
+ zIndex: 10000, // Higher than modal z-index
5867
+ maxHeight: `${viewportHeight - rect.bottom - 20}px`, // Leave 20px margin from bottom
5868
+ };
5869
+ };
5870
+ const renderDropdownContent = (attrs, selectedIds, multiple, placeholder) => [
5871
+ placeholder && m('li.disabled', { tabindex: 0 }, m('span', placeholder)),
5872
+ // Render ungrouped options first
5873
+ attrs.options
5874
+ .filter((option) => !option.group)
5875
+ .map((option) => m('li', Object.assign({ key: option.id, class: option.disabled
5876
+ ? 'disabled'
5877
+ : state.focusedIndex === attrs.options.indexOf(option)
5878
+ ? 'focused'
5879
+ : '' }, (option.disabled
5880
+ ? {}
5881
+ : {
5882
+ onclick: (e) => {
5883
+ e.stopPropagation();
5884
+ toggleOption(option.id, multiple, attrs);
5885
+ },
5886
+ })), [
5887
+ option.img && m('img', { src: option.img, alt: option.label }),
5888
+ m('span', [
5889
+ multiple
5890
+ ? m('label', { for: option.id }, m('input', {
5891
+ id: option.id,
5892
+ type: 'checkbox',
5893
+ checked: selectedIds.includes(option.id),
5894
+ disabled: option.disabled ? true : undefined,
5895
+ onclick: (e) => {
5896
+ e.stopPropagation();
5897
+ },
5898
+ }), m('span', option.label))
5899
+ : m('span', option.label),
5900
+ ].filter(Boolean)),
5901
+ ])),
5902
+ // Render grouped options
5903
+ Object.entries(attrs.options
5904
+ .filter((option) => option.group)
5905
+ .reduce((groups, option) => {
5906
+ const group = option.group;
5907
+ if (!groups[group])
5908
+ groups[group] = [];
5909
+ groups[group].push(option);
5910
+ return groups;
5911
+ }, {}))
5912
+ .map(([groupName, groupOptions]) => [
5913
+ m('li.optgroup', { key: `group-${groupName}`, tabindex: 0 }, m('span', groupName)),
5914
+ ...groupOptions.map((option) => m('li', Object.assign({ key: option.id, class: `optgroup-option${option.disabled ? ' disabled' : ''}${isSelected(option.id, selectedIds) ? ' selected' : ''}${state.focusedIndex === attrs.options.indexOf(option) ? ' focused' : ''}` }, (option.disabled
5915
+ ? {}
5916
+ : {
5917
+ onclick: (e) => {
5918
+ e.stopPropagation();
5919
+ toggleOption(option.id, multiple, attrs);
5920
+ },
5921
+ })), [
5922
+ option.img && m('img', { src: option.img, alt: option.label }),
5923
+ m('span', [
5924
+ multiple
5925
+ ? m('label', { for: option.id }, m('input', {
5926
+ id: option.id,
5927
+ type: 'checkbox',
5928
+ checked: selectedIds.includes(option.id),
5929
+ disabled: option.disabled ? true : undefined,
5930
+ onclick: (e) => {
5931
+ e.stopPropagation();
5932
+ },
5933
+ }), m('span', option.label))
5934
+ : m('span', option.label),
5935
+ ].filter(Boolean)),
5936
+ ])),
5937
+ ])
5938
+ .reduce((acc, val) => acc.concat(val), []),
5939
+ ];
5940
+ const updatePortalDropdown = (attrs, selectedIds, multiple, placeholder) => {
5941
+ var _a;
5942
+ if (!state.isInsideModal)
5943
+ return;
5944
+ let portalElement = document.getElementById(state.dropdownId);
5945
+ if (!state.isOpen) {
5946
+ // Clean up portal when dropdown is closed
5947
+ if (portalElement) {
5948
+ m.render(portalElement, []);
5949
+ (_a = portalElement.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(portalElement);
5950
+ }
5951
+ return;
5952
+ }
5953
+ if (!portalElement) {
5954
+ portalElement = document.createElement('div');
5955
+ portalElement.id = state.dropdownId;
5956
+ document.body.appendChild(portalElement);
5957
+ }
5958
+ const dropdownVnode = m('ul.dropdown-content.select-dropdown', {
5959
+ tabindex: 0,
5960
+ style: getPortalStyles(state.inputRef),
5961
+ oncreate: ({ dom }) => {
5962
+ state.dropdownRef = dom;
5963
+ },
5964
+ onremove: () => {
5965
+ state.dropdownRef = null;
5966
+ },
5967
+ }, renderDropdownContent(attrs, selectedIds, multiple, placeholder));
5968
+ m.render(portalElement, dropdownVnode);
5969
+ };
5850
5970
  return {
5851
5971
  oninit: ({ attrs }) => {
5852
5972
  state.id = attrs.id || uniqueId();
5973
+ state.dropdownId = `${state.id}-dropdown`;
5853
5974
  const controlled = isControlled(attrs);
5854
5975
  // Warn developer for improper controlled usage
5855
5976
  if (attrs.checkedId !== undefined && !controlled && !attrs.disabled) {
@@ -5868,9 +5989,20 @@ const Select = () => {
5868
5989
  // Add global click listener to close dropdown
5869
5990
  document.addEventListener('click', closeDropdown);
5870
5991
  },
5992
+ oncreate: ({ dom }) => {
5993
+ // Detect if component is inside a modal
5994
+ state.isInsideModal = !!dom.closest('.modal');
5995
+ },
5871
5996
  onremove: () => {
5872
5997
  // Cleanup global listener
5873
5998
  document.removeEventListener('click', closeDropdown);
5999
+ // Cleanup portaled dropdown if it exists
6000
+ if (state.isInsideModal && state.dropdownRef) {
6001
+ const portalElement = document.getElementById(state.dropdownId);
6002
+ if (portalElement && portalElement.parentNode) {
6003
+ portalElement.parentNode.removeChild(portalElement);
6004
+ }
6005
+ }
5874
6006
  },
5875
6007
  view: ({ attrs }) => {
5876
6008
  var _a;
@@ -5879,20 +6011,13 @@ const Select = () => {
5879
6011
  // Get selected IDs from props or internal state
5880
6012
  let selectedIds;
5881
6013
  if (controlled) {
5882
- selectedIds = attrs.checkedId !== undefined
5883
- ? Array.isArray(attrs.checkedId)
5884
- ? attrs.checkedId
5885
- : [attrs.checkedId]
5886
- : [];
6014
+ selectedIds =
6015
+ attrs.checkedId !== undefined ? (Array.isArray(attrs.checkedId) ? attrs.checkedId : [attrs.checkedId]) : [];
5887
6016
  }
5888
6017
  else if (disabled) {
5889
6018
  // Non-interactive components: prefer defaultCheckedId, fallback to checkedId
5890
6019
  const fallbackId = (_a = attrs.defaultCheckedId) !== null && _a !== void 0 ? _a : attrs.checkedId;
5891
- selectedIds = fallbackId !== undefined
5892
- ? Array.isArray(fallbackId)
5893
- ? fallbackId
5894
- : [fallbackId]
5895
- : [];
6020
+ selectedIds = fallbackId !== undefined ? (Array.isArray(fallbackId) ? fallbackId : [fallbackId]) : [];
5896
6021
  }
5897
6022
  else {
5898
6023
  // Interactive uncontrolled: use internal state
@@ -5901,6 +6026,10 @@ const Select = () => {
5901
6026
  const { newRow, className = 'col s12', key, options, multiple = false, label, helperText, placeholder = '', isMandatory, iconName, style, } = attrs;
5902
6027
  const finalClassName = newRow ? `${className} clear` : className;
5903
6028
  const selectedOptions = options.filter((opt) => isSelected(opt.id, selectedIds));
6029
+ // Update portal dropdown when inside modal
6030
+ if (state.isInsideModal) {
6031
+ updatePortalDropdown(attrs, selectedIds, multiple, placeholder);
6032
+ }
5904
6033
  return m('.input-field.select-space', {
5905
6034
  className: finalClassName,
5906
6035
  key,
@@ -5913,6 +6042,7 @@ const Select = () => {
5913
6042
  tabindex: disabled ? -1 : 0,
5914
6043
  'aria-expanded': state.isOpen ? 'true' : 'false',
5915
6044
  'aria-haspopup': 'listbox',
6045
+ 'aria-controls': state.dropdownId,
5916
6046
  role: 'combobox',
5917
6047
  }, [
5918
6048
  m('input[type=text][readonly=true].select-dropdown.dropdown-trigger', {
@@ -5929,8 +6059,8 @@ const Select = () => {
5929
6059
  }
5930
6060
  },
5931
6061
  }),
5932
- // Dropdown Menu
5933
- state.isOpen &&
6062
+ // Dropdown Menu - render inline only when NOT inside modal
6063
+ state.isOpen && !state.isInsideModal &&
5934
6064
  m('ul.dropdown-content.select-dropdown', {
5935
6065
  tabindex: 0,
5936
6066
  oncreate: ({ dom }) => {
@@ -5940,66 +6070,7 @@ const Select = () => {
5940
6070
  state.dropdownRef = null;
5941
6071
  },
5942
6072
  style: getDropdownStyles(state.inputRef, true, options),
5943
- }, [
5944
- placeholder && m('li.disabled', { tabindex: 0 }, m('span', placeholder)),
5945
- // Render ungrouped options first
5946
- options
5947
- .filter((option) => !option.group)
5948
- .map((option) => m('li', Object.assign({ key: option.id, class: option.disabled
5949
- ? 'disabled'
5950
- : state.focusedIndex === options.indexOf(option)
5951
- ? 'focused'
5952
- : '' }, (option.disabled
5953
- ? {}
5954
- : {
5955
- onclick: (e) => {
5956
- e.stopPropagation();
5957
- toggleOption(option.id, multiple, attrs);
5958
- },
5959
- })), m('span', multiple
5960
- ? m('label', { for: option.id }, m('input', {
5961
- id: option.id,
5962
- type: 'checkbox',
5963
- checked: selectedIds.includes(option.id),
5964
- disabled: option.disabled ? true : undefined,
5965
- onclick: (e) => {
5966
- e.stopPropagation();
5967
- },
5968
- }), m('span', option.label))
5969
- : option.label))),
5970
- // Render grouped options
5971
- Object.entries(options
5972
- .filter((option) => option.group)
5973
- .reduce((groups, option) => {
5974
- const group = option.group;
5975
- if (!groups[group])
5976
- groups[group] = [];
5977
- groups[group].push(option);
5978
- return groups;
5979
- }, {}))
5980
- .map(([groupName, groupOptions]) => [
5981
- m('li.optgroup', { key: `group-${groupName}`, tabindex: 0 }, m('span', groupName)),
5982
- ...groupOptions.map((option) => m('li', Object.assign({ key: option.id, class: `optgroup-option${option.disabled ? ' disabled' : ''}${isSelected(option.id, selectedIds) ? ' selected' : ''}${state.focusedIndex === options.indexOf(option) ? ' focused' : ''}` }, (option.disabled
5983
- ? {}
5984
- : {
5985
- onclick: (e) => {
5986
- e.stopPropagation();
5987
- toggleOption(option.id, multiple, attrs);
5988
- },
5989
- })), m('span', multiple
5990
- ? m('label', { for: option.id }, m('input', {
5991
- id: option.id,
5992
- type: 'checkbox',
5993
- checked: selectedIds.includes(option.id),
5994
- disabled: option.disabled ? true : undefined,
5995
- onclick: (e) => {
5996
- e.stopPropagation();
5997
- },
5998
- }), m('span', option.label))
5999
- : option.label))),
6000
- ])
6001
- .reduce((acc, val) => acc.concat(val), []),
6002
- ]),
6073
+ }, renderDropdownContent(attrs, selectedIds, multiple, placeholder)),
6003
6074
  m(MaterialIcon, {
6004
6075
  name: 'caret',
6005
6076
  direction: 'down',
package/dist/index.umd.js CHANGED
@@ -2815,6 +2815,7 @@
2815
2815
  height: undefined,
2816
2816
  active: false,
2817
2817
  textarea: undefined,
2818
+ hiddenDiv: undefined,
2818
2819
  internalValue: '',
2819
2820
  };
2820
2821
  const updateHeight = (textarea, hiddenDiv) => {
@@ -2911,13 +2912,13 @@
2911
2912
  overflowWrap: 'break-word',
2912
2913
  },
2913
2914
  oncreate: ({ dom }) => {
2914
- const hiddenDiv = dom;
2915
+ const hiddenDiv = state.hiddenDiv = dom;
2915
2916
  if (state.textarea) {
2916
2917
  updateHeight(state.textarea, hiddenDiv);
2917
2918
  }
2918
2919
  },
2919
2920
  onupdate: ({ dom }) => {
2920
- const hiddenDiv = dom;
2921
+ const hiddenDiv = state.hiddenDiv = dom;
2921
2922
  if (state.textarea) {
2922
2923
  updateHeight(state.textarea, hiddenDiv);
2923
2924
  }
@@ -2942,7 +2943,10 @@
2942
2943
  const textarea = dom;
2943
2944
  if (state.height)
2944
2945
  textarea.style.height = state.height;
2945
- // No need to manually sync in onupdate since value attribute handles it
2946
+ // Trigger height recalculation when value changes programmatically
2947
+ if (state.hiddenDiv) {
2948
+ updateHeight(textarea, state.hiddenDiv);
2949
+ }
2946
2950
  }, onfocus: () => {
2947
2951
  state.active = true;
2948
2952
  }, oninput: (e) => {
@@ -3102,9 +3106,6 @@
3102
3106
  const { className = 'col s12', dataError, dataSuccess, helperText, iconName, id = state.id, placeholder, isMandatory, label, maxLength, newRow, oninput, onchange, onkeydown, onkeypress, onkeyup, style, validate, canClear } = attrs, params = __rest(attrs, ["className", "dataError", "dataSuccess", "helperText", "iconName", "id", "placeholder", "isMandatory", "label", "maxLength", "newRow", "oninput", "onchange", "onkeydown", "onkeypress", "onkeyup", "style", "validate", "canClear"]);
3103
3107
  // const attributes = toAttrs(params);
3104
3108
  const cn = [newRow ? 'clear' : '', defaultClass, className].filter(Boolean).join(' ').trim() || undefined;
3105
- const isActive = state.active || ((_a = state.inputElement) === null || _a === void 0 ? void 0 : _a.value) || placeholder || type === 'color' || type === 'range'
3106
- ? true
3107
- : false;
3108
3109
  // Special rendering for minmax range sliders
3109
3110
  if (type === 'range' && (attrs.minmax || attrs.valueDisplay)) {
3110
3111
  return m(attrs.minmax ? DoubleRangeSlider : SingleRangeSlider, Object.assign(Object.assign({}, attrs), { state,
@@ -3125,12 +3126,15 @@
3125
3126
  }
3126
3127
  else if (isNonInteractive) {
3127
3128
  // Non-interactive components: prefer defaultValue, fallback to value
3128
- value = ((_c = (_b = attrs.defaultValue) !== null && _b !== void 0 ? _b : attrs.value) !== null && _c !== void 0 ? _c : (isNumeric ? 0 : ''));
3129
+ value = ((_b = (_a = attrs.defaultValue) !== null && _a !== void 0 ? _a : attrs.value) !== null && _b !== void 0 ? _b : (isNumeric ? 0 : ''));
3129
3130
  }
3130
3131
  else {
3131
3132
  // Interactive uncontrolled: use internal state
3132
- value = ((_e = (_d = state.internalValue) !== null && _d !== void 0 ? _d : attrs.defaultValue) !== null && _e !== void 0 ? _e : (isNumeric ? 0 : ''));
3133
+ value = ((_d = (_c = state.internalValue) !== null && _c !== void 0 ? _c : attrs.defaultValue) !== null && _d !== void 0 ? _d : (isNumeric ? 0 : ''));
3133
3134
  }
3135
+ const isActive = state.active || ((_e = state.inputElement) === null || _e === void 0 ? void 0 : _e.value) || value || placeholder || type === 'color' || type === 'range'
3136
+ ? true
3137
+ : false;
3134
3138
  const rangeType = type === 'range' && !attrs.minmax;
3135
3139
  return m('.input-field', { className: cn, style }, [
3136
3140
  iconName ? m('i.material-icons.prefix', iconName) : undefined,
@@ -5756,11 +5760,13 @@
5756
5760
  const Select = () => {
5757
5761
  const state = {
5758
5762
  id: '',
5763
+ dropdownId: '',
5759
5764
  isOpen: false,
5760
5765
  focusedIndex: -1,
5761
5766
  inputRef: null,
5762
5767
  dropdownRef: null,
5763
5768
  internalSelectedIds: [],
5769
+ isInsideModal: false,
5764
5770
  };
5765
5771
  const isControlled = (attrs) => attrs.checkedId !== undefined && attrs.onchange !== undefined;
5766
5772
  const isSelected = (id, selectedIds) => {
@@ -5849,9 +5855,124 @@
5849
5855
  m.redraw();
5850
5856
  }
5851
5857
  };
5858
+ const getPortalStyles = (inputRef) => {
5859
+ if (!inputRef)
5860
+ return {};
5861
+ const rect = inputRef.getBoundingClientRect();
5862
+ const viewportHeight = window.innerHeight;
5863
+ return {
5864
+ position: 'fixed',
5865
+ top: `${rect.bottom}px`,
5866
+ left: `${rect.left}px`,
5867
+ width: `${rect.width}px`,
5868
+ zIndex: 10000, // Higher than modal z-index
5869
+ maxHeight: `${viewportHeight - rect.bottom - 20}px`, // Leave 20px margin from bottom
5870
+ };
5871
+ };
5872
+ const renderDropdownContent = (attrs, selectedIds, multiple, placeholder) => [
5873
+ placeholder && m('li.disabled', { tabindex: 0 }, m('span', placeholder)),
5874
+ // Render ungrouped options first
5875
+ attrs.options
5876
+ .filter((option) => !option.group)
5877
+ .map((option) => m('li', Object.assign({ key: option.id, class: option.disabled
5878
+ ? 'disabled'
5879
+ : state.focusedIndex === attrs.options.indexOf(option)
5880
+ ? 'focused'
5881
+ : '' }, (option.disabled
5882
+ ? {}
5883
+ : {
5884
+ onclick: (e) => {
5885
+ e.stopPropagation();
5886
+ toggleOption(option.id, multiple, attrs);
5887
+ },
5888
+ })), [
5889
+ option.img && m('img', { src: option.img, alt: option.label }),
5890
+ m('span', [
5891
+ multiple
5892
+ ? m('label', { for: option.id }, m('input', {
5893
+ id: option.id,
5894
+ type: 'checkbox',
5895
+ checked: selectedIds.includes(option.id),
5896
+ disabled: option.disabled ? true : undefined,
5897
+ onclick: (e) => {
5898
+ e.stopPropagation();
5899
+ },
5900
+ }), m('span', option.label))
5901
+ : m('span', option.label),
5902
+ ].filter(Boolean)),
5903
+ ])),
5904
+ // Render grouped options
5905
+ Object.entries(attrs.options
5906
+ .filter((option) => option.group)
5907
+ .reduce((groups, option) => {
5908
+ const group = option.group;
5909
+ if (!groups[group])
5910
+ groups[group] = [];
5911
+ groups[group].push(option);
5912
+ return groups;
5913
+ }, {}))
5914
+ .map(([groupName, groupOptions]) => [
5915
+ m('li.optgroup', { key: `group-${groupName}`, tabindex: 0 }, m('span', groupName)),
5916
+ ...groupOptions.map((option) => m('li', Object.assign({ key: option.id, class: `optgroup-option${option.disabled ? ' disabled' : ''}${isSelected(option.id, selectedIds) ? ' selected' : ''}${state.focusedIndex === attrs.options.indexOf(option) ? ' focused' : ''}` }, (option.disabled
5917
+ ? {}
5918
+ : {
5919
+ onclick: (e) => {
5920
+ e.stopPropagation();
5921
+ toggleOption(option.id, multiple, attrs);
5922
+ },
5923
+ })), [
5924
+ option.img && m('img', { src: option.img, alt: option.label }),
5925
+ m('span', [
5926
+ multiple
5927
+ ? m('label', { for: option.id }, m('input', {
5928
+ id: option.id,
5929
+ type: 'checkbox',
5930
+ checked: selectedIds.includes(option.id),
5931
+ disabled: option.disabled ? true : undefined,
5932
+ onclick: (e) => {
5933
+ e.stopPropagation();
5934
+ },
5935
+ }), m('span', option.label))
5936
+ : m('span', option.label),
5937
+ ].filter(Boolean)),
5938
+ ])),
5939
+ ])
5940
+ .reduce((acc, val) => acc.concat(val), []),
5941
+ ];
5942
+ const updatePortalDropdown = (attrs, selectedIds, multiple, placeholder) => {
5943
+ var _a;
5944
+ if (!state.isInsideModal)
5945
+ return;
5946
+ let portalElement = document.getElementById(state.dropdownId);
5947
+ if (!state.isOpen) {
5948
+ // Clean up portal when dropdown is closed
5949
+ if (portalElement) {
5950
+ m.render(portalElement, []);
5951
+ (_a = portalElement.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(portalElement);
5952
+ }
5953
+ return;
5954
+ }
5955
+ if (!portalElement) {
5956
+ portalElement = document.createElement('div');
5957
+ portalElement.id = state.dropdownId;
5958
+ document.body.appendChild(portalElement);
5959
+ }
5960
+ const dropdownVnode = m('ul.dropdown-content.select-dropdown', {
5961
+ tabindex: 0,
5962
+ style: getPortalStyles(state.inputRef),
5963
+ oncreate: ({ dom }) => {
5964
+ state.dropdownRef = dom;
5965
+ },
5966
+ onremove: () => {
5967
+ state.dropdownRef = null;
5968
+ },
5969
+ }, renderDropdownContent(attrs, selectedIds, multiple, placeholder));
5970
+ m.render(portalElement, dropdownVnode);
5971
+ };
5852
5972
  return {
5853
5973
  oninit: ({ attrs }) => {
5854
5974
  state.id = attrs.id || uniqueId();
5975
+ state.dropdownId = `${state.id}-dropdown`;
5855
5976
  const controlled = isControlled(attrs);
5856
5977
  // Warn developer for improper controlled usage
5857
5978
  if (attrs.checkedId !== undefined && !controlled && !attrs.disabled) {
@@ -5870,9 +5991,20 @@
5870
5991
  // Add global click listener to close dropdown
5871
5992
  document.addEventListener('click', closeDropdown);
5872
5993
  },
5994
+ oncreate: ({ dom }) => {
5995
+ // Detect if component is inside a modal
5996
+ state.isInsideModal = !!dom.closest('.modal');
5997
+ },
5873
5998
  onremove: () => {
5874
5999
  // Cleanup global listener
5875
6000
  document.removeEventListener('click', closeDropdown);
6001
+ // Cleanup portaled dropdown if it exists
6002
+ if (state.isInsideModal && state.dropdownRef) {
6003
+ const portalElement = document.getElementById(state.dropdownId);
6004
+ if (portalElement && portalElement.parentNode) {
6005
+ portalElement.parentNode.removeChild(portalElement);
6006
+ }
6007
+ }
5876
6008
  },
5877
6009
  view: ({ attrs }) => {
5878
6010
  var _a;
@@ -5881,20 +6013,13 @@
5881
6013
  // Get selected IDs from props or internal state
5882
6014
  let selectedIds;
5883
6015
  if (controlled) {
5884
- selectedIds = attrs.checkedId !== undefined
5885
- ? Array.isArray(attrs.checkedId)
5886
- ? attrs.checkedId
5887
- : [attrs.checkedId]
5888
- : [];
6016
+ selectedIds =
6017
+ attrs.checkedId !== undefined ? (Array.isArray(attrs.checkedId) ? attrs.checkedId : [attrs.checkedId]) : [];
5889
6018
  }
5890
6019
  else if (disabled) {
5891
6020
  // Non-interactive components: prefer defaultCheckedId, fallback to checkedId
5892
6021
  const fallbackId = (_a = attrs.defaultCheckedId) !== null && _a !== void 0 ? _a : attrs.checkedId;
5893
- selectedIds = fallbackId !== undefined
5894
- ? Array.isArray(fallbackId)
5895
- ? fallbackId
5896
- : [fallbackId]
5897
- : [];
6022
+ selectedIds = fallbackId !== undefined ? (Array.isArray(fallbackId) ? fallbackId : [fallbackId]) : [];
5898
6023
  }
5899
6024
  else {
5900
6025
  // Interactive uncontrolled: use internal state
@@ -5903,6 +6028,10 @@
5903
6028
  const { newRow, className = 'col s12', key, options, multiple = false, label, helperText, placeholder = '', isMandatory, iconName, style, } = attrs;
5904
6029
  const finalClassName = newRow ? `${className} clear` : className;
5905
6030
  const selectedOptions = options.filter((opt) => isSelected(opt.id, selectedIds));
6031
+ // Update portal dropdown when inside modal
6032
+ if (state.isInsideModal) {
6033
+ updatePortalDropdown(attrs, selectedIds, multiple, placeholder);
6034
+ }
5906
6035
  return m('.input-field.select-space', {
5907
6036
  className: finalClassName,
5908
6037
  key,
@@ -5915,6 +6044,7 @@
5915
6044
  tabindex: disabled ? -1 : 0,
5916
6045
  'aria-expanded': state.isOpen ? 'true' : 'false',
5917
6046
  'aria-haspopup': 'listbox',
6047
+ 'aria-controls': state.dropdownId,
5918
6048
  role: 'combobox',
5919
6049
  }, [
5920
6050
  m('input[type=text][readonly=true].select-dropdown.dropdown-trigger', {
@@ -5931,8 +6061,8 @@
5931
6061
  }
5932
6062
  },
5933
6063
  }),
5934
- // Dropdown Menu
5935
- state.isOpen &&
6064
+ // Dropdown Menu - render inline only when NOT inside modal
6065
+ state.isOpen && !state.isInsideModal &&
5936
6066
  m('ul.dropdown-content.select-dropdown', {
5937
6067
  tabindex: 0,
5938
6068
  oncreate: ({ dom }) => {
@@ -5942,66 +6072,7 @@
5942
6072
  state.dropdownRef = null;
5943
6073
  },
5944
6074
  style: getDropdownStyles(state.inputRef, true, options),
5945
- }, [
5946
- placeholder && m('li.disabled', { tabindex: 0 }, m('span', placeholder)),
5947
- // Render ungrouped options first
5948
- options
5949
- .filter((option) => !option.group)
5950
- .map((option) => m('li', Object.assign({ key: option.id, class: option.disabled
5951
- ? 'disabled'
5952
- : state.focusedIndex === options.indexOf(option)
5953
- ? 'focused'
5954
- : '' }, (option.disabled
5955
- ? {}
5956
- : {
5957
- onclick: (e) => {
5958
- e.stopPropagation();
5959
- toggleOption(option.id, multiple, attrs);
5960
- },
5961
- })), m('span', multiple
5962
- ? m('label', { for: option.id }, m('input', {
5963
- id: option.id,
5964
- type: 'checkbox',
5965
- checked: selectedIds.includes(option.id),
5966
- disabled: option.disabled ? true : undefined,
5967
- onclick: (e) => {
5968
- e.stopPropagation();
5969
- },
5970
- }), m('span', option.label))
5971
- : option.label))),
5972
- // Render grouped options
5973
- Object.entries(options
5974
- .filter((option) => option.group)
5975
- .reduce((groups, option) => {
5976
- const group = option.group;
5977
- if (!groups[group])
5978
- groups[group] = [];
5979
- groups[group].push(option);
5980
- return groups;
5981
- }, {}))
5982
- .map(([groupName, groupOptions]) => [
5983
- m('li.optgroup', { key: `group-${groupName}`, tabindex: 0 }, m('span', groupName)),
5984
- ...groupOptions.map((option) => m('li', Object.assign({ key: option.id, class: `optgroup-option${option.disabled ? ' disabled' : ''}${isSelected(option.id, selectedIds) ? ' selected' : ''}${state.focusedIndex === options.indexOf(option) ? ' focused' : ''}` }, (option.disabled
5985
- ? {}
5986
- : {
5987
- onclick: (e) => {
5988
- e.stopPropagation();
5989
- toggleOption(option.id, multiple, attrs);
5990
- },
5991
- })), m('span', multiple
5992
- ? m('label', { for: option.id }, m('input', {
5993
- id: option.id,
5994
- type: 'checkbox',
5995
- checked: selectedIds.includes(option.id),
5996
- disabled: option.disabled ? true : undefined,
5997
- onclick: (e) => {
5998
- e.stopPropagation();
5999
- },
6000
- }), m('span', option.label))
6001
- : option.label))),
6002
- ])
6003
- .reduce((acc, val) => acc.concat(val), []),
6004
- ]),
6075
+ }, renderDropdownContent(attrs, selectedIds, multiple, placeholder)),
6005
6076
  m(MaterialIcon, {
6006
6077
  name: 'caret',
6007
6078
  direction: 'down',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mithril-materialized",
3
- "version": "3.3.6",
3
+ "version": "3.3.8",
4
4
  "description": "A materialize library for mithril.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",