@mono-lit/helper 0.0.8 → 0.0.10
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/accordion-core-DaNyPWRr.js +277 -0
- package/dist/alert-core-DWtHbX_-.js +134 -0
- package/dist/breadcrumb-list-core-Dh68T8Cf.js +747 -0
- package/dist/{mono-button-CLkHg3WW.js → button-core-DerXg84Q.js} +3 -276
- package/dist/button-dropdown-core-DKYEOyjy.js +654 -0
- package/dist/button-utils-D5-66M02.js +63 -0
- package/dist/card-utils-l80qAmrN.js +312 -0
- package/dist/chart-core-DV7hD3ZY.js +801 -0
- package/dist/checkbox-utils-DKdrhAzF.js +337 -0
- package/dist/chip-utils-DpRrd7Zj.js +403 -0
- package/dist/{data-source-controller-C6C4ej_M.js → data-source-controller-DS_JLrmS.js} +1 -1
- package/dist/{data-source-options-fxT5QIX4.js → data-source-options-DJUNU26C.js} +6 -6
- package/dist/{data-source-read-BL266IW0.js → data-source-read-uKJpRAzx.js} +2 -2
- package/dist/date-core-CyuSyvvG.js +734 -0
- package/dist/drawer-core-DbFWvNln.js +759 -0
- package/dist/dropdown-core-BCH1pK14.js +511 -0
- package/dist/dropdown-table-core-SfHUJVFq.js +1342 -0
- package/dist/export.js +1 -1
- package/dist/{field-path-BabiMrrA.js → field-path-DK2VBWHl.js} +1 -1
- package/dist/field-tooltip.css_raw-DVblekCl.js +5 -0
- package/dist/{field-validation.css_raw-Cx6SGrfP.js → field-validation.css_raw-BU7C6173.js} +1 -170
- package/dist/file-upload-core-Cz_dBQMx.js +624 -0
- package/dist/filter-builder-core-DyWjbBP7.js +381 -0
- package/dist/{filter-builder-B6Y2mmbM.js → filter-builder-vbqIuPhX.js} +1 -1
- package/dist/{filter-eval-ChDSaAUH.js → filter-eval-CqeBnMYh.js} +1 -1
- package/dist/{filter-odata-Bi27XUpQ.js → filter-odata-GsczYKNC.js} +1 -1
- package/dist/{hydration-flush-BaE9gN3C.js → hydration-flush-Volt9X7Q.js} +2 -1071
- package/dist/index.js +11 -11
- package/dist/{index.node-CLqE8F8P.js → index.node-Csy9zrr1.js} +4 -4
- package/dist/index.node.js +11 -11
- package/dist/input-utils-BglY-k0H.js +1145 -0
- package/dist/menu-core-DkAYuCZ2.js +831 -0
- package/dist/modal-core-CSBSPN_m.js +844 -0
- package/dist/mono-button-DVvZ03P-.js +280 -0
- package/dist/{mono-button.shadow-DqZMpcqY.js → mono-button.shadow-BANxMGln.js} +6 -594
- package/dist/{mono-data-chart-NKPdAgVq.js → mono-data-chart-ChF4J9RT.js} +6 -6
- package/dist/{mono-data-dropdown-DUXo_jxd.js → mono-data-dropdown-Bgj2PDfm.js} +1 -1
- package/dist/{mono-data-grid-Bb00QM72.js → mono-data-grid-DJkp96N-.js} +346 -51
- package/dist/{mono-event-BPku9HpS.js → mono-event-CAZf0F_k.js} +14 -9
- package/dist/{mono-form-controller-BrA10erm.js → mono-form-controller-DxZLvyg6.js} +2 -1
- package/dist/mono-table-checkbox-core-BKOMx8R5.js +5288 -0
- package/dist/nav-core-B5qU2dzn.js +225 -0
- package/dist/{normalize-error-D93O4q8g.js → normalize-error-BEcd1tmS.js} +2 -2
- package/dist/otp-core-DXg3vFLh.js +758 -0
- package/dist/radio-utils-Dk9Tl1jz.js +319 -0
- package/dist/rich-text-editor-core-Ddd_QaLn.js +1280 -0
- package/dist/select-utils-BgArYHk8.js +2140 -0
- package/dist/sidebar-core-CD6txDo3.js +583 -0
- package/dist/slider-core-vcWr321-.js +1014 -0
- package/dist/src/components/dropdown-table/dropdown-table-core.d.ts +2 -2
- package/dist/src/components/dropdown-table/dropdown-table-types.d.ts +1 -1
- package/dist/src/components/dropdown-table/index.d.ts +1 -1
- package/dist/src/components/dropdown-table/index.shadow.d.ts +1 -1
- package/dist/src/components/dropdown-table/mono-data-dropdown.d.ts +1 -1
- package/dist/src/components/form/form-types.d.ts +9 -3
- package/dist/src/components/input/input-core.d.ts +1 -1
- package/dist/src/components/input/input-types.d.ts +1 -1
- package/dist/src/components/otp/otp-core.d.ts +1 -1
- package/dist/src/components/select/select-core.d.ts +1 -1
- package/dist/src/components/select/select-types.d.ts +1 -1
- package/dist/src/components/slider/slider-core.d.ts +1 -1
- package/dist/src/components/slider/slider-types.d.ts +1 -1
- package/dist/src/components/table/filter-suggestion.d.ts +171 -0
- package/dist/src/components/table/index.d.ts +5 -4
- package/dist/src/components/table/index.shadow.d.ts +5 -4
- package/dist/src/components/table/mono-data-grid.d.ts +58 -3
- package/dist/src/components/table/mono-table-empty-core.d.ts +37 -0
- package/dist/src/components/table/mono-table-search-core.d.ts +22 -3
- package/dist/src/components/table/table-types.d.ts +74 -4
- package/dist/src/components/tag-input/tag-input-core.d.ts +1 -1
- package/dist/src/components/tag-input/tag-input-types.d.ts +1 -1
- package/dist/src/components/textarea/textarea-core.d.ts +1 -1
- package/dist/src/composables/mono-event.d.ts +7 -1
- package/dist/src/entries/index.d.ts +8 -6
- package/dist/src/entries/index.node.d.ts +8 -6
- package/dist/src/search/index.d.ts +1 -1
- package/dist/src/utils/group-count.d.ts +36 -0
- package/dist/switch-utils-CTZ4id2V.js +338 -0
- package/dist/tabs-core-r5-B8k_N.js +317 -0
- package/dist/tag-input-utils-D2JA90DQ.js +3060 -0
- package/dist/textarea-utils-VU1KeXm8.js +821 -0
- package/dist/ui/accordion.js +2 -274
- package/dist/ui/alert.js +2 -131
- package/dist/ui/breadcrumb.js +4 -745
- package/dist/ui/button-dropdown.js +4 -652
- package/dist/ui/button.js +2 -63
- package/dist/ui/card.js +2 -310
- package/dist/ui/chart.js +4 -800
- package/dist/ui/checkbox.js +4 -335
- package/dist/ui/chip.js +4 -402
- package/dist/ui/date.js +3 -732
- package/dist/ui/drawer.js +3 -757
- package/dist/ui/dropdown-table.js +5 -1341
- package/dist/ui/dropdown.js +4 -509
- package/dist/ui/file-upload.js +3 -622
- package/dist/ui/filter.js +5 -380
- package/dist/ui/form.js +1 -1
- package/dist/ui/index.css +130 -5
- package/dist/ui/input.js +3 -1141
- package/dist/ui/menu.js +4 -828
- package/dist/ui/modal.js +4 -843
- package/dist/ui/nav.js +4 -223
- package/dist/ui/otp.js +4 -756
- package/dist/ui/radio.js +4 -317
- package/dist/ui/rich-text-editor.js +4 -1278
- package/dist/ui/select.js +5 -2138
- package/dist/ui/shadow/accordion.js +4 -273
- package/dist/ui/shadow/alert.js +4 -130
- package/dist/ui/shadow/breadcrumb.js +5 -744
- package/dist/ui/shadow/button-dropdown.js +6 -652
- package/dist/ui/shadow/button.js +3 -63
- package/dist/ui/shadow/card.js +4 -309
- package/dist/ui/shadow/chart.js +6 -1576
- package/dist/ui/shadow/checkbox.js +4 -334
- package/dist/ui/shadow/chip.js +4 -396
- package/dist/ui/shadow/date.js +7 -731
- package/dist/ui/shadow/drawer.js +4 -756
- package/dist/ui/shadow/dropdown-table.js +8 -1762
- package/dist/ui/shadow/dropdown.js +4 -508
- package/dist/ui/shadow/file-upload.js +4 -620
- package/dist/ui/shadow/filter.js +7 -379
- package/dist/ui/shadow/input.js +6 -1140
- package/dist/ui/shadow/menu.js +5 -828
- package/dist/ui/shadow/modal.js +6 -1063
- package/dist/ui/shadow/nav.js +5 -223
- package/dist/ui/shadow/otp.js +6 -754
- package/dist/ui/shadow/radio.js +4 -316
- package/dist/ui/shadow/rich-text-editor.js +4 -1276
- package/dist/ui/shadow/select.js +6 -2136
- package/dist/ui/shadow/sidebar.js +5 -581
- package/dist/ui/shadow/slider.js +5 -1010
- package/dist/ui/shadow/switch.js +4 -335
- package/dist/ui/shadow/table.js +10 -4501
- package/dist/ui/shadow/tabs.js +6 -315
- package/dist/ui/shadow/tag-input.js +7 -3057
- package/dist/ui/shadow/textarea.js +6 -817
- package/dist/ui/sidebar.js +3 -581
- package/dist/ui/slider.js +4 -1012
- package/dist/ui/switch.js +4 -336
- package/dist/ui/table.js +9 -4502
- package/dist/ui/tabs.js +4 -315
- package/dist/ui/tag-input.js +5 -3058
- package/dist/ui/textarea.js +4 -819
- package/dist/vue.d.ts +3 -2
- package/package.json +3 -3
- package/dist/chip-strip-bNfLn52Z.js +0 -215
- package/dist/data-source-controller-Dx6IQ2CN.js +0 -243
- package/dist/data-source-options-BM4r4PRw.js +0 -558
- package/dist/data-source-read-HyBCRg1t.js +0 -242
- package/dist/excel-BXzr3uI1.js +0 -784
- package/dist/export-ixRdCS2y.js +0 -2388
- package/dist/field-tooltip-addon-CWCp19mJ.js +0 -702
- package/dist/field-tooltip.css_raw-U5UeTa2d.js +0 -269
- package/dist/filter-builder-C0T3pMx2.js +0 -208
- package/dist/form-control-core-BbiACMtL.js +0 -226
- package/dist/icon-ClxnYhBG.js +0 -19
- package/dist/import-Dc4eXC02.js +0 -612
- package/dist/light-slots-_no0r2Z-.js +0 -246
- package/dist/markdown-uGlE_OfJ.js +0 -20191
- package/dist/mono-data-grid-Bkr-e1-i.js +0 -4043
- package/dist/normalize-error-BmLbgANw.js +0 -1048
|
@@ -0,0 +1,831 @@
|
|
|
1
|
+
import { a as defineHybridPropAliases, n as arrayHasChanged, r as booleanStringConverter, t as __decorate } from "./decorate-DbYFpi8R.js";
|
|
2
|
+
import { t as dispatchMonoEvent } from "./mono-event-CAZf0F_k.js";
|
|
3
|
+
import { t as isIconifyClass } from "./icon-BM9N-jOt.js";
|
|
4
|
+
import { a as validateColorProp, i as isThemeColorToken, n as colorClassToken, r as customColorStyle, t as CUSTOM_COLOR_CLASS } from "./color-CEYYtRX-.js";
|
|
5
|
+
import { html, isServer, nothing } from "lit";
|
|
6
|
+
import { property, state } from "lit/decorators.js";
|
|
7
|
+
|
|
8
|
+
//#region src/components/menu/menu-utils.ts
|
|
9
|
+
function isItem(node) {
|
|
10
|
+
return !node.type || node.type === "item";
|
|
11
|
+
}
|
|
12
|
+
function isGroup(node) {
|
|
13
|
+
return node.type === "group";
|
|
14
|
+
}
|
|
15
|
+
function isDivider(node) {
|
|
16
|
+
return node.type === "divider";
|
|
17
|
+
}
|
|
18
|
+
function isSubheader(node) {
|
|
19
|
+
return node.type === "subheader";
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Walk the tree and collect the chain (root → leaf) leading to the item with
|
|
23
|
+
* the given id. Returns an empty array if not found.
|
|
24
|
+
*/
|
|
25
|
+
function findActivePath(items, id) {
|
|
26
|
+
for (const node of items) {
|
|
27
|
+
if (node.id === id) return [node];
|
|
28
|
+
if (node.items?.length) {
|
|
29
|
+
const sub = findActivePath(node.items, id);
|
|
30
|
+
if (sub.length) return [node, ...sub];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
function findItem(items, id) {
|
|
36
|
+
for (const node of items) {
|
|
37
|
+
if (node.id === id) return node;
|
|
38
|
+
if (node.items?.length) {
|
|
39
|
+
const sub = findItem(node.items, id);
|
|
40
|
+
if (sub) return sub;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Generate a 1–2 character alias from a menu item's title for the icon
|
|
47
|
+
* fallback (used by `renderMenuIcon` when no `item.icon` and no slot icon are
|
|
48
|
+
* provided). Each space-delimited word contributes its first character; output
|
|
49
|
+
* is uppercased and capped at `max` characters.
|
|
50
|
+
*
|
|
51
|
+
* Examples:
|
|
52
|
+
* getMenuAlias('Dashboard') → 'D'
|
|
53
|
+
* getMenuAlias('Post Budget') → 'PB'
|
|
54
|
+
* getMenuAlias('Sales Order Report') → 'SO'
|
|
55
|
+
* getMenuAlias('logbook') → 'L'
|
|
56
|
+
* getMenuAlias('') → ''
|
|
57
|
+
*/
|
|
58
|
+
function getMenuAlias(input, max = 2) {
|
|
59
|
+
if (!input || typeof input !== "string") return "";
|
|
60
|
+
const words = input.trim().split(/\s+/).filter(Boolean);
|
|
61
|
+
if (!words.length) return "";
|
|
62
|
+
return words.slice(0, max).map((w) => w.charAt(0)).join("").toUpperCase();
|
|
63
|
+
}
|
|
64
|
+
function collectDefaultOpenGroups(items) {
|
|
65
|
+
const out = [];
|
|
66
|
+
const visit = (list) => {
|
|
67
|
+
for (const node of list) {
|
|
68
|
+
if (isGroup(node) && node.defaultOpen) out.push(node.id);
|
|
69
|
+
if (node.items?.length) visit(node.items);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
visit(items);
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
function generateMenuRootClasses(props) {
|
|
76
|
+
return [
|
|
77
|
+
"mono-menu",
|
|
78
|
+
props.density,
|
|
79
|
+
colorClassToken(props.color),
|
|
80
|
+
props.nav ? "nav" : "plain",
|
|
81
|
+
props.selectable ? "" : "not-selectable",
|
|
82
|
+
props.disabled ? "disabled" : "",
|
|
83
|
+
props.cssClassName ?? "",
|
|
84
|
+
props.rootExtra ?? ""
|
|
85
|
+
].filter(Boolean).join(" ");
|
|
86
|
+
}
|
|
87
|
+
function validateMenuProps(props) {
|
|
88
|
+
const errors = [];
|
|
89
|
+
if (props.density && ![
|
|
90
|
+
"compact",
|
|
91
|
+
"comfortable",
|
|
92
|
+
"default"
|
|
93
|
+
].includes(props.density)) errors.push(`Invalid density: ${String(props.density)}`);
|
|
94
|
+
const colorError = validateColorProp(props.color);
|
|
95
|
+
if (colorError) errors.push(colorError);
|
|
96
|
+
return errors;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The Basecoat styling attributes for the menu ROOT, mirroring the props one
|
|
100
|
+
* for one. A prop at its DEFAULT emits nothing — `:not([mono-density])` is
|
|
101
|
+
* comfortable and `:not([mono-color])` is primary — so the rendered DOM is
|
|
102
|
+
* also the shortest hand-written markup that paints the same (see menu.css).
|
|
103
|
+
* `nav` defaults to TRUE, so `mono-plain` is the attribute that says
|
|
104
|
+
* something. Shared so `<mono-menu>` and a standalone `<mono-menu-list>`
|
|
105
|
+
* cannot drift apart.
|
|
106
|
+
*/
|
|
107
|
+
function menuRootAttrs(props) {
|
|
108
|
+
return {
|
|
109
|
+
density: props.density === "comfortable" ? null : props.density,
|
|
110
|
+
color: isThemeColorToken(props.color) || props.color === "surface" ? props.color === "primary" ? null : props.color : CUSTOM_COLOR_CLASS
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region src/components/menu/menu-render.ts
|
|
116
|
+
function clsFor(base, key, cssClass) {
|
|
117
|
+
const extra = cssClass?.[key];
|
|
118
|
+
return extra ? `${base} ${extra}` : base;
|
|
119
|
+
}
|
|
120
|
+
function renderMenuIcon(item, ctx) {
|
|
121
|
+
const slotNodes = ctx.getSlotIconNodes(item.id);
|
|
122
|
+
if (!!(slotNodes && slotNodes.length)) return html`
|
|
123
|
+
<span
|
|
124
|
+
class=${clsFor("mono-menu-icon", "icon", ctx.cssClass)}
|
|
125
|
+
mono-icon
|
|
126
|
+
aria-hidden="true"
|
|
127
|
+
>
|
|
128
|
+
<span data-mono-slot=${`icon-${item.id}`}></span>
|
|
129
|
+
</span>
|
|
130
|
+
`;
|
|
131
|
+
if (ctx.iconSlot && item.icon && isIconifyClass(item.icon)) return html`
|
|
132
|
+
<span
|
|
133
|
+
class=${clsFor("mono-menu-icon", "icon", ctx.cssClass)}
|
|
134
|
+
mono-icon
|
|
135
|
+
aria-hidden="true"
|
|
136
|
+
>
|
|
137
|
+
<slot name=${`icon-${item.id}`}></slot>
|
|
138
|
+
</span>
|
|
139
|
+
`;
|
|
140
|
+
if (item.icon && isIconifyClass(item.icon)) return html`
|
|
141
|
+
<span
|
|
142
|
+
class=${clsFor("mono-menu-icon", "icon", ctx.cssClass)}
|
|
143
|
+
mono-icon
|
|
144
|
+
aria-hidden="true"
|
|
145
|
+
>
|
|
146
|
+
<span class=${`mono-menu-iconify ${item.icon}`} mono-glyph></span>
|
|
147
|
+
</span>
|
|
148
|
+
`;
|
|
149
|
+
if (item.icon) return html`
|
|
150
|
+
<span
|
|
151
|
+
class=${clsFor("mono-menu-icon", "icon", ctx.cssClass)}
|
|
152
|
+
mono-icon
|
|
153
|
+
aria-hidden="true"
|
|
154
|
+
>
|
|
155
|
+
${item.icon}
|
|
156
|
+
</span>
|
|
157
|
+
`;
|
|
158
|
+
const alias = getMenuAlias(item.title || item.id);
|
|
159
|
+
if (alias) return html`
|
|
160
|
+
<span
|
|
161
|
+
class=${`${clsFor("mono-menu-icon", "icon", ctx.cssClass)} alias`}
|
|
162
|
+
mono-icon
|
|
163
|
+
mono-alias
|
|
164
|
+
aria-hidden="true"
|
|
165
|
+
data-mono-alias=${alias}
|
|
166
|
+
>
|
|
167
|
+
${alias}
|
|
168
|
+
</span>
|
|
169
|
+
`;
|
|
170
|
+
return nothing;
|
|
171
|
+
}
|
|
172
|
+
function renderMenuBadge(item, ctx) {
|
|
173
|
+
if (item.badge === void 0 || item.badge === null || item.badge === "") return nothing;
|
|
174
|
+
const colorClass = item.badgeColor && item.badgeColor !== "default" ? item.badgeColor : "";
|
|
175
|
+
return html`
|
|
176
|
+
<span
|
|
177
|
+
class=${`${clsFor("mono-menu-badge", "badge", ctx.cssClass)} ${colorClass}`.trim()}
|
|
178
|
+
mono-badge=${colorClass}
|
|
179
|
+
>
|
|
180
|
+
${item.badge}
|
|
181
|
+
</span>
|
|
182
|
+
`;
|
|
183
|
+
}
|
|
184
|
+
function renderMenuAppend(item, ctx) {
|
|
185
|
+
if (item.badge !== void 0 && item.badge !== null && item.badge !== "") return renderMenuBadge(item, ctx);
|
|
186
|
+
if (!item.appendIcon) return nothing;
|
|
187
|
+
return html`
|
|
188
|
+
<span
|
|
189
|
+
class=${clsFor("mono-menu-append", "appendIcon", ctx.cssClass)}
|
|
190
|
+
mono-append
|
|
191
|
+
aria-hidden="true"
|
|
192
|
+
>
|
|
193
|
+
${item.appendIcon}
|
|
194
|
+
</span>
|
|
195
|
+
`;
|
|
196
|
+
}
|
|
197
|
+
function renderMenuItemRow(item, ctx) {
|
|
198
|
+
const active = ctx.isSelected(item.id);
|
|
199
|
+
const itemClasses = [
|
|
200
|
+
clsFor("mono-menu-item", "item", ctx.cssClass),
|
|
201
|
+
active ? "active" : "",
|
|
202
|
+
active && ctx.cssClass?.itemActive ? ctx.cssClass.itemActive : "",
|
|
203
|
+
item.disabled ? "disabled" : "",
|
|
204
|
+
item.disabled && ctx.cssClass?.itemDisabled ? ctx.cssClass.itemDisabled : ""
|
|
205
|
+
].filter(Boolean).join(" ");
|
|
206
|
+
const tag = item.href ? "a" : "button";
|
|
207
|
+
const actionInner = html`
|
|
208
|
+
${renderMenuIcon(item, ctx)}
|
|
209
|
+
<span class=${clsFor("mono-menu-content", "content", ctx.cssClass)} mono-content>
|
|
210
|
+
<span class=${clsFor("mono-menu-title", "title", ctx.cssClass)} mono-title>
|
|
211
|
+
${item.title ?? item.id}
|
|
212
|
+
</span>
|
|
213
|
+
${item.subtitle ? html`<span
|
|
214
|
+
class=${clsFor("mono-menu-subtitle", "subtitle", ctx.cssClass)}
|
|
215
|
+
mono-subtitle
|
|
216
|
+
>${item.subtitle}</span
|
|
217
|
+
>` : nothing}
|
|
218
|
+
</span>
|
|
219
|
+
${renderMenuAppend(item, ctx)}
|
|
220
|
+
`;
|
|
221
|
+
return html`
|
|
222
|
+
<li class=${itemClasses} mono-item ?mono-active=${active} ?mono-disabled=${!!item.disabled}>
|
|
223
|
+
${tag === "a" ? html`
|
|
224
|
+
<a
|
|
225
|
+
class=${clsFor("mono-menu-action", "action", ctx.cssClass)}
|
|
226
|
+
mono-action
|
|
227
|
+
href=${item.href}
|
|
228
|
+
role=${ctx.selectable ? "option" : "link"}
|
|
229
|
+
aria-current=${active ? "page" : "false"}
|
|
230
|
+
aria-disabled=${item.disabled ? "true" : "false"}
|
|
231
|
+
@click=${(e) => ctx.onItemClick(item, e)}
|
|
232
|
+
>
|
|
233
|
+
${actionInner}
|
|
234
|
+
</a>
|
|
235
|
+
` : html`
|
|
236
|
+
<button
|
|
237
|
+
type="button"
|
|
238
|
+
class=${clsFor("mono-menu-action", "action", ctx.cssClass)}
|
|
239
|
+
mono-action
|
|
240
|
+
role=${ctx.selectable ? "option" : "menuitem"}
|
|
241
|
+
aria-selected=${ctx.selectable ? active ? "true" : "false" : nothing}
|
|
242
|
+
aria-disabled=${item.disabled ? "true" : "false"}
|
|
243
|
+
?disabled=${item.disabled || ctx.disabled}
|
|
244
|
+
@click=${(e) => ctx.onItemClick(item, e)}
|
|
245
|
+
>
|
|
246
|
+
${actionInner}
|
|
247
|
+
</button>
|
|
248
|
+
`}
|
|
249
|
+
${ctx.bodySlot && !isGroup(item) ? html`<ul
|
|
250
|
+
class=${clsFor("mono-menu-list", "list", ctx.cssClass)}
|
|
251
|
+
mono-list
|
|
252
|
+
data-mono-slot="body"
|
|
253
|
+
></ul>` : item.items?.length && !isGroup(item) ? html`<ul class=${clsFor("mono-menu-list", "list", ctx.cssClass)} mono-list>
|
|
254
|
+
${renderMenuList(item.items, ctx)}
|
|
255
|
+
</ul>` : nothing}
|
|
256
|
+
</li>
|
|
257
|
+
`;
|
|
258
|
+
}
|
|
259
|
+
function renderMenuGroup(group, ctx) {
|
|
260
|
+
const open = ctx.isGroupOpen(group.id);
|
|
261
|
+
const ancestorActive = ctx.isGroupActive?.(group) ?? false;
|
|
262
|
+
const groupClasses = [clsFor("mono-menu-group", "group", ctx.cssClass), ancestorActive ? "active" : ""].filter(Boolean).join(" ");
|
|
263
|
+
return html`
|
|
264
|
+
<li
|
|
265
|
+
class=${groupClasses}
|
|
266
|
+
mono-item
|
|
267
|
+
mono-group
|
|
268
|
+
?mono-open=${open}
|
|
269
|
+
?mono-active=${ancestorActive}
|
|
270
|
+
?mono-disabled=${!!group.disabled}
|
|
271
|
+
data-open=${open ? "true" : "false"}
|
|
272
|
+
>
|
|
273
|
+
<button
|
|
274
|
+
type="button"
|
|
275
|
+
class=${clsFor("mono-menu-group-header", "groupHeader", ctx.cssClass)}
|
|
276
|
+
mono-group-header
|
|
277
|
+
aria-expanded=${open ? "true" : "false"}
|
|
278
|
+
?disabled=${group.disabled || ctx.disabled}
|
|
279
|
+
@click=${(e) => ctx.onGroupToggle(group, e)}
|
|
280
|
+
>
|
|
281
|
+
${renderMenuIcon(group, ctx)}
|
|
282
|
+
<span class=${clsFor("mono-menu-content", "content", ctx.cssClass)} mono-content>
|
|
283
|
+
<span class=${clsFor("mono-menu-title", "title", ctx.cssClass)} mono-title>
|
|
284
|
+
${group.title ?? group.id}
|
|
285
|
+
</span>
|
|
286
|
+
${group.subtitle ? html`<span
|
|
287
|
+
class=${clsFor("mono-menu-subtitle", "subtitle", ctx.cssClass)}
|
|
288
|
+
mono-subtitle
|
|
289
|
+
>${group.subtitle}</span
|
|
290
|
+
>` : nothing}
|
|
291
|
+
</span>
|
|
292
|
+
<span
|
|
293
|
+
class=${clsFor("mono-menu-chevron", "groupChevron", ctx.cssClass)}
|
|
294
|
+
mono-chevron
|
|
295
|
+
aria-hidden="true"
|
|
296
|
+
>
|
|
297
|
+
${ctx.chevronSvg ?? html`<span class="mono-icon i-mdi-chevron-right" aria-hidden="true"></span>`}
|
|
298
|
+
</span>
|
|
299
|
+
</button>
|
|
300
|
+
${ctx.bodySlot ? html`<ul
|
|
301
|
+
class=${clsFor("mono-menu-list", "groupBody", ctx.cssClass)}
|
|
302
|
+
mono-list
|
|
303
|
+
mono-group-body
|
|
304
|
+
data-mono-slot="body"
|
|
305
|
+
></ul>` : group.items?.length ? html`<ul
|
|
306
|
+
class=${clsFor("mono-menu-list", "groupBody", ctx.cssClass)}
|
|
307
|
+
mono-list
|
|
308
|
+
mono-group-body
|
|
309
|
+
>
|
|
310
|
+
${renderMenuList(group.items, ctx)}
|
|
311
|
+
</ul>` : nothing}
|
|
312
|
+
</li>
|
|
313
|
+
`;
|
|
314
|
+
}
|
|
315
|
+
function renderMenuDivider(item, ctx) {
|
|
316
|
+
return html`<li
|
|
317
|
+
class=${clsFor("mono-menu-divider", "divider", ctx.cssClass)}
|
|
318
|
+
mono-divider
|
|
319
|
+
role="separator"
|
|
320
|
+
data-id=${item.id}
|
|
321
|
+
></li>`;
|
|
322
|
+
}
|
|
323
|
+
function renderMenuSubheader(item, ctx) {
|
|
324
|
+
return html`<li
|
|
325
|
+
class=${clsFor("mono-menu-subheader", "subheader", ctx.cssClass)}
|
|
326
|
+
mono-subheader
|
|
327
|
+
data-id=${item.id}
|
|
328
|
+
>
|
|
329
|
+
${item.title ?? ""}
|
|
330
|
+
</li>`;
|
|
331
|
+
}
|
|
332
|
+
function renderMenuList(list, ctx) {
|
|
333
|
+
return list.map((item) => {
|
|
334
|
+
if (isDivider(item)) return renderMenuDivider(item, ctx);
|
|
335
|
+
if (isSubheader(item)) return renderMenuSubheader(item, ctx);
|
|
336
|
+
if (isGroup(item)) return renderMenuGroup(item, ctx);
|
|
337
|
+
return renderMenuItemRow(item, ctx);
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Render only the group rows from `list` — non-group items are skipped.
|
|
342
|
+
* Used by `<mono-menu-list type="group">`.
|
|
343
|
+
*/
|
|
344
|
+
function renderMenuGroupsOnly(list, ctx) {
|
|
345
|
+
const out = [];
|
|
346
|
+
for (const item of list) if (isGroup(item)) out.push(renderMenuGroup(item, ctx));
|
|
347
|
+
return out;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
//#endregion
|
|
351
|
+
//#region src/components/menu/menu-core.ts
|
|
352
|
+
/** Coerce any `items` input (array, JSON string, or other) to a MenuItem array. */
|
|
353
|
+
function coerceItems(value) {
|
|
354
|
+
if (Array.isArray(value)) return value;
|
|
355
|
+
if (typeof value === "string") {
|
|
356
|
+
if (!value) return [];
|
|
357
|
+
try {
|
|
358
|
+
const parsed = JSON.parse(value);
|
|
359
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
360
|
+
} catch {
|
|
361
|
+
return [];
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return [];
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* `MonoMenuCore` — all render-mode-agnostic logic for `mono-menu`: reactive
|
|
368
|
+
* props, hybrid aliases, css-class interop, selection + open-group state,
|
|
369
|
+
* default-open seeding, the click/toggle/change events, the full public API, and
|
|
370
|
+
* the chrome `render()` (which delegates the body to a `_renderBody()` hook).
|
|
371
|
+
*
|
|
372
|
+
* Leaves to each build: `createRenderRoot()`, the body strategy (light: slot
|
|
373
|
+
* capture / declarative `slot="body"`; shadow: items-driven only), and
|
|
374
|
+
* `_chevronSvg()` (light: undefined → UnoCSS icon span; shadow: inline SVG).
|
|
375
|
+
*/
|
|
376
|
+
const MonoMenuCore = (superClass) => {
|
|
377
|
+
class MonoMenuCoreClass extends superClass {
|
|
378
|
+
constructor(...args) {
|
|
379
|
+
super(...args);
|
|
380
|
+
this.items = [];
|
|
381
|
+
this.modelValue = "";
|
|
382
|
+
this.multiple = false;
|
|
383
|
+
this.density = "comfortable";
|
|
384
|
+
this.color = "primary";
|
|
385
|
+
this.nav = true;
|
|
386
|
+
this.selectable = true;
|
|
387
|
+
this.disabled = false;
|
|
388
|
+
this.controlled = false;
|
|
389
|
+
this.cssClass = {};
|
|
390
|
+
this.cssClassName = "";
|
|
391
|
+
this._openGroups = /* @__PURE__ */ new Set();
|
|
392
|
+
this._seededGroups = /* @__PURE__ */ new Set();
|
|
393
|
+
this._slotIcons = /* @__PURE__ */ new Map();
|
|
394
|
+
this._listChildren = /* @__PURE__ */ new Set();
|
|
395
|
+
this._railSidebar = null;
|
|
396
|
+
this._railObserver = null;
|
|
397
|
+
this._railRetryRaf = null;
|
|
398
|
+
this._railRetryTimer = null;
|
|
399
|
+
defineHybridPropAliases(this, ["modelValue", "cssClass"]);
|
|
400
|
+
Object.defineProperty(this, "css-class", {
|
|
401
|
+
get: () => this.cssClass,
|
|
402
|
+
set: (value) => this._setCssClass(value),
|
|
403
|
+
configurable: true,
|
|
404
|
+
enumerable: false
|
|
405
|
+
});
|
|
406
|
+
Object.defineProperty(this, "cssclass", {
|
|
407
|
+
get: () => this.cssClass,
|
|
408
|
+
set: (value) => this._setCssClass(value),
|
|
409
|
+
configurable: true,
|
|
410
|
+
enumerable: false
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
static get observedAttributes() {
|
|
414
|
+
return [
|
|
415
|
+
...super.observedAttributes ?? [],
|
|
416
|
+
"modelvalue",
|
|
417
|
+
"css-class",
|
|
418
|
+
"cssclass"
|
|
419
|
+
];
|
|
420
|
+
}
|
|
421
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
422
|
+
super.attributeChangedCallback(name, oldValue, newValue);
|
|
423
|
+
if (oldValue === newValue) return;
|
|
424
|
+
if (name === "modelvalue") {
|
|
425
|
+
this.modelValue = newValue ?? "";
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (name === "css-class" || name === "cssclass") this._setCssClass(newValue);
|
|
429
|
+
}
|
|
430
|
+
connectedCallback() {
|
|
431
|
+
super.connectedCallback();
|
|
432
|
+
if (isServer) return;
|
|
433
|
+
this._setupRailSync();
|
|
434
|
+
}
|
|
435
|
+
disconnectedCallback() {
|
|
436
|
+
if (!isServer) this._teardownRailSync();
|
|
437
|
+
super.disconnectedCallback();
|
|
438
|
+
}
|
|
439
|
+
willUpdate(changed) {
|
|
440
|
+
if (typeof this.items === "string") this.items = coerceItems(this.items);
|
|
441
|
+
super.willUpdate?.(changed);
|
|
442
|
+
if (changed.has("items")) this._seedDefaultOpenGroups();
|
|
443
|
+
}
|
|
444
|
+
_seedDefaultOpenGroups() {
|
|
445
|
+
const existing = new Set(this._openGroups);
|
|
446
|
+
let changed = false;
|
|
447
|
+
for (const id of collectDefaultOpenGroups(this.items)) {
|
|
448
|
+
if (this._seededGroups.has(id)) continue;
|
|
449
|
+
this._seededGroups.add(id);
|
|
450
|
+
if (!existing.has(id)) {
|
|
451
|
+
existing.add(id);
|
|
452
|
+
changed = true;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
if (!changed) return;
|
|
456
|
+
this._openGroups = existing;
|
|
457
|
+
}
|
|
458
|
+
_setCssClass(value) {
|
|
459
|
+
if (value == null) {
|
|
460
|
+
this.cssClass = {};
|
|
461
|
+
this.cssClassName = "";
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
if (typeof value === "object") {
|
|
465
|
+
this.cssClass = value;
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
if (typeof value === "string") {
|
|
469
|
+
const trimmed = value.trim();
|
|
470
|
+
if (!trimmed) {
|
|
471
|
+
this.cssClass = {};
|
|
472
|
+
this.cssClassName = "";
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}")) try {
|
|
476
|
+
this.cssClass = JSON.parse(trimmed);
|
|
477
|
+
return;
|
|
478
|
+
} catch {}
|
|
479
|
+
this.cssClassName = trimmed;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
_cls(base, key) {
|
|
483
|
+
const extra = this.cssClass?.[key];
|
|
484
|
+
return extra ? `${base} ${extra}` : base;
|
|
485
|
+
}
|
|
486
|
+
get _rootClasses() {
|
|
487
|
+
return generateMenuRootClasses({
|
|
488
|
+
density: this.density,
|
|
489
|
+
color: this.color,
|
|
490
|
+
nav: this.nav,
|
|
491
|
+
selectable: this.selectable,
|
|
492
|
+
disabled: this.disabled,
|
|
493
|
+
cssClassName: this.cssClassName,
|
|
494
|
+
rootExtra: this.cssClass?.root
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
_isSelected(id) {
|
|
498
|
+
if (this.multiple) return Array.isArray(this.modelValue) && this.modelValue.includes(id);
|
|
499
|
+
return !this.multiple && this.modelValue === id;
|
|
500
|
+
}
|
|
501
|
+
_isGroupOpen(id) {
|
|
502
|
+
return this._openGroups.has(id);
|
|
503
|
+
}
|
|
504
|
+
/** A group is "active" when the currently-selected item is a descendant. */
|
|
505
|
+
_isGroupActive(group) {
|
|
506
|
+
const selected = this.multiple ? Array.isArray(this.modelValue) ? this.modelValue : [] : [this.modelValue];
|
|
507
|
+
const ids = new Set(selected.filter(Boolean));
|
|
508
|
+
if (!ids.size) return false;
|
|
509
|
+
const contains = (node) => !!node.items?.some((child) => ids.has(child.id) || contains(child));
|
|
510
|
+
return contains(group);
|
|
511
|
+
}
|
|
512
|
+
_findRegisteredItem(id) {
|
|
513
|
+
for (const child of this._listChildren) {
|
|
514
|
+
const items = child.getMenuItems?.() ?? [];
|
|
515
|
+
const found = findItem(items, id);
|
|
516
|
+
if (found) return found;
|
|
517
|
+
}
|
|
518
|
+
return null;
|
|
519
|
+
}
|
|
520
|
+
_findAnyItem(id) {
|
|
521
|
+
return findItem(this.items, id) ?? this._findRegisteredItem(id);
|
|
522
|
+
}
|
|
523
|
+
_getRegisteredActivePath(id) {
|
|
524
|
+
for (const child of this._listChildren) {
|
|
525
|
+
const items = child.getMenuItems?.() ?? [];
|
|
526
|
+
const path = findActivePath(items, id);
|
|
527
|
+
if (path.length) return path;
|
|
528
|
+
}
|
|
529
|
+
return [];
|
|
530
|
+
}
|
|
531
|
+
select(id) {
|
|
532
|
+
const item = this._findAnyItem(id);
|
|
533
|
+
if (!item || !isItem(item)) return;
|
|
534
|
+
this._handleItemActivation(item);
|
|
535
|
+
}
|
|
536
|
+
deselect(id) {
|
|
537
|
+
if (!this.multiple) {
|
|
538
|
+
if (this.modelValue === id) {
|
|
539
|
+
const oldValue = this.modelValue;
|
|
540
|
+
this.modelValue = "";
|
|
541
|
+
this._emitChange(id, this._findAnyItem(id) ?? { id }, false, oldValue);
|
|
542
|
+
}
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
if (Array.isArray(this.modelValue) && this.modelValue.includes(id)) {
|
|
546
|
+
const oldValue = [...this.modelValue];
|
|
547
|
+
this.modelValue = this.modelValue.filter((v) => v !== id);
|
|
548
|
+
this._emitChange(id, this._findAnyItem(id) ?? { id }, false, oldValue);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
toggleGroup(id) {
|
|
552
|
+
const item = this._findAnyItem(id);
|
|
553
|
+
if (!item || !isGroup(item)) return;
|
|
554
|
+
this._handleGroupToggle(item);
|
|
555
|
+
}
|
|
556
|
+
expandGroup(id) {
|
|
557
|
+
if (this._openGroups.has(id)) return;
|
|
558
|
+
const next = new Set(this._openGroups);
|
|
559
|
+
next.add(id);
|
|
560
|
+
this._openGroups = next;
|
|
561
|
+
}
|
|
562
|
+
collapseGroup(id) {
|
|
563
|
+
if (!this._openGroups.has(id)) return;
|
|
564
|
+
const next = new Set(this._openGroups);
|
|
565
|
+
next.delete(id);
|
|
566
|
+
this._openGroups = next;
|
|
567
|
+
}
|
|
568
|
+
focus() {
|
|
569
|
+
this.querySelector(".mono-menu-action, .mono-menu-group-header")?.focus();
|
|
570
|
+
}
|
|
571
|
+
getActivePath() {
|
|
572
|
+
const id = !this.multiple ? this.modelValue : Array.isArray(this.modelValue) && this.modelValue.length ? this.modelValue[this.modelValue.length - 1] : "";
|
|
573
|
+
if (!id) return [];
|
|
574
|
+
const ownPath = findActivePath(this.items, id);
|
|
575
|
+
if (ownPath.length) return ownPath;
|
|
576
|
+
return this._getRegisteredActivePath(id);
|
|
577
|
+
}
|
|
578
|
+
requestItemActivation(item, event) {
|
|
579
|
+
this._handleItemActivation(item, event);
|
|
580
|
+
}
|
|
581
|
+
requestGroupToggle(group, event) {
|
|
582
|
+
this._handleGroupToggle(group, event);
|
|
583
|
+
}
|
|
584
|
+
isItemSelected(id) {
|
|
585
|
+
return this._isSelected(id);
|
|
586
|
+
}
|
|
587
|
+
isGroupOpenPublic(id) {
|
|
588
|
+
return this._isGroupOpen(id);
|
|
589
|
+
}
|
|
590
|
+
getSlotIconNodes(id) {
|
|
591
|
+
return this._slotIcons.get(id);
|
|
592
|
+
}
|
|
593
|
+
/** @internal called by `<mono-menu-list>` from its connectedCallback. */
|
|
594
|
+
_registerListChild(child) {
|
|
595
|
+
this._listChildren.add(child);
|
|
596
|
+
}
|
|
597
|
+
/** @internal called by `<mono-menu-list>` from its disconnectedCallback. */
|
|
598
|
+
_unregisterListChild(child) {
|
|
599
|
+
this._listChildren.delete(child);
|
|
600
|
+
}
|
|
601
|
+
/** Walk up across slot + shadow boundaries to the host `<mono-sidebar>`, if any. */
|
|
602
|
+
_findAncestorSidebar() {
|
|
603
|
+
let node = this.assignedSlot ?? this.parentNode;
|
|
604
|
+
while (node) {
|
|
605
|
+
if (node instanceof Element && (node.localName === "mono-sidebar" || node.localName === "mono-shadow-sidebar")) return node;
|
|
606
|
+
node = node.assignedSlot ?? (node instanceof ShadowRoot ? node.host : node.parentNode);
|
|
607
|
+
}
|
|
608
|
+
return null;
|
|
609
|
+
}
|
|
610
|
+
_setupRailSync(retries = 30) {
|
|
611
|
+
if (this._railObserver) this._teardownRailSync();
|
|
612
|
+
const sidebar = this._findAncestorSidebar();
|
|
613
|
+
if (!sidebar) {
|
|
614
|
+
if (retries <= 0 || isServer) return;
|
|
615
|
+
let fired = false;
|
|
616
|
+
const retry = () => {
|
|
617
|
+
if (fired) return;
|
|
618
|
+
fired = true;
|
|
619
|
+
this._railRetryRaf = null;
|
|
620
|
+
this._railRetryTimer = null;
|
|
621
|
+
if (this.isConnected) this._setupRailSync(retries - 1);
|
|
622
|
+
};
|
|
623
|
+
this._cancelRailRetry();
|
|
624
|
+
if (typeof requestAnimationFrame !== "undefined") this._railRetryRaf = requestAnimationFrame(retry);
|
|
625
|
+
this._railRetryTimer = setTimeout(retry, 32);
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
this._railSidebar = sidebar;
|
|
629
|
+
this._applyRailCollapsed(sidebar.hasAttribute("data-rail-collapsed"));
|
|
630
|
+
this._railObserver = new MutationObserver(() => {
|
|
631
|
+
this._applyRailCollapsed(sidebar.hasAttribute("data-rail-collapsed"));
|
|
632
|
+
});
|
|
633
|
+
this._railObserver.observe(sidebar, {
|
|
634
|
+
attributes: true,
|
|
635
|
+
attributeFilter: ["data-rail-collapsed"]
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
_cancelRailRetry() {
|
|
639
|
+
if (this._railRetryRaf !== null && typeof cancelAnimationFrame !== "undefined") cancelAnimationFrame(this._railRetryRaf);
|
|
640
|
+
if (this._railRetryTimer !== null) clearTimeout(this._railRetryTimer);
|
|
641
|
+
this._railRetryRaf = null;
|
|
642
|
+
this._railRetryTimer = null;
|
|
643
|
+
}
|
|
644
|
+
_teardownRailSync() {
|
|
645
|
+
this._cancelRailRetry();
|
|
646
|
+
this._railObserver?.disconnect();
|
|
647
|
+
this._railObserver = null;
|
|
648
|
+
this._railSidebar = null;
|
|
649
|
+
}
|
|
650
|
+
static {
|
|
651
|
+
this._RAIL_COLLAPSE_VARS = [
|
|
652
|
+
["--mono-menu-label-display", "none"],
|
|
653
|
+
["--mono-menu-row-display", "flex"],
|
|
654
|
+
["--mono-menu-row-justify", "center"],
|
|
655
|
+
["--mono-menu-action-width", "auto"],
|
|
656
|
+
["--mono-menu-action-justify", "center"],
|
|
657
|
+
["--mono-menu-action-gap", "0"],
|
|
658
|
+
["--mono-menu-group-children-display", "none"]
|
|
659
|
+
];
|
|
660
|
+
}
|
|
661
|
+
_applyRailCollapsed(collapsed) {
|
|
662
|
+
this.toggleAttribute("rail-collapsed", collapsed);
|
|
663
|
+
const vars = MonoMenuCoreClass._RAIL_COLLAPSE_VARS;
|
|
664
|
+
if (collapsed) for (const [name, value] of vars) this.style.setProperty(name, value);
|
|
665
|
+
else for (const [name] of vars) this.style.removeProperty(name);
|
|
666
|
+
}
|
|
667
|
+
_handleItemActivation(item, event) {
|
|
668
|
+
if (item.disabled || this.disabled) return;
|
|
669
|
+
dispatchMonoEvent(this, "click", {
|
|
670
|
+
value: item.id,
|
|
671
|
+
item,
|
|
672
|
+
sourceEvent: event
|
|
673
|
+
});
|
|
674
|
+
if (this.controlled) return;
|
|
675
|
+
if (!this.selectable) return;
|
|
676
|
+
if (this.multiple) {
|
|
677
|
+
const oldArr = Array.isArray(this.modelValue) ? [...this.modelValue] : [];
|
|
678
|
+
let nextArr;
|
|
679
|
+
let selected;
|
|
680
|
+
if (oldArr.includes(item.id)) {
|
|
681
|
+
nextArr = oldArr.filter((v) => v !== item.id);
|
|
682
|
+
selected = false;
|
|
683
|
+
} else {
|
|
684
|
+
nextArr = [...oldArr, item.id];
|
|
685
|
+
selected = true;
|
|
686
|
+
}
|
|
687
|
+
this.modelValue = nextArr;
|
|
688
|
+
this._emitChange(item.id, item, selected, oldArr, event);
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
const oldValue = this.modelValue;
|
|
692
|
+
if (oldValue === item.id) return;
|
|
693
|
+
this.modelValue = item.id;
|
|
694
|
+
this._emitChange(item.id, item, true, oldValue, event);
|
|
695
|
+
}
|
|
696
|
+
_emitChange(value, item, selected, oldValue, event) {
|
|
697
|
+
const detail = {
|
|
698
|
+
modelValue: this.modelValue,
|
|
699
|
+
oldValue,
|
|
700
|
+
value,
|
|
701
|
+
item,
|
|
702
|
+
selected,
|
|
703
|
+
sourceEvent: event
|
|
704
|
+
};
|
|
705
|
+
dispatchMonoEvent(this, "change", detail);
|
|
706
|
+
}
|
|
707
|
+
_handleGroupToggle(group, event) {
|
|
708
|
+
if (group.disabled || this.disabled) return;
|
|
709
|
+
const oldOpen = this._openGroups.has(group.id);
|
|
710
|
+
const next = new Set(this._openGroups);
|
|
711
|
+
if (oldOpen) next.delete(group.id);
|
|
712
|
+
else next.add(group.id);
|
|
713
|
+
this._openGroups = next;
|
|
714
|
+
const detail = {
|
|
715
|
+
groupId: group.id,
|
|
716
|
+
open: !oldOpen,
|
|
717
|
+
oldOpen,
|
|
718
|
+
group,
|
|
719
|
+
sourceEvent: event
|
|
720
|
+
};
|
|
721
|
+
dispatchMonoEvent(this, "toggle-group", detail);
|
|
722
|
+
}
|
|
723
|
+
/** Inline chevron — light: undefined (UnoCSS span); shadow: inline SVG. */
|
|
724
|
+
_chevronSvg() {}
|
|
725
|
+
/** Whether to project icons via native `<slot>` — light: false; shadow: true. */
|
|
726
|
+
_useIconSlots() {
|
|
727
|
+
return false;
|
|
728
|
+
}
|
|
729
|
+
_renderContext() {
|
|
730
|
+
return {
|
|
731
|
+
multiple: this.multiple,
|
|
732
|
+
selectable: this.selectable,
|
|
733
|
+
disabled: this.disabled,
|
|
734
|
+
cssClass: this.cssClass,
|
|
735
|
+
chevronSvg: this._chevronSvg(),
|
|
736
|
+
iconSlot: this._useIconSlots(),
|
|
737
|
+
isSelected: (id) => this._isSelected(id),
|
|
738
|
+
isGroupOpen: (id) => this._isGroupOpen(id),
|
|
739
|
+
isGroupActive: (group) => this._isGroupActive(group),
|
|
740
|
+
getSlotIconNodes: (id) => this._slotIcons.get(id),
|
|
741
|
+
onItemClick: (item, e) => this._handleItemActivation(item, e),
|
|
742
|
+
onGroupToggle: (group, e) => this._handleGroupToggle(group, e)
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
/** Default body — items-driven. Light overrides to add the slot="body" path. */
|
|
746
|
+
_renderBody() {
|
|
747
|
+
return html`
|
|
748
|
+
<ul
|
|
749
|
+
class=${this._cls("mono-menu-list", "list")}
|
|
750
|
+
mono-list
|
|
751
|
+
role=${this.selectable ? "listbox" : "menu"}
|
|
752
|
+
>
|
|
753
|
+
${renderMenuList(this.items, this._renderContext())}
|
|
754
|
+
</ul>
|
|
755
|
+
`;
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
|
|
759
|
+
* Carries a literal `color` (`#7c3aed`, `rgb(…)`) that no stylesheet can know about.
|
|
760
|
+
* Empty for a palette slot, which resolves entirely through the `.mono-menu.<token>`
|
|
761
|
+
* rules instead.
|
|
762
|
+
*
|
|
763
|
+
* Must land on the ROOT element, not the host: a class-based `-preset` declared on
|
|
764
|
+
* the root beats an inherited one, so a host-level write would silently lose. If a
|
|
765
|
+
* `_syncRootFromState`-style attribute re-assert is ever added here (sidebar has one),
|
|
766
|
+
* it has to serialize from THIS getter or it will wipe the colour.
|
|
767
|
+
*/
|
|
768
|
+
get _inlineRootStyle() {
|
|
769
|
+
const raw = isThemeColorToken(this.color) || this.color === "surface" ? "" : this.color;
|
|
770
|
+
return customColorStyle(raw, "menu");
|
|
771
|
+
}
|
|
772
|
+
render() {
|
|
773
|
+
const attrs = menuRootAttrs(this);
|
|
774
|
+
return html`
|
|
775
|
+
<nav
|
|
776
|
+
class=${this._rootClasses}
|
|
777
|
+
style=${this._inlineRootStyle}
|
|
778
|
+
role="navigation"
|
|
779
|
+
mono-menu
|
|
780
|
+
mono-density=${attrs.density ?? nothing}
|
|
781
|
+
mono-color=${attrs.color ?? nothing}
|
|
782
|
+
?mono-plain=${!this.nav}
|
|
783
|
+
?mono-disabled=${this.disabled}
|
|
784
|
+
>
|
|
785
|
+
${this._renderBody()}
|
|
786
|
+
</nav>
|
|
787
|
+
`;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
__decorate([property({
|
|
791
|
+
attribute: "items",
|
|
792
|
+
converter: {
|
|
793
|
+
fromAttribute: (value) => coerceItems(value),
|
|
794
|
+
toAttribute: () => null
|
|
795
|
+
},
|
|
796
|
+
hasChanged: arrayHasChanged
|
|
797
|
+
})], MonoMenuCoreClass.prototype, "items", void 0);
|
|
798
|
+
__decorate([property({
|
|
799
|
+
attribute: "model-value",
|
|
800
|
+
reflect: true
|
|
801
|
+
})], MonoMenuCoreClass.prototype, "modelValue", void 0);
|
|
802
|
+
__decorate([property({
|
|
803
|
+
reflect: true,
|
|
804
|
+
converter: booleanStringConverter
|
|
805
|
+
})], MonoMenuCoreClass.prototype, "multiple", void 0);
|
|
806
|
+
__decorate([property({ type: String })], MonoMenuCoreClass.prototype, "density", void 0);
|
|
807
|
+
__decorate([property({ type: String })], MonoMenuCoreClass.prototype, "color", void 0);
|
|
808
|
+
__decorate([property({
|
|
809
|
+
reflect: true,
|
|
810
|
+
converter: booleanStringConverter
|
|
811
|
+
})], MonoMenuCoreClass.prototype, "nav", void 0);
|
|
812
|
+
__decorate([property({
|
|
813
|
+
reflect: true,
|
|
814
|
+
converter: booleanStringConverter
|
|
815
|
+
})], MonoMenuCoreClass.prototype, "selectable", void 0);
|
|
816
|
+
__decorate([property({
|
|
817
|
+
reflect: true,
|
|
818
|
+
converter: booleanStringConverter
|
|
819
|
+
})], MonoMenuCoreClass.prototype, "disabled", void 0);
|
|
820
|
+
__decorate([property({
|
|
821
|
+
reflect: true,
|
|
822
|
+
converter: booleanStringConverter
|
|
823
|
+
})], MonoMenuCoreClass.prototype, "controlled", void 0);
|
|
824
|
+
__decorate([property({ attribute: false })], MonoMenuCoreClass.prototype, "cssClass", void 0);
|
|
825
|
+
__decorate([property({ attribute: false })], MonoMenuCoreClass.prototype, "cssClassName", void 0);
|
|
826
|
+
__decorate([state()], MonoMenuCoreClass.prototype, "_openGroups", void 0);
|
|
827
|
+
return MonoMenuCoreClass;
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
//#endregion
|
|
831
|
+
export { isGroup as _, renderMenuGroup as a, validateMenuProps as b, renderMenuItemRow as c, collectDefaultOpenGroups as d, findActivePath as f, isDivider as g, getMenuAlias as h, renderMenuDivider as i, renderMenuList as l, generateMenuRootClasses as m, renderMenuAppend as n, renderMenuGroupsOnly as o, findItem as p, renderMenuBadge as r, renderMenuIcon as s, MonoMenuCore as t, renderMenuSubheader as u, isItem as v, isSubheader as y };
|