@mono-lit/helper 0.0.4 → 0.0.6

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 (173) 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/{form-control-core-CIdMLXMo.js → form-control-core-rW2WvOcb.js} +1 -1
  15. package/dist/{hydration-flush-DHrl4_KK.js → hydration-flush-9AJE8FRl.js} +398 -1
  16. package/dist/index.js +6 -5
  17. package/dist/{index.node-dvrNviMx.js → index.node-tTkISFn2.js} +2 -2
  18. package/dist/index.node.js +6 -5
  19. package/dist/input-format-GrRCJBqV.js +251 -0
  20. package/dist/input.css_raw-CQu2fAsU.js +5 -0
  21. package/dist/{light-slots-DdDdZ6zs.js → light-slots-BnBR29E7.js} +1 -1
  22. package/dist/{light-slots-4ZCjOcBg.js → light-slots-Cb6e-LU3.js} +1 -1
  23. package/dist/{mono-button-CeDB9khW.js → mono-button-Cy5-Y0At.js} +3 -3
  24. package/dist/{mono-button.shadow-D9NdMsmH.js → mono-button.shadow-CIBGisyo.js} +1 -2
  25. package/dist/{mono-data-grid-BHlo1IgR.js → mono-data-grid-KDpu4d4_.js} +5 -4
  26. package/dist/{mono-element-C7vCschg.js → mono-element-Bc9wElPy.js} +1 -1
  27. package/dist/{mono-form-controller-IYn0MuUQ.js → mono-form-controller-BkMR8g14.js} +18 -3
  28. package/dist/mono-ui-KOBJcnXk.js +758 -0
  29. package/dist/{reactive-DFCdZbH9.js → normalize-error-BmLbgANw.js} +1 -48
  30. package/dist/nuxt.js +1 -1
  31. package/dist/{popup-portal-HWhkd7oy.js → popup-portal-C8ttHDRX.js} +17 -1
  32. package/dist/{popup-stack-De05Y-mJ.js → popup-stack-C64WCuXq.js} +21 -1
  33. package/dist/src/components/accordion/accordion-core.d.ts +4 -1
  34. package/dist/src/components/accordion/mono-accordion.shadow.d.ts +4 -1
  35. package/dist/src/components/date/date-core.d.ts +3 -0
  36. package/dist/src/components/date/date-types.d.ts +36 -1
  37. package/dist/src/components/drawer/drawer-core.d.ts +1 -0
  38. package/dist/src/components/dropdown-table/dropdown-table-core.d.ts +3 -0
  39. package/dist/src/components/dropdown-table/dropdown-table-types.d.ts +31 -0
  40. package/dist/src/components/form/form-types.d.ts +23 -5
  41. package/dist/src/components/input/index.d.ts +2 -2
  42. package/dist/src/components/input/index.shadow.d.ts +2 -2
  43. package/dist/src/components/input/input-core.d.ts +23 -3
  44. package/dist/src/components/input/input-types.d.ts +84 -9
  45. package/dist/src/components/input/mono-input.d.ts +3 -2
  46. package/dist/src/components/input/mono-input.shadow.d.ts +3 -2
  47. package/dist/src/components/modal/modal-core.d.ts +1 -0
  48. package/dist/src/components/otp/index.d.ts +5 -0
  49. package/dist/src/components/otp/index.shadow.d.ts +6 -0
  50. package/dist/src/components/otp/mono-otp.d.ts +32 -0
  51. package/dist/src/components/otp/mono-otp.shadow.d.ts +30 -0
  52. package/dist/src/components/otp/otp-core.d.ts +91 -0
  53. package/dist/src/components/otp/otp-types.d.ts +161 -0
  54. package/dist/src/components/otp/otp-utils.d.ts +41 -0
  55. package/dist/src/components/select/select-core.d.ts +3 -0
  56. package/dist/src/components/select/select-types.d.ts +31 -0
  57. package/dist/src/components/slider/index.d.ts +5 -0
  58. package/dist/src/components/slider/index.shadow.d.ts +6 -0
  59. package/dist/src/components/slider/mono-slider.d.ts +33 -0
  60. package/dist/src/components/slider/mono-slider.shadow.d.ts +29 -0
  61. package/dist/src/components/slider/slider-core.d.ts +77 -0
  62. package/dist/src/components/slider/slider-math.d.ts +102 -0
  63. package/dist/src/components/slider/slider-types.d.ts +188 -0
  64. package/dist/src/components/table/column-autosize.d.ts +74 -0
  65. package/dist/src/components/table/mono-data-grid.d.ts +10 -0
  66. package/dist/src/components/table/mono-table-th-core.d.ts +3 -0
  67. package/dist/src/components/table/table-types.d.ts +8 -1
  68. package/dist/src/components/tag-input/mono-tag-input.d.ts +12 -0
  69. package/dist/src/components/tag-input/mono-tag-input.shadow.d.ts +9 -1
  70. package/dist/src/components/tag-input/tag-input-core.d.ts +12 -1
  71. package/dist/src/components/tag-input/tag-input-types.d.ts +33 -0
  72. package/dist/src/components/textarea/textarea-core.d.ts +3 -0
  73. package/dist/src/components/textarea/textarea-types.d.ts +31 -0
  74. package/dist/src/composables/field-bubble.d.ts +34 -0
  75. package/dist/src/composables/field-icons.d.ts +10 -0
  76. package/dist/src/composables/field-tooltip.d.ts +52 -0
  77. package/dist/src/composables/field-validation.d.ts +58 -0
  78. package/dist/src/composables/mono-size-attrs.d.ts +10 -0
  79. package/dist/src/composables/popup-portal.d.ts +12 -0
  80. package/dist/src/composables/popup-stack.d.ts +21 -0
  81. package/dist/src/entries/index.d.ts +3 -2
  82. package/dist/src/entries/index.node.d.ts +3 -2
  83. package/dist/ssr-lit/runtime/components/LitWrapper.vue +11 -11
  84. package/dist/ssr-lit/runtime/components/LitWrapperClient.vue +11 -11
  85. package/dist/ssr-lit/runtime/components/LitWrapperServer.vue +38 -38
  86. package/dist/ssr-lit/runtime/plugins/antiFouc.server.js +25 -25
  87. package/dist/ssr-lit/runtime/plugins/hydrateSupport.client.js +4 -4
  88. package/dist/ssr-lit/runtime/plugins/polyfill.client.js +9 -9
  89. package/dist/ssr-lit/runtime/utils/customElements.js +11 -11
  90. package/dist/ssr-lit/runtime/utils/litElementRenderer.js +28 -28
  91. package/dist/{styles-D-ergrfR.js → styles-BODNpZV1.js} +1 -1
  92. package/dist/tooltip-Drekihf5.js +102 -0
  93. package/dist/tooltip-loader-3U9FTOXj.js +20 -0
  94. package/dist/tooltip-loader-Dcp9AUZn.js +23 -0
  95. package/dist/tooltip.js +3 -1
  96. package/dist/ui/accordion.js +19 -6
  97. package/dist/ui/alert.js +3 -3
  98. package/dist/ui/breadcrumb.js +3 -3
  99. package/dist/ui/button-dropdown.js +3 -3
  100. package/dist/ui/button.js +1 -1
  101. package/dist/ui/card.js +3 -3
  102. package/dist/ui/chart.js +3 -4
  103. package/dist/ui/checkbox.js +3 -3
  104. package/dist/ui/chip.js +2 -2
  105. package/dist/ui/date.js +68 -7
  106. package/dist/ui/drawer.js +14 -5
  107. package/dist/ui/dropdown-table.js +63 -9
  108. package/dist/ui/dropdown.js +6 -5
  109. package/dist/ui/file-upload.js +3 -3
  110. package/dist/ui/filter.js +2 -2
  111. package/dist/ui/form.js +1 -1
  112. package/dist/ui/index.css +4276 -2543
  113. package/dist/ui/input.js +365 -264
  114. package/dist/ui/menu.js +3 -3
  115. package/dist/ui/modal.js +15 -6
  116. package/dist/ui/nav.js +3 -3
  117. package/dist/ui/otp.js +834 -0
  118. package/dist/ui/radio.js +3 -3
  119. package/dist/ui/rich-text-editor.js +3 -4
  120. package/dist/ui/select.js +70 -7
  121. package/dist/ui/shadow/accordion.js +31 -4
  122. package/dist/ui/shadow/alert.js +2 -2
  123. package/dist/ui/shadow/breadcrumb.js +1 -1
  124. package/dist/ui/shadow/button-dropdown.js +3 -3
  125. package/dist/ui/shadow/button.js +1 -1
  126. package/dist/ui/shadow/card.js +1 -2
  127. package/dist/ui/shadow/chart.js +5 -6
  128. package/dist/ui/shadow/checkbox.js +2 -2
  129. package/dist/ui/shadow/chip.js +1 -1
  130. package/dist/ui/shadow/date.js +69 -9
  131. package/dist/ui/shadow/drawer.js +12 -3
  132. package/dist/ui/shadow/dropdown-table.js +64 -10
  133. package/dist/ui/shadow/dropdown.js +4 -3
  134. package/dist/ui/shadow/file-upload.js +2 -2
  135. package/dist/ui/shadow/filter.js +1 -2
  136. package/dist/ui/shadow/input.js +369 -264
  137. package/dist/ui/shadow/menu.js +1 -1
  138. package/dist/ui/shadow/modal.js +13 -4
  139. package/dist/ui/shadow/nav.js +1 -1
  140. package/dist/ui/shadow/otp.js +841 -0
  141. package/dist/ui/shadow/radio.js +2 -2
  142. package/dist/ui/shadow/rich-text-editor.js +2 -3
  143. package/dist/ui/shadow/select.js +74 -10
  144. package/dist/ui/shadow/sidebar.js +3 -3
  145. package/dist/ui/shadow/slider.js +1081 -0
  146. package/dist/ui/shadow/switch.js +2 -2
  147. package/dist/ui/shadow/table.js +40 -11
  148. package/dist/ui/shadow/tabs.js +1 -1
  149. package/dist/ui/shadow/tag-input.js +160 -15
  150. package/dist/ui/shadow/textarea.js +65 -5
  151. package/dist/ui/sidebar.js +5 -5
  152. package/dist/ui/slider.js +1078 -0
  153. package/dist/ui/switch.js +3 -3
  154. package/dist/ui/table.js +36 -7
  155. package/dist/ui/tabs.js +3 -3
  156. package/dist/ui/tag-input.js +167 -7
  157. package/dist/ui/textarea.js +65 -5
  158. package/dist/ui/theme/luma.css +505 -466
  159. package/dist/ui/theme/lyra.css +505 -466
  160. package/dist/ui/theme/maia.css +501 -466
  161. package/dist/ui/theme/mira.css +505 -466
  162. package/dist/ui/theme/nova.css +503 -466
  163. package/dist/ui/theme/one.css +742 -699
  164. package/dist/ui/theme/rhea.css +506 -466
  165. package/dist/ui/theme/sera.css +507 -466
  166. package/dist/ui/theme/vega.css +495 -466
  167. package/dist/{vite-DcyRlTTf.js → vite-CivRCJaf.js} +2 -0
  168. package/dist/vite.js +1 -1
  169. package/dist/vue.d.ts +10 -0
  170. package/package.json +31 -13
  171. package/dist/css-size-DWAPgQdT.js +0 -38
  172. package/dist/input.css_raw-CGESifay.js +0 -5
  173. package/dist/mono-ui-BwUc0L6B.js +0 -360
