mithril-materialized 3.5.3 → 3.5.5

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.js CHANGED
@@ -7812,6 +7812,87 @@ const FileUpload = () => {
7812
7812
  };
7813
7813
  };
7814
7814
 
7815
+ // List of MaterialIcon SVG icons that are available
7816
+ const materialIconSvgNames = [
7817
+ 'caret',
7818
+ 'close',
7819
+ 'chevron',
7820
+ 'chevron_left',
7821
+ 'chevron_right',
7822
+ 'menu',
7823
+ 'expand',
7824
+ 'collapse',
7825
+ 'check',
7826
+ 'radio_checked',
7827
+ 'radio_unchecked',
7828
+ 'light_mode',
7829
+ 'dark_mode',
7830
+ ];
7831
+ /**
7832
+ * Helper function to render icons based on IconDefinition type
7833
+ */
7834
+ const renderIcon = (icon, style) => {
7835
+ if (!icon)
7836
+ return null;
7837
+ if (typeof icon === 'string') {
7838
+ // Check if this is a MaterialIcon SVG name
7839
+ if (materialIconSvgNames.includes(icon)) {
7840
+ return m(MaterialIcon, { name: icon, style });
7841
+ }
7842
+ // Fall back to Material Icons font for other icon names
7843
+ return m('i.material-icons', { style }, icon);
7844
+ }
7845
+ if (icon.type === 'svg') {
7846
+ // Inline SVG
7847
+ return m.trust(icon.content);
7848
+ }
7849
+ if (icon.type === 'image') {
7850
+ // Image URL
7851
+ return m('img', {
7852
+ src: icon.content,
7853
+ style: Object.assign(Object.assign({}, style), { width: '24px', height: '24px', objectFit: 'contain' }),
7854
+ });
7855
+ }
7856
+ return null;
7857
+ };
7858
+ /**
7859
+ * Sidenav Header/Footer Item Component
7860
+ */
7861
+ const SidenavHeaderFooterItem = () => {
7862
+ return {
7863
+ view: ({ attrs }) => {
7864
+ const { text, icon, onclick, href, className = '', _isExpanded = true, _position = 'left' } = attrs;
7865
+ const isRightAligned = _position === 'right';
7866
+ const handleClick = (e) => {
7867
+ if (onclick) {
7868
+ e.preventDefault();
7869
+ onclick(e);
7870
+ }
7871
+ };
7872
+ const content = isRightAligned
7873
+ ? [
7874
+ _isExpanded &&
7875
+ m('span.sidenav-item-text', { style: { flex: '1', 'text-align': 'left', 'margin-right': '8px' } }, text),
7876
+ renderIcon(icon, { 'min-width': '24px', width: '24px' }),
7877
+ ]
7878
+ : [
7879
+ renderIcon(icon, { 'min-width': '24px', width: '24px' }),
7880
+ _isExpanded && m('span.sidenav-item-text', { style: { 'margin-left': '8px', flex: '1' } }, text),
7881
+ ];
7882
+ const linkStyle = {
7883
+ display: 'flex',
7884
+ 'align-items': 'center',
7885
+ padding: _isExpanded ? '12px 16px' : '12px 18px',
7886
+ 'justify-content': _isExpanded ? (isRightAligned ? 'flex-end' : 'flex-start') : 'center',
7887
+ };
7888
+ return m('li', { class: className }, m('a', {
7889
+ href: href || '#!',
7890
+ onclick: handleClick,
7891
+ style: linkStyle,
7892
+ }, content));
7893
+ },
7894
+ };
7895
+ };
7815
7896
  /**
7816
7897
  * Sidenav Component
7817
7898
  * A responsive navigation drawer that slides in from the side
@@ -7934,6 +8015,9 @@ const Sidenav = () => {
7934
8015
  name: 'menu',
7935
8016
  style: { width: '24px', height: '24px' },
7936
8017
  })),
8018
+ // Header item (if provided, appears before expand/collapse toggle)
8019
+ attrs.header &&
8020
+ m(SidenavHeaderFooterItem, Object.assign(Object.assign({}, attrs.header), { _isExpanded: isExpanded, _position: position })),
7937
8021
  // Expand/collapse toggle button (if expandable, right below hamburger)
7938
8022
  expandable &&
7939
8023
  m('li.sidenav-expand-toggle', {
@@ -7948,8 +8032,12 @@ const Sidenav = () => {
7948
8032
  onclick: () => toggleExpanded(attrs),
7949
8033
  }, m(MaterialIcon, {
7950
8034
  name: position === 'right'
7951
- ? (isExpanded ? 'chevron_right' : 'chevron_left')
7952
- : (isExpanded ? 'chevron_left' : 'chevron_right'),
8035
+ ? isExpanded
8036
+ ? 'chevron_right'
8037
+ : 'chevron_left'
8038
+ : isExpanded
8039
+ ? 'chevron_left'
8040
+ : 'chevron_right',
7953
8041
  style: { width: '24px', height: '24px' },
7954
8042
  })),
7955
8043
  // Children (menu items) - inject internal props
@@ -7962,6 +8050,9 @@ const Sidenav = () => {
7962
8050
  return child;
7963
8051
  })
7964
8052
  : children,
8053
+ // Footer item (if provided, appears at the bottom)
8054
+ attrs.footer &&
8055
+ m(SidenavHeaderFooterItem, Object.assign(Object.assign({}, attrs.footer), { _isExpanded: isExpanded, _position: position, className: 'sidenav-footer-item' })),
7965
8056
  ]),
7966
8057
  ];
7967
8058
  },
@@ -7980,43 +8071,42 @@ const NavbarSubItem = () => {
7980
8071
  }
7981
8072
  };
7982
8073
  const isRightAligned = position === 'right';
8074
+ // Render indicator icon for checkbox/radio modes
8075
+ const indicatorIcon = mode !== 'none'
8076
+ ? m(MaterialIcon, {
8077
+ name: mode === 'checkbox' ? (selected ? 'check' : 'close') : selected ? 'radio_checked' : 'radio_unchecked',
8078
+ style: {
8079
+ width: '18px',
8080
+ height: '18px',
8081
+ opacity: mode === 'checkbox' && !selected ? '0.3' : '1',
8082
+ },
8083
+ })
8084
+ : null;
7983
8085
  const submenuContent = isRightAligned
7984
8086
  ? [
7985
8087
  // Right-aligned: text on left, icons on right
7986
- isExpanded && m('span', { style: { 'flex': '1', 'text-align': 'left' } }, text),
7987
- icon && isExpanded && m('i.material-icons', { style: { 'font-size': '18px' } }, icon),
7988
- m(MaterialIcon, {
7989
- name: mode === 'checkbox' ? (selected ? 'check' : 'close') : selected ? 'radio_checked' : 'radio_unchecked',
7990
- style: {
7991
- width: '18px',
7992
- height: '18px',
7993
- opacity: mode === 'checkbox' && !selected ? '0.3' : '1',
7994
- },
7995
- }),
8088
+ isExpanded && m('span', { style: { flex: '1', 'text-align': 'left' } }, text),
8089
+ icon && isExpanded && renderIcon(icon, { 'font-size': '18px' }),
8090
+ indicatorIcon,
7996
8091
  ]
7997
8092
  : [
7998
8093
  // Left-aligned: indicator on left, text and icon on right
7999
- m(MaterialIcon, {
8000
- name: mode === 'checkbox' ? (selected ? 'check' : 'close') : selected ? 'radio_checked' : 'radio_unchecked',
8001
- style: {
8002
- width: '18px',
8003
- height: '18px',
8004
- opacity: mode === 'checkbox' && !selected ? '0.3' : '1',
8005
- },
8006
- }),
8007
- icon && isExpanded && m('i.material-icons', { style: { 'font-size': '18px', 'margin-left': '8px' } }, icon),
8008
- isExpanded && m('span', { style: { 'margin-left': icon ? '8px' : '8px' } }, text),
8094
+ indicatorIcon,
8095
+ icon && isExpanded && renderIcon(icon, { 'font-size': '18px', 'margin-left': indicatorIcon ? '8px' : '0' }),
8096
+ isExpanded && m('span', { style: { 'margin-left': icon || indicatorIcon ? '8px' : '0' } }, text),
8009
8097
  ];
8010
8098
  return m('li.sidenav-subitem', {
8011
8099
  class: selected ? 'selected' : '',
8012
8100
  style: {
8013
- padding: isExpanded ? '8px 16px 8px 48px' : '8px 16px',
8101
+ padding: isExpanded ? '0 16px 0 48px' : '0 16px',
8014
8102
  cursor: 'pointer',
8015
8103
  display: 'flex',
8016
8104
  'align-items': 'center',
8017
8105
  gap: '8px',
8018
8106
  'font-size': '0.9em',
8019
8107
  'justify-content': isRightAligned ? 'space-between' : 'flex-start',
8108
+ height: '48px',
8109
+ 'min-height': '48px',
8020
8110
  },
8021
8111
  onclick: handleClick,
8022
8112
  }, submenuContent);
@@ -8039,20 +8129,16 @@ const SidenavItem = () => {
8039
8129
  return m('li.subheader', text || children);
8040
8130
  }
8041
8131
  const hasSubmenu = submenu && submenu.length > 0;
8042
- const itemClasses = [
8043
- active ? 'active' : '',
8044
- disabled ? 'disabled' : '',
8045
- hasSubmenu ? 'has-submenu' : '',
8046
- className,
8047
- ]
8132
+ const itemClasses = [active ? 'active' : '', disabled ? 'disabled' : '', hasSubmenu ? 'has-submenu' : '', className]
8048
8133
  .filter(Boolean)
8049
8134
  .join(' ') || undefined;
8050
8135
  const handleMainClick = (e) => {
8051
- e.preventDefault();
8052
8136
  if (hasSubmenu) {
8137
+ e.preventDefault();
8053
8138
  isSubmenuOpen = active ? !isSubmenuOpen : true;
8054
8139
  }
8055
8140
  if (onclick && !disabled) {
8141
+ e.preventDefault();
8056
8142
  onclick(e);
8057
8143
  }
8058
8144
  };
@@ -8065,13 +8151,14 @@ const SidenavItem = () => {
8065
8151
  const content = isRightAligned
8066
8152
  ? [
8067
8153
  // Right-aligned: text on left, icon on right
8068
- isExpanded && m('span.sidenav-item-text', { style: { 'flex': '1', 'text-align': 'left', 'margin-right': '8px' } }, text || children),
8069
- m('i.material-icons', { style: { 'min-width': '24px', 'width': '24px' } }, icon || ''),
8154
+ isExpanded &&
8155
+ m('span.sidenav-item-text', { style: { flex: '1', 'text-align': 'left', 'margin-right': '8px' } }, text || children),
8156
+ renderIcon(icon, { 'min-width': '24px', width: '24px' }),
8070
8157
  ]
8071
8158
  : [
8072
8159
  // Left-aligned: icon on left, text on right
8073
- m('i.material-icons', { style: { 'min-width': '24px', 'width': '24px' } }, icon || ''),
8074
- isExpanded && m('span.sidenav-item-text', { style: { 'margin-left': '8px', 'flex': '1' } }, text || children),
8160
+ renderIcon(icon, { 'min-width': '24px', width: '24px' }),
8161
+ isExpanded && m('span.sidenav-item-text', { style: { 'margin-left': '8px', flex: '1' } }, text || children),
8075
8162
  ];
8076
8163
  const linkStyle = {
8077
8164
  display: 'flex',