mithril-materialized 3.5.3 → 3.5.4
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/advanced.css +54 -6
- package/dist/components.css +38 -7
- package/dist/index.css +55 -7
- package/dist/index.esm.js +86 -23
- package/dist/index.js +86 -23
- package/dist/index.min.css +2 -2
- package/dist/index.umd.js +86 -23
- package/dist/sidenav.d.ts +15 -6
- package/package.json +12 -12
- package/sass/components/_navbar.scss +23 -0
- package/sass/components/_sidenav.scss +44 -9
- package/sass/components/_theme-variables.scss +1 -1
package/dist/index.umd.js
CHANGED
|
@@ -7814,6 +7814,66 @@
|
|
|
7814
7814
|
};
|
|
7815
7815
|
};
|
|
7816
7816
|
|
|
7817
|
+
// List of MaterialIcon SVG icons that are available
|
|
7818
|
+
const materialIconSvgNames = [
|
|
7819
|
+
'caret', 'close', 'chevron', 'chevron_left', 'chevron_right', 'menu',
|
|
7820
|
+
'expand', 'collapse', 'check', 'radio_checked', 'radio_unchecked',
|
|
7821
|
+
'light_mode', 'dark_mode'
|
|
7822
|
+
];
|
|
7823
|
+
/**
|
|
7824
|
+
* Helper function to render icons based on IconDefinition type
|
|
7825
|
+
*/
|
|
7826
|
+
const renderIcon = (icon, style) => {
|
|
7827
|
+
if (!icon)
|
|
7828
|
+
return null;
|
|
7829
|
+
if (typeof icon === 'string') {
|
|
7830
|
+
// Check if this is a MaterialIcon SVG name
|
|
7831
|
+
if (materialIconSvgNames.includes(icon)) {
|
|
7832
|
+
return m(MaterialIcon, { name: icon, style });
|
|
7833
|
+
}
|
|
7834
|
+
// Fall back to Material Icons font for other icon names
|
|
7835
|
+
return m('i.material-icons', { style }, icon);
|
|
7836
|
+
}
|
|
7837
|
+
if (icon.type === 'svg') {
|
|
7838
|
+
// Inline SVG
|
|
7839
|
+
return m.trust(icon.content);
|
|
7840
|
+
}
|
|
7841
|
+
if (icon.type === 'image') {
|
|
7842
|
+
// Image URL
|
|
7843
|
+
return m('img', {
|
|
7844
|
+
src: icon.content,
|
|
7845
|
+
style: Object.assign(Object.assign({}, style), { width: '24px', height: '24px', objectFit: 'contain' }),
|
|
7846
|
+
});
|
|
7847
|
+
}
|
|
7848
|
+
return null;
|
|
7849
|
+
};
|
|
7850
|
+
/**
|
|
7851
|
+
* Helper function to render a single sidenav item (for header/footer items)
|
|
7852
|
+
*/
|
|
7853
|
+
const renderSidenavItem = (item, isExpanded, position) => {
|
|
7854
|
+
const { text, icon, onclick, href, className = '' } = item;
|
|
7855
|
+
const isRightAligned = position === 'right';
|
|
7856
|
+
const content = isRightAligned
|
|
7857
|
+
? [
|
|
7858
|
+
isExpanded && m('span.sidenav-item-text', { style: { 'flex': '1', 'text-align': 'left', 'margin-right': '8px' } }, text),
|
|
7859
|
+
renderIcon(icon, { 'min-width': '24px', 'width': '24px' }),
|
|
7860
|
+
]
|
|
7861
|
+
: [
|
|
7862
|
+
renderIcon(icon, { 'min-width': '24px', 'width': '24px' }),
|
|
7863
|
+
isExpanded && m('span.sidenav-item-text', { style: { 'margin-left': '8px', 'flex': '1' } }, text),
|
|
7864
|
+
];
|
|
7865
|
+
const linkStyle = {
|
|
7866
|
+
display: 'flex',
|
|
7867
|
+
'align-items': 'center',
|
|
7868
|
+
padding: isExpanded ? '12px 16px' : '12px 18px',
|
|
7869
|
+
'justify-content': isExpanded ? (isRightAligned ? 'flex-end' : 'flex-start') : 'center',
|
|
7870
|
+
};
|
|
7871
|
+
return m('li', { class: className }, m('a', {
|
|
7872
|
+
href: href || '#!',
|
|
7873
|
+
onclick: onclick,
|
|
7874
|
+
style: linkStyle,
|
|
7875
|
+
}, content));
|
|
7876
|
+
};
|
|
7817
7877
|
/**
|
|
7818
7878
|
* Sidenav Component
|
|
7819
7879
|
* A responsive navigation drawer that slides in from the side
|
|
@@ -7936,6 +7996,8 @@
|
|
|
7936
7996
|
name: 'menu',
|
|
7937
7997
|
style: { width: '24px', height: '24px' },
|
|
7938
7998
|
})),
|
|
7999
|
+
// Header item (if provided, appears before expand/collapse toggle)
|
|
8000
|
+
attrs.header && renderSidenavItem(attrs.header, isExpanded, position),
|
|
7939
8001
|
// Expand/collapse toggle button (if expandable, right below hamburger)
|
|
7940
8002
|
expandable &&
|
|
7941
8003
|
m('li.sidenav-expand-toggle', {
|
|
@@ -7964,6 +8026,8 @@
|
|
|
7964
8026
|
return child;
|
|
7965
8027
|
})
|
|
7966
8028
|
: children,
|
|
8029
|
+
// Footer item (if provided, appears at the bottom)
|
|
8030
|
+
attrs.footer && renderSidenavItem(attrs.footer, isExpanded, position),
|
|
7967
8031
|
]),
|
|
7968
8032
|
];
|
|
7969
8033
|
},
|
|
@@ -7982,43 +8046,42 @@
|
|
|
7982
8046
|
}
|
|
7983
8047
|
};
|
|
7984
8048
|
const isRightAligned = position === 'right';
|
|
8049
|
+
// Render indicator icon for checkbox/radio modes
|
|
8050
|
+
const indicatorIcon = mode !== 'none'
|
|
8051
|
+
? m(MaterialIcon, {
|
|
8052
|
+
name: mode === 'checkbox' ? (selected ? 'check' : 'close') : selected ? 'radio_checked' : 'radio_unchecked',
|
|
8053
|
+
style: {
|
|
8054
|
+
width: '18px',
|
|
8055
|
+
height: '18px',
|
|
8056
|
+
opacity: mode === 'checkbox' && !selected ? '0.3' : '1',
|
|
8057
|
+
},
|
|
8058
|
+
})
|
|
8059
|
+
: null;
|
|
7985
8060
|
const submenuContent = isRightAligned
|
|
7986
8061
|
? [
|
|
7987
8062
|
// Right-aligned: text on left, icons on right
|
|
7988
8063
|
isExpanded && m('span', { style: { 'flex': '1', 'text-align': 'left' } }, text),
|
|
7989
|
-
icon && isExpanded &&
|
|
7990
|
-
|
|
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
|
-
}),
|
|
8064
|
+
icon && isExpanded && renderIcon(icon, { 'font-size': '18px' }),
|
|
8065
|
+
indicatorIcon,
|
|
7998
8066
|
]
|
|
7999
8067
|
: [
|
|
8000
8068
|
// Left-aligned: indicator on left, text and icon on right
|
|
8001
|
-
|
|
8002
|
-
|
|
8003
|
-
|
|
8004
|
-
width: '18px',
|
|
8005
|
-
height: '18px',
|
|
8006
|
-
opacity: mode === 'checkbox' && !selected ? '0.3' : '1',
|
|
8007
|
-
},
|
|
8008
|
-
}),
|
|
8009
|
-
icon && isExpanded && m('i.material-icons', { style: { 'font-size': '18px', 'margin-left': '8px' } }, icon),
|
|
8010
|
-
isExpanded && m('span', { style: { 'margin-left': icon ? '8px' : '8px' } }, text),
|
|
8069
|
+
indicatorIcon,
|
|
8070
|
+
icon && isExpanded && renderIcon(icon, { 'font-size': '18px', 'margin-left': indicatorIcon ? '8px' : '0' }),
|
|
8071
|
+
isExpanded && m('span', { style: { 'margin-left': icon || indicatorIcon ? '8px' : '0' } }, text),
|
|
8011
8072
|
];
|
|
8012
8073
|
return m('li.sidenav-subitem', {
|
|
8013
8074
|
class: selected ? 'selected' : '',
|
|
8014
8075
|
style: {
|
|
8015
|
-
padding: isExpanded ? '
|
|
8076
|
+
padding: isExpanded ? '0 16px 0 48px' : '0 16px',
|
|
8016
8077
|
cursor: 'pointer',
|
|
8017
8078
|
display: 'flex',
|
|
8018
8079
|
'align-items': 'center',
|
|
8019
8080
|
gap: '8px',
|
|
8020
8081
|
'font-size': '0.9em',
|
|
8021
8082
|
'justify-content': isRightAligned ? 'space-between' : 'flex-start',
|
|
8083
|
+
height: '48px',
|
|
8084
|
+
'min-height': '48px',
|
|
8022
8085
|
},
|
|
8023
8086
|
onclick: handleClick,
|
|
8024
8087
|
}, submenuContent);
|
|
@@ -8050,8 +8113,8 @@
|
|
|
8050
8113
|
.filter(Boolean)
|
|
8051
8114
|
.join(' ') || undefined;
|
|
8052
8115
|
const handleMainClick = (e) => {
|
|
8053
|
-
e.preventDefault();
|
|
8054
8116
|
if (hasSubmenu) {
|
|
8117
|
+
e.preventDefault();
|
|
8055
8118
|
isSubmenuOpen = active ? !isSubmenuOpen : true;
|
|
8056
8119
|
}
|
|
8057
8120
|
if (onclick && !disabled) {
|
|
@@ -8068,11 +8131,11 @@
|
|
|
8068
8131
|
? [
|
|
8069
8132
|
// Right-aligned: text on left, icon on right
|
|
8070
8133
|
isExpanded && m('span.sidenav-item-text', { style: { 'flex': '1', 'text-align': 'left', 'margin-right': '8px' } }, text || children),
|
|
8071
|
-
|
|
8134
|
+
renderIcon(icon, { 'min-width': '24px', 'width': '24px' }),
|
|
8072
8135
|
]
|
|
8073
8136
|
: [
|
|
8074
8137
|
// Left-aligned: icon on left, text on right
|
|
8075
|
-
|
|
8138
|
+
renderIcon(icon, { 'min-width': '24px', 'width': '24px' }),
|
|
8076
8139
|
isExpanded && m('span.sidenav-item-text', { style: { 'margin-left': '8px', 'flex': '1' } }, text || children),
|
|
8077
8140
|
];
|
|
8078
8141
|
const linkStyle = {
|
package/dist/sidenav.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { FactoryComponent, Attributes } from 'mithril';
|
|
2
|
+
/** Icon definition - supports material icon name, inline SVG, or image URL */
|
|
3
|
+
export type IconDefinition = string | {
|
|
4
|
+
type: 'svg' | 'image';
|
|
5
|
+
content: string;
|
|
6
|
+
};
|
|
2
7
|
export interface NavbarSubItemAttrs {
|
|
3
8
|
/** Text content of the submenu item */
|
|
4
9
|
text: string;
|
|
5
|
-
/** Optional icon name */
|
|
6
|
-
icon?:
|
|
10
|
+
/** Optional icon - material icon name, SVG object, or image object */
|
|
11
|
+
icon?: IconDefinition;
|
|
7
12
|
/** Whether this submenu item is selected */
|
|
8
13
|
selected?: boolean;
|
|
9
14
|
/** Value for the submenu item */
|
|
@@ -46,12 +51,16 @@ export interface SidenavAttrs extends Attributes {
|
|
|
46
51
|
isExpanded?: boolean;
|
|
47
52
|
/** Callback when expand state changes */
|
|
48
53
|
onExpandChange?: (expanded: boolean) => void;
|
|
54
|
+
/** Header item displayed before expand/collapse toggle */
|
|
55
|
+
header?: SidenavItemAttrs;
|
|
56
|
+
/** Footer item displayed at the bottom of the sidenav */
|
|
57
|
+
footer?: SidenavItemAttrs;
|
|
49
58
|
}
|
|
50
59
|
export interface SidenavItemAttrs {
|
|
51
60
|
/** Text content of the item */
|
|
52
61
|
text?: string;
|
|
53
|
-
/** Icon
|
|
54
|
-
icon?:
|
|
62
|
+
/** Icon - material icon name, SVG object, or image object */
|
|
63
|
+
icon?: IconDefinition;
|
|
55
64
|
/** Whether this item is active */
|
|
56
65
|
active?: boolean;
|
|
57
66
|
/** Whether this item is disabled */
|
|
@@ -68,8 +77,8 @@ export interface SidenavItemAttrs {
|
|
|
68
77
|
subheader?: boolean;
|
|
69
78
|
/** Submenu items */
|
|
70
79
|
submenu?: NavbarSubItemAttrs[];
|
|
71
|
-
/** Submenu selection mode */
|
|
72
|
-
submenuMode?: 'checkbox' | 'radio';
|
|
80
|
+
/** Submenu selection mode - 'checkbox' for multi-select, 'radio' for single-select, 'none' for no indicators */
|
|
81
|
+
submenuMode?: 'checkbox' | 'radio' | 'none';
|
|
73
82
|
/** @internal - Whether the sidenav is expanded (passed from parent) */
|
|
74
83
|
_isExpanded?: boolean;
|
|
75
84
|
/** @internal - Position of the sidenav (passed from parent) */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mithril-materialized",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.4",
|
|
4
4
|
"description": "A materialize library for mithril.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
@@ -75,10 +75,10 @@
|
|
|
75
75
|
"mithril": "^2.3.7"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
|
-
"@playwright/test": "^1.
|
|
79
|
-
"@rollup/plugin-typescript": "^12.
|
|
78
|
+
"@playwright/test": "^1.56.1",
|
|
79
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
80
80
|
"@testing-library/dom": "^10.4.1",
|
|
81
|
-
"@testing-library/jest-dom": "^6.
|
|
81
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
82
82
|
"@testing-library/user-event": "^14.6.1",
|
|
83
83
|
"@types/jest": "^30.0.0",
|
|
84
84
|
"@types/mithril": "^2.2.7",
|
|
@@ -86,16 +86,16 @@
|
|
|
86
86
|
"concurrently": "^9.2.1",
|
|
87
87
|
"express": "^5.1.0",
|
|
88
88
|
"identity-obj-proxy": "^3.0.0",
|
|
89
|
-
"jest": "^30.
|
|
90
|
-
"jest-environment-jsdom": "^30.
|
|
89
|
+
"jest": "^30.2.0",
|
|
90
|
+
"jest-environment-jsdom": "^30.2.0",
|
|
91
91
|
"js-yaml": "^4.1.0",
|
|
92
|
-
"rimraf": "^6.0
|
|
93
|
-
"rollup": "^4.
|
|
92
|
+
"rimraf": "^6.1.0",
|
|
93
|
+
"rollup": "^4.52.5",
|
|
94
94
|
"rollup-plugin-postcss": "^4.0.2",
|
|
95
|
-
"sass": "^1.
|
|
96
|
-
"ts-jest": "^29.4.
|
|
95
|
+
"sass": "^1.93.2",
|
|
96
|
+
"ts-jest": "^29.4.5",
|
|
97
97
|
"tslib": "^2.8.1",
|
|
98
|
-
"typedoc": "^0.28.
|
|
99
|
-
"typescript": "^5.9.
|
|
98
|
+
"typedoc": "^0.28.14",
|
|
99
|
+
"typescript": "^5.9.3"
|
|
100
100
|
}
|
|
101
101
|
}
|
|
@@ -217,3 +217,26 @@ nav {
|
|
|
217
217
|
height: variables.$navbar-height;
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
|
+
|
|
221
|
+
// Dark theme support
|
|
222
|
+
[data-theme="dark"] {
|
|
223
|
+
nav ul li.active {
|
|
224
|
+
background-color: rgba(38, 166, 154, 0.2);
|
|
225
|
+
|
|
226
|
+
a {
|
|
227
|
+
color: var(--mm-text-primary, rgba(255, 255, 255, 0.87));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
i, .material-icons {
|
|
231
|
+
color: var(--mm-text-primary, rgba(255, 255, 255, 0.87));
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Make menu items non-selectable by default
|
|
237
|
+
nav ul li {
|
|
238
|
+
user-select: none;
|
|
239
|
+
-webkit-user-select: none;
|
|
240
|
+
-moz-user-select: none;
|
|
241
|
+
-ms-user-select: none;
|
|
242
|
+
}
|
|
@@ -193,14 +193,17 @@ ul.sidenav.right-aligned li > a:not(.btn):not(.btn-large):not(.btn-flat):not(.bt
|
|
|
193
193
|
li > a:not(.btn):not(.btn-large):not(.btn-flat):not(.btn-floating) {
|
|
194
194
|
&:hover { background-color: var(--mm-border-color, rgba(0,0,0,.05));}
|
|
195
195
|
|
|
196
|
-
|
|
197
|
-
color: var(--mm-nav-active-text, #fff);
|
|
196
|
+
color: var(--mm-text-primary, variables.$sidenav-font-color);
|
|
198
197
|
display: block;
|
|
199
198
|
font-size: variables.$sidenav-font-size;
|
|
200
199
|
font-weight: 500;
|
|
201
200
|
height: variables.$sidenav-item-height;
|
|
202
201
|
line-height: variables.$sidenav-line-height;
|
|
203
202
|
padding: 0 (variables.$sidenav-padding * 2);
|
|
203
|
+
user-select: none;
|
|
204
|
+
-webkit-user-select: none;
|
|
205
|
+
-moz-user-select: none;
|
|
206
|
+
-ms-user-select: none;
|
|
204
207
|
|
|
205
208
|
& > i,
|
|
206
209
|
& > [class^="mdi-"], li > a > [class*="mdi-"],
|
|
@@ -215,6 +218,17 @@ ul.sidenav.right-aligned li > a:not(.btn):not(.btn-large):not(.btn-flat):not(.bt
|
|
|
215
218
|
}
|
|
216
219
|
}
|
|
217
220
|
|
|
221
|
+
// Active menu item styling
|
|
222
|
+
li.active > a:not(.btn):not(.btn-large):not(.btn-flat):not(.btn-floating) {
|
|
223
|
+
color: var(--mm-nav-active-text, #fff);
|
|
224
|
+
background-color: var(--mm-primary-color, #26a69a);
|
|
225
|
+
|
|
226
|
+
& > i,
|
|
227
|
+
& > i.material-icons {
|
|
228
|
+
color: var(--mm-nav-active-text, #fff);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
218
232
|
// Stlye btn anchors
|
|
219
233
|
li > .btn, li > .btn-large, li > .btn-flat, li > .btn-floating {
|
|
220
234
|
margin: 10px (variables.$sidenav-padding * 2);
|
|
@@ -452,17 +466,25 @@ ul.sidenav.right-aligned li > a:not(.btn):not(.btn-large):not(.btn-flat):not(.bt
|
|
|
452
466
|
.sidenav-subitem {
|
|
453
467
|
list-style: none;
|
|
454
468
|
transition: background-color 0.2s ease;
|
|
469
|
+
user-select: none;
|
|
470
|
+
-webkit-user-select: none;
|
|
471
|
+
-moz-user-select: none;
|
|
472
|
+
-ms-user-select: none;
|
|
455
473
|
|
|
456
474
|
&:hover {
|
|
457
475
|
background: var(--mm-border-color, rgba(0, 0, 0, 0.05));
|
|
458
476
|
}
|
|
459
477
|
|
|
460
|
-
// Don't show selected background - only the check/radio icon indicates selection
|
|
461
|
-
// to avoid confusion with multiple active menu items
|
|
462
478
|
&.selected {
|
|
479
|
+
background-color: var(--mm-primary-color-light, rgba(38, 166, 154, 0.15));
|
|
480
|
+
|
|
463
481
|
svg {
|
|
464
482
|
fill: var(--mm-primary-color, #26a69a);
|
|
465
483
|
}
|
|
484
|
+
|
|
485
|
+
i.material-icons {
|
|
486
|
+
color: var(--mm-primary-color, #26a69a);
|
|
487
|
+
}
|
|
466
488
|
}
|
|
467
489
|
|
|
468
490
|
svg {
|
|
@@ -510,24 +532,24 @@ ul.sidenav.right-aligned li > a:not(.btn):not(.btn-large):not(.btn-flat):not(.bt
|
|
|
510
532
|
}
|
|
511
533
|
|
|
512
534
|
li.active {
|
|
513
|
-
background-color:
|
|
535
|
+
background-color: var(--mm-primary-color, #26a69a);
|
|
514
536
|
|
|
515
537
|
& > a:not(.btn):not(.btn-large):not(.btn-flat):not(.btn-floating) {
|
|
516
|
-
color:
|
|
538
|
+
color: #000;
|
|
517
539
|
|
|
518
540
|
& > i,
|
|
519
541
|
& > i.material-icons {
|
|
520
|
-
color:
|
|
542
|
+
color: #000;
|
|
521
543
|
}
|
|
522
544
|
}
|
|
523
545
|
}
|
|
524
546
|
|
|
525
547
|
.collapsible-body > ul:not(.collapsible) > li.active a {
|
|
526
|
-
color:
|
|
548
|
+
color: #000;
|
|
527
549
|
|
|
528
550
|
i,
|
|
529
551
|
i.material-icons {
|
|
530
|
-
color:
|
|
552
|
+
color: #000;
|
|
531
553
|
}
|
|
532
554
|
}
|
|
533
555
|
|
|
@@ -552,6 +574,19 @@ ul.sidenav.right-aligned li > a:not(.btn):not(.btn-large):not(.btn-flat):not(.bt
|
|
|
552
574
|
i.material-icons {
|
|
553
575
|
color: var(--mm-text-secondary, rgba(255, 255, 255, 0.6));
|
|
554
576
|
}
|
|
577
|
+
|
|
578
|
+
&.selected {
|
|
579
|
+
background-color: rgba(38, 166, 154, 0.2);
|
|
580
|
+
color: var(--mm-text-primary, rgba(255, 255, 255, 0.87));
|
|
581
|
+
|
|
582
|
+
svg {
|
|
583
|
+
fill: var(--mm-primary-color, #26a69a);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
i.material-icons {
|
|
587
|
+
color: var(--mm-primary-color, #26a69a);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
555
590
|
}
|
|
556
591
|
}
|
|
557
592
|
|