mithril-materialized 3.4.4 → 3.5.0

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.umd.js CHANGED
@@ -268,6 +268,7 @@
268
268
  state.isOpen = false;
269
269
  state.selectedIndex = -1;
270
270
  }
271
+ m.redraw();
271
272
  };
272
273
  const getDropdownStyles = () => {
273
274
  if (!state.inputElement) {
@@ -966,6 +967,18 @@
966
967
  'M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z', // chevron down
967
968
  'M0 0h24v24H0z', // background
968
969
  ],
970
+ chevron_left: [
971
+ 'M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z', // chevron left
972
+ 'M0 0h24v24H0z', // background
973
+ ],
974
+ chevron_right: [
975
+ 'M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z', // chevron right
976
+ 'M0 0h24v24H0z', // background
977
+ ],
978
+ menu: [
979
+ 'M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z', // hamburger menu
980
+ 'M0 0h24v24H0z', // background
981
+ ],
969
982
  expand: [
970
983
  'M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z', // plus
971
984
  'M0 0h24v24H0z', // background
@@ -974,6 +987,18 @@
974
987
  'M19 13H5v-2h14v2z', // minus
975
988
  'M0 0h24v24H0z', // background
976
989
  ],
990
+ check: [
991
+ 'M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z', // checkmark
992
+ 'M0 0h24v24H0z', // background
993
+ ],
994
+ radio_checked: [
995
+ 'M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z', // radio button checked
996
+ 'M0 0h24v24H0z', // background
997
+ ],
998
+ radio_unchecked: [
999
+ 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z', // radio button unchecked
1000
+ 'M0 0h24v24H0z', // background
1001
+ ],
977
1002
  light_mode: [
978
1003
  'M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5M2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1m18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1M11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1m0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1M5.99 4.58a.996.996 0 0 0-1.41 0 .996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41zm12.4 12.4a.996.996 0 0 0-1.41 0 .996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0a.996.996 0 0 0 0-1.41zm1.06-11a.996.996 0 0 0 0-1.41.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0zM7.05 18.4a.996.996 0 0 0 0-1.41.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0z',
979
1004
  'M0 0h24v24H0z', // background
@@ -7800,12 +7825,27 @@
7800
7825
  document.body.style.overflow = isOpen && mode === 'overlay' ? 'hidden' : '';
7801
7826
  }
7802
7827
  };
