@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.
- package/dist/control-tooltip-7vegYmq3.js +678 -0
- package/dist/{tooltip-FCMRUSLi.js → control-tooltip-C3rA_nSH.js} +12 -119
- package/dist/{data-source-controller-Cf_sMxEh.js → data-source-controller-C6C4ej_M.js} +1 -1
- package/dist/{data-source-options-Bk-UoaZV.js → data-source-options-Cz9fVLK8.js} +3 -2
- package/dist/{data-source-read-Cuqw3LcP.js → data-source-read-i6CYSUEl.js} +2 -1
- package/dist/{excel-DtRpxmxs.js → excel-BPdDt06G.js} +1 -1
- package/dist/{export-B91P6J1y.js → export-DgomqI_3.js} +2 -2
- package/dist/export.js +2 -2
- package/dist/{field-icons-FmyBWa0g.js → field-icons-t8rXRCKs.js} +50 -1
- package/dist/field-tooltip-FyMi9vNM.js +266 -0
- package/dist/field-tooltip.css_raw-DEctHXKm.js +270 -0
- package/dist/field-validation-CHHQi1zl.js +170 -0
- package/dist/field-validation.css_raw-B3Iu33rS.js +178 -0
- package/dist/{form-control-core-CIdMLXMo.js → form-control-core-rW2WvOcb.js} +1 -1
- package/dist/{hydration-flush-DHrl4_KK.js → hydration-flush-9AJE8FRl.js} +398 -1
- package/dist/index.js +6 -5
- package/dist/{index.node-dvrNviMx.js → index.node-tTkISFn2.js} +2 -2
- package/dist/index.node.js +6 -5
- package/dist/input-format-GrRCJBqV.js +251 -0
- package/dist/input.css_raw-CQu2fAsU.js +5 -0
- package/dist/{light-slots-DdDdZ6zs.js → light-slots-BnBR29E7.js} +1 -1
- package/dist/{light-slots-4ZCjOcBg.js → light-slots-Cb6e-LU3.js} +1 -1
- package/dist/{mono-button-CeDB9khW.js → mono-button-Cy5-Y0At.js} +3 -3
- package/dist/{mono-button.shadow-D9NdMsmH.js → mono-button.shadow-CIBGisyo.js} +1 -2
- package/dist/{mono-data-grid-BHlo1IgR.js → mono-data-grid-KDpu4d4_.js} +5 -4
- package/dist/{mono-element-C7vCschg.js → mono-element-Bc9wElPy.js} +1 -1
- package/dist/{mono-form-controller-IYn0MuUQ.js → mono-form-controller-BkMR8g14.js} +18 -3
- package/dist/mono-ui-KOBJcnXk.js +758 -0
- package/dist/{reactive-DFCdZbH9.js → normalize-error-BmLbgANw.js} +1 -48
- package/dist/nuxt.js +1 -1
- package/dist/{popup-portal-HWhkd7oy.js → popup-portal-C8ttHDRX.js} +17 -1
- package/dist/{popup-stack-De05Y-mJ.js → popup-stack-C64WCuXq.js} +21 -1
- package/dist/src/components/accordion/accordion-core.d.ts +4 -1
- package/dist/src/components/accordion/mono-accordion.shadow.d.ts +4 -1
- package/dist/src/components/date/date-core.d.ts +3 -0
- package/dist/src/components/date/date-types.d.ts +36 -1
- package/dist/src/components/drawer/drawer-core.d.ts +1 -0
- package/dist/src/components/dropdown-table/dropdown-table-core.d.ts +3 -0
- package/dist/src/components/dropdown-table/dropdown-table-types.d.ts +31 -0
- package/dist/src/components/form/form-types.d.ts +23 -5
- package/dist/src/components/input/index.d.ts +2 -2
- package/dist/src/components/input/index.shadow.d.ts +2 -2
- package/dist/src/components/input/input-core.d.ts +23 -3
- package/dist/src/components/input/input-types.d.ts +84 -9
- package/dist/src/components/input/mono-input.d.ts +3 -2
- package/dist/src/components/input/mono-input.shadow.d.ts +3 -2
- package/dist/src/components/modal/modal-core.d.ts +1 -0
- package/dist/src/components/otp/index.d.ts +5 -0
- package/dist/src/components/otp/index.shadow.d.ts +6 -0
- package/dist/src/components/otp/mono-otp.d.ts +32 -0
- package/dist/src/components/otp/mono-otp.shadow.d.ts +30 -0
- package/dist/src/components/otp/otp-core.d.ts +91 -0
- package/dist/src/components/otp/otp-types.d.ts +161 -0
- package/dist/src/components/otp/otp-utils.d.ts +41 -0
- package/dist/src/components/select/select-core.d.ts +3 -0
- package/dist/src/components/select/select-types.d.ts +31 -0
- package/dist/src/components/slider/index.d.ts +5 -0
- package/dist/src/components/slider/index.shadow.d.ts +6 -0
- package/dist/src/components/slider/mono-slider.d.ts +33 -0
- package/dist/src/components/slider/mono-slider.shadow.d.ts +29 -0
- package/dist/src/components/slider/slider-core.d.ts +77 -0
- package/dist/src/components/slider/slider-math.d.ts +102 -0
- package/dist/src/components/slider/slider-types.d.ts +188 -0
- package/dist/src/components/table/column-autosize.d.ts +74 -0
- package/dist/src/components/table/mono-data-grid.d.ts +10 -0
- package/dist/src/components/table/mono-table-th-core.d.ts +3 -0
- package/dist/src/components/table/table-types.d.ts +8 -1
- package/dist/src/components/tag-input/mono-tag-input.d.ts +12 -0
- package/dist/src/components/tag-input/mono-tag-input.shadow.d.ts +9 -1
- package/dist/src/components/tag-input/tag-input-core.d.ts +12 -1
- package/dist/src/components/tag-input/tag-input-types.d.ts +33 -0
- package/dist/src/components/textarea/textarea-core.d.ts +3 -0
- package/dist/src/components/textarea/textarea-types.d.ts +31 -0
- package/dist/src/composables/field-bubble.d.ts +34 -0
- package/dist/src/composables/field-icons.d.ts +10 -0
- package/dist/src/composables/field-tooltip.d.ts +52 -0
- package/dist/src/composables/field-validation.d.ts +58 -0
- package/dist/src/composables/mono-size-attrs.d.ts +10 -0
- package/dist/src/composables/popup-portal.d.ts +12 -0
- package/dist/src/composables/popup-stack.d.ts +21 -0
- package/dist/src/entries/index.d.ts +3 -2
- package/dist/src/entries/index.node.d.ts +3 -2
- package/dist/ssr-lit/runtime/components/LitWrapper.vue +11 -11
- package/dist/ssr-lit/runtime/components/LitWrapperClient.vue +11 -11
- package/dist/ssr-lit/runtime/components/LitWrapperServer.vue +38 -38
- package/dist/ssr-lit/runtime/plugins/antiFouc.server.js +25 -25
- package/dist/ssr-lit/runtime/plugins/hydrateSupport.client.js +4 -4
- package/dist/ssr-lit/runtime/plugins/polyfill.client.js +9 -9
- package/dist/ssr-lit/runtime/utils/customElements.js +11 -11
- package/dist/ssr-lit/runtime/utils/litElementRenderer.js +28 -28
- package/dist/{styles-D-ergrfR.js → styles-BODNpZV1.js} +1 -1
- package/dist/tooltip-Drekihf5.js +102 -0
- package/dist/tooltip-loader-3U9FTOXj.js +20 -0
- package/dist/tooltip-loader-Dcp9AUZn.js +23 -0
- package/dist/tooltip.js +3 -1
- package/dist/ui/accordion.js +19 -6
- package/dist/ui/alert.js +3 -3
- package/dist/ui/breadcrumb.js +3 -3
- package/dist/ui/button-dropdown.js +3 -3
- package/dist/ui/button.js +1 -1
- package/dist/ui/card.js +3 -3
- package/dist/ui/chart.js +3 -4
- package/dist/ui/checkbox.js +3 -3
- package/dist/ui/chip.js +2 -2
- package/dist/ui/date.js +68 -7
- package/dist/ui/drawer.js +14 -5
- package/dist/ui/dropdown-table.js +63 -9
- package/dist/ui/dropdown.js +6 -5
- package/dist/ui/file-upload.js +3 -3
- package/dist/ui/filter.js +2 -2
- package/dist/ui/form.js +1 -1
- package/dist/ui/index.css +4276 -2543
- package/dist/ui/input.js +365 -264
- package/dist/ui/menu.js +3 -3
- package/dist/ui/modal.js +15 -6
- package/dist/ui/nav.js +3 -3
- package/dist/ui/otp.js +834 -0
- package/dist/ui/radio.js +3 -3
- package/dist/ui/rich-text-editor.js +3 -4
- package/dist/ui/select.js +70 -7
- package/dist/ui/shadow/accordion.js +31 -4
- package/dist/ui/shadow/alert.js +2 -2
- package/dist/ui/shadow/breadcrumb.js +1 -1
- package/dist/ui/shadow/button-dropdown.js +3 -3
- package/dist/ui/shadow/button.js +1 -1
- package/dist/ui/shadow/card.js +1 -2
- package/dist/ui/shadow/chart.js +5 -6
- package/dist/ui/shadow/checkbox.js +2 -2
- package/dist/ui/shadow/chip.js +1 -1
- package/dist/ui/shadow/date.js +69 -9
- package/dist/ui/shadow/drawer.js +12 -3
- package/dist/ui/shadow/dropdown-table.js +64 -10
- package/dist/ui/shadow/dropdown.js +4 -3
- package/dist/ui/shadow/file-upload.js +2 -2
- package/dist/ui/shadow/filter.js +1 -2
- package/dist/ui/shadow/input.js +369 -264
- package/dist/ui/shadow/menu.js +1 -1
- package/dist/ui/shadow/modal.js +13 -4
- package/dist/ui/shadow/nav.js +1 -1
- package/dist/ui/shadow/otp.js +841 -0
- package/dist/ui/shadow/radio.js +2 -2
- package/dist/ui/shadow/rich-text-editor.js +2 -3
- package/dist/ui/shadow/select.js +74 -10
- package/dist/ui/shadow/sidebar.js +3 -3
- package/dist/ui/shadow/slider.js +1081 -0
- package/dist/ui/shadow/switch.js +2 -2
- package/dist/ui/shadow/table.js +40 -11
- package/dist/ui/shadow/tabs.js +1 -1
- package/dist/ui/shadow/tag-input.js +160 -15
- package/dist/ui/shadow/textarea.js +65 -5
- package/dist/ui/sidebar.js +5 -5
- package/dist/ui/slider.js +1078 -0
- package/dist/ui/switch.js +3 -3
- package/dist/ui/table.js +36 -7
- package/dist/ui/tabs.js +3 -3
- package/dist/ui/tag-input.js +167 -7
- package/dist/ui/textarea.js +65 -5
- package/dist/ui/theme/luma.css +505 -466
- package/dist/ui/theme/lyra.css +505 -466
- package/dist/ui/theme/maia.css +501 -466
- package/dist/ui/theme/mira.css +505 -466
- package/dist/ui/theme/nova.css +503 -466
- package/dist/ui/theme/one.css +742 -699
- package/dist/ui/theme/rhea.css +506 -466
- package/dist/ui/theme/sera.css +507 -466
- package/dist/ui/theme/vega.css +495 -466
- package/dist/{vite-DcyRlTTf.js → vite-CivRCJaf.js} +2 -0
- package/dist/vite.js +1 -1
- package/dist/vue.d.ts +10 -0
- package/package.json +31 -13
- package/dist/css-size-DWAPgQdT.js +0 -38
- package/dist/input.css_raw-CGESifay.js +0 -5
- package/dist/mono-ui-BwUc0L6B.js +0 -360
package/dist/ui/input.js
CHANGED
|
@@ -1,266 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as customElement } from "../mono-element-
|
|
1
|
+
import { d as buildSizeStyle, g as monoHostChildNodes } from "../mono-ui-KOBJcnXk.js";
|
|
2
|
+
import { t as customElement } from "../mono-element-Bc9wElPy.js";
|
|
3
3
|
import { a as defineHybridPropAliases, r as booleanStringConverter, t as __decorate } from "../decorate-DbYFpi8R.js";
|
|
4
4
|
import { t as dispatchMonoEvent } from "../mono-event-BPku9HpS.js";
|
|
5
|
-
import { s as placeSlotNode } from "../light-slots-
|
|
6
|
-
import { t as buildSizeStyle } from "../css-size-DWAPgQdT.js";
|
|
5
|
+
import { s as placeSlotNode } from "../light-slots-BnBR29E7.js";
|
|
7
6
|
import { t as MonoFormControlCore } from "../form-control-core-CRZPZ1ru.js";
|
|
7
|
+
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";
|
|
8
8
|
import { n as cssPart } from "../css-class-B6Tc_MAx.js";
|
|
9
|
+
import { t as FieldTooltipController } from "../field-tooltip-FyMi9vNM.js";
|
|
10
|
+
import { t as FieldValidationController } from "../field-validation-CHHQi1zl.js";
|
|
9
11
|
import { LitElement, html, isServer, nothing, unsafeCSS } from "lit";
|
|
10
12
|
import { property, query, state } from "lit/decorators.js";
|
|
11
13
|
import { ifDefined } from "lit/directives/if-defined.js";
|
|
12
14
|
import { styleMap } from "lit/directives/style-map.js";
|
|
13
15
|
|
|
14
|
-
//#region src/components/input/input-format.ts
|
|
15
|
-
const SEPARATOR_CACHE = /* @__PURE__ */ new Map();
|
|
16
|
-
/**
|
|
17
|
-
* Ask `Intl` which characters this locale uses, rather than assuming `,` and `.`.
|
|
18
|
-
*
|
|
19
|
-
* Several locales use neither — `fr-FR` groups with a narrow no-break space, `de-CH` with an
|
|
20
|
-
* apostrophe — and a hardcoded pair would silently mangle them.
|
|
21
|
-
*/
|
|
22
|
-
function localeSeparators(locale) {
|
|
23
|
-
const key = locale ?? "";
|
|
24
|
-
const cached = SEPARATOR_CACHE.get(key);
|
|
25
|
-
if (cached) return cached;
|
|
26
|
-
let separators = {
|
|
27
|
-
group: ",",
|
|
28
|
-
decimal: "."
|
|
29
|
-
};
|
|
30
|
-
try {
|
|
31
|
-
const parts = new Intl.NumberFormat(locale || void 0, {
|
|
32
|
-
useGrouping: true,
|
|
33
|
-
minimumFractionDigits: 1
|
|
34
|
-
}).formatToParts(12345.6);
|
|
35
|
-
separators = {
|
|
36
|
-
group: parts.find((p) => p.type === "group")?.value ?? ",",
|
|
37
|
-
decimal: parts.find((p) => p.type === "decimal")?.value ?? "."
|
|
38
|
-
};
|
|
39
|
-
} catch {}
|
|
40
|
-
SEPARATOR_CACHE.set(key, separators);
|
|
41
|
-
return separators;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Parse a pattern string into a descriptor, or `null` when it is not a pattern we understand.
|
|
45
|
-
*
|
|
46
|
-
* `null` is deliberately not an error: an unparseable pattern leaves the field an ordinary
|
|
47
|
-
* unformatted input rather than blanking it or throwing mid-keystroke.
|
|
48
|
-
*/
|
|
49
|
-
function parseFormat(pattern) {
|
|
50
|
-
const raw = String(pattern ?? "");
|
|
51
|
-
if (!raw) return null;
|
|
52
|
-
const hole = raw.indexOf("{}");
|
|
53
|
-
if (hole !== -1) return {
|
|
54
|
-
kind: "template",
|
|
55
|
-
before: raw.slice(0, hole),
|
|
56
|
-
after: raw.slice(hole + 2)
|
|
57
|
-
};
|
|
58
|
-
let body = raw;
|
|
59
|
-
let prefix = "";
|
|
60
|
-
let suffix = "";
|
|
61
|
-
const leading = body.match(/^"([^"]*)"/);
|
|
62
|
-
if (leading) {
|
|
63
|
-
prefix = leading[1] ?? "";
|
|
64
|
-
body = body.slice(leading[0].length);
|
|
65
|
-
}
|
|
66
|
-
const trailing = body.match(/"([^"]*)"$/);
|
|
67
|
-
if (trailing) {
|
|
68
|
-
suffix = trailing[1] ?? "";
|
|
69
|
-
body = body.slice(0, body.length - trailing[0].length);
|
|
70
|
-
}
|
|
71
|
-
if (!body || !/^[#0,]*(?:\.[#0]*)?$/.test(body)) return null;
|
|
72
|
-
if (!/[#0]/.test(body)) return null;
|
|
73
|
-
const [intPart = "", fracPart] = body.split(".");
|
|
74
|
-
return {
|
|
75
|
-
kind: "number",
|
|
76
|
-
grouping: intPart.includes(","),
|
|
77
|
-
minFraction: fracPart ? (fracPart.match(/0/g) ?? []).length : 0,
|
|
78
|
-
maxFraction: fracPart ? fracPart.length : 0,
|
|
79
|
-
prefix,
|
|
80
|
-
suffix
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Strip a formatted string back to its raw value.
|
|
85
|
-
*
|
|
86
|
-
* For numbers the result is always canonical — digits, an optional leading `-`, and `.` as the
|
|
87
|
-
* decimal point — whatever the locale draws with, so it is safe to hand to `Number()`.
|
|
88
|
-
*/
|
|
89
|
-
/**
|
|
90
|
-
* Decide whether a GROUP character in the text is really the decimal point the user typed.
|
|
91
|
-
*
|
|
92
|
-
* It exists because the two roles collide: in `id-ID` the grouping character is `.`, so typing
|
|
93
|
-
* `0.9` produced `09` — the strip deleted the point before anything could read it as one. Yet
|
|
94
|
-
* `1.000` typed in the same field must keep meaning a thousand, and that is not a matter of
|
|
95
|
-
* guessing intent: the field re-strips its OWN formatted text on every keystroke, and
|
|
96
|
-
* `addGrouping` only ever emits runs of exactly three digits.
|
|
97
|
-
*
|
|
98
|
-
* So a group character is the decimal point when
|
|
99
|
-
* · the pattern has a fraction at all,
|
|
100
|
-
* · the locale's real decimal character is nowhere in the text (an explicit `1.000,5` wins), and
|
|
101
|
-
* · the digits after the LAST group character number at most `maxFraction` and are not exactly 3.
|
|
102
|
-
*
|
|
103
|
-
* A run of length ZERO qualifies deliberately: a trailing `0.` must survive, or the point is
|
|
104
|
-
* deleted the instant it is typed and `0.9` can never be reached left to right — `applyFormat`
|
|
105
|
-
* carries the matching rule that keeps a lone trailing point on screen.
|
|
106
|
-
*
|
|
107
|
-
* The consequence, and it is documented rather than worked around: under a dot-grouping locale a
|
|
108
|
-
* THREE-digit fraction (`0.123`) is unreachable by dot and has to be typed `0,123`.
|
|
109
|
-
*
|
|
110
|
-
* Returns the split, or `null` when every group character is grouping. Works for either locale
|
|
111
|
-
* shape — under `en-US` the roles are simply swapped and a typed `,` is promoted the same way.
|
|
112
|
-
*/
|
|
113
|
-
function decimalGroupSplit(text, descriptor, group, decimal) {
|
|
114
|
-
if (descriptor.maxFraction <= 0) return null;
|
|
115
|
-
if (!group || group === decimal) return null;
|
|
116
|
-
if (text.includes(decimal)) return null;
|
|
117
|
-
const at = text.lastIndexOf(group);
|
|
118
|
-
if (at === -1) return null;
|
|
119
|
-
const tail = text.slice(at + group.length);
|
|
120
|
-
if (tail.length > descriptor.maxFraction || tail.length === 3) return null;
|
|
121
|
-
if (tail && !/^\d+$/.test(tail)) return null;
|
|
122
|
-
return {
|
|
123
|
-
head: text.slice(0, at),
|
|
124
|
-
tail
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
function stripFormat(text, descriptor, locale) {
|
|
128
|
-
const value = String(text ?? "");
|
|
129
|
-
if (!descriptor) return value;
|
|
130
|
-
if (descriptor.kind === "template") {
|
|
131
|
-
let out = value;
|
|
132
|
-
if (descriptor.before && out.startsWith(descriptor.before)) out = out.slice(descriptor.before.length);
|
|
133
|
-
if (descriptor.after && out.endsWith(descriptor.after)) out = out.slice(0, out.length - descriptor.after.length);
|
|
134
|
-
return out;
|
|
135
|
-
}
|
|
136
|
-
const { group, decimal } = localeSeparators(locale);
|
|
137
|
-
let out = value;
|
|
138
|
-
if (descriptor.prefix) out = out.split(descriptor.prefix).join("");
|
|
139
|
-
if (descriptor.suffix) out = out.split(descriptor.suffix).join("");
|
|
140
|
-
const promoted = decimalGroupSplit(out, descriptor, group, decimal);
|
|
141
|
-
if (promoted) out = `${promoted.head.split(group).join("")}.${promoted.tail}`;
|
|
142
|
-
else {
|
|
143
|
-
out = out.split(group).join("");
|
|
144
|
-
if (decimal !== ".") out = out.split(decimal).join(".");
|
|
145
|
-
}
|
|
146
|
-
const negative = out.trimStart().startsWith("-");
|
|
147
|
-
out = out.replace(/[^\d.]/g, "");
|
|
148
|
-
const first = out.indexOf(".");
|
|
149
|
-
if (first !== -1) out = out.slice(0, first + 1) + out.slice(first + 1).replace(/\./g, "");
|
|
150
|
-
if (descriptor.maxFraction === 0) out = out.split(".")[0] ?? "";
|
|
151
|
-
return negative && out ? `-${out}` : out;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Render a raw value for DISPLAY.
|
|
155
|
-
*
|
|
156
|
-
* The number branch deliberately does NOT hand the whole string to `Intl`: a value being typed is
|
|
157
|
-
* usually not yet a finished number, and `Intl` would tidy away exactly the characters the user is
|
|
158
|
-
* in the middle of writing — a trailing decimal point (`10000.`) and trailing fraction zeros
|
|
159
|
-
* (`10.50`) both vanish, which makes the field fight the person using it. Only the INTEGER part is
|
|
160
|
-
* grouped; the fraction is carried through verbatim, clamped to the pattern's ceiling.
|
|
161
|
-
*/
|
|
162
|
-
function applyFormat(raw, descriptor, locale, opts = {}) {
|
|
163
|
-
const value = String(raw ?? "");
|
|
164
|
-
if (!descriptor) return value;
|
|
165
|
-
if (descriptor.kind === "template") {
|
|
166
|
-
if (!value) return "";
|
|
167
|
-
return `${descriptor.before}${value}${descriptor.after}`;
|
|
168
|
-
}
|
|
169
|
-
if (!value || value === "-") return value;
|
|
170
|
-
const negative = value.startsWith("-");
|
|
171
|
-
const unsigned = negative ? value.slice(1) : value;
|
|
172
|
-
const [intRaw = "", fracRaw] = unsigned.split(".");
|
|
173
|
-
const hasPoint = unsigned.includes(".");
|
|
174
|
-
const { group, decimal } = localeSeparators(locale);
|
|
175
|
-
const digits = intRaw.replace(/\D/g, "").replace(/^0+(?=\d)/, "");
|
|
176
|
-
const grouped = descriptor.grouping ? addGrouping(digits, group) : digits;
|
|
177
|
-
let fraction = (fracRaw ?? "").replace(/\D/g, "").slice(0, descriptor.maxFraction);
|
|
178
|
-
if (opts.pad && descriptor.minFraction > 0) fraction = fraction.padEnd(descriptor.minFraction, "0");
|
|
179
|
-
let out = grouped || (hasPoint ? "0" : "");
|
|
180
|
-
if (fraction) out += decimal + fraction;
|
|
181
|
-
else if (hasPoint && descriptor.maxFraction > 0 && !opts.pad) out += decimal;
|
|
182
|
-
if (!out) return "";
|
|
183
|
-
return `${descriptor.prefix}${negative ? "-" : ""}${out}${descriptor.suffix}`;
|
|
184
|
-
}
|
|
185
|
-
/** Group a digit string from the right. */
|
|
186
|
-
function addGrouping(digits, separator) {
|
|
187
|
-
if (digits.length < 4) return digits;
|
|
188
|
-
let out = "";
|
|
189
|
-
for (let i = 0; i < digits.length; i++) {
|
|
190
|
-
if (i > 0 && (digits.length - i) % 3 === 0) out += separator;
|
|
191
|
-
out += digits[i];
|
|
192
|
-
}
|
|
193
|
-
return out;
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Normalise a raw value for the VALUE side.
|
|
197
|
-
*
|
|
198
|
-
* A number pattern yields a canonical numeric string (`"10000000.25"`) rather than the formatted
|
|
199
|
-
* text, so `Number(v)` works and a store that does arithmetic on it does not have to know a format
|
|
200
|
-
* was ever involved. A template yields the assembled string, because there the decoration IS the
|
|
201
|
-
* value — an email is not an email without its domain.
|
|
202
|
-
*/
|
|
203
|
-
function normaliseValue(raw, descriptor) {
|
|
204
|
-
const value = String(raw ?? "");
|
|
205
|
-
if (!descriptor) return value;
|
|
206
|
-
if (descriptor.kind === "template") return value ? `${descriptor.before}${value}${descriptor.after}` : "";
|
|
207
|
-
if (!value || value === "-") return "";
|
|
208
|
-
const negative = value.startsWith("-");
|
|
209
|
-
const [intRaw = "", fracRaw] = (negative ? value.slice(1) : value).split(".");
|
|
210
|
-
const digits = intRaw.replace(/\D/g, "");
|
|
211
|
-
const fraction = (fracRaw ?? "").replace(/\D/g, "").slice(0, descriptor.maxFraction);
|
|
212
|
-
let out = digits.replace(/^0+(?=\d)/, "");
|
|
213
|
-
if (!out) out = digits ? "0" : "";
|
|
214
|
-
if (!out && !fraction) return "";
|
|
215
|
-
if (fraction) out = `${out || "0"}.${fraction}`;
|
|
216
|
-
return negative && out ? `-${out}` : out;
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Where the caret belongs after the text was reformatted.
|
|
220
|
-
*
|
|
221
|
-
* Reformatting rewrites the whole field, and the browser then parks the caret at the end — so
|
|
222
|
-
* inserting a digit in the middle of a number would throw you to the end on every keystroke. The
|
|
223
|
-
* fix is to count in SIGNIFICANT characters (the ones the user actually typed) rather than in
|
|
224
|
-
* string offsets: count how many sit left of the caret before, then walk the new text until the
|
|
225
|
-
* same number have gone by.
|
|
226
|
-
*/
|
|
227
|
-
function caretAfterFormat(next, caretInPrev, prev, isSignificant) {
|
|
228
|
-
let typed = 0;
|
|
229
|
-
for (let i = 0; i < Math.min(caretInPrev, prev.length); i++) if (isSignificant(prev[i])) typed++;
|
|
230
|
-
if (typed === 0) {
|
|
231
|
-
let i = 0;
|
|
232
|
-
while (i < next.length && !isSignificant(next[i])) i++;
|
|
233
|
-
return i;
|
|
234
|
-
}
|
|
235
|
-
let seen = 0;
|
|
236
|
-
for (let i = 0; i < next.length; i++) if (isSignificant(next[i])) {
|
|
237
|
-
seen++;
|
|
238
|
-
if (seen === typed) return i + 1;
|
|
239
|
-
}
|
|
240
|
-
return next.length;
|
|
241
|
-
}
|
|
242
|
-
/**
|
|
243
|
-
* Which characters count as "typed" for caret purposes — everything the format did NOT insert.
|
|
244
|
-
*/
|
|
245
|
-
function significantFor(descriptor, locale) {
|
|
246
|
-
if (!descriptor || descriptor.kind === "template") return () => true;
|
|
247
|
-
const { decimal } = localeSeparators(locale);
|
|
248
|
-
return (ch) => /\d/.test(ch) || ch === decimal || ch === "-";
|
|
249
|
-
}
|
|
250
|
-
/** Resolve either form of a format prop to its finished text. */
|
|
251
|
-
function resolveFormat(format, raw, ctx, mode) {
|
|
252
|
-
if (format == null || format === "") return null;
|
|
253
|
-
if (typeof format === "function") return String(format({
|
|
254
|
-
value: raw,
|
|
255
|
-
type: ctx.type,
|
|
256
|
-
locale: ctx.locale
|
|
257
|
-
}) ?? "");
|
|
258
|
-
const descriptor = parseFormat(format);
|
|
259
|
-
if (!descriptor) return null;
|
|
260
|
-
return mode === "display" ? applyFormat(raw, descriptor, ctx.locale) : normaliseValue(raw, descriptor);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
//#endregion
|
|
264
16
|
//#region src/components/input/input-core.ts
|
|
265
17
|
const numberStringConverter = {
|
|
266
18
|
fromAttribute(value) {
|
|
@@ -274,6 +26,18 @@ const numberStringConverter = {
|
|
|
274
26
|
}
|
|
275
27
|
};
|
|
276
28
|
/**
|
|
29
|
+
* `modelValue` reflects to `model-value`, but only while it is TEXT — a `type="file"` value is a
|
|
30
|
+
* `File` / `File[]`, which would otherwise land in the DOM as `"[object File]"`.
|
|
31
|
+
*/
|
|
32
|
+
const modelValueConverter = {
|
|
33
|
+
fromAttribute(value) {
|
|
34
|
+
return value ?? "";
|
|
35
|
+
},
|
|
36
|
+
toAttribute(value) {
|
|
37
|
+
return typeof value === "string" ? value : null;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
277
41
|
* `MonoInputCore` — all render-mode-agnostic logic for `mono-input`: reactive
|
|
278
42
|
* props, hybrid prop aliases (camelCase ↔ kebab ↔ lowercase), attribute
|
|
279
43
|
* observation, value/model two-way sync, events, validation/class computation,
|
|
@@ -296,13 +60,27 @@ const MonoInputCore = (superClass) => {
|
|
|
296
60
|
this.size = "md";
|
|
297
61
|
this.color = "primary";
|
|
298
62
|
this.variant = "outlined";
|
|
63
|
+
this.labelPosition = "top";
|
|
64
|
+
this.validationPosition = "bottom";
|
|
299
65
|
this.modelValue = "";
|
|
300
66
|
this.value = "";
|
|
67
|
+
this.accept = "";
|
|
68
|
+
this.multiple = false;
|
|
69
|
+
this.showValue = true;
|
|
301
70
|
this.formatOn = "input";
|
|
302
71
|
this.name = "";
|
|
303
72
|
this.placeholder = "";
|
|
304
73
|
this.label = "";
|
|
305
74
|
this.helperText = "";
|
|
75
|
+
this.tooltip = null;
|
|
76
|
+
this._tooltip = new FieldTooltipController(this, () => this.tooltip);
|
|
77
|
+
this._validation = new FieldValidationController(this, () => ({
|
|
78
|
+
position: this.validationPosition,
|
|
79
|
+
...this._validationNotice ?? {
|
|
80
|
+
state: void 0,
|
|
81
|
+
text: void 0
|
|
82
|
+
}
|
|
83
|
+
}), () => this.renderRoot?.querySelector?.("[mono-input] > [mono-field]"));
|
|
306
84
|
this.validationState = "default";
|
|
307
85
|
this.validationMessage = "";
|
|
308
86
|
this.error = false;
|
|
@@ -327,6 +105,8 @@ const MonoInputCore = (superClass) => {
|
|
|
327
105
|
this._inputId = `mono-input-${Math.random().toString(36).slice(2)}`;
|
|
328
106
|
this._messageId = `${this._inputId}-message`;
|
|
329
107
|
defineHybridPropAliases(this, [
|
|
108
|
+
"labelPosition",
|
|
109
|
+
"validationPosition",
|
|
330
110
|
"modelValue",
|
|
331
111
|
"formatDisplay",
|
|
332
112
|
"formatValue",
|
|
@@ -340,6 +120,8 @@ const MonoInputCore = (superClass) => {
|
|
|
340
120
|
"ariaLabelText",
|
|
341
121
|
"minLength",
|
|
342
122
|
"maxLength",
|
|
123
|
+
"maxFileSize",
|
|
124
|
+
"showValue",
|
|
343
125
|
"cssClass",
|
|
344
126
|
"minWidth",
|
|
345
127
|
"maxWidth",
|
|
@@ -388,6 +170,8 @@ const MonoInputCore = (superClass) => {
|
|
|
388
170
|
"arialabel",
|
|
389
171
|
"minlength",
|
|
390
172
|
"maxlength",
|
|
173
|
+
"maxfilesize",
|
|
174
|
+
"showvalue",
|
|
391
175
|
"css-class",
|
|
392
176
|
"cssclass",
|
|
393
177
|
"formatdisplay",
|
|
@@ -448,10 +232,53 @@ const MonoInputCore = (superClass) => {
|
|
|
448
232
|
case "maxlength":
|
|
449
233
|
this.maxLength = this._toOptionalNumber(newValue);
|
|
450
234
|
return;
|
|
235
|
+
case "maxfilesize":
|
|
236
|
+
this.maxFileSize = this._toOptionalNumber(newValue);
|
|
237
|
+
return;
|
|
238
|
+
case "showvalue":
|
|
239
|
+
this.showValue = newValue === null ? true : booleanStringConverter.fromAttribute(newValue);
|
|
240
|
+
return;
|
|
451
241
|
}
|
|
452
242
|
}
|
|
243
|
+
/** The validation message and its state — the same precedence the message row uses. */
|
|
244
|
+
get _validationNotice() {
|
|
245
|
+
if (this.validationMessage) return {
|
|
246
|
+
state: this._resolvedValidationState,
|
|
247
|
+
text: this.validationMessage
|
|
248
|
+
};
|
|
249
|
+
if (this.errorMessage) return {
|
|
250
|
+
state: "invalid",
|
|
251
|
+
text: this.errorMessage
|
|
252
|
+
};
|
|
253
|
+
if (this.successMessage) return {
|
|
254
|
+
state: "valid",
|
|
255
|
+
text: this.successMessage
|
|
256
|
+
};
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
/** The message that moved to the icon / float bubble, kept for assistive tech only. */
|
|
260
|
+
_renderMovedMessage() {
|
|
261
|
+
const notice = this._validationNotice;
|
|
262
|
+
return html`<div
|
|
263
|
+
class=${`${this._cls("mono-input-message", "message")} ${notice.state}`}
|
|
264
|
+
mono-message=${notice.state}
|
|
265
|
+
mono-sr-only
|
|
266
|
+
role=${notice.state === "invalid" ? "alert" : nothing}
|
|
267
|
+
>${notice.text}</div>`;
|
|
268
|
+
}
|
|
453
269
|
willUpdate(changed) {
|
|
454
|
-
if (
|
|
270
|
+
if (this._isFile) {
|
|
271
|
+
if (changed.has("modelValue") || changed.has("type")) {
|
|
272
|
+
const files = this._fileList();
|
|
273
|
+
const names = this._fileNames(files);
|
|
274
|
+
this.value = names;
|
|
275
|
+
this._display = names;
|
|
276
|
+
if (!files.length && this._fileEl) this._fileEl.value = "";
|
|
277
|
+
}
|
|
278
|
+
this._internalWrite = false;
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
if (changed.has("modelValue") && this.value !== this.modelValue) this.value = typeof this.modelValue === "string" ? this.modelValue : "";
|
|
455
282
|
if (changed.has("value") && this.modelValue !== this.value) this.modelValue = String(this.value ?? "");
|
|
456
283
|
if (!this._internalWrite && !this._focused && (changed.has("value") || changed.has("modelValue") || changed.has("formatDisplay"))) this._syncDisplayFromValue();
|
|
457
284
|
this._internalWrite = false;
|
|
@@ -498,7 +325,7 @@ const MonoInputCore = (superClass) => {
|
|
|
498
325
|
this.readonly ? "readonly" : "",
|
|
499
326
|
this._resolvedValidationState !== "default" ? `is-${this._resolvedValidationState}` : "",
|
|
500
327
|
this._hasPrefixSlot ? "has-prefix" : "",
|
|
501
|
-
this._hasSuffixSlot || this.clearable ? "has-suffix" : "",
|
|
328
|
+
this._hasSuffixSlot || this.clearable || this._isFile ? "has-suffix" : "",
|
|
502
329
|
this.value ? "has-value" : "",
|
|
503
330
|
this.cssClassName,
|
|
504
331
|
this.cssClass?.root
|
|
@@ -514,12 +341,127 @@ const MonoInputCore = (superClass) => {
|
|
|
514
341
|
this.readonly ? "readonly" : "",
|
|
515
342
|
this._resolvedValidationState !== "default" ? `is-${this._resolvedValidationState}` : "",
|
|
516
343
|
this._hasPrefixSlot ? "has-prefix" : "",
|
|
517
|
-
this._hasSuffixSlot || this.clearable ? "has-suffix" : "",
|
|
344
|
+
this._hasSuffixSlot || this.clearable || this._isFile ? "has-suffix" : "",
|
|
518
345
|
this.value ? "has-value" : ""
|
|
519
346
|
].filter(Boolean).join(" ");
|
|
520
347
|
}
|
|
348
|
+
get _isFile() {
|
|
349
|
+
return this.type === "file";
|
|
350
|
+
}
|
|
351
|
+
get _isRange() {
|
|
352
|
+
return this.type === "range";
|
|
353
|
+
}
|
|
354
|
+
/** `min` / `max` / `step` as the native range resolves them (0 / 100 / 1 when unset). */
|
|
355
|
+
_rangeBounds() {
|
|
356
|
+
const min = this._toOptionalNumber(this.min) ?? 0;
|
|
357
|
+
const rawMax = this._toOptionalNumber(this.max) ?? 100;
|
|
358
|
+
const max = rawMax < min ? min : rawMax;
|
|
359
|
+
const step = this._toOptionalNumber(this.step);
|
|
360
|
+
return {
|
|
361
|
+
min,
|
|
362
|
+
max,
|
|
363
|
+
step: step && step > 0 ? step : 1
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* The value the slider is actually AT, as a string. An empty value is not a position — the
|
|
368
|
+
* native range parks itself at the midpoint — so the readout and the fill follow the native
|
|
369
|
+
* rule rather than reading `''` as 0. The model is not rewritten: nothing was chosen yet.
|
|
370
|
+
*/
|
|
371
|
+
get _rangeValue() {
|
|
372
|
+
const { min, max, step } = this._rangeBounds();
|
|
373
|
+
const target = this._toOptionalNumber(this.value) ?? min + (max - min) / 2;
|
|
374
|
+
const snapped = min + Math.round((target - min) / step) * step;
|
|
375
|
+
return String(Number(Math.min(max, Math.max(min, snapped)).toFixed(10)));
|
|
376
|
+
}
|
|
377
|
+
/** How far along the track the value sits, 0–100 — drives the fill. */
|
|
378
|
+
get _rangeProgress() {
|
|
379
|
+
const { min, max } = this._rangeBounds();
|
|
380
|
+
if (max === min) return 0;
|
|
381
|
+
return (Number(this._rangeValue) - min) / (max - min) * 100;
|
|
382
|
+
}
|
|
383
|
+
/** The readout text: the value drawn through `format-display`. */
|
|
384
|
+
get _rangeText() {
|
|
385
|
+
return this._formatDisplay(this._rangeValue, { pad: true });
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* A native range ignores `readonly`, so a readonly slider would still move. Put the thumb
|
|
389
|
+
* back where the value says and report that the event was handled.
|
|
390
|
+
*/
|
|
391
|
+
_revertReadonlyRange(event) {
|
|
392
|
+
if (!this._isRange || !this.readonly || this.disabled) return false;
|
|
393
|
+
event.currentTarget.value = this._rangeValue;
|
|
394
|
+
event.stopPropagation();
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
/** `modelValue` as an array of files, whatever shape it arrived in (File, File[], null, ''). */
|
|
398
|
+
_fileList() {
|
|
399
|
+
const isFile = (v) => !!v && typeof v === "object" && typeof v.name === "string";
|
|
400
|
+
const v = this.modelValue;
|
|
401
|
+
if (Array.isArray(v)) return v.filter(isFile);
|
|
402
|
+
return isFile(v) ? [v] : [];
|
|
403
|
+
}
|
|
404
|
+
_fileNames(files) {
|
|
405
|
+
return files.map((f) => f.name).join(", ");
|
|
406
|
+
}
|
|
407
|
+
_openFilePicker() {
|
|
408
|
+
if (this.disabled || this.readonly) return;
|
|
409
|
+
this._fileEl?.click();
|
|
410
|
+
}
|
|
411
|
+
_handleFileKeydown(event) {
|
|
412
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
413
|
+
event.preventDefault();
|
|
414
|
+
this._openFilePicker();
|
|
415
|
+
}
|
|
416
|
+
/** Files above `maxFileSize` are dropped, each one reported through `error`. */
|
|
417
|
+
_acceptFiles(files, sourceEvent) {
|
|
418
|
+
const limit = this.maxFileSize;
|
|
419
|
+
if (!limit || limit <= 0) return files;
|
|
420
|
+
return files.filter((file) => {
|
|
421
|
+
if (file.size <= limit) return true;
|
|
422
|
+
const detail = {
|
|
423
|
+
message: `File "${file.name}" exceeds the maximum size limit.`,
|
|
424
|
+
reason: "max-file-size",
|
|
425
|
+
file,
|
|
426
|
+
maxFileSize: limit,
|
|
427
|
+
sourceEvent
|
|
428
|
+
};
|
|
429
|
+
dispatchMonoEvent(this, "error", detail);
|
|
430
|
+
return false;
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* The picker's native `input` fires BEFORE its `change`, i.e. before the value below is
|
|
435
|
+
* written — left to bubble, a host `@input` (and a bound form) would read the OLD value. Our
|
|
436
|
+
* own `input` is emitted from the change handler instead.
|
|
437
|
+
*/
|
|
438
|
+
_swallowNativeInput(event) {
|
|
439
|
+
event.stopPropagation();
|
|
440
|
+
}
|
|
441
|
+
_handleFileChange(event) {
|
|
442
|
+
if (this.disabled || this.readonly) return;
|
|
443
|
+
const input = event.currentTarget;
|
|
444
|
+
const files = this._acceptFiles(Array.from(input.files ?? []), event);
|
|
445
|
+
if (!files.length) {
|
|
446
|
+
input.value = "";
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
this._internalWrite = true;
|
|
450
|
+
const oldValue = this.modelValue;
|
|
451
|
+
const nextValue = this.multiple ? files : files[0];
|
|
452
|
+
this.modelValue = nextValue;
|
|
453
|
+
this.value = this._display = this._fileNames(files);
|
|
454
|
+
const detail = this._createModelDetail({
|
|
455
|
+
modelValue: nextValue,
|
|
456
|
+
oldValue,
|
|
457
|
+
sourceEvent: event
|
|
458
|
+
});
|
|
459
|
+
this._emitInput(detail);
|
|
460
|
+
this._emitChange(detail);
|
|
461
|
+
}
|
|
521
462
|
_createModelDetail(args) {
|
|
522
463
|
return {
|
|
464
|
+
...this._isFile ? { files: this._fileList() } : {},
|
|
523
465
|
modelValue: args.modelValue,
|
|
524
466
|
currentValue: args.modelValue,
|
|
525
467
|
oldValue: args.oldValue,
|
|
@@ -669,11 +611,12 @@ const MonoInputCore = (superClass) => {
|
|
|
669
611
|
} catch {}
|
|
670
612
|
}
|
|
671
613
|
_handleInput(event) {
|
|
614
|
+
if (this._revertReadonlyRange(event)) return;
|
|
672
615
|
if (this.disabled || this.readonly) return;
|
|
673
616
|
this._internalWrite = true;
|
|
674
617
|
const input = event.currentTarget;
|
|
675
618
|
const oldValue = this.modelValue;
|
|
676
|
-
if (!this._hasFormat) {
|
|
619
|
+
if (!this._hasFormat || this._isRange) {
|
|
677
620
|
const nextValue = input.value;
|
|
678
621
|
this.value = nextValue;
|
|
679
622
|
this.modelValue = nextValue;
|
|
@@ -699,11 +642,12 @@ const MonoInputCore = (superClass) => {
|
|
|
699
642
|
}));
|
|
700
643
|
}
|
|
701
644
|
_handleChange(event) {
|
|
645
|
+
if (this._revertReadonlyRange(event)) return;
|
|
702
646
|
if (this.disabled || this.readonly) return;
|
|
703
647
|
this._internalWrite = true;
|
|
704
648
|
const input = event.currentTarget;
|
|
705
649
|
const oldValue = this.modelValue;
|
|
706
|
-
if (!this._hasFormat) {
|
|
650
|
+
if (!this._hasFormat || this._isRange) {
|
|
707
651
|
const nextValue = input.value;
|
|
708
652
|
this.value = nextValue;
|
|
709
653
|
this.modelValue = nextValue;
|
|
@@ -737,6 +681,21 @@ const MonoInputCore = (superClass) => {
|
|
|
737
681
|
if (this.disabled || this.readonly) return;
|
|
738
682
|
this._internalWrite = true;
|
|
739
683
|
const oldValue = this.modelValue;
|
|
684
|
+
if (this._isFile) {
|
|
685
|
+
const empty = this.multiple ? [] : null;
|
|
686
|
+
this.modelValue = empty;
|
|
687
|
+
this.value = this._display = "";
|
|
688
|
+
if (this._fileEl) this._fileEl.value = "";
|
|
689
|
+
this._inputEl?.focus();
|
|
690
|
+
const detail = this._createModelDetail({
|
|
691
|
+
modelValue: empty,
|
|
692
|
+
oldValue
|
|
693
|
+
});
|
|
694
|
+
this._emitInput(detail);
|
|
695
|
+
this._emitChange(detail);
|
|
696
|
+
this._emitClear(detail);
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
740
699
|
const nextValue = "";
|
|
741
700
|
this.value = nextValue;
|
|
742
701
|
this.modelValue = nextValue;
|
|
@@ -771,7 +730,10 @@ const MonoInputCore = (superClass) => {
|
|
|
771
730
|
mono-size=${this.size === "md" ? nothing : this.size}
|
|
772
731
|
mono-color=${this.color === "primary" ? nothing : this.color}
|
|
773
732
|
mono-variant=${this.variant === "outlined" ? nothing : this.variant}
|
|
733
|
+
mono-label-position=${this.labelPosition === "top" ? nothing : this.labelPosition}
|
|
734
|
+
mono-validation-position=${this.validationPosition === "bottom" ? nothing : this.validationPosition}
|
|
774
735
|
mono-validation-state=${state === "default" ? nothing : state}
|
|
736
|
+
mono-type=${this._isFile || this._isRange ? this.type : nothing}
|
|
775
737
|
?mono-disabled=${this.disabled}
|
|
776
738
|
?mono-readonly=${this.readonly}
|
|
777
739
|
?mono-required=${this.required}
|
|
@@ -786,8 +748,111 @@ const MonoInputCore = (superClass) => {
|
|
|
786
748
|
get _describedBy() {
|
|
787
749
|
return this.validationMessage || this.errorMessage || this.successMessage || this.helperText || this._hasHelperSlot ? this._messageId : void 0;
|
|
788
750
|
}
|
|
751
|
+
/**
|
|
752
|
+
* `type="file"`: a hidden native picker, and in front of it a read-only text input showing
|
|
753
|
+
* the picked name(s). The text input keeps `mono-native` + `.mono-input-native`, so focus,
|
|
754
|
+
* the label's `for`, sizing and the focus ring all behave exactly as on a text field.
|
|
755
|
+
*/
|
|
756
|
+
_renderFileNative() {
|
|
757
|
+
return html`
|
|
758
|
+
<input
|
|
759
|
+
type="file"
|
|
760
|
+
mono-file-input
|
|
761
|
+
hidden
|
|
762
|
+
tabindex="-1"
|
|
763
|
+
accept=${ifDefined(this.accept || void 0)}
|
|
764
|
+
?multiple=${this.multiple}
|
|
765
|
+
name=${ifDefined(this.name || void 0)}
|
|
766
|
+
?disabled=${this.disabled}
|
|
767
|
+
@input=${this._swallowNativeInput}
|
|
768
|
+
@change=${this._handleFileChange}
|
|
769
|
+
/>
|
|
770
|
+
<input
|
|
771
|
+
id=${this._inputId}
|
|
772
|
+
class=${`${this._cls("mono-input-native", "native")} ${this.size}`}
|
|
773
|
+
mono-native
|
|
774
|
+
mono-file
|
|
775
|
+
type="text"
|
|
776
|
+
readonly
|
|
777
|
+
.value=${this._display}
|
|
778
|
+
placeholder=${ifDefined(this.placeholder || void 0)}
|
|
779
|
+
?disabled=${this.disabled}
|
|
780
|
+
?required=${this.required}
|
|
781
|
+
aria-label=${ifDefined(this._ariaLabel)}
|
|
782
|
+
aria-invalid=${this._resolvedValidationState === "invalid" ? "true" : "false"}
|
|
783
|
+
aria-describedby=${ifDefined(this._describedBy)}
|
|
784
|
+
aria-haspopup="dialog"
|
|
785
|
+
@focus=${this._handleFocus}
|
|
786
|
+
@blur=${this._handleBlur}
|
|
787
|
+
@click=${this._openFilePicker}
|
|
788
|
+
@keydown=${this._handleFileKeydown}
|
|
789
|
+
/>
|
|
790
|
+
`;
|
|
791
|
+
}
|
|
792
|
+
/** `type="file"` — the upload glyph at the end of the field; clicking it opens the picker too. */
|
|
793
|
+
_renderFileIcon() {
|
|
794
|
+
if (!this._isFile) return nothing;
|
|
795
|
+
return html`
|
|
796
|
+
<span
|
|
797
|
+
class=${this._cls("mono-input-suffix", "fileIcon")}
|
|
798
|
+
mono-suffix
|
|
799
|
+
mono-file-icon
|
|
800
|
+
aria-hidden="true"
|
|
801
|
+
@click=${this._openFilePicker}
|
|
802
|
+
>${this.renderIcon("upload")}</span>
|
|
803
|
+
`;
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* `type="range"`: Basecoat's slider. The fill is a gradient stop on the track, so the element
|
|
807
|
+
* writes the position as `--mono-input-range-value` (Basecoat's `--slider-value`) — hand-written
|
|
808
|
+
* markup sets the same property itself.
|
|
809
|
+
*/
|
|
810
|
+
_renderRangeNative() {
|
|
811
|
+
const { min, max, step } = this._rangeBounds();
|
|
812
|
+
const text = this._rangeText;
|
|
813
|
+
return html`
|
|
814
|
+
<input
|
|
815
|
+
id=${this._inputId}
|
|
816
|
+
class=${`${this._cls("mono-input-native", "native")} ${this.size}`}
|
|
817
|
+
mono-native
|
|
818
|
+
mono-range
|
|
819
|
+
type="range"
|
|
820
|
+
min=${min}
|
|
821
|
+
max=${max}
|
|
822
|
+
step=${ifDefined(this.step == null ? void 0 : step)}
|
|
823
|
+
.value=${this._rangeValue}
|
|
824
|
+
name=${ifDefined(this.name || void 0)}
|
|
825
|
+
style=${`--mono-input-range-value: ${this._rangeProgress}%`}
|
|
826
|
+
?disabled=${this.disabled}
|
|
827
|
+
?required=${this.required}
|
|
828
|
+
aria-label=${ifDefined(this._ariaLabel)}
|
|
829
|
+
aria-valuetext=${ifDefined(text !== this._rangeValue ? text : void 0)}
|
|
830
|
+
aria-readonly=${ifDefined(this.readonly ? "true" : void 0)}
|
|
831
|
+
aria-invalid=${this._resolvedValidationState === "invalid" ? "true" : "false"}
|
|
832
|
+
aria-describedby=${ifDefined(this._describedBy)}
|
|
833
|
+
@focus=${this._handleFocus}
|
|
834
|
+
@blur=${this._handleBlur}
|
|
835
|
+
@input=${this._handleInput}
|
|
836
|
+
@change=${this._handleChange}
|
|
837
|
+
/>
|
|
838
|
+
`;
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* `type="range"` — the value readout. It sits at the end of the LABEL row when there is a
|
|
842
|
+
* label (the EJI ONE layout), and after the slider when there is not; each build calls this
|
|
843
|
+
* from both places and exactly one of them renders. `aria-hidden`: the slider already
|
|
844
|
+
* announces its value (`aria-valuetext` carries the formatted text).
|
|
845
|
+
*/
|
|
846
|
+
_renderRangeValue(where) {
|
|
847
|
+
if (!this._isRange || !this.showValue) return nothing;
|
|
848
|
+
const inLabel = !!(this.label || this._hasLabelSlot);
|
|
849
|
+
if (where === "label" !== inLabel) return nothing;
|
|
850
|
+
return html`<span class=${this._cls("mono-input-range-value", "rangeValue")} mono-range-value aria-hidden="true">${this._rangeText}</span>`;
|
|
851
|
+
}
|
|
789
852
|
/** The native <input>, shared by both builds' render(). */
|
|
790
853
|
_renderNative() {
|
|
854
|
+
if (this._isFile) return this._renderFileNative();
|
|
855
|
+
if (this._isRange) return this._renderRangeNative();
|
|
791
856
|
return html`
|
|
792
857
|
<input
|
|
793
858
|
id=${this._inputId}
|
|
@@ -820,7 +885,7 @@ const MonoInputCore = (superClass) => {
|
|
|
820
885
|
}
|
|
821
886
|
/** The clear button (uses the build-specific icon). */
|
|
822
887
|
_renderClear() {
|
|
823
|
-
if (!(this.clearable && this.value && !this.disabled && !this.readonly)) return nothing;
|
|
888
|
+
if (this._isRange || !(this.clearable && this.value && !this.disabled && !this.readonly)) return nothing;
|
|
824
889
|
return html`
|
|
825
890
|
<button
|
|
826
891
|
type="button"
|
|
@@ -861,10 +926,31 @@ const MonoInputCore = (superClass) => {
|
|
|
861
926
|
__decorate([property({ type: String })], MonoInputCoreClass.prototype, "variant", void 0);
|
|
862
927
|
__decorate([property({
|
|
863
928
|
type: String,
|
|
929
|
+
attribute: "label-position"
|
|
930
|
+
})], MonoInputCoreClass.prototype, "labelPosition", void 0);
|
|
931
|
+
__decorate([property({
|
|
932
|
+
type: String,
|
|
933
|
+
attribute: "validation-position"
|
|
934
|
+
})], MonoInputCoreClass.prototype, "validationPosition", void 0);
|
|
935
|
+
__decorate([property({
|
|
864
936
|
attribute: "model-value",
|
|
865
|
-
reflect: true
|
|
937
|
+
reflect: true,
|
|
938
|
+
converter: modelValueConverter
|
|
866
939
|
})], MonoInputCoreClass.prototype, "modelValue", void 0);
|
|
867
940
|
__decorate([property({ type: String })], MonoInputCoreClass.prototype, "value", void 0);
|
|
941
|
+
__decorate([property({ type: String })], MonoInputCoreClass.prototype, "accept", void 0);
|
|
942
|
+
__decorate([property({
|
|
943
|
+
reflect: true,
|
|
944
|
+
converter: booleanStringConverter
|
|
945
|
+
})], MonoInputCoreClass.prototype, "multiple", void 0);
|
|
946
|
+
__decorate([property({
|
|
947
|
+
attribute: "max-file-size",
|
|
948
|
+
converter: numberStringConverter
|
|
949
|
+
})], MonoInputCoreClass.prototype, "maxFileSize", void 0);
|
|
950
|
+
__decorate([property({
|
|
951
|
+
attribute: "show-value",
|
|
952
|
+
converter: { fromAttribute: (v) => v === null ? true : booleanStringConverter.fromAttribute(v) }
|
|
953
|
+
})], MonoInputCoreClass.prototype, "showValue", void 0);
|
|
868
954
|
__decorate([property({ attribute: false })], MonoInputCoreClass.prototype, "formatDisplay", void 0);
|
|
869
955
|
__decorate([property({ attribute: false })], MonoInputCoreClass.prototype, "formatValue", void 0);
|
|
870
956
|
__decorate([property({ attribute: "format-on" })], MonoInputCoreClass.prototype, "formatOn", void 0);
|
|
@@ -876,6 +962,7 @@ const MonoInputCore = (superClass) => {
|
|
|
876
962
|
type: String,
|
|
877
963
|
attribute: "helper-text"
|
|
878
964
|
})], MonoInputCoreClass.prototype, "helperText", void 0);
|
|
965
|
+
__decorate([property()], MonoInputCoreClass.prototype, "tooltip", void 0);
|
|
879
966
|
__decorate([property({
|
|
880
967
|
type: String,
|
|
881
968
|
attribute: "validation-state"
|
|
@@ -957,6 +1044,7 @@ const MonoInputCore = (superClass) => {
|
|
|
957
1044
|
attribute: "max-height"
|
|
958
1045
|
})], MonoInputCoreClass.prototype, "maxHeight", void 0);
|
|
959
1046
|
__decorate([query(".mono-input-native")], MonoInputCoreClass.prototype, "_inputEl", void 0);
|
|
1047
|
+
__decorate([query("[mono-file-input]")], MonoInputCoreClass.prototype, "_fileEl", void 0);
|
|
960
1048
|
__decorate([state()], MonoInputCoreClass.prototype, "_display", void 0);
|
|
961
1049
|
__decorate([state()], MonoInputCoreClass.prototype, "_focused", void 0);
|
|
962
1050
|
__decorate([state()], MonoInputCoreClass.prototype, "_hasPrefixSlotState", void 0);
|
|
@@ -968,7 +1056,7 @@ const MonoInputCore = (superClass) => {
|
|
|
968
1056
|
|
|
969
1057
|
//#endregion
|
|
970
1058
|
//#region \0raw:C:\Users\VCT-DEV\Desktop\libs\packages\helper\src\components\input\input.css?raw.js
|
|
971
|
-
var input_css_raw_default = "/* =========================================================================\r\n mono-input — a port of Basecoat's `.field` / `.input-group` / `.label`\r\n (basecoat-css@1.0.2, vega style).\r\n\r\n Styled by ATTRIBUTE, like Basecoat (`.input-group:has([aria-invalid])`) —\r\n and the attributes mirror the element's props one for one, so hand-written\r\n markup reads like the Lit / Vue tag:\r\n\r\n <mono-input size=\"sm\" color=\"danger\" variant=\"filled\" label=\"Name\">\r\n <div mono-input mono-size=\"sm\" mono-color=\"danger\" mono-variant=\"filled\">\r\n <label mono-label>Name</label>\r\n <div mono-field><input mono-native></div>\r\n </div>\r\n\r\n An absent attribute is the prop's default (`:not([mono-size])` = md,\r\n `:not([mono-color])` = primary, `:not([mono-variant])` = outlined,\r\n `:not([mono-validation-state])` = default). The element renders these\r\n attributes on its wrapper (both builds); the old classes\r\n (`.mono-input.sm.danger.filled`) are still emitted as inert hooks for\r\n consumer CSS until 2.0 but no rule here reads them.\r\n\r\n Selector map (ours ≡ upstream):\r\n [mono-input] ≡ .field (flex column, gap-3)\r\n [mono-input] > [mono-label] ≡ .field > label / .label\r\n [mono-input] > [mono-field] ≡ .input-group (the bordered box: h-9 rounded-md border-input shadow-xs)\r\n [mono-field] > [mono-native] ≡ .input-group > input (borderless, px-2.5 text-sm; `.input` for the metrics)\r\n [mono-field] > [mono-prefix|mono-suffix] ≡ .input-group > span[data-align='start'|'end']\r\n [mono-field] > [mono-clear] ≡ .input-group > button[data-align='end']:has(> svg)\r\n [mono-input] > [mono-message-wrap] ≡ .field > p\r\n [mono-message=\"helper\"] ≡ .field > p (text-sm text-muted-foreground)\r\n [mono-message=\"invalid\"] ≡ .field [role='alert']\r\n [mono-validation-state=\"invalid\"] ≡ .input-group:has([aria-invalid=true]) + .field[data-invalid]\r\n [mono-validation-state=\"valid|warning\"] ≡ EXTENSION (the invalid pattern with --success / --warning)\r\n [mono-size=\"xs|sm|lg|xl|xxl\"] ≡ EXTENSION (Basecoat sizes only the select; the ladder is --mono-control-height-*)\r\n [mono-variant=\"filled\"] ≡ EXTENSION (luma's .input-group: border-transparent bg-input/50, ring-ring/30)\r\n [mono-variant=\"underlined\"] ≡ EXTENSION (sera's .input-group: rounded-none border-b-input px-0, no ring)\r\n [mono-disabled] / [mono-native]:disabled ≡ .input-group:has(input:disabled) — opacity-50\r\n [mono-readonly] ≡ EXTENSION (a muted surface)\r\n\r\n Specificity contract (same as the pre-port class sheet, and as checkbox.css):\r\n a part's RESTING rule is written `:where([mono-input]) [mono-part]` = exactly\r\n one attribute, (0,1,0) — so a utility class composed onto the markup (the\r\n `cssClass` prop, or a hand-written class in a css/ demo) wins by source order,\r\n while the prop and state rules ([mono-size], [mono-variant], [mono-disabled],\r\n :focus-within, [aria-invalid], …) stay heavier and still win over it.\r\n\r\n Inner parts are attributes too: [mono-label] (+ [mono-required-mark]),\r\n [mono-field], [mono-prefix] / [mono-suffix] (+ [mono-empty] in the shadow\r\n build for an unassigned slot), [mono-native], [mono-clear] > [mono-icon],\r\n [mono-message-wrap] > [mono-message=\"helper|valid|invalid|warning\"].\r\n\r\n Values are copied from the compiled vendor sheet (vendor/basecoat/basecoat-\r\n vega.cdn.css) through the token layer: `--spacing` → `--mono-spacing`,\r\n `--text-sm` → `--mono-text-sm`, `--radius-md` → `--mono-radius-md`,\r\n `--color-x` → `--x`, Tailwind's `--tw-ring-*` stack → the two-slot\r\n `box-shadow: ring, shadow` below, and every `dark:` variant → a\r\n `--mono-mode-*` token (a selector cannot cross a shadow boundary; an\r\n inherited custom property can).\r\n\r\n FLAVORS (Basecoat's other seven styles, src/data/theme/flavors/*.css) set\r\n the knobs read below — `--mono-input-radius`, `--mono-input-padding-x-<size>`,\r\n `--mono-input-font-<size>`, `--mono-input-line-height`, `--mono-input-ring-width`,\r\n `--mono-input-ring-alpha`, `--mono-input-gap`, `--mono-input-affix-*`,\r\n `--mono-input-label-*`, `--mono-input-message-*`, `--mono-input-clear-radius`,\r\n `--mono-input-disabled-bg`, and the outline-variant set `--mono-input-outline-\r\n {bg,border-color,side-border-color,shadow,ring-width,radius,padding-x,affix-padding}`.\r\n Every fallback here is vega's value\r\n (`node scripts/basecoat-styles.mjs --varying \"^\\.(field|label|input|input-group)\\b\"`).\r\n\r\n The public `--mono-input-*` knobs and the three-tier resolver\r\n (`--mono-input-x` → `--_mono-input-x-preset` → base) are unchanged: a\r\n colour / variant attribute only ever writes a `*-preset` slot, so a\r\n consumer's own `--mono-input-bg` on the host still wins.\r\n ========================================================================= */\r\n\r\nmono-input {\r\n display: block;\r\n}\r\n\r\n[mono-input] {\r\n /* ── palette: each slot is a public knob over a Basecoat token ─────────── */\r\n --_mono-input-text: var(--mono-input-color, var(--mono-input-text, var(--foreground)));\r\n --_mono-input-placeholder: var(--mono-input-placeholder, var(--muted-foreground));\r\n --_mono-input-muted: var(--mono-input-muted, var(--muted-foreground));\r\n /* the `color` prop picks the FOCUS colour; primary is Basecoat's `--ring` */\r\n --_mono-input-primary: var(--mono-input-primary, var(--ring));\r\n --_mono-input-secondary: var(--mono-input-secondary, var(--muted-foreground));\r\n --_mono-input-success: var(--mono-input-success, var(--success));\r\n --_mono-input-danger: var(--mono-input-danger, var(--destructive));\r\n --_mono-input-warning: var(--mono-input-warning, var(--warning));\r\n --_mono-input-info: var(--mono-input-info, var(--info));\r\n --_mono-input-teal: var(--mono-input-teal, var(--teal));\r\n --_mono-input-purple: var(--mono-input-purple, var(--purple));\r\n --_mono-input-neutral: var(--mono-input-neutral, var(--neutral));\r\n --_mono-input-dark: var(--mono-input-dark, var(--dark));\r\n --_mono-input-valid: var(--mono-input-valid, var(--success));\r\n --_mono-input-invalid: var(--mono-input-invalid, var(--destructive));\r\n\r\n /* ── the painted result — three tiers, base = .input-group (vega) ──────── */\r\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))));\r\n --_mono-input-ring-width: var(--mono-input-ring-width, var(--_mono-input-ring-width-preset, var(--mono-ring-width)));\r\n --_mono-input-ring-alpha: var(--mono-input-ring-alpha, var(--mono-ring-alpha));\r\n --_mono-input-border-color: var(--mono-input-rest-border, var(--mono-input-border-color, var(--_mono-input-border-color-preset, var(--input))));\r\n --_mono-input-bg: var(--mono-input-bg, var(--mono-input-surface, var(--_mono-input-bg-preset, var(--mono-mode-surface))));\r\n --_mono-input-shadow: var(--mono-input-shadow, var(--_mono-input-shadow-preset, 0 0 #0000));\r\n --_mono-input-affix-padding: var(--mono-input-affix-padding, var(--_mono-input-affix-padding-preset, calc(var(--mono-spacing) * 2)));\r\n --_mono-input-affix-icon: var(--mono-input-affix-icon-size, calc(var(--mono-spacing) * 4));\r\n\r\n /* ── md metrics live on the unqualified root ON PURPOSE: hand-written\r\n `<div mono-input>` that names no size renders exactly like size=\"md\".\r\n basecoat@1.0.2 styles/vega.css .input-group — h-9 rounded-md; > input px-2.5 text-sm ── */\r\n --_mono-input-height: var(--mono-input-height-md, var(--mono-control-height-md));\r\n --_mono-input-radius: var(--mono-input-radius-md, var(--_mono-input-radius-preset, var(--mono-input-radius, var(--mono-radius-md))));\r\n --_mono-input-padding-x: var(--mono-input-padding-x-md, var(--_mono-input-padding-x-preset, calc(var(--mono-spacing) * 2.5)));\r\n --_mono-input-font-size: var(--mono-input-font-md, var(--mono-text-sm));\r\n --_mono-input-line-height: var(--mono-input-line-height, var(--mono-input-line-height-md, var(--mono-text-sm--lh)));\r\n --_mono-input-clear: calc(var(--mono-spacing) * 6);\r\n --_mono-input-clear-glyph: calc(var(--mono-spacing) * 3.5);\r\n\r\n /* basecoat@1.0.2 styles/vega.css .field — flex w-full flex-col gap-3 */\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--mono-input-gap, calc(var(--mono-spacing) * 3));\r\n width: 100%;\r\n font-family: inherit;\r\n color: var(--_mono-input-text);\r\n}\r\n\r\n/* A page-level `* { box-sizing: border-box }` reset does NOT cross a shadow\r\n boundary; scoped here so both builds measure the same. */\r\n[mono-input],\r\n:where([mono-input]) *,\r\n:where([mono-input]) *::before,\r\n:where([mono-input]) *::after {\r\n box-sizing: border-box;\r\n}\r\n\r\n/* The shadow build renders every slot wrapper and marks an unassigned one\r\n `mono-empty`; the light build simply omits it. Inert in the light build. */\r\n:where([mono-input]) :is([mono-label], [mono-prefix], [mono-suffix], [mono-message])[mono-empty] {\r\n display: none;\r\n}\r\n\r\n/* =========================================\r\n Sizes — the field's painted height IS the token (tests/perf/field-heights).\r\n EXTENSION: Basecoat sizes only its select (data-size=sm); the ladder is the\r\n shared --mono-control-height-* scale and the text follows .btn's steps.\r\n ========================================= */\r\n\r\n/* `.input` is text-base under 48rem (no iOS zoom) and md:text-sm above it —\r\n vendor behaviour, kept for the default size only. */\r\n@media (width < 48rem) {\r\n [mono-input]:is(:not([mono-size]), [mono-size=\"md\"]) {\r\n --_mono-input-font-size: var(--mono-input-font-md, var(--mono-text-base));\r\n --_mono-input-line-height: var(--mono-input-line-height, var(--mono-input-line-height-md, var(--mono-text-base--lh)));\r\n }\r\n}\r\n\r\n[mono-input][mono-size=\"xs\"] {\r\n --_mono-input-height: var(--mono-input-height-xs, var(--mono-control-height-xs));\r\n --_mono-input-radius: var(--mono-input-radius-xs, var(--_mono-input-radius-preset, var(--mono-input-radius, var(--mono-radius-md))));\r\n --_mono-input-padding-x: var(--mono-input-padding-x-xs, var(--_mono-input-padding-x-preset, calc(var(--mono-spacing) * 2)));\r\n --_mono-input-font-size: var(--mono-input-font-xs, var(--mono-text-xs));\r\n --_mono-input-line-height: var(--mono-input-line-height, var(--mono-input-line-height-xs, var(--mono-text-xs--lh)));\r\n --_mono-input-affix-icon: var(--mono-input-affix-icon-size, calc(var(--mono-spacing) * 3.5));\r\n --_mono-input-clear: calc(var(--mono-spacing) * 4);\r\n --_mono-input-clear-glyph: calc(var(--mono-spacing) * 3);\r\n}\r\n\r\n[mono-input][mono-size=\"sm\"] {\r\n --_mono-input-height: var(--mono-input-height-sm, var(--mono-control-height-sm));\r\n --_mono-input-radius: var(--mono-input-radius-sm, var(--_mono-input-radius-preset, var(--mono-input-radius, var(--mono-radius-md))));\r\n --_mono-input-padding-x: var(--mono-input-padding-x-sm, var(--_mono-input-padding-x-preset, calc(var(--mono-spacing) * 2.5)));\r\n --_mono-input-font-size: var(--mono-input-font-sm, var(--mono-input-font-md, var(--mono-text-sm)));\r\n --_mono-input-line-height: var(--mono-input-line-height, var(--mono-input-line-height-sm, var(--mono-text-sm--lh)));\r\n --_mono-input-clear: calc(var(--mono-spacing) * 5);\r\n --_mono-input-clear-glyph: calc(var(--mono-spacing) * 3.5);\r\n}\r\n\r\n[mono-input][mono-size=\"lg\"] {\r\n --_mono-input-height: var(--mono-input-height-lg, var(--mono-control-height-lg));\r\n --_mono-input-radius: var(--mono-input-radius-lg, var(--_mono-input-radius-preset, var(--mono-input-radius, var(--mono-radius-md))));\r\n --_mono-input-padding-x: var(--mono-input-padding-x-lg, var(--_mono-input-padding-x-preset, calc(var(--mono-spacing) * 2.5)));\r\n --_mono-input-font-size: var(--mono-input-font-lg, var(--mono-input-font-md, var(--mono-text-sm)));\r\n --_mono-input-line-height: var(--mono-input-line-height, var(--mono-input-line-height-lg, var(--mono-text-sm--lh)));\r\n}\r\n\r\n[mono-input][mono-size=\"xl\"] {\r\n --_mono-input-height: var(--mono-input-height-xl, var(--mono-control-height-xl));\r\n --_mono-input-radius: var(--mono-input-radius-xl, var(--_mono-input-radius-preset, var(--mono-input-radius, var(--mono-radius-md))));\r\n --_mono-input-padding-x: var(--mono-input-padding-x-xl, var(--_mono-input-padding-x-preset, calc(var(--mono-spacing) * 3)));\r\n --_mono-input-font-size: var(--mono-input-font-xl, var(--mono-text-base));\r\n --_mono-input-line-height: var(--mono-input-line-height, var(--mono-input-line-height-xl, var(--mono-text-base--lh)));\r\n --_mono-input-affix-icon: var(--mono-input-affix-icon-size, calc(var(--mono-spacing) * 5));\r\n --_mono-input-clear: calc(var(--mono-spacing) * 7);\r\n --_mono-input-clear-glyph: calc(var(--mono-spacing) * 4);\r\n}\r\n\r\n[mono-input][mono-size=\"xxl\"] {\r\n --_mono-input-height: var(--mono-input-height-xxl, var(--mono-control-height-xxl));\r\n --_mono-input-radius: var(--mono-input-radius-xxl, var(--_mono-input-radius-preset, var(--mono-input-radius, var(--mono-radius-md))));\r\n --_mono-input-padding-x: var(--mono-input-padding-x-xxl, var(--_mono-input-padding-x-preset, calc(var(--mono-spacing) * 4)));\r\n --_mono-input-font-size: var(--mono-input-font-xxl, var(--mono-text-lg));\r\n --_mono-input-line-height: var(--mono-input-line-height, var(--mono-input-line-height-xxl, var(--mono-text-lg--lh)));\r\n --_mono-input-affix-icon: var(--mono-input-affix-icon-size, calc(var(--mono-spacing) * 5));\r\n --_mono-input-clear: calc(var(--mono-spacing) * 8);\r\n --_mono-input-clear-glyph: calc(var(--mono-spacing) * 4);\r\n}\r\n\r\n/* =========================================\r\n Variants — each writes only `*-preset` slots\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 styles/vega.css .input-group — rounded-md border border-input\r\n shadow-xs, bg-transparent (dark:bg-input/30 via --mono-mode-surface). The\r\n `--mono-input-outline-*` knobs are how a flavor restyles THIS variant alone\r\n (maia bg-input/30, luma / rhea border-transparent bg-input/50, sera the\r\n underline) without touching filled / underlined. */\r\n[mono-input]:is(:not([mono-variant]), [mono-variant=\"outlined\"]) {\r\n --_mono-input-bg-preset: var(--mono-input-outline-bg);\r\n --_mono-input-border-color-preset: var(--mono-input-outline-border-color);\r\n --_mono-input-side-border-color-preset: var(--mono-input-outline-side-border-color);\r\n --_mono-input-shadow-preset: var(--mono-input-outline-shadow, var(--mono-shadow-xs));\r\n --_mono-input-ring-width-preset: var(--mono-input-outline-ring-width);\r\n --_mono-input-radius-preset: var(--mono-input-outline-radius);\r\n --_mono-input-padding-x-preset: var(--mono-input-outline-padding-x);\r\n --_mono-input-affix-padding-preset: var(--mono-input-outline-affix-padding);\r\n}\r\n\r\n/* EXTENSION — filled ≡ basecoat@1.0.2 styles/luma.css .input-group:\r\n border-transparent bg-input/50, no shadow-xs (the ring stays) */\r\n[mono-input][mono-variant=\"filled\"] {\r\n --_mono-input-bg-preset: var(--mono-input-filled-bg, color-mix(in oklab, var(--input) 50%, transparent));\r\n --_mono-input-border-color-preset: transparent;\r\n --_mono-input-shadow-preset: 0 0 #0000;\r\n}\r\n\r\n/* EXTENSION — underlined ≡ basecoat@1.0.2 styles/sera.css .input-group:\r\n rounded-none border-transparent border-b-input bg-transparent px-0, no\r\n shadow, no ring, focus-within:border-b-ring, has-[aria-invalid]:border-b-destructive.\r\n Only the bottom edge paints; the sides are transparent in every state. */\r\n[mono-input][mono-variant=\"underlined\"] {\r\n --_mono-input-bg-preset: transparent;\r\n --_mono-input-side-border-color-preset: transparent;\r\n --_mono-input-shadow-preset: 0 0 #0000;\r\n --_mono-input-ring-width-preset: 0px;\r\n --_mono-input-radius-preset: 0;\r\n --_mono-input-padding-x-preset: 0;\r\n --_mono-input-affix-padding-preset: 0;\r\n}\r\n\r\n/* =========================================\r\n Colours — the `color` prop is the FOCUS colour (ring + focused border).\r\n No resting tint: Basecoat fields rest on --input whatever their role.\r\n ========================================= */\r\n\r\n[mono-input]:is(:not([mono-color]), [mono-color=\"primary\"]) {\r\n --_mono-input-ring-color-preset: var(--_mono-input-primary);\r\n}\r\n[mono-input][mono-color=\"secondary\"] {\r\n --_mono-input-ring-color-preset: var(--_mono-input-secondary);\r\n}\r\n[mono-input][mono-color=\"success\"] {\r\n --_mono-input-ring-color-preset: var(--_mono-input-success);\r\n}\r\n[mono-input][mono-color=\"danger\"] {\r\n --_mono-input-ring-color-preset: var(--_mono-input-danger);\r\n}\r\n[mono-input][mono-color=\"warning\"] {\r\n --_mono-input-ring-color-preset: var(--_mono-input-warning);\r\n}\r\n[mono-input][mono-color=\"info\"] {\r\n --_mono-input-ring-color-preset: var(--_mono-input-info);\r\n}\r\n[mono-input][mono-color=\"teal\"] {\r\n --_mono-input-ring-color-preset: var(--_mono-input-teal);\r\n}\r\n[mono-input][mono-color=\"purple\"] {\r\n --_mono-input-ring-color-preset: var(--_mono-input-purple);\r\n}\r\n[mono-input][mono-color=\"neutral\"] {\r\n --_mono-input-ring-color-preset: var(--_mono-input-neutral);\r\n}\r\n[mono-input][mono-color=\"dark\"] {\r\n --_mono-input-ring-color-preset: var(--_mono-input-dark);\r\n}\r\n\r\n/* =========================================\r\n Label\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 styles/vega.css .field > label, .label — flex items-center\r\n gap-2 text-sm leading-none font-medium select-none w-fit */\r\n:where([mono-input]) > [mono-label] {\r\n display: flex;\r\n align-items: center;\r\n width: fit-content;\r\n gap: var(--mono-input-label-gap, calc(var(--mono-spacing) * 2));\r\n font-size: var(--mono-input-label-font-size, var(--mono-text-sm));\r\n line-height: var(--mono-input-label-line-height, 1);\r\n font-weight: var(--mono-input-label-font-weight, var(--mono-label-font-weight, var(--mono-font-weight-medium)));\r\n text-transform: var(--mono-input-label-text-transform, none);\r\n letter-spacing: var(--mono-input-label-letter-spacing, normal);\r\n color: var(--_mono-input-text);\r\n user-select: none;\r\n}\r\n\r\n/* in-data-[disabled=true]:opacity-50 / peer-disabled:opacity-50 */\r\n[mono-input][mono-disabled] > [mono-label],\r\n[mono-input]:has(> [mono-field] > [mono-native]:disabled) > [mono-label] {\r\n opacity: 0.5;\r\n pointer-events: none;\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .field — data-invalid:text-destructive */\r\n[mono-input][mono-validation-state=\"invalid\"] > [mono-label],\r\n[mono-input]:has(> [mono-field] > [mono-native][aria-invalid=\"true\"]) > [mono-label] {\r\n color: var(--_mono-input-invalid);\r\n}\r\n\r\n/* EXTENSION — the required asterisk */\r\n:where([mono-input]) [mono-required-mark] {\r\n color: var(--_mono-input-danger);\r\n}\r\n\r\n/* =========================================\r\n The field — the bordered box\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 components/input-group.css .input-group */\r\n/* basecoat@1.0.2 styles/vega.css .input-group — h-9 rounded-md border\r\n border-input shadow-xs transition-[color,box-shadow] focus-within:border-ring\r\n focus-within:ring-3 focus-within:ring-ring/50; mono: `--tw-ring-*` flattened to\r\n the ring + shadow slots, the height is the control token, and the side\r\n edges read their own slot so a flavor can keep only the bottom one */\r\n:where([mono-input]) > [mono-field] {\r\n --_mono-input-bc: var(--_mono-input-border-color);\r\n --_mono-input-side-bc: var(--mono-input-side-border-color, var(--_mono-input-side-border-color-preset, var(--_mono-input-bc)));\r\n /* The focus / state ring slot — `0 0 #0000` until a state sets it. Kept as a\r\n slot so a variant can neutralise the resting shadow without ever writing\r\n `box-shadow: none` (which would out-specify the ring). */\r\n --_mono-input-ring: 0 0 #0000;\r\n\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n width: 100%;\r\n min-width: 0;\r\n min-height: var(--_mono-input-height);\r\n outline-style: none;\r\n border: var(--mono-border-width) solid var(--_mono-input-bc);\r\n border-top-color: var(--_mono-input-side-bc);\r\n border-inline-color: var(--_mono-input-side-bc);\r\n border-radius: var(--_mono-input-radius);\r\n background: var(--_mono-input-bg);\r\n color: var(--_mono-input-text);\r\n box-shadow: var(--_mono-input-ring), var(--_mono-input-shadow);\r\n transition-property: color, box-shadow, border-color, background-color;\r\n transition-timing-function: var(--mono-ease);\r\n transition-duration: var(--mono-duration);\r\n\r\n /* focus-within:border-ring focus-within:ring-3 focus-within:ring-ring/50 */\r\n &:focus-within {\r\n --_mono-input-bc: var(--_mono-input-ring-color);\r\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);\r\n }\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .input-group — has-[[aria-invalid=true]]:border-destructive\r\n has-[[aria-invalid=true]]:ring-3 has-[[aria-invalid=true]]:ring-destructive/20\r\n (dark: border /50, ring /40 — carried by the mode tokens). The ring is\r\n permanent, and it wins over the focus ring — same as the vendor order. */\r\n[mono-input][mono-validation-state=\"invalid\"] > [mono-field],\r\n:where([mono-input]) > [mono-field]:has(> [mono-native][aria-invalid=\"true\"]) {\r\n --_mono-input-bc: var(--mono-mode-invalid-border);\r\n --_mono-input-ring: 0 0 0 var(--_mono-input-ring-width) var(--mono-mode-invalid-ring);\r\n}\r\n\r\n/* EXTENSION — valid / warning are the invalid pattern in the role's colour */\r\n[mono-input][mono-validation-state=\"valid\"] > [mono-field] {\r\n --_mono-input-bc: color-mix(in oklab, var(--_mono-input-valid) var(--mono-mode-state-border-alpha), transparent);\r\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);\r\n}\r\n[mono-input][mono-validation-state=\"warning\"] > [mono-field] {\r\n --_mono-input-bc: color-mix(in oklab, var(--_mono-input-warning) var(--mono-mode-state-border-alpha), transparent);\r\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);\r\n}\r\n\r\n/* EXTENSION — readonly: focusable, on a muted surface */\r\n[mono-input][mono-readonly] > [mono-field],\r\n:where([mono-input]) > [mono-field]:has(> [mono-native]:read-only:not(:disabled)) {\r\n background: var(--mono-input-readonly-bg, var(--muted));\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .input-group:has(> :is(input, textarea, select, [data-control]):disabled) — opacity-50\r\n (`--mono-input-disabled-bg`: nova / lyra add disabled:bg-input/50) */\r\n[mono-input][mono-disabled] > [mono-field],\r\n:where([mono-input]) > [mono-field]:has(> [mono-native]:disabled) {\r\n opacity: 0.5;\r\n cursor: not-allowed;\r\n background: var(--mono-input-disabled-bg, var(--_mono-input-bg));\r\n}\r\n\r\n/* =========================================\r\n The native input\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 components/input-group.css .input-group > :is(input, textarea, select, [data-control]) —\r\n block min-w-0 flex-1 appearance-none rounded-none border-0 bg-transparent\r\n text-foreground shadow-none outline-none placeholder:text-muted-foreground */\r\n/* basecoat@1.0.2 styles/vega.css .input-group > :is(input, select, [data-control])\r\n — px-2.5 py-1 text-sm; mono: no block padding — the FIELD owns the height\r\n (`min-height: token`) and `align-self: stretch` spans the click target */\r\n:where([mono-input]) [mono-native] {\r\n display: block;\r\n flex: 1 1 auto;\r\n width: 100%;\r\n min-width: 0;\r\n align-self: stretch;\r\n appearance: none;\r\n margin: 0;\r\n border: 0;\r\n border-radius: 0;\r\n outline: none;\r\n background: transparent;\r\n box-shadow: none;\r\n color: var(--_mono-input-text);\r\n font-family: inherit;\r\n font-size: var(--_mono-input-font-size);\r\n line-height: var(--_mono-input-line-height);\r\n padding-inline: var(--_mono-input-padding-x);\r\n padding-block: 0;\r\n\r\n &::placeholder {\r\n color: var(--_mono-input-placeholder);\r\n }\r\n\r\n /* .input:disabled — pointer-events-none cursor-not-allowed (the opacity is\r\n on the field so the affixes fade with it) */\r\n &:disabled {\r\n pointer-events: none;\r\n cursor: not-allowed;\r\n }\r\n\r\n &:read-only {\r\n cursor: inherit;\r\n }\r\n\r\n /* Kill the native focus outline in host projects; the field draws the ring. */\r\n &:focus,\r\n &:focus-visible {\r\n outline: none !important;\r\n }\r\n\r\n &[type='number']::-webkit-outer-spin-button,\r\n &[type='number']::-webkit-inner-spin-button {\r\n margin: 0;\r\n }\r\n}\r\n\r\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\r\n (and pe-1.5 for an end affix). The clear button counts as an end affix. */\r\n:where([mono-input]) > [mono-field]:has(> [mono-prefix]:not([mono-empty])) > [mono-native] {\r\n padding-inline-start: var(--mono-input-affix-gap, calc(var(--mono-spacing) * 1.5));\r\n}\r\n:where([mono-input]) > [mono-field]:has(> :is([mono-suffix]:not([mono-empty]), [mono-clear])) > [mono-native] {\r\n padding-inline-end: var(--mono-input-affix-gap, calc(var(--mono-spacing) * 1.5));\r\n}\r\n\r\n/* =========================================\r\n Prefix / suffix\r\n ========================================= */\r\n\r\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\r\n text-sm font-medium text-muted-foreground select-none, svg size-4;\r\n [data-align='start'] ps-2 / [data-align='end'] pe-2 */\r\n:where([mono-input]) [mono-prefix],\r\n:where([mono-input]) [mono-suffix] {\r\n flex: 0 0 auto;\r\n display: inline-flex;\r\n align-items: center;\r\n gap: calc(var(--mono-spacing) * 2);\r\n font-size: var(--mono-input-affix-font-size, var(--_mono-input-font-size));\r\n line-height: var(--_mono-input-line-height);\r\n font-weight: var(--mono-font-weight-medium);\r\n color: var(--_mono-input-muted);\r\n user-select: none;\r\n}\r\n\r\n:where([mono-input]) [mono-prefix] {\r\n padding-inline-start: var(--_mono-input-affix-padding);\r\n}\r\n\r\n:where([mono-input]) [mono-suffix] {\r\n padding-inline-end: var(--_mono-input-affix-padding);\r\n}\r\n\r\n/* The light build re-appends slotted prefix/suffix content into this\r\n `[data-mono-slot]` placeholder, one level below the inline-flex wrapper.\r\n Make it a flex container too, so an `display: inline` icon span (e.g. a\r\n UnoCSS `i-mdi-*`, which ignores width/height while inline) is blockified\r\n into a flex item and actually renders its box. */\r\n:where([mono-input]) :is([mono-prefix], [mono-suffix]) > [data-mono-slot] {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: inherit;\r\n}\r\n\r\n/* `[&>svg:not([class*='size-'])]:size-4` — our icons are UnoCSS `i-*` mask\r\n spans as often as SVGs, so every glyph in an affix takes the affix size. */\r\n:where([mono-input]) :is([mono-prefix], [mono-suffix]) :is(svg, .mono-icon, [mono-icon]),\r\n:where([mono-input]) :is([mono-prefix], [mono-suffix]) ::slotted(svg),\r\n:where([mono-input]) :is([mono-prefix], [mono-suffix]) ::slotted(.mono-icon),\r\n:where([mono-input]) :is([mono-prefix], [mono-suffix]) ::slotted([mono-icon]) {\r\n display: block;\r\n width: var(--_mono-input-affix-icon);\r\n height: var(--_mono-input-affix-icon);\r\n flex-shrink: 0;\r\n pointer-events: none;\r\n}\r\n\r\n/* =========================================\r\n Clear button — a ghost icon button in the end affix slot\r\n ========================================= */\r\n\r\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)))\r\n — size-6 rounded-[calc(var(--radius)-5px)] p-0 shadow-none, svg size-3.5;\r\n .input-group > button[data-align='end'] me-1; painted as .btn[data-variant='ghost'] */\r\n:where([mono-input]) [mono-clear] {\r\n flex: 0 0 auto;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: var(--_mono-input-clear);\r\n height: var(--_mono-input-clear);\r\n padding: 0;\r\n margin: 0;\r\n margin-inline-end: var(--mono-spacing);\r\n border: 0;\r\n border-radius: var(--mono-input-clear-radius, calc(var(--radius) - 5px));\r\n background: transparent;\r\n box-shadow: none;\r\n color: var(--_mono-input-muted);\r\n font: inherit;\r\n line-height: 1;\r\n cursor: pointer;\r\n outline-style: none;\r\n transition-property: color, background-color, box-shadow;\r\n transition-timing-function: var(--mono-ease);\r\n transition-duration: var(--mono-duration);\r\n\r\n &:focus-visible {\r\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);\r\n }\r\n\r\n &:active {\r\n translate: 0 1px;\r\n }\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .btn[data-variant='ghost'] — hover:bg-muted\r\n hover:text-foreground (dark:hover:bg-muted/50 via --mono-mode-ghost-hover) */\r\n@media (hover: hover) {\r\n :where([mono-input]) [mono-clear]:hover {\r\n background: var(--mono-mode-ghost-hover);\r\n color: var(--_mono-input-text);\r\n }\r\n}\r\n\r\n:where([mono-input]) [mono-clear] > :is(svg, .mono-icon, [mono-icon]) {\r\n display: block;\r\n width: var(--_mono-input-clear-glyph);\r\n height: var(--_mono-input-clear-glyph);\r\n pointer-events: none;\r\n}\r\n\r\n/* =========================================\r\n Message — helper / validation text under the field\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 styles/vega.css .fieldset legend + p, .field > p, .field section > p — text-sm text-muted-foreground\r\n leading-normal font-normal text-start. The wrapper is always rendered\r\n (aria-describedby points at it); it takes no space until it holds text. */\r\n:where([mono-input]) > [mono-message-wrap] {\r\n display: block;\r\n}\r\n\r\n:where([mono-input]) > [mono-message-wrap]:not(:has([mono-message]:not([mono-empty]))) {\r\n display: none;\r\n}\r\n\r\n:where([mono-input]) [mono-message] {\r\n font-size: var(--mono-input-message-font-size, var(--mono-text-sm));\r\n line-height: var(--mono-input-message-line-height, var(--mono-leading-normal));\r\n font-weight: var(--mono-font-weight-normal);\r\n text-align: start;\r\n color: var(--_mono-input-muted);\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .field [role=\"alert\"] — text-destructive text-sm */\r\n:where([mono-input]) [mono-message=\"invalid\"] {\r\n color: var(--_mono-input-invalid);\r\n}\r\n\r\n/* EXTENSION — the other two states in their role colour */\r\n:where([mono-input]) [mono-message=\"valid\"] {\r\n color: var(--_mono-input-valid);\r\n}\r\n\r\n:where([mono-input]) [mono-message=\"warning\"] {\r\n color: var(--_mono-input-warning);\r\n}\r\n\r\n@media (prefers-reduced-motion: reduce) {\r\n :where([mono-input]) > [mono-field],\r\n :where([mono-input]) [mono-clear] {\r\n transition: none;\r\n }\r\n}\r\n";
|
|
1059
|
+
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";
|
|
972
1060
|
|
|
973
1061
|
//#endregion
|
|
974
1062
|
//#region src/components/input/mono-input.ts
|
|
@@ -1052,7 +1140,8 @@ let MonoInput = class MonoInput extends MonoInputCore(LitElement) {
|
|
|
1052
1140
|
if (!target) return;
|
|
1053
1141
|
for (const node of nodes) placeSlotNode(target, node);
|
|
1054
1142
|
}
|
|
1055
|
-
renderIcon(
|
|
1143
|
+
renderIcon(name) {
|
|
1144
|
+
if (name === "upload") return html`<span class="mono-icon i-mdi-cloud-upload-outline" mono-icon aria-hidden="true"></span>`;
|
|
1056
1145
|
return html`<span class="mono-icon i-mdi-close" mono-icon aria-hidden="true"></span>`;
|
|
1057
1146
|
}
|
|
1058
1147
|
_renderLabel() {
|
|
@@ -1061,17 +1150,23 @@ let MonoInput = class MonoInput extends MonoInputCore(LitElement) {
|
|
|
1061
1150
|
<label class=${this._cls("mono-input-label", "label")} mono-label for=${this._inputId}>
|
|
1062
1151
|
${this._hasLabelSlot ? html`<span data-mono-slot="label"></span>` : this.label}
|
|
1063
1152
|
${this.required ? html`<span class=${this._cls("mono-input-required", "required")} mono-required-mark>*</span>` : nothing}
|
|
1153
|
+
${this._tooltip.render()}
|
|
1154
|
+
${this._renderRangeValue("label")}
|
|
1064
1155
|
</label>
|
|
1065
1156
|
`;
|
|
1066
1157
|
}
|
|
1067
1158
|
_renderHelper() {
|
|
1068
1159
|
const base = this._cls("mono-input-message", "message");
|
|
1160
|
+
if (this._validation.moved) return html`${this._renderHelperText(base)}${this._renderMovedMessage()}`;
|
|
1069
1161
|
if (this.validationMessage) {
|
|
1070
1162
|
const state = this._resolvedValidationState;
|
|
1071
1163
|
return html`<div class=${`${base} ${state}`} mono-message=${state} role=${state === "invalid" ? "alert" : nothing}>${this.validationMessage}</div>`;
|
|
1072
1164
|
}
|
|
1073
1165
|
if (this.errorMessage) return html`<div class=${`${base} invalid`} mono-message="invalid" role="alert">${this.errorMessage}</div>`;
|
|
1074
1166
|
if (this.successMessage) return html`<div class=${`${base} valid`} mono-message="valid">${this.successMessage}</div>`;
|
|
1167
|
+
return this._renderHelperText(base);
|
|
1168
|
+
}
|
|
1169
|
+
_renderHelperText(base) {
|
|
1075
1170
|
if (this.helperText || this._hasHelperSlot) return html`<div class=${`${base} helper`} mono-message="helper">${this._hasHelperSlot ? html`<span data-mono-slot="helper"></span>` : this.helperText}</div>`;
|
|
1076
1171
|
return nothing;
|
|
1077
1172
|
}
|
|
@@ -1081,12 +1176,16 @@ let MonoInput = class MonoInput extends MonoInputCore(LitElement) {
|
|
|
1081
1176
|
<div class=${this._fieldClasses} mono-field>
|
|
1082
1177
|
${this._hasPrefixSlot ? html`<span class=${this._cls("mono-input-prefix", "prefix")} mono-prefix><span data-mono-slot="prefix"></span></span>` : nothing}
|
|
1083
1178
|
${this._renderNative()}
|
|
1179
|
+
${this._renderRangeValue("field")}
|
|
1180
|
+
${this._validation.renderIcon()}
|
|
1084
1181
|
${this._renderClear()}
|
|
1182
|
+
${this._renderFileIcon()}
|
|
1085
1183
|
${this._hasSuffixSlot ? html`<span class=${this._cls("mono-input-suffix", "suffix")} mono-suffix><span data-mono-slot="suffix"></span></span>` : nothing}
|
|
1086
1184
|
</div>
|
|
1087
1185
|
<div id=${this._messageId} class=${this.cssClass?.messageWrap ?? ""} mono-message-wrap>
|
|
1088
1186
|
${this._renderHelper()}
|
|
1089
1187
|
</div>
|
|
1188
|
+
${this._validation.renderFloat()}
|
|
1090
1189
|
`);
|
|
1091
1190
|
}
|
|
1092
1191
|
};
|
|
@@ -1174,7 +1273,9 @@ function getInputIcon(type) {
|
|
|
1174
1273
|
time: "M12 7v5l3 3M12 22a10 10 0 1 0 0-20a10 10 0 0 0 0 20z",
|
|
1175
1274
|
month: "M7 3v3M17 3v3M5 5h14v14H5zM8 11h8",
|
|
1176
1275
|
week: "M7 3v3M17 3v3M5 5h14v16H5zM9 11h6M9 15h4",
|
|
1177
|
-
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"
|
|
1276
|
+
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",
|
|
1277
|
+
file: "M12 16V8M8.5 11.5L12 8l3.5 3.5M7 18h10",
|
|
1278
|
+
range: "M4 12h16M9 9a3 3 0 1 0 0 6a3 3 0 0 0 0-6z"
|
|
1178
1279
|
};
|
|
1179
1280
|
return iconMap[type] ?? iconMap.text;
|
|
1180
1281
|
}
|