@wildmason/aegis 2.2.0 → 2.3.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/CHANGELOG.md
CHANGED
|
@@ -18,6 +18,74 @@ that 404s.
|
|
|
18
18
|
|
|
19
19
|
## [Unreleased]
|
|
20
20
|
|
|
21
|
+
## [2.3.0] - 2026-10-07
|
|
22
|
+
|
|
23
|
+
Minor: `WmSelect` gains a compact chip trigger, a suffix, option descriptions,
|
|
24
|
+
a danger tone and panel sizing. Every addition is opt-in. A select that sets
|
|
25
|
+
none of them renders the same trigger and option markup as 2.2.1, so a
|
|
26
|
+
consumer that styles `.wm-select-trigger`, `.wm-select-value` or
|
|
27
|
+
`.wm-select-option-label` sees no change. One behaviour changes for every
|
|
28
|
+
select: the panel takes the trigger's width when it opens, not on every check
|
|
29
|
+
(see Fixed).
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- `WmSelect` `appearance`: `'field'` (the default, as before) or `'chip'`, a
|
|
34
|
+
filled trigger with no border, as wide as its words, for a row of choices
|
|
35
|
+
with no label beside each one. The host takes `.wm-select--chip`.
|
|
36
|
+
- `WmSelect` `suffix`: a muted word after the chosen label, in the trigger
|
|
37
|
+
only, so `suffix="model"` reads "Opus model". It is left out while the
|
|
38
|
+
placeholder shows, so an empty chip never reads "Model model". On a chip the
|
|
39
|
+
suffix turns secondary while the trigger is hovered or open: muted text falls
|
|
40
|
+
under 3:1 on `--wm-bg-hover` in the `wildmason` theme.
|
|
41
|
+
- `SelectOption.description`: a second line under the label, in the panel
|
|
42
|
+
only. The option is named by its label (`aria-labelledby`) and described by
|
|
43
|
+
the line (`aria-describedby`); the ids are unique per select instance. The
|
|
44
|
+
line is secondary text, not muted: muted measures 3.2:1 on `--wm-bg-float`
|
|
45
|
+
in the `wildmason` theme, under the 4.5:1 a 12px line needs.
|
|
46
|
+
- `WmSelect` `tone`: `'neutral'` (the default) or `'danger'`, for a choice that
|
|
47
|
+
is risky to keep. It uses the guarded status recipe: `--wm-color-danger-readable`
|
|
48
|
+
on `--wm-color-danger-bg`, inside `--wm-color-danger-border`. The host takes
|
|
49
|
+
`.wm-select--danger`.
|
|
50
|
+
- `WmSelect` `panelWidth`: `'trigger'`, `'content'` (from the trigger's width
|
|
51
|
+
up to 24rem, where a description wraps) or a width in pixels. Unset, a field
|
|
52
|
+
keeps the trigger's width and a chip fits its content.
|
|
53
|
+
- Types `WmSelectAppearance`, `WmSelectTone` and `WmSelectPanelWidth`.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- `WmSelect` measures its trigger once, as the panel opens. It read
|
|
58
|
+
`offsetWidth` on every change-detection pass, so a trigger whose width moved
|
|
59
|
+
between Angular's update pass and its no-changes pass threw NG0100 in
|
|
60
|
+
development. A chip does that while its text renders.
|
|
61
|
+
- The docs app rendered the select page and the composition page from an old
|
|
62
|
+
copy of the component (`ui/src/app/components/select`), without the
|
|
63
|
+
scroll anchoring or the readable accent. Both pages now import the package
|
|
64
|
+
source, and the copy is deleted.
|
|
65
|
+
|
|
66
|
+
## [2.2.1] - 2026-10-07
|
|
67
|
+
|
|
68
|
+
Patch: one fix and one theme colour. Nothing is added, renamed or removed.
|
|
69
|
+
|
|
70
|
+
### Fixed
|
|
71
|
+
|
|
72
|
+
- `WmSlider`: the thumb sits on the value after the value and the range change
|
|
73
|
+
in one render. The native input bound its `value` before its `min`, `max`
|
|
74
|
+
and `step`, and the browser sanitizes a written value against the bounds the
|
|
75
|
+
input holds at that moment. A value that rose with `max` was clamped to the
|
|
76
|
+
old `max`, and the binding was not written again because the value did not
|
|
77
|
+
change. The thumb and the input's own value, which a screen reader reads as
|
|
78
|
+
the current value, sat a stop short, while the fill, the readout and
|
|
79
|
+
`aria-valuetext` named the new value. Scaffold hit it when an effort scale
|
|
80
|
+
gained a stop: the readout said "ultra" and the thumb sat on "max". The
|
|
81
|
+
bounds and the step are now bound first.
|
|
82
|
+
|
|
83
|
+
### Changed
|
|
84
|
+
|
|
85
|
+
- `wildmason` theme: `--wm-text-muted` is `#949d94`, down from `#c0cac0`. The
|
|
86
|
+
old value was within 2/255 of `--wm-text-secondary` (`#c2ccc2`), so muted text
|
|
87
|
+
such as a timestamp read as body text. Every muted label on this theme dims.
|
|
88
|
+
|
|
21
89
|
## [2.2.0] - 2026-10-02
|
|
22
90
|
|
|
23
91
|
Minor: new components, variants and inputs, and accessibility fixes. Nothing is
|
|
@@ -760,7 +828,8 @@ a `^1.x` range does not pick this release up by accident.
|
|
|
760
828
|
Releases before 1.8.0 are in `git log`. See also `wiki/products/Aegis - Health.md`
|
|
761
829
|
for the decisions behind these changes, including the ones decided against.
|
|
762
830
|
|
|
763
|
-
[Unreleased]: https://github.com/wildmason/aegis/compare/v2.2.
|
|
831
|
+
[Unreleased]: https://github.com/wildmason/aegis/compare/v2.2.1...HEAD
|
|
832
|
+
[2.2.1]: https://github.com/wildmason/aegis/releases/tag/v2.2.1
|
|
764
833
|
[2.2.0]: https://github.com/wildmason/aegis/releases/tag/v2.2.0
|
|
765
834
|
[2.1.0]: https://github.com/wildmason/aegis/releases/tag/v2.1.0
|
|
766
835
|
[2.0.0]: https://github.com/wildmason/aegis/releases/tag/v2.0.0
|
|
@@ -244,6 +244,9 @@ class WmAnchoredScrollStrategy {
|
|
|
244
244
|
* itself, including closing when its trigger is scrolled out of view.
|
|
245
245
|
*/
|
|
246
246
|
|
|
247
|
+
/** The widest a content-sized panel grows before its descriptions wrap. */
|
|
248
|
+
const CONTENT_MAX_WIDTH = '24rem';
|
|
249
|
+
let nextId$2 = 0;
|
|
247
250
|
/**
|
|
248
251
|
* WmSelect — Accessible dropdown select built on Angular CDK Overlay.
|
|
249
252
|
*
|
|
@@ -261,20 +264,26 @@ class WmAnchoredScrollStrategy {
|
|
|
261
264
|
* - Yes/No choices → use a Toggle or two radio buttons
|
|
262
265
|
*
|
|
263
266
|
* Options API:
|
|
264
|
-
* options: SelectOption[] — Array of { value, label, disabled? } objects.
|
|
267
|
+
* options: SelectOption[] — Array of { value, label, disabled?, description? } objects.
|
|
265
268
|
*
|
|
266
269
|
* Two-way binding:
|
|
267
270
|
* <wm-select [(value)]="selectedValue" [options]="myOptions" />
|
|
268
271
|
*
|
|
272
|
+
* A compact choice in a row of others, which reads "Opus model":
|
|
273
|
+
* <wm-select appearance="chip" suffix="model" aria-label="Model" [options]="models" [(value)]="model" />
|
|
274
|
+
*
|
|
269
275
|
* Accessibility:
|
|
270
276
|
* - Trigger has role="combobox", aria-expanded, aria-haspopup="listbox"
|
|
271
277
|
* - Panel has role="listbox"; each option has role="option" + aria-selected
|
|
272
278
|
* - Disabled options have aria-disabled="true"
|
|
279
|
+
* - An option with a description is named by its label (aria-labelledby) and
|
|
280
|
+
* described by the second line (aria-describedby)
|
|
273
281
|
* - Focus is trapped inside the open panel (cdkTrapFocus)
|
|
274
282
|
* - Clicking the backdrop closes the panel and returns focus to the trigger
|
|
275
283
|
* - Keyboard: Enter/Space on trigger opens; Escape closes; arrow keys
|
|
276
284
|
* navigate options (relies on natural tab order within the panel)
|
|
277
|
-
* - Always pair with a visible label via <wm-label> or aria-label on the host
|
|
285
|
+
* - Always pair with a visible label via <wm-label> or aria-label on the host.
|
|
286
|
+
* A chip has no visible label of its own, so it always needs the aria-label
|
|
278
287
|
*/
|
|
279
288
|
class WmSelect {
|
|
280
289
|
/**
|
|
@@ -287,6 +296,8 @@ class WmSelect {
|
|
|
287
296
|
* keeps the coordinates it was born with while the trigger scrolls away.
|
|
288
297
|
*/
|
|
289
298
|
scrollStrategy = new WmAnchoredScrollStrategy();
|
|
299
|
+
/** Prefix for the ids that tie an option to its label and description. */
|
|
300
|
+
uid = `wm-select-${++nextId$2}`;
|
|
290
301
|
/** Array of options to display. */
|
|
291
302
|
options = input([], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
|
|
292
303
|
/** The currently selected value. Two-way bindable. */
|
|
@@ -295,18 +306,58 @@ class WmSelect {
|
|
|
295
306
|
placeholder = input('Select…', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
296
307
|
/** Disables the trigger and prevents the panel from opening. */
|
|
297
308
|
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
309
|
+
/**
|
|
310
|
+
* `field` (the default) is a full-width form control with a border.
|
|
311
|
+
* `chip` is a compact, filled trigger as wide as its words, for a row of
|
|
312
|
+
* choices such as a composer's model and permissions.
|
|
313
|
+
*/
|
|
314
|
+
appearance = input('field', ...(ngDevMode ? [{ debugName: "appearance" }] : /* istanbul ignore next */ []));
|
|
315
|
+
/**
|
|
316
|
+
* A muted word after the chosen label, in the trigger only: `suffix="model"`
|
|
317
|
+
* reads "Opus model". It names the choice where no label sits beside it. It
|
|
318
|
+
* is left out while the placeholder shows.
|
|
319
|
+
*/
|
|
320
|
+
suffix = input(null, ...(ngDevMode ? [{ debugName: "suffix" }] : /* istanbul ignore next */ []));
|
|
321
|
+
/**
|
|
322
|
+
* `danger` draws the trigger in the danger status colours, for a choice that
|
|
323
|
+
* is risky to keep, such as running without permission prompts.
|
|
324
|
+
*/
|
|
325
|
+
tone = input('neutral', ...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
|
|
326
|
+
/**
|
|
327
|
+
* `trigger` holds the panel to the trigger's width. `content` lets it grow to
|
|
328
|
+
* its widest option, from the trigger's width up to 24rem, where a
|
|
329
|
+
* description wraps. A number is a fixed width in pixels. Left unset, a
|
|
330
|
+
* field's panel matches the trigger and a chip's panel fits its content.
|
|
331
|
+
*/
|
|
332
|
+
panelWidth = input(null, ...(ngDevMode ? [{ debugName: "panelWidth" }] : /* istanbul ignore next */ []));
|
|
298
333
|
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
|
|
299
334
|
selectedOption = computed(() => this.options().find((o) => o.value === this.value()) ?? null, ...(ngDevMode ? [{ debugName: "selectedOption" }] : /* istanbul ignore next */ []));
|
|
335
|
+
sizing = computed(() => this.panelWidth() ?? (this.appearance() === 'chip' ? 'content' : 'trigger'), ...(ngDevMode ? [{ debugName: "sizing" }] : /* istanbul ignore next */ []));
|
|
300
336
|
hostEl = inject((ElementRef));
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
337
|
+
/**
|
|
338
|
+
* The trigger's width, measured as the panel opens. A width read on every
|
|
339
|
+
* check would differ between Angular's update pass and its no-changes pass
|
|
340
|
+
* whenever the trigger is resizing, which a chip does while its text renders.
|
|
341
|
+
*/
|
|
342
|
+
triggerWidth = signal(200, ...(ngDevMode ? [{ debugName: "triggerWidth" }] : /* istanbul ignore next */ []));
|
|
343
|
+
// The overlay leaves a size unset when it is given an empty string.
|
|
344
|
+
overlayWidth = computed(() => {
|
|
345
|
+
const sizing = this.sizing();
|
|
346
|
+
if (typeof sizing === 'number')
|
|
347
|
+
return sizing;
|
|
348
|
+
return sizing === 'trigger' ? this.triggerWidth() : '';
|
|
349
|
+
}, ...(ngDevMode ? [{ debugName: "overlayWidth" }] : /* istanbul ignore next */ []));
|
|
350
|
+
overlayMinWidth = computed(() => this.sizing() === 'content' ? this.triggerWidth() : '', ...(ngDevMode ? [{ debugName: "overlayMinWidth" }] : /* istanbul ignore next */ []));
|
|
351
|
+
/** The overlay has no max-width input, so the cap sits on the panel it holds. */
|
|
352
|
+
panelMaxWidth = computed(() => this.sizing() === 'content' ? CONTENT_MAX_WIDTH : '', ...(ngDevMode ? [{ debugName: "panelMaxWidth" }] : /* istanbul ignore next */ []));
|
|
304
353
|
positions = [
|
|
305
354
|
{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
|
|
306
355
|
{ originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
|
|
307
356
|
];
|
|
308
357
|
toggleOpen() {
|
|
309
358
|
if (!this.disabled()) {
|
|
359
|
+
if (!this.isOpen())
|
|
360
|
+
this.triggerWidth.set(this.hostEl.nativeElement.offsetWidth || 200);
|
|
310
361
|
this.isOpen.update((v) => !v);
|
|
311
362
|
}
|
|
312
363
|
}
|
|
@@ -317,12 +368,15 @@ class WmSelect {
|
|
|
317
368
|
}
|
|
318
369
|
}
|
|
319
370
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: WmSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
320
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.23", type: WmSelect, isStandalone: true, selector: "wm-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, ngImport: i0, template: "<!-- Trigger button \u2014 anchors the CDK overlay -->\n<div\n class=\"wm-select-host\"\n cdkOverlayOrigin\n #origin=\"cdkOverlayOrigin\"\n>\n <button\n type=\"button\"\n role=\"combobox\"\n class=\"wm-select-trigger\"\n [class.is-open]=\"isOpen()\"\n [class.is-disabled]=\"disabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n aria-haspopup=\"listbox\"\n [attr.aria-disabled]=\"disabled() ? true : null\"\n [disabled]=\"disabled() || null\"\n (click)=\"toggleOpen()\"\n >\n <span class=\"wm-select-value\" [class.is-placeholder]=\"!selectedOption()\">\n {{ selectedOption()?.label ?? placeholder() }}\n </span>\n <!-- Chevron icon \u2014 rotates when open -->\n <svg\n class=\"wm-select-chevron\"\n [class.is-open]=\"isOpen()\"\n width=\"16\" height=\"16\" viewBox=\"0 0 24 24\"\n fill=\"none\" aria-hidden=\"true\"\n >\n <path d=\"M6 9l6 6 6-6\"\n stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n</div>\n\n<!-- Dropdown panel \u2014 rendered in CDK overlay container -->\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayWidth]=\"overlayWidth\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"wm-select-backdrop\"\n (backdropClick)=\"isOpen.set(false)\"\n (detach)=\"isOpen.set(false)\"\n>\n <div\n class=\"wm-select-panel\"\n role=\"listbox\"\n cdkTrapFocus\n [cdkTrapFocusAutoCapture]=\"true\"\n >\n @for (opt of options(); track opt.value) {\n <button\n type=\"button\"\n role=\"option\"\n class=\"wm-select-option\"\n [class.is-selected]=\"opt.value === value()\"\n [class.is-disabled]=\"!!opt.disabled\"\n [attr.aria-selected]=\"opt.value === value()\"\n [attr.aria-disabled]=\"opt.disabled ? true : null\"\n [disabled]=\"opt.disabled || null\"\n (click)=\"selectOption(opt)\"\n >\n <span class=\"wm-select-option-label\">{{ opt.label }}</span>\n @if (opt.value === value()) {\n <!-- Checkmark for selected option -->\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <polyline points=\"20 6 9 17 4 12\"\n stroke=\"currentColor\" stroke-width=\"2.5\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n }\n </button>\n }\n </div>\n</ng-template>\n", styles: [":host{display:block}.wm-select-host{display:block}.wm-select-trigger{display:flex;align-items:center;justify-content:space-between;gap:.5rem;width:100%;padding:0 .75rem;height:36px;background:var(--wm-bg-base);border:1px solid var(--wm-border-input);border-radius:var(--wm-radius-md);color:var(--wm-text-primary);font-size:.875rem;font-family:inherit;cursor:pointer;transition:border-color var(--wm-transition-fast),box-shadow var(--wm-transition-fast);outline:none;text-align:left}.wm-select-trigger:hover:not(.is-disabled){border-color:var(--wm-color-accent-readable)}.wm-select-trigger:focus-visible{border-color:var(--wm-color-accent-readable);box-shadow:0 0 0 3px color-mix(in srgb,var(--wm-color-accent) 25%,transparent)}.wm-select-trigger.is-open{border-color:var(--wm-color-accent-readable);box-shadow:0 0 0 3px color-mix(in srgb,var(--wm-color-accent) 20%,transparent)}.wm-select-trigger.is-disabled{opacity:.45;cursor:not-allowed}.wm-select-value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wm-select-value.is-placeholder{color:var(--wm-text-placeholder)}.wm-select-chevron{flex-shrink:0;color:var(--wm-text-muted);transition:transform var(--wm-transition-fast)}.wm-select-chevron.is-open{transform:rotate(180deg)}.wm-select-backdrop{position:fixed;inset:0}.wm-select-panel{width:100%;background:var(--wm-bg-float);border:1px solid var(--wm-border);border-radius:var(--wm-radius-lg);box-shadow:0 4px 6px -1px #00000014,0 10px 20px -4px #0000001f;overflow:hidden;outline:none;padding:.25rem}.wm-select-option{display:flex;align-items:center;justify-content:space-between;gap:.5rem;width:100%;padding:.4375rem .625rem;border:none;border-radius:var(--wm-radius-sm);background:transparent;color:var(--wm-text-primary);font-size:.875rem;font-family:inherit;cursor:pointer;text-align:left;transition:background var(--wm-transition-fast)}.wm-select-option:hover:not(.is-disabled):not(.is-selected){background:var(--wm-bg-active)}.wm-select-option.is-selected{background:color-mix(in srgb,var(--wm-color-accent) 10%,transparent);color:var(--wm-color-accent-readable);font-weight:500}.wm-select-option.is-disabled{opacity:.4;cursor:not-allowed}.wm-select-option-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wm-select-option svg{flex-shrink:0;color:var(--wm-color-accent-readable)}\n"], dependencies: [{ kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }] });
|
|
371
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.23", type: WmSelect, isStandalone: true, selector: "wm-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, suffix: { classPropertyName: "suffix", publicName: "suffix", isSignal: true, isRequired: false, transformFunction: null }, tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null }, panelWidth: { classPropertyName: "panelWidth", publicName: "panelWidth", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { properties: { "class.wm-select--chip": "appearance() === 'chip'", "class.wm-select--danger": "tone() === 'danger'" } }, ngImport: i0, template: "<!-- Trigger button \u2014 anchors the CDK overlay -->\n<div\n class=\"wm-select-host\"\n cdkOverlayOrigin\n #origin=\"cdkOverlayOrigin\"\n>\n <button\n type=\"button\"\n role=\"combobox\"\n class=\"wm-select-trigger\"\n [class.is-open]=\"isOpen()\"\n [class.is-disabled]=\"disabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n aria-haspopup=\"listbox\"\n [attr.aria-disabled]=\"disabled() ? true : null\"\n [disabled]=\"disabled() || null\"\n (click)=\"toggleOpen()\"\n >\n <span class=\"wm-select-value\" [class.is-placeholder]=\"!selectedOption()\">\n {{ selectedOption()?.label ?? placeholder() }}\n </span>\n @if (suffix() && selectedOption()) {\n <span class=\"wm-select-suffix\">{{ suffix() }}</span>\n }\n <!-- Chevron icon \u2014 rotates when open -->\n <svg\n class=\"wm-select-chevron\"\n [class.is-open]=\"isOpen()\"\n width=\"16\" height=\"16\" viewBox=\"0 0 24 24\"\n fill=\"none\" aria-hidden=\"true\"\n >\n <path d=\"M6 9l6 6 6-6\"\n stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n</div>\n\n<!-- Dropdown panel \u2014 rendered in CDK overlay container -->\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayWidth]=\"overlayWidth()\"\n [cdkConnectedOverlayMinWidth]=\"overlayMinWidth()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"wm-select-backdrop\"\n (backdropClick)=\"isOpen.set(false)\"\n (detach)=\"isOpen.set(false)\"\n>\n <div\n class=\"wm-select-panel\"\n role=\"listbox\"\n [style.max-width]=\"panelMaxWidth() || null\"\n cdkTrapFocus\n [cdkTrapFocusAutoCapture]=\"true\"\n >\n @for (opt of options(); track opt.value; let i = $index) {\n <button\n type=\"button\"\n role=\"option\"\n class=\"wm-select-option\"\n [class.is-selected]=\"opt.value === value()\"\n [class.is-disabled]=\"!!opt.disabled\"\n [attr.aria-selected]=\"opt.value === value()\"\n [attr.aria-disabled]=\"opt.disabled ? true : null\"\n [attr.aria-labelledby]=\"opt.description ? uid + '-label-' + i : null\"\n [attr.aria-describedby]=\"opt.description ? uid + '-description-' + i : null\"\n [disabled]=\"opt.disabled || null\"\n (click)=\"selectOption(opt)\"\n >\n @if (opt.description) {\n <span class=\"wm-select-option-text\">\n <span class=\"wm-select-option-label\" [id]=\"uid + '-label-' + i\">{{ opt.label }}</span>\n <span class=\"wm-select-option-description\" [id]=\"uid + '-description-' + i\">{{ opt.description }}</span>\n </span>\n } @else {\n <span class=\"wm-select-option-label\">{{ opt.label }}</span>\n }\n @if (opt.value === value()) {\n <!-- Checkmark for selected option -->\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <polyline points=\"20 6 9 17 4 12\"\n stroke=\"currentColor\" stroke-width=\"2.5\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n }\n </button>\n }\n </div>\n</ng-template>\n", styles: [":host{display:block}.wm-select-host{display:block}.wm-select-trigger{display:flex;align-items:center;justify-content:space-between;gap:.5rem;width:100%;padding:0 .75rem;height:36px;background:var(--wm-bg-base);border:1px solid var(--wm-border-input);border-radius:var(--wm-radius-md);color:var(--wm-text-primary);font-size:.875rem;font-family:inherit;cursor:pointer;transition:border-color var(--wm-transition-fast),box-shadow var(--wm-transition-fast);outline:none;text-align:left}.wm-select-trigger:hover:not(.is-disabled){border-color:var(--wm-color-accent-readable)}.wm-select-trigger:focus-visible{border-color:var(--wm-color-accent-readable);box-shadow:0 0 0 3px color-mix(in srgb,var(--wm-color-accent) 25%,transparent)}.wm-select-trigger.is-open{border-color:var(--wm-color-accent-readable);box-shadow:0 0 0 3px color-mix(in srgb,var(--wm-color-accent) 20%,transparent)}.wm-select-trigger.is-disabled{opacity:.45;cursor:not-allowed}.wm-select-value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wm-select-value.is-placeholder{color:var(--wm-text-placeholder)}.wm-select-chevron{flex-shrink:0;color:var(--wm-text-muted);transition:transform var(--wm-transition-fast)}.wm-select-chevron.is-open{transform:rotate(180deg)}.wm-select-backdrop{position:fixed;inset:0}.wm-select-panel{width:100%;background:var(--wm-bg-float);border:1px solid var(--wm-border);border-radius:var(--wm-radius-lg);box-shadow:0 4px 6px -1px #00000014,0 10px 20px -4px #0000001f;overflow:hidden;outline:none;padding:.25rem}.wm-select-option{display:flex;align-items:center;justify-content:space-between;gap:.5rem;width:100%;padding:.4375rem .625rem;border:none;border-radius:var(--wm-radius-sm);background:transparent;color:var(--wm-text-primary);font-size:.875rem;font-family:inherit;cursor:pointer;text-align:left;transition:background var(--wm-transition-fast)}.wm-select-option:hover:not(.is-disabled):not(.is-selected){background:var(--wm-bg-active)}.wm-select-option.is-selected{background:color-mix(in srgb,var(--wm-color-accent) 10%,transparent);color:var(--wm-color-accent-readable);font-weight:500}.wm-select-option.is-disabled{opacity:.4;cursor:not-allowed}.wm-select-option-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wm-select-option svg{flex-shrink:0;color:var(--wm-color-accent-readable)}.wm-select-suffix{flex-shrink:0;color:var(--wm-text-muted);font-size:.8125rem;font-weight:400}.wm-select-option-text{display:flex;flex:1;flex-direction:column;gap:.125rem;min-width:0}.wm-select-option:has(.wm-select-option-text){align-items:flex-start;padding-block:.5rem}.wm-select-option:has(.wm-select-option-text) svg{margin-top:.1875rem}.wm-select-option-description{color:var(--wm-text-secondary);font-size:.75rem;font-weight:400;line-height:1.4;white-space:normal}:host(.wm-select--chip){display:inline-block;max-width:100%}:host(.wm-select--chip) .wm-select-trigger{justify-content:flex-start;width:auto;max-width:100%;height:34px;padding:0 .625rem 0 .75rem;background:var(--wm-bg-base);border-color:transparent;font-weight:500;transition:background var(--wm-transition-fast),border-color var(--wm-transition-fast),box-shadow var(--wm-transition-fast)}:host(.wm-select--chip) .wm-select-value{flex:0 1 auto}:host(.wm-select--chip) .wm-select-chevron{width:14px;height:14px}:host(.wm-select--chip) .wm-select-trigger:hover:not(.is-disabled),:host(.wm-select--chip) .wm-select-trigger.is-open{background:var(--wm-bg-hover);border-color:transparent;box-shadow:none;animation:none}:host(.wm-select--chip) .wm-select-trigger:hover:not(.is-disabled) .wm-select-suffix,:host(.wm-select--chip) .wm-select-trigger.is-open .wm-select-suffix{color:var(--wm-text-secondary)}:host(.wm-select--chip) .wm-select-trigger:focus-visible{border-color:var(--wm-color-accent-readable);box-shadow:0 0 0 3px color-mix(in srgb,var(--wm-color-accent) 25%,transparent)}:host(.wm-select--danger) .wm-select-trigger,:host(.wm-select--danger) .wm-select-trigger:hover:not(.is-disabled),:host(.wm-select--danger) .wm-select-trigger.is-open{border-color:var(--wm-color-danger-border);color:var(--wm-color-danger-readable)}:host(.wm-select--danger) .wm-select-suffix,:host(.wm-select--danger) .wm-select-chevron{color:var(--wm-color-danger-readable)}:host(.wm-select--danger.wm-select--chip) .wm-select-trigger{background:linear-gradient(var(--wm-color-danger-bg),var(--wm-color-danger-bg)),var(--wm-bg-base)}:host(.wm-select--danger.wm-select--chip) .wm-select-trigger:hover:not(.is-disabled),:host(.wm-select--danger.wm-select--chip) .wm-select-trigger.is-open{background:linear-gradient(var(--wm-color-danger-bg),var(--wm-color-danger-bg)),var(--wm-bg-hover)}\n"], dependencies: [{ kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }] });
|
|
321
372
|
}
|
|
322
373
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: WmSelect, decorators: [{
|
|
323
374
|
type: Component,
|
|
324
|
-
args: [{ selector: 'wm-select', imports: [CdkConnectedOverlay, CdkOverlayOrigin, CdkTrapFocus],
|
|
325
|
-
|
|
375
|
+
args: [{ selector: 'wm-select', imports: [CdkConnectedOverlay, CdkOverlayOrigin, CdkTrapFocus], host: {
|
|
376
|
+
'[class.wm-select--chip]': "appearance() === 'chip'",
|
|
377
|
+
'[class.wm-select--danger]': "tone() === 'danger'",
|
|
378
|
+
}, template: "<!-- Trigger button \u2014 anchors the CDK overlay -->\n<div\n class=\"wm-select-host\"\n cdkOverlayOrigin\n #origin=\"cdkOverlayOrigin\"\n>\n <button\n type=\"button\"\n role=\"combobox\"\n class=\"wm-select-trigger\"\n [class.is-open]=\"isOpen()\"\n [class.is-disabled]=\"disabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n aria-haspopup=\"listbox\"\n [attr.aria-disabled]=\"disabled() ? true : null\"\n [disabled]=\"disabled() || null\"\n (click)=\"toggleOpen()\"\n >\n <span class=\"wm-select-value\" [class.is-placeholder]=\"!selectedOption()\">\n {{ selectedOption()?.label ?? placeholder() }}\n </span>\n @if (suffix() && selectedOption()) {\n <span class=\"wm-select-suffix\">{{ suffix() }}</span>\n }\n <!-- Chevron icon \u2014 rotates when open -->\n <svg\n class=\"wm-select-chevron\"\n [class.is-open]=\"isOpen()\"\n width=\"16\" height=\"16\" viewBox=\"0 0 24 24\"\n fill=\"none\" aria-hidden=\"true\"\n >\n <path d=\"M6 9l6 6 6-6\"\n stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n</div>\n\n<!-- Dropdown panel \u2014 rendered in CDK overlay container -->\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayWidth]=\"overlayWidth()\"\n [cdkConnectedOverlayMinWidth]=\"overlayMinWidth()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"wm-select-backdrop\"\n (backdropClick)=\"isOpen.set(false)\"\n (detach)=\"isOpen.set(false)\"\n>\n <div\n class=\"wm-select-panel\"\n role=\"listbox\"\n [style.max-width]=\"panelMaxWidth() || null\"\n cdkTrapFocus\n [cdkTrapFocusAutoCapture]=\"true\"\n >\n @for (opt of options(); track opt.value; let i = $index) {\n <button\n type=\"button\"\n role=\"option\"\n class=\"wm-select-option\"\n [class.is-selected]=\"opt.value === value()\"\n [class.is-disabled]=\"!!opt.disabled\"\n [attr.aria-selected]=\"opt.value === value()\"\n [attr.aria-disabled]=\"opt.disabled ? true : null\"\n [attr.aria-labelledby]=\"opt.description ? uid + '-label-' + i : null\"\n [attr.aria-describedby]=\"opt.description ? uid + '-description-' + i : null\"\n [disabled]=\"opt.disabled || null\"\n (click)=\"selectOption(opt)\"\n >\n @if (opt.description) {\n <span class=\"wm-select-option-text\">\n <span class=\"wm-select-option-label\" [id]=\"uid + '-label-' + i\">{{ opt.label }}</span>\n <span class=\"wm-select-option-description\" [id]=\"uid + '-description-' + i\">{{ opt.description }}</span>\n </span>\n } @else {\n <span class=\"wm-select-option-label\">{{ opt.label }}</span>\n }\n @if (opt.value === value()) {\n <!-- Checkmark for selected option -->\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <polyline points=\"20 6 9 17 4 12\"\n stroke=\"currentColor\" stroke-width=\"2.5\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n }\n </button>\n }\n </div>\n</ng-template>\n", styles: [":host{display:block}.wm-select-host{display:block}.wm-select-trigger{display:flex;align-items:center;justify-content:space-between;gap:.5rem;width:100%;padding:0 .75rem;height:36px;background:var(--wm-bg-base);border:1px solid var(--wm-border-input);border-radius:var(--wm-radius-md);color:var(--wm-text-primary);font-size:.875rem;font-family:inherit;cursor:pointer;transition:border-color var(--wm-transition-fast),box-shadow var(--wm-transition-fast);outline:none;text-align:left}.wm-select-trigger:hover:not(.is-disabled){border-color:var(--wm-color-accent-readable)}.wm-select-trigger:focus-visible{border-color:var(--wm-color-accent-readable);box-shadow:0 0 0 3px color-mix(in srgb,var(--wm-color-accent) 25%,transparent)}.wm-select-trigger.is-open{border-color:var(--wm-color-accent-readable);box-shadow:0 0 0 3px color-mix(in srgb,var(--wm-color-accent) 20%,transparent)}.wm-select-trigger.is-disabled{opacity:.45;cursor:not-allowed}.wm-select-value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wm-select-value.is-placeholder{color:var(--wm-text-placeholder)}.wm-select-chevron{flex-shrink:0;color:var(--wm-text-muted);transition:transform var(--wm-transition-fast)}.wm-select-chevron.is-open{transform:rotate(180deg)}.wm-select-backdrop{position:fixed;inset:0}.wm-select-panel{width:100%;background:var(--wm-bg-float);border:1px solid var(--wm-border);border-radius:var(--wm-radius-lg);box-shadow:0 4px 6px -1px #00000014,0 10px 20px -4px #0000001f;overflow:hidden;outline:none;padding:.25rem}.wm-select-option{display:flex;align-items:center;justify-content:space-between;gap:.5rem;width:100%;padding:.4375rem .625rem;border:none;border-radius:var(--wm-radius-sm);background:transparent;color:var(--wm-text-primary);font-size:.875rem;font-family:inherit;cursor:pointer;text-align:left;transition:background var(--wm-transition-fast)}.wm-select-option:hover:not(.is-disabled):not(.is-selected){background:var(--wm-bg-active)}.wm-select-option.is-selected{background:color-mix(in srgb,var(--wm-color-accent) 10%,transparent);color:var(--wm-color-accent-readable);font-weight:500}.wm-select-option.is-disabled{opacity:.4;cursor:not-allowed}.wm-select-option-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wm-select-option svg{flex-shrink:0;color:var(--wm-color-accent-readable)}.wm-select-suffix{flex-shrink:0;color:var(--wm-text-muted);font-size:.8125rem;font-weight:400}.wm-select-option-text{display:flex;flex:1;flex-direction:column;gap:.125rem;min-width:0}.wm-select-option:has(.wm-select-option-text){align-items:flex-start;padding-block:.5rem}.wm-select-option:has(.wm-select-option-text) svg{margin-top:.1875rem}.wm-select-option-description{color:var(--wm-text-secondary);font-size:.75rem;font-weight:400;line-height:1.4;white-space:normal}:host(.wm-select--chip){display:inline-block;max-width:100%}:host(.wm-select--chip) .wm-select-trigger{justify-content:flex-start;width:auto;max-width:100%;height:34px;padding:0 .625rem 0 .75rem;background:var(--wm-bg-base);border-color:transparent;font-weight:500;transition:background var(--wm-transition-fast),border-color var(--wm-transition-fast),box-shadow var(--wm-transition-fast)}:host(.wm-select--chip) .wm-select-value{flex:0 1 auto}:host(.wm-select--chip) .wm-select-chevron{width:14px;height:14px}:host(.wm-select--chip) .wm-select-trigger:hover:not(.is-disabled),:host(.wm-select--chip) .wm-select-trigger.is-open{background:var(--wm-bg-hover);border-color:transparent;box-shadow:none;animation:none}:host(.wm-select--chip) .wm-select-trigger:hover:not(.is-disabled) .wm-select-suffix,:host(.wm-select--chip) .wm-select-trigger.is-open .wm-select-suffix{color:var(--wm-text-secondary)}:host(.wm-select--chip) .wm-select-trigger:focus-visible{border-color:var(--wm-color-accent-readable);box-shadow:0 0 0 3px color-mix(in srgb,var(--wm-color-accent) 25%,transparent)}:host(.wm-select--danger) .wm-select-trigger,:host(.wm-select--danger) .wm-select-trigger:hover:not(.is-disabled),:host(.wm-select--danger) .wm-select-trigger.is-open{border-color:var(--wm-color-danger-border);color:var(--wm-color-danger-readable)}:host(.wm-select--danger) .wm-select-suffix,:host(.wm-select--danger) .wm-select-chevron{color:var(--wm-color-danger-readable)}:host(.wm-select--danger.wm-select--chip) .wm-select-trigger{background:linear-gradient(var(--wm-color-danger-bg),var(--wm-color-danger-bg)),var(--wm-bg-base)}:host(.wm-select--danger.wm-select--chip) .wm-select-trigger:hover:not(.is-disabled),:host(.wm-select--danger.wm-select--chip) .wm-select-trigger.is-open{background:linear-gradient(var(--wm-color-danger-bg),var(--wm-color-danger-bg)),var(--wm-bg-hover)}\n"] }]
|
|
379
|
+
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], suffix: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffix", required: false }] }], tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }], panelWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelWidth", required: false }] }] } });
|
|
326
380
|
|
|
327
381
|
/**
|
|
328
382
|
* WmPopover — general-purpose CDK-overlay floating panel.
|
|
@@ -1310,7 +1364,7 @@ class WmSlider {
|
|
|
1310
1364
|
useExisting: forwardRef(() => WmSlider),
|
|
1311
1365
|
multi: true,
|
|
1312
1366
|
},
|
|
1313
|
-
], ngImport: i0, template: "<!--\n The native <input type=\"range\"> is the control, not a decoration over one:\n its track and thumb are the styled surfaces. --wm-slider-p carries the thumb\n position to the CSS so the filled part of the track, every tick and every\n block are placed from the same number the thumb is.\n-->\n<div\n class=\"wm-slider\"\n [attr.data-track]=\"track()\"\n [class.is-disabled]=\"isDisabled()\"\n [class.has-ticks]=\"resolvedTicks().length > 0\"\n [style.--wm-slider-p]=\"fraction()\"\n>\n <div class=\"wm-slider-rail\">\n @if (segments().length > 0) {\n <!--\n Blocks sit under the transparent native track. They are bounded by the\n same resolved grid the marks come from, so a block and the mark on its\n edge can never disagree about where a value falls.\n -->\n <div class=\"wm-slider-segments\" aria-hidden=\"true\">\n @for (segment of segments(); track segment.from) {\n <span\n class=\"wm-slider-seg\"\n [class.is-passed]=\"segment.passed\"\n [class.is-current]=\"segment.current\"\n [style.flexGrow]=\"segment.span\"\n [style.--wm-slider-seg-p]=\"segment.fill\"\n ></span>\n }\n </div>\n }\n\n @if (resolvedTicks().length > 0) {\n <div class=\"wm-slider-ticks\" aria-hidden=\"true\">\n @for (tick of resolvedTicks(); track tick.value) {\n <span\n class=\"wm-slider-tick\"\n [class.wm-slider-tick--minor]=\"tick.level === 'minor'\"\n [class.is-passed]=\"tick.passed\"\n [style.left]=\"tick.left\"\n ></span>\n }\n </div>\n }\n\n <input\n class=\"wm-slider-input\"\n type=\"range\"\n [
|
|
1367
|
+
], ngImport: i0, template: "<!--\n The native <input type=\"range\"> is the control, not a decoration over one:\n its track and thumb are the styled surfaces. --wm-slider-p carries the thumb\n position to the CSS so the filled part of the track, every tick and every\n block are placed from the same number the thumb is.\n-->\n<div\n class=\"wm-slider\"\n [attr.data-track]=\"track()\"\n [class.is-disabled]=\"isDisabled()\"\n [class.has-ticks]=\"resolvedTicks().length > 0\"\n [style.--wm-slider-p]=\"fraction()\"\n>\n <div class=\"wm-slider-rail\">\n @if (segments().length > 0) {\n <!--\n Blocks sit under the transparent native track. They are bounded by the\n same resolved grid the marks come from, so a block and the mark on its\n edge can never disagree about where a value falls.\n -->\n <div class=\"wm-slider-segments\" aria-hidden=\"true\">\n @for (segment of segments(); track segment.from) {\n <span\n class=\"wm-slider-seg\"\n [class.is-passed]=\"segment.passed\"\n [class.is-current]=\"segment.current\"\n [style.flexGrow]=\"segment.span\"\n [style.--wm-slider-seg-p]=\"segment.fill\"\n ></span>\n }\n </div>\n }\n\n @if (resolvedTicks().length > 0) {\n <div class=\"wm-slider-ticks\" aria-hidden=\"true\">\n @for (tick of resolvedTicks(); track tick.value) {\n <span\n class=\"wm-slider-tick\"\n [class.wm-slider-tick--minor]=\"tick.level === 'minor'\"\n [class.is-passed]=\"tick.passed\"\n [style.left]=\"tick.left\"\n ></span>\n }\n </div>\n }\n\n <!--\n The bounds and the step are bound before the value. The browser sanitizes a\n written value against the bounds the input holds at that moment, so a value\n bound first is clamped or snapped to the old range when both change in one\n render, and it is not written again because its signal did not change.\n -->\n <input\n class=\"wm-slider-input\"\n type=\"range\"\n [min]=\"min()\"\n [max]=\"max()\"\n [step]=\"step() > 0 ? step() : 'any'\"\n [value]=\"value()\"\n [disabled]=\"isDisabled() || null\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-valuetext]=\"valueText()\"\n (input)=\"onRangeInput($event)\"\n (blur)=\"onTouchedFn()\"\n />\n </div>\n\n @if (showValue()) {\n <!--\n The sizers stack on the output in one grid cell, so the column reserves\n the widest string the readout can hold and stops stealing width from the\n rail every time the value changes.\n -->\n <div class=\"wm-slider-value-cell\">\n <output class=\"wm-slider-value\">{{ displayValue() }}</output>\n @for (candidate of valueCandidates(); track candidate) {\n <span class=\"wm-slider-value-sizer\" aria-hidden=\"true\">{{ candidate }}</span>\n }\n </div>\n }\n\n @if (hasTickLabels()) {\n <div class=\"wm-slider-tick-labels\" aria-hidden=\"true\">\n @for (tick of resolvedTicks(); track tick.value) {\n @if (tick.label !== undefined) {\n <span class=\"wm-slider-tick-label\" [style.left]=\"tick.left\">{{ tick.label }}</span>\n }\n }\n </div>\n }\n</div>\n", styles: [":host{display:block}.wm-slider{--wm-slider-thumb: 16px;--wm-slider-track: 4px;--wm-slider-gap: 3px;--wm-slider-p: 0;--wm-slider-stop: calc( var(--wm-slider-thumb) / 2 + var(--wm-slider-p) * (100% - var(--wm-slider-thumb)) );--wm-slider-fill: linear-gradient( to right, var(--wm-color-accent) 0 var(--wm-slider-stop), var(--wm-border-input) var(--wm-slider-stop) 100% );display:grid;grid-template-columns:1fr auto;align-items:center;column-gap:.75rem;row-gap:.375rem}.wm-slider-rail{position:relative;min-width:0}.wm-slider.has-ticks .wm-slider-rail{margin-bottom:10px}.wm-slider-input{-webkit-appearance:none;appearance:none;display:block;width:100%;height:var(--wm-slider-thumb);margin:0;padding:0;background:transparent;cursor:pointer;position:relative;z-index:1}.wm-slider-input:focus{outline:none}.wm-slider-input::-webkit-slider-runnable-track{height:var(--wm-slider-track);border-radius:var(--wm-radius-full);background:var(--wm-slider-fill)}.wm-slider-input::-webkit-slider-thumb{-webkit-appearance:none;width:var(--wm-slider-thumb);height:var(--wm-slider-thumb);margin-top:calc((var(--wm-slider-track) - var(--wm-slider-thumb)) / 2);border-radius:var(--wm-radius-full);background:var(--wm-color-accent);border:2px solid var(--wm-bg-base);box-shadow:var(--wm-shadow-sm);transition:background var(--wm-transition-fast),transform var(--wm-transition-fast)}.wm-slider-input:hover::-webkit-slider-thumb{background:var(--wm-color-accent-hover);transform:scale(1.12)}.wm-slider-input:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--wm-bg-base),0 0 0 4px var(--wm-color-accent)}.wm-slider-input::-moz-range-track{height:var(--wm-slider-track);border-radius:var(--wm-radius-full);background:var(--wm-slider-fill)}.wm-slider-input::-moz-range-thumb{width:var(--wm-slider-thumb);height:var(--wm-slider-thumb);box-sizing:border-box;border-radius:var(--wm-radius-full);background:var(--wm-color-accent);border:2px solid var(--wm-bg-base);box-shadow:var(--wm-shadow-sm);transition:background var(--wm-transition-fast),transform var(--wm-transition-fast)}.wm-slider-input:hover::-moz-range-thumb{background:var(--wm-color-accent-hover);transform:scale(1.12)}.wm-slider-input:focus-visible::-moz-range-thumb{box-shadow:0 0 0 2px var(--wm-bg-base),0 0 0 4px var(--wm-color-accent)}.wm-slider-ticks{position:absolute;inset-inline:0;top:100%;margin-top:2px;height:6px;pointer-events:none}.wm-slider-tick{position:absolute;top:0;width:2px;height:6px;margin-left:-1px;border-radius:1px;background:var(--wm-border-input);transition:background var(--wm-transition-fast)}.wm-slider-tick.is-passed{background:var(--wm-color-accent)}.wm-slider-tick--minor{height:3px;background:var(--wm-border-subtle)}.wm-slider-tick--minor.is-passed{background:color-mix(in srgb,var(--wm-color-accent) 55%,transparent)}.wm-slider[data-track=segmented]{--wm-slider-fill: none}.wm-slider-segments{position:absolute;inset:0 calc(var(--wm-slider-thumb) / 2);display:flex;align-items:center;gap:var(--wm-slider-gap);pointer-events:none}.wm-slider-seg{flex-basis:0;min-width:0;height:var(--wm-slider-track);border-radius:1px;background:var(--wm-border-input);transition:background var(--wm-transition-fast)}.wm-slider-seg.is-passed{background:var(--wm-color-accent)}.wm-slider-seg.is-current{background-image:linear-gradient(var(--wm-color-accent) 0 0);background-repeat:no-repeat;background-size:calc(var(--wm-slider-seg-p, 0) * 100%) 100%}.wm-slider-tick-labels{position:relative;grid-column:1;height:1rem}.wm-slider-tick-label{position:absolute;top:0;transform:translate(-50%);font-size:.75rem;color:var(--wm-text-muted);white-space:nowrap}.wm-slider-value-cell{grid-area:1 / 2;display:grid;justify-items:end}.wm-slider-value,.wm-slider-value-sizer{grid-area:1 / 1;font-family:var(--wm-font-mono);font-size:.8125rem;font-variant-numeric:tabular-nums;white-space:nowrap}.wm-slider-value{color:var(--wm-text-secondary);min-width:4ch;text-align:right}.wm-slider-value-sizer{visibility:hidden;pointer-events:none}.wm-slider.is-disabled{opacity:.5}.wm-slider-input:disabled{cursor:not-allowed}@media(prefers-reduced-motion:reduce){.wm-slider-input::-webkit-slider-thumb,.wm-slider-input::-moz-range-thumb,.wm-slider-tick{transition:none}.wm-slider-input:hover::-webkit-slider-thumb,.wm-slider-input:hover::-moz-range-thumb{transform:none}}\n"] });
|
|
1314
1368
|
}
|
|
1315
1369
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: WmSlider, decorators: [{
|
|
1316
1370
|
type: Component,
|
|
@@ -1320,7 +1374,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.23", ngImpo
|
|
|
1320
1374
|
useExisting: forwardRef(() => WmSlider),
|
|
1321
1375
|
multi: true,
|
|
1322
1376
|
},
|
|
1323
|
-
], template: "<!--\n The native <input type=\"range\"> is the control, not a decoration over one:\n its track and thumb are the styled surfaces. --wm-slider-p carries the thumb\n position to the CSS so the filled part of the track, every tick and every\n block are placed from the same number the thumb is.\n-->\n<div\n class=\"wm-slider\"\n [attr.data-track]=\"track()\"\n [class.is-disabled]=\"isDisabled()\"\n [class.has-ticks]=\"resolvedTicks().length > 0\"\n [style.--wm-slider-p]=\"fraction()\"\n>\n <div class=\"wm-slider-rail\">\n @if (segments().length > 0) {\n <!--\n Blocks sit under the transparent native track. They are bounded by the\n same resolved grid the marks come from, so a block and the mark on its\n edge can never disagree about where a value falls.\n -->\n <div class=\"wm-slider-segments\" aria-hidden=\"true\">\n @for (segment of segments(); track segment.from) {\n <span\n class=\"wm-slider-seg\"\n [class.is-passed]=\"segment.passed\"\n [class.is-current]=\"segment.current\"\n [style.flexGrow]=\"segment.span\"\n [style.--wm-slider-seg-p]=\"segment.fill\"\n ></span>\n }\n </div>\n }\n\n @if (resolvedTicks().length > 0) {\n <div class=\"wm-slider-ticks\" aria-hidden=\"true\">\n @for (tick of resolvedTicks(); track tick.value) {\n <span\n class=\"wm-slider-tick\"\n [class.wm-slider-tick--minor]=\"tick.level === 'minor'\"\n [class.is-passed]=\"tick.passed\"\n [style.left]=\"tick.left\"\n ></span>\n }\n </div>\n }\n\n <input\n class=\"wm-slider-input\"\n type=\"range\"\n [
|
|
1377
|
+
], template: "<!--\n The native <input type=\"range\"> is the control, not a decoration over one:\n its track and thumb are the styled surfaces. --wm-slider-p carries the thumb\n position to the CSS so the filled part of the track, every tick and every\n block are placed from the same number the thumb is.\n-->\n<div\n class=\"wm-slider\"\n [attr.data-track]=\"track()\"\n [class.is-disabled]=\"isDisabled()\"\n [class.has-ticks]=\"resolvedTicks().length > 0\"\n [style.--wm-slider-p]=\"fraction()\"\n>\n <div class=\"wm-slider-rail\">\n @if (segments().length > 0) {\n <!--\n Blocks sit under the transparent native track. They are bounded by the\n same resolved grid the marks come from, so a block and the mark on its\n edge can never disagree about where a value falls.\n -->\n <div class=\"wm-slider-segments\" aria-hidden=\"true\">\n @for (segment of segments(); track segment.from) {\n <span\n class=\"wm-slider-seg\"\n [class.is-passed]=\"segment.passed\"\n [class.is-current]=\"segment.current\"\n [style.flexGrow]=\"segment.span\"\n [style.--wm-slider-seg-p]=\"segment.fill\"\n ></span>\n }\n </div>\n }\n\n @if (resolvedTicks().length > 0) {\n <div class=\"wm-slider-ticks\" aria-hidden=\"true\">\n @for (tick of resolvedTicks(); track tick.value) {\n <span\n class=\"wm-slider-tick\"\n [class.wm-slider-tick--minor]=\"tick.level === 'minor'\"\n [class.is-passed]=\"tick.passed\"\n [style.left]=\"tick.left\"\n ></span>\n }\n </div>\n }\n\n <!--\n The bounds and the step are bound before the value. The browser sanitizes a\n written value against the bounds the input holds at that moment, so a value\n bound first is clamped or snapped to the old range when both change in one\n render, and it is not written again because its signal did not change.\n -->\n <input\n class=\"wm-slider-input\"\n type=\"range\"\n [min]=\"min()\"\n [max]=\"max()\"\n [step]=\"step() > 0 ? step() : 'any'\"\n [value]=\"value()\"\n [disabled]=\"isDisabled() || null\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-valuetext]=\"valueText()\"\n (input)=\"onRangeInput($event)\"\n (blur)=\"onTouchedFn()\"\n />\n </div>\n\n @if (showValue()) {\n <!--\n The sizers stack on the output in one grid cell, so the column reserves\n the widest string the readout can hold and stops stealing width from the\n rail every time the value changes.\n -->\n <div class=\"wm-slider-value-cell\">\n <output class=\"wm-slider-value\">{{ displayValue() }}</output>\n @for (candidate of valueCandidates(); track candidate) {\n <span class=\"wm-slider-value-sizer\" aria-hidden=\"true\">{{ candidate }}</span>\n }\n </div>\n }\n\n @if (hasTickLabels()) {\n <div class=\"wm-slider-tick-labels\" aria-hidden=\"true\">\n @for (tick of resolvedTicks(); track tick.value) {\n @if (tick.label !== undefined) {\n <span class=\"wm-slider-tick-label\" [style.left]=\"tick.left\">{{ tick.label }}</span>\n }\n }\n </div>\n }\n</div>\n", styles: [":host{display:block}.wm-slider{--wm-slider-thumb: 16px;--wm-slider-track: 4px;--wm-slider-gap: 3px;--wm-slider-p: 0;--wm-slider-stop: calc( var(--wm-slider-thumb) / 2 + var(--wm-slider-p) * (100% - var(--wm-slider-thumb)) );--wm-slider-fill: linear-gradient( to right, var(--wm-color-accent) 0 var(--wm-slider-stop), var(--wm-border-input) var(--wm-slider-stop) 100% );display:grid;grid-template-columns:1fr auto;align-items:center;column-gap:.75rem;row-gap:.375rem}.wm-slider-rail{position:relative;min-width:0}.wm-slider.has-ticks .wm-slider-rail{margin-bottom:10px}.wm-slider-input{-webkit-appearance:none;appearance:none;display:block;width:100%;height:var(--wm-slider-thumb);margin:0;padding:0;background:transparent;cursor:pointer;position:relative;z-index:1}.wm-slider-input:focus{outline:none}.wm-slider-input::-webkit-slider-runnable-track{height:var(--wm-slider-track);border-radius:var(--wm-radius-full);background:var(--wm-slider-fill)}.wm-slider-input::-webkit-slider-thumb{-webkit-appearance:none;width:var(--wm-slider-thumb);height:var(--wm-slider-thumb);margin-top:calc((var(--wm-slider-track) - var(--wm-slider-thumb)) / 2);border-radius:var(--wm-radius-full);background:var(--wm-color-accent);border:2px solid var(--wm-bg-base);box-shadow:var(--wm-shadow-sm);transition:background var(--wm-transition-fast),transform var(--wm-transition-fast)}.wm-slider-input:hover::-webkit-slider-thumb{background:var(--wm-color-accent-hover);transform:scale(1.12)}.wm-slider-input:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--wm-bg-base),0 0 0 4px var(--wm-color-accent)}.wm-slider-input::-moz-range-track{height:var(--wm-slider-track);border-radius:var(--wm-radius-full);background:var(--wm-slider-fill)}.wm-slider-input::-moz-range-thumb{width:var(--wm-slider-thumb);height:var(--wm-slider-thumb);box-sizing:border-box;border-radius:var(--wm-radius-full);background:var(--wm-color-accent);border:2px solid var(--wm-bg-base);box-shadow:var(--wm-shadow-sm);transition:background var(--wm-transition-fast),transform var(--wm-transition-fast)}.wm-slider-input:hover::-moz-range-thumb{background:var(--wm-color-accent-hover);transform:scale(1.12)}.wm-slider-input:focus-visible::-moz-range-thumb{box-shadow:0 0 0 2px var(--wm-bg-base),0 0 0 4px var(--wm-color-accent)}.wm-slider-ticks{position:absolute;inset-inline:0;top:100%;margin-top:2px;height:6px;pointer-events:none}.wm-slider-tick{position:absolute;top:0;width:2px;height:6px;margin-left:-1px;border-radius:1px;background:var(--wm-border-input);transition:background var(--wm-transition-fast)}.wm-slider-tick.is-passed{background:var(--wm-color-accent)}.wm-slider-tick--minor{height:3px;background:var(--wm-border-subtle)}.wm-slider-tick--minor.is-passed{background:color-mix(in srgb,var(--wm-color-accent) 55%,transparent)}.wm-slider[data-track=segmented]{--wm-slider-fill: none}.wm-slider-segments{position:absolute;inset:0 calc(var(--wm-slider-thumb) / 2);display:flex;align-items:center;gap:var(--wm-slider-gap);pointer-events:none}.wm-slider-seg{flex-basis:0;min-width:0;height:var(--wm-slider-track);border-radius:1px;background:var(--wm-border-input);transition:background var(--wm-transition-fast)}.wm-slider-seg.is-passed{background:var(--wm-color-accent)}.wm-slider-seg.is-current{background-image:linear-gradient(var(--wm-color-accent) 0 0);background-repeat:no-repeat;background-size:calc(var(--wm-slider-seg-p, 0) * 100%) 100%}.wm-slider-tick-labels{position:relative;grid-column:1;height:1rem}.wm-slider-tick-label{position:absolute;top:0;transform:translate(-50%);font-size:.75rem;color:var(--wm-text-muted);white-space:nowrap}.wm-slider-value-cell{grid-area:1 / 2;display:grid;justify-items:end}.wm-slider-value,.wm-slider-value-sizer{grid-area:1 / 1;font-family:var(--wm-font-mono);font-size:.8125rem;font-variant-numeric:tabular-nums;white-space:nowrap}.wm-slider-value{color:var(--wm-text-secondary);min-width:4ch;text-align:right}.wm-slider-value-sizer{visibility:hidden;pointer-events:none}.wm-slider.is-disabled{opacity:.5}.wm-slider-input:disabled{cursor:not-allowed}@media(prefers-reduced-motion:reduce){.wm-slider-input::-webkit-slider-thumb,.wm-slider-input::-moz-range-thumb,.wm-slider-tick{transition:none}.wm-slider-input:hover::-webkit-slider-thumb,.wm-slider-input:hover::-moz-range-thumb{transform:none}}\n"] }]
|
|
1324
1378
|
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], formatValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatValue", required: false }] }], track: [{ type: i0.Input, args: [{ isSignal: true, alias: "track", required: false }] }], ticks: [{ type: i0.Input, args: [{ isSignal: true, alias: "ticks", required: false }] }] } });
|
|
1325
1379
|
/**
|
|
1326
1380
|
* A stop every `interval`, starting at `min` and never passing `max`. Returns
|