@sebgroup/green-core 3.26.3 → 3.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/avatar/avatar.component.d.ts +1 -1
- package/components/div/div.component.d.ts +1 -1
- package/components/icon/icon.component.d.ts +1 -1
- package/components/index.d.ts +1 -0
- package/components/index.js +1 -0
- package/components/input/input.styles.js +5 -0
- package/components/progress/index.d.ts +1 -0
- package/components/progress/index.js +1 -0
- package/components/progress/progress.component.d.ts +67 -0
- package/components/progress/progress.component.js +172 -0
- package/components/progress/progress.d.ts +2 -0
- package/components/progress/progress.js +6 -0
- package/components/progress/progress.styles.d.ts +2 -0
- package/components/progress/progress.styles.js +175 -0
- package/components/rich-text/rich-text.component.js +7 -3
- package/components/slider/slider.component.d.ts +16 -0
- package/components/slider/slider.component.js +119 -13
- package/components/slider/slider.styles.js +107 -45
- package/custom-elements.json +19567 -18559
- package/gds-element.js +1 -1
- package/generated/mcp/components.json +13 -1
- package/generated/mcp/icons.json +1 -1
- package/generated/mcp/index.json +1 -1
- package/generated/mcp/progress/angular.md +15 -0
- package/generated/mcp/progress/api.md +41 -0
- package/generated/mcp/progress/index.json +8 -0
- package/generated/mcp/progress/react.md +15 -0
- package/generated/mcp/slider/api.md +2 -0
- package/generated/mcp/tokens.json +1 -1
- package/generated/react/index.d.ts +11 -10
- package/generated/react/index.js +11 -10
- package/generated/react/progress/index.d.ts +701 -0
- package/generated/react/progress/index.js +14 -0
- package/generated/react/slider/index.d.ts +2 -0
- package/package.json +3 -1
- package/primitives/field-base/field-base.styles.js +10 -6
- package/pure.d.ts +1 -0
- package/pure.js +1 -0
- package/utils/decorators/aria-forwarding.d.ts +2 -1
- package/utils/decorators/aria-forwarding.js +5 -1
- package/utils/helpers/custom-element-scoping.js +1 -1
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
__privateMethod,
|
|
6
6
|
__privateSet
|
|
7
7
|
} from "../../chunks/chunk.H2T4A5YY.js";
|
|
8
|
-
var _internalStart, _internalEnd, _thumbRects, _lastPointerX, _Slider_instances, effectiveMin_fn, effectiveMax_fn, start_fn, end_fn, normalizeValues_fn, clamp_fn, percent_fn, ratio_fn, startPercent_fn, endPercent_fn, tickPosition_fn, renderTicks_fn, setQuietUpdate_fn, controlClasses_fn, thumbClasses_fn, bubbleClasses_fn, renderBubbles_fn, controlStyle_fn, syncFormValue_fn, labelledBy_fn, _handleStartInput, _handleStartChange, _handleEndInput, _handleEndChange, _handleStartPointerDown, _handleEndPointerDown, _clearActiveThumb, _handleThumbPointerMove, _updateHoveredThumb, _handleThumbPointerLeave, _handleStartFocus, _handleEndFocus, _handleStartBlur, _handleEndBlur, renderTextbox_fn, formatValue_fn, openTextbox_fn, handleTextboxDraftInput_fn, handleTextboxKeyDown_fn, commitTextbox_fn, closeTextbox_fn, isThumbVisible_fn;
|
|
8
|
+
var _internalStart, _internalEnd, _textboxesWidth, _textboxCount, _thumbRects, _lastPointerX, _stackObserver, _Slider_instances, updateStacked_fn, effectiveMin_fn, effectiveMax_fn, start_fn, end_fn, normalizeValues_fn, clamp_fn, percent_fn, ratio_fn, startPercent_fn, endPercent_fn, tickPosition_fn, renderTicks_fn, setQuietUpdate_fn, controlClasses_fn, thumbClasses_fn, bubbleClasses_fn, renderBubbles_fn, renderBoundLabels_fn, controlStyle_fn, syncFormValue_fn, labelledBy_fn, _handleStartInput, _handleStartChange, _handleEndInput, _handleEndChange, _handleStartPointerDown, _handleEndPointerDown, _clearActiveThumb, _handleThumbPointerMove, _updateHoveredThumb, _handleThumbPointerLeave, _handleStartFocus, _handleEndFocus, _handleStartBlur, _handleEndBlur, renderTextbox_fn, _stopTextboxChange, textboxLabel_fn, formatValue_fn, openTextbox_fn, handleTextboxDraftInput_fn, handleTextboxKeyDown_fn, commitTextbox_fn, closeTextbox_fn, isThumbVisible_fn;
|
|
9
9
|
import { localized, msg } from "@lit/localize";
|
|
10
10
|
import { property, query, state } from "lit/decorators.js";
|
|
11
11
|
import { classMap } from "lit/directives/class-map.js";
|
|
@@ -22,7 +22,9 @@ import {
|
|
|
22
22
|
withSizeXProps
|
|
23
23
|
} from "../../utils/mixins/declarative-layout-mixins.js";
|
|
24
24
|
import { GdsFormControlElement } from "../form/form-control.js";
|
|
25
|
+
import { GdsInput } from "../input/input.component.js";
|
|
25
26
|
import SliderStyles from "./slider.styles.js";
|
|
27
|
+
const SLIDER_MIN_TRACK_WIDTH = 200;
|
|
26
28
|
const sliderValueConverter = {
|
|
27
29
|
fromAttribute(value) {
|
|
28
30
|
const [start, end] = value.split(",").map((part) => {
|
|
@@ -52,6 +54,8 @@ let Slider = class extends GdsFormControlElement {
|
|
|
52
54
|
__privateAdd(this, _internalStart);
|
|
53
55
|
__privateAdd(this, _internalEnd);
|
|
54
56
|
this.hideTextbox = false;
|
|
57
|
+
this.minLabel = "";
|
|
58
|
+
this.maxLabel = "";
|
|
55
59
|
this.readonly = false;
|
|
56
60
|
this._activeThumb = null;
|
|
57
61
|
this._focusedThumb = null;
|
|
@@ -64,9 +68,16 @@ let Slider = class extends GdsFormControlElement {
|
|
|
64
68
|
this._draftMinInvalid = false;
|
|
65
69
|
this._draftMaxInvalid = false;
|
|
66
70
|
this._quietUpdate = false;
|
|
71
|
+
this._stacked = false;
|
|
72
|
+
this._textboxesStacked = false;
|
|
73
|
+
__privateAdd(this, _textboxesWidth, 0);
|
|
74
|
+
__privateAdd(this, _textboxCount, 0);
|
|
67
75
|
__privateAdd(this, _thumbRects, {});
|
|
68
76
|
// Last known pointer X per thumb, used to re-check hover once a click-to-jump updates the thumb position.
|
|
69
77
|
__privateAdd(this, _lastPointerX, {});
|
|
78
|
+
// Undebounced: ResizeObserver callbacks run after layout but before paint, and Lit's
|
|
79
|
+
// update is a microtask, so the class lands in the same frame and nothing shifts.
|
|
80
|
+
__privateAdd(this, _stackObserver, new ResizeObserver(() => __privateMethod(this, _Slider_instances, updateStacked_fn).call(this)));
|
|
70
81
|
// The native "input" event is composed and already bubbles out of the shadow root, so it
|
|
71
82
|
// doesn't need to be re-dispatched here (unlike "change", which is not composed).
|
|
72
83
|
__privateAdd(this, _handleStartInput, (e) => {
|
|
@@ -177,6 +188,11 @@ let Slider = class extends GdsFormControlElement {
|
|
|
177
188
|
if (this._focusedThumb === "end") this._focusedThumb = null;
|
|
178
189
|
if (this._focusVisibleThumb === "end") this._focusVisibleThumb = null;
|
|
179
190
|
});
|
|
191
|
+
// The inner gds-input re-dispatches a composed "change", which would otherwise escape the
|
|
192
|
+
// slider and be mistaken for the slider's own change event.
|
|
193
|
+
__privateAdd(this, _stopTextboxChange, (event) => {
|
|
194
|
+
event.stopPropagation();
|
|
195
|
+
});
|
|
180
196
|
__privateSet(this, _internalStart, __privateMethod(this, _Slider_instances, effectiveMin_fn).call(this));
|
|
181
197
|
__privateSet(this, _internalEnd, __privateMethod(this, _Slider_instances, effectiveMax_fn).call(this));
|
|
182
198
|
}
|
|
@@ -204,14 +220,27 @@ let Slider = class extends GdsFormControlElement {
|
|
|
204
220
|
super.connectedCallback();
|
|
205
221
|
__privateMethod(this, _Slider_instances, normalizeValues_fn).call(this);
|
|
206
222
|
window.addEventListener("pointerup", __privateGet(this, _clearActiveThumb));
|
|
223
|
+
__privateGet(this, _stackObserver).observe(this);
|
|
207
224
|
}
|
|
208
225
|
disconnectedCallback() {
|
|
209
226
|
super.disconnectedCallback();
|
|
210
227
|
window.removeEventListener("pointerup", __privateGet(this, _clearActiveThumb));
|
|
228
|
+
__privateGet(this, _stackObserver).disconnect();
|
|
211
229
|
}
|
|
212
230
|
focus(options) {
|
|
213
231
|
this._getValidityAnchor()?.focus(options);
|
|
214
232
|
}
|
|
233
|
+
firstUpdated(changed) {
|
|
234
|
+
super.firstUpdated(changed);
|
|
235
|
+
__privateMethod(this, _Slider_instances, updateStacked_fn).call(this);
|
|
236
|
+
}
|
|
237
|
+
// Toggling either of these changes the row's contents without necessarily resizing the
|
|
238
|
+
// host, so the resize observer alone can't be relied on to recalculate.
|
|
239
|
+
updated(changed) {
|
|
240
|
+
super.updated(changed);
|
|
241
|
+
if (changed.has("range") || changed.has("hideTextbox"))
|
|
242
|
+
__privateMethod(this, _Slider_instances, updateStacked_fn).call(this);
|
|
243
|
+
}
|
|
215
244
|
render() {
|
|
216
245
|
const style = __privateMethod(this, _Slider_instances, controlStyle_fn).call(this);
|
|
217
246
|
const effectiveMin = __privateMethod(this, _Slider_instances, effectiveMin_fn).call(this);
|
|
@@ -246,7 +275,13 @@ let Slider = class extends GdsFormControlElement {
|
|
|
246
275
|
>`
|
|
247
276
|
)}
|
|
248
277
|
|
|
249
|
-
<div
|
|
278
|
+
<div
|
|
279
|
+
id="control-row"
|
|
280
|
+
class=${classMap({
|
|
281
|
+
stacked: this._stacked,
|
|
282
|
+
"textboxes-stacked": this._textboxesStacked
|
|
283
|
+
})}
|
|
284
|
+
>
|
|
250
285
|
${when(
|
|
251
286
|
this.range && !this.hideTextbox,
|
|
252
287
|
() => __privateMethod(this, _Slider_instances, renderTextbox_fn).call(this, "min")
|
|
@@ -313,7 +348,7 @@ let Slider = class extends GdsFormControlElement {
|
|
|
313
348
|
@change=${__privateGet(this, _handleEndChange)}
|
|
314
349
|
/>`
|
|
315
350
|
)}
|
|
316
|
-
${__privateMethod(this, _Slider_instances, renderBubbles_fn).call(this)}
|
|
351
|
+
${__privateMethod(this, _Slider_instances, renderBubbles_fn).call(this)} ${__privateMethod(this, _Slider_instances, renderBoundLabels_fn).call(this)}
|
|
317
352
|
</div>
|
|
318
353
|
|
|
319
354
|
${when(!this.hideTextbox, () => __privateMethod(this, _Slider_instances, renderTextbox_fn).call(this, "max"))}
|
|
@@ -344,9 +379,38 @@ let Slider = class extends GdsFormControlElement {
|
|
|
344
379
|
};
|
|
345
380
|
_internalStart = new WeakMap();
|
|
346
381
|
_internalEnd = new WeakMap();
|
|
382
|
+
_textboxesWidth = new WeakMap();
|
|
383
|
+
_textboxCount = new WeakMap();
|
|
347
384
|
_thumbRects = new WeakMap();
|
|
348
385
|
_lastPointerX = new WeakMap();
|
|
386
|
+
_stackObserver = new WeakMap();
|
|
349
387
|
_Slider_instances = new WeakSet();
|
|
388
|
+
updateStacked_fn = function() {
|
|
389
|
+
const row = this._controlRow;
|
|
390
|
+
if (!row) return;
|
|
391
|
+
const textboxes = Array.from(row.querySelectorAll(".textbox"));
|
|
392
|
+
if (textboxes.length === 0) {
|
|
393
|
+
__privateSet(this, _textboxCount, 0);
|
|
394
|
+
this._stacked = false;
|
|
395
|
+
this._textboxesStacked = false;
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
if (textboxes.length !== __privateGet(this, _textboxCount)) {
|
|
399
|
+
__privateSet(this, _textboxCount, textboxes.length);
|
|
400
|
+
if (this._textboxesStacked) {
|
|
401
|
+
this._textboxesStacked = false;
|
|
402
|
+
this.updateComplete.then(() => __privateMethod(this, _Slider_instances, updateStacked_fn).call(this));
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
const gap = parseFloat(getComputedStyle(row).columnGap) || 0;
|
|
407
|
+
if (!this._textboxesStacked) {
|
|
408
|
+
__privateSet(this, _textboxesWidth, textboxes.reduce((total, textbox) => total + textbox.offsetWidth, 0) + gap * (textboxes.length - 1));
|
|
409
|
+
}
|
|
410
|
+
const available = row.clientWidth;
|
|
411
|
+
this._stacked = available - __privateGet(this, _textboxesWidth) - gap < SLIDER_MIN_TRACK_WIDTH;
|
|
412
|
+
this._textboxesStacked = __privateGet(this, _textboxesWidth) > available;
|
|
413
|
+
};
|
|
350
414
|
effectiveMin_fn = function() {
|
|
351
415
|
return Math.min(this.min, this.max);
|
|
352
416
|
};
|
|
@@ -479,6 +543,19 @@ renderBubbles_fn = function() {
|
|
|
479
543
|
)}
|
|
480
544
|
`;
|
|
481
545
|
};
|
|
546
|
+
// The labels sit inside the control and are taken out of flow, so they always span the track
|
|
547
|
+
// itself regardless of the textboxes, and never shift the control vertically.
|
|
548
|
+
renderBoundLabels_fn = function() {
|
|
549
|
+
if (!this.minLabel && !this.maxLabel) return html``;
|
|
550
|
+
return html`<div id="bound-labels">
|
|
551
|
+
<span class="bound-label min-label" aria-hidden="true"
|
|
552
|
+
>${this.minLabel}</span
|
|
553
|
+
>
|
|
554
|
+
<span class="bound-label max-label" aria-hidden="true"
|
|
555
|
+
>${this.maxLabel}</span
|
|
556
|
+
>
|
|
557
|
+
</div>`;
|
|
558
|
+
};
|
|
482
559
|
controlStyle_fn = function() {
|
|
483
560
|
const thumbAwarePos = (ratio) => `calc((100% - var(--_thumb-size)) * ${ratio} + (var(--_thumb-size) / 2))`;
|
|
484
561
|
const clampedStart = __privateMethod(this, _Slider_instances, clamp_fn).call(this, __privateMethod(this, _Slider_instances, start_fn).call(this));
|
|
@@ -531,22 +608,36 @@ renderTextbox_fn = function(bound) {
|
|
|
531
608
|
const draft = bound === "min" ? this._draftMin : this._draftMax;
|
|
532
609
|
const isDraftInvalid = bound === "min" ? this._draftMinInvalid : this._draftMaxInvalid;
|
|
533
610
|
const displayValue = isEditing ? draft : __privateMethod(this, _Slider_instances, formatValue_fn).call(this, currentValue);
|
|
534
|
-
return html`<input
|
|
535
|
-
class="textbox
|
|
611
|
+
return html`<gds-input
|
|
612
|
+
class="textbox"
|
|
536
613
|
id="${bound}-textbox"
|
|
537
614
|
type="number"
|
|
615
|
+
plain
|
|
616
|
+
.size=${this.size}
|
|
617
|
+
.label=${__privateMethod(this, _Slider_instances, textboxLabel_fn).call(this, bound)}
|
|
618
|
+
gds-aria-labelledby=${__privateMethod(this, _Slider_instances, labelledBy_fn).call(this, bound === "min" ? "start" : "end")}
|
|
538
619
|
.value=${displayValue}
|
|
539
|
-
.step=${
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
620
|
+
.step=${this.step}
|
|
621
|
+
.disabled=${this.disabled}
|
|
622
|
+
.readonly=${this.readonly}
|
|
623
|
+
.invalid=${isDraftInvalid}
|
|
624
|
+
style="--_textbox-chars: ${Math.min(
|
|
625
|
+
Math.max(displayValue.length, 3),
|
|
626
|
+
12
|
|
627
|
+
)}"
|
|
545
628
|
@focus=${() => __privateMethod(this, _Slider_instances, openTextbox_fn).call(this, bound)}
|
|
546
629
|
@input=${(event) => __privateMethod(this, _Slider_instances, handleTextboxDraftInput_fn).call(this, bound, event)}
|
|
630
|
+
@change=${__privateGet(this, _stopTextboxChange)}
|
|
547
631
|
@blur=${() => __privateMethod(this, _Slider_instances, commitTextbox_fn).call(this, bound)}
|
|
548
632
|
@keydown=${(event) => __privateMethod(this, _Slider_instances, handleTextboxKeyDown_fn).call(this, bound, event)}
|
|
549
|
-
|
|
633
|
+
></gds-input>`;
|
|
634
|
+
};
|
|
635
|
+
_stopTextboxChange = new WeakMap();
|
|
636
|
+
// Mirrors the gds-aria-labelledby wiring as a plain string, since cross-root element
|
|
637
|
+
// references reflect to an empty content attribute that name computation tools can't read.
|
|
638
|
+
textboxLabel_fn = function(bound) {
|
|
639
|
+
if (!this.range) return this.label;
|
|
640
|
+
return bound === "min" ? `${this.label} ${msg("Start value")}` : `${this.label} ${msg("End value")}`;
|
|
550
641
|
};
|
|
551
642
|
/** Displays values with the same number of decimals as `step`, so the readout doesn't change width. */
|
|
552
643
|
formatValue_fn = function(value) {
|
|
@@ -686,6 +777,12 @@ __decorateClass([
|
|
|
686
777
|
__decorateClass([
|
|
687
778
|
property({ type: Boolean, attribute: "hide-textbox" })
|
|
688
779
|
], Slider.prototype, "hideTextbox", 2);
|
|
780
|
+
__decorateClass([
|
|
781
|
+
property({ attribute: "min-label" })
|
|
782
|
+
], Slider.prototype, "minLabel", 2);
|
|
783
|
+
__decorateClass([
|
|
784
|
+
property({ attribute: "max-label" })
|
|
785
|
+
], Slider.prototype, "maxLabel", 2);
|
|
689
786
|
__decorateClass([
|
|
690
787
|
property({ type: Boolean, reflect: true })
|
|
691
788
|
], Slider.prototype, "readonly", 2);
|
|
@@ -695,6 +792,9 @@ __decorateClass([
|
|
|
695
792
|
__decorateClass([
|
|
696
793
|
query("#slider-end")
|
|
697
794
|
], Slider.prototype, "_endInput", 2);
|
|
795
|
+
__decorateClass([
|
|
796
|
+
query("#control-row")
|
|
797
|
+
], Slider.prototype, "_controlRow", 2);
|
|
698
798
|
__decorateClass([
|
|
699
799
|
state()
|
|
700
800
|
], Slider.prototype, "_activeThumb", 2);
|
|
@@ -728,6 +828,12 @@ __decorateClass([
|
|
|
728
828
|
__decorateClass([
|
|
729
829
|
state()
|
|
730
830
|
], Slider.prototype, "_quietUpdate", 2);
|
|
831
|
+
__decorateClass([
|
|
832
|
+
state()
|
|
833
|
+
], Slider.prototype, "_stacked", 2);
|
|
834
|
+
__decorateClass([
|
|
835
|
+
state()
|
|
836
|
+
], Slider.prototype, "_textboxesStacked", 2);
|
|
731
837
|
__decorateClass([
|
|
732
838
|
watch("min"),
|
|
733
839
|
watch("max"),
|
|
@@ -743,7 +849,7 @@ let GdsSlider = class extends withSizeXProps(
|
|
|
743
849
|
};
|
|
744
850
|
GdsSlider = __decorateClass([
|
|
745
851
|
gdsCustomElement("gds-slider", {
|
|
746
|
-
dependsOn: [GdsFormControlHeader, GdsFormControlFooter]
|
|
852
|
+
dependsOn: [GdsFormControlHeader, GdsFormControlFooter, GdsInput]
|
|
747
853
|
})
|
|
748
854
|
], GdsSlider);
|
|
749
855
|
export {
|
|
@@ -8,9 +8,15 @@ const styles = css`
|
|
|
8
8
|
--_track-height: var(--gds-sys-space-3xs);
|
|
9
9
|
--_thumb-color: var(--gds-sys-color-l3-neutral-03);
|
|
10
10
|
--_thumb-ring-color: var(--gds-sys-color-border-neutral-02);
|
|
11
|
-
--_textbox-
|
|
12
|
-
--_textbox-
|
|
13
|
-
|
|
11
|
+
--_textbox-chrome: var(--gds-sys-space-2xl);
|
|
12
|
+
--_textbox-lock-space: calc(
|
|
13
|
+
var(--gds-sys-space-l) + var(--gds-sys-space-xs)
|
|
14
|
+
);
|
|
15
|
+
--_textbox-padding-inline: var(--gds-sys-space-s);
|
|
16
|
+
--_textbox-font: var(--gds-sys-text-detail-m-regular);
|
|
17
|
+
--_bound-label-font: var(--gds-sys-text-detail-s-regular);
|
|
18
|
+
--_bound-label-line-height: var(--gds-sys-space-l);
|
|
19
|
+
--_bound-label-gap: var(--gds-sys-space-5xs);
|
|
14
20
|
--_bubble-font: var(--gds-sys-text-detail-s-regular);
|
|
15
21
|
--_bubble-padding-x: var(--gds-sys-space-xs);
|
|
16
22
|
--_bubble-bg: var(--gds-sys-color-l3-neutral-03);
|
|
@@ -34,9 +40,14 @@ const styles = css`
|
|
|
34
40
|
:host([size='small']) {
|
|
35
41
|
--_thumb-size: var(--gds-sys-space-s);
|
|
36
42
|
--_track-height: var(--gds-sys-space-3xs);
|
|
37
|
-
--_textbox-
|
|
38
|
-
--_textbox-
|
|
39
|
-
|
|
43
|
+
--_textbox-chrome: var(--gds-sys-space-l);
|
|
44
|
+
--_textbox-lock-space: calc(
|
|
45
|
+
var(--gds-sys-space-m) + var(--gds-sys-space-3xs)
|
|
46
|
+
);
|
|
47
|
+
--_textbox-padding-inline: var(--gds-sys-space-xs);
|
|
48
|
+
--_textbox-font: var(--gds-sys-text-detail-s-regular);
|
|
49
|
+
--_bound-label-font: var(--gds-sys-text-detail-xs-regular);
|
|
50
|
+
--_bound-label-line-height: var(--gds-sys-space-m);
|
|
40
51
|
--_bubble-font: var(--gds-sys-text-detail-xs-regular);
|
|
41
52
|
--_bubble-gap-pressed: var(--gds-sys-space-4xs);
|
|
42
53
|
--_bubble-padding-x: var(--gds-sys-space-2xs);
|
|
@@ -60,68 +71,119 @@ const styles = css`
|
|
|
60
71
|
width: 1px;
|
|
61
72
|
}
|
|
62
73
|
|
|
74
|
+
#control-row {
|
|
75
|
+
align-items: center;
|
|
76
|
+
display: flex;
|
|
77
|
+
flex-wrap: wrap;
|
|
78
|
+
gap: var(--_row-gap);
|
|
79
|
+
}
|
|
80
|
+
|
|
63
81
|
#control {
|
|
64
82
|
align-items: center;
|
|
65
83
|
display: grid;
|
|
66
|
-
flex: 1;
|
|
84
|
+
flex: 1 1 auto;
|
|
85
|
+
min-inline-size: 0;
|
|
86
|
+
order: 1;
|
|
67
87
|
height: var(--_thumb-size);
|
|
68
88
|
min-height: var(--_thumb-size);
|
|
69
89
|
overflow: visible;
|
|
70
90
|
position: relative;
|
|
71
91
|
}
|
|
72
92
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
display: flex;
|
|
76
|
-
gap: var(--_row-gap);
|
|
93
|
+
.textbox {
|
|
94
|
+
flex: 0 0 auto;
|
|
77
95
|
}
|
|
78
96
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
appearance: textfield;
|
|
82
|
-
background: var(--gds-sys-color-l3-neutral-02);
|
|
83
|
-
border-width: var(--gds-sys-space-5xs);
|
|
84
|
-
border-style: solid;
|
|
85
|
-
border-color: var(--gds-sys-color-border-neutral-01);
|
|
86
|
-
border-radius: var(--gds-sys-radius-max);
|
|
87
|
-
box-sizing: content-box;
|
|
88
|
-
color: var(--gds-sys-color-content-neutral-01);
|
|
89
|
-
font: var(--_textbox-font);
|
|
90
|
-
min-height: calc(var(--_textbox-height) - 2 * var(--gds-sys-space-5xs));
|
|
91
|
-
min-width: 3ch;
|
|
92
|
-
max-width: 12ch;
|
|
93
|
-
width: 3ch;
|
|
94
|
-
outline: 2px solid transparent;
|
|
95
|
-
outline-offset: 0px;
|
|
96
|
-
padding: 0 var(--_textbox-padding);
|
|
97
|
-
text-align: center;
|
|
98
|
-
transition-property: outline-color, outline-offset;
|
|
99
|
-
transition-duration: var(--_t-duration), var(--_t-duration);
|
|
100
|
-
transition-timing-function: var(--_t-easing-out);
|
|
97
|
+
#min-textbox {
|
|
98
|
+
order: 0;
|
|
101
99
|
}
|
|
102
100
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
-webkit-appearance: none;
|
|
106
|
-
margin: 0;
|
|
101
|
+
#max-textbox {
|
|
102
|
+
order: 2;
|
|
107
103
|
}
|
|
108
104
|
|
|
109
|
-
.
|
|
110
|
-
|
|
111
|
-
|
|
105
|
+
/* Set by the resize observer once too little is left for the track on the row. */
|
|
106
|
+
#control-row.stacked #control {
|
|
107
|
+
order: -1;
|
|
108
|
+
flex-basis: 100%;
|
|
112
109
|
}
|
|
113
110
|
|
|
114
|
-
.textbox
|
|
115
|
-
|
|
111
|
+
#control-row.stacked #max-textbox {
|
|
112
|
+
margin-inline-start: auto;
|
|
116
113
|
}
|
|
117
114
|
|
|
118
|
-
:
|
|
119
|
-
|
|
120
|
-
|
|
115
|
+
/* Second stage: the two textboxes no longer fit on one row either. */
|
|
116
|
+
#control-row.textboxes-stacked .textbox {
|
|
117
|
+
flex-basis: 100%;
|
|
118
|
+
inline-size: 100%;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
#control-row.textboxes-stacked #max-textbox {
|
|
122
|
+
margin-inline-start: 0;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* Reserves room for the out-of-flow bound labels without moving the control itself,
|
|
126
|
+
since flex centering ignores the padding box. */
|
|
127
|
+
#control-row:has(#bound-labels) {
|
|
128
|
+
padding-block-end: calc(
|
|
129
|
+
var(--_bound-label-gap) + var(--_bound-label-line-height)
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* Stacked, the labels sit between the two rows, so the track carries the reservation. */
|
|
134
|
+
#control-row.stacked:has(#bound-labels) {
|
|
135
|
+
padding-block-end: 0;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
#control-row.stacked #control:has(#bound-labels) {
|
|
139
|
+
margin-block-end: calc(
|
|
140
|
+
var(--_bound-label-gap) + var(--_bound-label-line-height)
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
#bound-labels {
|
|
145
|
+
display: flex;
|
|
146
|
+
gap: var(--gds-sys-space-xs);
|
|
147
|
+
inset-block-start: calc(100% + var(--_bound-label-gap));
|
|
148
|
+
inset-inline: 0;
|
|
149
|
+
justify-content: space-between;
|
|
150
|
+
position: absolute;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.bound-label {
|
|
154
|
+
color: var(--gds-sys-color-content-neutral-02);
|
|
155
|
+
font: var(--_bound-label-font);
|
|
156
|
+
line-height: var(--_bound-label-line-height);
|
|
157
|
+
white-space: nowrap;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.max-label {
|
|
161
|
+
margin-inline-start: auto;
|
|
162
|
+
text-align: end;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.textbox {
|
|
166
|
+
--_appearance-spin-button: none;
|
|
167
|
+
--_gds-input-radius: var(--gds-sys-radius-max);
|
|
168
|
+
--_gds-input-text-align: center;
|
|
169
|
+
--_gds-input-padding-inline: var(--_textbox-padding-inline);
|
|
170
|
+
--_gds-input-block-size: var(--gds-sys-space-2xl);
|
|
171
|
+
|
|
172
|
+
/* Matches the native input's font so the ch-based width measures the right glyphs. */
|
|
173
|
+
font: var(--_textbox-font);
|
|
174
|
+
inline-size: calc(
|
|
175
|
+
var(--_textbox-chars, 3) * 1ch + var(--_textbox-chrome) +
|
|
176
|
+
var(--_textbox-extras, 0px)
|
|
177
|
+
);
|
|
121
178
|
}
|
|
122
179
|
|
|
123
180
|
:host([readonly]) .textbox {
|
|
181
|
+
--_textbox-extras: var(--_textbox-lock-space);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
:host([readonly]) .native-control {
|
|
124
185
|
cursor: default;
|
|
186
|
+
pointer-events: none;
|
|
125
187
|
}
|
|
126
188
|
|
|
127
189
|
#track-before,
|