@mono-lit/helper 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/dist/control-tooltip-7vegYmq3.js +678 -0
  2. package/dist/{tooltip-FCMRUSLi.js → control-tooltip-C3rA_nSH.js} +12 -119
  3. package/dist/{data-source-controller-Cf_sMxEh.js → data-source-controller-C6C4ej_M.js} +1 -1
  4. package/dist/{data-source-options-Bk-UoaZV.js → data-source-options-Cz9fVLK8.js} +3 -2
  5. package/dist/{data-source-read-Cuqw3LcP.js → data-source-read-i6CYSUEl.js} +2 -1
  6. package/dist/{excel-DtRpxmxs.js → excel-BPdDt06G.js} +1 -1
  7. package/dist/{export-B91P6J1y.js → export-DgomqI_3.js} +2 -2
  8. package/dist/export.js +2 -2
  9. package/dist/{field-icons-FmyBWa0g.js → field-icons-t8rXRCKs.js} +50 -1
  10. package/dist/field-tooltip-FyMi9vNM.js +266 -0
  11. package/dist/field-tooltip.css_raw-DEctHXKm.js +270 -0
  12. package/dist/field-validation-CHHQi1zl.js +170 -0
  13. package/dist/field-validation.css_raw-B3Iu33rS.js +178 -0
  14. package/dist/index.js +4 -3
  15. package/dist/{index.node-dvrNviMx.js → index.node-DzCuvHLg.js} +1 -1
  16. package/dist/index.node.js +4 -3
  17. package/dist/input-format-GrRCJBqV.js +251 -0
  18. package/dist/input.css_raw-CQu2fAsU.js +5 -0
  19. package/dist/{mono-data-grid-BHlo1IgR.js → mono-data-grid-KDpu4d4_.js} +5 -4
  20. package/dist/{mono-form-controller-IYn0MuUQ.js → mono-form-controller-BkMR8g14.js} +18 -3
  21. package/dist/{reactive-DFCdZbH9.js → normalize-error-BmLbgANw.js} +1 -48
  22. package/dist/nuxt.js +36 -8
  23. package/dist/{popup-portal-HWhkd7oy.js → popup-portal-C8ttHDRX.js} +17 -1
  24. package/dist/{popup-stack-De05Y-mJ.js → popup-stack-C64WCuXq.js} +21 -1
  25. package/dist/src/components/accordion/accordion-core.d.ts +4 -1
  26. package/dist/src/components/accordion/mono-accordion.shadow.d.ts +4 -1
  27. package/dist/src/components/date/date-core.d.ts +3 -0
  28. package/dist/src/components/date/date-types.d.ts +36 -1
  29. package/dist/src/components/drawer/drawer-core.d.ts +1 -0
  30. package/dist/src/components/dropdown-table/dropdown-table-core.d.ts +3 -0
  31. package/dist/src/components/dropdown-table/dropdown-table-types.d.ts +31 -0
  32. package/dist/src/components/form/form-types.d.ts +23 -5
  33. package/dist/src/components/input/index.d.ts +2 -2
  34. package/dist/src/components/input/index.shadow.d.ts +2 -2
  35. package/dist/src/components/input/input-core.d.ts +23 -3
  36. package/dist/src/components/input/input-types.d.ts +84 -9
  37. package/dist/src/components/input/mono-input.d.ts +3 -2
  38. package/dist/src/components/input/mono-input.shadow.d.ts +3 -2
  39. package/dist/src/components/modal/modal-core.d.ts +1 -0
  40. package/dist/src/components/otp/index.d.ts +5 -0
  41. package/dist/src/components/otp/index.shadow.d.ts +6 -0
  42. package/dist/src/components/otp/mono-otp.d.ts +32 -0
  43. package/dist/src/components/otp/mono-otp.shadow.d.ts +30 -0
  44. package/dist/src/components/otp/otp-core.d.ts +91 -0
  45. package/dist/src/components/otp/otp-types.d.ts +161 -0
  46. package/dist/src/components/otp/otp-utils.d.ts +41 -0
  47. package/dist/src/components/select/select-core.d.ts +3 -0
  48. package/dist/src/components/select/select-types.d.ts +31 -0
  49. package/dist/src/components/slider/index.d.ts +5 -0
  50. package/dist/src/components/slider/index.shadow.d.ts +6 -0
  51. package/dist/src/components/slider/mono-slider.d.ts +33 -0
  52. package/dist/src/components/slider/mono-slider.shadow.d.ts +29 -0
  53. package/dist/src/components/slider/slider-core.d.ts +77 -0
  54. package/dist/src/components/slider/slider-math.d.ts +102 -0
  55. package/dist/src/components/slider/slider-types.d.ts +188 -0
  56. package/dist/src/components/tag-input/tag-input-core.d.ts +3 -0
  57. package/dist/src/components/tag-input/tag-input-types.d.ts +31 -0
  58. package/dist/src/components/textarea/textarea-core.d.ts +3 -0
  59. package/dist/src/components/textarea/textarea-types.d.ts +31 -0
  60. package/dist/src/composables/field-bubble.d.ts +34 -0
  61. package/dist/src/composables/field-icons.d.ts +10 -0
  62. package/dist/src/composables/field-tooltip.d.ts +52 -0
  63. package/dist/src/composables/field-validation.d.ts +58 -0
  64. package/dist/src/composables/popup-portal.d.ts +12 -0
  65. package/dist/src/composables/popup-stack.d.ts +21 -0
  66. package/dist/src/entries/index.d.ts +1 -1
  67. package/dist/src/entries/index.node.d.ts +1 -1
  68. package/dist/src/nuxt/index.d.ts +2 -2
  69. package/dist/src/nuxt/ssr-lit/index.d.ts +4 -0
  70. package/dist/ssr-lit/runtime/components/LitWrapper.vue +11 -0
  71. package/dist/ssr-lit/runtime/components/LitWrapperClient.vue +11 -0
  72. package/dist/ssr-lit/runtime/components/LitWrapperServer.vue +38 -0
  73. package/dist/ssr-lit/runtime/plugins/antiFouc.server.js +25 -0
  74. package/dist/ssr-lit/runtime/plugins/hydrateSupport.client.js +4 -0
  75. package/dist/ssr-lit/runtime/plugins/polyfill.client.js +9 -0
  76. package/dist/ssr-lit/runtime/utils/customElements.js +11 -0
  77. package/dist/ssr-lit/runtime/utils/litElementRenderer.js +28 -0
  78. package/dist/{styles-D-ergrfR.js → styles-BODNpZV1.js} +1 -1
  79. package/dist/tooltip-Drekihf5.js +102 -0
  80. package/dist/tooltip-loader-3U9FTOXj.js +20 -0
  81. package/dist/tooltip-loader-Dcp9AUZn.js +23 -0
  82. package/dist/tooltip.js +3 -1
  83. package/dist/ui/accordion.js +16 -3
  84. package/dist/ui/alert.js +2 -2
  85. package/dist/ui/breadcrumb.js +1 -1
  86. package/dist/ui/button-dropdown.js +1 -1
  87. package/dist/ui/chart.js +1 -1
  88. package/dist/ui/date.js +66 -5
  89. package/dist/ui/drawer.js +11 -2
  90. package/dist/ui/dropdown-table.js +60 -5
  91. package/dist/ui/dropdown.js +3 -2
  92. package/dist/ui/file-upload.js +1 -1
  93. package/dist/ui/form.js +1 -1
  94. package/dist/ui/index.css +8857 -3974
  95. package/dist/ui/input.js +362 -260
  96. package/dist/ui/menu.js +1 -1
  97. package/dist/ui/modal.js +11 -2
  98. package/dist/ui/otp.js +835 -0
  99. package/dist/ui/select.js +67 -3
  100. package/dist/ui/shadow/accordion.js +31 -4
  101. package/dist/ui/shadow/alert.js +1 -1
  102. package/dist/ui/shadow/button-dropdown.js +1 -1
  103. package/dist/ui/shadow/chart.js +4 -4
  104. package/dist/ui/shadow/date.js +67 -6
  105. package/dist/ui/shadow/drawer.js +11 -2
  106. package/dist/ui/shadow/dropdown-table.js +62 -7
  107. package/dist/ui/shadow/dropdown.js +3 -2
  108. package/dist/ui/shadow/input.js +367 -261
  109. package/dist/ui/shadow/modal.js +11 -2
  110. package/dist/ui/shadow/otp.js +842 -0
  111. package/dist/ui/shadow/select.js +71 -6
  112. package/dist/ui/shadow/sidebar.js +2 -2
  113. package/dist/ui/shadow/slider.js +1082 -0
  114. package/dist/ui/shadow/table.js +6 -6
  115. package/dist/ui/shadow/tag-input.js +72 -7
  116. package/dist/ui/shadow/textarea.js +63 -2
  117. package/dist/ui/sidebar.js +2 -2
  118. package/dist/ui/slider.js +1079 -0
  119. package/dist/ui/table.js +2 -2
  120. package/dist/ui/tag-input.js +67 -3
  121. package/dist/ui/textarea.js +62 -1
  122. package/dist/ui/theme/luma.css +505 -466
  123. package/dist/ui/theme/lyra.css +505 -466
  124. package/dist/ui/theme/maia.css +501 -466
  125. package/dist/ui/theme/mira.css +505 -466
  126. package/dist/ui/theme/nova.css +503 -466
  127. package/dist/ui/theme/one.css +742 -699
  128. package/dist/ui/theme/rhea.css +506 -466
  129. package/dist/ui/theme/sera.css +507 -466
  130. package/dist/ui/theme/vega.css +495 -466
  131. package/dist/{vite-DcyRlTTf.js → vite-CivRCJaf.js} +2 -0
  132. package/dist/vite.js +1 -1
  133. package/dist/vue.d.ts +10 -0
  134. package/package.json +30 -15
  135. package/dist/input.css_raw-CGESifay.js +0 -5
@@ -7,11 +7,12 @@ import { t as monoDataGrid } from "./mono-data-grid-8jmeIXUU.js";
7
7
  import { d as OPERATOR_ARITY, l as treeToArray, m as operatorsFor, n as arrayToTree, s as odataStringToArray, t as arrayToODataString, u as DEFAULT_TEXTS } from "./filter-odata-Bi27XUpQ.js";
8
8
  import { t as monoFilterBuilder } from "./filter-builder-C0T3pMx2.js";
9
9
  import { a as resetMonoUI, g as resetMonoSkeleton, i as getMonoUIStatus, n as createMonoUI, o as getMonoSkeletonStatus, r as getMonoUI, s as isMonoSsrApp } from "./mono-ui-BwUc0L6B.js";
10
- import { t as monoForm } from "./mono-form-controller-IYn0MuUQ.js";
10
+ import { t as monoForm } from "./mono-form-controller-BkMR8g14.js";
11
11
  import { t as monoModal } from "./mono-modal-controller-ClObbHUs.js";
12
12
  import { i as composeApply, n as buildChartApply, r as buildChartOdataRequest, t as monoChart } from "./mono-data-chart-ChkelNT7.js";
13
13
  import { t as monoDataDropdown } from "./mono-data-dropdown-DxpUUk2y.js";