@@ -1,264 +1,16 @@
1
- import { a as __decorate, f as customElement, i as withShadowUtilityStyles, l as defineHybridPropAliases, r as toShadowCss, s as booleanStringConverter, t as flushSsrHydration } from "../../hydration-flush-DHrl4_KK.js";
1
+ import { _ as buildSizeStyle, a as __decorate, f as customElement, i as withShadowUtilityStyles, l as defineHybridPropAliases, r as toShadowCss, s as booleanStringConverter, t as flushSsrHydration } from "../../hydration-flush-9AJE8FRl.js";
2
2
  import { t as dispatchMonoEvent } from "../../mono-event-BPku9HpS.js";
3
3
  import { n as cssPart } from "../../css-class-B6Tc_MAx.js";
4
- import { t as buildSizeStyle } from "../../css-size-DWAPgQdT.js";
5
- import { t as MonoFormControlCore } from "../../form-control-core-CIdMLXMo.js";
6
- import { t as input_css_raw_default } from "../../input.css_raw-CGESifay.js";
4
+ import { a as parseFormat, c as stripFormat, i as normaliseValue, n as caretAfterFormat, o as resolveFormat, r as localeSeparators, s as significantFor, t as applyFormat } from "../../input-format-GrRCJBqV.js";
5
+ import { t as MonoFormControlCore } from "../../form-control-core-rW2WvOcb.js";
6
+ import { n as FieldTooltipController, t as field_tooltip_css_raw_default } from "../../field-tooltip.css_raw-DEctHXKm.js";
7
+ import { n as label_position_css_raw_default, r as FieldValidationController, t as field_validation_css_raw_default } from "../../field-validation.css_raw-B3Iu33rS.js";
8
+ import { t as input_css_raw_default } from "../../input.css_raw-CQu2fAsU.js";
7
9
  import { LitElement, html, isServer, nothing, unsafeCSS } from "lit";
8
10
  import { property, query, state } from "lit/decorators.js";
9
11
  import { ifDefined } from "lit/directives/if-defined.js";
10
12
  import { styleMap } from "lit/directives/style-map.js";
11
13
 
