@mono-lit/helper 0.0.9 → 0.1.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.
Files changed (164) hide show
  1. package/dist/accordion-core-DaNyPWRr.js +277 -0
  2. package/dist/alert-core-DWtHbX_-.js +134 -0
  3. package/dist/breadcrumb-list-core-Dh68T8Cf.js +747 -0
  4. package/dist/{mono-button-CLkHg3WW.js → button-core-DerXg84Q.js} +3 -276
  5. package/dist/button-dropdown-core-DKYEOyjy.js +654 -0
  6. package/dist/button-utils-D5-66M02.js +63 -0
  7. package/dist/card-utils-l80qAmrN.js +312 -0
  8. package/dist/chart-core-DV7hD3ZY.js +801 -0
  9. package/dist/checkbox-utils-DKdrhAzF.js +337 -0
  10. package/dist/chip-utils-DpRrd7Zj.js +403 -0
  11. package/dist/{data-source-controller-C6C4ej_M.js → data-source-controller-DS_JLrmS.js} +1 -1
  12. package/dist/{data-source-options-fxT5QIX4.js → data-source-options-DJUNU26C.js} +6 -6
  13. package/dist/{data-source-read-BL266IW0.js → data-source-read-uKJpRAzx.js} +2 -2
  14. package/dist/date-core-CyuSyvvG.js +734 -0
  15. package/dist/drawer-core-DbFWvNln.js +759 -0
  16. package/dist/dropdown-core-BCH1pK14.js +511 -0
  17. package/dist/dropdown-table-core-SfHUJVFq.js +1342 -0
  18. package/dist/export.js +1 -1
  19. package/dist/{field-path-BabiMrrA.js → field-path-DK2VBWHl.js} +1 -1
  20. package/dist/field-tooltip.css_raw-DVblekCl.js +5 -0
  21. package/dist/{field-validation.css_raw-Cx6SGrfP.js → field-validation.css_raw-BU7C6173.js} +1 -170
  22. package/dist/file-upload-core-Cz_dBQMx.js +624 -0
  23. package/dist/filter-builder-core-DyWjbBP7.js +381 -0
  24. package/dist/{filter-builder-B6Y2mmbM.js → filter-builder-vbqIuPhX.js} +1 -1
  25. package/dist/{filter-eval-ChDSaAUH.js → filter-eval-CqeBnMYh.js} +1 -1
  26. package/dist/{filter-odata-Bi27XUpQ.js → filter-odata-GsczYKNC.js} +1 -1
  27. package/dist/{hydration-flush-BaE9gN3C.js → hydration-flush-Volt9X7Q.js} +2 -1071
  28. package/dist/index.js +11 -11
  29. package/dist/{index.node-DTqDBca7.js → index.node-Csy9zrr1.js} +4 -4
  30. package/dist/index.node.js +11 -11
  31. package/dist/input-utils-BglY-k0H.js +1145 -0
  32. package/dist/menu-core-DkAYuCZ2.js +831 -0
  33. package/dist/modal-core-CSBSPN_m.js +844 -0
  34. package/dist/mono-button-DVvZ03P-.js +280 -0
  35. package/dist/{mono-button.shadow-DqZMpcqY.js → mono-button.shadow-BANxMGln.js} +6 -594
  36. package/dist/{mono-data-chart-NKPdAgVq.js → mono-data-chart-ChF4J9RT.js} +6 -6
  37. package/dist/{mono-data-dropdown-B2iRpJuI.js → mono-data-dropdown-Bgj2PDfm.js} +1 -1
  38. package/dist/{mono-data-grid-llJCX9MC.js → mono-data-grid-DJkp96N-.js} +144 -46
  39. package/dist/{mono-event-BPku9HpS.js → mono-event-CAZf0F_k.js} +14 -9
  40. package/dist/{mono-form-controller-BrA10erm.js → mono-form-controller-DxZLvyg6.js} +2 -1
  41. package/dist/mono-table-checkbox-core-BKOMx8R5.js +5288 -0
  42. package/dist/nav-core-B5qU2dzn.js +225 -0
  43. package/dist/{normalize-error-D93O4q8g.js → normalize-error-BEcd1tmS.js} +2 -2
  44. package/dist/nuxt.js +1 -1
  45. package/dist/otp-core-DXg3vFLh.js +758 -0
  46. package/dist/radio-utils-Dk9Tl1jz.js +319 -0
  47. package/dist/rich-text-editor-core-Ddd_QaLn.js +1280 -0
  48. package/dist/select-utils-BgArYHk8.js +2140 -0
  49. package/dist/sidebar-core-CD6txDo3.js +583 -0
  50. package/dist/slider-core-vcWr321-.js +1014 -0
  51. package/dist/src/components/dropdown-table/dropdown-table-core.d.ts +2 -2
  52. package/dist/src/components/dropdown-table/dropdown-table-types.d.ts +1 -1
  53. package/dist/src/components/dropdown-table/index.d.ts +1 -1
  54. package/dist/src/components/dropdown-table/index.shadow.d.ts +1 -1
  55. package/dist/src/components/dropdown-table/mono-data-dropdown.d.ts +1 -1
  56. package/dist/src/components/form/form-types.d.ts +9 -3
  57. package/dist/src/components/input/input-core.d.ts +1 -1
  58. package/dist/src/components/input/input-types.d.ts +1 -1
  59. package/dist/src/components/otp/otp-core.d.ts +1 -1
  60. package/dist/src/components/select/select-core.d.ts +1 -1
  61. package/dist/src/components/select/select-types.d.ts +1 -1
  62. package/dist/src/components/slider/slider-core.d.ts +1 -1
  63. package/dist/src/components/slider/slider-types.d.ts +1 -1
  64. package/dist/src/components/table/filter-suggestion.d.ts +171 -0
  65. package/dist/src/components/table/index.d.ts +5 -4
  66. package/dist/src/components/table/index.shadow.d.ts +5 -4
  67. package/dist/src/components/table/mono-data-grid.d.ts +22 -3
  68. package/dist/src/components/table/mono-table-empty-core.d.ts +37 -0
  69. package/dist/src/components/table/mono-table-search-core.d.ts +22 -3
  70. package/dist/src/components/table/table-types.d.ts +74 -4
  71. package/dist/src/components/tag-input/tag-input-core.d.ts +1 -1
  72. package/dist/src/components/tag-input/tag-input-types.d.ts +1 -1
  73. package/dist/src/components/textarea/textarea-core.d.ts +1 -1
  74. package/dist/src/composables/mono-event.d.ts +7 -1
  75. package/dist/src/entries/index.d.ts +8 -6
  76. package/dist/src/entries/index.node.d.ts +8 -6
  77. package/dist/src/search/index.d.ts +1 -1
  78. package/dist/src/utils/group-count.d.ts +36 -0
  79. package/dist/switch-utils-CTZ4id2V.js +338 -0
  80. package/dist/tabs-core-r5-B8k_N.js +317 -0
  81. package/dist/tag-input-utils-D2JA90DQ.js +3060 -0
  82. package/dist/textarea-utils-VU1KeXm8.js +821 -0
  83. package/dist/ui/accordion.js +2 -274
  84. package/dist/ui/alert.js +2 -131
  85. package/dist/ui/breadcrumb.js +4 -745
  86. package/dist/ui/button-dropdown.js +4 -652
  87. package/dist/ui/button.js +2 -63
  88. package/dist/ui/card.js +2 -310
  89. package/dist/ui/chart.js +4 -800
  90. package/dist/ui/checkbox.js +4 -335
  91. package/dist/ui/chip.js +4 -402
  92. package/dist/ui/date.js +3 -732
  93. package/dist/ui/drawer.js +3 -757
  94. package/dist/ui/dropdown-table.js +5 -1341
  95. package/dist/ui/dropdown.js +4 -509
  96. package/dist/ui/file-upload.js +3 -622
  97. package/dist/ui/filter.js +5 -380
  98. package/dist/ui/form.js +1 -1
  99. package/dist/ui/index.css +118 -1
  100. package/dist/ui/input.js +3 -1141
  101. package/dist/ui/menu.js +4 -828
  102. package/dist/ui/modal.js +4 -843
  103. package/dist/ui/nav.js +4 -223
  104. package/dist/ui/otp.js +4 -756
  105. package/dist/ui/radio.js +4 -317
  106. package/dist/ui/rich-text-editor.js +4 -1278
  107. package/dist/ui/select.js +5 -2138
  108. package/dist/ui/shadow/accordion.js +4 -273
  109. package/dist/ui/shadow/alert.js +4 -130
  110. package/dist/ui/shadow/breadcrumb.js +5 -744
  111. package/dist/ui/shadow/button-dropdown.js +6 -652
  112. package/dist/ui/shadow/button.js +3 -63
  113. package/dist/ui/shadow/card.js +4 -309
  114. package/dist/ui/shadow/chart.js +6 -1576
  115. package/dist/ui/shadow/checkbox.js +4 -334
  116. package/dist/ui/shadow/chip.js +4 -396
  117. package/dist/ui/shadow/date.js +7 -731
  118. package/dist/ui/shadow/drawer.js +4 -756
  119. package/dist/ui/shadow/dropdown-table.js +8 -1762
  120. package/dist/ui/shadow/dropdown.js +4 -508
  121. package/dist/ui/shadow/file-upload.js +4 -620
  122. package/dist/ui/shadow/filter.js +7 -379
  123. package/dist/ui/shadow/input.js +6 -1140
  124. package/dist/ui/shadow/menu.js +5 -828
  125. package/dist/ui/shadow/modal.js +6 -1063
  126. package/dist/ui/shadow/nav.js +5 -223
  127. package/dist/ui/shadow/otp.js +6 -754
  128. package/dist/ui/shadow/radio.js +4 -316
  129. package/dist/ui/shadow/rich-text-editor.js +4 -1276
  130. package/dist/ui/shadow/select.js +6 -2136
  131. package/dist/ui/shadow/sidebar.js +5 -581
  132. package/dist/ui/shadow/slider.js +5 -1010
  133. package/dist/ui/shadow/switch.js +4 -335
  134. package/dist/ui/shadow/table.js +10 -4501
  135. package/dist/ui/shadow/tabs.js +6 -315
  136. package/dist/ui/shadow/tag-input.js +7 -3057
  137. package/dist/ui/shadow/textarea.js +6 -817
  138. package/dist/ui/sidebar.js +3 -581
  139. package/dist/ui/slider.js +4 -1012
  140. package/dist/ui/switch.js +4 -336
  141. package/dist/ui/table.js +9 -4502
  142. package/dist/ui/tabs.js +4 -315
  143. package/dist/ui/tag-input.js +5 -3058
  144. package/dist/ui/textarea.js +4 -819
  145. package/dist/{vite-CivRCJaf.js → vite-CfW7z2wn.js} +21 -14
  146. package/dist/vite.js +1 -1
  147. package/dist/vue.d.ts +3 -2
  148. package/package.json +10 -11
  149. package/dist/chip-strip-bNfLn52Z.js +0 -215
  150. package/dist/data-source-controller-Dx6IQ2CN.js +0 -243
  151. package/dist/data-source-options-BM4r4PRw.js +0 -558
  152. package/dist/data-source-read-HyBCRg1t.js +0 -242
  153. package/dist/excel-BXzr3uI1.js +0 -784
  154. package/dist/export-ixRdCS2y.js +0 -2388
  155. package/dist/field-tooltip-addon-CWCp19mJ.js +0 -702
  156. package/dist/field-tooltip.css_raw-U5UeTa2d.js +0 -269
  157. package/dist/filter-builder-C0T3pMx2.js +0 -208
  158. package/dist/form-control-core-BbiACMtL.js +0 -226
  159. package/dist/icon-ClxnYhBG.js +0 -19
  160. package/dist/import-Dc4eXC02.js +0 -612
  161. package/dist/light-slots-_no0r2Z-.js +0 -246
  162. package/dist/markdown-uGlE_OfJ.js +0 -20191
  163. package/dist/mono-data-grid-e9ZVBlNN.js +0 -4240
  164. package/dist/normalize-error-BmLbgANw.js +0 -1048