14
- import { a as resetMonoTooltip, n as createMonoTooltip, o as controlMonoTooltip, r as destroyAllMonoTooltips, s as monoTooltip, u as getMonoTooltipGlobal } from "./tooltip-FCMRUSLi.js";
15
- import { _ as DEFAULT_FLAVOR, a as flavors, b as themePresets, c as getCurrentFlavor, d as getThemeData, f as isValidFlavor, g as themes, h as resetTheme, i as createThemeClass, l as getCurrentTheme, m as resetFlavor, n as applyTheme, o as getAllFlavors, p as isValidTheme, r as createFlavorClass, s as getAllThemes, t as applyFlavor, u as getFlavorData, v as DEFAULT_THEME, y as flavorPresets } from "./index.node-dvrNviMx.js";
14
+ import { c as getMonoTooltipGlobal, o as monoTooltip, t as controlMonoTooltip } from "./control-tooltip-C3rA_nSH.js";
15
+ import { a as resetMonoTooltip, n as createMonoTooltip, r as destroyAllMonoTooltips } from "./tooltip-Drekihf5.js";
16
+ import { _ as DEFAULT_FLAVOR, a as flavors, b as themePresets, c as getCurrentFlavor, d as getThemeData, f as isValidFlavor, g as themes, h as resetTheme, i as createThemeClass, l as getCurrentTheme, m as resetFlavor, n as applyTheme, o as getAllFlavors, p as isValidTheme, r as createFlavorClass, s as getAllThemes, t as applyFlavor, u as getFlavorData, v as DEFAULT_THEME, y as flavorPresets } from "./index.node-DzCuvHLg.js";
16
17
 
17
18
  export { DEFAULT_ERROR_MESSAGES, DEFAULT_FLAVOR, DEFAULT_SEARCH_OPERATION, DEFAULT_THEME, OPERATOR_ARITY as MONO_FILTER_OPERATOR_ARITY, DEFAULT_TEXTS as MONO_FILTER_TEXTS, MonoSourceSearch, SEARCH_FIELDS_KEYS, applyFlavor, applyTheme, arrayToODataString, arrayToTree, buildChartApply, buildChartOdataRequest, buildGroups, collectGroupPaths, composeApply, monoChart as controlMonoChart, monoChart, monoDataDropdown as controlMonoDataDropdown, monoDataDropdown, monoFilterBuilder as controlMonoFilterBuilder, monoFilterBuilder, monoForm as controlMonoForm, monoForm, monoModal as controlMonoModal, monoModal, monoDataGrid as controlMonoTable, monoDataGrid, controlMonoTooltip, createFlavorClass, createMonoTooltip, createMonoUI, createThemeClass, describeError, destroyAllMonoTooltips, errorStatus, flattenLeaves, flavorPresets, flavors, getAllFlavors, getAllThemes, getCurrentFlavor, getCurrentTheme, getFieldValue, getFlavorData, getMonoSkeletonStatus, getMonoTooltipGlobal, getMonoUI, getMonoUIStatus, getThemeData, isFoldableSearch, isGroupNode, isMonoSsrApp, isPath, isValidFlavor, isValidTheme, mergePatch, mergeSearchFields, monoArraySource, operatorsFor as monoFilterOperatorsFor, monoTooltip, normalizeError, odataStringToArray, parseFieldPath, parseSearchValue, plainSearchFields, readSearchField, resetFlavor, resetMonoSkeleton, resetMonoTooltip, resetMonoUI, resetTheme, resolveErrorMessages, resolveMaybeReactive, resolveSearchFields, searchRemoteFilter, searchRowPredicate, setErrorMessages, setFieldValue, themePresets, themes, toODataClause, toODataSelector, treeToArray };
