@mono-lit/helper 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/index.js +4 -3
- package/dist/{index.node-dvrNviMx.js → index.node-DzCuvHLg.js} +1 -1
- package/dist/index.node.js +4 -3
- package/dist/input-format-GrRCJBqV.js +251 -0
- package/dist/input.css_raw-CQu2fAsU.js +5 -0
- package/dist/{mono-data-grid-BHlo1IgR.js → mono-data-grid-KDpu4d4_.js} +5 -4
- package/dist/{mono-form-controller-IYn0MuUQ.js → mono-form-controller-BkMR8g14.js} +18 -3
- package/dist/{reactive-DFCdZbH9.js → normalize-error-BmLbgANw.js} +1 -48
- package/dist/nuxt.js +36 -8
- 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/tag-input/tag-input-core.d.ts +3 -0
- package/dist/src/components/tag-input/tag-input-types.d.ts +31 -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/popup-portal.d.ts +12 -0
- package/dist/src/composables/popup-stack.d.ts +21 -0
- package/dist/src/entries/index.d.ts +1 -1
- package/dist/src/entries/index.node.d.ts +1 -1
- package/dist/src/nuxt/index.d.ts +2 -2
- package/dist/src/nuxt/ssr-lit/index.d.ts +4 -0
- package/dist/ssr-lit/runtime/components/LitWrapper.vue +11 -0
- package/dist/ssr-lit/runtime/components/LitWrapperClient.vue +11 -0
- package/dist/ssr-lit/runtime/components/LitWrapperServer.vue +38 -0
- package/dist/ssr-lit/runtime/plugins/antiFouc.server.js +25 -0
- package/dist/ssr-lit/runtime/plugins/hydrateSupport.client.js +4 -0
- package/dist/ssr-lit/runtime/plugins/polyfill.client.js +9 -0
- package/dist/ssr-lit/runtime/utils/customElements.js +11 -0
- package/dist/ssr-lit/runtime/utils/litElementRenderer.js +28 -0
- 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 +16 -3
- package/dist/ui/alert.js +2 -2
- package/dist/ui/breadcrumb.js +1 -1
- package/dist/ui/button-dropdown.js +1 -1
- package/dist/ui/chart.js +1 -1
- package/dist/ui/date.js +66 -5
- package/dist/ui/drawer.js +11 -2
- package/dist/ui/dropdown-table.js +60 -5
- package/dist/ui/dropdown.js +3 -2
- package/dist/ui/file-upload.js +1 -1
- package/dist/ui/form.js +1 -1
- package/dist/ui/index.css +8857 -3974
- package/dist/ui/input.js +362 -260
- package/dist/ui/menu.js +1 -1
- package/dist/ui/modal.js +11 -2
- package/dist/ui/otp.js +835 -0
- package/dist/ui/select.js +67 -3
- package/dist/ui/shadow/accordion.js +31 -4
- package/dist/ui/shadow/alert.js +1 -1
- package/dist/ui/shadow/button-dropdown.js +1 -1
- package/dist/ui/shadow/chart.js +4 -4
- package/dist/ui/shadow/date.js +67 -6
- package/dist/ui/shadow/drawer.js +11 -2
- package/dist/ui/shadow/dropdown-table.js +62 -7
- package/dist/ui/shadow/dropdown.js +3 -2
- package/dist/ui/shadow/input.js +367 -261
- package/dist/ui/shadow/modal.js +11 -2
- package/dist/ui/shadow/otp.js +842 -0
- package/dist/ui/shadow/select.js +71 -6
- package/dist/ui/shadow/sidebar.js +2 -2
- package/dist/ui/shadow/slider.js +1082 -0
- package/dist/ui/shadow/table.js +6 -6
- package/dist/ui/shadow/tag-input.js +72 -7
- package/dist/ui/shadow/textarea.js +63 -2
- package/dist/ui/sidebar.js +2 -2
- package/dist/ui/slider.js +1079 -0
- package/dist/ui/table.js +2 -2
- package/dist/ui/tag-input.js +67 -3
- package/dist/ui/textarea.js +62 -1
- 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 +30 -15
- package/dist/input.css_raw-CGESifay.js +0 -5
|
@@ -0,0 +1,1079 @@
|
|
|
1
|
+
import { l as monoHostChildNodes } from "../mono-ui-BwUc0L6B.js";
|
|
2
|
+
import { t as customElement } from "../mono-element-C7vCschg.js";
|
|
3
|
+
import { a as defineHybridPropAliases, i as defineHybridPropAlias, r as booleanStringConverter, t as __decorate } from "../decorate-DbYFpi8R.js";
|
|
4
|
+
import { t as dispatchMonoEvent } from "../mono-event-BPku9HpS.js";
|
|
5
|
+
import { s as placeSlotNode } from "../light-slots-DdDdZ6zs.js";
|
|
6
|
+
import { n as toCssSize } from "../css-size-DWAPgQdT.js";
|
|
7
|
+
import { t as MonoFormControlCore } from "../form-control-core-CRZPZ1ru.js";
|
|
8
|
+
import { a as parseFormat, t as applyFormat } from "../input-format-GrRCJBqV.js";
|
|
9
|
+
import { n as cssPart } from "../css-class-B6Tc_MAx.js";
|
|
10
|
+
import { t as FieldTooltipController } from "../field-tooltip-FyMi9vNM.js";
|
|
11
|
+
import { LitElement, html, isServer, nothing, unsafeCSS } from "lit";
|
|
12
|
+
import { property, state } from "lit/decorators.js";
|
|
13
|
+
import { ifDefined } from "lit/directives/if-defined.js";
|
|
14
|
+
import { styleMap } from "lit/directives/style-map.js";
|
|
15
|
+
|
|
16
|
+
//#region src/components/slider/slider-math.ts
|
|
17
|
+
/** Past this many grid ticks, `marks` = true draws only the ends: denser than this reads as a texture. */
|
|
18
|
+
const MAX_AUTO_MARKS = 26;
|
|
19
|
+
/** Strip float noise (0.1 + 0.2) without losing a fractional step. */
|
|
20
|
+
function stripNoise(n) {
|
|
21
|
+
return Number(n.toFixed(10));
|
|
22
|
+
}
|
|
23
|
+
function toNumber(value) {
|
|
24
|
+
if (value === null || value === void 0 || value === "") return void 0;
|
|
25
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
26
|
+
return Number.isFinite(n) ? n : void 0;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Anything a consumer (or a framework) might hand over as a value — a number, an array, a JSON
|
|
30
|
+
* string (`"[20,80]"`, what an SSR attribute carries), a comma list (`"20,80"`), a numeric string —
|
|
31
|
+
* as a list of finite numbers. Non-numbers are dropped. `null` when nothing usable is left.
|
|
32
|
+
*/
|
|
33
|
+
function coerceNumbers(value) {
|
|
34
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
35
|
+
if (typeof value === "number") return Number.isFinite(value) ? [value] : null;
|
|
36
|
+
if (Array.isArray(value)) {
|
|
37
|
+
const out = value.map(toNumber).filter((n) => n !== void 0);
|
|
38
|
+
return out.length ? out : null;
|
|
39
|
+
}
|
|
40
|
+
if (typeof value === "string") {
|
|
41
|
+
const text = value.trim();
|
|
42
|
+
if (text.startsWith("[")) try {
|
|
43
|
+
return coerceNumbers(JSON.parse(text));
|
|
44
|
+
} catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
if (text.includes(",")) return coerceNumbers(text.split(","));
|
|
48
|
+
const n = toNumber(text);
|
|
49
|
+
return n === void 0 ? null : [n];
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
/** The scale from raw props: defaults 0 / 100 / 1, `max` never below `min`, stops cleaned. */
|
|
54
|
+
function resolveScale(input) {
|
|
55
|
+
const min = toNumber(input.min) ?? 0;
|
|
56
|
+
const rawMax = toNumber(input.max) ?? 100;
|
|
57
|
+
const max = rawMax < min ? min : rawMax;
|
|
58
|
+
const rawStep = toNumber(input.step);
|
|
59
|
+
const step = rawStep === void 0 ? 1 : rawStep > 0 ? rawStep : 0;
|
|
60
|
+
const minGap = Math.max(0, toNumber(input.minGap) ?? 0);
|
|
61
|
+
const list = coerceNumbers(input.stops);
|
|
62
|
+
const stops = list ? [...new Set(list.filter((n) => n >= min && n <= max).map(stripNoise))].sort((a, b) => a - b) : null;
|
|
63
|
+
return {
|
|
64
|
+
min,
|
|
65
|
+
max,
|
|
66
|
+
step,
|
|
67
|
+
stops: stops && stops.length ? stops : null,
|
|
68
|
+
minGap
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function clamp(v, lo, hi) {
|
|
72
|
+
return Math.min(hi, Math.max(lo, v));
|
|
73
|
+
}
|
|
74
|
+
/** The allowed value nearest to `v` (a stop, a grid point, or `v` itself when continuous). */
|
|
75
|
+
function snap(v, scale) {
|
|
76
|
+
const x = clamp(v, scale.min, scale.max);
|
|
77
|
+
if (scale.stops) {
|
|
78
|
+
let best = scale.stops[0];
|
|
79
|
+
for (const s of scale.stops) if (Math.abs(s - x) < Math.abs(best - x)) best = s;
|
|
80
|
+
return best;
|
|
81
|
+
}
|
|
82
|
+
if (!scale.step) return stripNoise(x);
|
|
83
|
+
const snapped = scale.min + Math.round((x - scale.min) / scale.step) * scale.step;
|
|
84
|
+
return stripNoise(snapped > scale.max ? snapped - scale.step : snapped);
|
|
85
|
+
}
|
|
86
|
+
/** The smallest allowed value ≥ x (or `max` when none is). */
|
|
87
|
+
function ceilTo(x, scale) {
|
|
88
|
+
if (x <= scale.min) return scale.min;
|
|
89
|
+
if (scale.stops) return scale.stops.find((s) => s >= x - 1e-9) ?? scale.max;
|
|
90
|
+
if (!scale.step) return Math.min(x, scale.max);
|
|
91
|
+
const v = scale.min + Math.ceil(stripNoise((x - scale.min) / scale.step)) * scale.step;
|
|
92
|
+
return stripNoise(v > scale.max ? scale.max : v);
|
|
93
|
+
}
|
|
94
|
+
/** The largest allowed value ≤ x (or `min` when none is). */
|
|
95
|
+
function floorTo(x, scale) {
|
|
96
|
+
if (x >= scale.max) return scale.stops ? scale.stops[scale.stops.length - 1] : snapFloorMax(scale);
|
|
97
|
+
if (scale.stops) {
|
|
98
|
+
for (let i = scale.stops.length - 1; i >= 0; i--) if (scale.stops[i] <= x + 1e-9) return scale.stops[i];
|
|
99
|
+
return scale.min;
|
|
100
|
+
}
|
|
101
|
+
if (!scale.step) return Math.max(x, scale.min);
|
|
102
|
+
const v = scale.min + Math.floor(stripNoise((x - scale.min) / scale.step)) * scale.step;
|
|
103
|
+
return stripNoise(v < scale.min ? scale.min : v);
|
|
104
|
+
}
|
|
105
|
+
/** The highest grid point (equals `max` only when the step divides the span). */
|
|
106
|
+
function snapFloorMax(scale) {
|
|
107
|
+
if (!scale.step) return scale.max;
|
|
108
|
+
return stripNoise(scale.min + Math.floor(stripNoise((scale.max - scale.min) / scale.step)) * scale.step);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The values, made valid: each clamped and snapped, sorted, then spread so neighbours are at least
|
|
112
|
+
* `minGap` apart. Thumbs are never dropped — when the gap cannot fit every thumb, they pack
|
|
113
|
+
* against the ends (the forward pass pushes right, the backward pass pulls back under `max`).
|
|
114
|
+
*/
|
|
115
|
+
function normalise(values, scale) {
|
|
116
|
+
const out = values.map((v) => snap(v, scale)).sort((a, b) => a - b);
|
|
117
|
+
if (!scale.minGap || out.length < 2) return out;
|
|
118
|
+
for (let i = 1; i < out.length; i++) if (out[i] - out[i - 1] < scale.minGap - 1e-9) out[i] = ceilTo(out[i - 1] + scale.minGap, scale);
|
|
119
|
+
for (let i = out.length - 2; i >= 0; i--) if (out[i + 1] - out[i] < scale.minGap - 1e-9) out[i] = floorTo(out[i + 1] - scale.minGap, scale);
|
|
120
|
+
return out.map((v) => clamp(v, scale.min, scale.max));
|
|
121
|
+
}
|
|
122
|
+
/** The range thumb `i` may move in: its neighbours ± `minGap` (the BLOCK rule). */
|
|
123
|
+
function thumbBounds(values, i, scale) {
|
|
124
|
+
const lo = i > 0 ? ceilTo(values[i - 1] + scale.minGap, scale) : scale.min;
|
|
125
|
+
const hi = i < values.length - 1 ? floorTo(values[i + 1] - scale.minGap, scale) : snapFloorMaxOrStop(scale);
|
|
126
|
+
return {
|
|
127
|
+
lo,
|
|
128
|
+
hi: Math.max(lo, hi)
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function snapFloorMaxOrStop(scale) {
|
|
132
|
+
return scale.stops ? scale.stops[scale.stops.length - 1] : snapFloorMax(scale);
|
|
133
|
+
}
|
|
134
|
+
function snapFloorMinOrStop(scale) {
|
|
135
|
+
return scale.stops ? scale.stops[0] : scale.min;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Move thumb `i` toward `v`: snap, then stop at the neighbours (± gap). Returns a NEW array when
|
|
139
|
+
* the thumb actually moved, the SAME array otherwise — callers use identity to skip no-op events.
|
|
140
|
+
*/
|
|
141
|
+
function moveThumb(values, i, v, scale) {
|
|
142
|
+
const { lo, hi } = thumbBounds(values, i, scale);
|
|
143
|
+
const next = clamp(snap(v, scale), lo, hi);
|
|
144
|
+
if (next === values[i]) return values;
|
|
145
|
+
const out = values.slice();
|
|
146
|
+
out[i] = next;
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Shift a whole run of thumbs `[from..to]` by `delta`, keeping their spacing — the drag of a filled
|
|
151
|
+
* segment between two thumbs. The run stops at the track ends and at the thumbs outside it.
|
|
152
|
+
*/
|
|
153
|
+
function moveRun(values, from, to, delta, scale) {
|
|
154
|
+
const lo = from > 0 ? values[from - 1] + scale.minGap : snapFloorMinOrStop(scale);
|
|
155
|
+
const hi = to < values.length - 1 ? values[to + 1] - scale.minGap : snapFloorMaxOrStop(scale);
|
|
156
|
+
const d = clamp(delta, lo - values[from], hi - values[to]);
|
|
157
|
+
if (!d) return values;
|
|
158
|
+
const applied = clamp(snap(values[from] + d, scale) - values[from], lo - values[from], hi - values[to]);
|
|
159
|
+
if (!applied) return values;
|
|
160
|
+
const out = values.slice();
|
|
161
|
+
for (let k = from; k <= to; k++) out[k] = stripNoise(values[k] + applied);
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* The thumb a press at `v` should grab: the nearest one. Thumbs sitting on the same spot (`[2, 2,
|
|
166
|
+
* 3]`) tie — then the press picks by SIDE: a press above the stack takes its LAST thumb, below it
|
|
167
|
+
* the FIRST, so stacked thumbs can always be pulled apart. `dir` (+1 / -1) breaks an exact hit,
|
|
168
|
+
* once the drag has shown which way it is heading.
|
|
169
|
+
*/
|
|
170
|
+
function nearestThumb(values, v, dir = 0) {
|
|
171
|
+
let best = 0;
|
|
172
|
+
let bestDist = Infinity;
|
|
173
|
+
for (let i = 0; i < values.length; i++) {
|
|
174
|
+
const d = Math.abs(values[i] - v);
|
|
175
|
+
if (d < bestDist - 1e-9) {
|
|
176
|
+
best = i;
|
|
177
|
+
bestDist = d;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
let first = best;
|
|
181
|
+
let last = best;
|
|
182
|
+
while (first > 0 && Math.abs(values[first - 1] - values[best]) < 1e-9) first--;
|
|
183
|
+
while (last < values.length - 1 && Math.abs(values[last + 1] - values[best]) < 1e-9) last++;
|
|
184
|
+
if (first === last) return best;
|
|
185
|
+
return (v > values[best] + 1e-9 ? 1 : v < values[best] - 1e-9 ? -1 : dir) > 0 ? last : first;
|
|
186
|
+
}
|
|
187
|
+
/** True when several thumbs share position `values[i]` (a stack the next drag must split). */
|
|
188
|
+
function isStacked(values, i) {
|
|
189
|
+
return i > 0 && Math.abs(values[i - 1] - values[i]) < 1e-9 || i < values.length - 1 && Math.abs(values[i + 1] - values[i]) < 1e-9;
|
|
190
|
+
}
|
|
191
|
+
/** `v` as a 0–100 position along the track. */
|
|
192
|
+
function toPercent(v, scale) {
|
|
193
|
+
const span = scale.max - scale.min;
|
|
194
|
+
if (span <= 0) return 0;
|
|
195
|
+
return clamp((v - scale.min) / span * 100, 0, 100);
|
|
196
|
+
}
|
|
197
|
+
/** A 0–1 position along the track as a raw (unsnapped) value. */
|
|
198
|
+
function fromRatio(ratio, scale) {
|
|
199
|
+
return scale.min + clamp(ratio, 0, 1) * (scale.max - scale.min);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* The track as pieces between its boundaries (the two ends and every thumb), each flagged filled
|
|
203
|
+
* or not by the `fill` mode. Rendering every stretch as its own piece is what lets `track-gap` cut
|
|
204
|
+
* the track back around each thumb, and lets a consumer colour segments one by one.
|
|
205
|
+
*/
|
|
206
|
+
function trackPieces(values, scale, fill) {
|
|
207
|
+
const bounds = [
|
|
208
|
+
0,
|
|
209
|
+
...values.map((v) => toPercent(v, scale)),
|
|
210
|
+
100
|
|
211
|
+
];
|
|
212
|
+
const n = values.length;
|
|
213
|
+
const pieces = [];
|
|
214
|
+
for (let k = 0; k < bounds.length - 1; k++) {
|
|
215
|
+
let filled = false;
|
|
216
|
+
if (fill === "start") filled = k === 0;
|
|
217
|
+
else if (fill === "end") filled = k === n;
|
|
218
|
+
else if (fill === "auto") filled = n === 1 ? k === 0 : k >= 1 && k <= n - 1;
|
|
219
|
+
pieces.push({
|
|
220
|
+
from: bounds[k],
|
|
221
|
+
to: bounds[k + 1],
|
|
222
|
+
cutStart: k > 0,
|
|
223
|
+
cutEnd: k < n,
|
|
224
|
+
filled
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return pieces;
|
|
228
|
+
}
|
|
229
|
+
/** The marks to draw. `true` = one per stop, or per step (only the two ends past ~26 — denser is a texture, not ticks). */
|
|
230
|
+
function markPoints(marks, scale) {
|
|
231
|
+
if (marks === false || marks === null || marks === void 0 || marks === "" || marks === "false") return [];
|
|
232
|
+
let list = marks;
|
|
233
|
+
if (typeof marks === "string") {
|
|
234
|
+
const text = marks.trim();
|
|
235
|
+
if (text === "true") list = true;
|
|
236
|
+
else try {
|
|
237
|
+
list = JSON.parse(text);
|
|
238
|
+
} catch {
|
|
239
|
+
list = coerceNumbers(text) ?? [];
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (list === true) return (scale.stops ?? autoGrid(scale)).map((value) => ({
|
|
243
|
+
value,
|
|
244
|
+
pct: toPercent(value, scale),
|
|
245
|
+
labelled: false
|
|
246
|
+
}));
|
|
247
|
+
if (!Array.isArray(list)) return [];
|
|
248
|
+
const out = [];
|
|
249
|
+
for (const item of list) if (typeof item === "number" || typeof item === "string") {
|
|
250
|
+
const value = toNumber(item);
|
|
251
|
+
if (value !== void 0 && value >= scale.min && value <= scale.max) out.push({
|
|
252
|
+
value,
|
|
253
|
+
pct: toPercent(value, scale),
|
|
254
|
+
labelled: false
|
|
255
|
+
});
|
|
256
|
+
} else if (item && typeof item === "object") {
|
|
257
|
+
const value = toNumber(item.value);
|
|
258
|
+
if (value !== void 0 && value >= scale.min && value <= scale.max) {
|
|
259
|
+
const label = item.label;
|
|
260
|
+
out.push({
|
|
261
|
+
value,
|
|
262
|
+
pct: toPercent(value, scale),
|
|
263
|
+
label: label == null ? void 0 : String(label),
|
|
264
|
+
labelled: true
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return out.sort((a, b) => a.value - b.value);
|
|
269
|
+
}
|
|
270
|
+
function autoGrid(scale) {
|
|
271
|
+
if (!scale.step) return [scale.min, scale.max];
|
|
272
|
+
const count = Math.floor(stripNoise((scale.max - scale.min) / scale.step)) + 1;
|
|
273
|
+
if (count > MAX_AUTO_MARKS) return [scale.min, scale.max];
|
|
274
|
+
return Array.from({ length: count }, (_, i) => stripNoise(scale.min + i * scale.step));
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* One keyboard step from `v`: `dir` ±1, `big` for PageUp/PageDown. With stops it walks the list
|
|
278
|
+
* (big = a tenth of it, at least one); with a grid it moves a step (big = ten); continuous moves
|
|
279
|
+
* 1% (big = 10%).
|
|
280
|
+
*/
|
|
281
|
+
function stepFrom(v, dir, big, scale) {
|
|
282
|
+
if (scale.stops) {
|
|
283
|
+
const stops = scale.stops;
|
|
284
|
+
let idx = stops.findIndex((s) => Math.abs(s - v) < 1e-9);
|
|
285
|
+
if (idx < 0) idx = stops.findIndex((s) => s > v) - (dir > 0 ? 1 : 0);
|
|
286
|
+
const jump = big ? Math.max(1, Math.round(stops.length / 10)) : 1;
|
|
287
|
+
return stops[clamp(idx + dir * jump, 0, stops.length - 1)];
|
|
288
|
+
}
|
|
289
|
+
return stripNoise(v + dir * (scale.step || (scale.max - scale.min) / 100) * (big ? 10 : 1));
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
//#endregion
|
|
293
|
+
//#region src/components/slider/slider-core.ts
|
|
294
|
+
/** Pixels a press must travel before a press between two thumbs becomes a segment drag. */
|
|
295
|
+
const SEGMENT_DRAG_THRESHOLD = 3;
|
|
296
|
+
/**
|
|
297
|
+
* `true` unless the attribute says `"false"` — for props that are ON by default (`show-value`),
|
|
298
|
+
* where an ABSENT attribute must not read as off.
|
|
299
|
+
*/
|
|
300
|
+
const defaultOnConverter = { fromAttribute: (v) => v === null ? true : booleanStringConverter.fromAttribute(v) };
|
|
301
|
+
/** A model that holds the same numbers in the same shape is not a change (Vue re-sends arrays). */
|
|
302
|
+
function sliderValueHasChanged(value, old) {
|
|
303
|
+
if (value === old) return false;
|
|
304
|
+
const a = coerceNumbers(value);
|
|
305
|
+
const b = coerceNumbers(old);
|
|
306
|
+
if (!a || !b) return a !== b;
|
|
307
|
+
if (Array.isArray(value) !== Array.isArray(old)) return true;
|
|
308
|
+
return a.length !== b.length || a.some((n, i) => n !== b[i]);
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* `MonoSliderCore` — everything `mono-slider` does that does not depend on light vs shadow DOM:
|
|
312
|
+
* props + hybrid aliases, the value maths (slider-math.ts), pointer + keyboard interaction,
|
|
313
|
+
* events, form binding, and the shared `render()`. The label / message regions are hooks the
|
|
314
|
+
* shadow build overrides with native `<slot>`s (the light build captures `slot="label|helper"`
|
|
315
|
+
* children and drops them into `[data-mono-slot]` placeholders, like mono-input).
|
|
316
|
+
*
|
|
317
|
+
* Thumbs are `role="slider"` elements, not native range inputs: N thumbs on one track, blocking,
|
|
318
|
+
* stops, gaps and segment drags are all beyond `<input type="range">`.
|
|
319
|
+
*/
|
|
320
|
+
const MonoSliderCore = (superClass) => {
|
|
321
|
+
class MonoSliderCoreClass extends MonoFormControlCore(superClass) {
|
|
322
|
+
constructor(...args) {
|
|
323
|
+
super(...args);
|
|
324
|
+
this.modelValue = 0;
|
|
325
|
+
this.min = 0;
|
|
326
|
+
this.max = 100;
|
|
327
|
+
this.step = 1;
|
|
328
|
+
this.minGap = 0;
|
|
329
|
+
this.type = "horizontal";
|
|
330
|
+
this.marks = false;
|
|
331
|
+
this.fill = "auto";
|
|
332
|
+
this.trackGap = 0;
|
|
333
|
+
this.valueTooltip = "auto";
|
|
334
|
+
this.showValue = true;
|
|
335
|
+
this.valueSeparator = " – ";
|
|
336
|
+
this.size = "md";
|
|
337
|
+
this.color = "primary";
|
|
338
|
+
this.label = "";
|
|
339
|
+
this.helperText = "";
|
|
340
|
+
this.tooltip = null;
|
|
341
|
+
this._tooltip = new FieldTooltipController(this, () => this.tooltip);
|
|
342
|
+
this.validationState = "default";
|
|
343
|
+
this.validationMessage = "";
|
|
344
|
+
this.error = false;
|
|
345
|
+
this.errorMessage = "";
|
|
346
|
+
this.success = false;
|
|
347
|
+
this.successMessage = "";
|
|
348
|
+
this.disabled = false;
|
|
349
|
+
this.readonly = false;
|
|
350
|
+
this.required = false;
|
|
351
|
+
this.name = "";
|
|
352
|
+
this.cssClass = {};
|
|
353
|
+
this.cssClassName = "";
|
|
354
|
+
this._values = [0];
|
|
355
|
+
this._active = 0;
|
|
356
|
+
this._dragging = -1;
|
|
357
|
+
this._hasLabelSlotState = false;
|
|
358
|
+
this._hasHelperSlotState = false;
|
|
359
|
+
this._scale = resolveScale({});
|
|
360
|
+
this._sliderId = `mono-slider-${Math.random().toString(36).slice(2)}`;
|
|
361
|
+
this._messageId = `${this._sliderId}-message`;
|
|
362
|
+
this._gesture = null;
|
|
363
|
+
defineHybridPropAliases(this, [
|
|
364
|
+
"modelValue",
|
|
365
|
+
"minGap",
|
|
366
|
+
"trackGap",
|
|
367
|
+
"valueTooltip",
|
|
368
|
+
"showValue",
|
|
369
|
+
"valueSeparator",
|
|
370
|
+
"formatDisplay",
|
|
371
|
+
"formatLocale",
|
|
372
|
+
"helperText",
|
|
373
|
+
"validationState",
|
|
374
|
+
"validationMessage",
|
|
375
|
+
"errorMessage",
|
|
376
|
+
"successMessage",
|
|
377
|
+
"ariaLabelText",
|
|
378
|
+
"cssClass"
|
|
379
|
+
]);
|
|
380
|
+
defineHybridPropAlias(this, "value", "modelValue");
|
|
381
|
+
for (const alias of [
|
|
382
|
+
"ariaLabel",
|
|
383
|
+
"aria-label",
|
|
384
|
+
"arialabel"
|
|
385
|
+
]) Object.defineProperty(this, alias, {
|
|
386
|
+
get: () => this.ariaLabelText,
|
|
387
|
+
set: (v) => {
|
|
388
|
+
this.ariaLabelText = v == null ? void 0 : String(v);
|
|
389
|
+
},
|
|
390
|
+
configurable: true,
|
|
391
|
+
enumerable: false
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
static get observedAttributes() {
|
|
395
|
+
return [
|
|
396
|
+
...super.observedAttributes ?? [],
|
|
397
|
+
"value",
|
|
398
|
+
"modelvalue",
|
|
399
|
+
"mingap",
|
|
400
|
+
"trackgap",
|
|
401
|
+
"valuetooltip",
|
|
402
|
+
"showvalue",
|
|
403
|
+
"valueseparator",
|
|
404
|
+
"formatdisplay",
|
|
405
|
+
"format-display",
|
|
406
|
+
"formatlocale",
|
|
407
|
+
"helpertext",
|
|
408
|
+
"validationstate",
|
|
409
|
+
"validationmessage",
|
|
410
|
+
"errormessage",
|
|
411
|
+
"successmessage",
|
|
412
|
+
"arialabel",
|
|
413
|
+
"arialabeltext",
|
|
414
|
+
"css-class",
|
|
415
|
+
"cssclass"
|
|
416
|
+
];
|
|
417
|
+
}
|
|
418
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
419
|
+
super.attributeChangedCallback(name, oldValue, newValue);
|
|
420
|
+
if (oldValue === newValue) return;
|
|
421
|
+
switch (name) {
|
|
422
|
+
case "value":
|
|
423
|
+
case "modelvalue":
|
|
424
|
+
this.modelValue = newValue ?? "";
|
|
425
|
+
return;
|
|
426
|
+
case "mingap":
|
|
427
|
+
this.minGap = newValue ?? 0;
|
|
428
|
+
return;
|
|
429
|
+
case "trackgap":
|
|
430
|
+
this.trackGap = newValue ?? 0;
|
|
431
|
+
return;
|
|
432
|
+
case "valuetooltip":
|
|
433
|
+
this.valueTooltip = newValue ?? "auto";
|
|
434
|
+
return;
|
|
435
|
+
case "showvalue":
|
|
436
|
+
this.showValue = defaultOnConverter.fromAttribute(newValue);
|
|
437
|
+
return;
|
|
438
|
+
case "valueseparator":
|
|
439
|
+
this.valueSeparator = newValue ?? " – ";
|
|
440
|
+
return;
|
|
441
|
+
case "formatdisplay":
|
|
442
|
+
case "format-display":
|
|
443
|
+
if (typeof this.formatDisplay === "function") return;
|
|
444
|
+
if (newValue && /^(?:async\s+)?(?:function|\([^)]*\)\s*=>|[A-Za-z_$][\w$]*\s*=>)/.test(newValue.trim())) return;
|
|
445
|
+
this.formatDisplay = newValue ?? void 0;
|
|
446
|
+
return;
|
|
447
|
+
case "formatlocale":
|
|
448
|
+
this.formatLocale = newValue ?? void 0;
|
|
449
|
+
return;
|
|
450
|
+
case "helpertext":
|
|
451
|
+
this.helperText = newValue ?? "";
|
|
452
|
+
return;
|
|
453
|
+
case "validationstate":
|
|
454
|
+
this.validationState = newValue ?? "default";
|
|
455
|
+
return;
|
|
456
|
+
case "validationmessage":
|
|
457
|
+
this.validationMessage = newValue ?? "";
|
|
458
|
+
return;
|
|
459
|
+
case "errormessage":
|
|
460
|
+
this.errorMessage = newValue ?? "";
|
|
461
|
+
return;
|
|
462
|
+
case "successmessage":
|
|
463
|
+
this.successMessage = newValue ?? "";
|
|
464
|
+
return;
|
|
465
|
+
case "arialabel":
|
|
466
|
+
case "arialabeltext":
|
|
467
|
+
this.ariaLabelText = newValue ?? void 0;
|
|
468
|
+
return;
|
|
469
|
+
case "css-class":
|
|
470
|
+
case "cssclass":
|
|
471
|
+
this.cssClassName = newValue ?? "";
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
/** The thumb positions, always as a sorted array. */
|
|
476
|
+
get values() {
|
|
477
|
+
return this._values.slice();
|
|
478
|
+
}
|
|
479
|
+
willUpdate(changed) {
|
|
480
|
+
const scaleKeys = [
|
|
481
|
+
"min",
|
|
482
|
+
"max",
|
|
483
|
+
"step",
|
|
484
|
+
"stops",
|
|
485
|
+
"minGap"
|
|
486
|
+
];
|
|
487
|
+
if (scaleKeys.some((k) => changed.has(k))) this._scale = resolveScale({
|
|
488
|
+
min: this.min,
|
|
489
|
+
max: this.max,
|
|
490
|
+
step: this.step,
|
|
491
|
+
stops: this.stops,
|
|
492
|
+
minGap: this.minGap
|
|
493
|
+
});
|
|
494
|
+
if (changed.has("modelValue") || scaleKeys.some((k) => changed.has(k))) {
|
|
495
|
+
const raw = coerceNumbers(this.modelValue) ?? [this._scale.min];
|
|
496
|
+
const next = normalise(raw, this._scale);
|
|
497
|
+
if (next.length !== this._values.length || next.some((n, i) => n !== this._values[i])) {
|
|
498
|
+
this._values = next;
|
|
499
|
+
if (this._active >= next.length) this._active = next.length - 1;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
super.willUpdate?.(changed);
|
|
503
|
+
}
|
|
504
|
+
/** True when the model is (or was handed over as) a list — the shape we hand back. */
|
|
505
|
+
get _isArrayModel() {
|
|
506
|
+
const v = this.modelValue;
|
|
507
|
+
return Array.isArray(v) || typeof v === "string" && (v.trim().startsWith("[") || v.includes(","));
|
|
508
|
+
}
|
|
509
|
+
_out(values) {
|
|
510
|
+
return this._isArrayModel || values.length > 1 ? values.slice() : values[0];
|
|
511
|
+
}
|
|
512
|
+
/** A value as text, through `format-display` (pattern or function), padded like a commit. */
|
|
513
|
+
_format(v) {
|
|
514
|
+
const raw = String(stripNoise(v));
|
|
515
|
+
const fmt = this.formatDisplay;
|
|
516
|
+
if (!fmt) return raw;
|
|
517
|
+
if (typeof fmt === "function") return String(fmt({
|
|
518
|
+
value: raw,
|
|
519
|
+
type: "slider",
|
|
520
|
+
locale: this.formatLocale
|
|
521
|
+
}) ?? "");
|
|
522
|
+
const descriptor = parseFormat(fmt);
|
|
523
|
+
return descriptor ? applyFormat(raw, descriptor, this.formatLocale, { pad: true }) : raw;
|
|
524
|
+
}
|
|
525
|
+
get _readoutText() {
|
|
526
|
+
return this._values.map((v) => this._format(v)).join(this.valueSeparator);
|
|
527
|
+
}
|
|
528
|
+
get _vertical() {
|
|
529
|
+
return this.type === "vertical";
|
|
530
|
+
}
|
|
531
|
+
get _trackEl() {
|
|
532
|
+
return this.renderRoot.querySelector("[mono-slider-track]");
|
|
533
|
+
}
|
|
534
|
+
_thumbEl(i) {
|
|
535
|
+
return this.renderRoot.querySelector(`[mono-slider-thumb][data-index="${i}"]`);
|
|
536
|
+
}
|
|
537
|
+
/** True when the slider is laid out right-to-left (horizontal only flips). */
|
|
538
|
+
_isRtl() {
|
|
539
|
+
if (this._vertical || typeof getComputedStyle === "undefined") return false;
|
|
540
|
+
return getComputedStyle(this).direction === "rtl";
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* The unsnapped value under a pointer. A thumb's CENTRE travels from half a thumb in to half a
|
|
544
|
+
* thumb short of the end (where a native range thumb sits), so the usable length is the track
|
|
545
|
+
* minus one thumb.
|
|
546
|
+
*/
|
|
547
|
+
_rawAt(event) {
|
|
548
|
+
const rect = this._trackEl?.getBoundingClientRect();
|
|
549
|
+
if (!rect) return this._scale.min;
|
|
550
|
+
const thumb = this._thumbEl(0);
|
|
551
|
+
let ratio;
|
|
552
|
+
if (this._vertical) {
|
|
553
|
+
const along = thumb?.offsetHeight ?? 0;
|
|
554
|
+
const usable = rect.height - along;
|
|
555
|
+
ratio = usable > 0 ? (rect.bottom - along / 2 - event.clientY) / usable : 0;
|
|
556
|
+
} else {
|
|
557
|
+
const along = thumb?.offsetWidth ?? 0;
|
|
558
|
+
const usable = rect.width - along;
|
|
559
|
+
ratio = usable > 0 ? (event.clientX - rect.left - along / 2) / usable : 0;
|
|
560
|
+
if (this._isRtl()) ratio = 1 - ratio;
|
|
561
|
+
}
|
|
562
|
+
return fromRatio(ratio, this._scale);
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Take `next` as the new value and announce it. `next === this._values` (identity — the maths
|
|
566
|
+
* returns the same array when nothing moved) is a no-op for `input`.
|
|
567
|
+
*/
|
|
568
|
+
_commit(next, index, kind, sourceEvent, oldValues) {
|
|
569
|
+
if (kind === "input" && next === this._values) return;
|
|
570
|
+
const old = oldValues ?? this._values;
|
|
571
|
+
this._values = next;
|
|
572
|
+
const out = this._out(next);
|
|
573
|
+
const oldOut = this._out(old);
|
|
574
|
+
this.modelValue = out;
|
|
575
|
+
const detail = {
|
|
576
|
+
modelValue: out,
|
|
577
|
+
currentValue: out,
|
|
578
|
+
oldValue: oldOut,
|
|
579
|
+
value: out,
|
|
580
|
+
values: next.slice(),
|
|
581
|
+
index,
|
|
582
|
+
name: this.name || void 0,
|
|
583
|
+
sourceEvent
|
|
584
|
+
};
|
|
585
|
+
dispatchMonoEvent(this, kind, detail);
|
|
586
|
+
}
|
|
587
|
+
get _interactive() {
|
|
588
|
+
return !this.disabled && !this.readonly;
|
|
589
|
+
}
|
|
590
|
+
_onPointerDown(event) {
|
|
591
|
+
if (event.button !== 0 || this.disabled) return;
|
|
592
|
+
const control = event.currentTarget;
|
|
593
|
+
const thumb = event.composedPath().find((n) => n instanceof Element && n.hasAttribute?.("mono-slider-thumb"));
|
|
594
|
+
if (this.readonly) {
|
|
595
|
+
if (thumb) thumb.focus({ preventScroll: true });
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
event.preventDefault();
|
|
599
|
+
const raw = this._rawAt(event);
|
|
600
|
+
const values = this._values;
|
|
601
|
+
let index = thumb ? Number(thumb.dataset.index) : nearestThumb(values, raw);
|
|
602
|
+
let mode = "thumb";
|
|
603
|
+
let stack;
|
|
604
|
+
let run;
|
|
605
|
+
if (thumb && isStacked(values, index)) {
|
|
606
|
+
let first = index;
|
|
607
|
+
let last = index;
|
|
608
|
+
while (first > 0 && values[first - 1] === values[index]) first--;
|
|
609
|
+
while (last < values.length - 1 && values[last + 1] === values[index]) last++;
|
|
610
|
+
stack = [first, last];
|
|
611
|
+
mode = "stack";
|
|
612
|
+
} else if (!thumb && values.length > 1) {
|
|
613
|
+
const k = values.findIndex((v) => v > raw);
|
|
614
|
+
if (k > 0) {
|
|
615
|
+
if (trackPieces(values, this._scale, this.fill)[k]?.filled) {
|
|
616
|
+
run = [k - 1, k];
|
|
617
|
+
mode = "segment-pending";
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
this._gesture = {
|
|
622
|
+
pointerId: event.pointerId,
|
|
623
|
+
mode,
|
|
624
|
+
index,
|
|
625
|
+
run,
|
|
626
|
+
stack,
|
|
627
|
+
startX: event.clientX,
|
|
628
|
+
startY: event.clientY,
|
|
629
|
+
startRaw: raw,
|
|
630
|
+
startValues: values
|
|
631
|
+
};
|
|
632
|
+
control.setPointerCapture?.(event.pointerId);
|
|
633
|
+
if (mode === "thumb") {
|
|
634
|
+
this._active = index;
|
|
635
|
+
this._dragging = index;
|
|
636
|
+
this._focusThumb(index);
|
|
637
|
+
if (!thumb) this._commit(moveThumb(values, index, raw, this._scale), index, "input", event);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
_onPointerMove(event) {
|
|
641
|
+
const g = this._gesture;
|
|
642
|
+
if (!g || g.pointerId !== event.pointerId) return;
|
|
643
|
+
const raw = this._rawAt(event);
|
|
644
|
+
if (g.mode === "stack" && g.stack) {
|
|
645
|
+
if (raw === g.startRaw) return;
|
|
646
|
+
g.index = raw > g.startRaw ? g.stack[1] : g.stack[0];
|
|
647
|
+
g.mode = "thumb";
|
|
648
|
+
this._active = g.index;
|
|
649
|
+
this._dragging = g.index;
|
|
650
|
+
this._focusThumb(g.index);
|
|
651
|
+
}
|
|
652
|
+
if (g.mode === "segment-pending") {
|
|
653
|
+
if (Math.hypot(event.clientX - g.startX, event.clientY - g.startY) < SEGMENT_DRAG_THRESHOLD) return;
|
|
654
|
+
g.mode = "segment";
|
|
655
|
+
this._dragging = g.run[0];
|
|
656
|
+
}
|
|
657
|
+
if (g.mode === "segment" && g.run) {
|
|
658
|
+
const next = moveRun(g.startValues, g.run[0], g.run[1], raw - g.startRaw, this._scale);
|
|
659
|
+
if (!(next.length === this._values.length && next.every((n, i) => n === this._values[i]))) this._commit(next, -1, "input", event);
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
if (g.mode === "thumb") this._commit(moveThumb(this._values, g.index, raw, this._scale), g.index, "input", event);
|
|
663
|
+
}
|
|
664
|
+
_onPointerUp(event) {
|
|
665
|
+
const g = this._gesture;
|
|
666
|
+
if (!g || g.pointerId !== event.pointerId) return;
|
|
667
|
+
this._gesture = null;
|
|
668
|
+
event.currentTarget.releasePointerCapture?.(event.pointerId);
|
|
669
|
+
if (g.mode === "segment-pending") {
|
|
670
|
+
const raw = this._rawAt(event);
|
|
671
|
+
const index = nearestThumb(this._values, raw);
|
|
672
|
+
this._active = index;
|
|
673
|
+
this._focusThumb(index);
|
|
674
|
+
this._commit(moveThumb(this._values, index, raw, this._scale), index, "input", event);
|
|
675
|
+
}
|
|
676
|
+
this._dragging = -1;
|
|
677
|
+
if (g.startValues.length !== this._values.length || g.startValues.some((n, i) => n !== this._values[i])) this._commit(this._values, g.mode === "segment" ? -1 : g.index, "change", event, g.startValues);
|
|
678
|
+
}
|
|
679
|
+
_onPointerCancel(event) {
|
|
680
|
+
const g = this._gesture;
|
|
681
|
+
if (!g || g.pointerId !== event.pointerId) return;
|
|
682
|
+
this._onPointerUp(event);
|
|
683
|
+
}
|
|
684
|
+
_focusThumb(i) {
|
|
685
|
+
this.updateComplete.then(() => this._thumbEl(i)?.focus({ preventScroll: true }));
|
|
686
|
+
}
|
|
687
|
+
_onThumbKeydown(event) {
|
|
688
|
+
if (!this._interactive) return;
|
|
689
|
+
let i = Number(event.currentTarget.dataset.index);
|
|
690
|
+
const values = this._values;
|
|
691
|
+
const rtl = this._isRtl();
|
|
692
|
+
let dir = 0;
|
|
693
|
+
let big = false;
|
|
694
|
+
let edge = null;
|
|
695
|
+
switch (event.key) {
|
|
696
|
+
case "ArrowUp":
|
|
697
|
+
dir = 1;
|
|
698
|
+
break;
|
|
699
|
+
case "ArrowDown":
|
|
700
|
+
dir = -1;
|
|
701
|
+
break;
|
|
702
|
+
case "ArrowRight":
|
|
703
|
+
dir = rtl ? -1 : 1;
|
|
704
|
+
break;
|
|
705
|
+
case "ArrowLeft":
|
|
706
|
+
dir = rtl ? 1 : -1;
|
|
707
|
+
break;
|
|
708
|
+
case "PageUp":
|
|
709
|
+
dir = 1;
|
|
710
|
+
big = true;
|
|
711
|
+
break;
|
|
712
|
+
case "PageDown":
|
|
713
|
+
dir = -1;
|
|
714
|
+
big = true;
|
|
715
|
+
break;
|
|
716
|
+
case "Home":
|
|
717
|
+
edge = "lo";
|
|
718
|
+
break;
|
|
719
|
+
case "End":
|
|
720
|
+
edge = "hi";
|
|
721
|
+
break;
|
|
722
|
+
default: return;
|
|
723
|
+
}
|
|
724
|
+
event.preventDefault();
|
|
725
|
+
if (dir && isStacked(values, i)) {
|
|
726
|
+
let j = i;
|
|
727
|
+
if (dir > 0) while (j < values.length - 1 && values[j + 1] === values[i]) j++;
|
|
728
|
+
else while (j > 0 && values[j - 1] === values[i]) j--;
|
|
729
|
+
if (j !== i) {
|
|
730
|
+
i = j;
|
|
731
|
+
this._focusThumb(i);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
const { lo, hi } = thumbBounds(values, i, this._scale);
|
|
735
|
+
const target = edge === "lo" ? lo : edge === "hi" ? hi : stepFrom(values[i], dir, big, this._scale);
|
|
736
|
+
const next = moveThumb(values, i, target, this._scale);
|
|
737
|
+
this._active = i;
|
|
738
|
+
if (next === values) return;
|
|
739
|
+
this._commit(next, i, "input", event);
|
|
740
|
+
this._commit(next, i, "change", event, values);
|
|
741
|
+
}
|
|
742
|
+
get _resolvedValidationState() {
|
|
743
|
+
if (this.validationState && this.validationState !== "default") return this.validationState;
|
|
744
|
+
if (this.error || this.errorMessage) return "invalid";
|
|
745
|
+
if (this.success || this.successMessage) return "valid";
|
|
746
|
+
return "default";
|
|
747
|
+
}
|
|
748
|
+
_cls(base, key) {
|
|
749
|
+
return cssPart(this.cssClass, base, key);
|
|
750
|
+
}
|
|
751
|
+
get _hasLabel() {
|
|
752
|
+
return !!(this.label || this._hasLabelSlotState);
|
|
753
|
+
}
|
|
754
|
+
get _describedBy() {
|
|
755
|
+
return this.validationMessage || this.errorMessage || this.successMessage || this.helperText || this._hasHelperSlotState ? this._messageId : void 0;
|
|
756
|
+
}
|
|
757
|
+
_thumbLabel(i) {
|
|
758
|
+
const base = this.ariaLabelText || this.label || void 0;
|
|
759
|
+
const n = this._values.length;
|
|
760
|
+
if (n === 1) return base;
|
|
761
|
+
const which = n === 2 ? i === 0 ? "minimum" : "maximum" : `${i + 1} of ${n}`;
|
|
762
|
+
return base ? `${base} (${which})` : which;
|
|
763
|
+
}
|
|
764
|
+
focus(options) {
|
|
765
|
+
this._thumbEl(this._active)?.focus(options);
|
|
766
|
+
}
|
|
767
|
+
blur() {
|
|
768
|
+
this._thumbEl(this._active)?.blur();
|
|
769
|
+
}
|
|
770
|
+
/** Label text region — light: placeholder for the captured slot; shadow overrides with `<slot>`. */
|
|
771
|
+
_renderLabelText() {
|
|
772
|
+
return this._hasLabelSlotState ? html`<span data-mono-slot="label"></span>` : this.label;
|
|
773
|
+
}
|
|
774
|
+
_renderReadout() {
|
|
775
|
+
return html`<span class=${this._cls("mono-slider-value", "value")} mono-slider-value aria-hidden="true">${this._readoutText}</span>`;
|
|
776
|
+
}
|
|
777
|
+
/** The label row: text, required mark, ⓘ, and the value at its end. */
|
|
778
|
+
_renderLabel() {
|
|
779
|
+
if (!this._hasLabel) return nothing;
|
|
780
|
+
return html`
|
|
781
|
+
<div mono-label-row>
|
|
782
|
+
<label class=${this._cls("mono-slider-label", "label")} mono-label id=${`${this._sliderId}-label`}>
|
|
783
|
+
${this._renderLabelText()}
|
|
784
|
+
${this.required ? html`<span class=${this._cls("mono-slider-required", "required")} mono-required-mark>*</span>` : nothing}
|
|
785
|
+
${this._tooltip.render()}
|
|
786
|
+
</label>
|
|
787
|
+
${this.showValue ? this._renderReadout() : nothing}
|
|
788
|
+
</div>
|
|
789
|
+
`;
|
|
790
|
+
}
|
|
791
|
+
_renderMessage() {
|
|
792
|
+
const base = this._cls("mono-slider-message", "message");
|
|
793
|
+
if (this.validationMessage) {
|
|
794
|
+
const s = this._resolvedValidationState;
|
|
795
|
+
return html`<div class=${`${base} ${s}`} mono-message=${s} role=${s === "invalid" ? "alert" : nothing}>${this.validationMessage}</div>`;
|
|
796
|
+
}
|
|
797
|
+
if (this.errorMessage) return html`<div class=${`${base} invalid`} mono-message="invalid" role="alert">${this.errorMessage}</div>`;
|
|
798
|
+
if (this.successMessage) return html`<div class=${`${base} valid`} mono-message="valid">${this.successMessage}</div>`;
|
|
799
|
+
if (this.helperText || this._hasHelperSlotState) return html`<div class=${`${base} helper`} mono-message="helper">${this._hasHelperSlotState ? html`<span data-mono-slot="helper"></span>` : this.helperText}</div>`;
|
|
800
|
+
return nothing;
|
|
801
|
+
}
|
|
802
|
+
_renderPieces(pieces) {
|
|
803
|
+
return html`${pieces.map((p, k) => html`<span
|
|
804
|
+
class=${this._cls("mono-slider-fill", "fill")}
|
|
805
|
+
mono-slider-piece
|
|
806
|
+
?mono-filled=${p.filled}
|
|
807
|
+
?mono-cut-start=${p.cutStart}
|
|
808
|
+
?mono-cut-end=${p.cutEnd}
|
|
809
|
+
data-k=${k}
|
|
810
|
+
style=${`--a: ${p.from / 100}; --b: ${p.to / 100}`}
|
|
811
|
+
></span>`)}`;
|
|
812
|
+
}
|
|
813
|
+
_renderMarks(marks, pieces) {
|
|
814
|
+
if (!marks.length) return nothing;
|
|
815
|
+
const filled = pieces.filter((p) => p.filled);
|
|
816
|
+
const active = (pct) => filled.some((p) => pct >= p.from - 1e-9 && pct <= p.to + 1e-9);
|
|
817
|
+
const labelled = Array.isArray(this.marks) || typeof this.marks === "string" && this.marks.trim().startsWith("[");
|
|
818
|
+
return html`
|
|
819
|
+
<div class=${this._cls("mono-slider-marks", "marks")} mono-slider-marks aria-hidden="true">
|
|
820
|
+
${marks.map((m) => html`<span
|
|
821
|
+
class=${this._cls("mono-slider-mark", "mark")}
|
|
822
|
+
mono-slider-mark
|
|
823
|
+
?mono-active=${active(m.pct)}
|
|
824
|
+
style=${`--p: ${m.pct / 100}`}
|
|
825
|
+
>${labelled ? html`<span class=${this._cls("mono-slider-mark-label", "markLabel")} mono-slider-mark-label>${m.label ?? this._format(m.value)}</span>` : nothing}</span>`)}
|
|
826
|
+
</div>
|
|
827
|
+
`;
|
|
828
|
+
}
|
|
829
|
+
_renderThumb(v, i) {
|
|
830
|
+
const { lo, hi } = thumbBounds(this._values, i, this._scale);
|
|
831
|
+
const text = this._format(v);
|
|
832
|
+
const raw = String(stripNoise(v));
|
|
833
|
+
return html`<div
|
|
834
|
+
class=${this._cls("mono-slider-thumb", "thumb")}
|
|
835
|
+
mono-slider-thumb
|
|
836
|
+
role="slider"
|
|
837
|
+
data-index=${i}
|
|
838
|
+
tabindex=${this.disabled ? -1 : 0}
|
|
839
|
+
style=${`--p: ${toPercent(v, this._scale) / 100}`}
|
|
840
|
+
?mono-active=${i === this._active}
|
|
841
|
+
?mono-dragging=${i === this._dragging}
|
|
842
|
+
aria-valuemin=${lo}
|
|
843
|
+
aria-valuemax=${hi}
|
|
844
|
+
aria-valuenow=${raw}
|
|
845
|
+
aria-valuetext=${ifDefined(text !== raw ? text : void 0)}
|
|
846
|
+
aria-orientation=${this._vertical ? "vertical" : "horizontal"}
|
|
847
|
+
aria-label=${ifDefined(this._thumbLabel(i))}
|
|
848
|
+
aria-labelledby=${ifDefined(!this.ariaLabelText && this._hasLabel && this._values.length === 1 ? `${this._sliderId}-label` : void 0)}
|
|
849
|
+
aria-disabled=${ifDefined(this.disabled ? "true" : void 0)}
|
|
850
|
+
aria-readonly=${ifDefined(this.readonly ? "true" : void 0)}
|
|
851
|
+
aria-required=${ifDefined(this.required ? "true" : void 0)}
|
|
852
|
+
aria-invalid=${ifDefined(this._resolvedValidationState === "invalid" ? "true" : void 0)}
|
|
853
|
+
aria-describedby=${ifDefined(this._describedBy)}
|
|
854
|
+
@keydown=${this._onThumbKeydown}
|
|
855
|
+
@focus=${() => {
|
|
856
|
+
this._active = i;
|
|
857
|
+
}}
|
|
858
|
+
>${this.valueTooltip === "never" ? nothing : html`<span class=${this._cls("mono-slider-tooltip", "tooltip")} mono-slider-tooltip aria-hidden="true">${text}</span>`}</div>`;
|
|
859
|
+
}
|
|
860
|
+
_renderHidden() {
|
|
861
|
+
if (!this.name) return nothing;
|
|
862
|
+
const name = (this._values.length > 1 || this._isArrayModel) && !this.name.endsWith("[]") ? `${this.name}[]` : this.name;
|
|
863
|
+
return html`${this._values.map((v) => html`<input type="hidden" mono-slider-hidden name=${name} .value=${String(v)} ?disabled=${this.disabled} />`)}`;
|
|
864
|
+
}
|
|
865
|
+
render() {
|
|
866
|
+
const pieces = trackPieces(this._values, this._scale, this.fill);
|
|
867
|
+
const marks = markPoints(this.marks === "" ? true : this.marks, this._scale);
|
|
868
|
+
const state = this._resolvedValidationState;
|
|
869
|
+
const gap = Number(this.trackGap) || 0;
|
|
870
|
+
const labelledMarks = marks.length > 0 && (Array.isArray(this.marks) || typeof this.marks === "string" && this.marks.trim().startsWith("["));
|
|
871
|
+
const style = {};
|
|
872
|
+
const width = toCssSize(this.width);
|
|
873
|
+
if (width) style.width = width;
|
|
874
|
+
const length = toCssSize(this.height);
|
|
875
|
+
if (length) style["--_mono-slider-length"] = length;
|
|
876
|
+
if (gap > 0) style["--_mono-slider-track-gap"] = `${gap}px`;
|
|
877
|
+
return html`<div
|
|
878
|
+
class=${[
|
|
879
|
+
"mono-slider",
|
|
880
|
+
this.size,
|
|
881
|
+
this.color,
|
|
882
|
+
this._vertical ? "vertical" : "",
|
|
883
|
+
this.disabled ? "disabled" : "",
|
|
884
|
+
this.cssClassName,
|
|
885
|
+
this.cssClass?.root
|
|
886
|
+
].filter(Boolean).join(" ")}
|
|
887
|
+
style=${styleMap(style)}
|
|
888
|
+
mono-slider
|
|
889
|
+
mono-size=${this.size === "md" ? nothing : this.size}
|
|
890
|
+
mono-color=${this.color === "primary" ? nothing : this.color}
|
|
891
|
+
mono-type=${this._vertical ? "vertical" : nothing}
|
|
892
|
+
mono-validation-state=${state === "default" ? nothing : state}
|
|
893
|
+
mono-value-tooltip=${this.valueTooltip === "auto" ? nothing : this.valueTooltip}
|
|
894
|
+
?mono-track-gap=${gap > 0}
|
|
895
|
+
?mono-marks-labelled=${labelledMarks}
|
|
896
|
+
?mono-disabled=${this.disabled}
|
|
897
|
+
?mono-readonly=${this.readonly}
|
|
898
|
+
?mono-required=${this.required}
|
|
899
|
+
?mono-dragging=${this._dragging >= 0}
|
|
900
|
+
>
|
|
901
|
+
${this._renderLabel()}
|
|
902
|
+
<div mono-slider-field>
|
|
903
|
+
<div
|
|
904
|
+
class=${this._cls("mono-slider-control", "control")}
|
|
905
|
+
mono-slider-control
|
|
906
|
+
@pointerdown=${this._onPointerDown}
|
|
907
|
+
@pointermove=${this._onPointerMove}
|
|
908
|
+
@pointerup=${this._onPointerUp}
|
|
909
|
+
@pointercancel=${this._onPointerCancel}
|
|
910
|
+
>
|
|
911
|
+
<div class=${this._cls("mono-slider-track", "track")} mono-slider-track>${this._renderPieces(pieces)}</div>
|
|
912
|
+
${this._renderMarks(marks, pieces)}
|
|
913
|
+
${this._values.map((v, i) => this._renderThumb(v, i))}
|
|
914
|
+
</div>
|
|
915
|
+
${!this._hasLabel && this.showValue ? this._renderReadout() : nothing}
|
|
916
|
+
</div>
|
|
917
|
+
${this._renderHidden()}
|
|
918
|
+
<div id=${this._messageId} class=${this.cssClass?.messageWrap ?? ""} mono-message-wrap>${this._renderMessage()}</div>
|
|
919
|
+
</div>`;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
__decorate([property({
|
|
923
|
+
attribute: "model-value",
|
|
924
|
+
hasChanged: sliderValueHasChanged
|
|
925
|
+
})], MonoSliderCoreClass.prototype, "modelValue", void 0);
|
|
926
|
+
__decorate([property()], MonoSliderCoreClass.prototype, "min", void 0);
|
|
927
|
+
__decorate([property()], MonoSliderCoreClass.prototype, "max", void 0);
|
|
928
|
+
__decorate([property()], MonoSliderCoreClass.prototype, "step", void 0);
|
|
929
|
+
__decorate([property({ hasChanged: sliderValueHasChanged })], MonoSliderCoreClass.prototype, "stops", void 0);
|
|
930
|
+
__decorate([property({ attribute: "min-gap" })], MonoSliderCoreClass.prototype, "minGap", void 0);
|
|
931
|
+
__decorate([property({ type: String })], MonoSliderCoreClass.prototype, "type", void 0);
|
|
932
|
+
__decorate([property()], MonoSliderCoreClass.prototype, "marks", void 0);
|
|
933
|
+
__decorate([property({ type: String })], MonoSliderCoreClass.prototype, "fill", void 0);
|
|
934
|
+
__decorate([property({ attribute: "track-gap" })], MonoSliderCoreClass.prototype, "trackGap", void 0);
|
|
935
|
+
__decorate([property({
|
|
936
|
+
type: String,
|
|
937
|
+
attribute: "value-tooltip"
|
|
938
|
+
})], MonoSliderCoreClass.prototype, "valueTooltip", void 0);
|
|
939
|
+
__decorate([property({
|
|
940
|
+
attribute: "show-value",
|
|
941
|
+
converter: defaultOnConverter
|
|
942
|
+
})], MonoSliderCoreClass.prototype, "showValue", void 0);
|
|
943
|
+
__decorate([property({
|
|
944
|
+
type: String,
|
|
945
|
+
attribute: "value-separator"
|
|
946
|
+
})], MonoSliderCoreClass.prototype, "valueSeparator", void 0);
|
|
947
|
+
__decorate([property({ attribute: false })], MonoSliderCoreClass.prototype, "formatDisplay", void 0);
|
|
948
|
+
__decorate([property({
|
|
949
|
+
type: String,
|
|
950
|
+
attribute: "format-locale"
|
|
951
|
+
})], MonoSliderCoreClass.prototype, "formatLocale", void 0);
|
|
952
|
+
__decorate([property({ type: String })], MonoSliderCoreClass.prototype, "size", void 0);
|
|
953
|
+
__decorate([property({ type: String })], MonoSliderCoreClass.prototype, "color", void 0);
|
|
954
|
+
__decorate([property({ type: String })], MonoSliderCoreClass.prototype, "label", void 0);
|
|
955
|
+
__decorate([property({
|
|
956
|
+
type: String,
|
|
957
|
+
attribute: "helper-text"
|
|
958
|
+
})], MonoSliderCoreClass.prototype, "helperText", void 0);
|
|
959
|
+
__decorate([property()], MonoSliderCoreClass.prototype, "tooltip", void 0);
|
|
960
|
+
__decorate([property({
|
|
961
|
+
type: String,
|
|
962
|
+
attribute: "validation-state"
|
|
963
|
+
})], MonoSliderCoreClass.prototype, "validationState", void 0);
|
|
964
|
+
__decorate([property({
|
|
965
|
+
type: String,
|
|
966
|
+
attribute: "validation-message"
|
|
967
|
+
})], MonoSliderCoreClass.prototype, "validationMessage", void 0);
|
|
968
|
+
__decorate([property({
|
|
969
|
+
reflect: true,
|
|
970
|
+
converter: booleanStringConverter
|
|
971
|
+
})], MonoSliderCoreClass.prototype, "error", void 0);
|
|
972
|
+
__decorate([property({
|
|
973
|
+
type: String,
|
|
974
|
+
attribute: "error-message"
|
|
975
|
+
})], MonoSliderCoreClass.prototype, "errorMessage", void 0);
|
|
976
|
+
__decorate([property({
|
|
977
|
+
reflect: true,
|
|
978
|
+
converter: booleanStringConverter
|
|
979
|
+
})], MonoSliderCoreClass.prototype, "success", void 0);
|
|
980
|
+
__decorate([property({
|
|
981
|
+
type: String,
|
|
982
|
+
attribute: "success-message"
|
|
983
|
+
})], MonoSliderCoreClass.prototype, "successMessage", void 0);
|
|
984
|
+
__decorate([property({
|
|
985
|
+
reflect: true,
|
|
986
|
+
converter: booleanStringConverter
|
|
987
|
+
})], MonoSliderCoreClass.prototype, "disabled", void 0);
|
|
988
|
+
__decorate([property({
|
|
989
|
+
reflect: true,
|
|
990
|
+
converter: booleanStringConverter
|
|
991
|
+
})], MonoSliderCoreClass.prototype, "readonly", void 0);
|
|
992
|
+
__decorate([property({
|
|
993
|
+
reflect: true,
|
|
994
|
+
converter: booleanStringConverter
|
|
995
|
+
})], MonoSliderCoreClass.prototype, "required", void 0);
|
|
996
|
+
__decorate([property({ type: String })], MonoSliderCoreClass.prototype, "name", void 0);
|
|
997
|
+
__decorate([property({
|
|
998
|
+
type: String,
|
|
999
|
+
attribute: "aria-label"
|
|
1000
|
+
})], MonoSliderCoreClass.prototype, "ariaLabelText", void 0);
|
|
1001
|
+
__decorate([property({ type: String })], MonoSliderCoreClass.prototype, "width", void 0);
|
|
1002
|
+
__decorate([property({ type: String })], MonoSliderCoreClass.prototype, "height", void 0);
|
|
1003
|
+
__decorate([property({ attribute: false })], MonoSliderCoreClass.prototype, "cssClass", void 0);
|
|
1004
|
+
__decorate([property({
|
|
1005
|
+
type: String,
|
|
1006
|
+
attribute: "css-class"
|
|
1007
|
+
})], MonoSliderCoreClass.prototype, "cssClassName", void 0);
|
|
1008
|
+
__decorate([state()], MonoSliderCoreClass.prototype, "_values", void 0);
|
|
1009
|
+
__decorate([state()], MonoSliderCoreClass.prototype, "_active", void 0);
|
|
1010
|
+
__decorate([state()], MonoSliderCoreClass.prototype, "_dragging", void 0);
|
|
1011
|
+
__decorate([state()], MonoSliderCoreClass.prototype, "_hasLabelSlotState", void 0);
|
|
1012
|
+
__decorate([state()], MonoSliderCoreClass.prototype, "_hasHelperSlotState", void 0);
|
|
1013
|
+
return MonoSliderCoreClass;
|
|
1014
|
+
};
|
|
1015
|
+
|
|
1016
|
+
//#endregion
|
|
1017
|
+
//#region \0raw:C:\Users\VCT-DEV\Desktop\libs\packages\helper\src\components\slider\slider.css?raw.js
|
|
1018
|
+
var slider_css_raw_default = "/* =========================================================================\n mono-slider — a multi-thumb slider drawn in the look of Basecoat's range\n (basecoat-css@1.0.2 components/range.css + each style's `input[type='range']`),\n the same look `<mono-input type=\"range\">` has.\n\n Styled by ATTRIBUTE, like mono-input:\n\n <div mono-slider mono-size mono-color mono-type=\"vertical\"\n mono-validation-state mono-value-tooltip=\"always|never\"\n mono-track-gap mono-marks-labelled mono-disabled mono-readonly mono-dragging>\n <div mono-label-row><label mono-label>…</label><span mono-slider-value>20 – 80</span></div>\n <div mono-slider-field>\n <div mono-slider-control> the pointer target\n <div mono-slider-track> the rail; it holds the pieces\n <span mono-slider-piece mono-filled? mono-cut-start? mono-cut-end? style=\"--a;--b\">\n <div mono-slider-marks><span mono-slider-mark mono-active? style=\"--p\">\n <span mono-slider-mark-label>\n <div mono-slider-thumb role=\"slider\" mono-active? mono-dragging? style=\"--p\">\n <span mono-slider-tooltip>\n <div mono-message-wrap><div mono-message=\"helper|valid|invalid|warning\">\n\n GEOMETRY. `--p` / `--a` / `--b` are 0–1 positions (unitless). A thumb's CENTRE travels\n from half a thumb in to half a thumb short of the end — exactly where a native range\n thumb sits — so the slider lines up with `<mono-input type=\"range\">` under every flavor.\n The track is cut into pieces at every thumb: that is what lets a piece be filled or not\n (`fill`), and what lets `track-gap` cut the track back around each thumb (M3 style).\n\n KNOBS. Every look value resolves `--mono-slider-x` → `--mono-input-range-x` → vega,\n so the eight Basecoat styles and ONE (which write the input-range knobs in\n flavors/*.css) restyle the slider with no slider entries of their own — the\n \"flavor via public knobs\" pattern (filter.css). Slider-only knobs: --mono-slider-\n {length, track-gap, accent, mark-size, mark-color, mark-active-color, mark-label-*,\n tooltip-bg, tooltip-color, tooltip-radius, tooltip-font-*}.\n\n The track/thumb rules cite Basecoat; marks, tooltips, track gaps, multiple\n thumbs and the vertical type are EXTENSIONs.\n ========================================================================= */\n\nmono-slider {\n display: block;\n}\n\n[mono-slider] {\n /* ── palette ─────────────────────────────────────────────────────────── */\n --_mono-slider-text: var(--mono-slider-color, var(--foreground));\n --_mono-slider-muted: var(--mono-slider-muted, var(--muted-foreground));\n /* the fill + thumb colour: the `color` prop, a validation state outranks it */\n --_mono-slider-accent: var(--mono-slider-accent, var(--_mono-slider-accent-preset, var(--primary)));\n /* the hover / focus halo: Basecoat's ring-ring/50 (the role colour for a non-primary `color`) */\n --_mono-slider-ring-color: var(--mono-slider-ring-color, var(--_mono-slider-ring-preset, var(--ring)));\n --_mono-slider-ring-c: color-mix(in oklab, var(--_mono-slider-ring-color) var(--mono-slider-ring-alpha, var(--mono-ring-alpha, 50%)), transparent);\n\n /* ── geometry: md here, `size` multiplies ────────────────────────────── */\n --_mono-slider-scale: 1;\n --_mono-slider-track-h: round(nearest, calc(var(--mono-slider-track-height, var(--mono-input-range-track-height, 0.375rem)) * var(--_mono-slider-scale)), 1px);\n /* along = the thumb's size in the direction of travel, across = the other one */\n --_mono-slider-across: round(nearest, calc(var(--mono-slider-thumb-size, var(--mono-input-range-thumb-size, 1rem)) * var(--_mono-slider-scale)), 1px);\n --_mono-slider-along: round(nearest, calc(var(--mono-slider-thumb-width, var(--mono-input-range-thumb-width, var(--mono-slider-thumb-size, var(--mono-input-range-thumb-size, 1rem)))) * var(--_mono-slider-scale)), 1px);\n --_mono-slider-box: max(round(nearest, calc(var(--mono-slider-height, var(--mono-input-range-height, 1.25rem)) * var(--_mono-slider-scale)), 1px), var(--_mono-slider-across));\n --_mono-slider-track-radius: var(--mono-slider-track-radius, var(--mono-input-range-track-radius, 9999px));\n --_mono-slider-track-bg: var(--mono-slider-track-bg, var(--mono-input-range-track-bg, var(--muted)));\n --_mono-slider-fill: var(--mono-slider-fill, var(--mono-input-range-fill, currentColor));\n --_mono-slider-cut: calc(var(--_mono-slider-track-gap, 0px) + var(--_mono-slider-along) / 2);\n\n /* basecoat@1.0.2 styles/vega.css .field — flex w-full flex-col gap-3 (the input range's gap) */\n display: flex;\n flex-direction: column;\n gap: var(--mono-slider-gap, var(--mono-input-range-gap, var(--mono-input-gap, calc(var(--mono-spacing) * 3))));\n width: 100%;\n font-family: inherit;\n color: var(--_mono-slider-text);\n}\n\n[mono-slider],\n:where([mono-slider]) *,\n:where([mono-slider]) *::before,\n:where([mono-slider]) *::after {\n box-sizing: border-box;\n}\n\n/* the shadow build renders every region and marks an empty one */\n[mono-slider] [mono-empty] {\n display: none;\n}\n\n[mono-slider][mono-size=\"xs\"] { --_mono-slider-scale: 0.75; }\n[mono-slider][mono-size=\"sm\"] { --_mono-slider-scale: 0.875; }\n[mono-slider][mono-size=\"lg\"] { --_mono-slider-scale: 1.125; }\n[mono-slider][mono-size=\"xl\"] { --_mono-slider-scale: 1.25; }\n[mono-slider][mono-size=\"xxl\"] { --_mono-slider-scale: 1.375; }\n\n/* ── colours: the accent + halo per role (primary is Basecoat's --primary / --ring) ── */\n[mono-slider][mono-color=\"secondary\"] { --_mono-slider-accent-preset: var(--muted-foreground); --_mono-slider-ring-preset: var(--muted-foreground); }\n[mono-slider][mono-color=\"success\"] { --_mono-slider-accent-preset: var(--success); --_mono-slider-ring-preset: var(--success); }\n[mono-slider][mono-color=\"danger\"] { --_mono-slider-accent-preset: var(--destructive); --_mono-slider-ring-preset: var(--destructive); }\n[mono-slider][mono-color=\"warning\"] { --_mono-slider-accent-preset: var(--warning); --_mono-slider-ring-preset: var(--warning); }\n[mono-slider][mono-color=\"info\"] { --_mono-slider-accent-preset: var(--info); --_mono-slider-ring-preset: var(--info); }\n[mono-slider][mono-color=\"teal\"] { --_mono-slider-accent-preset: var(--teal); --_mono-slider-ring-preset: var(--teal); }\n[mono-slider][mono-color=\"purple\"] { --_mono-slider-accent-preset: var(--purple); --_mono-slider-ring-preset: var(--purple); }\n[mono-slider][mono-color=\"neutral\"] { --_mono-slider-accent-preset: var(--neutral); --_mono-slider-ring-preset: var(--neutral); }\n[mono-slider][mono-color=\"dark\"] { --_mono-slider-accent-preset: var(--dark); --_mono-slider-ring-preset: var(--dark); }\n\n/* a validation state recolours the fill + thumb (after the colours, so it wins) */\n[mono-slider][mono-validation-state=\"invalid\"] { --_mono-slider-accent-preset: var(--destructive); --_mono-slider-ring-preset: var(--destructive); }\n[mono-slider][mono-validation-state=\"valid\"] { --_mono-slider-accent-preset: var(--success); --_mono-slider-ring-preset: var(--success); }\n[mono-slider][mono-validation-state=\"warning\"] { --_mono-slider-accent-preset: var(--warning); --_mono-slider-ring-preset: var(--warning); }\n\n/* =========================================\n Label row — the label, and the value at its end (EJI ONE `.eji-range__row`)\n ========================================= */\n\n/* basecoat@1.0.2 styles/vega.css .field > label, .label — flex items-center gap-2 text-sm\n leading-none font-medium select-none; the row spans so the value can end it */\n:where([mono-slider]) > [mono-label-row] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: calc(var(--mono-spacing) * 4);\n min-width: 0;\n}\n\n:where([mono-slider]) [mono-label] {\n display: flex;\n align-items: center;\n min-width: 0;\n gap: var(--mono-input-label-gap, calc(var(--mono-spacing) * 2));\n font-size: var(--mono-slider-label-font-size, var(--mono-input-range-label-font-size, var(--mono-input-label-font-size, var(--mono-text-sm))));\n line-height: var(--mono-slider-label-line-height, var(--mono-input-range-label-line-height, var(--mono-input-label-line-height, 1)));\n font-weight: var(--mono-slider-label-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 color: var(--mono-slider-label-color, var(--mono-input-range-label-color, var(--_mono-slider-text)));\n user-select: none;\n}\n\n:where([mono-slider]) [mono-required-mark] {\n color: var(--destructive);\n}\n\n/* the label ⓘ (`tooltip` prop) — same as mono-input's */\n:where([mono-slider]) [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 &:is(:hover, :focus-visible) {\n opacity: 1;\n }\n &:focus-visible {\n outline: 2px solid currentColor;\n outline-offset: 2px;\n }\n & > [mono-icon] {\n width: 1em;\n height: 1em;\n }\n}\n\n/* EXTENSION — the value readout (EJI ONE `.eji-range__val`); tabular so it does not shimmer */\n:where([mono-slider]) [mono-slider-value] {\n flex: none;\n font-family: var(--mono-slider-value-font-family, var(--mono-input-range-value-font-family, inherit));\n font-size: var(--mono-slider-value-font-size, var(--mono-input-range-value-font-size, var(--mono-slider-label-font-size, var(--mono-input-range-label-font-size, var(--mono-input-label-font-size, var(--mono-text-sm))))));\n font-weight: var(--mono-slider-value-font-weight, var(--mono-input-range-value-font-weight, var(--mono-font-weight-medium)));\n line-height: var(--mono-slider-label-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-slider-value-color, var(--mono-input-range-value-color, var(--_mono-slider-muted)));\n white-space: nowrap;\n user-select: none;\n}\n\n/* no label: the readout follows the control, in reserved room */\n:where([mono-slider]) > [mono-slider-field] > [mono-slider-value] {\n min-width: var(--mono-slider-value-min-width, var(--mono-input-range-value-min-width, 3ch));\n text-align: end;\n}\n\n/* =========================================\n Field + control\n ========================================= */\n\n:where([mono-slider]) > [mono-slider-field] {\n display: flex;\n align-items: center;\n gap: calc(var(--mono-spacing) * 3);\n min-width: 0;\n}\n\n/* basecoat@1.0.2 components/range.css .field > input[type='range'], .input[type='range'] — flex appearance-none\n items-center p-0 outline-none disabled:pointer-events-none disabled:opacity-50 */\n/* basecoat@1.0.2 styles/vega.css .field > input[type='range'], .input[type='range'] — h-5 (the box), --slider-track-height,\n --slider-thumb-size; mono: the box also grows to fit a taller thumb */\n:where([mono-slider]) [mono-slider-control] {\n position: relative;\n flex: 1 1 auto;\n min-width: 0;\n height: var(--_mono-slider-box);\n color: var(--_mono-slider-accent);\n cursor: pointer;\n touch-action: none;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n}\n\n/* room for mark labels under the track */\n[mono-slider][mono-marks-labelled] [mono-slider-control] {\n margin-block-end: calc(var(--mono-slider-mark-label-gap, calc(var(--mono-spacing) * 1.5)) + var(--mono-slider-mark-label-line-height, 1rem));\n}\n\n/* =========================================\n Track — the rail, cut into pieces at every thumb\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\n rounded-full (+ components/range.css: the --primary / --muted gradient stop, here one piece each) */\n:where([mono-slider]) [mono-slider-track] {\n position: absolute;\n inset-inline: 0;\n top: 50%;\n height: var(--_mono-slider-track-h);\n margin-top: calc(var(--_mono-slider-track-h) / -2);\n}\n\n:where([mono-slider]) [mono-slider-piece] {\n /* piece ends: a thumb centre, or the very end of the rail */\n --_x0: calc(var(--_mono-slider-along) / 2 + (100% - var(--_mono-slider-along)) * var(--a));\n --_x1: calc(var(--_mono-slider-along) / 2 + (100% - var(--_mono-slider-along)) * var(--b));\n --_cs: 0px;\n --_ce: 0px;\n position: absolute;\n inset-block: 0;\n inset-inline-start: calc(var(--_x0) + var(--_cs));\n inline-size: max(0px, calc(var(--_x1) - var(--_x0) - var(--_cs) - var(--_ce)));\n border-radius: var(--_mono-slider-track-radius);\n background: var(--_mono-slider-track-bg);\n}\n:where([mono-slider]) [mono-slider-piece]:not([mono-cut-start]) { --_x0: 0%; }\n:where([mono-slider]) [mono-slider-piece]:not([mono-cut-end]) { --_x1: 100%; }\n:where([mono-slider]) [mono-slider-piece][mono-filled] {\n background: var(--_mono-slider-fill);\n}\n\n/* joins at a thumb are square unless `track-gap` opens them (then each piece is a\n whole rounded bar, Material 3's look) */\n[mono-slider]:not([mono-track-gap]) [mono-slider-piece][mono-cut-start] {\n border-start-start-radius: 0;\n border-end-start-radius: 0;\n}\n[mono-slider]:not([mono-track-gap]) [mono-slider-piece][mono-cut-end] {\n border-start-end-radius: 0;\n border-end-end-radius: 0;\n}\n[mono-slider][mono-track-gap] [mono-slider-piece][mono-cut-start] { --_cs: var(--_mono-slider-cut); }\n[mono-slider][mono-track-gap] [mono-slider-piece][mono-cut-end] { --_ce: var(--_mono-slider-cut); }\n\n/* =========================================\n Thumb\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\n size-4 rounded-full border bg-white shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4;\n mono: the three box-shadow slots of mono-input's range — a resting ring, the halo, the shadow */\n:where([mono-slider]) [mono-slider-thumb] {\n --_halo: 0 0 #0000;\n position: absolute;\n z-index: 1;\n top: 50%;\n inset-inline-start: calc(var(--_mono-slider-along) / 2 + (100% - var(--_mono-slider-along)) * var(--p));\n width: var(--_mono-slider-along);\n height: var(--_mono-slider-across);\n margin-top: calc(var(--_mono-slider-across) / -2);\n margin-inline-start: calc(var(--_mono-slider-along) / -2);\n border: var(--mono-slider-thumb-border-width, var(--mono-input-range-thumb-border-width, 1px)) solid\n var(--mono-slider-thumb-border-color, var(--mono-input-range-thumb-border-color, currentColor));\n border-radius: var(--mono-slider-thumb-radius, var(--mono-input-range-thumb-radius, 9999px));\n background: var(--mono-slider-thumb-bg, var(--mono-input-range-thumb-bg, #fff));\n box-shadow:\n 0 0 0 var(--mono-slider-thumb-ring-width, var(--mono-input-range-thumb-ring-width, 0px))\n var(--mono-slider-thumb-ring-color, var(--mono-input-range-thumb-ring-color, transparent)),\n var(--_halo),\n var(--mono-slider-thumb-shadow, var(--mono-input-range-thumb-shadow, var(--mono-shadow-sm)));\n outline: none;\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/* the last-touched thumb rides on top, so a stack lifts the one being moved */\n:where([mono-slider]) [mono-slider-thumb][mono-active] {\n z-index: 2;\n}\n\n/* focus-visible:ring-4 focus-visible:outline-hidden; a drag keeps the halo on */\n:where([mono-slider]) [mono-slider-thumb]:is(:focus-visible, [mono-dragging]) {\n --_halo: 0 0 0 var(--mono-slider-ring-width, var(--mono-input-range-ring-width, 4px)) var(--_mono-slider-ring-c);\n}\n\n/* hover:ring-4 */\n@media (hover: hover) {\n [mono-slider]:not([mono-disabled], [mono-readonly]) [mono-slider-thumb]:hover:not(:focus-visible, [mono-dragging]) {\n --_halo: 0 0 0 var(--mono-slider-hover-ring-width, var(--mono-input-range-hover-ring-width, var(--mono-slider-ring-width, var(--mono-input-range-ring-width, 4px)))) var(--_mono-slider-ring-c);\n }\n}\n\n/* =========================================\n EXTENSION — marks\n ========================================= */\n\n:where([mono-slider]) [mono-slider-marks] {\n position: absolute;\n inset: 0;\n pointer-events: none;\n}\n\n:where([mono-slider]) [mono-slider-mark] {\n --_size: var(--mono-slider-mark-size, max(4px, calc(var(--_mono-slider-track-h) * 0.5)));\n position: absolute;\n top: 50%;\n inset-inline-start: calc(var(--_mono-slider-along) / 2 + (100% - var(--_mono-slider-along)) * var(--p));\n width: var(--_size);\n height: var(--_size);\n margin-top: calc(var(--_size) / -2);\n margin-inline-start: calc(var(--_size) / -2);\n border-radius: 9999px;\n background: var(--mono-slider-mark-color, color-mix(in oklab, var(--_mono-slider-muted) 55%, transparent));\n}\n\n:where([mono-slider]) [mono-slider-mark][mono-active] {\n background: var(--mono-slider-mark-active-color, color-mix(in oklab, var(--primary-foreground) 85%, transparent));\n}\n\n:where([mono-slider]) [mono-slider-mark-label] {\n position: absolute;\n top: calc(var(--_mono-slider-box) / 2 + var(--mono-slider-mark-label-gap, calc(var(--mono-spacing) * 1.5)));\n left: 50%;\n translate: -50% 0;\n font-size: var(--mono-slider-mark-label-font-size, var(--mono-text-xs));\n line-height: var(--mono-slider-mark-label-line-height, 1rem);\n font-weight: var(--mono-slider-mark-label-font-weight, var(--mono-font-weight-normal));\n color: var(--mono-slider-mark-label-color, var(--_mono-slider-muted));\n white-space: nowrap;\n}\n\n/* =========================================\n EXTENSION — the value bubble on each thumb (shadcn's tooltip: bg-foreground text-background)\n ========================================= */\n\n:where([mono-slider]) [mono-slider-tooltip] {\n position: absolute;\n left: 50%;\n bottom: calc(100% + var(--mono-slider-tooltip-offset, calc(var(--mono-spacing) * 2)));\n translate: -50% 0;\n padding: calc(var(--mono-spacing) * 0.5) calc(var(--mono-spacing) * 2);\n border-radius: var(--mono-slider-tooltip-radius, var(--mono-radius-md));\n background: var(--mono-slider-tooltip-bg, var(--foreground));\n color: var(--mono-slider-tooltip-color, var(--background));\n font-family: var(--mono-slider-tooltip-font-family, inherit);\n font-size: var(--mono-slider-tooltip-font-size, var(--mono-text-xs));\n line-height: var(--mono-slider-tooltip-line-height, 1rem);\n font-weight: var(--mono-slider-tooltip-font-weight, var(--mono-font-weight-medium));\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n pointer-events: none;\n opacity: 0;\n visibility: hidden;\n transition: opacity var(--mono-duration) var(--mono-ease), visibility var(--mono-duration);\n\n /* the arrow */\n &::after {\n content: '';\n position: absolute;\n top: 100%;\n left: 50%;\n width: 0.5rem;\n height: 0.25rem;\n translate: -50% 0;\n background: inherit;\n clip-path: polygon(0 0, 100% 0, 50% 100%);\n }\n}\n\n/* `value-tooltip=\"always\"`: the bubbles are permanent, so the label row must not sit under them */\n[mono-slider][mono-value-tooltip=\"always\"]:not([mono-type=\"vertical\"]) [mono-slider-control] {\n margin-block-start: max(0px, calc(var(--mono-slider-tooltip-line-height, 1rem) + var(--mono-spacing) * 3 + var(--mono-slider-tooltip-offset, calc(var(--mono-spacing) * 2)) - (var(--_mono-slider-box) - var(--_mono-slider-across)) / 2));\n}\n\n/* `value-tooltip=\"auto\"`: on focus, while dragging, and on hover */\n:where([mono-slider]) [mono-slider-thumb]:is(:focus-visible, [mono-dragging]) > [mono-slider-tooltip],\n[mono-slider][mono-value-tooltip=\"always\"] [mono-slider-tooltip] {\n opacity: 1;\n visibility: visible;\n}\n@media (hover: hover) {\n [mono-slider]:not([mono-disabled]) [mono-slider-thumb]:hover > [mono-slider-tooltip] {\n opacity: 1;\n visibility: visible;\n }\n}\n\n/* =========================================\n EXTENSION — type=\"vertical\": the same parts with the axes swapped, min at the bottom\n ========================================= */\n\n[mono-slider][mono-type=\"vertical\"] {\n width: auto;\n}\n\n[mono-slider][mono-type=\"vertical\"] > [mono-slider-field] {\n flex-direction: column;\n align-items: flex-start;\n}\n\n[mono-slider][mono-type=\"vertical\"] [mono-slider-control] {\n flex: none;\n width: var(--_mono-slider-box);\n height: var(--_mono-slider-length, var(--mono-slider-length, 200px));\n}\n\n[mono-slider][mono-type=\"vertical\"][mono-marks-labelled] [mono-slider-control] {\n margin-block-end: 0;\n}\n\n[mono-slider][mono-type=\"vertical\"] [mono-slider-track] {\n inset-inline: auto;\n inset-block: 0;\n left: 50%;\n top: 0;\n width: var(--_mono-slider-track-h);\n height: auto;\n margin-top: 0;\n margin-left: calc(var(--_mono-slider-track-h) / -2);\n}\n\n[mono-slider][mono-type=\"vertical\"] [mono-slider-piece] {\n --_x0: calc(var(--_mono-slider-along) / 2 + (100% - var(--_mono-slider-along)) * var(--a));\n --_x1: calc(var(--_mono-slider-along) / 2 + (100% - var(--_mono-slider-along)) * var(--b));\n inset-block: auto;\n inset-inline: 0;\n bottom: calc(var(--_x0) + var(--_cs));\n inline-size: auto;\n block-size: max(0px, calc(var(--_x1) - var(--_x0) - var(--_cs) - var(--_ce)));\n}\n[mono-slider][mono-type=\"vertical\"] [mono-slider-piece]:not([mono-cut-start]) { --_x0: 0%; }\n[mono-slider][mono-type=\"vertical\"] [mono-slider-piece]:not([mono-cut-end]) { --_x1: 100%; }\n/* vertical joins: the piece's START is its bottom, its END its top */\n[mono-slider][mono-type=\"vertical\"]:not([mono-track-gap]) [mono-slider-piece][mono-cut-start] {\n border-radius: var(--_mono-slider-track-radius);\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n}\n[mono-slider][mono-type=\"vertical\"]:not([mono-track-gap]) [mono-slider-piece][mono-cut-end] {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n[mono-slider][mono-type=\"vertical\"]:not([mono-track-gap]) [mono-slider-piece][mono-cut-start][mono-cut-end] {\n border-radius: 0;\n}\n\n[mono-slider][mono-type=\"vertical\"] [mono-slider-thumb],\n[mono-slider][mono-type=\"vertical\"] [mono-slider-mark] {\n /* the logical reset goes FIRST: written after `left` it would reset it too */\n inset-inline-start: auto;\n top: auto;\n left: 50%;\n bottom: calc(var(--_mono-slider-along) / 2 + (100% - var(--_mono-slider-along)) * var(--p));\n margin: 0;\n}\n[mono-slider][mono-type=\"vertical\"] [mono-slider-thumb] {\n width: var(--_mono-slider-across);\n height: var(--_mono-slider-along);\n margin-left: calc(var(--_mono-slider-across) / -2);\n margin-bottom: calc(var(--_mono-slider-along) / -2);\n}\n[mono-slider][mono-type=\"vertical\"] [mono-slider-mark] {\n margin-left: calc(var(--_size) / -2);\n margin-bottom: calc(var(--_size) / -2);\n}\n[mono-slider][mono-type=\"vertical\"] [mono-slider-mark-label] {\n top: 50%;\n left: calc(var(--_mono-slider-box) / 2 + var(--mono-slider-mark-label-gap, calc(var(--mono-spacing) * 2)));\n translate: 0 -50%;\n}\n[mono-slider][mono-type=\"vertical\"] [mono-slider-tooltip] {\n left: auto;\n right: calc(100% + var(--mono-slider-tooltip-offset, calc(var(--mono-spacing) * 2)));\n bottom: 50%;\n translate: 0 50%;\n\n &::after {\n top: 50%;\n left: 100%;\n width: 0.25rem;\n height: 0.5rem;\n translate: 0 -50%;\n clip-path: polygon(0 0, 100% 50%, 0 100%);\n }\n}\n\n/* =========================================\n States\n ========================================= */\n\n/* in-data-[disabled=true]:opacity-50 */\n[mono-slider][mono-disabled] > :is([mono-label-row], [mono-slider-field]) {\n opacity: 0.5;\n}\n[mono-slider][mono-disabled] [mono-slider-control] {\n pointer-events: none;\n cursor: not-allowed;\n}\n\n[mono-slider][mono-readonly] [mono-slider-control] {\n cursor: default;\n}\n\n[mono-slider][mono-dragging] [mono-slider-control] {\n cursor: grabbing;\n}\n\n/* =========================================\n Message — helper / validation text (mono-input's)\n ========================================= */\n\n:where([mono-slider]) > [mono-message-wrap]:not(:has([mono-message]:not([mono-empty]))) {\n display: none;\n}\n\n:where([mono-slider]) [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 color: var(--_mono-slider-muted);\n}\n:where([mono-slider]) [mono-message=\"invalid\"] { color: var(--destructive); }\n:where([mono-slider]) [mono-message=\"valid\"] { color: var(--success); }\n:where([mono-slider]) [mono-message=\"warning\"] { color: var(--warning); }\n\n[mono-slider][mono-validation-state=\"invalid\"] [mono-label] {\n color: var(--destructive);\n}\n\n@media (prefers-reduced-motion: reduce) {\n :where([mono-slider]) :is([mono-slider-thumb], [mono-slider-tooltip]) {\n transition: none;\n }\n}\n";
|
|
1019
|
+
|
|
1020
|
+
//#endregion
|
|
1021
|
+
//#region src/components/slider/mono-slider.ts
|
|
1022
|
+
let MonoSlider = class MonoSlider extends MonoSliderCore(LitElement) {
|
|
1023
|
+
constructor(..._args) {
|
|
1024
|
+
super(..._args);
|
|
1025
|
+
this._slotLabel = [];
|
|
1026
|
+
this._slotHelper = [];
|
|
1027
|
+
}
|
|
1028
|
+
static {
|
|
1029
|
+
this.styles = [unsafeCSS(slider_css_raw_default)];
|
|
1030
|
+
}
|
|
1031
|
+
createRenderRoot() {
|
|
1032
|
+
return this;
|
|
1033
|
+
}
|
|
1034
|
+
/** Capture `slot="label|helper"` children. Safe to re-run: captured nodes lose `slot` and leave the host. */
|
|
1035
|
+
_captureSlots() {
|
|
1036
|
+
this._slotObserver?.disconnect();
|
|
1037
|
+
const captured = /* @__PURE__ */ new Set();
|
|
1038
|
+
for (const node of monoHostChildNodes(this)) {
|
|
1039
|
+
if (!(node instanceof Element)) continue;
|
|
1040
|
+
const name = node.getAttribute("slot");
|
|
1041
|
+
if (name === "label") this._slotLabel.push(node);
|
|
1042
|
+
else if (name === "helper") this._slotHelper.push(node);
|
|
1043
|
+
else continue;
|
|
1044
|
+
node.removeAttribute("slot");
|
|
1045
|
+
captured.add(node);
|
|
1046
|
+
}
|
|
1047
|
+
if (captured.size) {
|
|
1048
|
+
this._hasLabelSlotState = this._slotLabel.length > 0;
|
|
1049
|
+
this._hasHelperSlotState = this._slotHelper.length > 0;
|
|
1050
|
+
for (const node of captured) if (node.parentNode === this) this.removeChild(node);
|
|
1051
|
+
}
|
|
1052
|
+
if (this._slotObserver && this.isConnected) this._slotObserver.observe(this, { childList: true });
|
|
1053
|
+
}
|
|
1054
|
+
connectedCallback() {
|
|
1055
|
+
super.connectedCallback();
|
|
1056
|
+
if (!isServer && !this._slotObserver && typeof MutationObserver !== "undefined") this._slotObserver = new MutationObserver(() => this._captureSlots());
|
|
1057
|
+
this._captureSlots();
|
|
1058
|
+
if (this.isConnected) this.performUpdate();
|
|
1059
|
+
}
|
|
1060
|
+
disconnectedCallback() {
|
|
1061
|
+
this._slotObserver?.disconnect();
|
|
1062
|
+
super.disconnectedCallback();
|
|
1063
|
+
}
|
|
1064
|
+
updated(changed) {
|
|
1065
|
+
super.updated(changed);
|
|
1066
|
+
this._placeSlot("label", this._slotLabel);
|
|
1067
|
+
this._placeSlot("helper", this._slotHelper);
|
|
1068
|
+
}
|
|
1069
|
+
_placeSlot(name, nodes) {
|
|
1070
|
+
if (!nodes.length) return;
|
|
1071
|
+
const target = this.querySelector(`[data-mono-slot="${name}"]`);
|
|
1072
|
+
if (!target) return;
|
|
1073
|
+
for (const node of nodes) placeSlotNode(target, node);
|
|
1074
|
+
}
|
|
1075
|
+
};
|
|
1076
|
+
MonoSlider = __decorate([customElement("mono-slider")], MonoSlider);
|
|
1077
|
+
|
|
1078
|
+
//#endregion
|
|
1079
|
+
export { MonoSlider, coerceNumbers, fromRatio, markPoints, moveRun, moveThumb, nearestThumb, normalise, resolveScale, snap, stepFrom, thumbBounds, toPercent, trackPieces };
|