12
- //#region src/components/input/input-format.ts
13
- const SEPARATOR_CACHE = /* @__PURE__ */ new Map();
14
- /**
15
- * Ask `Intl` which characters this locale uses, rather than assuming `,` and `.`.
16
- *
17
- * Several locales use neither — `fr-FR` groups with a narrow no-break space, `de-CH` with an
18
- * apostrophe — and a hardcoded pair would silently mangle them.
19
- */
20
- function localeSeparators(locale) {
21
- const key = locale ?? "";
22
- const cached = SEPARATOR_CACHE.get(key);
23
- if (cached) return cached;
24
- let separators = {
25
- group: ",",
26
- decimal: "."
27
- };
28
- try {
29
- const parts = new Intl.NumberFormat(locale || void 0, {
30
- useGrouping: true,
31
- minimumFractionDigits: 1
32
- }).formatToParts(12345.6);
33
- separators = {
34
- group: parts.find((p) => p.type === "group")?.value ?? ",",
35
- decimal: parts.find((p) => p.type === "decimal")?.value ?? "."
36
- };
37
- } catch {}
38
- SEPARATOR_CACHE.set(key, separators);
39
- return separators;
40
- }
41
- /**
42
- * Parse a pattern string into a descriptor, or `null` when it is not a pattern we understand.
43
- *
44
- * `null` is deliberately not an error: an unparseable pattern leaves the field an ordinary
45
- * unformatted input rather than blanking it or throwing mid-keystroke.
46
- */
47
- function parseFormat(pattern) {
48
- const raw = String(pattern ?? "");
49
- if (!raw) return null;
50
- const hole = raw.indexOf("{}");
51
- if (hole !== -1) return {
52
- kind: "template",
53
- before: raw.slice(0, hole),
54
- after: raw.slice(hole + 2)
55
- };
56
- let body = raw;
57
- let prefix = "";
58
- let suffix = "";
59
- const leading = body.match(/^"([^"]*)"/);
60
- if (leading) {
61
- prefix = leading[1] ?? "";
62
- body = body.slice(leading[0].length);
63
- }
64
- const trailing = body.match(/"([^"]*)"$/);
65
- if (trailing) {
66
- suffix = trailing[1] ?? "";
67
- body = body.slice(0, body.length - trailing[0].length);
68
- }
69
- if (!body || !/^[#0,]*(?:\.[#0]*)?$/.test(body)) return null;
70
- if (!/[#0]/.test(body)) return null;
71
- const [intPart = "", fracPart] = body.split(".");
72
- return {
73
- kind: "number",
74
- grouping: intPart.includes(","),
75
- minFraction: fracPart ? (fracPart.match(/0/g) ?? []).length : 0,
76
- maxFraction: fracPart ? fracPart.length : 0,
77
- prefix,
78
- suffix
79
- };
80
- }
81
- /**
82
- * Strip a formatted string back to its raw value.
83
- *
84
- * For numbers the result is always canonical — digits, an optional leading `-`, and `.` as the
85
- * decimal point — whatever the locale draws with, so it is safe to hand to `Number()`.
86
- */
87
- /**
88
- * Decide whether a GROUP character in the text is really the decimal point the user typed.
89
- *
90
- * It exists because the two roles collide: in `id-ID` the grouping character is `.`, so typing
91
- * `0.9` produced `09` — the strip deleted the point before anything could read it as one. Yet
92
- * `1.000` typed in the same field must keep meaning a thousand, and that is not a matter of
93
- * guessing intent: the field re-strips its OWN formatted text on every keystroke, and
94
- * `addGrouping` only ever emits runs of exactly three digits.
95
- *
96
- * So a group character is the decimal point when
97
- * · the pattern has a fraction at all,
98
- * · the locale's real decimal character is nowhere in the text (an explicit `1.000,5` wins), and
99
- * · the digits after the LAST group character number at most `maxFraction` and are not exactly 3.
100
- *
101
- * A run of length ZERO qualifies deliberately: a trailing `0.` must survive, or the point is
102
- * deleted the instant it is typed and `0.9` can never be reached left to right — `applyFormat`
103
- * carries the matching rule that keeps a lone trailing point on screen.
104
- *
105
- * The consequence, and it is documented rather than worked around: under a dot-grouping locale a
106
- * THREE-digit fraction (`0.123`) is unreachable by dot and has to be typed `0,123`.
107
- *
108
- * Returns the split, or `null` when every group character is grouping. Works for either locale
109
- * shape — under `en-US` the roles are simply swapped and a typed `,` is promoted the same way.
110
- */
111
- function decimalGroupSplit(text, descriptor, group, decimal) {
112
- if (descriptor.maxFraction <= 0) return null;
113
- if (!group || group === decimal) return null;
114
- if (text.includes(decimal)) return null;
115
- const at = text.lastIndexOf(group);
116
- if (at === -1) return null;
117
- const tail = text.slice(at + group.length);
118
- if (tail.length > descriptor.maxFraction || tail.length === 3) return null;
119
- if (tail && !/^\d+$/.test(tail)) return null;
120
- return {
121
- head: text.slice(0, at),
122
- tail
123
- };
124
- }
125
- function stripFormat(text, descriptor, locale) {
126
- const value = String(text ?? "");
127
- if (!descriptor) return value;
128
- if (descriptor.kind === "template") {
129
- let out = value;
130
- if (descriptor.before && out.startsWith(descriptor.before)) out = out.slice(descriptor.before.length);
131
- if (descriptor.after && out.endsWith(descriptor.after)) out = out.slice(0, out.length - descriptor.after.length);
132
- return out;
133
- }
134
- const { group, decimal } = localeSeparators(locale);
135
- let out = value;
136
- if (descriptor.prefix) out = out.split(descriptor.prefix).join("");
137
- if (descriptor.suffix) out = out.split(descriptor.suffix).join("");
138
- const promoted = decimalGroupSplit(out, descriptor, group, decimal);
139
- if (promoted) out = `${promoted.head.split(group).join("")}.${promoted.tail}`;
140
- else {
141
- out = out.split(group).join("");
142
- if (decimal !== ".") out = out.split(decimal).join(".");
143
- }
144
- const negative = out.trimStart().startsWith("-");
145
- out = out.replace(/[^\d.]/g, "");
146
- const first = out.indexOf(".");
147
- if (first !== -1) out = out.slice(0, first + 1) + out.slice(first + 1).replace(/\./g, "");
148
- if (descriptor.maxFraction === 0) out = out.split(".")[0] ?? "";
149
- return negative && out ? `-${out}` : out;
150
- }
151
- /**
152
- * Render a raw value for DISPLAY.
153
- *
154
- * The number branch deliberately does NOT hand the whole string to `Intl`: a value being typed is
155
- * usually not yet a finished number, and `Intl` would tidy away exactly the characters the user is
156
- * in the middle of writing — a trailing decimal point (`10000.`) and trailing fraction zeros
157
- * (`10.50`) both vanish, which makes the field fight the person using it. Only the INTEGER part is
158
- * grouped; the fraction is carried through verbatim, clamped to the pattern's ceiling.
159
- */
160
- function applyFormat(raw, descriptor, locale, opts = {}) {
161
- const value = String(raw ?? "");
162
- if (!descriptor) return value;
163
- if (descriptor.kind === "template") {
164
- if (!value) return "";
165
- return `${descriptor.before}${value}${descriptor.after}`;
166
- }
167
- if (!value || value === "-") return value;
168
- const negative = value.startsWith("-");
169
- const unsigned = negative ? value.slice(1) : value;
170
- const [intRaw = "", fracRaw] = unsigned.split(".");
171
- const hasPoint = unsigned.includes(".");
172
- const { group, decimal } = localeSeparators(locale);
173
- const digits = intRaw.replace(/\D/g, "").replace(/^0+(?=\d)/, "");
174
- const grouped = descriptor.grouping ? addGrouping(digits, group) : digits;
175
- let fraction = (fracRaw ?? "").replace(/\D/g, "").slice(0, descriptor.maxFraction);
176
- if (opts.pad && descriptor.minFraction > 0) fraction = fraction.padEnd(descriptor.minFraction, "0");
177
- let out = grouped || (hasPoint ? "0" : "");
178
- if (fraction) out += decimal + fraction;
179
- else if (hasPoint && descriptor.maxFraction > 0 && !opts.pad) out += decimal;
180
- if (!out) return "";
181
- return `${descriptor.prefix}${negative ? "-" : ""}${out}${descriptor.suffix}`;
182
- }
183
- /** Group a digit string from the right. */
184
- function addGrouping(digits, separator) {
185
- if (digits.length < 4) return digits;
186
- let out = "";
187
- for (let i = 0; i < digits.length; i++) {
188
- if (i > 0 && (digits.length - i) % 3 === 0) out += separator;
189
- out += digits[i];
190
- }
191
- return out;
192
- }
193
- /**
194
- * Normalise a raw value for the VALUE side.
195
- *
196
- * A number pattern yields a canonical numeric string (`"10000000.25"`) rather than the formatted
197
- * text, so `Number(v)` works and a store that does arithmetic on it does not have to know a format
198
- * was ever involved. A template yields the assembled string, because there the decoration IS the
199
- * value — an email is not an email without its domain.
200
- */
201
- function normaliseValue(raw, descriptor) {
202
- const value = String(raw ?? "");
203
- if (!descriptor) return value;
204
- if (descriptor.kind === "template") return value ? `${descriptor.before}${value}${descriptor.after}` : "";
205
- if (!value || value === "-") return "";
206
- const negative = value.startsWith("-");
207
- const [intRaw = "", fracRaw] = (negative ? value.slice(1) : value).split(".");
208
- const digits = intRaw.replace(/\D/g, "");
209
- const fraction = (fracRaw ?? "").replace(/\D/g, "").slice(0, descriptor.maxFraction);
210
- let out = digits.replace(/^0+(?=\d)/, "");
211
- if (!out) out = digits ? "0" : "";
212
- if (!out && !fraction) return "";
213
- if (fraction) out = `${out || "0"}.${fraction}`;
214
- return negative && out ? `-${out}` : out;
215
- }
216
- /**
217
- * Where the caret belongs after the text was reformatted.
218
- *
219
- * Reformatting rewrites the whole field, and the browser then parks the caret at the end — so
220
- * inserting a digit in the middle of a number would throw you to the end on every keystroke. The
221
- * fix is to count in SIGNIFICANT characters (the ones the user actually typed) rather than in
222
- * string offsets: count how many sit left of the caret before, then walk the new text until the
223
- * same number have gone by.
224
- */
225
- function caretAfterFormat(next, caretInPrev, prev, isSignificant) {
226
- let typed = 0;
227
- for (let i = 0; i < Math.min(caretInPrev, prev.length); i++) if (isSignificant(prev[i])) typed++;
228
- if (typed === 0) {
229
- let i = 0;
230
- while (i < next.length && !isSignificant(next[i])) i++;
231
- return i;
232
- }
233
- let seen = 0;
234
- for (let i = 0; i < next.length; i++) if (isSignificant(next[i])) {
235
- seen++;
236
- if (seen === typed) return i + 1;
237
- }
238
- return next.length;
239
- }
240
- /**
241
- * Which characters count as "typed" for caret purposes — everything the format did NOT insert.
242
- */
243
- function significantFor(descriptor, locale) {
244
- if (!descriptor || descriptor.kind === "template") return () => true;
245
- const { decimal } = localeSeparators(locale);
246
- return (ch) => /\d/.test(ch) || ch === decimal || ch === "-";
247
- }
248
- /** Resolve either form of a format prop to its finished text. */
249
- function resolveFormat(format, raw, ctx, mode) {
250
- if (format == null || format === "") return null;
251
- if (typeof format === "function") return String(format({
252
- value: raw,
253
- type: ctx.type,
254
- locale: ctx.locale
255
- }) ?? "");
256
- const descriptor = parseFormat(format);
257
- if (!descriptor) return null;
258
- return mode === "display" ? applyFormat(raw, descriptor, ctx.locale) : normaliseValue(raw, descriptor);
259
- }
260
-
261
- //#endregion
262
14
  //#region src/components/input/input-core.ts
263
15
  const numberStringConverter = {
264
16
  fromAttribute(value) {
@@ -272,6 +24,18 @@ const numberStringConverter = {
272
24
  }
273
25
  };
274
26
  /**
27
+ * `modelValue` reflects to `model-value`, but only while it is TEXT — a `type="file"` value is a
28
+ * `File` / `File[]`, which would otherwise land in the DOM as `"[object File]"`.
29
+ */
30
+ const modelValueConverter = {
31
+ fromAttribute(value) {
32
+ return value ?? "";
33
+ },
34
+ toAttribute(value) {
35
+ return typeof value === "string" ? value : null;
36
+ }
37
+ };
38
+ /**
275
39
  * `MonoInputCore` — all render-mode-agnostic logic for `mono-input`: reactive
276
40
  * props, hybrid prop aliases (camelCase ↔ kebab ↔ lowercase), attribute
277
41
  * observation, value/model two-way sync, events, validation/class computation,
@@ -294,13 +58,27 @@ const MonoInputCore = (superClass) => {
294
58
  this.size = "md";
295
59
  this.color = "primary";
296
60
  this.variant = "outlined";
61
+ this.labelPosition = "top";
62
+ this.validationPosition = "bottom";
297
63
  this.modelValue = "";
298
64
  this.value = "";
65
+ this.accept = "";
66
+ this.multiple = false;
67
+ this.showValue = true;
299
68
  this.formatOn = "input";
300
69
  this.name = "";
301
70
  this.placeholder = "";
302
71
  this.label = "";
303
72
  this.helperText = "";
73
+ this.tooltip = null;
74
+ this._tooltip = new FieldTooltipController(this, () => this.tooltip);
75
+ this._validation = new FieldValidationController(this, () => ({
76
+ position: this.validationPosition,
77
+ ...this._validationNotice ?? {
78
+ state: void 0,
79
+ text: void 0
80
+ }
81
+ }), () => this.renderRoot?.querySelector?.("[mono-input] > [mono-field]"));
304
82
  this.validationState = "default";
305
83
  this.validationMessage = "";
306
84
  this.error = false;
@@ -325,6 +103,8 @@ const MonoInputCore = (superClass) => {
325
103
  this._inputId = `mono-input-${Math.random().toString(36).slice(2)}`;
326
104
  this._messageId = `${this._inputId}-message`;
327
105
  defineHybridPropAliases(this, [
106
+ "labelPosition",
107
+ "validationPosition",
328
108
  "modelValue",
329
109
  "formatDisplay",
330
110
  "formatValue",
@@ -338,6 +118,8 @@ const MonoInputCore = (superClass) => {
338
118
  "ariaLabelText",
339
119
  "minLength",
340
120
  "maxLength",
121
+ "maxFileSize",
122
+ "showValue",
341
123
  "cssClass",
342
124
  "minWidth",
343
125
  "maxWidth",
@@ -386,6 +168,8 @@ const MonoInputCore = (superClass) => {
386
168
  "arialabel",
387
169
  "minlength",
388
170
  "maxlength",
171
+ "maxfilesize",
172
+ "showvalue",
389
173
  "css-class",
390
174
  "cssclass",
391
175
  "formatdisplay",
@@ -446,10 +230,53 @@ const MonoInputCore = (superClass) => {
446
230
  case "maxlength":
447
231
  this.maxLength = this._toOptionalNumber(newValue);
448
232
  return;
233
+ case "maxfilesize":
234
+ this.maxFileSize = this._toOptionalNumber(newValue);
235
+ return;
236
+ case "showvalue":
237
+ this.showValue = newValue === null ? true : booleanStringConverter.fromAttribute(newValue);
238
+ return;
449
239
  }
450
240
  }
241
+ /** The validation message and its state — the same precedence the message row uses. */
242
+ get _validationNotice() {
243
+ if (this.validationMessage) return {
244
+ state: this._resolvedValidationState,
245
+ text: this.validationMessage
246
+ };
247
+ if (this.errorMessage) return {
248
+ state: "invalid",
249
+ text: this.errorMessage
250
+ };
251
+ if (this.successMessage) return {
252
+ state: "valid",
253
+ text: this.successMessage
254
+ };
255
+ return null;
256
+ }
257
+ /** The message that moved to the icon / float bubble, kept for assistive tech only. */
258
+ _renderMovedMessage() {
259
+ const notice = this._validationNotice;
260
+ return html`<div
261
+ class=${`${this._cls("mono-input-message", "message")} ${notice.state}`}
262
+ mono-message=${notice.state}
263
+ mono-sr-only
264
+ role=${notice.state === "invalid" ? "alert" : nothing}
265
+ >${notice.text}</div>`;
266
+ }
451
267
  willUpdate(changed) {
452
- if (changed.has("modelValue") && this.value !== this.modelValue) this.value = this.modelValue ?? "";
268
+ if (this._isFile) {
269
+ if (changed.has("modelValue") || changed.has("type")) {
270
+ const files = this._fileList();
271
+ const names = this._fileNames(files);
272
+ this.value = names;
273
+ this._display = names;
274
+ if (!files.length && this._fileEl) this._fileEl.value = "";
275
+ }
276
+ this._internalWrite = false;
277
+ return;
278
+ }
279
+ if (changed.has("modelValue") && this.value !== this.modelValue) this.value = typeof this.modelValue === "string" ? this.modelValue : "";
453
280
  if (changed.has("value") && this.modelValue !== this.value) this.modelValue = String(this.value ?? "");
454
281
  if (!this._internalWrite && !this._focused && (changed.has("value") || changed.has("modelValue") || changed.has("formatDisplay"))) this._syncDisplayFromValue();
455
282
  this._internalWrite = false;
@@ -496,7 +323,7 @@ const MonoInputCore = (superClass) => {
496
323
  this.readonly ? "readonly" : "",
497
324
  this._resolvedValidationState !== "default" ? `is-${this._resolvedValidationState}` : "",
498
325
  this._hasPrefixSlot ? "has-prefix" : "",
499
- this._hasSuffixSlot || this.clearable ? "has-suffix" : "",
326
+ this._hasSuffixSlot || this.clearable || this._isFile ? "has-suffix" : "",
500
327
  this.value ? "has-value" : "",
501
328
  this.cssClassName,
502
329
  this.cssClass?.root
@@ -512,12 +339,127 @@ const MonoInputCore = (superClass) => {
512
339
  this.readonly ? "readonly" : "",
513
340
  this._resolvedValidationState !== "default" ? `is-${this._resolvedValidationState}` : "",
514
341
  this._hasPrefixSlot ? "has-prefix" : "",
515
- this._hasSuffixSlot || this.clearable ? "has-suffix" : "",
342
+ this._hasSuffixSlot || this.clearable || this._isFile ? "has-suffix" : "",
516
343
  this.value ? "has-value" : ""
517
344
  ].filter(Boolean).join(" ");
518
345
  }
346
+ get _isFile() {
347
+ return this.type === "file";
348
+ }
349
+ get _isRange() {
350
+ return this.type === "range";
351
+ }
352
+ /** `min` / `max` / `step` as the native range resolves them (0 / 100 / 1 when unset). */
353
+ _rangeBounds() {
354
+ const min = this._toOptionalNumber(this.min) ?? 0;
355
+ const rawMax = this._toOptionalNumber(this.max) ?? 100;
356
+ const max = rawMax < min ? min : rawMax;
357
+ const step = this._toOptionalNumber(this.step);
358
+ return {
359
+ min,
360
+ max,
361
+ step: step && step > 0 ? step : 1
362
+ };
363
+ }
364
+ /**
365
+ * The value the slider is actually AT, as a string. An empty value is not a position — the
366
+ * native range parks itself at the midpoint — so the readout and the fill follow the native
367
+ * rule rather than reading `''` as 0. The model is not rewritten: nothing was chosen yet.
368
+ */
369
+ get _rangeValue() {
370
+ const { min, max, step } = this._rangeBounds();
371
+ const target = this._toOptionalNumber(this.value) ?? min + (max - min) / 2;
372
+ const snapped = min + Math.round((target - min) / step) * step;
373
+ return String(Number(Math.min(max, Math.max(min, snapped)).toFixed(10)));
374
+ }
375
+ /** How far along the track the value sits, 0–100 — drives the fill. */
376
+ get _rangeProgress() {
377
+ const { min, max } = this._rangeBounds();
378
+ if (max === min) return 0;
379
+ return (Number(this._rangeValue) - min) / (max - min) * 100;
380
+ }
381
+ /** The readout text: the value drawn through `format-display`. */
382
+ get _rangeText() {
383
+ return this._formatDisplay(this._rangeValue, { pad: true });
384
+ }
385
+ /**
386
+ * A native range ignores `readonly`, so a readonly slider would still move. Put the thumb
387
+ * back where the value says and report that the event was handled.
388
+ */
389
+ _revertReadonlyRange(event) {
390
+ if (!this._isRange || !this.readonly || this.disabled) return false;
391
+ event.currentTarget.value = this._rangeValue;
392
+ event.stopPropagation();
393
+ return true;
394
+ }
395
+ /** `modelValue` as an array of files, whatever shape it arrived in (File, File[], null, ''). */
396
+ _fileList() {
397
+ const isFile = (v) => !!v && typeof v === "object" && typeof v.name === "string";
398
+ const v = this.modelValue;
399
+ if (Array.isArray(v)) return v.filter(isFile);
400
+ return isFile(v) ? [v] : [];
401
+ }
402
+ _fileNames(files) {
403
+ return files.map((f) => f.name).join(", ");
404
+ }
405
+ _openFilePicker() {
406
+ if (this.disabled || this.readonly) return;
407
+ this._fileEl?.click();
408
+ }
409
+ _handleFileKeydown(event) {
410
+ if (event.key !== "Enter" && event.key !== " ") return;
411
+ event.preventDefault();
412
+ this._openFilePicker();
413
+ }
414
+ /** Files above `maxFileSize` are dropped, each one reported through `error`. */
415
+ _acceptFiles(files, sourceEvent) {
416
+ const limit = this.maxFileSize;
417
+ if (!limit || limit <= 0) return files;
418
+ return files.filter((file) => {
419
+ if (file.size <= limit) return true;
420
+ const detail = {
421
+ message: `File "${file.name}" exceeds the maximum size limit.`,
422
+ reason: "max-file-size",
423
+ file,
424
+ maxFileSize: limit,
425
+ sourceEvent
426
+ };
427
+ dispatchMonoEvent(this, "error", detail);
428
+ return false;
429
+ });
430
+ }
431
+ /**
432
+ * The picker's native `input` fires BEFORE its `change`, i.e. before the value below is
433
+ * written — left to bubble, a host `@input` (and a bound form) would read the OLD value. Our
434
+ * own `input` is emitted from the change handler instead.
435
+ */
436
+ _swallowNativeInput(event) {
437
+ event.stopPropagation();
438
+ }
439
+ _handleFileChange(event) {
440
+ if (this.disabled || this.readonly) return;
441
+ const input = event.currentTarget;
442
+ const files = this._acceptFiles(Array.from(input.files ?? []), event);
443
+ if (!files.length) {
444
+ input.value = "";
445
+ return;
446
+ }
447
+ this._internalWrite = true;
448
+ const oldValue = this.modelValue;
449
+ const nextValue = this.multiple ? files : files[0];
450
+ this.modelValue = nextValue;
451
+ this.value = this._display = this._fileNames(files);
452
+ const detail = this._createModelDetail({
453
+ modelValue: nextValue,
454
+ oldValue,
455
+ sourceEvent: event
456
+ });
457
+ this._emitInput(detail);
458
+ this._emitChange(detail);
459
+ }
519
460
  _createModelDetail(args) {
520
461
  return {
462
+ ...this._isFile ? { files: this._fileList() } : {},
521
463
  modelValue: args.modelValue,
522
464
  currentValue: args.modelValue,
523
465
  oldValue: args.oldValue,
@@ -667,11 +609,12 @@ const MonoInputCore = (superClass) => {
667
609
  } catch {}
668
610
  }
669
611
  _handleInput(event) {
612
+ if (this._revertReadonlyRange(event)) return;
670
613
  if (this.disabled || this.readonly) return;
671
614
  this._internalWrite = true;
672
615
  const input = event.currentTarget;
673
616
  const oldValue = this.modelValue;
674
- if (!this._hasFormat) {
617
+ if (!this._hasFormat || this._isRange) {
675
618
  const nextValue = input.value;
676
619
  this.value = nextValue;
677
620
  this.modelValue = nextValue;
@@ -697,11 +640,12 @@ const MonoInputCore = (superClass) => {
697
640
  }));
698
641
  }
699
642
  _handleChange(event) {
643
+ if (this._revertReadonlyRange(event)) return;
700
644
  if (this.disabled || this.readonly) return;
701
645
  this._internalWrite = true;
702
646
  const input = event.currentTarget;
703
647
  const oldValue = this.modelValue;
704
- if (!this._hasFormat) {
648
+ if (!this._hasFormat || this._isRange) {
705
649
  const nextValue = input.value;
706
650
  this.value = nextValue;
707
651
  this.modelValue = nextValue;
@@ -735,6 +679,21 @@ const MonoInputCore = (superClass) => {
735
679
  if (this.disabled || this.readonly) return;
736
680
  this._internalWrite = true;
737
681
  const oldValue = this.modelValue;
682
+ if (this._isFile) {
683
+ const empty = this.multiple ? [] : null;
684
+ this.modelValue = empty;
685
+ this.value = this._display = "";
686
+ if (this._fileEl) this._fileEl.value = "";
687
+ this._inputEl?.focus();
688
+ const detail = this._createModelDetail({
689
+ modelValue: empty,
690
+ oldValue
691
+ });
692
+ this._emitInput(detail);
693
+ this._emitChange(detail);
694
+ this._emitClear(detail);
695
+ return;
696
+ }
738
697
  const nextValue = "";
739
698
  this.value = nextValue;
740
699
  this.modelValue = nextValue;
@@ -769,7 +728,10 @@ const MonoInputCore = (superClass) => {
769
728
  mono-size=${this.size === "md" ? nothing : this.size}
770
729
  mono-color=${this.color === "primary" ? nothing : this.color}
771
730
  mono-variant=${this.variant === "outlined" ? nothing : this.variant}
731
+ mono-label-position=${this.labelPosition === "top" ? nothing : this.labelPosition}
732
+ mono-validation-position=${this.validationPosition === "bottom" ? nothing : this.validationPosition}
772
733
  mono-validation-state=${state === "default" ? nothing : state}
734
+ mono-type=${this._isFile || this._isRange ? this.type : nothing}
773
735
  ?mono-disabled=${this.disabled}
774
736
  ?mono-readonly=${this.readonly}
775
737
  ?mono-required=${this.required}
@@ -784,8 +746,111 @@ const MonoInputCore = (superClass) => {
784
746
  get _describedBy() {
785
747
  return this.validationMessage || this.errorMessage || this.successMessage || this.helperText || this._hasHelperSlot ? this._messageId : void 0;
786
748
  }
749
+ /**
750
+ * `type="file"`: a hidden native picker, and in front of it a read-only text input showing
751
+ * the picked name(s). The text input keeps `mono-native` + `.mono-input-native`, so focus,
752
+ * the label's `for`, sizing and the focus ring all behave exactly as on a text field.
753
+ */
754
+ _renderFileNative() {
755
+ return html`
756
+ <input
757
+ type="file"
758
+ mono-file-input
759
+ hidden
760
+ tabindex="-1"
761
+ accept=${ifDefined(this.accept || void 0)}
762
+ ?multiple=${this.multiple}
763
+ name=${ifDefined(this.name || void 0)}
764
+ ?disabled=${this.disabled}
765
+ @input=${this._swallowNativeInput}
766
+ @change=${this._handleFileChange}
767
+ />
768
+ <input
769
+ id=${this._inputId}
770
+ class=${`${this._cls("mono-input-native", "native")} ${this.size}`}
771
+ mono-native
772
+ mono-file
773
+ type="text"
774
+ readonly
775
+ .value=${this._display}
776
+ placeholder=${ifDefined(this.placeholder || void 0)}
777
+ ?disabled=${this.disabled}
778
+ ?required=${this.required}
779
+ aria-label=${ifDefined(this._ariaLabel)}
780
+ aria-invalid=${this._resolvedValidationState === "invalid" ? "true" : "false"}
781
+ aria-describedby=${ifDefined(this._describedBy)}
782
+ aria-haspopup="dialog"
783
+ @focus=${this._handleFocus}
784
+ @blur=${this._handleBlur}
785
+ @click=${this._openFilePicker}
786
+ @keydown=${this._handleFileKeydown}
787
+ />
788
+ `;
789
+ }
790
+ /** `type="file"` — the upload glyph at the end of the field; clicking it opens the picker too. */
791
+ _renderFileIcon() {
792
+ if (!this._isFile) return nothing;
793
+ return html`
794
+ <span
795
+ class=${this._cls("mono-input-suffix", "fileIcon")}
796
+ mono-suffix
797
+ mono-file-icon
798
+ aria-hidden="true"
799
+ @click=${this._openFilePicker}
800
+ >${this.renderIcon("upload")}</span>
801
+ `;
802
+ }
803
+ /**
804
+ * `type="range"`: Basecoat's slider. The fill is a gradient stop on the track, so the element
805
+ * writes the position as `--mono-input-range-value` (Basecoat's `--slider-value`) — hand-written
806
+ * markup sets the same property itself.
807
+ */
808
+ _renderRangeNative() {
809
+ const { min, max, step } = this._rangeBounds();
810
+ const text = this._rangeText;
811
+ return html`
812
+ <input
813
+ id=${this._inputId}
814
+ class=${`${this._cls("mono-input-native", "native")} ${this.size}`}
815
+ mono-native
816
+ mono-range
817
+ type="range"
818
+ min=${min}
819
+ max=${max}
820
+ step=${ifDefined(this.step == null ? void 0 : step)}
821
+ .value=${this._rangeValue}
822
+ name=${ifDefined(this.name || void 0)}
823
+ style=${`--mono-input-range-value: ${this._rangeProgress}%`}
824
+ ?disabled=${this.disabled}
825
+ ?required=${this.required}
826
+ aria-label=${ifDefined(this._ariaLabel)}
827
+ aria-valuetext=${ifDefined(text !== this._rangeValue ? text : void 0)}
828
+ aria-readonly=${ifDefined(this.readonly ? "true" : void 0)}
829
+ aria-invalid=${this._resolvedValidationState === "invalid" ? "true" : "false"}
830
+ aria-describedby=${ifDefined(this._describedBy)}
831
+ @focus=${this._handleFocus}
832
+ @blur=${this._handleBlur}
833
+ @input=${this._handleInput}
834
+ @change=${this._handleChange}
835
+ />
836
+ `;
837
+ }
838
+ /**
839
+ * `type="range"` — the value readout. It sits at the end of the LABEL row when there is a
840
+ * label (the EJI ONE layout), and after the slider when there is not; each build calls this
841
+ * from both places and exactly one of them renders. `aria-hidden`: the slider already
842
+ * announces its value (`aria-valuetext` carries the formatted text).
843
+ */
844
+ _renderRangeValue(where) {
845
+ if (!this._isRange || !this.showValue) return nothing;
846
+ const inLabel = !!(this.label || this._hasLabelSlot);
847
+ if (where === "label" !== inLabel) return nothing;
848
+ return html`<span class=${this._cls("mono-input-range-value", "rangeValue")} mono-range-value aria-hidden="true">${this._rangeText}</span>`;
849
+ }
787
850
  /** The native <input>, shared by both builds' render(). */
788
851
  _renderNative() {
852
+ if (this._isFile) return this._renderFileNative();
853
+ if (this._isRange) return this._renderRangeNative();
789
854
  return html`
790
855
  <input
791
856
  id=${this._inputId}
@@ -818,7 +883,7 @@ const MonoInputCore = (superClass) => {
818
883
  }
819
884
  /** The clear button (uses the build-specific icon). */
820
885
  _renderClear() {
821
- if (!(this.clearable && this.value && !this.disabled && !this.readonly)) return nothing;
886
+ if (this._isRange || !(this.clearable && this.value && !this.disabled && !this.readonly)) return nothing;
822
887
  return html`
823
888
  <button
824
889
  type="button"
@@ -859,10 +924,31 @@ const MonoInputCore = (superClass) => {
859
924
  __decorate([property({ type: String })], MonoInputCoreClass.prototype, "variant", void 0);
860
925
  __decorate([property({
861
926
  type: String,
927
+ attribute: "label-position"
928
+ })], MonoInputCoreClass.prototype, "labelPosition", void 0);
929
+ __decorate([property({
930
+ type: String,
931
+ attribute: "validation-position"
932
+ })], MonoInputCoreClass.prototype, "validationPosition", void 0);
933
+ __decorate([property({
862
934
  attribute: "model-value",
863
- reflect: true
935
+ reflect: true,
936
+ converter: modelValueConverter
864
937
  })], MonoInputCoreClass.prototype, "modelValue", void 0);
865
938
  __decorate([property({ type: String })], MonoInputCoreClass.prototype, "value", void 0);
939
+ __decorate([property({ type: String })], MonoInputCoreClass.prototype, "accept", void 0);
940
+ __decorate([property({
941
+ reflect: true,
942
+ converter: booleanStringConverter
943
+ })], MonoInputCoreClass.prototype, "multiple", void 0);
944
+ __decorate([property({
945
+ attribute: "max-file-size",
946
+ converter: numberStringConverter
947
+ })], MonoInputCoreClass.prototype, "maxFileSize", void 0);
948
+ __decorate([property({
949
+ attribute: "show-value",
950
+ converter: { fromAttribute: (v) => v === null ? true : booleanStringConverter.fromAttribute(v) }
951
+ })], MonoInputCoreClass.prototype, "showValue", void 0);
866
952
  __decorate([property({ attribute: false })], MonoInputCoreClass.prototype, "formatDisplay", void 0);
867
953
  __decorate([property({ attribute: false })], MonoInputCoreClass.prototype, "formatValue", void 0);
868
954
  __decorate([property({ attribute: "format-on" })], MonoInputCoreClass.prototype, "formatOn", void 0);
@@ -874,6 +960,7 @@ const MonoInputCore = (superClass) => {
874
960
  type: String,
875
961
  attribute: "helper-text"
876
962
  })], MonoInputCoreClass.prototype, "helperText", void 0);
963
+ __decorate([property()], MonoInputCoreClass.prototype, "tooltip", void 0);
877
964
  __decorate([property({
878
965
  type: String,
879
966
  attribute: "validation-state"
@@ -955,6 +1042,7 @@ const MonoInputCore = (superClass) => {
955
1042
  attribute: "max-height"
956
1043
  })], MonoInputCoreClass.prototype, "maxHeight", void 0);
957
1044
  __decorate([query(".mono-input-native")], MonoInputCoreClass.prototype, "_inputEl", void 0);
1045
+ __decorate([query("[mono-file-input]")], MonoInputCoreClass.prototype, "_fileEl", void 0);
958
1046
  __decorate([state()], MonoInputCoreClass.prototype, "_display", void 0);
959
1047
  __decorate([state()], MonoInputCoreClass.prototype, "_focused", void 0);
960
1048
  __decorate([state()], MonoInputCoreClass.prototype, "_hasPrefixSlotState", void 0);
@@ -972,7 +1060,7 @@ let MonoInputShadow = class MonoInputShadow extends withShadowUtilityStyles(Mono
972
1060
  this.disableWarning?.("change-in-update");
973
1061
  }
974
1062
  static {
975
- this.styles = [unsafeCSS(toShadowCss(input_css_raw_default, {
1063
+ this.styles = [unsafeCSS(toShadowCss(input_css_raw_default + label_position_css_raw_default + field_tooltip_css_raw_default + field_validation_css_raw_default, {
976
1064
  host: "mono-input",
977
1065
  append: SHADOW_EXTRA_CSS
978
1066
  }))];
@@ -1001,7 +1089,12 @@ let MonoInputShadow = class MonoInputShadow extends withShadowUtilityStyles(Mono
1001
1089
  _onSlotChange(name, event) {
1002
1090
  this._setSlotState(name, this._slotHasContent(event.target));
1003
1091
  }
1004
- renderIcon(_name) {
1092
+ renderIcon(name) {
1093
+ if (name === "upload") return html`
1094
+ <svg viewBox="0 0 24 24" mono-icon fill="currentColor" aria-hidden="true">
1095
+ <path d="M6.5 20q-2.28 0-3.89-1.57Q1 16.85 1 14.58q0-1.95 1.17-3.48q1.18-1.53 3.08-1.95q.63-2.3 2.5-3.72Q9.63 4 12 4q2.93 0 4.96 2.04Q19 8.07 19 11q1.73.2 2.86 1.5q1.14 1.28 1.14 3q0 1.88-1.31 3.19T18.5 20H13q-.82 0-1.41-.59Q11 18.83 11 18v-5.15L9.4 14.4L8 13l4-4l4 4l-1.4 1.4l-1.6-1.55V18h5.5q1.05 0 1.77-.73q.73-.72.73-1.77t-.73-1.77Q19.55 13 18.5 13H17v-2q0-2.07-1.46-3.54Q14.08 6 12 6Q9.93 6 8.46 7.46Q7 8.93 7 11h-.5q-1.45 0-2.47 1.03Q3 13.05 3 14.5T4.03 17q1.02 1 2.47 1H9v2m3-7" />
1096
+ </svg>
1097
+ `;
1005
1098
  return html`
1006
1099
  <svg viewBox="0 0 24 24" mono-icon fill="currentColor" aria-hidden="true">
1007
1100
  <path d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" />
@@ -1018,17 +1111,23 @@ let MonoInputShadow = class MonoInputShadow extends withShadowUtilityStyles(Mono
1018
1111
  >
1019
1112
  <slot name="label" @slotchange=${(e) => this._onSlotChange("label", e)}>${this.label}</slot>
1020
1113
  ${this.required ? html`<span class=${this._cls("mono-input-required", "required")} mono-required-mark>*</span>` : nothing}
1114
+ ${this._tooltip.render()}
1115
+ ${this._renderRangeValue("label")}
1021
1116
  </label>
1022
1117
  `;
1023
1118
  }
1024
1119
  _renderHelper() {
1025
1120
  const base = this._cls("mono-input-message", "message");
1121
+ if (this._validation.moved) return html`${this._renderHelperText(base)}${this._renderMovedMessage()}`;
1026
1122
  if (this.validationMessage) {
1027
1123
  const state = this._resolvedValidationState;
1028
1124
  return html`<div class=${`${base} ${state}`} mono-message=${state} role=${state === "invalid" ? "alert" : nothing}>${this.validationMessage}</div>`;
1029
1125
  }
1030
1126
  if (this.errorMessage) return html`<div class=${`${base} invalid`} mono-message="invalid" role="alert">${this.errorMessage}</div>`;
1031
1127
  if (this.successMessage) return html`<div class=${`${base} valid`} mono-message="valid">${this.successMessage}</div>`;
1128
+ return this._renderHelperText(base);
1129
+ }
1130
+ _renderHelperText(base) {
1032
1131
  return html`
1033
1132
  <div
1034
1133
  class=${`${base} helper`}
@@ -1047,7 +1146,10 @@ let MonoInputShadow = class MonoInputShadow extends withShadowUtilityStyles(Mono
1047
1146
  <slot name="prefix" @slotchange=${(e) => this._onSlotChange("prefix", e)}></slot>
1048
1147
  </span>
1049
1148
  ${this._renderNative()}
1149
+ ${this._renderRangeValue("field")}
1150
+ ${this._validation.renderIcon()}
1050
1151
  ${this._renderClear()}
1152
+ ${this._renderFileIcon()}
1051
1153
  <span class=${this._cls("mono-input-suffix", "suffix")} mono-suffix ?mono-empty=${!this._hasSuffixSlot}>
1052
1154
  <slot name="suffix" @slotchange=${(e) => this._onSlotChange("suffix", e)}></slot>
1053
1155
  </span>
@@ -1055,6 +1157,7 @@ let MonoInputShadow = class MonoInputShadow extends withShadowUtilityStyles(Mono
1055
1157
  <div id=${this._messageId} class=${this.cssClass?.messageWrap ?? ""} mono-message-wrap>
1056
1158
  ${this._renderHelper()}
1057
1159
  </div>
1160
+ ${this._validation.renderFloat()}
1058
1161
  `);
1059
1162
  }
1060
1163
  connectedCallback() {
@@ -1147,7 +1250,9 @@ function getInputIcon(type) {
1147
1250
  time: "M12 7v5l3 3M12 22a10 10 0 1 0 0-20a10 10 0 0 0 0 20z",
1148
1251
  month: "M7 3v3M17 3v3M5 5h14v14H5zM8 11h8",
1149
1252
  week: "M7 3v3M17 3v3M5 5h14v16H5zM9 11h6M9 15h4",
1150
- search: "M21 21l-4.35-4.35M10.5 18a7.5 7.5 0 1 1 0-15a7.5 7.5 0 0 1 0 15z"
1253
+ search: "M21 21l-4.35-4.35M10.5 18a7.5 7.5 0 1 1 0-15a7.5 7.5 0 0 1 0 15z",
1254
+ file: "M12 16V8M8.5 11.5L12 8l3.5 3.5M7 18h10",
1255
+ range: "M4 12h16M9 9a3 3 0 1 0 0 6a3 3 0 0 0 0-6z"
1151
1256
  };
1152
1257
  return iconMap[type] ?? iconMap.text;
1153
1258
  }