@@ -0,0 +1,654 @@
1
+ import { t as applyProps } from "./element-props-xvw0EB7H.js";
2
+ import { a as defineHybridPropAliases, o as numberStringConverter, r as booleanStringConverter, t as __decorate } from "./decorate-DbYFpi8R.js";
3
+ import { t as dispatchMonoEvent } from "./mono-event-CAZf0F_k.js";
4
+ import { a as rateLimitHasChanged } from "./rate-limit-e9Jlpl5l.js";
5
+ import { t as PopupPortalController } from "./popup-portal-CINuVjNY.js";
6
+ import { html, isServer, nothing } from "lit";
7
+ import { ref } from "lit/directives/ref.js";
8
+ import { property, state } from "lit/decorators.js";
9
+ import { repeat } from "lit/directives/repeat.js";
10
+
11
+ //#region src/components/button/button-dropdown-core.ts
12
+ /**
13
+ * Would these two entry lists RENDER identically?
14
+ *
15
+ * Function-valued fields are skipped: a consumer rebuilds `onClick` on every render
16
+ * so it closes over the current row, and those handlers are resolved at click time
17
+ * rather than baked into the DOM, so they cannot make the output differ. Everything
18
+ * else — label, icon, size, color, variant, disabled — is compared strictly, and any
19
+ * non-primitive field (a fresh `cssClass` object, say) simply compares unequal and
20
+ * falls back to a normal update. Conservative by construction: a false "same" would
21
+ * show stale markup, a false "different" only costs the render we have today.
22
+ */
23
+ function sameButtonItems(a, b) {
24
+ if (a === b) return true;
25
+ if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
26
+ for (let i = 0; i < a.length; i++) {
27
+ const x = a[i];
28
+ const y = b[i];
29
+ if (x === y) continue;
30
+ if (!x || !y || typeof x !== "object" || typeof y !== "object") return false;
31
+ const keys = Object.keys(x);
32
+ if (keys.length !== Object.keys(y).length) return false;
33
+ for (const key of keys) {
34
+ const xv = x[key];
35
+ const yv = y[key];
36
+ if (typeof xv === "function" && typeof yv === "function") continue;
37
+ if (xv !== yv) return false;
38
+ }
39
+ }
40
+ return true;
41
+ }
42
+ /**
43
+ * `MonoButtonDropdownCore` — everything render-mode-agnostic for
44
+ * `mono-button-dropdown`.
45
+ *
46
+ * The behaviour in one line: **while `buttons.length <= min` the entries render
47
+ * as plain buttons; past that they ALL move into a dropdown and only the trigger
48
+ * is left.** That all-or-nothing rule is deliberate (it mirrors the Vuetify
49
+ * `ButtonMenu` this replaces) — a partial split would leave the row's width
50
+ * jumping around as the action list changes.
51
+ *
52
+ * Two pieces are borrowed rather than rebuilt:
53
+ * - **`PopupPortalController`** does the positioning, flipping and z-index
54
+ * stacking, exactly as `mono-dropdown` uses it, so this panel ranks correctly
55
+ * against modals and other popups.
56
+ * - **Each entry is a real `<mono-button>`**, so every `ButtonProps` — `loading`,
57
+ * `throttle`, `handler`, `badge` — keeps working with nothing re-implemented.
58
+ * Props are pushed on with `applyProps` rather than a fixed attribute list, so
59
+ * a prop added to the button later flows through without touching this file.
60
+ */
61
+ /**
62
+ * The component's PUBLIC custom properties, handed to the popup portal so a
63
+ * relocated panel keeps overrides an ancestor of the host set — a portaled panel
64
+ * is a child of `<body>`, so it inherits none of them, and `getComputedStyle`
65
+ * cannot enumerate custom properties for the portal to copy them blindly.
66
+ *
67
+ * Kept in step with button-dropdown.css by tests/button-dropdown-attributes.test.ts.
68
+ */
69
+ const BUTTON_DROPDOWN_STYLE_VARS = [
70
+ "--mono-button-dropdown-bg",
71
+ "--mono-button-dropdown-border",
72
+ "--mono-button-dropdown-dark",
73
+ "--mono-button-dropdown-danger",
74
+ "--mono-button-dropdown-gap",
75
+ "--mono-button-dropdown-info",
76
+ "--mono-button-dropdown-item-base-color",
77
+ "--mono-button-dropdown-item-base-hover-bg",
78
+ "--mono-button-dropdown-item-base-hover-color",
79
+ "--mono-button-dropdown-item-color",
80
+ "--mono-button-dropdown-item-font-weight",
81
+ "--mono-button-dropdown-item-hover",
82
+ "--mono-button-dropdown-item-hover-bg",
83
+ "--mono-button-dropdown-item-hover-color",
84
+ "--mono-button-dropdown-item-radius",
85
+ "--mono-button-dropdown-item-radius-lg",
86
+ "--mono-button-dropdown-item-radius-xl",
87
+ "--mono-button-dropdown-item-radius-xxl",
88
+ "--mono-button-dropdown-light",
89
+ "--mono-button-dropdown-list-gap",
90
+ "--mono-button-dropdown-min-width",
91
+ "--mono-button-dropdown-min-width-lg",
92
+ "--mono-button-dropdown-min-width-md",
93
+ "--mono-button-dropdown-min-width-sm",
94
+ "--mono-button-dropdown-min-width-xl",
95
+ "--mono-button-dropdown-min-width-xs",
96
+ "--mono-button-dropdown-min-width-xxl",
97
+ "--mono-button-dropdown-offset",
98
+ "--mono-button-dropdown-offset-lg",
99
+ "--mono-button-dropdown-offset-md",
100
+ "--mono-button-dropdown-offset-sm",
101
+ "--mono-button-dropdown-offset-xl",
102
+ "--mono-button-dropdown-offset-xs",
103
+ "--mono-button-dropdown-offset-xxl",
104
+ "--mono-button-dropdown-padding",
105
+ "--mono-button-dropdown-padding-lg",
106
+ "--mono-button-dropdown-padding-md",
107
+ "--mono-button-dropdown-padding-sm",
108
+ "--mono-button-dropdown-padding-xl",
109
+ "--mono-button-dropdown-padding-xs",
110
+ "--mono-button-dropdown-padding-xxl",
111
+ "--mono-button-dropdown-primary",
112
+ "--mono-button-dropdown-purple",
113
+ "--mono-button-dropdown-radius",
114
+ "--mono-button-dropdown-radius-lg",
115
+ "--mono-button-dropdown-radius-md",
116
+ "--mono-button-dropdown-radius-sm",
117
+ "--mono-button-dropdown-radius-xl",
118
+ "--mono-button-dropdown-radius-xs",
119
+ "--mono-button-dropdown-radius-xxl",
120
+ "--mono-button-dropdown-ring-color",
121
+ "--mono-button-dropdown-ring-width",
122
+ "--mono-button-dropdown-secondary",
123
+ "--mono-button-dropdown-shadow",
124
+ "--mono-button-dropdown-success",
125
+ "--mono-button-dropdown-surface",
126
+ "--mono-button-dropdown-teal",
127
+ "--mono-button-dropdown-text",
128
+ "--mono-button-dropdown-warning"
129
+ ];
130
+ const MonoButtonDropdownCore = (superClass) => {
131
+ class MonoButtonDropdownCoreClass extends superClass {
132
+ constructor(...args) {
133
+ super(...args);
134
+ this._panelEl = null;
135
+ this._triggerEl = null;
136
+ this._popup = new PopupPortalController(this, {
137
+ getPanel: () => this._panelEl,
138
+ getAnchor: () => this._triggerEl,
139
+ /**
140
+ * The INNER wrapper, not the host — it's what carries
141
+ * `.mono-button-dropdown`, and therefore the `--_mono-button-dropdown-*`
142
+ * variables every panel rule reads. The portal mirrors this element's class
143
+ * onto itself, so the relocated panel keeps inheriting them; pointing at the
144
+ * host (which has no class) left the panel transparent and border-less,
145
+ * since each value resolved to an undefined var.
146
+ */
147
+ getStyleScope: () => this.renderRoot?.querySelector?.(".mono-button-dropdown"),
148
+ isOpen: () => this.modelValue,
149
+ side: () => this._side(),
150
+ align: () => this._align(),
151
+ offset: () => this.offset,
152
+ styleVars: () => BUTTON_DROPDOWN_STYLE_VARS,
153
+ flip: () => true,
154
+ shift: () => true,
155
+ onSideResolved: (side) => {
156
+ if (this._resolvedSide !== side) this._resolvedSide = side;
157
+ }
158
+ });
159
+ this._buttons = [];
160
+ this.min = 1;
161
+ this.placement = "bottom-end";
162
+ this.offset = 4;
163
+ this.modelValue = false;
164
+ this.disabled = false;
165
+ this.closeOnSelect = true;
166
+ this.closeOnOutsideClick = true;
167
+ this.closeOnEscape = true;
168
+ this.cssClass = {};
169
+ this._resolvedSide = "bottom";
170
+ this._documentBound = false;
171
+ this._onDocumentClick = (event) => {
172
+ if (!this.modelValue || !this.closeOnOutsideClick) return;
173
+ const path = event.composedPath();
174
+ if (path.includes(this) || this._popup.containsInPath(path)) return;
175
+ this._setOpen(false, "outside", event);
176
+ };
177
+ this._onDocumentKeydown = (event) => {
178
+ if (!this.modelValue) return;
179
+ if (event.key === "Escape" && this.closeOnEscape) {
180
+ this._setOpen(false, "escape", event);
181
+ this._focusTrigger();
182
+ return;
183
+ }
184
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
185
+ const rows = this._menuButtons();
186
+ if (!rows.length) return;
187
+ event.preventDefault();
188
+ rows[(rows.findIndex((b) => b === document.activeElement || b.contains(document.activeElement)) + (event.key === "ArrowDown" ? 1 : -1) + rows.length) % rows.length]?.focus?.();
189
+ }
190
+ };
191
+ this._itemEls = /* @__PURE__ */ new Map();
192
+ this._itemParts = /* @__PURE__ */ new Map();
193
+ this.bindPanel = (el) => {
194
+ this._panelEl = el ?? null;
195
+ };
196
+ this._rootEl = null;
197
+ this.bindRoot = (el) => {
198
+ this._rootEl = el ?? null;
199
+ this._applyRootAttrs(this._rootEl);
200
+ };
201
+ defineHybridPropAliases(this, [
202
+ "modelValue",
203
+ "closeOnSelect",
204
+ "closeOnOutsideClick",
205
+ "closeOnEscape",
206
+ "cssClass",
207
+ "cssClassName"
208
+ ]);
209
+ }
210
+ /**
211
+ * Entries for this dropdown.
212
+ *
213
+ * `noAccessor` because assignment does two things, only one of which is an
214
+ * update. Building a fresh array on every render is the NORMAL shape whenever an
215
+ * entry's `onClick` closes over the current row — and with one dropdown per table
216
+ * row that means an unrelated re-render (a filter panel opening, say) hands N
217
+ * dropdowns a brand-new array and re-renders all of them. Measured on a 2000-row
218
+ * table: 737ms of blocked main thread per toggle, against 60ms when the array
219
+ * identity happened to be stable. Nothing about the RENDER differed.
220
+ *
221
+ * So: compare by content and skip the update when it is equivalent. Handlers are
222
+ * excluded from that comparison deliberately — they are rebuilt every render by
223
+ * design and are resolved at CLICK time from `_itemParts`, never captured in the
224
+ * listener closure (see `_itemElement`). That is also why `_retargetItemParts()`
225
+ * has to run on EVERY assignment including a skipped one: `_itemParts` is
226
+ * normally refreshed during render, so without it a suppressed update would
227
+ * leave the cached entries pointing at the previous array's closures and a click
228
+ * would fire the wrong row's handler.
229
+ */
230
+ get buttons() {
231
+ return this._buttons;
232
+ }
233
+ set buttons(next) {
234
+ const previous = this._buttons;
235
+ this._buttons = next ?? [];
236
+ this._retargetItemParts();
237
+ if (!sameButtonItems(previous, this._buttons)) this.requestUpdate("buttons", previous);
238
+ }
239
+ /**
240
+ * Point the cached entry elements at the CURRENT array without rendering, so a
241
+ * click resolves this render's `item`/`index` even when the update was skipped.
242
+ */
243
+ _retargetItemParts() {
244
+ if (!this._itemParts?.size) return;
245
+ for (const [key, state] of this._itemParts) {
246
+ const index = Number(key.slice(2));
247
+ const item = this._buttons[index];
248
+ if (item) this._itemParts.set(key, {
249
+ ...state,
250
+ item,
251
+ index
252
+ });
253
+ }
254
+ }
255
+ connectedCallback() {
256
+ super.connectedCallback();
257
+ if (isServer) return;
258
+ this._syncDocument();
259
+ }
260
+ disconnectedCallback() {
261
+ this._syncDocument(false);
262
+ super.disconnectedCallback();
263
+ }
264
+ /**
265
+ * Outside-click / Escape listeners, bound while OPEN only (select's rule). Both handlers
266
+ * bail when closed, and a grid that puts one of these in every row held two `document`
267
+ * listeners per row — one capture-phase — in the path of every click and keystroke.
268
+ */
269
+ _syncDocument(want = this.modelValue && this.isConnected) {
270
+ if (isServer || want === this._documentBound) return;
271
+ this._documentBound = want;
272
+ if (want) {
273
+ document.addEventListener("click", this._onDocumentClick, true);
274
+ document.addEventListener("keydown", this._onDocumentKeydown);
275
+ } else {
276
+ document.removeEventListener("click", this._onDocumentClick, true);
277
+ document.removeEventListener("keydown", this._onDocumentKeydown);
278
+ }
279
+ }
280
+ /** Entries are behind the trigger once there are more of them than `min`. */
281
+ get collapsed() {
282
+ return (this.buttons?.length ?? 0) > Math.max(0, this.min ?? 1);
283
+ }
284
+ show(source = "manual") {
285
+ this._setOpen(true, source);
286
+ }
287
+ hide(source = "manual") {
288
+ this._setOpen(false, source);
289
+ }
290
+ toggle(source = "manual") {
291
+ this._setOpen(!this.modelValue, source);
292
+ }
293
+ _setOpen(next, source, sourceEvent) {
294
+ if (this.disabled && next) return;
295
+ if (this.modelValue === next) return;
296
+ this.modelValue = next;
297
+ const detail = {
298
+ modelValue: next,
299
+ collapsed: this.collapsed,
300
+ source,
301
+ sourceEvent
302
+ };
303
+ dispatchMonoEvent(this, next ? "open" : "close", detail);
304
+ }
305
+ /** The rendered entry buttons inside the open panel, in order. */
306
+ _menuButtons() {
307
+ return this._panelEl ? Array.from(this._panelEl.querySelectorAll("[data-mono-bd-item]")) : [];
308
+ }
309
+ _focusTrigger() {
310
+ this._triggerEl?.focus?.();
311
+ }
312
+ _side() {
313
+ return this.placement?.split("-")[0] ?? "bottom";
314
+ }
315
+ _align() {
316
+ const part = this.placement?.split("-")[1];
317
+ return part === "start" || part === "end" ? part : "center";
318
+ }
319
+ /** Light renders `mono-button`; the shadow build overrides with its own tag. */
320
+ _buttonTag() {
321
+ return "mono-button";
322
+ }
323
+ /**
324
+ * Whether entry content can be written as a Lit template.
325
+ *
326
+ * **It can't for the light build.** A light `<mono-button>` CAPTURES its
327
+ * children in `connectedCallback` and relocates them into its own
328
+ * `[data-mono-slot]` targets — including nodes our template rendered into it.
329
+ * That ejects this element's part markers, and the next render dies with
330
+ * "this `ChildPart` has no `parentNode`". So the light build hands Lit a
331
+ * fully-built element instead (see `_itemElement`), leaving Lit no parts
332
+ * inside the button to lose.
333
+ *
334
+ * The shadow build has no such problem: it projects through a native
335
+ * `<slot>`, moves nothing, and stays SSR-safe.
336
+ */
337
+ _declarativeItems() {
338
+ return false;
339
+ }
340
+ updated(changed) {
341
+ super.updated?.(changed);
342
+ this._syncDocument();
343
+ this._applyRootAttrs(this._rootEl);
344
+ }
345
+ willUpdate(changed) {
346
+ if (changed.has("buttons")) this._pruneItemCache();
347
+ super.willUpdate?.(changed);
348
+ }
349
+ /** Forget cached entries whose index no longer exists in `buttons`. */
350
+ _pruneItemCache() {
351
+ const len = this.buttons?.length ?? 0;
352
+ for (const key of [...this._itemEls.keys()]) {
353
+ const index = Number(key.slice(2));
354
+ if (!Number.isFinite(index) || index >= len) {
355
+ this._itemEls.delete(key);
356
+ this._itemParts.delete(key);
357
+ }
358
+ }
359
+ }
360
+ /** Build (or update) the real element for one entry. */
361
+ _itemElement(item, index, inMenu, opts) {
362
+ const key = `${inMenu ? "m" : "r"}:${index}`;
363
+ let el = this._itemEls.get(key);
364
+ const prev = this._itemParts.get(key);
365
+ if (el && prev && (prev.label !== item.label || prev.icon !== item.icon)) {
366
+ this._itemEls.delete(key);
367
+ el = void 0;
368
+ }
369
+ if (!el) {
370
+ el = document.createElement(this._buttonTag());
371
+ el.setAttribute("data-mono-bd-item", "");
372
+ if (item.icon) {
373
+ const icon = document.createElement("span");
374
+ icon.setAttribute("slot", "icon");
375
+ icon.className = `mono-icon ${item.icon}`;
376
+ el.appendChild(icon);
377
+ }
378
+ if (item.label) el.appendChild(document.createTextNode(item.label));
379
+ el.addEventListener("click", ((event) => {
380
+ const state = this._itemParts.get(key);
381
+ if (state) this._onItemClick(state.item, state.index, event);
382
+ }));
383
+ el.addEventListener("mno-click", (e) => e.stopPropagation());
384
+ el.addEventListener("mnoClick", (e) => e.stopPropagation());
385
+ this._itemEls.set(key, el);
386
+ }
387
+ this._itemParts.set(key, {
388
+ label: item.label,
389
+ icon: item.icon,
390
+ item,
391
+ index
392
+ });
393
+ el.className = opts.cls;
394
+ this._applyItem(el, item);
395
+ return el;
396
+ }
397
+ _cls(base, key) {
398
+ const extra = this.cssClass?.[key];
399
+ return extra ? `${base} ${extra}` : base;
400
+ }
401
+ /**
402
+ * Push an entry's props onto its rendered `<mono-button>`.
403
+ *
404
+ * Done imperatively via a Lit ref callback rather than as template
405
+ * attributes: object/function props (`handler`, `cssClass`, `throttle`) can't
406
+ * cross as attributes, and going through `applyProps` means any prop the
407
+ * button gains later works here with no change.
408
+ */
409
+ _applyItem(el, item) {
410
+ if (!el) return;
411
+ const { label: _l, icon: _i, onClick: _c, className: _n, ...rest } = item;
412
+ applyProps(el, rest);
413
+ if (this.disabled) el.disabled = true;
414
+ }
415
+ _onItemClick(item, index, event) {
416
+ if (item.disabled || this.disabled) return;
417
+ item.onClick?.(event);
418
+ dispatchMonoEvent(this, "click", {
419
+ item,
420
+ index,
421
+ modelValue: this.modelValue,
422
+ collapsed: this.collapsed,
423
+ source: "trigger",
424
+ sourceEvent: event
425
+ });
426
+ if (this.collapsed && this.closeOnSelect) this._setOpen(false, "manual", event);
427
+ }
428
+ /** One entry, as a real button element carrying its own props. */
429
+ renderItem(item, index, inMenu) {
430
+ const tag = this._buttonTag();
431
+ const cls = [
432
+ inMenu ? "mono-button-dropdown-item-btn" : "mono-button-dropdown-row-btn",
433
+ inMenu && item.color ? `mono-bd-c-${item.color}` : "",
434
+ item.className ?? ""
435
+ ].filter(Boolean).join(" ");
436
+ const content = html`
437
+ ${item.icon ? html`<span slot="icon" class="mono-icon ${item.icon}"></span>` : nothing}
438
+ ${item.label ?? nothing}
439
+ `;
440
+ const onClick = (e) => this._onItemClick(item, index, e);
441
+ if (!this._declarativeItems()) return this._itemElement(item, index, inMenu, {
442
+ cls,
443
+ onClick
444
+ });
445
+ const bind = (el) => this._applyItem(el, item);
446
+ const stop = (e) => e.stopPropagation();
447
+ return tag === "mono-button" ? html`<mono-button
448
+ class=${cls}
449
+ data-mono-bd-item
450
+ ${ref(bind)}
451
+ @click=${onClick}
452
+ @mno-click=${stop}
453
+ @mnoClick=${stop}
454
+ >${content}</mono-button
455
+ >` : html`<mono-shadow-button
456
+ class=${cls}
457
+ data-mono-bd-item
458
+ ${ref(bind)}
459
+ @click=${onClick}
460
+ @mno-click=${stop}
461
+ @mnoClick=${stop}
462
+ >${content}</mono-shadow-button
463
+ >`;
464
+ }
465
+ /** The inline row — every entry as a plain button, no dropdown involved. */
466
+ renderRow() {
467
+ return html`
468
+ <div class=${this._cls("mono-button-dropdown-row", "row")} mono-row ?hidden=${this.collapsed}>
469
+ ${this.collapsed ? nothing : repeat(this.buttons ?? [], (_item, i) => i, (item, i) => this.renderItem(item, i, false))}
470
+ </div>
471
+ `;
472
+ }
473
+ /** Class + state for the panel, which each build writes into its own template. */
474
+ get panelClass() {
475
+ return this._cls("mono-button-dropdown-panel", "panel");
476
+ }
477
+ get panelHidden() {
478
+ return !this.collapsed || !this.modelValue;
479
+ }
480
+ /**
481
+ * The prop mirrors, each omitted at its default so `:not([mono-size])` means
482
+ * "md" for hand-written markup exactly as it does for the element.
483
+ */
484
+ _computeRootAttrs() {
485
+ const align = this._align();
486
+ const side = this.modelValue ? this._resolvedSide : this._side();
487
+ return {
488
+ "mono-size": !this.size || this.size === "md" ? null : this.size,
489
+ "mono-color": !this.color || this.color === "primary" ? null : this.color,
490
+ "mono-variant": !this.variant || this.variant === "solid" ? null : this.variant,
491
+ "mono-rounded": this.rounded ?? null,
492
+ "mono-placement": this.placement === "bottom-end" ? null : this.placement,
493
+ "mono-side": side === "bottom" ? null : side,
494
+ "mono-align": align === "end" ? null : align,
495
+ "mono-open": this.modelValue ? "" : null,
496
+ "mono-collapsed": this.collapsed ? "" : null,
497
+ "mono-disabled": this.disabled ? "" : null,
498
+ "mono-fixed": this._positionsPanel() ? "" : null
499
+ };
500
+ }
501
+ /** Does this build measure and place the panel itself? (light only — see above.) */
502
+ _positionsPanel() {
503
+ return !isServer && this.renderRoot === this;
504
+ }
505
+ _applyRootAttrs(root) {
506
+ if (!root) return;
507
+ if (!root.hasAttribute("mono-button-dropdown")) root.setAttribute("mono-button-dropdown", "");
508
+ for (const [name, value] of Object.entries(this._computeRootAttrs())) if (value === null) root.removeAttribute(name);
509
+ else if (root.getAttribute(name) !== value) root.setAttribute(name, value);
510
+ }
511
+ /**
512
+ * An entry's `color` inside the menu.
513
+ *
514
+ * It is NOT a button colour in there (see button-dropdown.css): the row takes
515
+ * the role as its INK and a 10%/20% wash of it on hover, the way Basecoat
516
+ * treats `[data-variant='destructive']`. `primary` is written out rather
517
+ * than dropped as a default, because the panel's own ink is the popover
518
+ * foreground, not the primary role.
519
+ */
520
+ _itemColorAttr(item) {
521
+ return item.color ?? null;
522
+ }
523
+ /** The menu rows. Lives INSIDE the panel, so these parts travel with it. */
524
+ renderMenuList() {
525
+ return html`
526
+ <ul class=${this._cls("mono-button-dropdown-list", "list")} mono-list>
527
+ ${this.collapsed ? repeat(this.buttons ?? [], (_item, i) => i, (item, i) => html`
528
+ <li
529
+ class=${this._cls("mono-button-dropdown-item", "item")}
530
+ mono-item
531
+ mono-item-color=${this._itemColorAttr(item) ?? nothing}
532
+ role="none"
533
+ >
534
+ ${this.renderItem(item, i, true)}
535
+ </li>
536
+ `) : nothing}
537
+ </ul>
538
+ `;
539
+ }
540
+ /** The `⋮` trigger. `nothing` while the entries are inline. */
541
+ renderTrigger() {
542
+ if (!this.collapsed) return nothing;
543
+ return this._renderTriggerButton();
544
+ }
545
+ _renderTriggerButton() {
546
+ const t = {
547
+ ...this.color ? { color: this.color } : {},
548
+ ...this.variant ? { variant: this.variant } : {},
549
+ ...this.size ? { size: this.size } : {},
550
+ ...this.rounded ? { rounded: this.rounded } : {},
551
+ ...this.trigger ?? {}
552
+ };
553
+ const tag = this._buttonTag();
554
+ const triggerCls = this._cls("mono-button-dropdown-trigger", "trigger");
555
+ const bindTrigger = (el) => {
556
+ this._triggerEl = el ?? null;
557
+ if (!el) return;
558
+ const { label: _l, icon: _i, ...rest } = t;
559
+ applyProps(el, rest);
560
+ if (this.disabled) el.disabled = true;
561
+ };
562
+ const stop = (e) => e.stopPropagation();
563
+ const onTrigger = (e) => {
564
+ e.stopPropagation();
565
+ this.toggle("trigger");
566
+ };
567
+ if (!this._declarativeItems()) {
568
+ let el = this._itemEls.get("trigger");
569
+ if (!el) {
570
+ el = document.createElement(tag);
571
+ el.setAttribute("mono-trigger", "");
572
+ const icon = document.createElement("span");
573
+ icon.setAttribute("slot", "icon");
574
+ icon.className = `mono-icon ${t.icon ?? "i-mdi-dots-vertical"}`;
575
+ el.appendChild(icon);
576
+ if (t.label) el.appendChild(document.createTextNode(t.label));
577
+ if (!t.label) el.setAttribute("icon-only", "true");
578
+ el.addEventListener("click", onTrigger);
579
+ el.addEventListener("mno-click", stop);
580
+ el.addEventListener("mnoClick", stop);
581
+ this._itemEls.set("trigger", el);
582
+ }
583
+ el.className = triggerCls;
584
+ bindTrigger(el);
585
+ return el;
586
+ }
587
+ const triggerContent = html`
588
+ <span slot="icon" class="mono-icon ${t.icon ?? "i-mdi-dots-vertical"}"></span>
589
+ ${t.label ?? nothing}
590
+ `;
591
+ return tag === "mono-button" ? html`<mono-button
592
+ class=${triggerCls}
593
+ mono-trigger
594
+ icon-only=${t.label ? nothing : "true"}
595
+ ${ref(bindTrigger)}
596
+ @click=${onTrigger}
597
+ @mno-click=${stop}
598
+ @mnoClick=${stop}
599
+ >${triggerContent}</mono-button
600
+ >` : html`<mono-shadow-button
601
+ class=${triggerCls}
602
+ mono-trigger
603
+ icon-only=${t.label ? nothing : "true"}
604
+ ${ref(bindTrigger)}
605
+ @click=${onTrigger}
606
+ @mno-click=${stop}
607
+ @mnoClick=${stop}
608
+ >${triggerContent}</mono-shadow-button
609
+ >`;
610
+ }
611
+ }
612
+ __decorate([property({
613
+ attribute: false,
614
+ noAccessor: true
615
+ })], MonoButtonDropdownCoreClass.prototype, "buttons", null);
616
+ __decorate([property({ converter: numberStringConverter })], MonoButtonDropdownCoreClass.prototype, "min", void 0);
617
+ __decorate([property({ type: String })], MonoButtonDropdownCoreClass.prototype, "placement", void 0);
618
+ __decorate([property({ converter: numberStringConverter })], MonoButtonDropdownCoreClass.prototype, "offset", void 0);
619
+ __decorate([property({ type: String })], MonoButtonDropdownCoreClass.prototype, "color", void 0);
620
+ __decorate([property({ type: String })], MonoButtonDropdownCoreClass.prototype, "variant", void 0);
621
+ __decorate([property({ type: String })], MonoButtonDropdownCoreClass.prototype, "size", void 0);
622
+ __decorate([property({ type: String })], MonoButtonDropdownCoreClass.prototype, "rounded", void 0);
623
+ __decorate([property({
624
+ attribute: false,
625
+ hasChanged: rateLimitHasChanged
626
+ })], MonoButtonDropdownCoreClass.prototype, "trigger", void 0);
627
+ __decorate([property({
628
+ attribute: "model-value",
629
+ reflect: true,
630
+ converter: booleanStringConverter
631
+ })], MonoButtonDropdownCoreClass.prototype, "modelValue", void 0);
632
+ __decorate([property({
633
+ reflect: true,
634
+ converter: booleanStringConverter
635
+ })], MonoButtonDropdownCoreClass.prototype, "disabled", void 0);
636
+ __decorate([property({
637
+ attribute: "close-on-select",
638
+ converter: booleanStringConverter
639
+ })], MonoButtonDropdownCoreClass.prototype, "closeOnSelect", void 0);
640
+ __decorate([property({
641
+ attribute: "close-on-outside-click",
642
+ converter: booleanStringConverter
643
+ })], MonoButtonDropdownCoreClass.prototype, "closeOnOutsideClick", void 0);
644
+ __decorate([property({
645
+ attribute: "close-on-escape",
646
+ converter: booleanStringConverter
647
+ })], MonoButtonDropdownCoreClass.prototype, "closeOnEscape", void 0);
648
+ __decorate([property({ attribute: false })], MonoButtonDropdownCoreClass.prototype, "cssClass", void 0);
649
+ __decorate([state()], MonoButtonDropdownCoreClass.prototype, "_resolvedSide", void 0);
650
+ return MonoButtonDropdownCoreClass;
651
+ };
652
+
653
+ //#endregion
654
+ export { MonoButtonDropdownCore as t };