@@ -0,0 +1,251 @@
1
+ //#region src/components/input/input-format.ts
2
+ const SEPARATOR_CACHE = /* @__PURE__ */ new Map();
3
+ /**
4
+ * Ask `Intl` which characters this locale uses, rather than assuming `,` and `.`.
5
+ *
6
+ * Several locales use neither — `fr-FR` groups with a narrow no-break space, `de-CH` with an
7
+ * apostrophe — and a hardcoded pair would silently mangle them.
8
+ */
9
+ function localeSeparators(locale) {
10
+ const key = locale ?? "";
11
+ const cached = SEPARATOR_CACHE.get(key);
12
+ if (cached) return cached;
13
+ let separators = {
14
+ group: ",",
15
+ decimal: "."
16
+ };
17
+ try {
18
+ const parts = new Intl.NumberFormat(locale || void 0, {
19
+ useGrouping: true,
20
+ minimumFractionDigits: 1
21
+ }).formatToParts(12345.6);
22
+ separators = {
23
+ group: parts.find((p) => p.type === "group")?.value ?? ",",
24
+ decimal: parts.find((p) => p.type === "decimal")?.value ?? "."
25
+ };
26
+ } catch {}
27
+ SEPARATOR_CACHE.set(key, separators);
28
+ return separators;
29
+ }
30
+ /**
31
+ * Parse a pattern string into a descriptor, or `null` when it is not a pattern we understand.
32
+ *
33
+ * `null` is deliberately not an error: an unparseable pattern leaves the field an ordinary
34
+ * unformatted input rather than blanking it or throwing mid-keystroke.
35
+ */
36
+ function parseFormat(pattern) {
37
+ const raw = String(pattern ?? "");
38
+ if (!raw) return null;
39
+ const hole = raw.indexOf("{}");
40
+ if (hole !== -1) return {
41
+ kind: "template",
42
+ before: raw.slice(0, hole),
43
+ after: raw.slice(hole + 2)
44
+ };
45
+ let body = raw;
46
+ let prefix = "";
47
+ let suffix = "";
48
+ const leading = body.match(/^"([^"]*)"/);
49
+ if (leading) {
50
+ prefix = leading[1] ?? "";
51
+ body = body.slice(leading[0].length);
52
+ }
53
+ const trailing = body.match(/"([^"]*)"$/);
54
+ if (trailing) {
55
+ suffix = trailing[1] ?? "";
56
+ body = body.slice(0, body.length - trailing[0].length);
57
+ }
58
+ if (!body || !/^[#0,]*(?:\.[#0]*)?$/.test(body)) return null;
59
+ if (!/[#0]/.test(body)) return null;
60
+ const [intPart = "", fracPart] = body.split(".");
61
+ return {
62
+ kind: "number",
63
+ grouping: intPart.includes(","),
64
+ minFraction: fracPart ? (fracPart.match(/0/g) ?? []).length : 0,
65
+ maxFraction: fracPart ? fracPart.length : 0,
66
+ prefix,
67
+ suffix
68
+ };
69
+ }
70
+ /**
71
+ * Strip a formatted string back to its raw value.
72
+ *
73
+ * For numbers the result is always canonical — digits, an optional leading `-`, and `.` as the
74
+ * decimal point — whatever the locale draws with, so it is safe to hand to `Number()`.
75
+ */
76
+ /**
77
+ * Decide whether a GROUP character in the text is really the decimal point the user typed.
78
+ *
79
+ * It exists because the two roles collide: in `id-ID` the grouping character is `.`, so typing
80
+ * `0.9` produced `09` — the strip deleted the point before anything could read it as one. Yet
81
+ * `1.000` typed in the same field must keep meaning a thousand, and that is not a matter of
82
+ * guessing intent: the field re-strips its OWN formatted text on every keystroke, and
83
+ * `addGrouping` only ever emits runs of exactly three digits.
84
+ *
85
+ * So a group character is the decimal point when
86
+ * · the pattern has a fraction at all,
87
+ * · the locale's real decimal character is nowhere in the text (an explicit `1.000,5` wins), and
88
+ * · the digits after the LAST group character number at most `maxFraction` and are not exactly 3.
89
+ *
90
+ * A run of length ZERO qualifies deliberately: a trailing `0.` must survive, or the point is
91
+ * deleted the instant it is typed and `0.9` can never be reached left to right — `applyFormat`
92
+ * carries the matching rule that keeps a lone trailing point on screen.
93
+ *
94
+ * The consequence, and it is documented rather than worked around: under a dot-grouping locale a
95
+ * THREE-digit fraction (`0.123`) is unreachable by dot and has to be typed `0,123`.
96
+ *
97
+ * Returns the split, or `null` when every group character is grouping. Works for either locale
98
+ * shape — under `en-US` the roles are simply swapped and a typed `,` is promoted the same way.
99
+ */
100
+ function decimalGroupSplit(text, descriptor, group, decimal) {
101
+ if (descriptor.maxFraction <= 0) return null;
102
+ if (!group || group === decimal) return null;
103
+ if (text.includes(decimal)) return null;
104
+ const at = text.lastIndexOf(group);
105
+ if (at === -1) return null;
106
+ const tail = text.slice(at + group.length);
107
+ if (tail.length > descriptor.maxFraction || tail.length === 3) return null;
108
+ if (tail && !/^\d+$/.test(tail)) return null;
109
+ return {
110
+ head: text.slice(0, at),
111
+ tail
112
+ };
113
+ }
114
+ function stripFormat(text, descriptor, locale) {
115
+ const value = String(text ?? "");
116
+ if (!descriptor) return value;
117
+ if (descriptor.kind === "template") {
118
+ let out = value;
119
+ if (descriptor.before && out.startsWith(descriptor.before)) out = out.slice(descriptor.before.length);
120
+ if (descriptor.after && out.endsWith(descriptor.after)) out = out.slice(0, out.length - descriptor.after.length);
121
+ return out;
122
+ }
123
+ const { group, decimal } = localeSeparators(locale);
124
+ let out = value;
125
+ if (descriptor.prefix) out = out.split(descriptor.prefix).join("");
126
+ if (descriptor.suffix) out = out.split(descriptor.suffix).join("");
127
+ const promoted = decimalGroupSplit(out, descriptor, group, decimal);
128
+ if (promoted) out = `${promoted.head.split(group).join("")}.${promoted.tail}`;
129
+ else {
130
+ out = out.split(group).join("");
131
+ if (decimal !== ".") out = out.split(decimal).join(".");
132
+ }
133
+ const negative = out.trimStart().startsWith("-");
134
+ out = out.replace(/[^\d.]/g, "");
135
+ const first = out.indexOf(".");
136
+ if (first !== -1) out = out.slice(0, first + 1) + out.slice(first + 1).replace(/\./g, "");
137
+ if (descriptor.maxFraction === 0) out = out.split(".")[0] ?? "";
138
+ return negative && out ? `-${out}` : out;
139
+ }
140
+ /**
141
+ * Render a raw value for DISPLAY.
142
+ *
143
+ * The number branch deliberately does NOT hand the whole string to `Intl`: a value being typed is
144
+ * usually not yet a finished number, and `Intl` would tidy away exactly the characters the user is
145
+ * in the middle of writing — a trailing decimal point (`10000.`) and trailing fraction zeros
146
+ * (`10.50`) both vanish, which makes the field fight the person using it. Only the INTEGER part is
147
+ * grouped; the fraction is carried through verbatim, clamped to the pattern's ceiling.
148
+ */
149
+ function applyFormat(raw, descriptor, locale, opts = {}) {
150
+ const value = String(raw ?? "");
151
+ if (!descriptor) return value;
152
+ if (descriptor.kind === "template") {
153
+ if (!value) return "";
154
+ return `${descriptor.before}${value}${descriptor.after}`;
155
+ }
156
+ if (!value || value === "-") return value;
157
+ const negative = value.startsWith("-");
158
+ const unsigned = negative ? value.slice(1) : value;
159
+ const [intRaw = "", fracRaw] = unsigned.split(".");
160
+ const hasPoint = unsigned.includes(".");
161
+ const { group, decimal } = localeSeparators(locale);
162
+ const digits = intRaw.replace(/\D/g, "").replace(/^0+(?=\d)/, "");
163
+ const grouped = descriptor.grouping ? addGrouping(digits, group) : digits;
164
+ let fraction = (fracRaw ?? "").replace(/\D/g, "").slice(0, descriptor.maxFraction);
165
+ if (opts.pad && descriptor.minFraction > 0) fraction = fraction.padEnd(descriptor.minFraction, "0");
166
+ let out = grouped || (hasPoint ? "0" : "");
167
+ if (fraction) out += decimal + fraction;
168
+ else if (hasPoint && descriptor.maxFraction > 0 && !opts.pad) out += decimal;
169
+ if (!out) return "";
170
+ return `${descriptor.prefix}${negative ? "-" : ""}${out}${descriptor.suffix}`;
171
+ }
172
+ /** Group a digit string from the right. */
173
+ function addGrouping(digits, separator) {
174
+ if (digits.length < 4) return digits;
175
+ let out = "";
176
+ for (let i = 0; i < digits.length; i++) {
177
+ if (i > 0 && (digits.length - i) % 3 === 0) out += separator;
178
+ out += digits[i];
179
+ }
180
+ return out;
181
+ }
182
+ /**
183
+ * Normalise a raw value for the VALUE side.
184
+ *
185
+ * A number pattern yields a canonical numeric string (`"10000000.25"`) rather than the formatted
186
+ * text, so `Number(v)` works and a store that does arithmetic on it does not have to know a format
187
+ * was ever involved. A template yields the assembled string, because there the decoration IS the
188
+ * value — an email is not an email without its domain.
189
+ */
190
+ function normaliseValue(raw, descriptor) {
191
+ const value = String(raw ?? "");
192
+ if (!descriptor) return value;
193
+ if (descriptor.kind === "template") return value ? `${descriptor.before}${value}${descriptor.after}` : "";
194
+ if (!value || value === "-") return "";
195
+ const negative = value.startsWith("-");
196
+ const [intRaw = "", fracRaw] = (negative ? value.slice(1) : value).split(".");
197
+ const digits = intRaw.replace(/\D/g, "");
198
+ const fraction = (fracRaw ?? "").replace(/\D/g, "").slice(0, descriptor.maxFraction);
199
+ let out = digits.replace(/^0+(?=\d)/, "");
200
+ if (!out) out = digits ? "0" : "";
201
+ if (!out && !fraction) return "";
202
+ if (fraction) out = `${out || "0"}.${fraction}`;
203
+ return negative && out ? `-${out}` : out;
204
+ }
205
+ /**
206
+ * Where the caret belongs after the text was reformatted.
207
+ *
208
+ * Reformatting rewrites the whole field, and the browser then parks the caret at the end — so
209
+ * inserting a digit in the middle of a number would throw you to the end on every keystroke. The
210
+ * fix is to count in SIGNIFICANT characters (the ones the user actually typed) rather than in
211
+ * string offsets: count how many sit left of the caret before, then walk the new text until the
212
+ * same number have gone by.
213
+ */
214
+ function caretAfterFormat(next, caretInPrev, prev, isSignificant) {
215
+ let typed = 0;
216
+ for (let i = 0; i < Math.min(caretInPrev, prev.length); i++) if (isSignificant(prev[i])) typed++;
217
+ if (typed === 0) {
218
+ let i = 0;
219
+ while (i < next.length && !isSignificant(next[i])) i++;
220
+ return i;
221
+ }
222
+ let seen = 0;
223
+ for (let i = 0; i < next.length; i++) if (isSignificant(next[i])) {
224
+ seen++;
225
+ if (seen === typed) return i + 1;
226
+ }
227
+ return next.length;
228
+ }
229
+ /**
230
+ * Which characters count as "typed" for caret purposes — everything the format did NOT insert.
231
+ */
232
+ function significantFor(descriptor, locale) {
233
+ if (!descriptor || descriptor.kind === "template") return () => true;
234
+ const { decimal } = localeSeparators(locale);
235
+ return (ch) => /\d/.test(ch) || ch === decimal || ch === "-";
236
+ }
237
+ /** Resolve either form of a format prop to its finished text. */
238
+ function resolveFormat(format, raw, ctx, mode) {
239
+ if (format == null || format === "") return null;
240
+ if (typeof format === "function") return String(format({
241
+ value: raw,
242
+ type: ctx.type,
243
+ locale: ctx.locale
244
+ }) ?? "");
245
+ const descriptor = parseFormat(format);
246
+ if (!descriptor) return null;
247
+ return mode === "display" ? applyFormat(raw, descriptor, ctx.locale) : normaliseValue(raw, descriptor);
248
+ }
249
+
250
+ //#endregion
251
+ export { parseFormat as a, stripFormat as c, normaliseValue as i, caretAfterFormat as n, resolveFormat as o, localeSeparators as r, significantFor as s, applyFormat as t };
@@ -0,0 +1,5 @@
1
+ //#region \0raw:C:\Users\VCT-DEV\Desktop\libs\packages\helper\src\components\input\input.css?raw.js
2
+ var input_css_raw_default = "/* =========================================================================\n mono-input — a port of Basecoat's `.field` / `.input-group` / `.label`\n (basecoat-css@1.0.2, vega style).\n\n Styled by ATTRIBUTE, like Basecoat (`.input-group:has([aria-invalid])`) —\n and the attributes mirror the element's props one for one, so hand-written\n markup reads like the Lit / Vue tag:\n\n <mono-input size=\"sm\" color=\"danger\" variant=\"filled\" label=\"Name\">\n <div mono-input mono-size=\"sm\" mono-color=\"danger\" mono-variant=\"filled\">\n <label mono-label>Name</label>\n <div mono-field><input mono-native></div>\n </div>\n\n An absent attribute is the prop's default (`:not([mono-size])` = md,\n `:not([mono-color])` = primary, `:not([mono-variant])` = outlined,\n `:not([mono-validation-state])` = default). The element renders these\n attributes on its wrapper (both builds); the old classes\n (`.mono-input.sm.danger.filled`) are still emitted as inert hooks for\n consumer CSS until 2.0 but no rule here reads them.\n\n Selector map (ours ≡ upstream):\n [mono-input] ≡ .field (flex column, gap-3)\n [mono-input] > [mono-label] ≡ .field > label / .label\n [mono-input] > [mono-field] ≡ .input-group (the bordered box: h-9 rounded-md border-input shadow-xs)\n [mono-field] > [mono-native] ≡ .input-group > input (borderless, px-2.5 text-sm; `.input` for the metrics)\n [mono-field] > [mono-prefix|mono-suffix] ≡ .input-group > span[data-align='start'|'end']\n [mono-field] > [mono-clear] ≡ .input-group > button[data-align='end']:has(> svg)\n [mono-input] > [mono-message-wrap] ≡ .field > p\n [mono-message=\"helper\"] ≡ .field > p (text-sm text-muted-foreground)\n [mono-message=\"invalid\"] ≡ .field [role='alert']\n [mono-validation-state=\"invalid\"] ≡ .input-group:has([aria-invalid=true]) + .field[data-invalid]\n [mono-validation-state=\"valid|warning\"] ≡ EXTENSION (the invalid pattern with --success / --warning)\n [mono-size=\"xs|sm|lg|xl|xxl\"] ≡ EXTENSION (Basecoat sizes only the select; the ladder is --mono-control-height-*)\n [mono-variant=\"filled\"] ≡ EXTENSION (luma's .input-group: border-transparent bg-input/50, ring-ring/30)\n [mono-variant=\"underlined\"] ≡ EXTENSION (sera's .input-group: rounded-none border-b-input px-0, no ring)\n [mono-disabled] / [mono-native]:disabled ≡ .input-group:has(input:disabled) — opacity-50\n [mono-readonly] ≡ EXTENSION (a muted surface)\n\n Specificity contract (same as the pre-port class sheet, and as checkbox.css):\n a part's RESTING rule is written `:where([mono-input]) [mono-part]` = exactly\n one attribute, (0,1,0) — so a utility class composed onto the markup (the\n `cssClass` prop, or a hand-written class in a css/ demo) wins by source order,\n while the prop and state rules ([mono-size], [mono-variant], [mono-disabled],\n :focus-within, [aria-invalid], …) stay heavier and still win over it.\n\n Inner parts are attributes too: [mono-label] (+ [mono-required-mark]),\n [mono-field], [mono-prefix] / [mono-suffix] (+ [mono-empty] in the shadow\n build for an unassigned slot), [mono-native], [mono-clear] > [mono-icon],\n [mono-message-wrap] > [mono-message=\"helper|valid|invalid|warning\"].\n\n Values are copied from the compiled vendor sheet (vendor/basecoat/basecoat-\n vega.cdn.css) through the token layer: `--spacing` → `--mono-spacing`,\n `--text-sm` → `--mono-text-sm`, `--radius-md` → `--mono-radius-md`,\n `--color-x` → `--x`, Tailwind's `--tw-ring-*` stack → the two-slot\n `box-shadow: ring, shadow` below, and every `dark:` variant → a\n `--mono-mode-*` token (a selector cannot cross a shadow boundary; an\n inherited custom property can).\n\n FLAVORS (Basecoat's other seven styles, src/data/theme/flavors/*.css) set\n the knobs read below — `--mono-input-radius`, `--mono-input-padding-x-<size>`,\n `--mono-input-font-<size>`, `--mono-input-line-height`, `--mono-input-ring-width`,\n `--mono-input-ring-alpha`, `--mono-input-gap`, `--mono-input-affix-*`,\n `--mono-input-label-*`, `--mono-input-message-*`, `--mono-input-clear-radius`,\n `--mono-input-disabled-bg`, and the outline-variant set `--mono-input-outline-\n {bg,border-color,side-border-color,shadow,ring-width,radius,padding-x,affix-padding}`.\n Every fallback here is vega's value\n (`node scripts/basecoat-styles.mjs --varying \"^\\.(field|label|input|input-group)\\b\"`).\n\n The public `--mono-input-*` knobs and the three-tier resolver\n (`--mono-input-x` → `--_mono-input-x-preset` → base) are unchanged: a\n colour / variant attribute only ever writes a `*-preset` slot, so a\n consumer's own `--mono-input-bg` on the host still wins.\n ========================================================================= */\n\nmono-input {\n display: block;\n}\n\n[mono-input] {\n /* ── palette: each slot is a public knob over a Basecoat token ─────────── */\n --_mono-input-text: var(--mono-input-color, var(--mono-input-text, var(--foreground)));\n --_mono-input-placeholder: var(--mono-input-placeholder, var(--muted-foreground));\n --_mono-input-muted: var(--mono-input-muted, var(--muted-foreground));\n /* the `color` prop picks the FOCUS colour; primary is Basecoat's `--ring` */\n --_mono-input-primary: var(--mono-input-primary, var(--ring));\n --_mono-input-secondary: var(--mono-input-secondary, var(--muted-foreground));\n --_mono-input-success: var(--mono-input-success, var(--success));\n --_mono-input-danger: var(--mono-input-danger, var(--destructive));\n --_mono-input-warning: var(--mono-input-warning, var(--warning));\n --_mono-input-info: var(--mono-input-info, var(--info));\n --_mono-input-teal: var(--mono-input-teal, var(--teal));\n --_mono-input-purple: var(--mono-input-purple, var(--purple));\n --_mono-input-neutral: var(--mono-input-neutral, var(--neutral));\n --_mono-input-dark: var(--mono-input-dark, var(--dark));\n --_mono-input-valid: var(--mono-input-valid, var(--success));\n --_mono-input-invalid: var(--mono-input-invalid, var(--destructive));\n /* the FILL colour of a range (Basecoat paints the slider with --primary, not\n --ring); the `color` prop writes the preset, a validation state outranks it */\n --_mono-input-accent: var(--mono-input-accent, var(--_mono-input-accent-preset, var(--mono-input-primary, var(--primary))));\n\n /* ── the painted result — three tiers, base = .input-group (vega) ──────── */\n --_mono-input-ring-color: var(--mono-input-ring-color, var(--mono-input-focus-color, var(--_mono-input-ring-color-preset, var(--_mono-input-primary))));\n --_mono-input-ring-width: var(--mono-input-ring-width, var(--_mono-input-ring-width-preset, var(--mono-ring-width)));\n --_mono-input-ring-alpha: var(--mono-input-ring-alpha, var(--mono-ring-alpha));\n --_mono-input-border-color: var(--mono-input-rest-border, var(--mono-input-border-color, var(--_mono-input-border-color-preset, var(--input))));\n --_mono-input-bg: var(--mono-input-bg, var(--mono-input-surface, var(--_mono-input-bg-preset, var(--mono-mode-surface))));\n --_mono-input-shadow: var(--mono-input-shadow, var(--_mono-input-shadow-preset, 0 0 #0000));\n --_mono-input-affix-padding: var(--mono-input-affix-padding, var(--_mono-input-affix-padding-preset, calc(var(--mono-spacing) * 2)));\n --_mono-input-affix-icon: var(--mono-input-affix-icon-size, calc(var(--mono-spacing) * 4));\n\n /* ── md metrics live on the unqualified root ON PURPOSE: hand-written\n `<div mono-input>` that names no size renders exactly like size=\"md\".\n basecoat@1.0.2 styles/vega.css .input-group — h-9 rounded-md; > input px-2.5 text-sm ── */\n --_mono-input-height: var(--mono-input-height-md, var(--mono-control-height-md));\n --_mono-input-radius: var(--mono-input-radius-md, var(--_mono-input-radius-preset, var(--mono-input-radius, var(--mono-radius-md))));\n --_mono-input-padding-x: var(--mono-input-padding-x-md, var(--_mono-input-padding-x-preset, calc(var(--mono-spacing) * 2.5)));\n --_mono-input-font-size: var(--mono-input-font-md, var(--mono-text-sm));\n --_mono-input-line-height: var(--mono-input-line-height, var(--mono-input-line-height-md, var(--mono-text-sm--lh)));\n --_mono-input-clear: calc(var(--mono-spacing) * 6);\n --_mono-input-clear-glyph: calc(var(--mono-spacing) * 3.5);\n\n /* basecoat@1.0.2 styles/vega.css .field — flex w-full flex-col gap-3 */\n display: flex;\n flex-direction: column;\n gap: var(--mono-input-gap, calc(var(--mono-spacing) * 3));\n width: 100%;\n font-family: inherit;\n color: var(--_mono-input-text);\n}\n\n/* A page-level `* { box-sizing: border-box }` reset does NOT cross a shadow\n boundary; scoped here so both builds measure the same. */\n[mono-input],\n:where([mono-input]) *,\n:where([mono-input]) *::before,\n:where([mono-input]) *::after {\n box-sizing: border-box;\n}\n\n/* The shadow build renders every slot wrapper and marks an unassigned one\n `mono-empty`; the light build simply omits it. Inert in the light build. */\n:where([mono-input]) :is([mono-label], [mono-prefix], [mono-suffix], [mono-message])[mono-empty] {\n display: none;\n}\n\n/* =========================================\n Sizes — the field's painted height IS the token (tests/perf/field-heights).\n EXTENSION: Basecoat sizes only its select (data-size=sm); the ladder is the\n shared --mono-control-height-* scale and the text follows .btn's steps.\n ========================================= */\n\n/* `.input` is text-base under 48rem (no iOS zoom) and md:text-sm above it —\n vendor behaviour, kept for the default size only. */\n@media (width < 48rem) {\n [mono-input]:is(:not([mono-size]), [mono-size=\"md\"]) {\n --_mono-input-font-size: var(--mono-input-font-md, var(--mono-text-base));\n --_mono-input-line-height: var(--mono-input-line-height, var(--mono-input-line-height-md, var(--mono-text-base--lh)));\n }\n}\n\n[mono-input][mono-size=\"xs\"] {\n --_mono-input-height: var(--mono-input-height-xs, var(--mono-control-height-xs));\n --_mono-input-radius: var(--mono-input-radius-xs, var(--_mono-input-radius-preset, var(--mono-input-radius, var(--mono-radius-md))));\n --_mono-input-padding-x: var(--mono-input-padding-x-xs, var(--_mono-input-padding-x-preset, calc(var(--mono-spacing) * 2)));\n --_mono-input-font-size: var(--mono-input-font-xs, var(--mono-text-xs));\n --_mono-input-line-height: var(--mono-input-line-height, var(--mono-input-line-height-xs, var(--mono-text-xs--lh)));\n --_mono-input-affix-icon: var(--mono-input-affix-icon-size, calc(var(--mono-spacing) * 3.5));\n --_mono-input-clear: calc(var(--mono-spacing) * 4);\n --_mono-input-clear-glyph: calc(var(--mono-spacing) * 3);\n}\n\n[mono-input][mono-size=\"sm\"] {\n --_mono-input-height: var(--mono-input-height-sm, var(--mono-control-height-sm));\n --_mono-input-radius: var(--mono-input-radius-sm, var(--_mono-input-radius-preset, var(--mono-input-radius, var(--mono-radius-md))));\n --_mono-input-padding-x: var(--mono-input-padding-x-sm, var(--_mono-input-padding-x-preset, calc(var(--mono-spacing) * 2.5)));\n --_mono-input-font-size: var(--mono-input-font-sm, var(--mono-input-font-md, var(--mono-text-sm)));\n --_mono-input-line-height: var(--mono-input-line-height, var(--mono-input-line-height-sm, var(--mono-text-sm--lh)));\n --_mono-input-clear: calc(var(--mono-spacing) * 5);\n --_mono-input-clear-glyph: calc(var(--mono-spacing) * 3.5);\n}\n\n[mono-input][mono-size=\"lg\"] {\n --_mono-input-height: var(--mono-input-height-lg, var(--mono-control-height-lg));\n --_mono-input-radius: var(--mono-input-radius-lg, var(--_mono-input-radius-preset, var(--mono-input-radius, var(--mono-radius-md))));\n --_mono-input-padding-x: var(--mono-input-padding-x-lg, var(--_mono-input-padding-x-preset, calc(var(--mono-spacing) * 2.5)));\n --_mono-input-font-size: var(--mono-input-font-lg, var(--mono-input-font-md, var(--mono-text-sm)));\n --_mono-input-line-height: var(--mono-input-line-height, var(--mono-input-line-height-lg, var(--mono-text-sm--lh)));\n}\n\n[mono-input][mono-size=\"xl\"] {\n --_mono-input-height: var(--mono-input-height-xl, var(--mono-control-height-xl));\n --_mono-input-radius: var(--mono-input-radius-xl, var(--_mono-input-radius-preset, var(--mono-input-radius, var(--mono-radius-md))));\n --_mono-input-padding-x: var(--mono-input-padding-x-xl, var(--_mono-input-padding-x-preset, calc(var(--mono-spacing) * 3)));\n --_mono-input-font-size: var(--mono-input-font-xl, var(--mono-text-base));\n --_mono-input-line-height: var(--mono-input-line-height, var(--mono-input-line-height-xl, var(--mono-text-base--lh)));\n --_mono-input-affix-icon: var(--mono-input-affix-icon-size, calc(var(--mono-spacing) * 5));\n --_mono-input-clear: calc(var(--mono-spacing) * 7);\n --_mono-input-clear-glyph: calc(var(--mono-spacing) * 4);\n}\n\n[mono-input][mono-size=\"xxl\"] {\n --_mono-input-height: var(--mono-input-height-xxl, var(--mono-control-height-xxl));\n --_mono-input-radius: var(--mono-input-radius-xxl, var(--_mono-input-radius-preset, var(--mono-input-radius, var(--mono-radius-md))));\n --_mono-input-padding-x: var(--mono-input-padding-x-xxl, var(--_mono-input-padding-x-preset, calc(var(--mono-spacing) * 4)));\n --_mono-input-font-size: var(--mono-input-font-xxl, var(--mono-text-lg));\n --_mono-input-line-height: var(--mono-input-line-height, var(--mono-input-line-height-xxl, var(--mono-text-lg--lh)));\n --_mono-input-affix-icon: var(--mono-input-affix-icon-size, calc(var(--mono-spacing) * 5));\n --_mono-input-clear: calc(var(--mono-spacing) * 8);\n --_mono-input-clear-glyph: calc(var(--mono-spacing) * 4);\n}\n\n/* =========================================\n Variants — each writes only `*-preset` slots\n ========================================= */\n\n/* basecoat@1.0.2 styles/vega.css .input-group — rounded-md border border-input\n shadow-xs, bg-transparent (dark:bg-input/30 via --mono-mode-surface). The\n `--mono-input-outline-*` knobs are how a flavor restyles THIS variant alone\n (maia bg-input/30, luma / rhea border-transparent bg-input/50, sera the\n underline) without touching filled / underlined. */\n[mono-input]:is(:not([mono-variant]), [mono-variant=\"outlined\"]) {\n --_mono-input-bg-preset: var(--mono-input-outline-bg);\n --_mono-input-border-color-preset: var(--mono-input-outline-border-color);\n --_mono-input-side-border-color-preset: var(--mono-input-outline-side-border-color);\n --_mono-input-shadow-preset: var(--mono-input-outline-shadow, var(--mono-shadow-xs));\n --_mono-input-ring-width-preset: var(--mono-input-outline-ring-width);\n --_mono-input-radius-preset: var(--mono-input-outline-radius);\n --_mono-input-padding-x-preset: var(--mono-input-outline-padding-x);\n --_mono-input-affix-padding-preset: var(--mono-input-outline-affix-padding);\n}\n\n/* EXTENSION — filled ≡ basecoat@1.0.2 styles/luma.css .input-group:\n border-transparent bg-input/50, no shadow-xs (the ring stays) */\n[mono-input][mono-variant=\"filled\"] {\n --_mono-input-bg-preset: var(--mono-input-filled-bg, color-mix(in oklab, var(--input) 50%, transparent));\n --_mono-input-border-color-preset: transparent;\n --_mono-input-shadow-preset: 0 0 #0000;\n}\n\n/* EXTENSION — underlined ≡ basecoat@1.0.2 styles/sera.css .input-group:\n rounded-none border-transparent border-b-input bg-transparent px-0, no\n shadow, no ring, focus-within:border-b-ring, has-[aria-invalid]:border-b-destructive.\n Only the bottom edge paints; the sides are transparent in every state. */\n[mono-input][mono-variant=\"underlined\"] {\n --_mono-input-bg-preset: transparent;\n --_mono-input-side-border-color-preset: transparent;\n --_mono-input-shadow-preset: 0 0 #0000;\n --_mono-input-ring-width-preset: 0px;\n --_mono-input-radius-preset: 0;\n --_mono-input-padding-x-preset: 0;\n --_mono-input-affix-padding-preset: 0;\n}\n\n/* =========================================\n Colours — the `color` prop is the FOCUS colour (ring + focused border).\n No resting tint: Basecoat fields rest on --input whatever their role.\n ========================================= */\n\n[mono-input]:is(:not([mono-color]), [mono-color=\"primary\"]) {\n --_mono-input-ring-color-preset: var(--_mono-input-primary);\n}\n[mono-input][mono-color=\"secondary\"] {\n --_mono-input-ring-color-preset: var(--_mono-input-secondary);\n --_mono-input-accent-preset: var(--_mono-input-secondary);\n}\n[mono-input][mono-color=\"success\"] {\n --_mono-input-ring-color-preset: var(--_mono-input-success);\n --_mono-input-accent-preset: var(--_mono-input-success);\n}\n[mono-input][mono-color=\"danger\"] {\n --_mono-input-ring-color-preset: var(--_mono-input-danger);\n --_mono-input-accent-preset: var(--_mono-input-danger);\n}\n[mono-input][mono-color=\"warning\"] {\n --_mono-input-ring-color-preset: var(--_mono-input-warning);\n --_mono-input-accent-preset: var(--_mono-input-warning);\n}\n[mono-input][mono-color=\"info\"] {\n --_mono-input-ring-color-preset: var(--_mono-input-info);\n --_mono-input-accent-preset: var(--_mono-input-info);\n}\n[mono-input][mono-color=\"teal\"] {\n --_mono-input-ring-color-preset: var(--_mono-input-teal);\n --_mono-input-accent-preset: var(--_mono-input-teal);\n}\n[mono-input][mono-color=\"purple\"] {\n --_mono-input-ring-color-preset: var(--_mono-input-purple);\n --_mono-input-accent-preset: var(--_mono-input-purple);\n}\n[mono-input][mono-color=\"neutral\"] {\n --_mono-input-ring-color-preset: var(--_mono-input-neutral);\n --_mono-input-accent-preset: var(--_mono-input-neutral);\n}\n[mono-input][mono-color=\"dark\"] {\n --_mono-input-ring-color-preset: var(--_mono-input-dark);\n --_mono-input-accent-preset: var(--_mono-input-dark);\n}\n\n/* =========================================\n Label\n ========================================= */\n\n/* basecoat@1.0.2 styles/vega.css .field > label, .label — flex items-center\n gap-2 text-sm leading-none font-medium select-none w-fit */\n:where([mono-input]) > [mono-label] {\n display: flex;\n align-items: center;\n width: fit-content;\n gap: var(--mono-input-label-gap, calc(var(--mono-spacing) * 2));\n font-size: var(--mono-input-label-font-size, var(--mono-text-sm));\n line-height: var(--mono-input-label-line-height, 1);\n font-weight: var(--mono-input-label-font-weight, var(--mono-label-font-weight, var(--mono-font-weight-medium)));\n text-transform: var(--mono-input-label-text-transform, none);\n letter-spacing: var(--mono-input-label-letter-spacing, normal);\n color: var(--_mono-input-text);\n user-select: none;\n}\n\n/* in-data-[disabled=true]:opacity-50 / peer-disabled:opacity-50 */\n[mono-input][mono-disabled] > [mono-label],\n[mono-input]:has(> [mono-field] > [mono-native]:disabled) > [mono-label] {\n opacity: 0.5;\n pointer-events: none;\n}\n\n/* basecoat@1.0.2 styles/vega.css .field — data-invalid:text-destructive */\n[mono-input][mono-validation-state=\"invalid\"] > [mono-label],\n[mono-input]:has(> [mono-field] > [mono-native][aria-invalid=\"true\"]) > [mono-label] {\n color: var(--_mono-input-invalid);\n}\n\n/* EXTENSION — the required asterisk */\n:where([mono-input]) [mono-required-mark] {\n color: var(--_mono-input-danger);\n}\n\n/* `tooltip` prop — the info icon at the end of the label row (the label's\n flex gap spaces it). `pointer-events` is restored because a disabled field\n switches its label's off, and a disabled field is exactly where the reason\n is worth a hover. Knobs: --mono-input-label-tooltip-size / -color / -opacity. */\n:where([mono-input]) > [mono-label] > [mono-label-tooltip] {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n font-size: var(--mono-input-label-tooltip-size, 1.1em);\n color: var(--mono-input-label-tooltip-color, currentColor);\n opacity: var(--mono-input-label-tooltip-opacity, 0.6);\n border-radius: 9999px;\n cursor: help;\n pointer-events: auto;\n outline: none;\n transition: opacity 150ms ease;\n}\n\n:where([mono-input]) > [mono-label] > [mono-label-tooltip]:is(:hover, :focus-visible) {\n opacity: 1;\n}\n\n:where([mono-input]) > [mono-label] > [mono-label-tooltip]:focus-visible {\n outline: 2px solid currentColor;\n outline-offset: 2px;\n}\n\n:where([mono-input]) > [mono-label] > [mono-label-tooltip] > [mono-icon] {\n width: 1em;\n height: 1em;\n}\n\n/* =========================================\n The field — the bordered box\n ========================================= */\n\n/* basecoat@1.0.2 components/input-group.css .input-group */\n/* basecoat@1.0.2 styles/vega.css .input-group — h-9 rounded-md border\n border-input shadow-xs transition-[color,box-shadow] focus-within:border-ring\n focus-within:ring-3 focus-within:ring-ring/50; mono: `--tw-ring-*` flattened to\n the ring + shadow slots, the height is the control token, and the side\n edges read their own slot so a flavor can keep only the bottom one */\n:where([mono-input]) > [mono-field] {\n --_mono-input-bc: var(--_mono-input-border-color);\n --_mono-input-side-bc: var(--mono-input-side-border-color, var(--_mono-input-side-border-color-preset, var(--_mono-input-bc)));\n /* The focus / state ring slot — `0 0 #0000` until a state sets it. Kept as a\n slot so a variant can neutralise the resting shadow without ever writing\n `box-shadow: none` (which would out-specify the ring). */\n --_mono-input-ring: 0 0 #0000;\n\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n min-width: 0;\n min-height: var(--_mono-input-height);\n outline-style: none;\n border: var(--mono-border-width) solid var(--_mono-input-bc);\n border-top-color: var(--_mono-input-side-bc);\n border-inline-color: var(--_mono-input-side-bc);\n border-radius: var(--_mono-input-radius);\n background: var(--_mono-input-bg);\n color: var(--_mono-input-text);\n box-shadow: var(--_mono-input-ring), var(--_mono-input-shadow);\n transition-property: color, box-shadow, border-color, background-color;\n transition-timing-function: var(--mono-ease);\n transition-duration: var(--mono-duration);\n\n /* focus-within:border-ring focus-within:ring-3 focus-within:ring-ring/50 */\n &:focus-within {\n --_mono-input-bc: var(--_mono-input-ring-color);\n --_mono-input-ring: 0 0 0 var(--_mono-input-ring-width) color-mix(in oklab, var(--_mono-input-ring-color) var(--_mono-input-ring-alpha), transparent);\n }\n}\n\n/* basecoat@1.0.2 styles/vega.css .input-group — has-[[aria-invalid=true]]:border-destructive\n has-[[aria-invalid=true]]:ring-3 has-[[aria-invalid=true]]:ring-destructive/20\n (dark: border /50, ring /40 — carried by the mode tokens). The ring is\n permanent, and it wins over the focus ring — same as the vendor order. */\n[mono-input][mono-validation-state=\"invalid\"] > [mono-field],\n:where([mono-input]) > [mono-field]:has(> [mono-native][aria-invalid=\"true\"]) {\n --_mono-input-bc: var(--mono-mode-invalid-border);\n --_mono-input-ring: 0 0 0 var(--_mono-input-ring-width) var(--mono-mode-invalid-ring);\n}\n\n/* EXTENSION — valid / warning are the invalid pattern in the role's colour */\n[mono-input][mono-validation-state=\"valid\"] > [mono-field] {\n --_mono-input-bc: color-mix(in oklab, var(--_mono-input-valid) var(--mono-mode-state-border-alpha), transparent);\n --_mono-input-ring: 0 0 0 var(--_mono-input-ring-width) color-mix(in oklab, var(--_mono-input-valid) var(--mono-mode-state-ring-alpha), transparent);\n}\n[mono-input][mono-validation-state=\"warning\"] > [mono-field] {\n --_mono-input-bc: color-mix(in oklab, var(--_mono-input-warning) var(--mono-mode-state-border-alpha), transparent);\n --_mono-input-ring: 0 0 0 var(--_mono-input-ring-width) color-mix(in oklab, var(--_mono-input-warning) var(--mono-mode-state-ring-alpha), transparent);\n}\n\n/* EXTENSION — readonly: focusable, on a muted surface */\n[mono-input][mono-readonly] > [mono-field],\n:where([mono-input]) > [mono-field]:has(> [mono-native]:read-only:not(:disabled):not([mono-file]):not([mono-range])) {\n background: var(--mono-input-readonly-bg, var(--muted));\n}\n\n/* basecoat@1.0.2 styles/vega.css .input-group:has(> :is(input, textarea, select, [data-control]):disabled) — opacity-50\n (`--mono-input-disabled-bg`: nova / lyra add disabled:bg-input/50) */\n[mono-input][mono-disabled] > [mono-field],\n:where([mono-input]) > [mono-field]:has(> [mono-native]:disabled) {\n opacity: 0.5;\n cursor: not-allowed;\n background: var(--mono-input-disabled-bg, var(--_mono-input-bg));\n}\n\n/* =========================================\n The native input\n ========================================= */\n\n/* basecoat@1.0.2 components/input-group.css .input-group > :is(input, textarea, select, [data-control]) —\n block min-w-0 flex-1 appearance-none rounded-none border-0 bg-transparent\n text-foreground shadow-none outline-none placeholder:text-muted-foreground */\n/* basecoat@1.0.2 styles/vega.css .input-group > :is(input, select, [data-control])\n — px-2.5 py-1 text-sm; mono: no block padding — the FIELD owns the height\n (`min-height: token`) and `align-self: stretch` spans the click target */\n:where([mono-input]) [mono-native] {\n display: block;\n flex: 1 1 auto;\n width: 100%;\n min-width: 0;\n align-self: stretch;\n appearance: none;\n margin: 0;\n border: 0;\n border-radius: 0;\n outline: none;\n background: transparent;\n box-shadow: none;\n color: var(--_mono-input-text);\n font-family: inherit;\n font-size: var(--_mono-input-font-size);\n line-height: var(--_mono-input-line-height);\n padding-inline: var(--_mono-input-padding-x);\n padding-block: 0;\n\n &::placeholder {\n color: var(--_mono-input-placeholder);\n }\n\n /* .input:disabled — pointer-events-none cursor-not-allowed (the opacity is\n on the field so the affixes fade with it) */\n &:disabled {\n pointer-events: none;\n cursor: not-allowed;\n }\n\n &:read-only {\n cursor: inherit;\n }\n\n /* Kill the native focus outline in host projects; the field draws the ring. */\n &:focus,\n &:focus-visible {\n outline: none !important;\n }\n\n &[type='number']::-webkit-outer-spin-button,\n &[type='number']::-webkit-inner-spin-button {\n margin: 0;\n }\n}\n\n/* basecoat@1.0.2 styles/vega.css .input-group:not([data-orientation='vertical']):has(> :is([data-align='start'], [data-align='inline-start'])) > :is(input, select, [data-control]) — ps-1.5\n (and pe-1.5 for an end affix). The clear button counts as an end affix. */\n:where([mono-input]) > [mono-field]:has(> [mono-prefix]:not([mono-empty])) > [mono-native] {\n padding-inline-start: var(--mono-input-affix-gap, calc(var(--mono-spacing) * 1.5));\n}\n:where([mono-input]) > [mono-field]:has(> :is([mono-suffix]:not([mono-empty]), [mono-clear])) > [mono-native] {\n padding-inline-end: var(--mono-input-affix-gap, calc(var(--mono-spacing) * 1.5));\n}\n\n/* =========================================\n Prefix / suffix\n ========================================= */\n\n/* basecoat@1.0.2 styles/vega.css .input-group > :is(span, [role='group'], header, footer), .input-group > :is(svg, kbd, .popover, .dropdown-menu) — gap-2 py-1.5\n text-sm font-medium text-muted-foreground select-none, svg size-4;\n [data-align='start'] ps-2 / [data-align='end'] pe-2 */\n:where([mono-input]) [mono-prefix],\n:where([mono-input]) [mono-suffix] {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n gap: calc(var(--mono-spacing) * 2);\n font-size: var(--mono-input-affix-font-size, var(--_mono-input-font-size));\n line-height: var(--_mono-input-line-height);\n font-weight: var(--mono-font-weight-medium);\n color: var(--_mono-input-muted);\n user-select: none;\n}\n\n:where([mono-input]) [mono-prefix] {\n padding-inline-start: var(--_mono-input-affix-padding);\n}\n\n:where([mono-input]) [mono-suffix] {\n padding-inline-end: var(--_mono-input-affix-padding);\n}\n\n/* The light build re-appends slotted prefix/suffix content into this\n `[data-mono-slot]` placeholder, one level below the inline-flex wrapper.\n Make it a flex container too, so an `display: inline` icon span (e.g. a\n UnoCSS `i-mdi-*`, which ignores width/height while inline) is blockified\n into a flex item and actually renders its box. */\n:where([mono-input]) :is([mono-prefix], [mono-suffix]) > [data-mono-slot] {\n display: inline-flex;\n align-items: center;\n gap: inherit;\n}\n\n/* `[&>svg:not([class*='size-'])]:size-4` — our icons are UnoCSS `i-*` mask\n spans as often as SVGs, so every glyph in an affix takes the affix size. */\n:where([mono-input]) :is([mono-prefix], [mono-suffix]) :is(svg, .mono-icon, [mono-icon]),\n:where([mono-input]) :is([mono-prefix], [mono-suffix]) ::slotted(svg),\n:where([mono-input]) :is([mono-prefix], [mono-suffix]) ::slotted(.mono-icon),\n:where([mono-input]) :is([mono-prefix], [mono-suffix]) ::slotted([mono-icon]) {\n display: block;\n width: var(--_mono-input-affix-icon);\n height: var(--_mono-input-affix-icon);\n flex-shrink: 0;\n pointer-events: none;\n}\n\n/* =========================================\n Clear button — a ghost icon button in the end affix slot\n ========================================= */\n\n/* basecoat@1.0.2 styles/vega.css .input-group > :is(button, [role='group'] > button, header > button, footer > button):has(> svg):not(:has(> :not(svg)))\n — size-6 rounded-[calc(var(--radius)-5px)] p-0 shadow-none, svg size-3.5;\n .input-group > button[data-align='end'] me-1; painted as .btn[data-variant='ghost'] */\n:where([mono-input]) [mono-clear] {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--_mono-input-clear);\n height: var(--_mono-input-clear);\n padding: 0;\n margin: 0;\n margin-inline-end: var(--mono-spacing);\n border: 0;\n border-radius: var(--mono-input-clear-radius, calc(var(--radius) - 5px));\n background: transparent;\n box-shadow: none;\n color: var(--_mono-input-muted);\n font: inherit;\n line-height: 1;\n cursor: pointer;\n outline-style: none;\n transition-property: color, background-color, box-shadow;\n transition-timing-function: var(--mono-ease);\n transition-duration: var(--mono-duration);\n\n &:focus-visible {\n box-shadow: 0 0 0 var(--_mono-input-ring-width) color-mix(in oklab, var(--_mono-input-ring-color) var(--_mono-input-ring-alpha), transparent);\n }\n\n &:active {\n translate: 0 1px;\n }\n}\n\n/* basecoat@1.0.2 styles/vega.css .btn[data-variant='ghost'] — hover:bg-muted\n hover:text-foreground (dark:hover:bg-muted/50 via --mono-mode-ghost-hover) */\n@media (hover: hover) {\n :where([mono-input]) [mono-clear]:hover {\n background: var(--mono-mode-ghost-hover);\n color: var(--_mono-input-text);\n }\n}\n\n:where([mono-input]) [mono-clear] > :is(svg, .mono-icon, [mono-icon]) {\n display: block;\n width: var(--_mono-input-clear-glyph);\n height: var(--_mono-input-clear-glyph);\n pointer-events: none;\n}\n\n/* =========================================\n EXTENSION — type=\"file\": a read-only name field in front of a hidden native\n picker, with an upload glyph (`[mono-file-icon]`, a `[mono-suffix]`) at the\n end. The whole field reads as one button. The `mono-file` native is\n `readonly` only as a means — it stays off the muted read-only surface above\n unless `readonly` is actually set.\n ========================================= */\n\n:where([mono-input][mono-type=\"file\"]) > [mono-field],\n:where([mono-input][mono-type=\"file\"]) [mono-native][mono-file],\n:where([mono-input][mono-type=\"file\"]) [mono-file-icon] {\n cursor: pointer;\n}\n\n:where([mono-input][mono-type=\"file\"]) [mono-native][mono-file] {\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n\n:where([mono-input][mono-type=\"file\"][mono-readonly]) :is([mono-field], [mono-native][mono-file], [mono-file-icon]) {\n cursor: default;\n}\n\n:where([mono-input][mono-type=\"file\"][mono-disabled]) :is([mono-field], [mono-native][mono-file], [mono-file-icon]) {\n cursor: not-allowed;\n}\n\n:where([mono-input]) [mono-file-input] {\n display: none !important;\n}\n\n/* =========================================\n type=\"range\" — a port of Basecoat's components/range.css (`.field > input[type='range']`)\n\n [mono-input][mono-type=\"range\"] the root; `> [mono-field]` loses its box (a Basecoat\n range sits straight in the .field, no .input-group)\n [mono-native][mono-range] ≡ .field > input[type='range'] (h-5, the track + thumb)\n [mono-range-value] EXTENSION — the value readout: end of the label row, or\n after the slider when there is no label (EJI ONE's\n `.eji-range__row`; Basecoat has no readout)\n\n The fill is upstream's gradient stop: the element writes the position as\n `--mono-input-range-value` (upstream `--slider-value`) inline on the native,\n and raw markup sets it itself. The track/thumb paint in currentColor, and the\n native's `color` is the ACCENT (`--_mono-input-accent`: the `color` prop, or a\n validation state), so a flavor that wants the accent writes `currentColor`\n — a flavor block may never read a `--_mono-*` private.\n\n Knobs (vega fallbacks below; every Basecoat style + ONE writes its own in\n flavors/*.css, `node scripts/basecoat-styles.mjs --varying \"range\"`):\n --mono-input-range-{height, gap, track-height, track-radius, track-bg, fill,\n thumb-size, thumb-width, thumb-radius, thumb-bg, thumb-border-width,\n thumb-border-color, thumb-shadow, thumb-ring-width, thumb-ring-color,\n ring-width, hover-ring-width, label-color, label-font-size, label-line-height,\n label-font-weight, value-color,\n value-font-family, value-font-size, value-font-weight, value-min-width}.\n A flavor sets the md geometry only: `size` multiplies it (xs .75 … xxl\n 1.375), so every flavor keeps a whole xs→xxl ladder.\n ========================================= */\n\n[mono-input][mono-type=\"range\"] {\n --_mono-input-range-scale: 1;\n gap: var(--mono-input-range-gap, var(--mono-input-gap, calc(var(--mono-spacing) * 3)));\n}\n[mono-input][mono-type=\"range\"][mono-size=\"xs\"] { --_mono-input-range-scale: 0.75; }\n[mono-input][mono-type=\"range\"][mono-size=\"sm\"] { --_mono-input-range-scale: 0.875; }\n[mono-input][mono-type=\"range\"][mono-size=\"lg\"] { --_mono-input-range-scale: 1.125; }\n[mono-input][mono-type=\"range\"][mono-size=\"xl\"] { --_mono-input-range-scale: 1.25; }\n[mono-input][mono-type=\"range\"][mono-size=\"xxl\"] { --_mono-input-range-scale: 1.375; }\n\n/* a validation state recolours the fill + thumb (after the colour rules, so it wins) */\n[mono-input][mono-type=\"range\"][mono-validation-state=\"invalid\"] { --_mono-input-accent-preset: var(--_mono-input-invalid); }\n[mono-input][mono-type=\"range\"][mono-validation-state=\"valid\"] { --_mono-input-accent-preset: var(--_mono-input-valid); }\n[mono-input][mono-type=\"range\"][mono-validation-state=\"warning\"] { --_mono-input-accent-preset: var(--_mono-input-warning); }\n\n/* No .input-group around a Basecoat range: the field keeps only its flex row\n (prefix / slider / readout / suffix). Placed after the readonly / disabled\n field rules, which it ties, so the box stays off in every state; the\n disabled opacity is kept. */\n[mono-input][mono-type=\"range\"] > [mono-field] {\n gap: calc(var(--mono-spacing) * 3);\n min-height: 0;\n border-width: 0;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n}\n\n[mono-input][mono-type=\"range\"] :is([mono-prefix], [mono-suffix]) {\n padding-inline: 0;\n}\n\n/* the label spans the row so the readout can sit at its end (EJI ONE) */\n[mono-input][mono-type=\"range\"] > [mono-label] {\n width: 100%;\n font-size: var(--mono-input-range-label-font-size, var(--mono-input-label-font-size, var(--mono-text-sm)));\n line-height: var(--mono-input-range-label-line-height, var(--mono-input-label-line-height, 1));\n color: var(--mono-input-range-label-color, var(--_mono-input-text));\n font-weight: var(--mono-input-range-label-font-weight, var(--mono-input-label-font-weight, var(--mono-label-font-weight, var(--mono-font-weight-medium))));\n}\n\n/* basecoat@1.0.2 components/range.css .field > input[type='range'], .input[type='range'] — flex appearance-none items-center\n p-0 outline-none disabled:pointer-events-none disabled:opacity-50 (the opacity is the field's) */\n/* basecoat@1.0.2 styles/vega.css .field > input[type='range'], .input[type='range'] — h-5, --slider-track-height: 0.375rem, --slider-thumb-size: 1rem */\n[mono-native][mono-range] {\n --_mono-input-range-track-h: round(nearest, calc(var(--mono-input-range-track-height, 0.375rem) * var(--_mono-input-range-scale, 1)), 1px);\n --_mono-input-range-thumb-h: round(nearest, calc(var(--mono-input-range-thumb-size, 1rem) * var(--_mono-input-range-scale, 1)), 1px);\n --_mono-input-range-thumb-w: round(nearest, calc(var(--mono-input-range-thumb-width, var(--mono-input-range-thumb-size, 1rem)) * var(--_mono-input-range-scale, 1)), 1px);\n --_mono-input-range-fill: var(--mono-input-range-fill, currentColor);\n --_mono-input-range-track: var(--mono-input-range-track-bg, var(--muted));\n --_mono-input-range-dir: to right;\n --_mono-input-range-ring-w: var(--mono-input-range-ring-width, 4px);\n --_mono-input-range-hover-ring-w: var(--mono-input-range-hover-ring-width, var(--_mono-input-range-ring-w));\n --_mono-input-range-ring-c: color-mix(in oklab, var(--_mono-input-ring-color) var(--_mono-input-ring-alpha), transparent);\n /* the hover / focus halo slot — `0 0 #0000` at rest */\n --_mono-input-range-halo: 0 0 #0000;\n\n display: flex;\n align-items: center;\n flex: 1 1 auto;\n width: 100%;\n min-width: 0;\n height: max(round(nearest, calc(var(--mono-input-range-height, 1.25rem) * var(--_mono-input-range-scale, 1)), 1px), var(--_mono-input-range-thumb-h));\n margin: 0;\n padding: 0;\n appearance: none;\n background: transparent;\n color: var(--_mono-input-accent);\n cursor: pointer;\n outline: none;\n\n &:dir(rtl) {\n --_mono-input-range-dir: to left;\n }\n\n /* basecoat@1.0.2 styles/vega.css :is(.field > input[type='range'], .input[type='range'])::-webkit-slider-runnable-track — bg-muted h-1.5 rounded-full\n (+ components/range.css: w-full appearance-none, the --primary / --muted gradient stop) */\n &::-webkit-slider-runnable-track {\n width: 100%;\n height: var(--_mono-input-range-track-h);\n appearance: none;\n border-radius: var(--mono-input-range-track-radius, 9999px);\n background: linear-gradient(var(--_mono-input-range-dir), var(--_mono-input-range-fill) var(--mono-input-range-value, 20%), var(--_mono-input-range-track) var(--mono-input-range-value, 20%));\n }\n\n &::-moz-range-track {\n width: 100%;\n height: var(--_mono-input-range-track-h);\n appearance: none;\n border-radius: var(--mono-input-range-track-radius, 9999px);\n background: linear-gradient(var(--_mono-input-range-dir), var(--_mono-input-range-fill) var(--mono-input-range-value, 20%), var(--_mono-input-range-track) var(--mono-input-range-value, 20%));\n }\n\n /* basecoat@1.0.2 styles/vega.css :is(.field > input[type='range'], .input[type='range'])::-webkit-slider-thumb — border-primary ring-ring/50 size-4\n rounded-full border bg-white shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4\n -mt-[calc((var(--slider-thumb-size)-var(--slider-track-height))/2)]; mono: border-box, so\n size-4 is the painted size whatever the border; the ring is three slots — a\n resting ring (luma / rhea ring-1, ONE's navy rim), the halo, the shadow */\n &::-webkit-slider-thumb {\n display: block;\n flex-shrink: 0;\n box-sizing: border-box;\n width: var(--_mono-input-range-thumb-w);\n height: var(--_mono-input-range-thumb-h);\n margin-top: calc((var(--_mono-input-range-track-h) - var(--_mono-input-range-thumb-h)) / 2);\n appearance: none;\n border: var(--mono-input-range-thumb-border-width, 1px) solid var(--mono-input-range-thumb-border-color, currentColor);\n border-radius: var(--mono-input-range-thumb-radius, 9999px);\n background: var(--mono-input-range-thumb-bg, #fff);\n box-shadow:\n 0 0 0 var(--mono-input-range-thumb-ring-width, 0px) var(--mono-input-range-thumb-ring-color, transparent),\n var(--_mono-input-range-halo),\n var(--mono-input-range-thumb-shadow, var(--mono-shadow-sm));\n transition-property: color, box-shadow, background-color, border-color;\n transition-timing-function: var(--mono-ease);\n transition-duration: var(--mono-duration);\n }\n\n &::-moz-range-thumb {\n display: block;\n flex-shrink: 0;\n box-sizing: border-box;\n width: var(--_mono-input-range-thumb-w);\n height: var(--_mono-input-range-thumb-h);\n appearance: none;\n border: var(--mono-input-range-thumb-border-width, 1px) solid var(--mono-input-range-thumb-border-color, currentColor);\n border-radius: var(--mono-input-range-thumb-radius, 9999px);\n background: var(--mono-input-range-thumb-bg, #fff);\n box-shadow:\n 0 0 0 var(--mono-input-range-thumb-ring-width, 0px) var(--mono-input-range-thumb-ring-color, transparent),\n var(--_mono-input-range-halo),\n var(--mono-input-range-thumb-shadow, var(--mono-shadow-sm));\n transition-property: color, box-shadow, background-color, border-color;\n transition-timing-function: var(--mono-ease);\n transition-duration: var(--mono-duration);\n }\n\n /* focus-visible:ring-4 focus-visible:outline-hidden */\n &:focus-visible {\n --_mono-input-range-halo: 0 0 0 var(--_mono-input-range-ring-w) var(--_mono-input-range-ring-c);\n }\n\n &:disabled {\n pointer-events: none;\n }\n}\n\n/* hover:ring-4 (lyra / mira / nova also active:) */\n@media (hover: hover) {\n [mono-native][mono-range]:hover:not(:disabled, :focus-visible) {\n --_mono-input-range-halo: 0 0 0 var(--_mono-input-range-hover-ring-w) var(--_mono-input-range-ring-c);\n }\n}\n[mono-native][mono-range]:active:not(:disabled, :focus-visible) {\n --_mono-input-range-halo: 0 0 0 var(--_mono-input-range-hover-ring-w) var(--_mono-input-range-ring-c);\n}\n\n/* readonly: a native range ignores `readonly`, so the element reverts any move;\n the pointer is switched off so a drag never even starts */\n[mono-input][mono-readonly] [mono-native][mono-range] {\n pointer-events: none;\n cursor: default;\n}\n\n/* EXTENSION — the value readout (EJI ONE `.eji-range__val`: the number is always\n on screen). Tabular figures so the row does not shimmer while dragging. */\n:where([mono-input]) [mono-range-value] {\n flex: none;\n margin-inline-start: auto;\n font-family: var(--mono-input-range-value-font-family, inherit);\n font-size: var(--mono-input-range-value-font-size, var(--mono-input-range-label-font-size, var(--mono-input-label-font-size, var(--mono-text-sm))));\n font-weight: var(--mono-input-range-value-font-weight, var(--mono-font-weight-medium));\n line-height: var(--mono-input-range-label-line-height, var(--mono-input-label-line-height, 1));\n font-variant-numeric: tabular-nums;\n color: var(--mono-input-range-value-color, var(--_mono-input-muted));\n white-space: nowrap;\n user-select: none;\n}\n\n/* after the slider (no label): a reserved width, so the track does not resize\n as the number gains a digit */\n:where([mono-input]) > [mono-field] > [mono-range-value] {\n min-width: var(--mono-input-range-value-min-width, 3ch);\n text-align: end;\n}\n\n/* =========================================\n Message — helper / validation text under the field\n ========================================= */\n\n/* basecoat@1.0.2 styles/vega.css .fieldset legend + p, .field > p, .field section > p — text-sm text-muted-foreground\n leading-normal font-normal text-start. The wrapper is always rendered\n (aria-describedby points at it); it takes no space until it holds text. */\n:where([mono-input]) > [mono-message-wrap] {\n display: block;\n}\n\n:where([mono-input]) > [mono-message-wrap]:not(:has([mono-message]:not([mono-empty]))) {\n display: none;\n}\n\n:where([mono-input]) [mono-message] {\n font-size: var(--mono-input-message-font-size, var(--mono-text-sm));\n line-height: var(--mono-input-message-line-height, var(--mono-leading-normal));\n font-weight: var(--mono-font-weight-normal);\n text-align: start;\n color: var(--_mono-input-muted);\n}\n\n/* basecoat@1.0.2 styles/vega.css .field [role=\"alert\"] — text-destructive text-sm */\n:where([mono-input]) [mono-message=\"invalid\"] {\n color: var(--_mono-input-invalid);\n}\n\n/* EXTENSION — the other two states in their role colour */\n:where([mono-input]) [mono-message=\"valid\"] {\n color: var(--_mono-input-valid);\n}\n\n:where([mono-input]) [mono-message=\"warning\"] {\n color: var(--_mono-input-warning);\n}\n\n@media (prefers-reduced-motion: reduce) {\n :where([mono-input]) > [mono-field],\n :where([mono-input]) [mono-clear] {\n transition: none;\n }\n}\n\n/* =========================================\n label-position — the slots form/label-position.css reads\n (top / notched / left / right; public knobs: --mono-input-label-width,\n -label-side-gap, -label-notch-font-size, -label-notch-bg)\n ========================================= */\n\n[mono-input][mono-label-position] {\n --_mono-lp-width: var(--mono-input-label-width, auto);\n --_mono-lp-gap: var(--mono-input-label-side-gap, calc(var(--mono-spacing) * 3));\n --_mono-lp-height: var(--_mono-input-height);\n --_mono-lp-box-min: var(--_mono-input-height);\n --_mono-lp-padding-x: var(--_mono-input-padding-x);\n --_mono-lp-padding-y: 0px;\n --_mono-lp-font: var(--mono-input-label-notch-font-size, var(--mono-text-xs));\n --_mono-lp-notch-bg: var(--mono-input-label-notch-bg, var(--background));\n --_mono-lp-field-bg: var(--_mono-input-bg);\n}\n";
3
+
4
+ //#endregion
5
+ export { input_css_raw_default as t };
@@ -1,8 +1,9 @@
1
1
  import { t as createNotifier } from "./notifier-BIrqUzRh.js";
2
2
  import { a as parseFieldPath, c as toODataClause, l as toODataSelector, n as isPath, o as projectFields, r as mergePatch, s as setFieldValue, t as getFieldValue } from "./field-path-BabiMrrA.js";
3
- import { A as compileFilterPredicate, D as searchEntryFor, E as resolveSearchEntries, O as andFilters, S as hasWildcardSearch, T as plainSearchColumns, a as describeError, h as mergeSearchFields, j as joinFilters, k as andPredicates, l as isCanceled, n as unwrapReactive, p as DEFAULT_SEARCH_FIELDS, v as customPredicate, x as hasCustomSearch, y as customRemoteClause } from "./reactive-DFCdZbH9.js";
4
- import { a as buildGroups, c as isGroupNode, i as searchFilterOf, o as collectGroupPaths, r as readAllRows, s as flattenLeaves } from "./data-source-read-Cuqw3LcP.js";
5
- import { a as resolveDataSourceOptions, c as composeSummaryApply, d as createApplyGate, f as isRolledUp, h as monoArraySource, i as normalizeSortList, l as summaryAliases, m as storeRows, n as extraLoadOptions, o as toList, p as loadApply, s as buildSummaryApply, t as dataSourceOptionsKey, u as summaryFilterOf } from "./data-source-options-Bk-UoaZV.js";
3
+ import { C as resolveSearchEntries, D as compileFilterPredicate, E as andPredicates, O as joinFilters, S as plainSearchColumns, T as andFilters, f as mergeSearchFields, g as customRemoteClause, h as customPredicate, n as describeError, o as isCanceled, u as DEFAULT_SEARCH_FIELDS, v as hasCustomSearch, w as searchEntryFor, y as hasWildcardSearch } from "./normalize-error-BmLbgANw.js";
4
+ import { a as buildGroups, c as isGroupNode, i as searchFilterOf, o as collectGroupPaths, r as readAllRows, s as flattenLeaves } from "./data-source-read-i6CYSUEl.js";
5
+ import { a as resolveDataSourceOptions, c as composeSummaryApply, d as createApplyGate, f as isRolledUp, h as monoArraySource, i as normalizeSortList, l as summaryAliases, m as storeRows, n as extraLoadOptions, o as toList, p as loadApply, s as buildSummaryApply, t as dataSourceOptionsKey, u as summaryFilterOf } from "./data-source-options-Cz9fVLK8.js";
6
+ import { n as unwrapReactive } from "./reactive-Dtd-esHO.js";
6
7
  import { t as arrayToODataString } from "./filter-odata-Bi27XUpQ.js";
7
8
  import { t as monoFilterBuilder } from "./filter-builder-B6Y2mmbM.js";
8
9
 
@@ -3907,7 +3908,7 @@ function monoDataGrid(ds = null, opts = {}) {
3907
3908
  });
3908
3909
  }
3909
3910
  async function exportReport(options) {
3910
- const { exportTable } = await import("./export-B91P6J1y.js");
3911
+ const { exportTable } = await import("./export-DgomqI_3.js");
3911
3912
  return exportTable(options);
3912
3913
  }
3913
3914
  function subscribe(cb) {
@@ -20,10 +20,16 @@ function sizeOf(value) {
20
20
  if (value == null) return 0;
21
21
  return String(value).length;
22
22
  }
23
+ let warnedUnknownSchema = false;
23
24
  /**
24
- * Run one schema-shaped rule. Duck-typed so yup works without @mono-lit/helper
25
- * depending on it: prefer `validateSync`, fall back to `validate` (which may be
26
- * a promise). The schema's OWN message wins over the rule's `message`.
25
+ * Run one schema-shaped rule. Duck-typed so neither yup nor Valibot is a
26
+ * dependency of @mono-lit/helper. The schema's OWN message wins over the
27
+ * rule's `message`.
28
+ *
29
+ * - yup-shaped (`validateSync` / `validate` that THROW): checked first, because
30
+ * yup ≥1.7 also exposes `~standard` and its own path keeps its exact messages.
31
+ * - Standard Schema (`schema['~standard'].validate`, which RETURNS issues):
32
+ * Valibot, Zod, ArkType, … — sync or async.
27
33
  */
28
34
  async function runSchema(schema, value) {
29
35
  try {
@@ -35,6 +41,15 @@ async function runSchema(schema, value) {
35
41
  await schema.validate(value);
36
42
  return true;
37
43
  }
44
+ const standard = schema["~standard"];
45
+ if (typeof standard?.validate === "function") {
46
+ const result = await standard.validate(value);
47
+ return result.issues?.length ? result.issues[0].message || "Invalid" : true;
48
+ }
49
+ if (!warnedUnknownSchema) {
50
+ warnedUnknownSchema = true;
51
+ console.warn("[mono-form] rule.schema is neither yup-shaped nor a Standard Schema (e.g. Valibot); it is ignored:", schema);
52
+ }
38
53
  return true;
39
54
  } catch (err) {
40
55
  const e = err;
@@ -1045,51 +1045,4 @@ function isCanceled(err) {
1045
1045
  }
1046
1046
 
1047
1047
  //#endregion
1048
- //#region src/composables/reactive.ts
1049
- /**
1050
- * Unwrap a `ref()` / `computed()` wrapper and a `reactive()` proxy to the raw
1051
- * target underneath. Returns the value unchanged when it isn't reactive.
1052
- */
1053
- function unwrapReactive(value) {
1054
- let out = value;
1055
- if (out && typeof out === "object" && out.__v_isRef) out = out.value;
1056
- if (out && typeof out === "object" && out.__v_raw) out = out.__v_raw;
1057
- return out;
1058
- }
1059
- /**
1060
- * Read a {@link MaybeReactive} option: call a getter, unwrap a ref/computed or a
1061
- * reactive proxy, unbox a plain `{ value }`. Never caches — the caller decides
1062
- * when "now" is.
1063
- */
1064
- function resolveMaybeReactive(option) {
1065
- if (option === void 0 || option === null) return void 0;
1066
- if (typeof option === "function") return option();
1067
- const raw = unwrapReactive(option);
1068
- if (raw && typeof raw === "object") {
1069
- const keys = Object.keys(raw);
1070
- if (keys.length === 1 && keys[0] === "value") return unwrapReactive(raw.value);
1071
- }
1072
- return raw;
1073
- }
1074
- /**
1075
- * {@link unwrapReactive}, then — for an **array** — unwrap each element too.
1076
- *
1077
- * Reading an index off a deep-reactive array yields a proxy of that element, so
1078
- * unwrapping only the container still leaves proxies inside. One level of
1079
- * elements is all the value models here need; this deliberately does not recurse
1080
- * into nested objects, which would rewrite data the consumer owns.
1081
- */
1082
- function unwrapReactiveDeep(value) {
1083
- const out = unwrapReactive(value);
1084
- if (!Array.isArray(out)) return out;
1085
- let changed = false;
1086
- const items = out.map((item) => {
1087
- const raw = unwrapReactive(item);
1088
- if (raw !== item) changed = true;
1089
- return raw;
1090
- });
1091
- return changed ? items : out;
1092
- }
1093
-
1094
- //#endregion
1095
- export { compileFilterPredicate as A, isWildcardPattern as C, searchEntryFor as D, resolveSearchEntries as E, andFilters as O, hasWildcardSearch as S, plainSearchColumns as T, searchRowPredicate as _, describeError as a, expandWildcard as b, errorTitle as c, resolveErrorMessages as d, setErrorMessages as f, resolveSearchFields as g, mergeSearchFields as h, DEFAULT_ERROR_MESSAGES as i, joinFilters as j, andPredicates as k, isCanceled as l, MonoSourceSearch as m, unwrapReactive as n, errorStatus as o, DEFAULT_SEARCH_FIELDS as p, unwrapReactiveDeep as r, errorText as s, resolveMaybeReactive as t, normalizeError as u, customPredicate as v, normalizeSearchExpr as w, hasCustomSearch as x, customRemoteClause as y };
1048
+ export { resolveSearchEntries as C, compileFilterPredicate as D, andPredicates as E, joinFilters as O, plainSearchColumns as S, andFilters as T, expandWildcard as _, errorTitle as a, isWildcardPattern as b, resolveErrorMessages as c, MonoSourceSearch as d, mergeSearchFields as f, customRemoteClause as g, customPredicate as h, errorText as i, setErrorMessages as l, searchRowPredicate as m, describeError as n, isCanceled as o, resolveSearchFields as p, errorStatus as r, normalizeError as s, DEFAULT_ERROR_MESSAGES as t, DEFAULT_SEARCH_FIELDS as u, hasCustomSearch as v, searchEntryFor as w, normalizeSearchExpr as x, hasWildcardSearch as y };
package/dist/nuxt.js CHANGED
@@ -1,8 +1,39 @@
1
- import { t as monoSsr } from "./vite-DcyRlTTf.js";
1
+ import { t as monoSsr } from "./vite-CivRCJaf.js";
2
2
  import { join } from "node:path";
3
3
  import { pathToFileURL } from "node:url";
4
- import { addPluginTemplate, addVitePlugin, defineNuxtModule, extendViteConfig, hasNuxtModule, installModule, tryResolveModule, useLogger } from "@nuxt/kit";
4
+ import { addComponent, addPlugin, addPluginTemplate, addVitePlugin, createResolver, defineNuxtModule, extendViteConfig, hasNuxtModule, tryResolveModule, useLogger } from "@nuxt/kit";
5
5
 
6
+ //#region src/nuxt/ssr-lit/index.ts
7
+ async function installSsrLit(nuxt) {
8
+ const { resolve } = createResolver(import.meta.url);
9
+ const runtimeDir = resolve("./ssr-lit/runtime");
10
+ nuxt.options.build.transpile.push(runtimeDir);
11
+ const nitro = nuxt.options.nitro;
12
+ nitro.moduleSideEffects ||= [];
13
+ nitro.moduleSideEffects.push("@lit-labs/ssr/lib/render-lit-html.js");
14
+ nuxt.options.vite.ssr ||= {};
15
+ const ssrExternal = nuxt.options.vite.ssr.external;
16
+ if (Array.isArray(ssrExternal)) {
17
+ if (!ssrExternal.includes("@vue/server-renderer")) ssrExternal.push("@vue/server-renderer");
18
+ } else if (ssrExternal === void 0) nuxt.options.vite.ssr.external = ["@vue/server-renderer"];
19
+ addPlugin(resolve(runtimeDir, "plugins/antiFouc.server"));
20
+ addPlugin(resolve(runtimeDir, "plugins/polyfill.client"));
21
+ addPlugin(resolve(runtimeDir, "plugins/hydrateSupport.client"));
22
+ await addComponent({
23
+ name: "LitWrapper",
24
+ filePath: resolve(runtimeDir, "components/LitWrapper.vue")
25
+ });
26
+ await addComponent({
27
+ name: "LitWrapperClient",
28
+ filePath: resolve(runtimeDir, "components/LitWrapperClient.vue")
29
+ });
30
+ await addComponent({
31
+ name: "LitWrapperServer",
32
+ filePath: resolve(runtimeDir, "components/LitWrapperServer.vue")
33
+ });
34
+ }
35
+
36
+ //#endregion
6
37
  //#region src/nuxt/index.ts
7
38
  /** The optional peer the automatic skeleton (`pending`) renders with. */
8
39
  const PHANTOM_UI = "@aejkatappaja/phantom-ui";
@@ -30,15 +61,12 @@ const monoHelperModule = defineNuxtModule({
30
61
  const phantom = helper.skeleton === false ? null : await tryResolveModule(PHANTOM_UI, appAnchor);
31
62
  if (!phantom && helper.skeleton !== false) logger.debug(`skeleton: "${PHANTOM_UI}" is not installed in the app — \`pending\` stays a no-op. Install it to turn the automatic skeleton on.`);
32
63
  let litWrapper = false;
33
- if (helper.ssr !== false && !ssrApp) logger.debug("ssr:false — skipping nuxt-ssr-lit; shadow builds render client-side as plain custom elements.");
64
+ if (helper.ssr !== false && !ssrApp) logger.debug("ssr:false — skipping the Lit SSR bridge; shadow builds render client-side as plain custom elements.");
34
65
  else if (helper.ssr !== false) {
35
66
  if (hasNuxtModule("nuxt-ssr-lit")) logger.info("nuxt-ssr-lit is configured by the host — using legacy manual SSR wiring (litElementPrefix). Remove that module entry to enable @mono-lit/helper auto-wrap, or set mono.helper.ssr:false to silence.");
36
- else try {
37
- const ssrLit = await tryResolveModule("nuxt-ssr-lit", import.meta.url);
38
- await installModule(ssrLit ?? "nuxt-ssr-lit", { litElementPrefix: [] });
67
+ else {
68
+ await installSsrLit(nuxt);
39
69
  litWrapper = true;
40
- } catch {
41
- logger.info("nuxt-ssr-lit could not be loaded — mono shadow components fall back to client-only. It ships as a @mono-lit/helper dependency, so this usually means a broken or deduped install; try reinstalling, or set mono.helper.ssr:false to silence.");
42
70
  }
43
71
  }
44
72
  if (ssrApp || clientOnlyWrap) {
@@ -1,4 +1,4 @@
1
- import { a as unregisterPopupLayer, r as registerPopupLayer } from "./popup-stack-De05Y-mJ.js";
1
+ import { i as registerPopupLayer, n as pathInLayerAbove, o as unregisterPopupLayer } from "./popup-stack-C64WCuXq.js";
2
2
  import { isServer } from "lit";
3
3
 
4
4
  //#region src/composables/popup-portal.ts
@@ -388,10 +388,26 @@ var PopupPortalController = class {
388
388
  * in the library asks this method.
389
389
  */
390
390
  containsInPath(path) {
391
+ return this.containsEventPath(path) || this.inLayerAbove(path);
392
+ }
393
+ /**
394
+ * PopupLayer hook — this popup's OWN containment: its portaled panel or a popup
395
+ * opened from inside it. Never the layers above (that is `inLayerAbove`), so
396
+ * `pathInLayerAbove` walking the stack does not recurse.
397
+ */
398
+ containsEventPath(path) {
391
399
  if (this._portal && path.includes(this._portal)) return true;
392
400
  return this.ownsNestedInPath(path);
393
401
  }
394
402
  /**
403
+ * True when the path lands in a layer opened ABOVE this popup while it is open
404
+ * — a modal opened from a figure in this panel, say. That layer is on top of the
405
+ * panel, not outside it, so its clicks, focus and Escape are not a dismiss.
406
+ */
407
+ inLayerAbove(path) {
408
+ return this._registered && pathInLayerAbove(this, path);
409
+ }
410
+ /**
395
411
  * True when the path passes through a popup opened from INSIDE this one
396
412
  * (at any depth) — not this popup's own panel.
397
413
  *
@@ -187,6 +187,26 @@ function setExternalScrollLock(owner, wanted) {
187
187
  function getOpenPopupLayers() {
188
188
  return stack;
189
189
  }
190
+ /**
191
+ * True when an event's composed path lands inside a layer opened AFTER `layer`
192
+ * — one stacked above it.
193
+ *
194
+ * The other half of the "topmost only" rule modal and drawer apply to their own
195
+ * outside click. A dropdown open under a dialog that was opened from its panel
196
+ * (a figure in a tag-input option opening a breakdown modal) must not read a
197
+ * click or focus in that dialog as "outside": the dialog is not behind the
198
+ * panel, it is on top of it. Ownership (`pathOwnedBy`) cannot tell, because the
199
+ * dialog's element usually lives elsewhere on the page, not inside the panel.
200
+ *
201
+ * A layer opened BEFORE `layer` (the modal a dropdown sits in) is below it and
202
+ * does not count, so a click in that modal's body still closes the dropdown.
203
+ */
204
+ function pathInLayerAbove(layer, path) {
205
+ const idx = stack.indexOf(layer);
206
+ if (idx === -1) return false;
207
+ for (let i = idx + 1; i < stack.length; i++) if (stack[i].containsEventPath?.(path)) return true;
208
+ return false;
209
+ }
190
210
 
191
211
  //#endregion
192
- export { unregisterPopupLayer as a, setExternalScrollLock as i, refreshPopupStack as n, registerPopupLayer as r, getOpenPopupLayers as t };
212
+ export { setExternalScrollLock as a, registerPopupLayer as i, pathInLayerAbove as n, unregisterPopupLayer as o, refreshPopupStack as r, getOpenPopupLayers as t };