7828
+ const toggleExpanded = (attrs) => {
7829
+ const newExpandedState = !(attrs.isExpanded !== false);
7830
+ if (attrs.onExpandChange) {
7831
+ attrs.onExpandChange(newExpandedState);
7832
+ }
7833
+ };
7834
+ const toggleHamburger = (attrs) => {
7835
+ const newOpenState = !state.isOpen;
7836
+ if (attrs.onToggle) {
7837
+ attrs.onToggle(newOpenState);
7838
+ }
7839
+ };
7803
7840
  return {
7804
7841
  oninit: ({ attrs }) => {
7805
7842
  state = {
7806
7843
  id: attrs.id || uniqueId(),
7807
7844
  isOpen: attrs.isOpen || false,
7808
7845
  isAnimating: false,
7846
+ isExpanded: attrs.isExpanded !== false,
7847
+ activeItemIndex: null,
7848
+ selectedSubmenuItems: new Map(),
7809
7849
  };
7810
7850
  // Set up keyboard listener
7811
7851
  if (typeof document !== 'undefined' && attrs.closeOnEscape !== false) {
@@ -7834,12 +7874,16 @@
7834
7874
  }
7835
7875
  },
7836
7876
  view: ({ attrs, children }) => {
7837
- const { position = 'left', mode = 'overlay', width = 300, className = '', showBackdrop = true, animationDuration = 300, fixed = false, } = attrs;
7877
+ const { position = 'left', mode = 'overlay', width = 300, className = '', showBackdrop = true, animationDuration = 300, fixed = false, showHamburger = false, expandable = false, } = attrs;
7838
7878
  const isOpen = state.isOpen;
7879
+ const collapsedWidth = 60;
7880
+ const isExpanded = attrs.isExpanded !== false;
7881
+ const currentWidth = expandable && !isExpanded ? collapsedWidth : width;
7839
7882
  return [
7840
- // Backdrop (using existing materialize class)
7883
+ // Backdrop (using existing materialize class) - only for overlay mode
7841
7884
  showBackdrop &&
7842
7885
  mode === 'overlay' &&
7886
+ !fixed &&
7843
7887
  m('.sidenav-overlay', {
7844
7888
  style: {
7845
7889
  display: isOpen ? 'block' : 'none',
@@ -7850,49 +7894,206 @@
7850
7894
  // Sidenav (using existing materialize structure)
7851
7895
  m('ul.sidenav', {
7852
7896
  id: state.id,
7853
- class: [position === 'right' ? 'right-aligned' : '', fixed ? 'sidenav-fixed' : '', className]
7897
+ class: [
7898
+ position === 'right' ? 'right-aligned' : '',
7899
+ fixed ? 'sidenav-fixed' : '',
7900
+ expandable && !isExpanded ? 'sidenav-collapsed' : '',
7901
+ className,
7902
+ ]
7854
7903
  .filter(Boolean)
7855
7904
  .join(' ') || undefined,
7856
7905
  style: {
7857
- width: `${width}px`,
7906
+ width: `${currentWidth}px`,
7858
7907
  transform: isOpen ? 'translateX(0)' : position === 'left' ? 'translateX(-105%)' : 'translateX(105%)',
7859
7908
  'transition-duration': `${animationDuration}ms`,
7909
+ 'transition-property': 'transform, width',
7860
7910
  },
7861
- }, children),
7911
+ }, [
7912
+ // Hamburger toggle button (inside sidenav, at the top)
7913
+ showHamburger &&
7914
+ m('li.sidenav-hamburger-item', {
7915
+ style: {
7916
+ display: 'flex',
7917
+ 'justify-content': position === 'right' ? 'flex-end' : 'flex-start',
7918
+ 'align-items': 'center',
7919
+ padding: '12px 16px',
7920
+ cursor: 'pointer',
7921
+ 'border-bottom': '1px solid rgba(0,0,0,0.1)',
7922
+ },
7923
+ onclick: () => toggleHamburger(attrs),
7924
+ }, m(MaterialIcon, {
7925
+ name: 'menu',
7926
+ style: { width: '24px', height: '24px' },
7927
+ })),
7928
+ // Expand/collapse toggle button (if expandable, right below hamburger)
7929
+ expandable &&
7930
+ m('li.sidenav-expand-toggle', {
7931
+ style: {
7932
+ display: 'flex',
7933
+ 'justify-content': position === 'right' ? 'flex-end' : 'flex-start',
7934
+ 'align-items': 'center',
7935
+ padding: '12px 16px',
7936
+ cursor: 'pointer',
7937
+ 'border-bottom': '1px solid rgba(0,0,0,0.1)',
7938
+ },
7939
+ onclick: () => toggleExpanded(attrs),
7940
+ }, m(MaterialIcon, {
7941
+ name: position === 'right'
7942
+ ? (isExpanded ? 'chevron_right' : 'chevron_left')
7943
+ : (isExpanded ? 'chevron_left' : 'chevron_right'),
7944
+ style: { width: '24px', height: '24px' },
7945
+ })),
7946
+ // Children (menu items) - inject internal props
7947
+ Array.isArray(children)
7948
+ ? children.map((child) => {
7949
+ if (child && typeof child === 'object' && 'tag' in child) {
7950
+ // Clone the vnode and add internal props
7951
+ return Object.assign(Object.assign({}, child), { attrs: Object.assign(Object.assign({}, child.attrs), { _isExpanded: isExpanded, _position: position }) });
7952
+ }
7953
+ return child;
7954
+ })
7955
+ : children,
7956
+ ]),
7862
7957
  ];
7863
7958
  },
7864
7959
  };
7865
7960
  };
7961
+ /**
7962
+ * Sidenav Submenu Item Component
7963
+ */
7964
+ const NavbarSubItem = () => {
7965
+ return {
7966
+ view: ({ attrs }) => {
7967
+ const { text, icon, selected = false, value, onSelect, mode, isExpanded, position = 'left' } = attrs;
7968
+ const handleClick = () => {
7969
+ if (onSelect) {
7970
+ onSelect(value !== undefined ? value : text, !selected);
7971
+ }
7972
+ };
7973
+ const isRightAligned = position === 'right';
7974
+ const submenuContent = isRightAligned
7975
+ ? [
7976
+ // Right-aligned: text on left, icons on right
7977
+ isExpanded && m('span', { style: { 'flex': '1', 'text-align': 'left' } }, text),
7978
+ icon && isExpanded && m('i.material-icons', { style: { 'font-size': '18px' } }, icon),
7979
+ m(MaterialIcon, {
7980
+ name: mode === 'checkbox' ? (selected ? 'check' : 'close') : selected ? 'radio_checked' : 'radio_unchecked',
7981
+ style: {
7982
+ width: '18px',
7983
+ height: '18px',
7984
+ opacity: mode === 'checkbox' && !selected ? '0.3' : '1',
7985
+ },
7986
+ }),
7987
+ ]
7988
+ : [
7989
+ // Left-aligned: indicator on left, text and icon on right
7990
+ m(MaterialIcon, {
7991
+ name: mode === 'checkbox' ? (selected ? 'check' : 'close') : selected ? 'radio_checked' : 'radio_unchecked',
7992
+ style: {
7993
+ width: '18px',
7994
+ height: '18px',
7995
+ opacity: mode === 'checkbox' && !selected ? '0.3' : '1',
7996
+ },
7997
+ }),
7998
+ icon && isExpanded && m('i.material-icons', { style: { 'font-size': '18px', 'margin-left': '8px' } }, icon),
7999
+ isExpanded && m('span', { style: { 'margin-left': icon ? '8px' : '8px' } }, text),
8000
+ ];
8001
+ return m('li.sidenav-subitem', {
8002
+ class: selected ? 'selected' : '',
8003
+ style: {
8004
+ padding: isExpanded ? '8px 16px 8px 48px' : '8px 16px',
8005
+ cursor: 'pointer',
8006
+ display: 'flex',
8007
+ 'align-items': 'center',
8008
+ gap: '8px',
8009
+ 'font-size': '0.9em',
8010
+ 'justify-content': isRightAligned ? 'space-between' : 'flex-start',
8011
+ },
8012
+ onclick: handleClick,
8013
+ }, submenuContent);
8014
+ },
8015
+ };
8016
+ };
7866
8017
  /**
7867
8018
  * Sidenav Item Component
7868
8019
  * Individual items for the sidenav menu
7869
8020
  */
7870
8021
  const SidenavItem = () => {
8022
+ let isSubmenuOpen = false;
7871
8023
  return {
7872
8024
  view: ({ attrs, children }) => {
7873
- const { text, icon, active = false, disabled = false, onclick, href, className = '', divider = false, subheader = false, } = attrs;
8025
+ const { text, icon, active = false, disabled = false, onclick, href, className = '', divider = false, subheader = false, submenu = [], submenuMode = 'checkbox', } = attrs;
7874
8026
  if (divider) {
7875
8027
  return m('li.divider');
7876
8028
  }
7877
8029
  if (subheader) {
7878
8030
  return m('li.subheader', text || children);
7879
8031
  }
7880
- const itemClasses = [active ? 'active' : '', disabled ? 'disabled' : '', className].filter(Boolean).join(' ') || undefined;
7881
- const content = [icon && m('i.material-icons', icon), text || children];
7882
- if (href && !disabled) {
7883
- return m('li', { class: itemClasses }, [
8032
+ const hasSubmenu = submenu && submenu.length > 0;
8033
+ const itemClasses = [
8034
+ active ? 'active' : '',
8035
+ disabled ? 'disabled' : '',
8036
+ hasSubmenu ? 'has-submenu' : '',
8037
+ className,
8038
+ ]
8039
+ .filter(Boolean)
8040
+ .join(' ') || undefined;
8041
+ const handleMainClick = (e) => {
8042
+ e.preventDefault();
8043
+ if (hasSubmenu) {
8044
+ isSubmenuOpen = active ? !isSubmenuOpen : true;
8045
+ }
8046
+ if (onclick && !disabled) {
8047
+ onclick(e);
8048
+ }
8049
+ };
8050
+ // Get internal props passed from parent Sidenav
8051
+ const isExpanded = attrs._isExpanded !== false;
8052
+ const position = attrs._position || 'left';
8053
+ const isRightAligned = position === 'right';
8054
+ // In expanded mode, icons are at the outside edge
8055
+ // In collapsed mode, icons are centered
8056
+ const content = isRightAligned
8057
+ ? [
8058
+ // Right-aligned: text on left, icon on right
8059
+ isExpanded && m('span.sidenav-item-text', { style: { 'flex': '1', 'text-align': 'left', 'margin-right': '8px' } }, text || children),
8060
+ m('i.material-icons', { style: { 'min-width': '24px', 'width': '24px' } }, icon || ''),
8061
+ ]
8062
+ : [
8063
+ // Left-aligned: icon on left, text on right
8064
+ m('i.material-icons', { style: { 'min-width': '24px', 'width': '24px' } }, icon || ''),
8065
+ isExpanded && m('span.sidenav-item-text', { style: { 'margin-left': '8px', 'flex': '1' } }, text || children),
8066
+ ];
8067
+ const linkStyle = {
8068
+ display: 'flex',
8069
+ 'align-items': 'center',
8070
+ padding: isExpanded ? '12px 16px' : '12px 18px',
8071
+ 'justify-content': isExpanded ? (isRightAligned ? 'flex-end' : 'flex-start') : 'center',
8072
+ };
8073
+ const mainItem = href && !disabled
8074
+ ? m('li', { class: itemClasses }, [
7884
8075
  m('a', {
7885
8076
  href,
7886
- onclick: disabled ? undefined : onclick,
8077
+ onclick: handleMainClick,
8078
+ style: linkStyle,
8079
+ }, content),
8080
+ ])
8081
+ : m('li', { class: itemClasses }, [
8082
+ m('a', {
8083
+ onclick: handleMainClick,
8084
+ href: '#!',
8085
+ style: linkStyle,
7887
8086
  }, content),
7888
8087
  ]);
8088
+ // Return main item with submenu if applicable
8089
+ if (hasSubmenu && active && isSubmenuOpen) {
8090
+ return [
8091
+ mainItem,
8092
+ submenu.map((subItem) => m(NavbarSubItem, Object.assign(Object.assign({}, subItem), { mode: submenuMode, isExpanded,
8093
+ position }))),
8094
+ ];
7889
8095
  }
7890
- return m('li', { class: itemClasses }, [
7891
- m('a', {
7892
- onclick: disabled ? undefined : onclick,
7893
- href: '#!',
7894
- }, content),
7895
- ]);
8096
+ return mainItem;
7896
8097
  },
7897
8098
  };
7898
8099
  };
@@ -3,8 +3,14 @@ declare const iconPaths: {
3
3
  readonly caret: readonly ["M7 10l5 5 5-5z", "M0 0h24v24H0z"];
4
4
  readonly close: readonly ["M18.3 5.71a1 1 0 0 0-1.41 0L12 10.59 7.11 5.7A1 1 0 0 0 5.7 7.11L10.59 12l-4.89 4.89a1 1 0 1 0 1.41 1.41L12 13.41l4.89 4.89a1 1 0 0 0 1.41-1.41L13.41 12l4.89-4.89a1 1 0 0 0 0-1.4z", "M0 0h24v24H0z"];
5
5
  readonly chevron: readonly ["M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z", "M0 0h24v24H0z"];
6
+ readonly chevron_left: readonly ["M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z", "M0 0h24v24H0z"];
7
+ readonly chevron_right: readonly ["M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z", "M0 0h24v24H0z"];
8
+ readonly menu: readonly ["M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z", "M0 0h24v24H0z"];
6
9
  readonly expand: readonly ["M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z", "M0 0h24v24H0z"];
7
10
  readonly collapse: readonly ["M19 13H5v-2h14v2z", "M0 0h24v24H0z"];
11
+ readonly check: readonly ["M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z", "M0 0h24v24H0z"];
12
+ readonly radio_checked: readonly ["M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z", "M0 0h24v24H0z"];
13
+ readonly radio_unchecked: readonly ["M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z", "M0 0h24v24H0z"];
8
14
  readonly light_mode: readonly ["M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5M2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1m18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1M11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1m0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1M5.99 4.58a.996.996 0 0 0-1.41 0 .996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41zm12.4 12.4a.996.996 0 0 0-1.41 0 .996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0a.996.996 0 0 0 0-1.41zm1.06-11a.996.996 0 0 0 0-1.41.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0zM7.05 18.4a.996.996 0 0 0 0-1.41.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0z", "M0 0h24v24H0z"];
9
15
  readonly dark_mode: readonly ["M12 3a9 9 0 1 0 9 9c0-.46-.04-.92-.1-1.36a5.39 5.39 0 0 1-4.4 2.26 5.4 5.4 0 0 1-3.14-9.8c-.44-.06-.9-.1-1.36-.1z", "M0 0h24v24H0z"];
10
16
  };
package/dist/sidenav.d.ts CHANGED
@@ -1,4 +1,16 @@
1
1
  import { FactoryComponent, Attributes } from 'mithril';
2
+ export interface NavbarSubItemAttrs {
3
+ /** Text content of the submenu item */
4
+ text: string;
5
+ /** Optional icon name */
6
+ icon?: string;
7
+ /** Whether this submenu item is selected */
8
+ selected?: boolean;
9
+ /** Value for the submenu item */
10
+ value?: any;
11
+ /** Selection callback */
12
+ onSelect?: (value: any, selected: boolean) => void;
13
+ }
2
14
  export interface SidenavAttrs extends Attributes {
3
15
  /** Unique ID for the sidenav */
4
16
  id?: string;
@@ -10,7 +22,7 @@ export interface SidenavAttrs extends Attributes {
10
22
  position?: 'left' | 'right';
11
23
  /** Whether sidenav should overlay content or push it */
12
24
  mode?: 'overlay' | 'push';
13
- /** Width of the sidenav in pixels */
25
+ /** Width of the sidenav in pixels (when expanded) */
14
26
  width?: number;
15
27
  /** Custom class for the sidenav */
16
28
  className?: string;
@@ -26,6 +38,14 @@ export interface SidenavAttrs extends Attributes {
26
38
  fixed?: boolean;
27
39
  /** Breakpoint for responsive behavior (in pixels) */
28
40
  breakpoint?: number;
41
+ /** Show hamburger toggle button */
42
+ showHamburger?: boolean;
43
+ /** Enable collapse/expand functionality */
44
+ expandable?: boolean;
45
+ /** Whether the sidenav is expanded (shows icons + text) */
46
+ isExpanded?: boolean;
47
+ /** Callback when expand state changes */
48
+ onExpandChange?: (expanded: boolean) => void;
29
49
  }
30
50
  export interface SidenavItemAttrs {
31
51
  /** Text content of the item */
@@ -46,6 +66,14 @@ export interface SidenavItemAttrs {
46
66
  divider?: boolean;
47
67
  /** Whether this is a subheader */
48
68
  subheader?: boolean;
69
+ /** Submenu items */
70
+ submenu?: NavbarSubItemAttrs[];
71
+ /** Submenu selection mode */
72
+ submenuMode?: 'checkbox' | 'radio';
73
+ /** @internal - Whether the sidenav is expanded (passed from parent) */
74
+ _isExpanded?: boolean;
75
+ /** @internal - Position of the sidenav (passed from parent) */
76
+ _position?: 'left' | 'right';
49
77
  }
50
78
  /**
51
79
  * Sidenav Component
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mithril-materialized",
3
- "version": "3.4.4",
3
+ "version": "3.5.0",
4
4
  "description": "A materialize library for mithril.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",
@@ -109,7 +109,9 @@
109
109
  }
110
110
 
111
111
  // Legacy Sidenav Styles (maintain backward compatibility)
112
-
112
+ ul.sidenav.right-aligned li > a:not(.btn):not(.btn-large):not(.btn-flat):not(.btn-floating) i.material-icons {
113
+ margin: 0;
114
+ }
113
115
  .sidenav {
114
116
  position: fixed;
115
117
  width: variables.$sidenav-width;
@@ -191,7 +193,8 @@
191
193
  li > a:not(.btn):not(.btn-large):not(.btn-flat):not(.btn-floating) {
192
194
  &:hover { background-color: var(--mm-border-color, rgba(0,0,0,.05));}
193
195
 
194
- color: var(--mm-text-primary, variables.$sidenav-font-color);
196
+ // color: var(--mm-text-primary, variables.$sidenav-font-color);
197
+ color: var(--mm-nav-active-text, #fff);
195
198
  display: block;
196
199
  font-size: variables.$sidenav-font-size;
197
200
  font-weight: 500;
@@ -208,6 +211,7 @@
208
211
  margin: 0 (variables.$sidenav-padding * 2) 0 0;
209
212
  width: math.div(variables.$sidenav-item-height, 2);
210
213
  color: var(--mm-text-secondary, rgba(0,0,0,.54));
214
+ user-select: none;
211
215
  }
212
216
  }
213
217
 
@@ -341,7 +345,7 @@
341
345
  .sidenav.sidenav-fixed .collapsible-body > ul:not(.collapsible) > li.active {
342
346
  background-color: variables.$primary-color;
343
347
  a {
344
- color: variables.$sidenav-bg-color;
348
+ color: var(--mm-nav-active-text, #fff);
345
349
  }
346
350
  }
347
351
  .sidenav .collapsible-body {
@@ -368,3 +372,190 @@
368
372
  .sidenav-overlay {
369
373
  pointer-events: auto;
370
374
  }
375
+
376
+ // Hamburger button styles (legacy - external button)
377
+ .sidenav-hamburger {
378
+ background: var(--mm-surface-color, #fff);
379
+ border-radius: 4px;
380
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
381
+ transition: background-color 0.2s ease, box-shadow 0.2s ease;
382
+
383
+ &:hover {
384
+ background: var(--mm-border-color, rgba(0, 0, 0, 0.05));
385
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
386
+ }
387
+
388
+ svg {
389
+ fill: var(--mm-text-primary, rgba(0, 0, 0, 0.87));
390
+ }
391
+ }
392
+
393
+ // Hamburger item inside sidenav
394
+ .sidenav-hamburger-item {
395
+ list-style: none;
396
+
397
+ &:hover {
398
+ background: var(--mm-border-color, rgba(0, 0, 0, 0.05));
399
+ }
400
+
401
+ svg {
402
+ fill: var(--mm-text-secondary, rgba(0, 0, 0, 0.6));
403
+ }
404
+ }
405
+
406
+ // Collapsed sidenav state
407
+ .sidenav.sidenav-collapsed {
408
+ width: 60px !important;
409
+
410
+ .sidenav-item-text {
411
+ display: none;
412
+ }
413
+
414
+ li > a:not(.btn):not(.btn-large):not(.btn-flat):not(.btn-floating) {
415
+ padding: 0 18px;
416
+ justify-content: center;
417
+
418
+ & > i,
419
+ & > i.material-icons {
420
+ margin: 0;
421
+ float: none;
422
+ }
423
+ }
424
+
425
+ .subheader {
426
+ display: none;
427
+ }
428
+
429
+ .sidenav-subitem {
430
+ padding: 8px 16px !important;
431
+ justify-content: center;
432
+
433
+ span {
434
+ display: none;
435
+ }
436
+ }
437
+ }
438
+
439
+ // Expand/collapse toggle button
440
+ .sidenav-expand-toggle {
441
+ &:hover {
442
+ background: var(--mm-border-color, rgba(0, 0, 0, 0.05));
443
+ }
444
+
445
+ svg {
446
+ fill: var(--mm-text-secondary, rgba(0, 0, 0, 0.6));
447
+ transition: transform 0.2s ease;
448
+ }
449
+ }
450
+
451
+ // Submenu item styles
452
+ .sidenav-subitem {
453
+ list-style: none;
454
+ transition: background-color 0.2s ease;
455
+
456
+ &:hover {
457
+ background: var(--mm-border-color, rgba(0, 0, 0, 0.05));
458
+ }
459
+
460
+ // Don't show selected background - only the check/radio icon indicates selection
461
+ // to avoid confusion with multiple active menu items
462
+ &.selected {
463
+ svg {
464
+ fill: var(--mm-primary-color, #26a69a);
465
+ }
466
+ }
467
+
468
+ svg {
469
+ fill: var(--mm-text-secondary, rgba(0, 0, 0, 0.6));
470
+ transition: fill 0.2s ease;
471
+ }
472
+
473
+ i.material-icons {
474
+ color: var(--mm-text-secondary, rgba(0, 0, 0, 0.6));
475
+ }
476
+ }
477
+
478
+ // Menu item with submenu indicator
479
+ .sidenav li.has-submenu {
480
+ &.active > a {
481
+ background: var(--mm-primary-color-light, rgba(38, 166, 154, 0.1));
482
+ color: var(--mm-primary-color, #26a69a);
483
+ }
484
+ }
485
+
486
+ // Dark theme support
487
+ [data-theme="dark"] {
488
+ .sidenav-hamburger {
489
+ background: var(--mm-surface-color, #1e1e1e);
490
+
491
+ svg {
492
+ fill: var(--mm-text-primary, rgba(255, 255, 255, 0.87));
493
+ }
494
+ }
495
+
496
+ .sidenav {
497
+ background-color: var(--mm-surface-color, #1e1e1e);
498
+
499
+ li > a:not(.btn):not(.btn-large):not(.btn-flat):not(.btn-floating) {
500
+ color: var(--mm-text-primary, rgba(255, 255, 255, 0.87));
501
+
502
+ &:hover {
503
+ background-color: var(--mm-border-color, rgba(255, 255, 255, 0.05));
504
+ }
505
+
506
+ & > i,
507
+ & > i.material-icons {
508
+ color: var(--mm-text-secondary, rgba(255, 255, 255, 0.6));
509
+ }
510
+ }
511
+
512
+ li.active {
513
+ background-color: rgba(255, 255, 255, 0.05);
514
+
515
+ & > a:not(.btn):not(.btn-large):not(.btn-flat):not(.btn-floating) {
516
+ color: var(--mm-nav-active-text, #fff);
517
+
518
+ & > i,
519
+ & > i.material-icons {
520
+ color: var(--mm-nav-active-text, #fff);
521
+ }
522
+ }
523
+ }
524
+
525
+ .collapsible-body > ul:not(.collapsible) > li.active a {
526
+ color: var(--mm-nav-active-text, #fff);
527
+
528
+ i,
529
+ i.material-icons {
530
+ color: var(--mm-nav-active-text, #fff);
531
+ }
532
+ }
533
+
534
+ .subheader {
535
+ color: var(--mm-text-secondary, rgba(255, 255, 255, 0.6));
536
+ }
537
+ }
538
+
539
+ .sidenav-expand-toggle svg {
540
+ fill: var(--mm-text-secondary, rgba(255, 255, 255, 0.6));
541
+ }
542
+
543
+ .sidenav-subitem {
544
+ &:hover {
545
+ background: var(--mm-border-color, rgba(255, 255, 255, 0.05));
546
+ }
547
+
548
+ svg {
549
+ fill: var(--mm-text-secondary, rgba(255, 255, 255, 0.6));
550
+ }
551
+
552
+ i.material-icons {
553
+ color: var(--mm-text-secondary, rgba(255, 255, 255, 0.6));
554
+ }
555
+ }
556
+ }
557
+
558
+ // Animation for smooth width transitions
559
+ .sidenav {
560
+ transition: transform 0.3s ease, width 0.3s ease;
561
+ }