@uni-design-system/uni-angular 8.3.0 → 8.4.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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { signal, computed, linkedSignal, resource, Injectable, inject, DestroyRef, InjectionToken, input, ChangeDetectionStrategy, Component, contentChildren, output, Renderer2, ElementRef, Directive, model, viewChild, effect, untracked, afterNextRender, ViewChild,
|
|
2
|
+
import { signal, computed, linkedSignal, resource, Injectable, inject, DestroyRef, InjectionToken, input, ChangeDetectionStrategy, Component, contentChildren, output, Renderer2, ElementRef, Directive, model, viewChild, effect, untracked, afterRenderEffect, afterNextRender, ViewChild, booleanAttribute, viewChildren } from '@angular/core';
|
|
3
3
|
import { injectGlobal, css, keyframes } from '@emotion/css';
|
|
4
|
-
import { UniThemes, LightTheme, toTypefaces, parseTheme, formatThemeIssues, hydrateTheme, createThemeFromPalette, Z_INDEX, removeInputPlatformStyling, fadeIn, fadeOut,
|
|
4
|
+
import { UniThemes, LightTheme, toTypefaces, parseTheme, formatThemeIssues, hydrateTheme, createThemeFromPalette, Z_INDEX, removeInputPlatformStyling, fadeIn, fadeOut, expandDuration, expandFadeIn, collapseFadeOut, HOVER_OR_KEYBOARD_FOCUS, ShapeRadii, generatePalette, emitThemeFile, emitDtcgTokens } from '@uni-design-system/uni-core';
|
|
5
5
|
import { NgClass, NgTemplateOutlet, CommonModule } from '@angular/common';
|
|
6
6
|
|
|
7
7
|
let nextUniqueId = 0;
|
|
@@ -49,6 +49,35 @@ const visuallyHidden = {
|
|
|
49
49
|
function motionSafe(styles) {
|
|
50
50
|
return { '@media (prefers-reduced-motion: no-preference)': styles };
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* A polite live region's text, for the running commentary a form control owes
|
|
54
|
+
* a screen reader: commits, clears, refused entries, result counts — changes
|
|
55
|
+
* a sighted user sees but that are otherwise silent.
|
|
56
|
+
*
|
|
57
|
+
* Extracted because five controls (`uni-combobox`, `uni-tag-input`,
|
|
58
|
+
* `uni-time-input`, `uni-date-input`, `uni-calendar`) carried byte-identical
|
|
59
|
+
* copies, including the repeat trick below — the kind of subtlety that is
|
|
60
|
+
* quietly dropped when the sixth control hand-rolls its own.
|
|
61
|
+
*
|
|
62
|
+
* Announcing the same text twice must still be heard: assistive tech reads a
|
|
63
|
+
* live region when its content *changes*, so setting an identical string is a
|
|
64
|
+
* no-op and the second "No match." would be silent. A trailing space breaks
|
|
65
|
+
* the equality without changing a word of what is read. Successive repeats
|
|
66
|
+
* alternate between the padded and unpadded form, so nothing accumulates.
|
|
67
|
+
*
|
|
68
|
+
* Deliberately holds no DOM and no styling: the region belongs to the
|
|
69
|
+
* component's own template, where its placement and visually-hidden class are
|
|
70
|
+
* already the component's business.
|
|
71
|
+
*/
|
|
72
|
+
function createAnnouncer() {
|
|
73
|
+
const message = signal('', ...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
|
|
74
|
+
return {
|
|
75
|
+
message: message.asReadonly(),
|
|
76
|
+
announce(text) {
|
|
77
|
+
message.set(message() === text ? `${text} ` : text);
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
52
81
|
|
|
53
82
|
/**
|
|
54
83
|
* Canonical date/time value shapes shared by `uni-calendar`,
|
|
@@ -347,8 +376,9 @@ const joinDateTime = (date, time) => date && time ? `${date}T${time}` : undefine
|
|
|
347
376
|
* Extracted because three controls need the identical contract
|
|
348
377
|
* (`uni-search-input`, `uni-tag-input`, and the multi-select upgrade), and the
|
|
349
378
|
* parts that silently drift between hand-rolled copies all live here: the
|
|
350
|
-
* wrap-around arithmetic
|
|
351
|
-
*
|
|
379
|
+
* wrap-around arithmetic and keeping the active id in sync with the option
|
|
380
|
+
* list. Home/End are opt-in (`homeEndNavigates`) because a text field's caret
|
|
381
|
+
* has the better claim on them.
|
|
352
382
|
*
|
|
353
383
|
* `Enter` and `Escape` are deliberately *not* handled: what they mean depends
|
|
354
384
|
* on the control (submit a search, commit a typed token, clear the field), and
|
|
@@ -362,6 +392,7 @@ class ListboxNavigation {
|
|
|
362
392
|
_activeIndex = signal(-1, ...(ngDevMode ? [{ debugName: "_activeIndex" }] : /* istanbul ignore next */ []));
|
|
363
393
|
wrap;
|
|
364
394
|
isDisabled;
|
|
395
|
+
homeEndNavigates;
|
|
365
396
|
/** Whether the popup is showing. Also false when there is nothing to show. */
|
|
366
397
|
open = computed(() => this._open() && this.config.count() > 0, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
367
398
|
/** Index of the highlighted option, or -1 when none is active. */
|
|
@@ -380,6 +411,7 @@ class ListboxNavigation {
|
|
|
380
411
|
this.listboxId = uniqueId(config.idPrefix ?? 'uni-listbox');
|
|
381
412
|
this.wrap = config.wrap ?? true;
|
|
382
413
|
this.isDisabled = config.disabled ?? (() => false);
|
|
414
|
+
this.homeEndNavigates = config.homeEndNavigates ?? false;
|
|
383
415
|
}
|
|
384
416
|
/** Stable per-option id, for `role="option"` elements. */
|
|
385
417
|
optionId(index) {
|
|
@@ -397,9 +429,9 @@ class ListboxNavigation {
|
|
|
397
429
|
this._activeIndex.set(index);
|
|
398
430
|
}
|
|
399
431
|
/**
|
|
400
|
-
* Handle ArrowDown / ArrowUp
|
|
401
|
-
* Returns true when the key was consumed, so
|
|
402
|
-
* its own handling for everything else.
|
|
432
|
+
* Handle ArrowDown / ArrowUp — and Home / End where `homeEndNavigates` is
|
|
433
|
+
* on. Opens the popup if needed. Returns true when the key was consumed, so
|
|
434
|
+
* a caller can fall through to its own handling for everything else.
|
|
403
435
|
*/
|
|
404
436
|
navigate(event) {
|
|
405
437
|
const count = this.config.count();
|
|
@@ -421,10 +453,11 @@ class ListboxNavigation {
|
|
|
421
453
|
case 'ArrowUp':
|
|
422
454
|
// Opening with ArrowUp lands on the last option, matching menus.
|
|
423
455
|
return current < 0 ? this.seek(count - 1, -1, count) : this.step(current, -1, count);
|
|
456
|
+
// Left to the caret unless a consumer opts in — see `homeEndNavigates`.
|
|
424
457
|
case 'Home':
|
|
425
|
-
return this.seek(0, 1, count);
|
|
458
|
+
return this.homeEndNavigates ? this.seek(0, 1, count) : null;
|
|
426
459
|
case 'End':
|
|
427
|
-
return this.seek(count - 1, -1, count);
|
|
460
|
+
return this.homeEndNavigates ? this.seek(count - 1, -1, count) : null;
|
|
428
461
|
default:
|
|
429
462
|
return null;
|
|
430
463
|
}
|
|
@@ -637,13 +670,68 @@ function spotlightStyles(anchor, options = {}) {
|
|
|
637
670
|
cover: { ...blocker, ...holeInset(0) },
|
|
638
671
|
};
|
|
639
672
|
}
|
|
673
|
+
/**
|
|
674
|
+
* Transform origin for a panel's open/close scale animation, derived from
|
|
675
|
+
* where the panel **actually** rendered relative to its anchor — not from the
|
|
676
|
+
* requested placement. `position-try-fallbacks` lets the browser flip a panel
|
|
677
|
+
* at viewport edges, and a statically mapped origin then animates from the
|
|
678
|
+
* wrong corner (a `bottom-end` picker flipped above its field would still
|
|
679
|
+
* scale from `top right`). Measure after the popover is shown and apply the
|
|
680
|
+
* result as an inline style.
|
|
681
|
+
*
|
|
682
|
+
* Returns keyword pairs like `'top right'` / `'bottom center'`, or `null`
|
|
683
|
+
* when the panel has no box yet (e.g. `display: none`, or jsdom).
|
|
684
|
+
*/
|
|
685
|
+
function transformOriginFor(panel, trigger) {
|
|
686
|
+
if (!panel.width && !panel.height)
|
|
687
|
+
return null;
|
|
688
|
+
// Which side of the trigger the panel sits on wins; when it overlaps on an
|
|
689
|
+
// axis (aligned placements), the closer-aligned edge is the anchored one.
|
|
690
|
+
const axis = (panelStart, panelEnd, triggerStart, triggerEnd) => {
|
|
691
|
+
if (panelStart >= triggerEnd)
|
|
692
|
+
return 'start'; // panel after the trigger: grows away from its start edge
|
|
693
|
+
if (panelEnd <= triggerStart)
|
|
694
|
+
return 'end'; // panel before the trigger: grows toward its end edge
|
|
695
|
+
const startGap = Math.abs(panelStart - triggerStart);
|
|
696
|
+
const endGap = Math.abs(panelEnd - triggerEnd);
|
|
697
|
+
if (Math.abs(startGap - endGap) <= 1)
|
|
698
|
+
return 'center';
|
|
699
|
+
return startGap < endGap ? 'start' : 'end';
|
|
700
|
+
};
|
|
701
|
+
const y = axis(panel.top, panel.bottom, trigger.top, trigger.bottom);
|
|
702
|
+
const x = axis(panel.left, panel.right, trigger.left, trigger.right);
|
|
703
|
+
const vertical = y === 'start' ? 'top' : y === 'end' ? 'bottom' : 'center';
|
|
704
|
+
const horizontal = x === 'start' ? 'left' : x === 'end' ? 'right' : 'center';
|
|
705
|
+
return `${vertical} ${horizontal}`;
|
|
706
|
+
}
|
|
640
707
|
|
|
641
708
|
/**
|
|
642
709
|
* Shared plumbing for top-layer overlays built on the native `popover`
|
|
643
|
-
* attribute (dropdown, popover, callout
|
|
644
|
-
*
|
|
645
|
-
*
|
|
646
|
-
* sourced.
|
|
710
|
+
* attribute (dropdown, popover, callout, tooltip, the listbox popups,
|
|
711
|
+
* snackbar). Pure functions and data — no DOM ownership — so each component
|
|
712
|
+
* keeps its own template while the anchor bookkeeping, discrete-transition
|
|
713
|
+
* block, and focus-restore rule stay single-sourced.
|
|
714
|
+
*
|
|
715
|
+
* These are deliberately à-la-carte rather than one factory: the overlays
|
|
716
|
+
* share *mechanics* but not *lifecycles*. A dropdown toggles from a trigger
|
|
717
|
+
* click and restores focus; a tooltip follows hover and never takes focus; a
|
|
718
|
+
* callout traps focus behind a scrim; a listbox popup is rendered by `@if`
|
|
719
|
+
* with focus staying in the field; a snackbar has no anchor at all and closes
|
|
720
|
+
* on a timer. Take what a component needs and leave the rest.
|
|
721
|
+
*
|
|
722
|
+
* **Choosing `popover="auto"` vs `"manual"`** — the one decision worth making
|
|
723
|
+
* deliberately. `auto` brings native light-dismiss: an outside pointerdown or
|
|
724
|
+
* Escape closes it. That is right for a panel the user opened and can dismiss
|
|
725
|
+
* by looking away — dropdown, popover, callout, tooltip.
|
|
726
|
+
*
|
|
727
|
+
* `manual` is right when the control already owns dismissal, and light-dismiss
|
|
728
|
+
* would fight it. Two cases in this library:
|
|
729
|
+
* - the listbox popups, whose own field is *outside* the popup, so `auto`
|
|
730
|
+
* would close the list on every click into the input;
|
|
731
|
+
* - the snackbar, which would be torn away from someone still reading it by
|
|
732
|
+
* a click anywhere on the page.
|
|
733
|
+
*
|
|
734
|
+
* `manual` means the component must close it — nothing else will.
|
|
647
735
|
*/
|
|
648
736
|
/** Placement → `transform-origin`, so scale animations grow from the anchor. */
|
|
649
737
|
const TRANSFORM_ORIGINS = {
|
|
@@ -687,13 +775,20 @@ function isToggleOpen(event) {
|
|
|
687
775
|
* top layer: `transition-behavior: allow-discrete` over the `hidden` keys plus
|
|
688
776
|
* `display`/`overlay`, the shown state under `:popover-open`, and
|
|
689
777
|
* `@starting-style` so entry transitions run from the hidden state.
|
|
778
|
+
*
|
|
779
|
+
* `display` and `overlay` must ride along or the element cannot animate into
|
|
780
|
+
* and out of the top layer at all — it would simply appear and vanish.
|
|
781
|
+
*
|
|
782
|
+
* `timingFunction` is omitted from the output when not given, leaving the CSS
|
|
783
|
+
* initial value (`ease`), so callers that never asked for one are unaffected.
|
|
690
784
|
*/
|
|
691
|
-
function discreteOverlayTransition(durationMs, hidden, shown) {
|
|
785
|
+
function discreteOverlayTransition(durationMs, hidden, shown, timingFunction) {
|
|
692
786
|
return {
|
|
693
787
|
transitionProperty: [...Object.keys(hidden), 'display', 'overlay']
|
|
694
788
|
.map((key) => key.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`))
|
|
695
789
|
.join(', '),
|
|
696
790
|
transitionDuration: `${durationMs}ms`,
|
|
791
|
+
...(timingFunction ? { transitionTimingFunction: timingFunction } : {}),
|
|
697
792
|
transitionBehavior: 'allow-discrete',
|
|
698
793
|
...hidden,
|
|
699
794
|
'&:popover-open': shown,
|
|
@@ -1242,6 +1337,9 @@ class ThemeService {
|
|
|
1242
1337
|
borders = computed(() => this.theme().borders, ...(ngDevMode ? [{ debugName: "borders" }] : /* istanbul ignore next */ []));
|
|
1243
1338
|
shadows = computed(() => this.theme().shadows, ...(ngDevMode ? [{ debugName: "shadows" }] : /* istanbul ignore next */ []));
|
|
1244
1339
|
icons = computed(() => this.theme().icons, ...(ngDevMode ? [{ debugName: "icons" }] : /* istanbul ignore next */ []));
|
|
1340
|
+
// `?? {}` for themes registered as JSON that predate the motion scale —
|
|
1341
|
+
// the validator does not require it, so they must not crash on read.
|
|
1342
|
+
motions = computed(() => this.theme().motion ?? {}, ...(ngDevMode ? [{ debugName: "motions" }] : /* istanbul ignore next */ []));
|
|
1245
1343
|
constructor() {
|
|
1246
1344
|
// Honor the user's reduced-motion preference across every component
|
|
1247
1345
|
// (WCAG 2.3.3): collapse all animations/transitions to a single frame.
|
|
@@ -1479,6 +1577,16 @@ class ThemeService {
|
|
|
1479
1577
|
borderRadius,
|
|
1480
1578
|
};
|
|
1481
1579
|
}
|
|
1580
|
+
/**
|
|
1581
|
+
* Resolves a named motion primitive. Falls back to `popup` and then to a
|
|
1582
|
+
* hard default, so a theme that predates the motion scale — or names a
|
|
1583
|
+
* token that isn't there — still animates rather than snapping.
|
|
1584
|
+
*/
|
|
1585
|
+
motion(token) {
|
|
1586
|
+
const motions = this.motions();
|
|
1587
|
+
return ((token ? motions[token] : undefined) ??
|
|
1588
|
+
motions['popup'] ?? { duration: 100, easing: 'linear', scale: 0.8 });
|
|
1589
|
+
}
|
|
1482
1590
|
radius(size) {
|
|
1483
1591
|
return !size ? undefined : { borderRadius: this.radii()[size] };
|
|
1484
1592
|
}
|
|
@@ -2870,7 +2978,8 @@ class UniCalendarComponent extends BaseComponent {
|
|
|
2870
2978
|
/** Hover/focus candidate painting the preview band while a range is pending. */
|
|
2871
2979
|
previewDate = signal(null, ...(ngDevMode ? [{ debugName: "previewDate" }] : /* istanbul ignore next */ []));
|
|
2872
2980
|
/** Live-region text; selections are otherwise silent for a screen reader. */
|
|
2873
|
-
|
|
2981
|
+
/** Commits, clears and refusals are otherwise silent to a screen reader. */
|
|
2982
|
+
announcer = createAnnouncer();
|
|
2874
2983
|
resolvedLocale = computed(() => this.locale() ?? (document.documentElement.lang || navigator.language || 'en-US'), ...(ngDevMode ? [{ debugName: "resolvedLocale" }] : /* istanbul ignore next */ []));
|
|
2875
2984
|
resolvedWeekStart = computed(() => this.weekStart() ?? localeWeekStart(this.resolvedLocale()), ...(ngDevMode ? [{ debugName: "resolvedWeekStart" }] : /* istanbul ignore next */ []));
|
|
2876
2985
|
/**
|
|
@@ -3002,12 +3111,12 @@ class UniCalendarComponent extends BaseComponent {
|
|
|
3002
3111
|
const full = (d) => formatDate(d, locale, { dateStyle: 'full' });
|
|
3003
3112
|
if (this.mode() === 'single') {
|
|
3004
3113
|
this.value.set(date);
|
|
3005
|
-
this.announce(`${full(date)} selected.`);
|
|
3114
|
+
this.announcer.announce(`${full(date)} selected.`);
|
|
3006
3115
|
}
|
|
3007
3116
|
else if (!this.pendingStart()) {
|
|
3008
3117
|
this.pendingStart.set(date);
|
|
3009
3118
|
this.previewDate.set(date);
|
|
3010
|
-
this.announce(`Start date ${full(date)}. Choose an end date.`);
|
|
3119
|
+
this.announcer.announce(`Start date ${full(date)}. Choose an end date.`);
|
|
3011
3120
|
}
|
|
3012
3121
|
else {
|
|
3013
3122
|
let [start, end] = [this.pendingStart(), date];
|
|
@@ -3017,14 +3126,14 @@ class UniCalendarComponent extends BaseComponent {
|
|
|
3017
3126
|
this.previewDate.set(null);
|
|
3018
3127
|
this.value.set({ start, end });
|
|
3019
3128
|
const days = inclusiveDayCount(start, end);
|
|
3020
|
-
this.announce(`Range selected, ${full(start)} to ${full(end)}. ${days} ${days === 1 ? 'day' : 'days'}.`);
|
|
3129
|
+
this.announcer.announce(`Range selected, ${full(start)} to ${full(end)}. ${days} ${days === 1 ? 'day' : 'days'}.`);
|
|
3021
3130
|
}
|
|
3022
3131
|
this.selected.emit(date);
|
|
3023
3132
|
}
|
|
3024
3133
|
cancelPending() {
|
|
3025
3134
|
this.pendingStart.set(null);
|
|
3026
3135
|
this.previewDate.set(null);
|
|
3027
|
-
this.announce('Range selection cancelled.');
|
|
3136
|
+
this.announcer.announce('Range selection cancelled.');
|
|
3028
3137
|
}
|
|
3029
3138
|
// --- Navigation ------------------------------------------------------------
|
|
3030
3139
|
onNav(direction) {
|
|
@@ -3124,10 +3233,6 @@ class UniCalendarComponent extends BaseComponent {
|
|
|
3124
3233
|
}
|
|
3125
3234
|
return first;
|
|
3126
3235
|
}
|
|
3127
|
-
announce(message) {
|
|
3128
|
-
// Re-announce identical text by breaking the string equality.
|
|
3129
|
-
this.announcement.set(this.announcement() === message ? `${message} ` : message);
|
|
3130
|
-
}
|
|
3131
3236
|
// --- Styling ---------------------------------------------------------------
|
|
3132
3237
|
daySize = computed(() => (this.componentTheme().sizes?.[this.size()] ?? {}), ...(ngDevMode ? [{ debugName: "daySize" }] : /* istanbul ignore next */ []));
|
|
3133
3238
|
className = computed(() => css([(this.componentTheme().fixed ?? { display: 'inline-block' })]), ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
|
|
@@ -3260,11 +3365,11 @@ class UniCalendarComponent extends BaseComponent {
|
|
|
3260
3365
|
}
|
|
3261
3366
|
showOutside = computed(() => this.componentOptions().showOutsideDays ?? false, ...(ngDevMode ? [{ debugName: "showOutside" }] : /* istanbul ignore next */ []));
|
|
3262
3367
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniCalendarComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
3263
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniCalendarComponent, isStandalone: true, selector: "uni-calendar, Calendar", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, month: { classPropertyName: "month", publicName: "month", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null }, markers: { classPropertyName: "markers", publicName: "markers", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, weekStart: { classPropertyName: "weekStart", publicName: "weekStart", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange", month: "monthChange", selected: "selected" }, host: { listeners: { "focusout": "onHostFocusOut($event)" }, properties: { "class": "className()" } }, providers: [{ provide: COMPONENT_NAME, useValue: 'calendar' }], usesInheritance: true, ngImport: i0, template: "<div [class]=\"navClass()\">\n <button\n icon-button\n type=\"button\"\n size=\"sm\"\n [symbolName]=\"componentOptions().navPrevSymbol ?? 'chevron_left'\"\n [disable]=\"disabled()\"\n (click)=\"onNav(-1)\"\n >\n Previous month\n </button>\n <!-- aria-live so PageUp/Down narrates the new month without refocusing. -->\n <div [class]=\"headingClass()\" [id]=\"headingId\" aria-live=\"polite\">{{ heading() }}</div>\n <button\n icon-button\n type=\"button\"\n size=\"sm\"\n [symbolName]=\"componentOptions().navNextSymbol ?? 'chevron_right'\"\n [disable]=\"disabled()\"\n (click)=\"onNav(1)\"\n >\n Next month\n </button>\n</div>\n\n<!-- One tab stop: the roving tabindex lives on the day buttons, and the grid\n itself only relays their bubbling keys (same delegation as tag-input). -->\n<!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n<div\n role=\"grid\"\n [class]=\"gridClass()\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabel() ? null : headingId\"\n [attr.aria-describedby]=\"ariaDescribedBy() ?? null\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onGridKeydown($event)\"\n>\n <div role=\"row\" [class]=\"rowClass()\">\n @for (weekday of weekdays(); track weekday.full) {\n <div role=\"columnheader\" [class]=\"weekdayClass()\">\n <abbr [attr.title]=\"weekday.full\">{{ weekday.label }}</abbr>\n </div>\n }\n </div>\n\n @for (week of gridWeeks(); track week[0].date) {\n <div role=\"row\" [class]=\"rowClass()\">\n @for (cell of week; track cell.date) {\n @if (cell.outside) {\n <!-- Outside days: hidden placeholders by default (geometry kept),\n muted and non-interactive under the showOutsideDays option. -->\n <div role=\"gridcell\" aria-hidden=\"true\" [class]=\"cell.cellClass\">\n @if (showOutside()) {\n <span [class]=\"outsideDayClass()\">{{ cell.day }}</span>\n }\n </div>\n } @else {\n <div\n role=\"gridcell\"\n [class]=\"cell.cellClass\"\n [attr.aria-selected]=\"cell.selected || cell.inBand ? true : null\"\n >\n <button\n type=\"button\"\n [class]=\"cell.dayClass\"\n [attr.data-date]=\"cell.date\"\n [tabindex]=\"cell.tabIndex\"\n [attr.aria-label]=\"cell.ariaLabel\"\n [attr.aria-current]=\"cell.today ? 'date' : null\"\n [disabled]=\"cell.disabled || disabled()\"\n (click)=\"select(cell.date)\"\n (mouseenter)=\"onDayHover(cell.date)\"\n >\n {{ cell.day }}\n @if (cell.markers.length) {\n <span [class]=\"dotsClass()\">\n @for (marker of cell.markers; track $index) {\n <span data-dot [class]=\"dotClassFor(marker.variant)\"></span>\n }\n </span>\n }\n </button>\n </div>\n }\n }\n </div>\n }\n</div>\n\n<!-- Selections and range progress are otherwise silent for a screen reader. -->\n<span role=\"status\" aria-live=\"polite\" [class]=\"srOnly\">{{
|
|
3368
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniCalendarComponent, isStandalone: true, selector: "uni-calendar, Calendar", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, month: { classPropertyName: "month", publicName: "month", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null }, markers: { classPropertyName: "markers", publicName: "markers", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, weekStart: { classPropertyName: "weekStart", publicName: "weekStart", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange", month: "monthChange", selected: "selected" }, host: { listeners: { "focusout": "onHostFocusOut($event)" }, properties: { "class": "className()" } }, providers: [{ provide: COMPONENT_NAME, useValue: 'calendar' }], usesInheritance: true, ngImport: i0, template: "<div [class]=\"navClass()\">\n <button\n icon-button\n type=\"button\"\n size=\"sm\"\n [symbolName]=\"componentOptions().navPrevSymbol ?? 'chevron_left'\"\n [disable]=\"disabled()\"\n (click)=\"onNav(-1)\"\n >\n Previous month\n </button>\n <!-- aria-live so PageUp/Down narrates the new month without refocusing. -->\n <div [class]=\"headingClass()\" [id]=\"headingId\" aria-live=\"polite\">{{ heading() }}</div>\n <button\n icon-button\n type=\"button\"\n size=\"sm\"\n [symbolName]=\"componentOptions().navNextSymbol ?? 'chevron_right'\"\n [disable]=\"disabled()\"\n (click)=\"onNav(1)\"\n >\n Next month\n </button>\n</div>\n\n<!-- One tab stop: the roving tabindex lives on the day buttons, and the grid\n itself only relays their bubbling keys (same delegation as tag-input). -->\n<!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n<div\n role=\"grid\"\n [class]=\"gridClass()\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabel() ? null : headingId\"\n [attr.aria-describedby]=\"ariaDescribedBy() ?? null\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onGridKeydown($event)\"\n>\n <div role=\"row\" [class]=\"rowClass()\">\n @for (weekday of weekdays(); track weekday.full) {\n <div role=\"columnheader\" [class]=\"weekdayClass()\">\n <abbr [attr.title]=\"weekday.full\">{{ weekday.label }}</abbr>\n </div>\n }\n </div>\n\n @for (week of gridWeeks(); track week[0].date) {\n <div role=\"row\" [class]=\"rowClass()\">\n @for (cell of week; track cell.date) {\n @if (cell.outside) {\n <!-- Outside days: hidden placeholders by default (geometry kept),\n muted and non-interactive under the showOutsideDays option. -->\n <div role=\"gridcell\" aria-hidden=\"true\" [class]=\"cell.cellClass\">\n @if (showOutside()) {\n <span [class]=\"outsideDayClass()\">{{ cell.day }}</span>\n }\n </div>\n } @else {\n <div\n role=\"gridcell\"\n [class]=\"cell.cellClass\"\n [attr.aria-selected]=\"cell.selected || cell.inBand ? true : null\"\n >\n <button\n type=\"button\"\n [class]=\"cell.dayClass\"\n [attr.data-date]=\"cell.date\"\n [tabindex]=\"cell.tabIndex\"\n [attr.aria-label]=\"cell.ariaLabel\"\n [attr.aria-current]=\"cell.today ? 'date' : null\"\n [disabled]=\"cell.disabled || disabled()\"\n (click)=\"select(cell.date)\"\n (mouseenter)=\"onDayHover(cell.date)\"\n >\n {{ cell.day }}\n @if (cell.markers.length) {\n <span [class]=\"dotsClass()\">\n @for (marker of cell.markers; track $index) {\n <span data-dot [class]=\"dotClassFor(marker.variant)\"></span>\n }\n </span>\n }\n </button>\n </div>\n }\n }\n </div>\n }\n</div>\n\n<!-- Selections and range progress are otherwise silent for a screen reader. -->\n<span role=\"status\" aria-live=\"polite\" [class]=\"srOnly\">{{ announcer.message() }}</span>\n", dependencies: [{ kind: "component", type: UniIconButtonComponent, selector: "button[uni-icon-button], button[icon-button]", inputs: ["ariaLabel", "iconName", "symbolName", "variant", "size", "disable", "loading", "opticalSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3264
3369
|
}
|
|
3265
3370
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniCalendarComponent, decorators: [{
|
|
3266
3371
|
type: Component,
|
|
3267
|
-
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'uni-calendar, Calendar', imports: [UniIconButtonComponent], providers: [{ provide: COMPONENT_NAME, useValue: 'calendar' }], host: { '[class]': 'className()', '(focusout)': 'onHostFocusOut($event)' }, template: "<div [class]=\"navClass()\">\n <button\n icon-button\n type=\"button\"\n size=\"sm\"\n [symbolName]=\"componentOptions().navPrevSymbol ?? 'chevron_left'\"\n [disable]=\"disabled()\"\n (click)=\"onNav(-1)\"\n >\n Previous month\n </button>\n <!-- aria-live so PageUp/Down narrates the new month without refocusing. -->\n <div [class]=\"headingClass()\" [id]=\"headingId\" aria-live=\"polite\">{{ heading() }}</div>\n <button\n icon-button\n type=\"button\"\n size=\"sm\"\n [symbolName]=\"componentOptions().navNextSymbol ?? 'chevron_right'\"\n [disable]=\"disabled()\"\n (click)=\"onNav(1)\"\n >\n Next month\n </button>\n</div>\n\n<!-- One tab stop: the roving tabindex lives on the day buttons, and the grid\n itself only relays their bubbling keys (same delegation as tag-input). -->\n<!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n<div\n role=\"grid\"\n [class]=\"gridClass()\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabel() ? null : headingId\"\n [attr.aria-describedby]=\"ariaDescribedBy() ?? null\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onGridKeydown($event)\"\n>\n <div role=\"row\" [class]=\"rowClass()\">\n @for (weekday of weekdays(); track weekday.full) {\n <div role=\"columnheader\" [class]=\"weekdayClass()\">\n <abbr [attr.title]=\"weekday.full\">{{ weekday.label }}</abbr>\n </div>\n }\n </div>\n\n @for (week of gridWeeks(); track week[0].date) {\n <div role=\"row\" [class]=\"rowClass()\">\n @for (cell of week; track cell.date) {\n @if (cell.outside) {\n <!-- Outside days: hidden placeholders by default (geometry kept),\n muted and non-interactive under the showOutsideDays option. -->\n <div role=\"gridcell\" aria-hidden=\"true\" [class]=\"cell.cellClass\">\n @if (showOutside()) {\n <span [class]=\"outsideDayClass()\">{{ cell.day }}</span>\n }\n </div>\n } @else {\n <div\n role=\"gridcell\"\n [class]=\"cell.cellClass\"\n [attr.aria-selected]=\"cell.selected || cell.inBand ? true : null\"\n >\n <button\n type=\"button\"\n [class]=\"cell.dayClass\"\n [attr.data-date]=\"cell.date\"\n [tabindex]=\"cell.tabIndex\"\n [attr.aria-label]=\"cell.ariaLabel\"\n [attr.aria-current]=\"cell.today ? 'date' : null\"\n [disabled]=\"cell.disabled || disabled()\"\n (click)=\"select(cell.date)\"\n (mouseenter)=\"onDayHover(cell.date)\"\n >\n {{ cell.day }}\n @if (cell.markers.length) {\n <span [class]=\"dotsClass()\">\n @for (marker of cell.markers; track $index) {\n <span data-dot [class]=\"dotClassFor(marker.variant)\"></span>\n }\n </span>\n }\n </button>\n </div>\n }\n }\n </div>\n }\n</div>\n\n<!-- Selections and range progress are otherwise silent for a screen reader. -->\n<span role=\"status\" aria-live=\"polite\" [class]=\"srOnly\">{{
|
|
3372
|
+
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'uni-calendar, Calendar', imports: [UniIconButtonComponent], providers: [{ provide: COMPONENT_NAME, useValue: 'calendar' }], host: { '[class]': 'className()', '(focusout)': 'onHostFocusOut($event)' }, template: "<div [class]=\"navClass()\">\n <button\n icon-button\n type=\"button\"\n size=\"sm\"\n [symbolName]=\"componentOptions().navPrevSymbol ?? 'chevron_left'\"\n [disable]=\"disabled()\"\n (click)=\"onNav(-1)\"\n >\n Previous month\n </button>\n <!-- aria-live so PageUp/Down narrates the new month without refocusing. -->\n <div [class]=\"headingClass()\" [id]=\"headingId\" aria-live=\"polite\">{{ heading() }}</div>\n <button\n icon-button\n type=\"button\"\n size=\"sm\"\n [symbolName]=\"componentOptions().navNextSymbol ?? 'chevron_right'\"\n [disable]=\"disabled()\"\n (click)=\"onNav(1)\"\n >\n Next month\n </button>\n</div>\n\n<!-- One tab stop: the roving tabindex lives on the day buttons, and the grid\n itself only relays their bubbling keys (same delegation as tag-input). -->\n<!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n<div\n role=\"grid\"\n [class]=\"gridClass()\"\n [attr.aria-label]=\"ariaLabel() ?? null\"\n [attr.aria-labelledby]=\"ariaLabel() ? null : headingId\"\n [attr.aria-describedby]=\"ariaDescribedBy() ?? null\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onGridKeydown($event)\"\n>\n <div role=\"row\" [class]=\"rowClass()\">\n @for (weekday of weekdays(); track weekday.full) {\n <div role=\"columnheader\" [class]=\"weekdayClass()\">\n <abbr [attr.title]=\"weekday.full\">{{ weekday.label }}</abbr>\n </div>\n }\n </div>\n\n @for (week of gridWeeks(); track week[0].date) {\n <div role=\"row\" [class]=\"rowClass()\">\n @for (cell of week; track cell.date) {\n @if (cell.outside) {\n <!-- Outside days: hidden placeholders by default (geometry kept),\n muted and non-interactive under the showOutsideDays option. -->\n <div role=\"gridcell\" aria-hidden=\"true\" [class]=\"cell.cellClass\">\n @if (showOutside()) {\n <span [class]=\"outsideDayClass()\">{{ cell.day }}</span>\n }\n </div>\n } @else {\n <div\n role=\"gridcell\"\n [class]=\"cell.cellClass\"\n [attr.aria-selected]=\"cell.selected || cell.inBand ? true : null\"\n >\n <button\n type=\"button\"\n [class]=\"cell.dayClass\"\n [attr.data-date]=\"cell.date\"\n [tabindex]=\"cell.tabIndex\"\n [attr.aria-label]=\"cell.ariaLabel\"\n [attr.aria-current]=\"cell.today ? 'date' : null\"\n [disabled]=\"cell.disabled || disabled()\"\n (click)=\"select(cell.date)\"\n (mouseenter)=\"onDayHover(cell.date)\"\n >\n {{ cell.day }}\n @if (cell.markers.length) {\n <span [class]=\"dotsClass()\">\n @for (marker of cell.markers; track $index) {\n <span data-dot [class]=\"dotClassFor(marker.variant)\"></span>\n }\n </span>\n }\n </button>\n </div>\n }\n }\n </div>\n }\n</div>\n\n<!-- Selections and range progress are otherwise silent for a screen reader. -->\n<span role=\"status\" aria-live=\"polite\" [class]=\"srOnly\">{{ announcer.message() }}</span>\n" }]
|
|
3268
3373
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], month: [{ type: i0.Input, args: [{ isSignal: true, alias: "month", required: false }] }, { type: i0.Output, args: ["monthChange"] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], disabledDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDates", required: false }] }], markers: [{ type: i0.Input, args: [{ isSignal: true, alias: "markers", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], weekStart: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekStart", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], selected: [{ type: i0.Output, args: ["selected"] }] } });
|
|
3269
3374
|
|
|
3270
3375
|
/**
|
|
@@ -3432,7 +3537,7 @@ class UniCalloutComponent extends BaseComponent {
|
|
|
3432
3537
|
clearAnchorName(target);
|
|
3433
3538
|
this.activeTarget.set(null);
|
|
3434
3539
|
this.scrimContent.set(false);
|
|
3435
|
-
}, this.
|
|
3540
|
+
}, this.motion().duration);
|
|
3436
3541
|
// The duet loop may have sent the user into the target on purpose — don't
|
|
3437
3542
|
// yank them back out of it.
|
|
3438
3543
|
if (!focusInTarget && this.prevFocus && document.contains(this.prevFocus)) {
|
|
@@ -3545,8 +3650,20 @@ class UniCalloutComponent extends BaseComponent {
|
|
|
3545
3650
|
scrimColor: options.scrimColor,
|
|
3546
3651
|
});
|
|
3547
3652
|
}, ...(ngDevMode ? [{ debugName: "spotlight" }] : /* istanbul ignore next */ []));
|
|
3548
|
-
|
|
3653
|
+
/**
|
|
3654
|
+
* Timing for the open/close fade and the teardown that follows it. The
|
|
3655
|
+
* deprecated `transitionMs` wins when a theme still sets it, so existing
|
|
3656
|
+
* themes keep their timing; otherwise the `motion` token decides.
|
|
3657
|
+
*/
|
|
3658
|
+
motion = computed(() => {
|
|
3549
3659
|
const options = this.componentOptions();
|
|
3660
|
+
const token = this.theme.motion(options.motion ?? 'panel');
|
|
3661
|
+
return options.transitionMs === undefined
|
|
3662
|
+
? token
|
|
3663
|
+
: { ...token, duration: options.transitionMs };
|
|
3664
|
+
}, ...(ngDevMode ? [{ debugName: "motion" }] : /* istanbul ignore next */ []));
|
|
3665
|
+
scrimClassName = computed(() => {
|
|
3666
|
+
const motion = this.motion();
|
|
3550
3667
|
return css({
|
|
3551
3668
|
position: 'fixed',
|
|
3552
3669
|
inset: 0,
|
|
@@ -3559,7 +3676,7 @@ class UniCalloutComponent extends BaseComponent {
|
|
|
3559
3676
|
overflow: 'visible',
|
|
3560
3677
|
pointerEvents: 'none',
|
|
3561
3678
|
'& > *': { position: 'fixed' },
|
|
3562
|
-
...discreteOverlayTransition(
|
|
3679
|
+
...discreteOverlayTransition(motion.duration, { opacity: 0 }, { opacity: 1 }, motion.easing),
|
|
3563
3680
|
});
|
|
3564
3681
|
}, ...(ngDevMode ? [{ debugName: "scrimClassName" }] : /* istanbul ignore next */ []));
|
|
3565
3682
|
windowClassName = computed(() => {
|
|
@@ -3581,6 +3698,7 @@ class UniCalloutComponent extends BaseComponent {
|
|
|
3581
3698
|
}), ...(ngDevMode ? [{ debugName: "fullCoverClassName" }] : /* istanbul ignore next */ []));
|
|
3582
3699
|
panelClassName = computed(() => {
|
|
3583
3700
|
const options = this.componentOptions();
|
|
3701
|
+
const motion = this.motion();
|
|
3584
3702
|
const anchored = this.activeTarget() !== null;
|
|
3585
3703
|
return css({
|
|
3586
3704
|
...this.theme.colorPair(options.color),
|
|
@@ -3599,7 +3717,7 @@ class UniCalloutComponent extends BaseComponent {
|
|
|
3599
3717
|
mainAxis: options.offset + options.spotlightPadding,
|
|
3600
3718
|
})
|
|
3601
3719
|
: {}),
|
|
3602
|
-
...discreteOverlayTransition(
|
|
3720
|
+
...discreteOverlayTransition(motion.duration, { opacity: 0, translate: '0 6px' }, { opacity: 1, translate: '0 0' }, motion.easing),
|
|
3603
3721
|
});
|
|
3604
3722
|
}, ...(ngDevMode ? [{ debugName: "panelClassName" }] : /* istanbul ignore next */ []));
|
|
3605
3723
|
headRowClassName = computed(() => {
|
|
@@ -3914,9 +4032,105 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
3914
4032
|
}], propDecorators: { checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }, { type: i0.Output, args: ["indeterminateChange"] }] } });
|
|
3915
4033
|
|
|
3916
4034
|
/**
|
|
3917
|
-
*
|
|
3918
|
-
*
|
|
3919
|
-
*
|
|
4035
|
+
* Whether the browser can keep a top-layer popup attached to its field.
|
|
4036
|
+
*
|
|
4037
|
+
* The top layer and anchor positioning must be adopted together, and support
|
|
4038
|
+
* for them does not arrive together: Safari shipped `popover` in 17 but
|
|
4039
|
+
* `position-anchor` only in 26. Promoting the popup without anchor support
|
|
4040
|
+
* would strand it — a top-layer element has no positioned ancestor, so the
|
|
4041
|
+
* fallback's `position: absolute; top: 100%` would resolve against the
|
|
4042
|
+
* viewport and drop the list a full screen height down the page. So the
|
|
4043
|
+
* `popover` attribute is gated on this too, not just the anchored CSS.
|
|
4044
|
+
*
|
|
4045
|
+
* Undefined `CSS` (jsdom) reads as unsupported, which is also what keeps the
|
|
4046
|
+
* popup in the normal flow — and the component specs unchanged — under test.
|
|
4047
|
+
*/
|
|
4048
|
+
const supportsAnchoredPopup = () => typeof CSS !== 'undefined' && CSS.supports?.('position-anchor: --a') === true;
|
|
4049
|
+
/** `popover` attribute value for a listbox popup, or null where unsupported.
|
|
4050
|
+
Always `manual`: these controls already own dismissal (focusout, Escape,
|
|
4051
|
+
commit), and `auto`'s light-dismiss fires on pointerdown outside the
|
|
4052
|
+
popup — which includes their own field, closing the list behind the
|
|
4053
|
+
component's back on every click into the input. */
|
|
4054
|
+
const listboxPopupAttr = () => supportsAnchoredPopup() ? 'manual' : null;
|
|
4055
|
+
/**
|
|
4056
|
+
* A document-unique `anchor-name`, plus the style fragment that puts it on the
|
|
4057
|
+
* field wrapper. Spread `style` into the wrapper's `css()` and pass `name` to
|
|
4058
|
+
* {@link listboxPopupStyles}.
|
|
4059
|
+
*/
|
|
4060
|
+
function newListboxAnchor() {
|
|
4061
|
+
const name = newAnchorName();
|
|
4062
|
+
return { name, style: { anchorName: name } };
|
|
4063
|
+
}
|
|
4064
|
+
/**
|
|
4065
|
+
* Shows the popup in the top layer as soon as it renders, and scales its
|
|
4066
|
+
* entry animation out of the edge it actually opened from.
|
|
4067
|
+
*
|
|
4068
|
+
* The popups are `@if`-rendered, and a `popover` element is `display: none`
|
|
4069
|
+
* until `showPopover()` runs — so appearing in the DOM is not enough. Runs on
|
|
4070
|
+
* every render pass; `showPopover()` on an already-open popup throws, which is
|
|
4071
|
+
* the cheapest way to ask "is it open?".
|
|
4072
|
+
*
|
|
4073
|
+
* The origin is measured rather than assumed: `position-try-fallbacks` may
|
|
4074
|
+
* have flipped the popup above its field near the bottom of the viewport, and
|
|
4075
|
+
* the static `top center` would then grow it from the wrong edge. Measuring
|
|
4076
|
+
* forces layout, so it lands before the first frame of the transition.
|
|
4077
|
+
*
|
|
4078
|
+
* Call from an injection context (a field initializer or the constructor);
|
|
4079
|
+
* the component's host element is the anchor.
|
|
4080
|
+
*/
|
|
4081
|
+
function promoteListboxPopup(ref) {
|
|
4082
|
+
const anchor = inject(ElementRef).nativeElement;
|
|
4083
|
+
afterRenderEffect(() => {
|
|
4084
|
+
const element = ref()?.nativeElement;
|
|
4085
|
+
// The attribute, not the `popover` IDL property: the property is what the
|
|
4086
|
+
// gate already decided, and jsdom does not reflect it.
|
|
4087
|
+
if (!element?.isConnected || !element.hasAttribute('popover'))
|
|
4088
|
+
return;
|
|
4089
|
+
try {
|
|
4090
|
+
element.showPopover();
|
|
4091
|
+
}
|
|
4092
|
+
catch {
|
|
4093
|
+
return; // Already open — its origin was set when it opened.
|
|
4094
|
+
}
|
|
4095
|
+
const origin = transformOriginFor(element.getBoundingClientRect(), anchor.getBoundingClientRect());
|
|
4096
|
+
if (origin)
|
|
4097
|
+
element.style.transformOrigin = origin;
|
|
4098
|
+
});
|
|
4099
|
+
}
|
|
4100
|
+
/**
|
|
4101
|
+
* The anchored half: the popup in the top layer, tracked to its field by the
|
|
4102
|
+
* browser with no scroll or resize listeners. This is what lets the list
|
|
4103
|
+
* escape an `overflow: hidden` ancestor, which the in-flow fallback below
|
|
4104
|
+
* cannot do.
|
|
4105
|
+
*
|
|
4106
|
+
* `anchor-size(width)` matches the field's width the way `left: 0; right: 0`
|
|
4107
|
+
* did in flow. Only the block flip is offered: the popup is as wide as its
|
|
4108
|
+
* own field, so flipping it inline would only slide it off that field.
|
|
4109
|
+
*
|
|
4110
|
+
* `border: none` drops the UA's `[popover]` border. Its `background-color:
|
|
4111
|
+
* Canvas` needs no reset — the base rules' `colorPair` beats it on origin
|
|
4112
|
+
* alone — and must not get one: `background` is a shorthand, so resetting it
|
|
4113
|
+
* here would erase that painted surface and leave the list transparent.
|
|
4114
|
+
*
|
|
4115
|
+
* `border-box` keeps the popup exactly as wide as its field: `anchor-size`
|
|
4116
|
+
* yields the anchor's border-box width, which the base rules' padding would
|
|
4117
|
+
* otherwise widen by 8px.
|
|
4118
|
+
*/
|
|
4119
|
+
const anchoredPopupStyles = (anchor, motion) => ({
|
|
4120
|
+
...anchorStyles(anchor, 'bottom-start', { mainAxis: 4 }),
|
|
4121
|
+
positionTryFallbacks: 'flip-block',
|
|
4122
|
+
width: 'anchor-size(width)',
|
|
4123
|
+
boxSizing: 'border-box',
|
|
4124
|
+
border: 'none',
|
|
4125
|
+
// Grows out of the field's bottom edge; corrected after measuring when the
|
|
4126
|
+
// browser flips the popup above instead (see promoteListboxPopup).
|
|
4127
|
+
transformOrigin: 'top center',
|
|
4128
|
+
...motionSafe(discreteOverlayTransition(motion.duration, { opacity: 0, transform: `scale(${motion.scale ?? 1})` }, { opacity: 1, transform: 'scale(1)' }, motion.easing)),
|
|
4129
|
+
});
|
|
4130
|
+
/**
|
|
4131
|
+
* Style block for the popup behind every `ListboxNavigation` consumer: a
|
|
4132
|
+
* `ul[role="listbox"]` under its field wrapper, with the shared option chrome
|
|
4133
|
+
* and active/hover highlight.
|
|
3920
4134
|
*
|
|
3921
4135
|
* Extracted because four components (`uni-search-input`, `uni-tag-input`,
|
|
3922
4136
|
* `uni-time-input`, `uni-combobox`) carried hand-rolled copies, and the parts
|
|
@@ -3924,11 +4138,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
3924
4138
|
* trio, and the `activeColor` pair that themes re-point when their container
|
|
3925
4139
|
* tokens don't contrast (see the Wellsourced overrides).
|
|
3926
4140
|
*
|
|
4141
|
+
* Pass `anchor` (from {@link newListboxAnchor}) to get the top-layer
|
|
4142
|
+
* positioning where the browser supports it. Without it — or on a browser that
|
|
4143
|
+
* lacks anchor positioning — the popup stays absolutely positioned under a
|
|
4144
|
+
* `position: relative` wrapper, which clips inside `overflow: hidden`
|
|
4145
|
+
* ancestors but at least stays on its field.
|
|
4146
|
+
*
|
|
3927
4147
|
* Compose extras with the array form — `css([listboxPopupStyles(…), {…}])` —
|
|
3928
4148
|
* so a component's own `& [role="option"]` block cascades after this one
|
|
3929
4149
|
* instead of replacing it (an object spread would overwrite the key).
|
|
3930
4150
|
*/
|
|
3931
|
-
const listboxPopupStyles = (theme, options, { maxHeight = 280 } = {}) => ({
|
|
4151
|
+
const listboxPopupStyles = (theme, options, { maxHeight = 280, anchor } = {}) => ({
|
|
3932
4152
|
position: 'absolute',
|
|
3933
4153
|
top: '100%',
|
|
3934
4154
|
left: 0,
|
|
@@ -3951,6 +4171,10 @@ const listboxPopupStyles = (theme, options, { maxHeight = 280 } = {}) => ({
|
|
|
3951
4171
|
...theme.colorPair((options.activeColor ?? 'primary-container')),
|
|
3952
4172
|
},
|
|
3953
4173
|
},
|
|
4174
|
+
// Last, so the anchored rules win over the in-flow ones they replace.
|
|
4175
|
+
...(anchor
|
|
4176
|
+
? { '@supports (position-anchor: --a)': anchoredPopupStyles(anchor, theme.motion(options.motion)) }
|
|
4177
|
+
: {}),
|
|
3954
4178
|
});
|
|
3955
4179
|
|
|
3956
4180
|
class UniInputBoxComponent extends BaseComponent {
|
|
@@ -4073,12 +4297,18 @@ class UniComboboxComponent extends BaseComponent {
|
|
|
4073
4297
|
listRef = viewChild('listbox', ...(ngDevMode ? [{ debugName: "listRef" }] : /* istanbul ignore next */ []));
|
|
4074
4298
|
/** Cancelled on destroy — a late tick would emit on a destroyed OutputRef. */
|
|
4075
4299
|
queryTimer;
|
|
4300
|
+
/** Ties the popup to the field so the browser tracks it in the top layer. */
|
|
4301
|
+
anchor = newListboxAnchor();
|
|
4302
|
+
/** `manual` where the top layer is usable, else null — see the popup helper. */
|
|
4303
|
+
popupAttr = listboxPopupAttr();
|
|
4076
4304
|
constructor() {
|
|
4077
4305
|
super();
|
|
4078
4306
|
inject(DestroyRef).onDestroy(() => clearTimeout(this.queryTimer));
|
|
4307
|
+
promoteListboxPopup(this.listRef);
|
|
4079
4308
|
}
|
|
4080
4309
|
srOnly = css(visuallyHidden);
|
|
4081
|
-
|
|
4310
|
+
/** Commits, clears and refusals are otherwise silent to a screen reader. */
|
|
4311
|
+
announcer = createAnnouncer();
|
|
4082
4312
|
/** null → the field shows the committed label; a string is an uncommitted draft. */
|
|
4083
4313
|
draft = signal(null, ...(ngDevMode ? [{ debugName: "draft" }] : /* istanbul ignore next */ []));
|
|
4084
4314
|
/**
|
|
@@ -4129,7 +4359,7 @@ class UniComboboxComponent extends BaseComponent {
|
|
|
4129
4359
|
this.draft.set(null);
|
|
4130
4360
|
this.closeList();
|
|
4131
4361
|
this.setFieldText(this.displayValue());
|
|
4132
|
-
this.announce(`${option.label} selected.`);
|
|
4362
|
+
this.announcer.announce(`${option.label} selected.`);
|
|
4133
4363
|
this.selected.emit(option);
|
|
4134
4364
|
return true;
|
|
4135
4365
|
}
|
|
@@ -4138,7 +4368,7 @@ class UniComboboxComponent extends BaseComponent {
|
|
|
4138
4368
|
this.draft.set(null);
|
|
4139
4369
|
this.closeList();
|
|
4140
4370
|
this.setFieldText('');
|
|
4141
|
-
this.announce('Selection cleared.');
|
|
4371
|
+
this.announcer.announce('Selection cleared.');
|
|
4142
4372
|
this.cleared.emit();
|
|
4143
4373
|
this.inputRef().nativeElement.focus();
|
|
4144
4374
|
}
|
|
@@ -4166,7 +4396,7 @@ class UniComboboxComponent extends BaseComponent {
|
|
|
4166
4396
|
// clearable fields may null the model this way.
|
|
4167
4397
|
if (this.clearable() && this.value() !== null && !enterOnly) {
|
|
4168
4398
|
this.value.set(null);
|
|
4169
|
-
this.announce('Selection cleared.');
|
|
4399
|
+
this.announcer.announce('Selection cleared.');
|
|
4170
4400
|
this.cleared.emit();
|
|
4171
4401
|
}
|
|
4172
4402
|
this.draft.set(null);
|
|
@@ -4197,7 +4427,7 @@ class UniComboboxComponent extends BaseComponent {
|
|
|
4197
4427
|
reject() {
|
|
4198
4428
|
const query = this.revertDraft();
|
|
4199
4429
|
if (query) {
|
|
4200
|
-
this.announce(`No match for “${query}”.`);
|
|
4430
|
+
this.announcer.announce(`No match for “${query}”.`);
|
|
4201
4431
|
this.rejected.emit({ query });
|
|
4202
4432
|
}
|
|
4203
4433
|
}
|
|
@@ -4233,12 +4463,9 @@ class UniComboboxComponent extends BaseComponent {
|
|
|
4233
4463
|
this.scrollToActive();
|
|
4234
4464
|
return;
|
|
4235
4465
|
}
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
this.scrollToActive();
|
|
4240
|
-
return;
|
|
4241
|
-
}
|
|
4466
|
+
// Home/End are deliberately absent: they belong to the caret, even with
|
|
4467
|
+
// the list open (APG's editable-combobox pattern). ArrowUp on a closed
|
|
4468
|
+
// list already lands on the last option, so nothing is lost.
|
|
4242
4469
|
switch (event.key) {
|
|
4243
4470
|
case 'Enter':
|
|
4244
4471
|
// Never submits a form while the list is open.
|
|
@@ -4246,7 +4473,7 @@ class UniComboboxComponent extends BaseComponent {
|
|
|
4246
4473
|
event.preventDefault();
|
|
4247
4474
|
if (!this.resolveDraft(true)) {
|
|
4248
4475
|
const count = this.filteredIndices().length;
|
|
4249
|
-
this.announce(count === 0 ? `${this.emptyText()}.` : `${count} results. Use the arrow keys.`);
|
|
4476
|
+
this.announcer.announce(count === 0 ? `${this.emptyText()}.` : `${count} results. Use the arrow keys.`);
|
|
4250
4477
|
}
|
|
4251
4478
|
return;
|
|
4252
4479
|
case 'Escape':
|
|
@@ -4278,7 +4505,7 @@ class UniComboboxComponent extends BaseComponent {
|
|
|
4278
4505
|
// Filtering is otherwise silent to a screen reader.
|
|
4279
4506
|
if (this.filterLocally() && text !== '') {
|
|
4280
4507
|
const count = this.filteredIndices().length;
|
|
4281
|
-
this.announce(count === 0 ? `${this.emptyText()}.` : `${count} result${count === 1 ? '' : 's'}.`);
|
|
4508
|
+
this.announcer.announce(count === 0 ? `${this.emptyText()}.` : `${count} result${count === 1 ? '' : 's'}.`);
|
|
4282
4509
|
}
|
|
4283
4510
|
}, this.debounceTime());
|
|
4284
4511
|
}
|
|
@@ -4346,12 +4573,8 @@ class UniComboboxComponent extends BaseComponent {
|
|
|
4346
4573
|
if (element)
|
|
4347
4574
|
element.value = text;
|
|
4348
4575
|
}
|
|
4349
|
-
announce(message) {
|
|
4350
|
-
// Re-announce identical text by breaking the string equality.
|
|
4351
|
-
this.announcement.set(this.announcement() === message ? `${message} ` : message);
|
|
4352
|
-
}
|
|
4353
4576
|
// --- Styling ----------------------------------------------------------------
|
|
4354
|
-
className = computed(() => css({ display: 'block', position: 'relative', width: this.width() }), ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
|
|
4577
|
+
className = computed(() => css({ display: 'block', position: 'relative', width: this.width(), ...this.anchor.style }), ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
|
|
4355
4578
|
rowClass = computed(() => css({ display: 'flex', alignItems: 'center', flex: 1, width: '100%', minWidth: 0 }), ...(ngDevMode ? [{ debugName: "rowClass" }] : /* istanbul ignore next */ []));
|
|
4356
4579
|
inputClass = computed(() => css({
|
|
4357
4580
|
flex: 1,
|
|
@@ -4387,6 +4610,7 @@ class UniComboboxComponent extends BaseComponent {
|
|
|
4387
4610
|
// A scroll height, never a cap: a closed-set control must not render a
|
|
4388
4611
|
// reachable-by-keyboard-only subset (contrast searchInput.maxSuggestions).
|
|
4389
4612
|
maxHeight: (options.maxVisibleOptions ?? 8) * 36 + 8,
|
|
4613
|
+
anchor: this.anchor.name,
|
|
4390
4614
|
}),
|
|
4391
4615
|
{
|
|
4392
4616
|
'& [role="option"]': {
|
|
@@ -4425,11 +4649,11 @@ class UniComboboxComponent extends BaseComponent {
|
|
|
4425
4649
|
]);
|
|
4426
4650
|
}, ...(ngDevMode ? [{ debugName: "listClass" }] : /* istanbul ignore next */ []));
|
|
4427
4651
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniComboboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4428
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniComboboxComponent, isStandalone: true, selector: "uni-combobox, Combobox", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, commitOnBlur: { classPropertyName: "commitOnBlur", publicName: "commitOnBlur", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, filterLocally: { classPropertyName: "filterLocally", publicName: "filterLocally", isSignal: true, isRequired: false, transformFunction: null }, filterWith: { classPropertyName: "filterWith", publicName: "filterWith", isSignal: true, isRequired: false, transformFunction: null }, debounceTime: { classPropertyName: "debounceTime", publicName: "debounceTime", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange", query: "query", selected: "selected", cleared: "cleared", rejected: "rejected" }, host: { properties: { "class": "className()" } }, providers: [{ provide: COMPONENT_NAME, useValue: 'combobox' }], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "listRef", first: true, predicate: ["listbox"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Focusout rides the bubbling event so the list closes and the draft\n resolves only when focus leaves the whole field. -->\n<div (focusout)=\"onFocusOut($event)\">\n <uni-input-box [error]=\"showError()\" [disabled]=\"disabled()\">\n <div [class]=\"rowClass()\">\n <input\n #field\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n aria-autocomplete=\"list\"\n [class]=\"inputClass()\"\n [disabled]=\"disabled()\"\n [placeholder]=\"placeholder() ?? ''\"\n [value]=\"displayValue()\"\n [attr.aria-label]=\"label()\"\n [attr.aria-expanded]=\"popupOpen()\"\n [attr.aria-controls]=\"list.listboxId\"\n [attr.aria-activedescendant]=\"list.activeDescendantId()\"\n [attr.aria-describedby]=\"ariaDescribedBy() ?? null\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onKeydown($event)\"\n (input)=\"onInput()\"\n (click)=\"onFieldClick()\"\n />\n @if (clearable() && value() !== null && !disabled()) {\n <button\n icon-button\n type=\"button\"\n size=\"sm\"\n [iconName]=\"componentOptions().clearIcon ?? 'close'\"\n (click)=\"clear()\"\n >\n Clear {{ label() }}\n </button>\n }\n <!-- Pointer-only: keyboard has ArrowDown, the input announces expanded. -->\n <button\n type=\"button\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n [class]=\"toggleClass()\"\n [disabled]=\"disabled()\"\n (mousedown)=\"onToggleMousedown($event)\"\n >\n <uni-icon [name]=\"componentOptions().toggleIcon ?? 'chevronDown'\" size=\"20\" />\n </button>\n </div>\n </uni-input-box>\n\n @if (popupOpen()) {\n <ul
|
|
4652
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniComboboxComponent, isStandalone: true, selector: "uni-combobox, Combobox", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, commitOnBlur: { classPropertyName: "commitOnBlur", publicName: "commitOnBlur", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, filterLocally: { classPropertyName: "filterLocally", publicName: "filterLocally", isSignal: true, isRequired: false, transformFunction: null }, filterWith: { classPropertyName: "filterWith", publicName: "filterWith", isSignal: true, isRequired: false, transformFunction: null }, debounceTime: { classPropertyName: "debounceTime", publicName: "debounceTime", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange", query: "query", selected: "selected", cleared: "cleared", rejected: "rejected" }, host: { properties: { "class": "className()" } }, providers: [{ provide: COMPONENT_NAME, useValue: 'combobox' }], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "listRef", first: true, predicate: ["listbox"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Focusout rides the bubbling event so the list closes and the draft\n resolves only when focus leaves the whole field. -->\n<div (focusout)=\"onFocusOut($event)\">\n <uni-input-box [error]=\"showError()\" [disabled]=\"disabled()\">\n <div [class]=\"rowClass()\">\n <input\n #field\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n aria-autocomplete=\"list\"\n [class]=\"inputClass()\"\n [disabled]=\"disabled()\"\n [placeholder]=\"placeholder() ?? ''\"\n [value]=\"displayValue()\"\n [attr.aria-label]=\"label()\"\n [attr.aria-expanded]=\"popupOpen()\"\n [attr.aria-controls]=\"list.listboxId\"\n [attr.aria-activedescendant]=\"list.activeDescendantId()\"\n [attr.aria-describedby]=\"ariaDescribedBy() ?? null\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onKeydown($event)\"\n (input)=\"onInput()\"\n (click)=\"onFieldClick()\"\n />\n @if (clearable() && value() !== null && !disabled()) {\n <button\n icon-button\n type=\"button\"\n size=\"sm\"\n [iconName]=\"componentOptions().clearIcon ?? 'close'\"\n (click)=\"clear()\"\n >\n Clear {{ label() }}\n </button>\n }\n <!-- Pointer-only: keyboard has ArrowDown, the input announces expanded. -->\n <button\n type=\"button\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n [class]=\"toggleClass()\"\n [disabled]=\"disabled()\"\n (mousedown)=\"onToggleMousedown($event)\"\n >\n <uni-icon [name]=\"componentOptions().toggleIcon ?? 'chevronDown'\" size=\"20\" />\n </button>\n </div>\n </uni-input-box>\n\n @if (popupOpen()) {\n <ul\n #listbox\n [id]=\"list.listboxId\"\n role=\"listbox\"\n [attr.popover]=\"popupAttr\"\n [attr.aria-label]=\"label()\"\n [class]=\"listClass()\"\n >\n @if (filteredIndices().length === 0) {\n <!-- Non-interactive: not an option, not navigable, no id. -->\n <li class=\"empty\">{{ emptyText() }}</li>\n } @else {\n @for (optIndex of filteredIndices(); track optIndex; let i = $index) {\n <!-- aria-selected marks the *committed* option; the active one is\n carried by aria-activedescendant \u2014 they are different facts. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <li\n role=\"option\"\n [id]=\"list.optionId(i)\"\n [class.active]=\"i === list.activeIndex()\"\n [attr.aria-selected]=\"optIndex === committedIndex()\"\n [attr.aria-disabled]=\"options()[optIndex].disabled ? true : null\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"onOptionClick(optIndex)\"\n >\n <span class=\"check\" aria-hidden=\"true\">\n @if (optIndex === committedIndex()) {\n <uni-icon [name]=\"componentOptions().selectedIcon ?? 'check'\" size=\"18\" />\n }\n </span>\n <span class=\"text\">\n <span class=\"option-label\">{{ options()[optIndex].label }}</span>\n @if (options()[optIndex].description) {\n <span class=\"desc\">{{ options()[optIndex].description }}</span>\n }\n </span>\n </li>\n }\n }\n </ul>\n }\n\n <!-- Commits, clears, refusals and result counts are otherwise silent. -->\n <span role=\"status\" aria-live=\"polite\" [class]=\"srOnly\">{{ announcer.message() }}</span>\n</div>\n", dependencies: [{ kind: "component", type: UniIconButtonComponent, selector: "button[uni-icon-button], button[icon-button]", inputs: ["ariaLabel", "iconName", "symbolName", "variant", "size", "disable", "loading", "opticalSize"] }, { kind: "component", type: UniIconComponent, selector: "uni-icon", inputs: ["color", "name", "size"] }, { kind: "component", type: UniInputBoxComponent, selector: "uni-input-box", inputs: ["disabled", "error", "minWidth", "height"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4429
4653
|
}
|
|
4430
4654
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniComboboxComponent, decorators: [{
|
|
4431
4655
|
type: Component,
|
|
4432
|
-
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'uni-combobox, Combobox', imports: [UniIconButtonComponent, UniIconComponent, UniInputBoxComponent], providers: [{ provide: COMPONENT_NAME, useValue: 'combobox' }], host: { '[class]': 'className()' }, template: "<!-- Focusout rides the bubbling event so the list closes and the draft\n resolves only when focus leaves the whole field. -->\n<div (focusout)=\"onFocusOut($event)\">\n <uni-input-box [error]=\"showError()\" [disabled]=\"disabled()\">\n <div [class]=\"rowClass()\">\n <input\n #field\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n aria-autocomplete=\"list\"\n [class]=\"inputClass()\"\n [disabled]=\"disabled()\"\n [placeholder]=\"placeholder() ?? ''\"\n [value]=\"displayValue()\"\n [attr.aria-label]=\"label()\"\n [attr.aria-expanded]=\"popupOpen()\"\n [attr.aria-controls]=\"list.listboxId\"\n [attr.aria-activedescendant]=\"list.activeDescendantId()\"\n [attr.aria-describedby]=\"ariaDescribedBy() ?? null\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onKeydown($event)\"\n (input)=\"onInput()\"\n (click)=\"onFieldClick()\"\n />\n @if (clearable() && value() !== null && !disabled()) {\n <button\n icon-button\n type=\"button\"\n size=\"sm\"\n [iconName]=\"componentOptions().clearIcon ?? 'close'\"\n (click)=\"clear()\"\n >\n Clear {{ label() }}\n </button>\n }\n <!-- Pointer-only: keyboard has ArrowDown, the input announces expanded. -->\n <button\n type=\"button\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n [class]=\"toggleClass()\"\n [disabled]=\"disabled()\"\n (mousedown)=\"onToggleMousedown($event)\"\n >\n <uni-icon [name]=\"componentOptions().toggleIcon ?? 'chevronDown'\" size=\"20\" />\n </button>\n </div>\n </uni-input-box>\n\n @if (popupOpen()) {\n <ul
|
|
4656
|
+
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'uni-combobox, Combobox', imports: [UniIconButtonComponent, UniIconComponent, UniInputBoxComponent], providers: [{ provide: COMPONENT_NAME, useValue: 'combobox' }], host: { '[class]': 'className()' }, template: "<!-- Focusout rides the bubbling event so the list closes and the draft\n resolves only when focus leaves the whole field. -->\n<div (focusout)=\"onFocusOut($event)\">\n <uni-input-box [error]=\"showError()\" [disabled]=\"disabled()\">\n <div [class]=\"rowClass()\">\n <input\n #field\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n aria-autocomplete=\"list\"\n [class]=\"inputClass()\"\n [disabled]=\"disabled()\"\n [placeholder]=\"placeholder() ?? ''\"\n [value]=\"displayValue()\"\n [attr.aria-label]=\"label()\"\n [attr.aria-expanded]=\"popupOpen()\"\n [attr.aria-controls]=\"list.listboxId\"\n [attr.aria-activedescendant]=\"list.activeDescendantId()\"\n [attr.aria-describedby]=\"ariaDescribedBy() ?? null\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onKeydown($event)\"\n (input)=\"onInput()\"\n (click)=\"onFieldClick()\"\n />\n @if (clearable() && value() !== null && !disabled()) {\n <button\n icon-button\n type=\"button\"\n size=\"sm\"\n [iconName]=\"componentOptions().clearIcon ?? 'close'\"\n (click)=\"clear()\"\n >\n Clear {{ label() }}\n </button>\n }\n <!-- Pointer-only: keyboard has ArrowDown, the input announces expanded. -->\n <button\n type=\"button\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n [class]=\"toggleClass()\"\n [disabled]=\"disabled()\"\n (mousedown)=\"onToggleMousedown($event)\"\n >\n <uni-icon [name]=\"componentOptions().toggleIcon ?? 'chevronDown'\" size=\"20\" />\n </button>\n </div>\n </uni-input-box>\n\n @if (popupOpen()) {\n <ul\n #listbox\n [id]=\"list.listboxId\"\n role=\"listbox\"\n [attr.popover]=\"popupAttr\"\n [attr.aria-label]=\"label()\"\n [class]=\"listClass()\"\n >\n @if (filteredIndices().length === 0) {\n <!-- Non-interactive: not an option, not navigable, no id. -->\n <li class=\"empty\">{{ emptyText() }}</li>\n } @else {\n @for (optIndex of filteredIndices(); track optIndex; let i = $index) {\n <!-- aria-selected marks the *committed* option; the active one is\n carried by aria-activedescendant \u2014 they are different facts. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <li\n role=\"option\"\n [id]=\"list.optionId(i)\"\n [class.active]=\"i === list.activeIndex()\"\n [attr.aria-selected]=\"optIndex === committedIndex()\"\n [attr.aria-disabled]=\"options()[optIndex].disabled ? true : null\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"onOptionClick(optIndex)\"\n >\n <span class=\"check\" aria-hidden=\"true\">\n @if (optIndex === committedIndex()) {\n <uni-icon [name]=\"componentOptions().selectedIcon ?? 'check'\" size=\"18\" />\n }\n </span>\n <span class=\"text\">\n <span class=\"option-label\">{{ options()[optIndex].label }}</span>\n @if (options()[optIndex].description) {\n <span class=\"desc\">{{ options()[optIndex].description }}</span>\n }\n </span>\n </li>\n }\n }\n </ul>\n }\n\n <!-- Commits, clears, refusals and result counts are otherwise silent. -->\n <span role=\"status\" aria-live=\"polite\" [class]=\"srOnly\">{{ announcer.message() }}</span>\n</div>\n" }]
|
|
4433
4657
|
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], commitOnBlur: [{ type: i0.Input, args: [{ isSignal: true, alias: "commitOnBlur", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], filterLocally: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterLocally", required: false }] }], filterWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterWith", required: false }] }], debounceTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "debounceTime", required: false }] }], query: [{ type: i0.Output, args: ["query"] }], selected: [{ type: i0.Output, args: ["selected"] }], cleared: [{ type: i0.Output, args: ["cleared"] }], rejected: [{ type: i0.Output, args: ["rejected"] }], inputRef: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], listRef: [{ type: i0.ViewChild, args: ['listbox', { isSignal: true }] }] } });
|
|
4434
4658
|
|
|
4435
4659
|
class UniDataSearchComponent extends BaseComponent {
|
|
@@ -4913,7 +5137,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
4913
5137
|
|
|
4914
5138
|
class UniDropdownComponent extends BaseComponent {
|
|
4915
5139
|
renderer = inject(Renderer2);
|
|
4916
|
-
delay = 100;
|
|
4917
5140
|
// Reactively track visibility status using Signals
|
|
4918
5141
|
showing = signal(false, ...(ngDevMode ? [{ debugName: "showing" }] : /* istanbul ignore next */ []));
|
|
4919
5142
|
trigger = input.required(...(ngDevMode ? [{ debugName: "trigger" }] : /* istanbul ignore next */ []));
|
|
@@ -4947,22 +5170,9 @@ class UniDropdownComponent extends BaseComponent {
|
|
|
4947
5170
|
get _dropdown() {
|
|
4948
5171
|
return this.dropdownRef.nativeElement;
|
|
4949
5172
|
}
|
|
4950
|
-
transformOriginMap = {
|
|
4951
|
-
top: 'bottom center',
|
|
4952
|
-
right: 'center left',
|
|
4953
|
-
bottom: 'top center',
|
|
4954
|
-
left: 'center right',
|
|
4955
|
-
'top-start': 'bottom left',
|
|
4956
|
-
'top-end': 'bottom right',
|
|
4957
|
-
'right-start': 'top left',
|
|
4958
|
-
'right-end': 'bottom left',
|
|
4959
|
-
'bottom-start': 'top left',
|
|
4960
|
-
'bottom-end': 'top right',
|
|
4961
|
-
'left-start': 'top right',
|
|
4962
|
-
'left-end': 'bottom right',
|
|
4963
|
-
};
|
|
4964
5173
|
dropdownClass = computed(() => {
|
|
4965
5174
|
const currentPlacement = this.placement();
|
|
5175
|
+
const motion = this.theme.motion(this.componentOptions().motion);
|
|
4966
5176
|
return css([
|
|
4967
5177
|
{
|
|
4968
5178
|
// Reset browser agent default popover styles
|
|
@@ -4974,27 +5184,14 @@ class UniDropdownComponent extends BaseComponent {
|
|
|
4974
5184
|
// Native anchor positioning: the browser keeps the panel attached to
|
|
4975
5185
|
// the trigger (no scroll/resize listeners needed)
|
|
4976
5186
|
...anchorStyles(this.anchorName, currentPlacement, this.offset()),
|
|
4977
|
-
//
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
//
|
|
4983
|
-
|
|
4984
|
-
transform:
|
|
4985
|
-
transformOrigin: this.transformOriginMap[currentPlacement],
|
|
4986
|
-
// 3. Active state styling controlled via the native browser pseudo-class
|
|
4987
|
-
['&:popover-open']: {
|
|
4988
|
-
opacity: 1,
|
|
4989
|
-
transform: 'scale(1)',
|
|
4990
|
-
},
|
|
4991
|
-
// 4. Starting-style rules what properties animate *from* when transitioning in
|
|
4992
|
-
['@starting-style']: {
|
|
4993
|
-
['&:popover-open']: {
|
|
4994
|
-
opacity: 0,
|
|
4995
|
-
transform: 'scale(0.8)',
|
|
4996
|
-
},
|
|
4997
|
-
},
|
|
5187
|
+
// Grows out of the corner touching the trigger. A pre-measure default
|
|
5188
|
+
// only: the real origin is measured per toggle (syncTransformOrigin),
|
|
5189
|
+
// because position-try fallbacks may have flipped the panel.
|
|
5190
|
+
transformOrigin: TRANSFORM_ORIGINS[currentPlacement],
|
|
5191
|
+
// Scale-and-fade into and out of the top layer, including the
|
|
5192
|
+
// `@starting-style` the entry transition runs from. Timing comes from
|
|
5193
|
+
// the theme's motion scale, so retiming every overlay is one edit.
|
|
5194
|
+
...discreteOverlayTransition(motion.duration, { opacity: 0, transform: `scale(${motion.scale ?? 1})` }, { opacity: 1, transform: 'scale(1)' }, motion.easing),
|
|
4998
5195
|
},
|
|
4999
5196
|
]);
|
|
5000
5197
|
}, ...(ngDevMode ? [{ debugName: "dropdownClass" }] : /* istanbul ignore next */ []));
|
|
@@ -5009,7 +5206,7 @@ class UniDropdownComponent extends BaseComponent {
|
|
|
5009
5206
|
this.toggleDropdown();
|
|
5010
5207
|
});
|
|
5011
5208
|
// Anchor the popover panel to the trigger element
|
|
5012
|
-
|
|
5209
|
+
setAnchorName(this._trigger, this.anchorName);
|
|
5013
5210
|
// Wire the ARIA popup contract onto the focusable trigger element
|
|
5014
5211
|
const focusTarget = this._focusTarget;
|
|
5015
5212
|
this.renderer.setAttribute(focusTarget, 'aria-expanded', 'false');
|
|
@@ -5019,7 +5216,11 @@ class UniDropdownComponent extends BaseComponent {
|
|
|
5019
5216
|
}
|
|
5020
5217
|
// Sync state if user invokes light-dismiss via outside click or Escape key
|
|
5021
5218
|
this.renderer.listen(this._dropdown, 'toggle', (event) => {
|
|
5022
|
-
const isOpened = event
|
|
5219
|
+
const isOpened = isToggleOpen(event);
|
|
5220
|
+
// Both edges: on open so the entry scale grows out of the trigger, and
|
|
5221
|
+
// on close-start so a panel the browser flipped while open (scroll near
|
|
5222
|
+
// a viewport edge) still collapses back toward the trigger.
|
|
5223
|
+
this.syncTransformOrigin();
|
|
5023
5224
|
this.showing.set(isOpened);
|
|
5024
5225
|
this.renderer.setAttribute(this._focusTarget, 'aria-expanded', `${isOpened}`);
|
|
5025
5226
|
if (isOpened) {
|
|
@@ -5027,20 +5228,23 @@ class UniDropdownComponent extends BaseComponent {
|
|
|
5027
5228
|
}
|
|
5028
5229
|
else {
|
|
5029
5230
|
this.dropdownHiding.emit(true);
|
|
5030
|
-
|
|
5231
|
+
// Keyboard users are never stranded when the top layer closes (WCAG 2.4.3).
|
|
5232
|
+
restoreOverlayFocus(this._dropdown, this._focusTarget);
|
|
5031
5233
|
}
|
|
5032
5234
|
});
|
|
5033
5235
|
}
|
|
5034
5236
|
/**
|
|
5035
|
-
*
|
|
5036
|
-
*
|
|
5037
|
-
*
|
|
5237
|
+
* Scale the open/close animation from the corner touching the trigger,
|
|
5238
|
+
* wherever the browser actually placed the panel. The static
|
|
5239
|
+
* `TRANSFORM_ORIGINS` entry covers only the *requested* placement; with
|
|
5240
|
+
* `position-try-fallbacks` the panel may have flipped at a viewport edge,
|
|
5241
|
+
* and a `bottom-end` picker rendered above its field would otherwise still
|
|
5242
|
+
* animate from the top-right corner.
|
|
5038
5243
|
*/
|
|
5039
|
-
|
|
5040
|
-
const
|
|
5041
|
-
if (
|
|
5042
|
-
this.
|
|
5043
|
-
}
|
|
5244
|
+
syncTransformOrigin() {
|
|
5245
|
+
const origin = transformOriginFor(this._dropdown.getBoundingClientRect(), this._trigger.getBoundingClientRect());
|
|
5246
|
+
if (origin)
|
|
5247
|
+
this.renderer.setStyle(this._dropdown, 'transform-origin', origin);
|
|
5044
5248
|
}
|
|
5045
5249
|
toggleDropdown() {
|
|
5046
5250
|
if (this.showing()) {
|
|
@@ -5162,7 +5366,8 @@ class UniDateInputComponent extends BaseComponent {
|
|
|
5162
5366
|
srOnly = css(visuallyHidden);
|
|
5163
5367
|
/** A refused commit — styles the field and sets aria-invalid until edited. */
|
|
5164
5368
|
draftInvalid = signal(false, ...(ngDevMode ? [{ debugName: "draftInvalid" }] : /* istanbul ignore next */ []));
|
|
5165
|
-
|
|
5369
|
+
/** Commits, clears and refusals are otherwise silent to a screen reader. */
|
|
5370
|
+
announcer = createAnnouncer();
|
|
5166
5371
|
toggleElement = computed(() => this.toggleRef()?.nativeElement, ...(ngDevMode ? [{ debugName: "toggleElement" }] : /* istanbul ignore next */ []));
|
|
5167
5372
|
popupOpen = computed(() => this.dropdown()?.showing() ?? false, ...(ngDevMode ? [{ debugName: "popupOpen" }] : /* istanbul ignore next */ []));
|
|
5168
5373
|
resolvedLocale = computed(() => this.locale() ?? (document.documentElement.lang || navigator.language || 'en-US'), ...(ngDevMode ? [{ debugName: "resolvedLocale" }] : /* istanbul ignore next */ []));
|
|
@@ -5193,7 +5398,7 @@ class UniDateInputComponent extends BaseComponent {
|
|
|
5193
5398
|
this.draftInvalid.set(false);
|
|
5194
5399
|
this.setFieldText(this.displayText());
|
|
5195
5400
|
if (!silent)
|
|
5196
|
-
this.announce(date ? `${this.fullDate(date)}.` : 'Date cleared.');
|
|
5401
|
+
this.announcer.announce(date ? `${this.fullDate(date)}.` : 'Date cleared.');
|
|
5197
5402
|
}
|
|
5198
5403
|
refuse(raw, reason) {
|
|
5199
5404
|
this.draftInvalid.set(true);
|
|
@@ -5202,7 +5407,7 @@ class UniDateInputComponent extends BaseComponent {
|
|
|
5202
5407
|
'out-of-range': `${raw} is outside the allowed dates.`,
|
|
5203
5408
|
disabled: `${raw} isn't available.`,
|
|
5204
5409
|
}[reason];
|
|
5205
|
-
this.announce(message);
|
|
5410
|
+
this.announcer.announce(message);
|
|
5206
5411
|
this.rejected.emit({ raw, reason });
|
|
5207
5412
|
}
|
|
5208
5413
|
commit(raw) {
|
|
@@ -5350,9 +5555,6 @@ class UniDateInputComponent extends BaseComponent {
|
|
|
5350
5555
|
if (element)
|
|
5351
5556
|
element.value = text;
|
|
5352
5557
|
}
|
|
5353
|
-
announce(message) {
|
|
5354
|
-
this.announcement.set(this.announcement() === message ? `${message} ` : message);
|
|
5355
|
-
}
|
|
5356
5558
|
// --- Styling -----------------------------------------------------------------------
|
|
5357
5559
|
className = computed(() => css({ display: 'block', position: 'relative' }), ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
|
|
5358
5560
|
rowClass = computed(() => css({ display: 'flex', alignItems: 'center', flex: 1, width: '100%', minWidth: 0 }), ...(ngDevMode ? [{ debugName: "rowClass" }] : /* istanbul ignore next */ []));
|
|
@@ -5386,7 +5588,7 @@ class UniDateInputComponent extends BaseComponent {
|
|
|
5386
5588
|
]);
|
|
5387
5589
|
}, ...(ngDevMode ? [{ debugName: "embeddedClass" }] : /* istanbul ignore next */ []));
|
|
5388
5590
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniDateInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
5389
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniDateInputComponent, isStandalone: true, selector: "uni-date-input, DateInput", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, displayFormat: { classPropertyName: "displayFormat", publicName: "displayFormat", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, commitOnBlur: { classPropertyName: "commitOnBlur", publicName: "commitOnBlur", isSignal: true, isRequired: false, transformFunction: null }, parse: { classPropertyName: "parse", publicName: "parse", isSignal: true, isRequired: false, transformFunction: null }, embedded: { classPropertyName: "embedded", publicName: "embedded", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null }, markers: { classPropertyName: "markers", publicName: "markers", isSignal: true, isRequired: false, transformFunction: null }, weekStart: { classPropertyName: "weekStart", publicName: "weekStart", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange", opened: "opened", closed: "closed", rejected: "rejected" }, host: { properties: { "class": "className()" } }, providers: [{ provide: COMPONENT_NAME, useValue: 'dateInput' }], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "toggleRef", first: true, predicate: ["toggle"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "popupRef", first: true, predicate: ["popupDialog"], descendants: true, isSignal: true }, { propertyName: "dropdown", first: true, predicate: UniDropdownComponent, descendants: true, isSignal: true }, { propertyName: "calendar", first: true, predicate: UniCalendarComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Focusout rides the bubbling event so commits happen only when focus\n leaves the whole field, not while moving into the popup. -->\n<div (focusout)=\"onFocusOut($event)\">\n <ng-template #parts>\n <input\n #field\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [class]=\"inputClass()\"\n [disabled]=\"disabled()\"\n [placeholder]=\"resolvedPlaceholder()\"\n [value]=\"displayText()\"\n [attr.aria-label]=\"label()\"\n [attr.aria-describedby]=\"ariaDescribedBy() ?? null\"\n [attr.aria-invalid]=\"showError() || draftInvalid() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onInputKeydown($event)\"\n (input)=\"onInput()\"\n />\n <span [class]=\"toggleWrapClass()\">\n <!-- The dropdown wires aria-haspopup/aria-expanded/aria-controls onto\n this button; its name tracks the value (\"Change date, \u2026\"). -->\n <button\n #toggle\n icon-button\n type=\"button\"\n size=\"sm\"\n [symbolName]=\"componentOptions().toggleSymbol ?? 'calendar_month'\"\n [disable]=\"disabled()\"\n >\n {{ toggleLabel() }}\n </button>\n </span>\n </ng-template>\n\n @if (embedded()) {\n <!-- A composer (uni-date-time-input) owns the field chrome. -->\n <div [class]=\"embeddedClass()\"><ng-container [ngTemplateOutlet]=\"parts\" /></div>\n } @else {\n <uni-input-box [error]=\"showError() || draftInvalid()\" [disabled]=\"disabled()\">\n <div [class]=\"rowClass()\"><ng-container [ngTemplateOutlet]=\"parts\" /></div>\n </uni-input-box>\n }\n\n @if (toggleElement()) {\n <uni-dropdown\n [trigger]=\"toggleElement()!\"\n ariaHasPopup=\"dialog\"\n placement=\"bottom-end\"\n [color]=\"componentOptions().popupColor ?? 'primary-surface'\"\n [shadow]=\"componentOptions().popupShadow ?? 'menu'\"\n [borderRadius]=\"componentOptions().popupBorderRadius ?? 'xs'\"\n paddingVertical=\"xs\"\n paddingHorizontal=\"xs\"\n (dropdownShowing)=\"onPopupShowing()\"\n (dropdownHiding)=\"onPopupHiding()\"\n >\n <!-- A focus-holding dialog per the APG date-picker pattern: Tab cycles\n inside, Escape closes and returns focus to the field. -->\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n <div #popupDialog role=\"dialog\" aria-label=\"Choose date\" (keydown)=\"onPopupKeydown($event)\">\n <uni-calendar\n mode=\"single\"\n [value]=\"value()\"\n [minDate]=\"minDate()\"\n [maxDate]=\"maxDate()\"\n [disabledDates]=\"disabledDates()\"\n [markers]=\"markers()\"\n [weekStart]=\"weekStart()\"\n [locale]=\"locale()\"\n (selected)=\"onCalendarPick($event)\"\n />\n </div>\n </uni-dropdown>\n }\n\n <!-- Commits, steps and rejections are otherwise a silent reformat. -->\n <span role=\"status\" aria-live=\"polite\" [class]=\"srOnly\">{{
|
|
5591
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniDateInputComponent, isStandalone: true, selector: "uni-date-input, DateInput", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, displayFormat: { classPropertyName: "displayFormat", publicName: "displayFormat", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, commitOnBlur: { classPropertyName: "commitOnBlur", publicName: "commitOnBlur", isSignal: true, isRequired: false, transformFunction: null }, parse: { classPropertyName: "parse", publicName: "parse", isSignal: true, isRequired: false, transformFunction: null }, embedded: { classPropertyName: "embedded", publicName: "embedded", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null }, markers: { classPropertyName: "markers", publicName: "markers", isSignal: true, isRequired: false, transformFunction: null }, weekStart: { classPropertyName: "weekStart", publicName: "weekStart", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange", opened: "opened", closed: "closed", rejected: "rejected" }, host: { properties: { "class": "className()" } }, providers: [{ provide: COMPONENT_NAME, useValue: 'dateInput' }], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "toggleRef", first: true, predicate: ["toggle"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "popupRef", first: true, predicate: ["popupDialog"], descendants: true, isSignal: true }, { propertyName: "dropdown", first: true, predicate: UniDropdownComponent, descendants: true, isSignal: true }, { propertyName: "calendar", first: true, predicate: UniCalendarComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Focusout rides the bubbling event so commits happen only when focus\n leaves the whole field, not while moving into the popup. -->\n<div (focusout)=\"onFocusOut($event)\">\n <ng-template #parts>\n <input\n #field\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [class]=\"inputClass()\"\n [disabled]=\"disabled()\"\n [placeholder]=\"resolvedPlaceholder()\"\n [value]=\"displayText()\"\n [attr.aria-label]=\"label()\"\n [attr.aria-describedby]=\"ariaDescribedBy() ?? null\"\n [attr.aria-invalid]=\"showError() || draftInvalid() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onInputKeydown($event)\"\n (input)=\"onInput()\"\n />\n <span [class]=\"toggleWrapClass()\">\n <!-- The dropdown wires aria-haspopup/aria-expanded/aria-controls onto\n this button; its name tracks the value (\"Change date, \u2026\"). -->\n <button\n #toggle\n icon-button\n type=\"button\"\n size=\"sm\"\n [symbolName]=\"componentOptions().toggleSymbol ?? 'calendar_month'\"\n [disable]=\"disabled()\"\n >\n {{ toggleLabel() }}\n </button>\n </span>\n </ng-template>\n\n @if (embedded()) {\n <!-- A composer (uni-date-time-input) owns the field chrome. -->\n <div [class]=\"embeddedClass()\"><ng-container [ngTemplateOutlet]=\"parts\" /></div>\n } @else {\n <uni-input-box [error]=\"showError() || draftInvalid()\" [disabled]=\"disabled()\">\n <div [class]=\"rowClass()\"><ng-container [ngTemplateOutlet]=\"parts\" /></div>\n </uni-input-box>\n }\n\n @if (toggleElement()) {\n <uni-dropdown\n [trigger]=\"toggleElement()!\"\n ariaHasPopup=\"dialog\"\n placement=\"bottom-end\"\n [color]=\"componentOptions().popupColor ?? 'primary-surface'\"\n [shadow]=\"componentOptions().popupShadow ?? 'menu'\"\n [borderRadius]=\"componentOptions().popupBorderRadius ?? 'xs'\"\n paddingVertical=\"xs\"\n paddingHorizontal=\"xs\"\n (dropdownShowing)=\"onPopupShowing()\"\n (dropdownHiding)=\"onPopupHiding()\"\n >\n <!-- A focus-holding dialog per the APG date-picker pattern: Tab cycles\n inside, Escape closes and returns focus to the field. -->\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n <div #popupDialog role=\"dialog\" aria-label=\"Choose date\" (keydown)=\"onPopupKeydown($event)\">\n <uni-calendar\n mode=\"single\"\n [value]=\"value()\"\n [minDate]=\"minDate()\"\n [maxDate]=\"maxDate()\"\n [disabledDates]=\"disabledDates()\"\n [markers]=\"markers()\"\n [weekStart]=\"weekStart()\"\n [locale]=\"locale()\"\n (selected)=\"onCalendarPick($event)\"\n />\n </div>\n </uni-dropdown>\n }\n\n <!-- Commits, steps and rejections are otherwise a silent reformat. -->\n <span role=\"status\" aria-live=\"polite\" [class]=\"srOnly\">{{ announcer.message() }}</span>\n</div>\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: UniCalendarComponent, selector: "uni-calendar, Calendar", inputs: ["value", "disabled", "touched", "invalid", "dirty", "required", "ariaDescribedBy", "mode", "month", "minDate", "maxDate", "disabledDates", "markers", "locale", "weekStart", "ariaLabel", "size"], outputs: ["valueChange", "touchedChange", "monthChange", "selected"] }, { kind: "component", type: UniDropdownComponent, selector: "uni-dropdown", inputs: ["trigger", "placement", "offset", "ariaHasPopup", "paddingVertical", "paddingHorizontal", "border", "borderRadius", "shadow", "color"], outputs: ["dropdownShowing", "dropdownHiding"] }, { kind: "component", type: UniIconButtonComponent, selector: "button[uni-icon-button], button[icon-button]", inputs: ["ariaLabel", "iconName", "symbolName", "variant", "size", "disable", "loading", "opticalSize"] }, { kind: "component", type: UniInputBoxComponent, selector: "uni-input-box", inputs: ["disabled", "error", "minWidth", "height"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5390
5592
|
}
|
|
5391
5593
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniDateInputComponent, decorators: [{
|
|
5392
5594
|
type: Component,
|
|
@@ -5396,7 +5598,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
5396
5598
|
UniDropdownComponent,
|
|
5397
5599
|
UniIconButtonComponent,
|
|
5398
5600
|
UniInputBoxComponent,
|
|
5399
|
-
], providers: [{ provide: COMPONENT_NAME, useValue: 'dateInput' }], host: { '[class]': 'className()' }, template: "<!-- Focusout rides the bubbling event so commits happen only when focus\n leaves the whole field, not while moving into the popup. -->\n<div (focusout)=\"onFocusOut($event)\">\n <ng-template #parts>\n <input\n #field\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [class]=\"inputClass()\"\n [disabled]=\"disabled()\"\n [placeholder]=\"resolvedPlaceholder()\"\n [value]=\"displayText()\"\n [attr.aria-label]=\"label()\"\n [attr.aria-describedby]=\"ariaDescribedBy() ?? null\"\n [attr.aria-invalid]=\"showError() || draftInvalid() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onInputKeydown($event)\"\n (input)=\"onInput()\"\n />\n <span [class]=\"toggleWrapClass()\">\n <!-- The dropdown wires aria-haspopup/aria-expanded/aria-controls onto\n this button; its name tracks the value (\"Change date, \u2026\"). -->\n <button\n #toggle\n icon-button\n type=\"button\"\n size=\"sm\"\n [symbolName]=\"componentOptions().toggleSymbol ?? 'calendar_month'\"\n [disable]=\"disabled()\"\n >\n {{ toggleLabel() }}\n </button>\n </span>\n </ng-template>\n\n @if (embedded()) {\n <!-- A composer (uni-date-time-input) owns the field chrome. -->\n <div [class]=\"embeddedClass()\"><ng-container [ngTemplateOutlet]=\"parts\" /></div>\n } @else {\n <uni-input-box [error]=\"showError() || draftInvalid()\" [disabled]=\"disabled()\">\n <div [class]=\"rowClass()\"><ng-container [ngTemplateOutlet]=\"parts\" /></div>\n </uni-input-box>\n }\n\n @if (toggleElement()) {\n <uni-dropdown\n [trigger]=\"toggleElement()!\"\n ariaHasPopup=\"dialog\"\n placement=\"bottom-end\"\n [color]=\"componentOptions().popupColor ?? 'primary-surface'\"\n [shadow]=\"componentOptions().popupShadow ?? 'menu'\"\n [borderRadius]=\"componentOptions().popupBorderRadius ?? 'xs'\"\n paddingVertical=\"xs\"\n paddingHorizontal=\"xs\"\n (dropdownShowing)=\"onPopupShowing()\"\n (dropdownHiding)=\"onPopupHiding()\"\n >\n <!-- A focus-holding dialog per the APG date-picker pattern: Tab cycles\n inside, Escape closes and returns focus to the field. -->\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n <div #popupDialog role=\"dialog\" aria-label=\"Choose date\" (keydown)=\"onPopupKeydown($event)\">\n <uni-calendar\n mode=\"single\"\n [value]=\"value()\"\n [minDate]=\"minDate()\"\n [maxDate]=\"maxDate()\"\n [disabledDates]=\"disabledDates()\"\n [markers]=\"markers()\"\n [weekStart]=\"weekStart()\"\n [locale]=\"locale()\"\n (selected)=\"onCalendarPick($event)\"\n />\n </div>\n </uni-dropdown>\n }\n\n <!-- Commits, steps and rejections are otherwise a silent reformat. -->\n <span role=\"status\" aria-live=\"polite\" [class]=\"srOnly\">{{
|
|
5601
|
+
], providers: [{ provide: COMPONENT_NAME, useValue: 'dateInput' }], host: { '[class]': 'className()' }, template: "<!-- Focusout rides the bubbling event so commits happen only when focus\n leaves the whole field, not while moving into the popup. -->\n<div (focusout)=\"onFocusOut($event)\">\n <ng-template #parts>\n <input\n #field\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [class]=\"inputClass()\"\n [disabled]=\"disabled()\"\n [placeholder]=\"resolvedPlaceholder()\"\n [value]=\"displayText()\"\n [attr.aria-label]=\"label()\"\n [attr.aria-describedby]=\"ariaDescribedBy() ?? null\"\n [attr.aria-invalid]=\"showError() || draftInvalid() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onInputKeydown($event)\"\n (input)=\"onInput()\"\n />\n <span [class]=\"toggleWrapClass()\">\n <!-- The dropdown wires aria-haspopup/aria-expanded/aria-controls onto\n this button; its name tracks the value (\"Change date, \u2026\"). -->\n <button\n #toggle\n icon-button\n type=\"button\"\n size=\"sm\"\n [symbolName]=\"componentOptions().toggleSymbol ?? 'calendar_month'\"\n [disable]=\"disabled()\"\n >\n {{ toggleLabel() }}\n </button>\n </span>\n </ng-template>\n\n @if (embedded()) {\n <!-- A composer (uni-date-time-input) owns the field chrome. -->\n <div [class]=\"embeddedClass()\"><ng-container [ngTemplateOutlet]=\"parts\" /></div>\n } @else {\n <uni-input-box [error]=\"showError() || draftInvalid()\" [disabled]=\"disabled()\">\n <div [class]=\"rowClass()\"><ng-container [ngTemplateOutlet]=\"parts\" /></div>\n </uni-input-box>\n }\n\n @if (toggleElement()) {\n <uni-dropdown\n [trigger]=\"toggleElement()!\"\n ariaHasPopup=\"dialog\"\n placement=\"bottom-end\"\n [color]=\"componentOptions().popupColor ?? 'primary-surface'\"\n [shadow]=\"componentOptions().popupShadow ?? 'menu'\"\n [borderRadius]=\"componentOptions().popupBorderRadius ?? 'xs'\"\n paddingVertical=\"xs\"\n paddingHorizontal=\"xs\"\n (dropdownShowing)=\"onPopupShowing()\"\n (dropdownHiding)=\"onPopupHiding()\"\n >\n <!-- A focus-holding dialog per the APG date-picker pattern: Tab cycles\n inside, Escape closes and returns focus to the field. -->\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n <div #popupDialog role=\"dialog\" aria-label=\"Choose date\" (keydown)=\"onPopupKeydown($event)\">\n <uni-calendar\n mode=\"single\"\n [value]=\"value()\"\n [minDate]=\"minDate()\"\n [maxDate]=\"maxDate()\"\n [disabledDates]=\"disabledDates()\"\n [markers]=\"markers()\"\n [weekStart]=\"weekStart()\"\n [locale]=\"locale()\"\n (selected)=\"onCalendarPick($event)\"\n />\n </div>\n </uni-dropdown>\n }\n\n <!-- Commits, steps and rejections are otherwise a silent reformat. -->\n <span role=\"status\" aria-live=\"polite\" [class]=\"srOnly\">{{ announcer.message() }}</span>\n</div>\n" }]
|
|
5400
5602
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], displayFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayFormat", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], commitOnBlur: [{ type: i0.Input, args: [{ isSignal: true, alias: "commitOnBlur", required: false }] }], parse: [{ type: i0.Input, args: [{ isSignal: true, alias: "parse", required: false }] }], embedded: [{ type: i0.Input, args: [{ isSignal: true, alias: "embedded", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], disabledDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDates", required: false }] }], markers: [{ type: i0.Input, args: [{ isSignal: true, alias: "markers", required: false }] }], weekStart: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekStart", required: false }] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], rejected: [{ type: i0.Output, args: ["rejected"] }], inputRef: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], toggleRef: [{ type: i0.ViewChild, args: ['toggle', { ...{ read: ElementRef }, isSignal: true }] }], popupRef: [{ type: i0.ViewChild, args: ['popupDialog', { isSignal: true }] }], dropdown: [{ type: i0.ViewChild, args: [i0.forwardRef(() => UniDropdownComponent), { isSignal: true }] }], calendar: [{ type: i0.ViewChild, args: [i0.forwardRef(() => UniCalendarComponent), { isSignal: true }] }] } });
|
|
5401
5603
|
|
|
5402
5604
|
const toMinutes = (time) => {
|
|
@@ -5447,10 +5649,19 @@ class UniTimeInputComponent extends BaseComponent {
|
|
|
5447
5649
|
host = inject(ElementRef);
|
|
5448
5650
|
inputRef = viewChild('field', ...(ngDevMode ? [{ debugName: "inputRef" }] : /* istanbul ignore next */ []));
|
|
5449
5651
|
listRef = viewChild('listbox', ...(ngDevMode ? [{ debugName: "listRef" }] : /* istanbul ignore next */ []));
|
|
5652
|
+
/** Ties the popup to the field so the browser tracks it in the top layer. */
|
|
5653
|
+
anchor = newListboxAnchor();
|
|
5654
|
+
/** `manual` where the top layer is usable, else null — see the popup helper. */
|
|
5655
|
+
popupAttr = listboxPopupAttr();
|
|
5656
|
+
constructor() {
|
|
5657
|
+
super();
|
|
5658
|
+
promoteListboxPopup(this.listRef);
|
|
5659
|
+
}
|
|
5450
5660
|
srOnly = css(visuallyHidden);
|
|
5451
5661
|
/** A refused commit — styles the field and sets aria-invalid until edited. */
|
|
5452
5662
|
draftInvalid = signal(false, ...(ngDevMode ? [{ debugName: "draftInvalid" }] : /* istanbul ignore next */ []));
|
|
5453
|
-
|
|
5663
|
+
/** Commits, clears and refusals are otherwise silent to a screen reader. */
|
|
5664
|
+
announcer = createAnnouncer();
|
|
5454
5665
|
resolvedLocale = computed(() => this.locale() ?? (document.documentElement.lang || navigator.language || 'en-US'), ...(ngDevMode ? [{ debugName: "resolvedLocale" }] : /* istanbul ignore next */ []));
|
|
5455
5666
|
resolvedHour12 = computed(() => this.hour12() ?? localeDefaultHour12(this.resolvedLocale()), ...(ngDevMode ? [{ debugName: "resolvedHour12" }] : /* istanbul ignore next */ []));
|
|
5456
5667
|
/** The listed times: pinned `slots` verbatim, else the generated step grid. */
|
|
@@ -5476,7 +5687,7 @@ class UniTimeInputComponent extends BaseComponent {
|
|
|
5476
5687
|
this.draftInvalid.set(false);
|
|
5477
5688
|
this.setFieldText(this.displayText());
|
|
5478
5689
|
if (!silent)
|
|
5479
|
-
this.announce(time ? `${this.formatValue(time)}.` : 'Time cleared.');
|
|
5690
|
+
this.announcer.announce(time ? `${this.formatValue(time)}.` : 'Time cleared.');
|
|
5480
5691
|
}
|
|
5481
5692
|
refuse(raw, reason, shown = raw) {
|
|
5482
5693
|
this.draftInvalid.set(true);
|
|
@@ -5485,7 +5696,7 @@ class UniTimeInputComponent extends BaseComponent {
|
|
|
5485
5696
|
'out-of-range': `${shown} is outside the allowed times.`,
|
|
5486
5697
|
unavailable: `${shown} isn't available.`,
|
|
5487
5698
|
}[reason];
|
|
5488
|
-
this.announce(message);
|
|
5699
|
+
this.announcer.announce(message);
|
|
5489
5700
|
this.rejected.emit({ raw, reason });
|
|
5490
5701
|
}
|
|
5491
5702
|
commit(raw) {
|
|
@@ -5667,11 +5878,8 @@ class UniTimeInputComponent extends BaseComponent {
|
|
|
5667
5878
|
if (element)
|
|
5668
5879
|
element.value = text;
|
|
5669
5880
|
}
|
|
5670
|
-
announce(message) {
|
|
5671
|
-
this.announcement.set(this.announcement() === message ? `${message} ` : message);
|
|
5672
|
-
}
|
|
5673
5881
|
// --- Styling -----------------------------------------------------------------------
|
|
5674
|
-
className = computed(() => css({ display: 'block', position: 'relative' }), ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
|
|
5882
|
+
className = computed(() => css({ display: 'block', position: 'relative', ...this.anchor.style }), ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
|
|
5675
5883
|
rowClass = computed(() => css({ display: 'flex', alignItems: 'center', flex: 1, width: '100%', minWidth: 0 }), ...(ngDevMode ? [{ debugName: "rowClass" }] : /* istanbul ignore next */ []));
|
|
5676
5884
|
inputClass = computed(() => {
|
|
5677
5885
|
const colors = this.theme.colorPalette();
|
|
@@ -5700,15 +5908,16 @@ class UniTimeInputComponent extends BaseComponent {
|
|
|
5700
5908
|
const options = this.componentOptions();
|
|
5701
5909
|
return css(listboxPopupStyles(this.theme, options, {
|
|
5702
5910
|
maxHeight: (options.maxVisibleOptions ?? 7) * 36,
|
|
5911
|
+
anchor: this.anchor.name,
|
|
5703
5912
|
}));
|
|
5704
5913
|
}, ...(ngDevMode ? [{ debugName: "listClass" }] : /* istanbul ignore next */ []));
|
|
5705
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniTimeInputComponent, deps:
|
|
5706
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniTimeInputComponent, isStandalone: true, selector: "uni-time-input, TimeInput", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, minuteStep: { classPropertyName: "minuteStep", publicName: "minuteStep", isSignal: true, isRequired: false, transformFunction: null }, minTime: { classPropertyName: "minTime", publicName: "minTime", isSignal: true, isRequired: false, transformFunction: null }, maxTime: { classPropertyName: "maxTime", publicName: "maxTime", isSignal: true, isRequired: false, transformFunction: null }, slots: { classPropertyName: "slots", publicName: "slots", isSignal: true, isRequired: false, transformFunction: null }, hour12: { classPropertyName: "hour12", publicName: "hour12", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, commitOnBlur: { classPropertyName: "commitOnBlur", publicName: "commitOnBlur", isSignal: true, isRequired: false, transformFunction: null }, embedded: { classPropertyName: "embedded", publicName: "embedded", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange", rejected: "rejected" }, host: { properties: { "class": "className()" } }, providers: [{ provide: COMPONENT_NAME, useValue: 'timeInput' }], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "listRef", first: true, predicate: ["listbox"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Focusout rides the bubbling event so the list closes and the draft\n commits only when focus leaves the whole field. -->\n<div (focusout)=\"onFocusOut($event)\">\n <ng-template #parts>\n <input\n #field\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n aria-autocomplete=\"list\"\n [class]=\"inputClass()\"\n [disabled]=\"disabled()\"\n [placeholder]=\"resolvedPlaceholder()\"\n [value]=\"displayText()\"\n [attr.aria-label]=\"label()\"\n [attr.aria-expanded]=\"list.open()\"\n [attr.aria-controls]=\"list.listboxId\"\n [attr.aria-activedescendant]=\"list.activeDescendantId()\"\n [attr.aria-describedby]=\"ariaDescribedBy() ?? null\"\n [attr.aria-invalid]=\"showError() || draftInvalid() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onInputKeydown($event)\"\n (input)=\"onInput()\"\n />\n <span [class]=\"toggleWrapClass()\">\n <button\n icon-button\n type=\"button\"\n size=\"sm\"\n aria-haspopup=\"listbox\"\n [symbolName]=\"componentOptions().toggleSymbol ?? 'schedule'\"\n [attr.aria-expanded]=\"list.open()\"\n [disable]=\"disabled()\"\n (click)=\"onToggle()\"\n >\n Choose time\n </button>\n </span>\n </ng-template>\n\n @if (embedded()) {\n <!-- A composer (uni-date-time-input) owns the field chrome. -->\n <div [class]=\"embeddedClass()\"><ng-container [ngTemplateOutlet]=\"parts\" /></div>\n } @else {\n <uni-input-box [error]=\"showError() || draftInvalid()\" [disabled]=\"disabled()\">\n <div [class]=\"rowClass()\"><ng-container [ngTemplateOutlet]=\"parts\" /></div>\n </uni-input-box>\n }\n\n @if (list.open()) {\n <ul
|
|
5914
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniTimeInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5915
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniTimeInputComponent, isStandalone: true, selector: "uni-time-input, TimeInput", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, minuteStep: { classPropertyName: "minuteStep", publicName: "minuteStep", isSignal: true, isRequired: false, transformFunction: null }, minTime: { classPropertyName: "minTime", publicName: "minTime", isSignal: true, isRequired: false, transformFunction: null }, maxTime: { classPropertyName: "maxTime", publicName: "maxTime", isSignal: true, isRequired: false, transformFunction: null }, slots: { classPropertyName: "slots", publicName: "slots", isSignal: true, isRequired: false, transformFunction: null }, hour12: { classPropertyName: "hour12", publicName: "hour12", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, commitOnBlur: { classPropertyName: "commitOnBlur", publicName: "commitOnBlur", isSignal: true, isRequired: false, transformFunction: null }, embedded: { classPropertyName: "embedded", publicName: "embedded", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange", rejected: "rejected" }, host: { properties: { "class": "className()" } }, providers: [{ provide: COMPONENT_NAME, useValue: 'timeInput' }], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "listRef", first: true, predicate: ["listbox"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Focusout rides the bubbling event so the list closes and the draft\n commits only when focus leaves the whole field. -->\n<div (focusout)=\"onFocusOut($event)\">\n <ng-template #parts>\n <input\n #field\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n aria-autocomplete=\"list\"\n [class]=\"inputClass()\"\n [disabled]=\"disabled()\"\n [placeholder]=\"resolvedPlaceholder()\"\n [value]=\"displayText()\"\n [attr.aria-label]=\"label()\"\n [attr.aria-expanded]=\"list.open()\"\n [attr.aria-controls]=\"list.listboxId\"\n [attr.aria-activedescendant]=\"list.activeDescendantId()\"\n [attr.aria-describedby]=\"ariaDescribedBy() ?? null\"\n [attr.aria-invalid]=\"showError() || draftInvalid() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onInputKeydown($event)\"\n (input)=\"onInput()\"\n />\n <span [class]=\"toggleWrapClass()\">\n <button\n icon-button\n type=\"button\"\n size=\"sm\"\n aria-haspopup=\"listbox\"\n [symbolName]=\"componentOptions().toggleSymbol ?? 'schedule'\"\n [attr.aria-expanded]=\"list.open()\"\n [disable]=\"disabled()\"\n (click)=\"onToggle()\"\n >\n Choose time\n </button>\n </span>\n </ng-template>\n\n @if (embedded()) {\n <!-- A composer (uni-date-time-input) owns the field chrome. -->\n <div [class]=\"embeddedClass()\"><ng-container [ngTemplateOutlet]=\"parts\" /></div>\n } @else {\n <uni-input-box [error]=\"showError() || draftInvalid()\" [disabled]=\"disabled()\">\n <div [class]=\"rowClass()\"><ng-container [ngTemplateOutlet]=\"parts\" /></div>\n </uni-input-box>\n }\n\n @if (list.open()) {\n <ul\n #listbox\n [id]=\"list.listboxId\"\n role=\"listbox\"\n [attr.popover]=\"popupAttr\"\n [attr.aria-label]=\"label()\"\n [class]=\"listClass()\"\n >\n @for (time of options(); track time; let i = $index) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <li\n role=\"option\"\n [id]=\"list.optionId(i)\"\n [class.active]=\"i === list.activeIndex()\"\n [attr.aria-selected]=\"time === value()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"selectOption(time)\"\n >\n {{ optionLabels()[i] }}\n </li>\n }\n </ul>\n }\n\n <!-- Commits and rejections are otherwise a silent reformat. -->\n <span role=\"status\" aria-live=\"polite\" [class]=\"srOnly\">{{ announcer.message() }}</span>\n</div>\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: UniIconButtonComponent, selector: "button[uni-icon-button], button[icon-button]", inputs: ["ariaLabel", "iconName", "symbolName", "variant", "size", "disable", "loading", "opticalSize"] }, { kind: "component", type: UniInputBoxComponent, selector: "uni-input-box", inputs: ["disabled", "error", "minWidth", "height"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5707
5916
|
}
|
|
5708
5917
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniTimeInputComponent, decorators: [{
|
|
5709
5918
|
type: Component,
|
|
5710
|
-
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'uni-time-input, TimeInput', imports: [NgTemplateOutlet, UniIconButtonComponent, UniInputBoxComponent], providers: [{ provide: COMPONENT_NAME, useValue: 'timeInput' }], host: { '[class]': 'className()' }, template: "<!-- Focusout rides the bubbling event so the list closes and the draft\n commits only when focus leaves the whole field. -->\n<div (focusout)=\"onFocusOut($event)\">\n <ng-template #parts>\n <input\n #field\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n aria-autocomplete=\"list\"\n [class]=\"inputClass()\"\n [disabled]=\"disabled()\"\n [placeholder]=\"resolvedPlaceholder()\"\n [value]=\"displayText()\"\n [attr.aria-label]=\"label()\"\n [attr.aria-expanded]=\"list.open()\"\n [attr.aria-controls]=\"list.listboxId\"\n [attr.aria-activedescendant]=\"list.activeDescendantId()\"\n [attr.aria-describedby]=\"ariaDescribedBy() ?? null\"\n [attr.aria-invalid]=\"showError() || draftInvalid() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onInputKeydown($event)\"\n (input)=\"onInput()\"\n />\n <span [class]=\"toggleWrapClass()\">\n <button\n icon-button\n type=\"button\"\n size=\"sm\"\n aria-haspopup=\"listbox\"\n [symbolName]=\"componentOptions().toggleSymbol ?? 'schedule'\"\n [attr.aria-expanded]=\"list.open()\"\n [disable]=\"disabled()\"\n (click)=\"onToggle()\"\n >\n Choose time\n </button>\n </span>\n </ng-template>\n\n @if (embedded()) {\n <!-- A composer (uni-date-time-input) owns the field chrome. -->\n <div [class]=\"embeddedClass()\"><ng-container [ngTemplateOutlet]=\"parts\" /></div>\n } @else {\n <uni-input-box [error]=\"showError() || draftInvalid()\" [disabled]=\"disabled()\">\n <div [class]=\"rowClass()\"><ng-container [ngTemplateOutlet]=\"parts\" /></div>\n </uni-input-box>\n }\n\n @if (list.open()) {\n <ul
|
|
5711
|
-
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], minuteStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }], minTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "minTime", required: false }] }], maxTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxTime", required: false }] }], slots: [{ type: i0.Input, args: [{ isSignal: true, alias: "slots", required: false }] }], hour12: [{ type: i0.Input, args: [{ isSignal: true, alias: "hour12", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], commitOnBlur: [{ type: i0.Input, args: [{ isSignal: true, alias: "commitOnBlur", required: false }] }], embedded: [{ type: i0.Input, args: [{ isSignal: true, alias: "embedded", required: false }] }], rejected: [{ type: i0.Output, args: ["rejected"] }], inputRef: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], listRef: [{ type: i0.ViewChild, args: ['listbox', { isSignal: true }] }] } });
|
|
5919
|
+
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'uni-time-input, TimeInput', imports: [NgTemplateOutlet, UniIconButtonComponent, UniInputBoxComponent], providers: [{ provide: COMPONENT_NAME, useValue: 'timeInput' }], host: { '[class]': 'className()' }, template: "<!-- Focusout rides the bubbling event so the list closes and the draft\n commits only when focus leaves the whole field. -->\n<div (focusout)=\"onFocusOut($event)\">\n <ng-template #parts>\n <input\n #field\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n aria-autocomplete=\"list\"\n [class]=\"inputClass()\"\n [disabled]=\"disabled()\"\n [placeholder]=\"resolvedPlaceholder()\"\n [value]=\"displayText()\"\n [attr.aria-label]=\"label()\"\n [attr.aria-expanded]=\"list.open()\"\n [attr.aria-controls]=\"list.listboxId\"\n [attr.aria-activedescendant]=\"list.activeDescendantId()\"\n [attr.aria-describedby]=\"ariaDescribedBy() ?? null\"\n [attr.aria-invalid]=\"showError() || draftInvalid() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onInputKeydown($event)\"\n (input)=\"onInput()\"\n />\n <span [class]=\"toggleWrapClass()\">\n <button\n icon-button\n type=\"button\"\n size=\"sm\"\n aria-haspopup=\"listbox\"\n [symbolName]=\"componentOptions().toggleSymbol ?? 'schedule'\"\n [attr.aria-expanded]=\"list.open()\"\n [disable]=\"disabled()\"\n (click)=\"onToggle()\"\n >\n Choose time\n </button>\n </span>\n </ng-template>\n\n @if (embedded()) {\n <!-- A composer (uni-date-time-input) owns the field chrome. -->\n <div [class]=\"embeddedClass()\"><ng-container [ngTemplateOutlet]=\"parts\" /></div>\n } @else {\n <uni-input-box [error]=\"showError() || draftInvalid()\" [disabled]=\"disabled()\">\n <div [class]=\"rowClass()\"><ng-container [ngTemplateOutlet]=\"parts\" /></div>\n </uni-input-box>\n }\n\n @if (list.open()) {\n <ul\n #listbox\n [id]=\"list.listboxId\"\n role=\"listbox\"\n [attr.popover]=\"popupAttr\"\n [attr.aria-label]=\"label()\"\n [class]=\"listClass()\"\n >\n @for (time of options(); track time; let i = $index) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <li\n role=\"option\"\n [id]=\"list.optionId(i)\"\n [class.active]=\"i === list.activeIndex()\"\n [attr.aria-selected]=\"time === value()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"selectOption(time)\"\n >\n {{ optionLabels()[i] }}\n </li>\n }\n </ul>\n }\n\n <!-- Commits and rejections are otherwise a silent reformat. -->\n <span role=\"status\" aria-live=\"polite\" [class]=\"srOnly\">{{ announcer.message() }}</span>\n</div>\n" }]
|
|
5920
|
+
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], minuteStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }], minTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "minTime", required: false }] }], maxTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxTime", required: false }] }], slots: [{ type: i0.Input, args: [{ isSignal: true, alias: "slots", required: false }] }], hour12: [{ type: i0.Input, args: [{ isSignal: true, alias: "hour12", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], commitOnBlur: [{ type: i0.Input, args: [{ isSignal: true, alias: "commitOnBlur", required: false }] }], embedded: [{ type: i0.Input, args: [{ isSignal: true, alias: "embedded", required: false }] }], rejected: [{ type: i0.Output, args: ["rejected"] }], inputRef: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], listRef: [{ type: i0.ViewChild, args: ['listbox', { isSignal: true }] }] } });
|
|
5712
5921
|
|
|
5713
5922
|
/**
|
|
5714
5923
|
* One field for a date and a time: a thin composer seating a uni-date-input
|
|
@@ -6303,10 +6512,23 @@ class UniExpandComponent extends BaseComponent {
|
|
|
6303
6512
|
const override = this.transitionSpeed();
|
|
6304
6513
|
if (override !== undefined)
|
|
6305
6514
|
return override;
|
|
6306
|
-
const speed = this.componentOptions().transitionSpeed ?? EXPAND_DEFAULT_SPEED;
|
|
6307
6515
|
const height = this.contentHeight();
|
|
6516
|
+
const speed = this.baseSpeed();
|
|
6308
6517
|
return height === undefined ? speed : expandDuration(height, speed);
|
|
6309
6518
|
}, ...(ngDevMode ? [{ debugName: "duration" }] : /* istanbul ignore next */ []));
|
|
6519
|
+
/**
|
|
6520
|
+
* Base speed in seconds, before the size-aware scaling above. The
|
|
6521
|
+
* deprecated `transitionSpeed` option wins when a theme still sets it;
|
|
6522
|
+
* otherwise the `motion` token's duration (ms) converts to seconds.
|
|
6523
|
+
*/
|
|
6524
|
+
baseSpeed = computed(() => {
|
|
6525
|
+
const options = this.componentOptions();
|
|
6526
|
+
if (options.transitionSpeed !== undefined)
|
|
6527
|
+
return options.transitionSpeed;
|
|
6528
|
+
return this.theme.motion(options.motion ?? 'reveal').duration / 1000;
|
|
6529
|
+
}, ...(ngDevMode ? [{ debugName: "baseSpeed" }] : /* istanbul ignore next */ []));
|
|
6530
|
+
/** Curve for the reveal, from the same token as the speed. */
|
|
6531
|
+
easing = computed(() => this.theme.motion(this.componentOptions().motion ?? 'reveal').easing, ...(ngDevMode ? [{ debugName: "easing" }] : /* istanbul ignore next */ []));
|
|
6310
6532
|
cssDuration = computed(() => `${this.duration()}s`, ...(ngDevMode ? [{ debugName: "cssDuration" }] : /* istanbul ignore next */ []));
|
|
6311
6533
|
/**
|
|
6312
6534
|
* A custom element is `display: inline` by default, which would lay the
|
|
@@ -6339,19 +6561,19 @@ class UniExpandComponent extends BaseComponent {
|
|
|
6339
6561
|
* `duration`, so the classes stay static while timing tracks the theme and
|
|
6340
6562
|
* the content's size through signals alone.
|
|
6341
6563
|
*/
|
|
6342
|
-
expandAnimation = css(motionSafe({
|
|
6564
|
+
expandAnimation = computed(() => css(motionSafe({
|
|
6343
6565
|
overflow: 'hidden',
|
|
6344
|
-
animation: `${this.expand}
|
|
6345
|
-
}));
|
|
6346
|
-
collapseAnimation = css(motionSafe({
|
|
6566
|
+
animation: `${this.expand} ${this.easing()} ${this.baseSpeed()}s`,
|
|
6567
|
+
})), ...(ngDevMode ? [{ debugName: "expandAnimation" }] : /* istanbul ignore next */ []));
|
|
6568
|
+
collapseAnimation = computed(() => css(motionSafe({
|
|
6347
6569
|
overflow: 'hidden',
|
|
6348
|
-
animation: `${this.collapse}
|
|
6349
|
-
}));
|
|
6570
|
+
animation: `${this.collapse} ${this.easing()} ${this.baseSpeed()}s`,
|
|
6571
|
+
})), ...(ngDevMode ? [{ debugName: "collapseAnimation" }] : /* istanbul ignore next */ []));
|
|
6350
6572
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniExpandComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6351
6573
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniExpandComponent, isStandalone: true, selector: "uni-expand", inputs: { collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, transitionSpeed: { classPropertyName: "transitionSpeed", publicName: "transitionSpeed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange" }, host: { properties: { "attr.id": "regionId", "class": "hostClassName" } }, providers: [{ provide: COMPONENT_NAME, useValue: 'expand' }], viewQueries: [{ propertyName: "contentRef", first: true, predicate: ["content"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `@if (!collapsed()) {
|
|
6352
6574
|
<div
|
|
6353
|
-
[animate.enter]="ready() ? expandAnimation : ''"
|
|
6354
|
-
[animate.leave]="collapseAnimation"
|
|
6575
|
+
[animate.enter]="ready() ? expandAnimation() : ''"
|
|
6576
|
+
[animate.leave]="collapseAnimation()"
|
|
6355
6577
|
[class]="expandClassName"
|
|
6356
6578
|
[style.animation-duration]="cssDuration()"
|
|
6357
6579
|
>
|
|
@@ -6370,8 +6592,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
6370
6592
|
providers: [{ provide: COMPONENT_NAME, useValue: 'expand' }],
|
|
6371
6593
|
template: `@if (!collapsed()) {
|
|
6372
6594
|
<div
|
|
6373
|
-
[animate.enter]="ready() ? expandAnimation : ''"
|
|
6374
|
-
[animate.leave]="collapseAnimation"
|
|
6595
|
+
[animate.enter]="ready() ? expandAnimation() : ''"
|
|
6596
|
+
[animate.leave]="collapseAnimation()"
|
|
6375
6597
|
[class]="expandClassName"
|
|
6376
6598
|
[style.animation-duration]="cssDuration()"
|
|
6377
6599
|
>
|
|
@@ -6417,9 +6639,20 @@ class UniExpandToggleComponent {
|
|
|
6417
6639
|
* region is size-scaled or overridden per instance.
|
|
6418
6640
|
*/
|
|
6419
6641
|
transitionSpeed = input(...(ngDevMode ? [undefined, { debugName: "transitionSpeed" }] : /* istanbul ignore next */ []));
|
|
6420
|
-
/** Fallback clock when no `transitionSpeed` is bound: the `expand`
|
|
6421
|
-
|
|
6422
|
-
|
|
6642
|
+
/** Fallback clock when no `transitionSpeed` is bound: the `expand` entry's
|
|
6643
|
+
motion token — the same one the region itself reads. */
|
|
6644
|
+
themeService = inject(ThemeService);
|
|
6645
|
+
expandOptions = this.themeService.getComponentOptions('expand');
|
|
6646
|
+
speed = computed(() => {
|
|
6647
|
+
const override = this.transitionSpeed();
|
|
6648
|
+
if (override !== undefined)
|
|
6649
|
+
return override;
|
|
6650
|
+
const options = this.expandOptions();
|
|
6651
|
+
// Same order uni-expand uses, so the chevron and the region never drift.
|
|
6652
|
+
if (options.transitionSpeed !== undefined)
|
|
6653
|
+
return options.transitionSpeed;
|
|
6654
|
+
return this.themeService.motion(options.motion ?? 'reveal').duration / 1000;
|
|
6655
|
+
}, ...(ngDevMode ? [{ debugName: "speed" }] : /* istanbul ignore next */ []));
|
|
6423
6656
|
/**
|
|
6424
6657
|
* The glyph rotates, never the host.
|
|
6425
6658
|
*
|
|
@@ -6900,7 +7133,10 @@ class UniMenuItemComponent {
|
|
|
6900
7133
|
const variantStyle = variant
|
|
6901
7134
|
? this.theme.component('menuItem')().variants?.[variant]
|
|
6902
7135
|
: undefined;
|
|
6903
|
-
|
|
7136
|
+
// Neither set means no transition at all — the escape hatch predates the
|
|
7137
|
+
// motion scale and still works. The deprecated option wins over the token.
|
|
7138
|
+
const motion = options.motion ? this.theme.motion(options.motion) : undefined;
|
|
7139
|
+
const transitionSpeed = options.transitionSpeed ?? (motion ? motion.duration / 1000 : 0);
|
|
6904
7140
|
return css([
|
|
6905
7141
|
{
|
|
6906
7142
|
display: 'flex',
|
|
@@ -6929,7 +7165,7 @@ class UniMenuItemComponent {
|
|
|
6929
7165
|
pointerEvents: 'none',
|
|
6930
7166
|
},
|
|
6931
7167
|
},
|
|
6932
|
-
transitionSpeed > 0 && { transition: `all ${transitionSpeed}s ease` },
|
|
7168
|
+
transitionSpeed > 0 && { transition: `all ${transitionSpeed}s ${motion?.easing ?? 'ease'}` },
|
|
6933
7169
|
// Variant tones override the base look. A variant that restyles the
|
|
6934
7170
|
// highlight must key it with HOVER_OR_KEYBOARD_FOCUS — Emotion merges by
|
|
6935
7171
|
// exact selector text, so a variant spelling it `&:hover, &:focus`
|
|
@@ -7209,6 +7445,9 @@ class UniMultiSelectComponent {
|
|
|
7209
7445
|
})), ...(ngDevMode ? [{ debugName: "optionsWithSelections" }] : /* istanbul ignore next */ []));
|
|
7210
7446
|
className = css({ display: 'contents' });
|
|
7211
7447
|
handleCheck(checked, value) {
|
|
7448
|
+
// The rendered checkbox is disabled, so this only guards a direct call.
|
|
7449
|
+
if (this.options().find((option) => option.value === value)?.disabled)
|
|
7450
|
+
return;
|
|
7212
7451
|
const selections = this.selections();
|
|
7213
7452
|
if (!selections && !checked)
|
|
7214
7453
|
return;
|
|
@@ -7223,8 +7462,11 @@ class UniMultiSelectComponent {
|
|
|
7223
7462
|
return;
|
|
7224
7463
|
}
|
|
7225
7464
|
}
|
|
7465
|
+
/** Selects every *enabled* option — a disabled option is not committable. */
|
|
7226
7466
|
selectAll() {
|
|
7227
|
-
const allValues = this.options()
|
|
7467
|
+
const allValues = this.options()
|
|
7468
|
+
.filter((option) => !option.disabled)
|
|
7469
|
+
.map((option) => option.value);
|
|
7228
7470
|
this.updates.emit(allValues);
|
|
7229
7471
|
}
|
|
7230
7472
|
deselectAll() {
|
|
@@ -7236,11 +7478,11 @@ class UniMultiSelectComponent {
|
|
|
7236
7478
|
width: '100%',
|
|
7237
7479
|
});
|
|
7238
7480
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniMultiSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7239
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniMultiSelectComponent, isStandalone: true, selector: "uni-multi-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, selections: { classPropertyName: "selections", publicName: "selections", isSignal: true, isRequired: false, transformFunction: null }, flexDirection: { classPropertyName: "flexDirection", publicName: "flexDirection", isSignal: true, isRequired: false, transformFunction: null }, checkboxGap: { classPropertyName: "checkboxGap", publicName: "checkboxGap", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { updates: "updates" }, host: { properties: { "class": "className" } }, ngImport: i0, template: "<div box-layout display=\"flex\" [flexDirection]=\"flexDirection()\" [gap]=\"checkboxGap()\">\n <!-- track $index: option values may be objects and consumers rebuild the\n array, so identity tracking recreated every node (NG0956). -->\n @for (option of options(); track $index) {\n <div [class]=\"optionWrapper\">\n <uni-checkbox\n [label]=\"option.label\"\n [checked]=\"values().indexOf(option.value) > -1\"\n (checkedChange)=\"handleCheck($event, option.value)\"\n variant=\"primary\"\n >\n </uni-checkbox>\n </div>\n }\n</div>\n", dependencies: [{ kind: "component", type: UniCheckboxComponent, selector: "uni-checkbox", inputs: ["checked", "disabled", "touched", "invalid", "dirty", "required", "ariaDescribedBy", "label", "indeterminate"], outputs: ["checkedChange", "touchedChange", "indeterminateChange"] }, { kind: "component", type: UniBoxComponent, selector: "[uni-box-layout], [box-layout]", inputs: ["color", "backgroundColor", "borderRadius", "borderRadiusLeft", "borderRadiusRight", "borderRadiusTop", "borderRadiusBottom", "padding", "paddingHorizontal", "paddingVertical", "paddingLeft", "paddingRight", "paddingTop", "paddingBottom", "border", "borderTop", "borderBottom", "borderLeft", "borderRight", "dashBorder", "alignSelf", "alignItems", "alignContent", "justifyContent", "grow", "display", "position", "inset", "height", "minHeight", "maxHeight", "width", "minWidth", "maxWidth", "ignoreDir", "gridArea", "gridColumn", "gridRow", "overflow", "elevation", "shadow", "gap", "fullWidth", "fullHeight", "flexDirection", "textAlign", "wrapItems", "zIndex"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7481
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniMultiSelectComponent, isStandalone: true, selector: "uni-multi-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, selections: { classPropertyName: "selections", publicName: "selections", isSignal: true, isRequired: false, transformFunction: null }, flexDirection: { classPropertyName: "flexDirection", publicName: "flexDirection", isSignal: true, isRequired: false, transformFunction: null }, checkboxGap: { classPropertyName: "checkboxGap", publicName: "checkboxGap", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { updates: "updates" }, host: { properties: { "class": "className" } }, ngImport: i0, template: "<div box-layout display=\"flex\" [flexDirection]=\"flexDirection()\" [gap]=\"checkboxGap()\">\n <!-- track $index: option values may be objects and consumers rebuild the\n array, so identity tracking recreated every node (NG0956). -->\n @for (option of options(); track $index) {\n <div [class]=\"optionWrapper\">\n <uni-checkbox\n [label]=\"option.label\"\n [checked]=\"values().indexOf(option.value) > -1\"\n (checkedChange)=\"handleCheck($event, option.value)\"\n variant=\"primary\"\n [disabled]=\"!!option.disabled\"\n >\n </uni-checkbox>\n </div>\n }\n</div>\n", dependencies: [{ kind: "component", type: UniCheckboxComponent, selector: "uni-checkbox", inputs: ["checked", "disabled", "touched", "invalid", "dirty", "required", "ariaDescribedBy", "label", "indeterminate"], outputs: ["checkedChange", "touchedChange", "indeterminateChange"] }, { kind: "component", type: UniBoxComponent, selector: "[uni-box-layout], [box-layout]", inputs: ["color", "backgroundColor", "borderRadius", "borderRadiusLeft", "borderRadiusRight", "borderRadiusTop", "borderRadiusBottom", "padding", "paddingHorizontal", "paddingVertical", "paddingLeft", "paddingRight", "paddingTop", "paddingBottom", "border", "borderTop", "borderBottom", "borderLeft", "borderRight", "dashBorder", "alignSelf", "alignItems", "alignContent", "justifyContent", "grow", "display", "position", "inset", "height", "minHeight", "maxHeight", "width", "minWidth", "maxWidth", "ignoreDir", "gridArea", "gridColumn", "gridRow", "overflow", "elevation", "shadow", "gap", "fullWidth", "fullHeight", "flexDirection", "textAlign", "wrapItems", "zIndex"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7240
7482
|
}
|
|
7241
7483
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniMultiSelectComponent, decorators: [{
|
|
7242
7484
|
type: Component,
|
|
7243
|
-
args: [{ selector: 'uni-multi-select', imports: [UniCheckboxComponent, UniBoxComponent], host: { '[class]': 'className' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div box-layout display=\"flex\" [flexDirection]=\"flexDirection()\" [gap]=\"checkboxGap()\">\n <!-- track $index: option values may be objects and consumers rebuild the\n array, so identity tracking recreated every node (NG0956). -->\n @for (option of options(); track $index) {\n <div [class]=\"optionWrapper\">\n <uni-checkbox\n [label]=\"option.label\"\n [checked]=\"values().indexOf(option.value) > -1\"\n (checkedChange)=\"handleCheck($event, option.value)\"\n variant=\"primary\"\n >\n </uni-checkbox>\n </div>\n }\n</div>\n" }]
|
|
7485
|
+
args: [{ selector: 'uni-multi-select', imports: [UniCheckboxComponent, UniBoxComponent], host: { '[class]': 'className' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div box-layout display=\"flex\" [flexDirection]=\"flexDirection()\" [gap]=\"checkboxGap()\">\n <!-- track $index: option values may be objects and consumers rebuild the\n array, so identity tracking recreated every node (NG0956). -->\n @for (option of options(); track $index) {\n <div [class]=\"optionWrapper\">\n <uni-checkbox\n [label]=\"option.label\"\n [checked]=\"values().indexOf(option.value) > -1\"\n (checkedChange)=\"handleCheck($event, option.value)\"\n variant=\"primary\"\n [disabled]=\"!!option.disabled\"\n >\n </uni-checkbox>\n </div>\n }\n</div>\n" }]
|
|
7244
7486
|
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], selections: [{ type: i0.Input, args: [{ isSignal: true, alias: "selections", required: false }] }], updates: [{ type: i0.Output, args: ["updates"] }], flexDirection: [{ type: i0.Input, args: [{ isSignal: true, alias: "flexDirection", required: false }] }], checkboxGap: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkboxGap", required: false }] }] } });
|
|
7245
7487
|
|
|
7246
7488
|
class UniMultiSelectDropdownComponent extends BaseComponent {
|
|
@@ -7283,10 +7525,18 @@ class UniMultiSelectDropdownComponent extends BaseComponent {
|
|
|
7283
7525
|
* arithmetic — wrapping, Home/End, and never pointing past a list the
|
|
7284
7526
|
* filter has narrowed — the same contract `uni-search-input` and
|
|
7285
7527
|
* `uni-tag-input` use, so the keys behave identically across all three.
|
|
7528
|
+
*
|
|
7529
|
+
* `disabled` indexes into `filteredOptions`, matching `count`: arrows step
|
|
7530
|
+
* over disabled rows and Home/End land on the nearest enabled one, so the
|
|
7531
|
+
* focus target is always a checkbox that can actually take focus.
|
|
7286
7532
|
*/
|
|
7287
7533
|
list = createListboxNavigation({
|
|
7288
7534
|
count: () => this.filteredOptions().length,
|
|
7289
7535
|
idPrefix: 'uni-multi-select',
|
|
7536
|
+
disabled: (index) => !!this.filteredOptions()[index]?.disabled,
|
|
7537
|
+
// Focus rides the option checkboxes here, not a text field, so Home/End
|
|
7538
|
+
// have no caret to defer to — unlike the combobox-style consumers.
|
|
7539
|
+
homeEndNavigates: true,
|
|
7290
7540
|
});
|
|
7291
7541
|
/** Announced with the selection so the count is not left to guesswork. */
|
|
7292
7542
|
selectionSummary = computed(() => {
|
|
@@ -7353,11 +7603,18 @@ class UniMultiSelectDropdownComponent extends BaseComponent {
|
|
|
7353
7603
|
this.list.show();
|
|
7354
7604
|
this.list.setActive(index);
|
|
7355
7605
|
}
|
|
7606
|
+
/**
|
|
7607
|
+
* Selects every *enabled* option. A disabled option is not committable, so
|
|
7608
|
+
* "select all" must not commit one on the user's behalf — the same rule
|
|
7609
|
+
* `toggleOption` and the keyboard path follow.
|
|
7610
|
+
*/
|
|
7356
7611
|
selectAll() {
|
|
7357
7612
|
if (this.disabled())
|
|
7358
7613
|
return;
|
|
7359
7614
|
this.touched.set(true);
|
|
7360
|
-
const allValues = this.options()
|
|
7615
|
+
const allValues = this.options()
|
|
7616
|
+
.filter((option) => !option.disabled)
|
|
7617
|
+
.map((option) => option.value);
|
|
7361
7618
|
this.value.set(allValues);
|
|
7362
7619
|
}
|
|
7363
7620
|
deselectAll() {
|
|
@@ -7370,7 +7627,8 @@ class UniMultiSelectDropdownComponent extends BaseComponent {
|
|
|
7370
7627
|
return computed(() => this.value().includes(option.value));
|
|
7371
7628
|
}
|
|
7372
7629
|
toggleOption(option, checked) {
|
|
7373
|
-
|
|
7630
|
+
// The nav hook keeps the keyboard off disabled rows; this stops a pointer.
|
|
7631
|
+
if (this.disabled() || option.disabled)
|
|
7374
7632
|
return;
|
|
7375
7633
|
this.touched.set(true);
|
|
7376
7634
|
const { value } = option;
|
|
@@ -7386,7 +7644,7 @@ class UniMultiSelectDropdownComponent extends BaseComponent {
|
|
|
7386
7644
|
});
|
|
7387
7645
|
}
|
|
7388
7646
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniMultiSelectDropdownComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
7389
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniMultiSelectDropdownComponent, isStandalone: true, selector: "uni-multi-select-dropdown", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, debounceTime: { classPropertyName: "debounceTime", publicName: "debounceTime", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, host: { properties: { "class": "className" } }, providers: [{ provide: COMPONENT_NAME, useValue: 'multiSelectDropdown' }], viewQueries: [{ propertyName: "optionRefs", predicate: ["optionRow"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<button\n [class]=\"triggerClass\"\n #trigger\n [style.cursor]=\"disabled() ? 'default' : 'pointer'\"\n [attr.aria-required]=\"required() ? true : null\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-describedby]=\"ariaDescribedBy() || null\"\n (click)=\"!disabled() && touched.set(true)\"\n>\n @if (label(); as fieldLabel) {\n <span [class]=\"srOnly\">{{ fieldLabel }},</span>\n }\n <span [class]=\"srOnly\">{{ selectionSummary() }}</span>\n <uni-input-box [error]=\"showError()\" [disabled]=\"disabled()\">\n <div\n row-layout\n alignItems=\"center\"\n justifyContent=\"space-between\"\n [fullWidth]=\"true\"\n [minWidth]=\"0\"\n paddingLeft=\"sm\"\n >\n <span uni-text\n display=\"block\"\n [typeface]=\"componentOptions().textRole\"\n [color]=\"textColor()\"\n [ellipsis]=\"true\"\n [style.flex-grow]=\"1\"\n >{{ selectedLabelsText() }}</span>\n <uni-symbol name=\"keyboard_arrow_down\" [style.flex-shrink]=\"0\"></uni-symbol>\n </div>\n </uni-input-box>\n</button>\n<uni-dropdown\n #dropdown\n [trigger]=\"trigger\"\n ariaHasPopup=\"dialog\"\n (dropdownShowing)=\"$event && searchInput.focus()\"\n (dropdownHiding)=\"$event && trigger.focus()\"\n>\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n <div (keydown)=\"onPanelKeydown($event)\">\n <div box-layout gap=\"xs\" padding=\"xs\">\n <input\n #searchInput\n type=\"text\"\n [class]=\"searchInputClass()\"\n [value]=\"query()\"\n (input)=\"handleQueryInput($event)\"\n placeholder=\"Search...\"\n aria-label=\"Filter options\"\n (click)=\"$event.stopPropagation()\"\n [disabled]=\"disabled()\"\n />\n </div>\n\n <uni-divider [border]=\"componentOptions().dividerBorder\" />\n\n <div\n stack-layout\n gap=\"xs\"\n padding=\"xs\"\n role=\"group\"\n [attr.aria-label]=\"label() ? label() + ' options' : 'Options'\"\n >\n @for (option of filteredOptions(); track option.value; let i = $index) {\n <div #optionRow (focusin)=\"onOptionFocus(i)\">\n <uni-checkbox\n [label]=\"option.label\"\n [checked]=\"isOptionSelected(option)()\"\n (checkedChange)=\"toggleOption(option, $event)\"\n variant=\"primary\"\n [disabled]=\"disabled()\"\n >\n </uni-checkbox>\n </div>\n }\n @if (filteredOptions().length === 0) {\n <span uni-text=\"label\" role=\"status\">No options match.</span>\n }\n </div>\n\n <uni-divider [border]=\"componentOptions().dividerBorder\" />\n\n <div row-layout gap=\"xs\" justifyContent=\"space-around\" padding=\"xs\">\n <button text-button (click)=\"dropdown.hideDropdown()\" size=\"sm\" variant=\"ghost\">Done</button>\n </div>\n </div>\n</uni-dropdown>\n", dependencies: [{ kind: "component", type: UniCheckboxComponent, selector: "uni-checkbox", inputs: ["checked", "disabled", "touched", "invalid", "dirty", "required", "ariaDescribedBy", "label", "indeterminate"], outputs: ["checkedChange", "touchedChange", "indeterminateChange"] }, { kind: "component", type: UniBoxComponent, selector: "[uni-box-layout], [box-layout]", inputs: ["color", "backgroundColor", "borderRadius", "borderRadiusLeft", "borderRadiusRight", "borderRadiusTop", "borderRadiusBottom", "padding", "paddingHorizontal", "paddingVertical", "paddingLeft", "paddingRight", "paddingTop", "paddingBottom", "border", "borderTop", "borderBottom", "borderLeft", "borderRight", "dashBorder", "alignSelf", "alignItems", "alignContent", "justifyContent", "grow", "display", "position", "inset", "height", "minHeight", "maxHeight", "width", "minWidth", "maxWidth", "ignoreDir", "gridArea", "gridColumn", "gridRow", "overflow", "elevation", "shadow", "gap", "fullWidth", "fullHeight", "flexDirection", "textAlign", "wrapItems", "zIndex"] }, { kind: "component", type: UniDropdownComponent, selector: "uni-dropdown", inputs: ["trigger", "placement", "offset", "ariaHasPopup", "paddingVertical", "paddingHorizontal", "border", "borderRadius", "shadow", "color"], outputs: ["dropdownShowing", "dropdownHiding"] }, { kind: "component", type: UniStackComponent, selector: "[uni-stack-layout], [stack-layout]", inputs: ["display", "flexDirection", "minHeight"] }, { kind: "component", type: UniDividerComponent, selector: "uni-divider", inputs: ["orientation", "border"] }, { kind: "component", type: UniButtonComponent, selector: "button[uni-text-button], button[text-button]", inputs: ["disable", "loading", "fullWidth", "symbolLeft", "symbolRight"] }, { kind: "component", type: UniTextComponent, selector: "[uni-text]", inputs: ["uni-text", "typeface", "color", "display", "align", "nowrap", "maxWidth", "ellipsis"] }, { kind: "component", type: UniSymbolComponent, selector: "uni-symbol", inputs: ["name", "fill", "weight", "grade", "opticalSize"] }, { kind: "component", type: UniRowComponent, selector: "[uni-row-layout], [row-layout]", inputs: ["display", "flexDirection", "minWidth"] }, { kind: "component", type: UniInputBoxComponent, selector: "uni-input-box", inputs: ["disabled", "error", "minWidth", "height"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7647
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniMultiSelectDropdownComponent, isStandalone: true, selector: "uni-multi-select-dropdown", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, debounceTime: { classPropertyName: "debounceTime", publicName: "debounceTime", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, host: { properties: { "class": "className" } }, providers: [{ provide: COMPONENT_NAME, useValue: 'multiSelectDropdown' }], viewQueries: [{ propertyName: "optionRefs", predicate: ["optionRow"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<button\n [class]=\"triggerClass\"\n #trigger\n [style.cursor]=\"disabled() ? 'default' : 'pointer'\"\n [attr.aria-required]=\"required() ? true : null\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-describedby]=\"ariaDescribedBy() || null\"\n (click)=\"!disabled() && touched.set(true)\"\n>\n @if (label(); as fieldLabel) {\n <span [class]=\"srOnly\">{{ fieldLabel }},</span>\n }\n <span [class]=\"srOnly\">{{ selectionSummary() }}</span>\n <uni-input-box [error]=\"showError()\" [disabled]=\"disabled()\">\n <div\n row-layout\n alignItems=\"center\"\n justifyContent=\"space-between\"\n [fullWidth]=\"true\"\n [minWidth]=\"0\"\n paddingLeft=\"sm\"\n >\n <span uni-text\n display=\"block\"\n [typeface]=\"componentOptions().textRole\"\n [color]=\"textColor()\"\n [ellipsis]=\"true\"\n [style.flex-grow]=\"1\"\n >{{ selectedLabelsText() }}</span>\n <uni-symbol name=\"keyboard_arrow_down\" [style.flex-shrink]=\"0\"></uni-symbol>\n </div>\n </uni-input-box>\n</button>\n<uni-dropdown\n #dropdown\n [trigger]=\"trigger\"\n ariaHasPopup=\"dialog\"\n (dropdownShowing)=\"$event && searchInput.focus()\"\n (dropdownHiding)=\"$event && trigger.focus()\"\n>\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n <div (keydown)=\"onPanelKeydown($event)\">\n <div box-layout gap=\"xs\" padding=\"xs\">\n <input\n #searchInput\n type=\"text\"\n [class]=\"searchInputClass()\"\n [value]=\"query()\"\n (input)=\"handleQueryInput($event)\"\n placeholder=\"Search...\"\n aria-label=\"Filter options\"\n (click)=\"$event.stopPropagation()\"\n [disabled]=\"disabled()\"\n />\n </div>\n\n <uni-divider [border]=\"componentOptions().dividerBorder\" />\n\n <div\n stack-layout\n gap=\"xs\"\n padding=\"xs\"\n role=\"group\"\n [attr.aria-label]=\"label() ? label() + ' options' : 'Options'\"\n >\n @for (option of filteredOptions(); track option.value; let i = $index) {\n <div #optionRow (focusin)=\"onOptionFocus(i)\">\n <uni-checkbox\n [label]=\"option.label\"\n [checked]=\"isOptionSelected(option)()\"\n (checkedChange)=\"toggleOption(option, $event)\"\n variant=\"primary\"\n [disabled]=\"disabled() || !!option.disabled\"\n >\n </uni-checkbox>\n </div>\n }\n @if (filteredOptions().length === 0) {\n <span uni-text=\"label\" role=\"status\">No options match.</span>\n }\n </div>\n\n <uni-divider [border]=\"componentOptions().dividerBorder\" />\n\n <div row-layout gap=\"xs\" justifyContent=\"space-around\" padding=\"xs\">\n <button text-button (click)=\"dropdown.hideDropdown()\" size=\"sm\" variant=\"ghost\">Done</button>\n </div>\n </div>\n</uni-dropdown>\n", dependencies: [{ kind: "component", type: UniCheckboxComponent, selector: "uni-checkbox", inputs: ["checked", "disabled", "touched", "invalid", "dirty", "required", "ariaDescribedBy", "label", "indeterminate"], outputs: ["checkedChange", "touchedChange", "indeterminateChange"] }, { kind: "component", type: UniBoxComponent, selector: "[uni-box-layout], [box-layout]", inputs: ["color", "backgroundColor", "borderRadius", "borderRadiusLeft", "borderRadiusRight", "borderRadiusTop", "borderRadiusBottom", "padding", "paddingHorizontal", "paddingVertical", "paddingLeft", "paddingRight", "paddingTop", "paddingBottom", "border", "borderTop", "borderBottom", "borderLeft", "borderRight", "dashBorder", "alignSelf", "alignItems", "alignContent", "justifyContent", "grow", "display", "position", "inset", "height", "minHeight", "maxHeight", "width", "minWidth", "maxWidth", "ignoreDir", "gridArea", "gridColumn", "gridRow", "overflow", "elevation", "shadow", "gap", "fullWidth", "fullHeight", "flexDirection", "textAlign", "wrapItems", "zIndex"] }, { kind: "component", type: UniDropdownComponent, selector: "uni-dropdown", inputs: ["trigger", "placement", "offset", "ariaHasPopup", "paddingVertical", "paddingHorizontal", "border", "borderRadius", "shadow", "color"], outputs: ["dropdownShowing", "dropdownHiding"] }, { kind: "component", type: UniStackComponent, selector: "[uni-stack-layout], [stack-layout]", inputs: ["display", "flexDirection", "minHeight"] }, { kind: "component", type: UniDividerComponent, selector: "uni-divider", inputs: ["orientation", "border"] }, { kind: "component", type: UniButtonComponent, selector: "button[uni-text-button], button[text-button]", inputs: ["disable", "loading", "fullWidth", "symbolLeft", "symbolRight"] }, { kind: "component", type: UniTextComponent, selector: "[uni-text]", inputs: ["uni-text", "typeface", "color", "display", "align", "nowrap", "maxWidth", "ellipsis"] }, { kind: "component", type: UniSymbolComponent, selector: "uni-symbol", inputs: ["name", "fill", "weight", "grade", "opticalSize"] }, { kind: "component", type: UniRowComponent, selector: "[uni-row-layout], [row-layout]", inputs: ["display", "flexDirection", "minWidth"] }, { kind: "component", type: UniInputBoxComponent, selector: "uni-input-box", inputs: ["disabled", "error", "minWidth", "height"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7390
7648
|
}
|
|
7391
7649
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniMultiSelectDropdownComponent, decorators: [{
|
|
7392
7650
|
type: Component,
|
|
@@ -7401,7 +7659,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
7401
7659
|
UniSymbolComponent,
|
|
7402
7660
|
UniRowComponent,
|
|
7403
7661
|
UniInputBoxComponent,
|
|
7404
|
-
], providers: [{ provide: COMPONENT_NAME, useValue: 'multiSelectDropdown' }], host: { '[class]': 'className' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n [class]=\"triggerClass\"\n #trigger\n [style.cursor]=\"disabled() ? 'default' : 'pointer'\"\n [attr.aria-required]=\"required() ? true : null\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-describedby]=\"ariaDescribedBy() || null\"\n (click)=\"!disabled() && touched.set(true)\"\n>\n @if (label(); as fieldLabel) {\n <span [class]=\"srOnly\">{{ fieldLabel }},</span>\n }\n <span [class]=\"srOnly\">{{ selectionSummary() }}</span>\n <uni-input-box [error]=\"showError()\" [disabled]=\"disabled()\">\n <div\n row-layout\n alignItems=\"center\"\n justifyContent=\"space-between\"\n [fullWidth]=\"true\"\n [minWidth]=\"0\"\n paddingLeft=\"sm\"\n >\n <span uni-text\n display=\"block\"\n [typeface]=\"componentOptions().textRole\"\n [color]=\"textColor()\"\n [ellipsis]=\"true\"\n [style.flex-grow]=\"1\"\n >{{ selectedLabelsText() }}</span>\n <uni-symbol name=\"keyboard_arrow_down\" [style.flex-shrink]=\"0\"></uni-symbol>\n </div>\n </uni-input-box>\n</button>\n<uni-dropdown\n #dropdown\n [trigger]=\"trigger\"\n ariaHasPopup=\"dialog\"\n (dropdownShowing)=\"$event && searchInput.focus()\"\n (dropdownHiding)=\"$event && trigger.focus()\"\n>\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n <div (keydown)=\"onPanelKeydown($event)\">\n <div box-layout gap=\"xs\" padding=\"xs\">\n <input\n #searchInput\n type=\"text\"\n [class]=\"searchInputClass()\"\n [value]=\"query()\"\n (input)=\"handleQueryInput($event)\"\n placeholder=\"Search...\"\n aria-label=\"Filter options\"\n (click)=\"$event.stopPropagation()\"\n [disabled]=\"disabled()\"\n />\n </div>\n\n <uni-divider [border]=\"componentOptions().dividerBorder\" />\n\n <div\n stack-layout\n gap=\"xs\"\n padding=\"xs\"\n role=\"group\"\n [attr.aria-label]=\"label() ? label() + ' options' : 'Options'\"\n >\n @for (option of filteredOptions(); track option.value; let i = $index) {\n <div #optionRow (focusin)=\"onOptionFocus(i)\">\n <uni-checkbox\n [label]=\"option.label\"\n [checked]=\"isOptionSelected(option)()\"\n (checkedChange)=\"toggleOption(option, $event)\"\n variant=\"primary\"\n [disabled]=\"disabled()\"\n >\n </uni-checkbox>\n </div>\n }\n @if (filteredOptions().length === 0) {\n <span uni-text=\"label\" role=\"status\">No options match.</span>\n }\n </div>\n\n <uni-divider [border]=\"componentOptions().dividerBorder\" />\n\n <div row-layout gap=\"xs\" justifyContent=\"space-around\" padding=\"xs\">\n <button text-button (click)=\"dropdown.hideDropdown()\" size=\"sm\" variant=\"ghost\">Done</button>\n </div>\n </div>\n</uni-dropdown>\n" }]
|
|
7662
|
+
], providers: [{ provide: COMPONENT_NAME, useValue: 'multiSelectDropdown' }], host: { '[class]': 'className' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n [class]=\"triggerClass\"\n #trigger\n [style.cursor]=\"disabled() ? 'default' : 'pointer'\"\n [attr.aria-required]=\"required() ? true : null\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-describedby]=\"ariaDescribedBy() || null\"\n (click)=\"!disabled() && touched.set(true)\"\n>\n @if (label(); as fieldLabel) {\n <span [class]=\"srOnly\">{{ fieldLabel }},</span>\n }\n <span [class]=\"srOnly\">{{ selectionSummary() }}</span>\n <uni-input-box [error]=\"showError()\" [disabled]=\"disabled()\">\n <div\n row-layout\n alignItems=\"center\"\n justifyContent=\"space-between\"\n [fullWidth]=\"true\"\n [minWidth]=\"0\"\n paddingLeft=\"sm\"\n >\n <span uni-text\n display=\"block\"\n [typeface]=\"componentOptions().textRole\"\n [color]=\"textColor()\"\n [ellipsis]=\"true\"\n [style.flex-grow]=\"1\"\n >{{ selectedLabelsText() }}</span>\n <uni-symbol name=\"keyboard_arrow_down\" [style.flex-shrink]=\"0\"></uni-symbol>\n </div>\n </uni-input-box>\n</button>\n<uni-dropdown\n #dropdown\n [trigger]=\"trigger\"\n ariaHasPopup=\"dialog\"\n (dropdownShowing)=\"$event && searchInput.focus()\"\n (dropdownHiding)=\"$event && trigger.focus()\"\n>\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n <div (keydown)=\"onPanelKeydown($event)\">\n <div box-layout gap=\"xs\" padding=\"xs\">\n <input\n #searchInput\n type=\"text\"\n [class]=\"searchInputClass()\"\n [value]=\"query()\"\n (input)=\"handleQueryInput($event)\"\n placeholder=\"Search...\"\n aria-label=\"Filter options\"\n (click)=\"$event.stopPropagation()\"\n [disabled]=\"disabled()\"\n />\n </div>\n\n <uni-divider [border]=\"componentOptions().dividerBorder\" />\n\n <div\n stack-layout\n gap=\"xs\"\n padding=\"xs\"\n role=\"group\"\n [attr.aria-label]=\"label() ? label() + ' options' : 'Options'\"\n >\n @for (option of filteredOptions(); track option.value; let i = $index) {\n <div #optionRow (focusin)=\"onOptionFocus(i)\">\n <uni-checkbox\n [label]=\"option.label\"\n [checked]=\"isOptionSelected(option)()\"\n (checkedChange)=\"toggleOption(option, $event)\"\n variant=\"primary\"\n [disabled]=\"disabled() || !!option.disabled\"\n >\n </uni-checkbox>\n </div>\n }\n @if (filteredOptions().length === 0) {\n <span uni-text=\"label\" role=\"status\">No options match.</span>\n }\n </div>\n\n <uni-divider [border]=\"componentOptions().dividerBorder\" />\n\n <div row-layout gap=\"xs\" justifyContent=\"space-around\" padding=\"xs\">\n <button text-button (click)=\"dropdown.hideDropdown()\" size=\"sm\" variant=\"ghost\">Done</button>\n </div>\n </div>\n</uni-dropdown>\n" }]
|
|
7405
7663
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], debounceTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "debounceTime", required: false }] }], optionRefs: [{ type: i0.ViewChildren, args: ['optionRow', { isSignal: true }] }] } });
|
|
7406
7664
|
|
|
7407
7665
|
class UniNotificationBadgeComponent extends BaseComponent {
|
|
@@ -7514,12 +7772,23 @@ class UniAlertComponent extends BaseComponent {
|
|
|
7514
7772
|
alertRef;
|
|
7515
7773
|
alertState = signal('closed', ...(ngDevMode ? [{ debugName: "alertState" }] : /* istanbul ignore next */ []));
|
|
7516
7774
|
effectiveVariant = computed(() => this.variant() || this.componentOptions().defaultVariant, ...(ngDevMode ? [{ debugName: "effectiveVariant" }] : /* istanbul ignore next */ []));
|
|
7775
|
+
/**
|
|
7776
|
+
* Timing for the enter/leave transition. The deprecated `transitionSpeed`
|
|
7777
|
+
* (seconds) wins when a theme still sets it.
|
|
7778
|
+
*/
|
|
7779
|
+
motion = computed(() => {
|
|
7780
|
+
const options = this.componentOptions();
|
|
7781
|
+
const token = this.theme.motion(options.motion ?? 'notification');
|
|
7782
|
+
return options.transitionSpeed === undefined
|
|
7783
|
+
? token
|
|
7784
|
+
: { ...token, duration: options.transitionSpeed * 1000 };
|
|
7785
|
+
}, ...(ngDevMode ? [{ debugName: "motion" }] : /* istanbul ignore next */ []));
|
|
7517
7786
|
alertClass = computed(() => css({
|
|
7518
7787
|
...this.theme.getContainerColors(this.effectiveVariant(), this.useVariant()),
|
|
7519
7788
|
...this.theme.radius(this.componentOptions().borderRadius),
|
|
7520
7789
|
...this.theme.border(this.effectiveVariant()),
|
|
7521
7790
|
...this.theme.boxShadow(this.componentOptions().elevation),
|
|
7522
|
-
transition: `all ${this.
|
|
7791
|
+
transition: `all ${this.motion().duration / 1000}s ${this.motion().easing}`,
|
|
7523
7792
|
transitionBehavior: 'allow-discrete',
|
|
7524
7793
|
opacity: 1,
|
|
7525
7794
|
top: this.componentOptions().topPosition,
|
|
@@ -7625,19 +7894,48 @@ class UniSnackbarComponent extends BaseComponent {
|
|
|
7625
7894
|
super();
|
|
7626
7895
|
effect(() => (this.show() ? this.open() : this.close()));
|
|
7627
7896
|
}
|
|
7897
|
+
/**
|
|
7898
|
+
* Timing for the enter/leave transition. The deprecated `transitionDelay`
|
|
7899
|
+
* wins when a theme still sets it — it is a CSS time string, so `0.35s` and
|
|
7900
|
+
* `350ms` both parse back to milliseconds.
|
|
7901
|
+
*/
|
|
7902
|
+
motion = computed(() => {
|
|
7903
|
+
const options = this.componentOptions();
|
|
7904
|
+
const token = this.theme.motion(options.motion ?? 'notification');
|
|
7905
|
+
const legacy = options.transitionDelay;
|
|
7906
|
+
if (!legacy)
|
|
7907
|
+
return token;
|
|
7908
|
+
const ms = legacy.trim().endsWith('ms') ? parseFloat(legacy) : parseFloat(legacy) * 1000;
|
|
7909
|
+
return Number.isFinite(ms) ? { ...token, duration: ms } : token;
|
|
7910
|
+
}, ...(ngDevMode ? [{ debugName: "motion" }] : /* istanbul ignore next */ []));
|
|
7628
7911
|
snackbarClass = computed(() => css({
|
|
7912
|
+
// The UA's `[popover]` border, before the theme's own so a themed border
|
|
7913
|
+
// still wins. Its `background-color: Canvas` needs no reset — the
|
|
7914
|
+
// container colors below beat it on origin, and resetting `background`
|
|
7915
|
+
// here would erase them, since it is a shorthand.
|
|
7916
|
+
border: 'none',
|
|
7629
7917
|
...this.theme.getContainerColors(this.variant() || 'primary', this.useVariant()),
|
|
7630
7918
|
...this.theme.radius('sm'),
|
|
7631
7919
|
...this.theme.border(this.variant() || 'primary'),
|
|
7632
7920
|
...this.theme.boxShadow('dialog'),
|
|
7633
7921
|
padding: 0,
|
|
7634
|
-
transition: `all ${this.
|
|
7922
|
+
transition: `all ${this.motion().duration}ms ${this.motion().easing}`,
|
|
7635
7923
|
transitionBehavior: 'allow-discrete',
|
|
7636
7924
|
opacity: 1,
|
|
7637
|
-
|
|
7638
|
-
|
|
7925
|
+
// `[popover]` arrives centred by `inset: 0; margin: auto`. Undo that,
|
|
7926
|
+
// then rebuild the bottom-centred placement `<dialog>` used to get from
|
|
7927
|
+
// its own UA rules: shrink to the content, pin to the bottom, and let
|
|
7928
|
+
// auto inline margins centre it between the viewport edges.
|
|
7639
7929
|
position: 'fixed',
|
|
7640
|
-
'
|
|
7930
|
+
inset: 'auto',
|
|
7931
|
+
left: 0,
|
|
7932
|
+
right: 0,
|
|
7933
|
+
bottom: this.componentOptions().bottomPosition,
|
|
7934
|
+
width: 'fit-content',
|
|
7935
|
+
maxWidth: '100%',
|
|
7936
|
+
marginInline: 'auto',
|
|
7937
|
+
marginBlock: 0,
|
|
7938
|
+
'&:popover-open': {
|
|
7641
7939
|
'@starting-style': {
|
|
7642
7940
|
bottom: 0,
|
|
7643
7941
|
opacity: 0,
|
|
@@ -7658,7 +7956,9 @@ class UniSnackbarComponent extends BaseComponent {
|
|
|
7658
7956
|
ngAfterViewInit() {
|
|
7659
7957
|
this._snackbar?.addEventListener('animationend', (e) => {
|
|
7660
7958
|
if (e.animationName == this.fadeOut) {
|
|
7661
|
-
|
|
7959
|
+
// Leaves the top layer only once the fade has finished — hiding first
|
|
7960
|
+
// would remove the bar mid-animation.
|
|
7961
|
+
this.hide();
|
|
7662
7962
|
this.showing.emit(false);
|
|
7663
7963
|
}
|
|
7664
7964
|
});
|
|
@@ -7673,7 +7973,12 @@ class UniSnackbarComponent extends BaseComponent {
|
|
|
7673
7973
|
}
|
|
7674
7974
|
open() {
|
|
7675
7975
|
this._snackbar?.removeAttribute('closing');
|
|
7676
|
-
|
|
7976
|
+
try {
|
|
7977
|
+
this._snackbar?.showPopover();
|
|
7978
|
+
}
|
|
7979
|
+
catch {
|
|
7980
|
+
// Already showing — reopening is a no-op, the timer below still restarts.
|
|
7981
|
+
}
|
|
7677
7982
|
this.show.set(true);
|
|
7678
7983
|
this.showing.emit(true);
|
|
7679
7984
|
if (this._timeout)
|
|
@@ -7683,6 +7988,15 @@ class UniSnackbarComponent extends BaseComponent {
|
|
|
7683
7988
|
this._snackbar?.setAttribute('closing', 'true');
|
|
7684
7989
|
this.show.set(false);
|
|
7685
7990
|
}
|
|
7991
|
+
/** Drops out of the top layer. Called once the closing fade has run. */
|
|
7992
|
+
hide() {
|
|
7993
|
+
try {
|
|
7994
|
+
this._snackbar?.hidePopover();
|
|
7995
|
+
}
|
|
7996
|
+
catch {
|
|
7997
|
+
// Already hidden.
|
|
7998
|
+
}
|
|
7999
|
+
}
|
|
7686
8000
|
pauseTimer() {
|
|
7687
8001
|
this.timer.pause();
|
|
7688
8002
|
}
|
|
@@ -7690,7 +8004,7 @@ class UniSnackbarComponent extends BaseComponent {
|
|
|
7690
8004
|
this.timer.resume();
|
|
7691
8005
|
}
|
|
7692
8006
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniSnackbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7693
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniSnackbarComponent, isStandalone: true, selector: "uni-snackbar", inputs: { show: { classPropertyName: "show", publicName: "show", isSignal: true, isRequired: false, transformFunction: null }, iconName: { classPropertyName: "iconName", publicName: "iconName", isSignal: true, isRequired: false, transformFunction: null }, symbolName: { classPropertyName: "symbolName", publicName: "symbolName", isSignal: true, isRequired: false, transformFunction: null }, timeout: { classPropertyName: "timeout", publicName: "timeout", isSignal: true, isRequired: false, transformFunction: null }, actionLabel: { classPropertyName: "actionLabel", publicName: "actionLabel", isSignal: true, isRequired: false, transformFunction: null }, useVariant: { classPropertyName: "useVariant", publicName: "useVariant", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { show: "showChange", action: "action", showing: "showing" }, providers: [{ provide: COMPONENT_NAME, useValue: 'snackbar' }], viewQueries: [{ propertyName: "snackbarRef", first: true, predicate: ["snackbar"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@let icon = iconName();\n@let symbol = symbolName();\n<!-- role=\"status\" announces the message politely without stealing focus
|
|
8007
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniSnackbarComponent, isStandalone: true, selector: "uni-snackbar", inputs: { show: { classPropertyName: "show", publicName: "show", isSignal: true, isRequired: false, transformFunction: null }, iconName: { classPropertyName: "iconName", publicName: "iconName", isSignal: true, isRequired: false, transformFunction: null }, symbolName: { classPropertyName: "symbolName", publicName: "symbolName", isSignal: true, isRequired: false, transformFunction: null }, timeout: { classPropertyName: "timeout", publicName: "timeout", isSignal: true, isRequired: false, transformFunction: null }, actionLabel: { classPropertyName: "actionLabel", publicName: "actionLabel", isSignal: true, isRequired: false, transformFunction: null }, useVariant: { classPropertyName: "useVariant", publicName: "useVariant", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { show: "showChange", action: "action", showing: "showing" }, providers: [{ provide: COMPONENT_NAME, useValue: 'snackbar' }], viewQueries: [{ propertyName: "snackbarRef", first: true, predicate: ["snackbar"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@let icon = iconName();\n@let symbol = symbolName();\n<!-- role=\"status\" announces the message politely without stealing focus.\n popover=\"manual\" puts the bar in the top layer so no stacking context or\n `overflow: hidden` ancestor can cover or clip it; \"manual\" because a\n snackbar is dismissed by its own button or its timer, never by a click\n elsewhere on the page. Not a <dialog>: it is never modal, and dialog's\n `open` attribute would be a second, competing notion of \"shown\". -->\n<div\n #snackbar\n popover=\"manual\"\n [class]=\"snackbarClass()\"\n role=\"status\"\n (mouseenter)=\"pauseTimer()\"\n (mouseleave)=\"resumeTimer()\"\n (focusin)=\"pauseTimer()\"\n (focusout)=\"resumeTimer()\"\n>\n <div row-layout alignItems=\"center\">\n @if (icon || symbol) {\n <div box-layout [height]=\"26\" [width]=\"26\" paddingLeft=\"sm\">\n @if (icon) {\n <uni-icon [name]=\"icon\"></uni-icon>\n } @else if (symbol) {\n <uni-symbol [name]=\"symbol\" [opticalSize]=\"26\"></uni-symbol>\n }\n </div>\n }\n <div box-layout padding=\"sm\">\n <span uni-text>\n <ng-content></ng-content>\n </span>\n </div>\n <div box-layout paddingRight=\"sm\">\n @if (!actionLabel()) {\n <button icon-button (click)=\"close()\" iconName=\"close\" size=\"md\">Close</button>\n } @else {\n <button text-button variant=\"ghost\" (click)=\"this.action.emit(); close()\">\n {{ actionLabel() }}\n </button>\n }\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: UniRowComponent, selector: "[uni-row-layout], [row-layout]", inputs: ["display", "flexDirection", "minWidth"] }, { kind: "component", type: UniBoxComponent, selector: "[uni-box-layout], [box-layout]", inputs: ["color", "backgroundColor", "borderRadius", "borderRadiusLeft", "borderRadiusRight", "borderRadiusTop", "borderRadiusBottom", "padding", "paddingHorizontal", "paddingVertical", "paddingLeft", "paddingRight", "paddingTop", "paddingBottom", "border", "borderTop", "borderBottom", "borderLeft", "borderRight", "dashBorder", "alignSelf", "alignItems", "alignContent", "justifyContent", "grow", "display", "position", "inset", "height", "minHeight", "maxHeight", "width", "minWidth", "maxWidth", "ignoreDir", "gridArea", "gridColumn", "gridRow", "overflow", "elevation", "shadow", "gap", "fullWidth", "fullHeight", "flexDirection", "textAlign", "wrapItems", "zIndex"] }, { kind: "component", type: UniTextComponent, selector: "[uni-text]", inputs: ["uni-text", "typeface", "color", "display", "align", "nowrap", "maxWidth", "ellipsis"] }, { kind: "component", type: UniIconButtonComponent, selector: "button[uni-icon-button], button[icon-button]", inputs: ["ariaLabel", "iconName", "symbolName", "variant", "size", "disable", "loading", "opticalSize"] }, { kind: "component", type: UniSymbolComponent, selector: "uni-symbol", inputs: ["name", "fill", "weight", "grade", "opticalSize"] }, { kind: "component", type: UniIconComponent, selector: "uni-icon", inputs: ["color", "name", "size"] }, { kind: "component", type: UniButtonComponent, selector: "button[uni-text-button], button[text-button]", inputs: ["disable", "loading", "fullWidth", "symbolLeft", "symbolRight"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7694
8008
|
}
|
|
7695
8009
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniSnackbarComponent, decorators: [{
|
|
7696
8010
|
type: Component,
|
|
@@ -7702,7 +8016,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
7702
8016
|
UniSymbolComponent,
|
|
7703
8017
|
UniIconComponent,
|
|
7704
8018
|
UniButtonComponent,
|
|
7705
|
-
], providers: [{ provide: COMPONENT_NAME, useValue: 'snackbar' }], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let icon = iconName();\n@let symbol = symbolName();\n<!-- role=\"status\" announces the message politely without stealing focus
|
|
8019
|
+
], providers: [{ provide: COMPONENT_NAME, useValue: 'snackbar' }], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let icon = iconName();\n@let symbol = symbolName();\n<!-- role=\"status\" announces the message politely without stealing focus.\n popover=\"manual\" puts the bar in the top layer so no stacking context or\n `overflow: hidden` ancestor can cover or clip it; \"manual\" because a\n snackbar is dismissed by its own button or its timer, never by a click\n elsewhere on the page. Not a <dialog>: it is never modal, and dialog's\n `open` attribute would be a second, competing notion of \"shown\". -->\n<div\n #snackbar\n popover=\"manual\"\n [class]=\"snackbarClass()\"\n role=\"status\"\n (mouseenter)=\"pauseTimer()\"\n (mouseleave)=\"resumeTimer()\"\n (focusin)=\"pauseTimer()\"\n (focusout)=\"resumeTimer()\"\n>\n <div row-layout alignItems=\"center\">\n @if (icon || symbol) {\n <div box-layout [height]=\"26\" [width]=\"26\" paddingLeft=\"sm\">\n @if (icon) {\n <uni-icon [name]=\"icon\"></uni-icon>\n } @else if (symbol) {\n <uni-symbol [name]=\"symbol\" [opticalSize]=\"26\"></uni-symbol>\n }\n </div>\n }\n <div box-layout padding=\"sm\">\n <span uni-text>\n <ng-content></ng-content>\n </span>\n </div>\n <div box-layout paddingRight=\"sm\">\n @if (!actionLabel()) {\n <button icon-button (click)=\"close()\" iconName=\"close\" size=\"md\">Close</button>\n } @else {\n <button text-button variant=\"ghost\" (click)=\"this.action.emit(); close()\">\n {{ actionLabel() }}\n </button>\n }\n </div>\n </div>\n</div>\n" }]
|
|
7706
8020
|
}], ctorParameters: () => [], propDecorators: { show: [{ type: i0.Input, args: [{ isSignal: true, alias: "show", required: false }] }, { type: i0.Output, args: ["showChange"] }], iconName: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconName", required: false }] }], symbolName: [{ type: i0.Input, args: [{ isSignal: true, alias: "symbolName", required: false }] }], timeout: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeout", required: false }] }], actionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionLabel", required: false }] }], useVariant: [{ type: i0.Input, args: [{ isSignal: true, alias: "useVariant", required: false }] }], action: [{ type: i0.Output, args: ["action"] }], showing: [{ type: i0.Output, args: ["showing"] }], snackbarRef: [{ type: i0.ViewChild, args: ['snackbar', { isSignal: true }] }] } });
|
|
7707
8021
|
|
|
7708
8022
|
class NotificationsComponent {
|
|
@@ -8080,6 +8394,7 @@ class UniPopoverComponent extends BaseComponent {
|
|
|
8080
8394
|
}, ...(ngDevMode ? [{ debugName: "resolvedMaxWidth" }] : /* istanbul ignore next */ []));
|
|
8081
8395
|
popoverClassName = computed(() => {
|
|
8082
8396
|
const options = this.componentOptions();
|
|
8397
|
+
const motion = this.theme.motion(options.motion);
|
|
8083
8398
|
return css({
|
|
8084
8399
|
...this.theme.colorPair(options.color),
|
|
8085
8400
|
...this.theme.radius(options.borderRadius),
|
|
@@ -8091,7 +8406,7 @@ class UniPopoverComponent extends BaseComponent {
|
|
|
8091
8406
|
maxWidth: this.resolvedMaxWidth(),
|
|
8092
8407
|
overflow: 'visible',
|
|
8093
8408
|
...anchorStyles(this.anchorName, this.placement(), { mainAxis: options.offset }),
|
|
8094
|
-
...discreteOverlayTransition(
|
|
8409
|
+
...discreteOverlayTransition(motion.duration, { opacity: 0 }, { opacity: 1 }, motion.easing),
|
|
8095
8410
|
});
|
|
8096
8411
|
}, ...(ngDevMode ? [{ debugName: "popoverClassName" }] : /* istanbul ignore next */ []));
|
|
8097
8412
|
/** Empty regions collapse, so bare content renders v1's single-region look. */
|
|
@@ -8290,9 +8605,12 @@ class UniRadioComponent extends BaseComponent {
|
|
|
8290
8605
|
// transitions are scoped — never `all` — so the focus ring's outline and
|
|
8291
8606
|
// shadow apply instantly instead of interpolating from a stale outline
|
|
8292
8607
|
// color, which flashed a dark ring before the themed ring color landed.
|
|
8293
|
-
const
|
|
8294
|
-
|
|
8295
|
-
const
|
|
8608
|
+
const options = this.componentOptions();
|
|
8609
|
+
// The deprecated option wins so a theme that set it keeps its timing.
|
|
8610
|
+
const motion = this.theme.motion(options.motion ?? 'control');
|
|
8611
|
+
const speed = options.transitionSpeed ?? motion.duration / 1000;
|
|
8612
|
+
const ringTransition = `border-color ${speed}s ${motion.easing}, background-color ${speed}s ${motion.easing}`;
|
|
8613
|
+
const dotTransition = `transform ${speed}s ${motion.easing}`;
|
|
8296
8614
|
return css({
|
|
8297
8615
|
userSelect: 'none',
|
|
8298
8616
|
cursor: this.disabled() ? 'not-allowed' : 'pointer',
|
|
@@ -8401,6 +8719,15 @@ class UniSearchInputComponent extends BaseComponent {
|
|
|
8401
8719
|
search = output();
|
|
8402
8720
|
suggestionSelected = output();
|
|
8403
8721
|
field = viewChild.required(UniDebounceInputComponent);
|
|
8722
|
+
listRef = viewChild('listbox', ...(ngDevMode ? [{ debugName: "listRef" }] : /* istanbul ignore next */ []));
|
|
8723
|
+
/** Ties the popup to the field so the browser tracks it in the top layer. */
|
|
8724
|
+
anchor = newListboxAnchor();
|
|
8725
|
+
/** `manual` where the top layer is usable, else null — see the popup helper. */
|
|
8726
|
+
popupAttr = listboxPopupAttr();
|
|
8727
|
+
constructor() {
|
|
8728
|
+
super();
|
|
8729
|
+
promoteListboxPopup(this.listRef);
|
|
8730
|
+
}
|
|
8404
8731
|
visibleSuggestions = computed(() => this.suggestions().slice(0, this.componentOptions().maxSuggestions ?? 8), ...(ngDevMode ? [{ debugName: "visibleSuggestions" }] : /* istanbul ignore next */ []));
|
|
8405
8732
|
/** Shared combobox bookkeeping: open state, active option, ARIA ids. */
|
|
8406
8733
|
list = createListboxNavigation({
|
|
@@ -8459,20 +8786,21 @@ class UniSearchInputComponent extends BaseComponent {
|
|
|
8459
8786
|
display: 'block',
|
|
8460
8787
|
position: 'relative',
|
|
8461
8788
|
width: this.width(),
|
|
8789
|
+
...this.anchor.style,
|
|
8462
8790
|
'& .uni-search-lead': {
|
|
8463
8791
|
fontSize: 20,
|
|
8464
8792
|
...this.theme.color('on-background-variant'),
|
|
8465
8793
|
...this.theme.paddingLeft('sm'),
|
|
8466
8794
|
},
|
|
8467
8795
|
}), ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
|
|
8468
|
-
listClass = computed(() => css(listboxPopupStyles(this.theme, this.componentOptions())), ...(ngDevMode ? [{ debugName: "listClass" }] : /* istanbul ignore next */ []));
|
|
8469
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniSearchInputComponent, deps:
|
|
8470
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniSearchInputComponent, isStandalone: true, selector: "uni-search-input", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, debounceTime: { classPropertyName: "debounceTime", publicName: "debounceTime", isSignal: true, isRequired: false, transformFunction: null }, suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { change: "change", search: "search", suggestionSelected: "suggestionSelected" }, host: { properties: { "class": "className()" } }, providers: [{ provide: COMPONENT_NAME, useValue: 'searchInput' }], viewQueries: [{ propertyName: "field", first: true, predicate: UniDebounceInputComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Keydown/focusout ride the bubbling events from the inner input; the\n wrapper itself stays out of the tab order. -->\n<!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n<div (keydown)=\"onKeydown($event)\" (focusout)=\"onFocusOut($event)\">\n <uni-debounce-input\n #searchField\n [label]=\"label()\"\n [placeholder]=\"placeholder() ?? label()\"\n [debounceTime]=\"debounceTime()\"\n role=\"combobox\"\n [ariaExpanded]=\"list.open()\"\n [ariaControls]=\"listboxId\"\n [ariaActivedescendant]=\"list.activeDescendantId() ?? undefined\"\n (change)=\"handleChange($event)\"\n >\n <uni-symbol pre-input class=\"uni-search-lead\" name=\"{{ componentOptions().searchSymbol ?? 'search' }}\" aria-hidden=\"true\" />\n @if (hasQuery()) {\n <button\n post-input\n icon-button\n [iconName]=\"componentOptions().clearSymbol ?? 'close'\"\n variant=\"ghost\"\n size=\"sm\"\n (click)=\"clear()\"\n >\n Clear search\n </button>\n }\n </uni-debounce-input>\n\n @if (list.open()) {\n <ul
|
|
8796
|
+
listClass = computed(() => css(listboxPopupStyles(this.theme, this.componentOptions(), { anchor: this.anchor.name })), ...(ngDevMode ? [{ debugName: "listClass" }] : /* istanbul ignore next */ []));
|
|
8797
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniSearchInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8798
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniSearchInputComponent, isStandalone: true, selector: "uni-search-input", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, debounceTime: { classPropertyName: "debounceTime", publicName: "debounceTime", isSignal: true, isRequired: false, transformFunction: null }, suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { change: "change", search: "search", suggestionSelected: "suggestionSelected" }, host: { properties: { "class": "className()" } }, providers: [{ provide: COMPONENT_NAME, useValue: 'searchInput' }], viewQueries: [{ propertyName: "field", first: true, predicate: UniDebounceInputComponent, descendants: true, isSignal: true }, { propertyName: "listRef", first: true, predicate: ["listbox"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Keydown/focusout ride the bubbling events from the inner input; the\n wrapper itself stays out of the tab order. -->\n<!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n<div (keydown)=\"onKeydown($event)\" (focusout)=\"onFocusOut($event)\">\n <uni-debounce-input\n #searchField\n [label]=\"label()\"\n [placeholder]=\"placeholder() ?? label()\"\n [debounceTime]=\"debounceTime()\"\n role=\"combobox\"\n [ariaExpanded]=\"list.open()\"\n [ariaControls]=\"listboxId\"\n [ariaActivedescendant]=\"list.activeDescendantId() ?? undefined\"\n (change)=\"handleChange($event)\"\n >\n <uni-symbol pre-input class=\"uni-search-lead\" name=\"{{ componentOptions().searchSymbol ?? 'search' }}\" aria-hidden=\"true\" />\n @if (hasQuery()) {\n <button\n post-input\n icon-button\n [iconName]=\"componentOptions().clearSymbol ?? 'close'\"\n variant=\"ghost\"\n size=\"sm\"\n (click)=\"clear()\"\n >\n Clear search\n </button>\n }\n </uni-debounce-input>\n\n @if (list.open()) {\n <ul\n #listbox\n [id]=\"listboxId\"\n role=\"listbox\"\n [attr.popover]=\"popupAttr\"\n [attr.aria-label]=\"label()\"\n [class]=\"listClass()\"\n >\n @for (suggestion of visibleSuggestions(); track suggestion; let i = $index) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <li\n role=\"option\"\n [id]=\"list.optionId(i)\"\n [class.active]=\"i === list.activeIndex()\"\n [attr.aria-selected]=\"i === list.activeIndex()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"select(suggestion)\"\n >\n {{ suggestion }}\n </li>\n }\n </ul>\n }\n</div>\n", dependencies: [{ kind: "component", type: UniDebounceInputComponent, selector: "uni-debounce-input", inputs: ["inputName", "inputId", "debounceTime", "label", "placeholder", "disabled", "role", "ariaExpanded", "ariaControls", "ariaActivedescendant"], outputs: ["change"] }, { kind: "component", type: UniIconButtonComponent, selector: "button[uni-icon-button], button[icon-button]", inputs: ["ariaLabel", "iconName", "symbolName", "variant", "size", "disable", "loading", "opticalSize"] }, { kind: "component", type: UniSymbolComponent, selector: "uni-symbol", inputs: ["name", "fill", "weight", "grade", "opticalSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
8471
8799
|
}
|
|
8472
8800
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniSearchInputComponent, decorators: [{
|
|
8473
8801
|
type: Component,
|
|
8474
|
-
args: [{ selector: 'uni-search-input', imports: [UniDebounceInputComponent, UniIconButtonComponent, UniSymbolComponent], providers: [{ provide: COMPONENT_NAME, useValue: 'searchInput' }], host: { '[class]': 'className()' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Keydown/focusout ride the bubbling events from the inner input; the\n wrapper itself stays out of the tab order. -->\n<!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n<div (keydown)=\"onKeydown($event)\" (focusout)=\"onFocusOut($event)\">\n <uni-debounce-input\n #searchField\n [label]=\"label()\"\n [placeholder]=\"placeholder() ?? label()\"\n [debounceTime]=\"debounceTime()\"\n role=\"combobox\"\n [ariaExpanded]=\"list.open()\"\n [ariaControls]=\"listboxId\"\n [ariaActivedescendant]=\"list.activeDescendantId() ?? undefined\"\n (change)=\"handleChange($event)\"\n >\n <uni-symbol pre-input class=\"uni-search-lead\" name=\"{{ componentOptions().searchSymbol ?? 'search' }}\" aria-hidden=\"true\" />\n @if (hasQuery()) {\n <button\n post-input\n icon-button\n [iconName]=\"componentOptions().clearSymbol ?? 'close'\"\n variant=\"ghost\"\n size=\"sm\"\n (click)=\"clear()\"\n >\n Clear search\n </button>\n }\n </uni-debounce-input>\n\n @if (list.open()) {\n <ul
|
|
8475
|
-
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], debounceTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "debounceTime", required: false }] }], suggestions: [{ type: i0.Input, args: [{ isSignal: true, alias: "suggestions", required: false }] }], change: [{ type: i0.Output, args: ["change"] }], search: [{ type: i0.Output, args: ["search"] }], suggestionSelected: [{ type: i0.Output, args: ["suggestionSelected"] }], field: [{ type: i0.ViewChild, args: [i0.forwardRef(() => UniDebounceInputComponent), { isSignal: true }] }] } });
|
|
8802
|
+
args: [{ selector: 'uni-search-input', imports: [UniDebounceInputComponent, UniIconButtonComponent, UniSymbolComponent], providers: [{ provide: COMPONENT_NAME, useValue: 'searchInput' }], host: { '[class]': 'className()' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Keydown/focusout ride the bubbling events from the inner input; the\n wrapper itself stays out of the tab order. -->\n<!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n<div (keydown)=\"onKeydown($event)\" (focusout)=\"onFocusOut($event)\">\n <uni-debounce-input\n #searchField\n [label]=\"label()\"\n [placeholder]=\"placeholder() ?? label()\"\n [debounceTime]=\"debounceTime()\"\n role=\"combobox\"\n [ariaExpanded]=\"list.open()\"\n [ariaControls]=\"listboxId\"\n [ariaActivedescendant]=\"list.activeDescendantId() ?? undefined\"\n (change)=\"handleChange($event)\"\n >\n <uni-symbol pre-input class=\"uni-search-lead\" name=\"{{ componentOptions().searchSymbol ?? 'search' }}\" aria-hidden=\"true\" />\n @if (hasQuery()) {\n <button\n post-input\n icon-button\n [iconName]=\"componentOptions().clearSymbol ?? 'close'\"\n variant=\"ghost\"\n size=\"sm\"\n (click)=\"clear()\"\n >\n Clear search\n </button>\n }\n </uni-debounce-input>\n\n @if (list.open()) {\n <ul\n #listbox\n [id]=\"listboxId\"\n role=\"listbox\"\n [attr.popover]=\"popupAttr\"\n [attr.aria-label]=\"label()\"\n [class]=\"listClass()\"\n >\n @for (suggestion of visibleSuggestions(); track suggestion; let i = $index) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <li\n role=\"option\"\n [id]=\"list.optionId(i)\"\n [class.active]=\"i === list.activeIndex()\"\n [attr.aria-selected]=\"i === list.activeIndex()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"select(suggestion)\"\n >\n {{ suggestion }}\n </li>\n }\n </ul>\n }\n</div>\n" }]
|
|
8803
|
+
}], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], debounceTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "debounceTime", required: false }] }], suggestions: [{ type: i0.Input, args: [{ isSignal: true, alias: "suggestions", required: false }] }], change: [{ type: i0.Output, args: ["change"] }], search: [{ type: i0.Output, args: ["search"] }], suggestionSelected: [{ type: i0.Output, args: ["suggestionSelected"] }], field: [{ type: i0.ViewChild, args: [i0.forwardRef(() => UniDebounceInputComponent), { isSignal: true }] }], listRef: [{ type: i0.ViewChild, args: ['listbox', { isSignal: true }] }] } });
|
|
8476
8804
|
|
|
8477
8805
|
/**
|
|
8478
8806
|
* UniSearchInputComponent Barrel File
|
|
@@ -8549,11 +8877,11 @@ class UniSelectComponent {
|
|
|
8549
8877
|
pointerEvents: 'none' /* Crucial for clicking through */,
|
|
8550
8878
|
});
|
|
8551
8879
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8552
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniSelectComponent, isStandalone: true, selector: "uni-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, ngImport: i0, template: "<uni-input-box [error]=\"showError()\" [class]=\"selectClass\">\n <select\n [disabled]=\"disabled()\"\n [value]=\"currentSelectedIndex()\"\n (change)=\"handleSelectChange($event)\"\n (blur)=\"touched.set(true)\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n [attr.aria-describedby]=\"ariaDescribedBy() || null\"\n >\n @if (placeholder()) {\n <option [value]=\"UNSELECTED\" disabled selected>\n {{ placeholder() }}\n </option>\n }\n\n @for (opt of options(); track opt.label; let i = $index) {\n <!-- [selected] evaluates during the option's own render, so a selection\n pointing at an option added in the same change-detection pass still\n applies (the select-level [value] write lands before new options\n exist and is ignored by the browser). -->\n <option
|
|
8880
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniSelectComponent, isStandalone: true, selector: "uni-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, ngImport: i0, template: "<uni-input-box [error]=\"showError()\" [class]=\"selectClass\">\n <select\n [disabled]=\"disabled()\"\n [value]=\"currentSelectedIndex()\"\n (change)=\"handleSelectChange($event)\"\n (blur)=\"touched.set(true)\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n [attr.aria-describedby]=\"ariaDescribedBy() || null\"\n >\n @if (placeholder()) {\n <option [value]=\"UNSELECTED\" disabled selected>\n {{ placeholder() }}\n </option>\n }\n\n @for (opt of options(); track opt.label; let i = $index) {\n <!-- [selected] evaluates during the option's own render, so a selection\n pointing at an option added in the same change-detection pass still\n applies (the select-level [value] write lands before new options\n exist and is ignored by the browser). -->\n <option\n [value]=\"i\"\n [selected]=\"currentSelectedIndex() === i.toString()\"\n [disabled]=\"opt.disabled ?? false\"\n >\n {{ opt.label }}\n </option>\n }\n </select>\n <uni-symbol name=\"keyboard_arrow_down\" [class]=\"arrowClass\" />\n</uni-input-box>\n", dependencies: [{ kind: "component", type: UniInputBoxComponent, selector: "uni-input-box", inputs: ["disabled", "error", "minWidth", "height"] }, { kind: "component", type: UniSymbolComponent, selector: "uni-symbol", inputs: ["name", "fill", "weight", "grade", "opticalSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
8553
8881
|
}
|
|
8554
8882
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniSelectComponent, decorators: [{
|
|
8555
8883
|
type: Component,
|
|
8556
|
-
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'uni-select', imports: [UniInputBoxComponent, UniSymbolComponent], template: "<uni-input-box [error]=\"showError()\" [class]=\"selectClass\">\n <select\n [disabled]=\"disabled()\"\n [value]=\"currentSelectedIndex()\"\n (change)=\"handleSelectChange($event)\"\n (blur)=\"touched.set(true)\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n [attr.aria-describedby]=\"ariaDescribedBy() || null\"\n >\n @if (placeholder()) {\n <option [value]=\"UNSELECTED\" disabled selected>\n {{ placeholder() }}\n </option>\n }\n\n @for (opt of options(); track opt.label; let i = $index) {\n <!-- [selected] evaluates during the option's own render, so a selection\n pointing at an option added in the same change-detection pass still\n applies (the select-level [value] write lands before new options\n exist and is ignored by the browser). -->\n <option
|
|
8884
|
+
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'uni-select', imports: [UniInputBoxComponent, UniSymbolComponent], template: "<uni-input-box [error]=\"showError()\" [class]=\"selectClass\">\n <select\n [disabled]=\"disabled()\"\n [value]=\"currentSelectedIndex()\"\n (change)=\"handleSelectChange($event)\"\n (blur)=\"touched.set(true)\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n [attr.aria-describedby]=\"ariaDescribedBy() || null\"\n >\n @if (placeholder()) {\n <option [value]=\"UNSELECTED\" disabled selected>\n {{ placeholder() }}\n </option>\n }\n\n @for (opt of options(); track opt.label; let i = $index) {\n <!-- [selected] evaluates during the option's own render, so a selection\n pointing at an option added in the same change-detection pass still\n applies (the select-level [value] write lands before new options\n exist and is ignored by the browser). -->\n <option\n [value]=\"i\"\n [selected]=\"currentSelectedIndex() === i.toString()\"\n [disabled]=\"opt.disabled ?? false\"\n >\n {{ opt.label }}\n </option>\n }\n </select>\n <uni-symbol name=\"keyboard_arrow_down\" [class]=\"arrowClass\" />\n</uni-input-box>\n" }]
|
|
8557
8885
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
|
|
8558
8886
|
|
|
8559
8887
|
/**
|
|
@@ -8561,6 +8889,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
8561
8889
|
* lines (the last line shortened, as real text would be), `rect` and `circle`
|
|
8562
8890
|
* render fixed shapes. The shimmer only animates when the user allows motion;
|
|
8563
8891
|
* it degrades to static blocks under `prefers-reduced-motion`.
|
|
8892
|
+
*
|
|
8893
|
+
* Color and radius are theme options with per-instance overrides, because one
|
|
8894
|
+
* app routinely needs several: skeletons on a card and on the page background
|
|
8895
|
+
* want different tints, and a pill placeholder wants a different corner than
|
|
8896
|
+
* the text bars beside it.
|
|
8564
8897
|
*/
|
|
8565
8898
|
class UniSkeletonComponent extends BaseComponent {
|
|
8566
8899
|
shape = input('text', ...(ngDevMode ? [{ debugName: "shape" }] : /* istanbul ignore next */ []));
|
|
@@ -8570,6 +8903,19 @@ class UniSkeletonComponent extends BaseComponent {
|
|
|
8570
8903
|
height = input(undefined, ...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
|
|
8571
8904
|
/** Number of text lines (text shape only). */
|
|
8572
8905
|
lines = input(1, ...(ngDevMode ? [{ debugName: "lines" }] : /* istanbul ignore next */ []));
|
|
8906
|
+
/** Base color token; overrides the theme option for this skeleton. */
|
|
8907
|
+
color = input(undefined, ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
|
|
8908
|
+
/** Shimmer highlight token; overrides the theme option for this skeleton. */
|
|
8909
|
+
highlightColor = input(undefined, ...(ngDevMode ? [{ debugName: "highlightColor" }] : /* istanbul ignore next */ []));
|
|
8910
|
+
/** Radius token; overrides the theme option. Circles are always round. */
|
|
8911
|
+
borderRadius = input(undefined, ...(ngDevMode ? [{ debugName: "borderRadius" }] : /* istanbul ignore next */ []));
|
|
8912
|
+
/**
|
|
8913
|
+
* Announces the skeleton to assistive tech as a polite status. Leave unset
|
|
8914
|
+
* when a container already carries `aria-busy` — the skeleton then stays
|
|
8915
|
+
* `aria-hidden`, as a decorative placeholder should.
|
|
8916
|
+
*/
|
|
8917
|
+
label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
8918
|
+
srOnly = css(visuallyHidden);
|
|
8573
8919
|
cssSize = (value) => typeof value === 'number' ? `${value}px` : value;
|
|
8574
8920
|
resolvedHeight = computed(() => {
|
|
8575
8921
|
const height = this.height();
|
|
@@ -8587,36 +8933,61 @@ class UniSkeletonComponent extends BaseComponent {
|
|
|
8587
8933
|
// Multi-line text blocks end on a short line, like real paragraphs do.
|
|
8588
8934
|
return Array.from({ length: lines }, (_, i) => lines > 1 && i === lines - 1 ? (width ?? '60%') : (width ?? '100%'));
|
|
8589
8935
|
}, ...(ngDevMode ? [{ debugName: "lineWidths" }] : /* istanbul ignore next */ []));
|
|
8590
|
-
|
|
8591
|
-
|
|
8592
|
-
|
|
8593
|
-
|
|
8936
|
+
/**
|
|
8937
|
+
* The band is `bandWidth`% of the block, so it clears the block after
|
|
8938
|
+
* travelling `100 / bandWidth` of its own width — the offsets below are
|
|
8939
|
+
* percentages of the band, not of the block.
|
|
8940
|
+
*/
|
|
8941
|
+
sweep = (bandWidth, direction) => {
|
|
8942
|
+
const travel = `${Number(((100 / bandWidth) * 100).toFixed(2))}%`;
|
|
8943
|
+
const [from, to] = direction === 'rtl' ? [travel, '-100%'] : ['-100%', travel];
|
|
8944
|
+
return keyframes({
|
|
8945
|
+
from: { transform: `translateX(${from})` },
|
|
8946
|
+
to: { transform: `translateX(${to})` },
|
|
8947
|
+
});
|
|
8948
|
+
};
|
|
8594
8949
|
className = computed(() => {
|
|
8595
8950
|
const options = this.componentOptions();
|
|
8596
|
-
const base = this.theme.colors()[options.color ?? 'surface-variant'];
|
|
8597
|
-
const highlight = this.theme.colors()[options.highlightColor ?? 'surface'];
|
|
8951
|
+
const base = this.theme.colors()[this.color() ?? options.color ?? 'surface-variant'];
|
|
8952
|
+
const highlight = this.theme.colors()[this.highlightColor() ?? options.highlightColor ?? 'surface'];
|
|
8598
8953
|
const animated = (options.animation ?? 'shimmer') === 'shimmer';
|
|
8954
|
+
const bandWidth = Math.max(1, options.highlightWidth ?? 40);
|
|
8599
8955
|
return css({
|
|
8600
8956
|
display: 'flex',
|
|
8601
8957
|
flexDirection: 'column',
|
|
8602
8958
|
...this.theme.gap(options.gap),
|
|
8603
8959
|
'& .uni-skeleton-block': {
|
|
8960
|
+
position: 'relative',
|
|
8961
|
+
overflow: 'hidden',
|
|
8604
8962
|
height: this.resolvedHeight(),
|
|
8605
8963
|
backgroundColor: base,
|
|
8606
8964
|
...(this.shape() === 'circle'
|
|
8607
8965
|
? { borderRadius: '50%', flex: 'none' }
|
|
8608
|
-
: this.theme.radius(options.borderRadius)),
|
|
8966
|
+
: this.theme.radius(this.borderRadius() ?? options.borderRadius)),
|
|
8609
8967
|
...(animated &&
|
|
8610
8968
|
motionSafe({
|
|
8611
|
-
|
|
8612
|
-
|
|
8613
|
-
|
|
8969
|
+
// A translated band composites; animating background-position
|
|
8970
|
+
// repaints the block every frame. Both gradient ends are the base
|
|
8971
|
+
// color, so the band dissolves into the block with no alpha and
|
|
8972
|
+
// no fringing where it meets the edges.
|
|
8973
|
+
'&::after': {
|
|
8974
|
+
content: '""',
|
|
8975
|
+
position: 'absolute',
|
|
8976
|
+
insetBlock: 0,
|
|
8977
|
+
left: 0,
|
|
8978
|
+
width: `${bandWidth}%`,
|
|
8979
|
+
backgroundImage: `linear-gradient(90deg, ${base} 0%, ${highlight} 50%, ${base} 100%)`,
|
|
8980
|
+
animation: `${this.sweep(bandWidth, options.direction ?? 'ltr')} ${options.duration ?? 1.4}s ease-in-out infinite`,
|
|
8981
|
+
},
|
|
8614
8982
|
})),
|
|
8615
8983
|
},
|
|
8616
8984
|
});
|
|
8617
8985
|
}, ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
|
|
8618
8986
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniSkeletonComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
8619
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniSkeletonComponent, isStandalone: true, selector: "uni-skeleton", inputs: { shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, lines: { classPropertyName: "lines", publicName: "lines", isSignal: true, isRequired: false, transformFunction: null } },
|
|
8987
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniSkeletonComponent, isStandalone: true, selector: "uni-skeleton", inputs: { shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, lines: { classPropertyName: "lines", publicName: "lines", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, highlightColor: { classPropertyName: "highlightColor", publicName: "highlightColor", isSignal: true, isRequired: false, transformFunction: null }, borderRadius: { classPropertyName: "borderRadius", publicName: "borderRadius", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "className()", "attr.aria-hidden": "label() ? null : true", "attr.role": "label() ? 'status' : null" } }, providers: [{ provide: COMPONENT_NAME, useValue: 'skeleton' }], usesInheritance: true, ngImport: i0, template: `
|
|
8988
|
+
@if (label(); as text) {
|
|
8989
|
+
<span [class]="srOnly">{{ text }}</span>
|
|
8990
|
+
}
|
|
8620
8991
|
@for (line of lineWidths(); track $index) {
|
|
8621
8992
|
<div class="uni-skeleton-block" [style.width]="line"></div>
|
|
8622
8993
|
}
|
|
@@ -8628,14 +8999,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
8628
8999
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
8629
9000
|
selector: 'uni-skeleton',
|
|
8630
9001
|
providers: [{ provide: COMPONENT_NAME, useValue: 'skeleton' }],
|
|
8631
|
-
host: {
|
|
9002
|
+
host: {
|
|
9003
|
+
'[class]': 'className()',
|
|
9004
|
+
'[attr.aria-hidden]': 'label() ? null : true',
|
|
9005
|
+
'[attr.role]': "label() ? 'status' : null",
|
|
9006
|
+
},
|
|
8632
9007
|
template: `
|
|
9008
|
+
@if (label(); as text) {
|
|
9009
|
+
<span [class]="srOnly">{{ text }}</span>
|
|
9010
|
+
}
|
|
8633
9011
|
@for (line of lineWidths(); track $index) {
|
|
8634
9012
|
<div class="uni-skeleton-block" [style.width]="line"></div>
|
|
8635
9013
|
}
|
|
8636
9014
|
`,
|
|
8637
9015
|
}]
|
|
8638
|
-
}], propDecorators: { shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], lines: [{ type: i0.Input, args: [{ isSignal: true, alias: "lines", required: false }] }] } });
|
|
9016
|
+
}], propDecorators: { shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], lines: [{ type: i0.Input, args: [{ isSignal: true, alias: "lines", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], highlightColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightColor", required: false }] }], borderRadius: [{ type: i0.Input, args: [{ isSignal: true, alias: "borderRadius", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
|
|
8639
9017
|
|
|
8640
9018
|
/**
|
|
8641
9019
|
* Range slider on a native `<input type="range">` — keyboard interaction and
|
|
@@ -9438,12 +9816,21 @@ class UniTagInputComponent extends BaseComponent {
|
|
|
9438
9816
|
rejected = output();
|
|
9439
9817
|
inputRef = viewChild.required('field');
|
|
9440
9818
|
chipRefs = viewChildren('chip', ...(ngDevMode ? [{ debugName: "chipRefs" }] : /* istanbul ignore next */ []));
|
|
9819
|
+
listRef = viewChild('listbox', ...(ngDevMode ? [{ debugName: "listRef" }] : /* istanbul ignore next */ []));
|
|
9820
|
+
/** Ties the popup to the field so the browser tracks it in the top layer. */
|
|
9821
|
+
anchor = newListboxAnchor();
|
|
9822
|
+
/** `manual` where the top layer is usable, else null — see the popup helper. */
|
|
9823
|
+
popupAttr = listboxPopupAttr();
|
|
9824
|
+
constructor() {
|
|
9825
|
+
super();
|
|
9826
|
+
promoteListboxPopup(this.listRef);
|
|
9827
|
+
}
|
|
9441
9828
|
/** Uncommitted text in the field. */
|
|
9442
9829
|
draft = signal('', ...(ngDevMode ? [{ debugName: "draft" }] : /* istanbul ignore next */ []));
|
|
9443
9830
|
/** Index of the focused chip, or -1 when focus is in the text input. */
|
|
9444
9831
|
focusedChip = signal(-1, ...(ngDevMode ? [{ debugName: "focusedChip" }] : /* istanbul ignore next */ []));
|
|
9445
|
-
/**
|
|
9446
|
-
|
|
9832
|
+
/** Adds, removes and refusals are otherwise silent to a screen reader. */
|
|
9833
|
+
announcer = createAnnouncer();
|
|
9447
9834
|
hintId = uniqueId('uni-tag-input-hint');
|
|
9448
9835
|
srOnly = css(visuallyHidden);
|
|
9449
9836
|
queryTimer;
|
|
@@ -9509,13 +9896,13 @@ class UniTagInputComponent extends BaseComponent {
|
|
|
9509
9896
|
};
|
|
9510
9897
|
this.value.update((items) => [...items, item]);
|
|
9511
9898
|
this.added.emit(item);
|
|
9512
|
-
this.announce(`${this.labelOf(item)} added. ${this.value().length} ${this.countNoun()}.`);
|
|
9899
|
+
this.announcer.announce(`${this.labelOf(item)} added. ${this.value().length} ${this.countNoun()}.`);
|
|
9513
9900
|
return true;
|
|
9514
9901
|
}
|
|
9515
9902
|
reject(raw, reason) {
|
|
9516
9903
|
this.rejected.emit({ raw, reason });
|
|
9517
9904
|
// The visual cue is a brief pulse a screen reader cannot see.
|
|
9518
|
-
this.announce(reason === 'duplicate' ? `${raw} is already added.` : `${raw} was not added: limit reached.`);
|
|
9905
|
+
this.announcer.announce(reason === 'duplicate' ? `${raw} is already added.` : `${raw} was not added: limit reached.`);
|
|
9519
9906
|
}
|
|
9520
9907
|
removeAt(index, focus = 'input') {
|
|
9521
9908
|
const item = this.value()[index];
|
|
@@ -9523,7 +9910,7 @@ class UniTagInputComponent extends BaseComponent {
|
|
|
9523
9910
|
return;
|
|
9524
9911
|
this.value.update((items) => items.filter((_, i) => i !== index));
|
|
9525
9912
|
this.removed.emit(item);
|
|
9526
|
-
this.announce(`${this.labelOf(item)} removed. ${this.value().length} ${this.countNoun()}.`);
|
|
9913
|
+
this.announcer.announce(`${this.labelOf(item)} removed. ${this.value().length} ${this.countNoun()}.`);
|
|
9527
9914
|
const remaining = this.value().length;
|
|
9528
9915
|
if (focus === 'left' && index > 0)
|
|
9529
9916
|
this.focusChip(index - 1);
|
|
@@ -9535,10 +9922,6 @@ class UniTagInputComponent extends BaseComponent {
|
|
|
9535
9922
|
countNoun() {
|
|
9536
9923
|
return this.value().length === 1 ? 'item' : 'items';
|
|
9537
9924
|
}
|
|
9538
|
-
announce(message) {
|
|
9539
|
-
// Re-announce identical text by breaking the string equality.
|
|
9540
|
-
this.announcement.set(this.announcement() === message ? `${message} ` : message);
|
|
9541
|
-
}
|
|
9542
9925
|
// --- Focus ---------------------------------------------------------------
|
|
9543
9926
|
focusInput() {
|
|
9544
9927
|
this.focusedChip.set(-1);
|
|
@@ -9711,7 +10094,11 @@ class UniTagInputComponent extends BaseComponent {
|
|
|
9711
10094
|
input.value = text;
|
|
9712
10095
|
}
|
|
9713
10096
|
// --- Styling -------------------------------------------------------------
|
|
9714
|
-
|
|
10097
|
+
/** The host is the popup's anchor — the box the list mirrors the width of,
|
|
10098
|
+
and the one its entry animation is measured against. The wrapper below
|
|
10099
|
+
has the same geometry but is only the fallback's positioning context. */
|
|
10100
|
+
className = computed(() => css({ display: 'block', ...this.anchor.style }), ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
|
|
10101
|
+
wrapperClass = computed(() => css({ position: 'relative' }), ...(ngDevMode ? [{ debugName: "wrapperClass" }] : /* istanbul ignore next */ []));
|
|
9715
10102
|
fieldClass = computed(() => {
|
|
9716
10103
|
const options = this.componentOptions();
|
|
9717
10104
|
return css({
|
|
@@ -9735,14 +10122,14 @@ class UniTagInputComponent extends BaseComponent {
|
|
|
9735
10122
|
font: 'inherit',
|
|
9736
10123
|
padding: 0,
|
|
9737
10124
|
}), ...(ngDevMode ? [{ debugName: "inputClass" }] : /* istanbul ignore next */ []));
|
|
9738
|
-
listClass = computed(() => css(listboxPopupStyles(this.theme, this.componentOptions())), ...(ngDevMode ? [{ debugName: "listClass" }] : /* istanbul ignore next */ []));
|
|
9739
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniTagInputComponent, deps:
|
|
9740
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniTagInputComponent, isStandalone: true, selector: "uni-tag-input", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, preset: { classPropertyName: "preset", publicName: "preset", isSignal: true, isRequired: false, transformFunction: null }, separators: { classPropertyName: "separators", publicName: "separators", isSignal: true, isRequired: false, transformFunction: null }, commitOnBlur: { classPropertyName: "commitOnBlur", publicName: "commitOnBlur", isSignal: true, isRequired: false, transformFunction: null }, allowDuplicates: { classPropertyName: "allowDuplicates", publicName: "allowDuplicates", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, validate: { classPropertyName: "validate", publicName: "validate", isSignal: true, isRequired: false, transformFunction: null }, parse: { classPropertyName: "parse", publicName: "parse", isSignal: true, isRequired: false, transformFunction: null }, tagVariant: { classPropertyName: "tagVariant", publicName: "tagVariant", isSignal: true, isRequired: false, transformFunction: null }, tagTone: { classPropertyName: "tagTone", publicName: "tagTone", isSignal: true, isRequired: false, transformFunction: null }, tagSize: { classPropertyName: "tagSize", publicName: "tagSize", isSignal: true, isRequired: false, transformFunction: null }, suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null }, debounceTime: { classPropertyName: "debounceTime", publicName: "debounceTime", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange", query: "query", added: "added", removed: "removed", rejected: "rejected" }, host: { properties: { "class": "className()" } }, providers: [{ provide: COMPONENT_NAME, useValue: 'tagInput' }], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "chipRefs", predicate: ["chip"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Focusout rides the bubbling event so the list closes only when focus\n leaves the whole field, not while moving between chips and the input. -->\n<div
|
|
10125
|
+
listClass = computed(() => css(listboxPopupStyles(this.theme, this.componentOptions(), { anchor: this.anchor.name })), ...(ngDevMode ? [{ debugName: "listClass" }] : /* istanbul ignore next */ []));
|
|
10126
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniTagInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10127
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniTagInputComponent, isStandalone: true, selector: "uni-tag-input", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, preset: { classPropertyName: "preset", publicName: "preset", isSignal: true, isRequired: false, transformFunction: null }, separators: { classPropertyName: "separators", publicName: "separators", isSignal: true, isRequired: false, transformFunction: null }, commitOnBlur: { classPropertyName: "commitOnBlur", publicName: "commitOnBlur", isSignal: true, isRequired: false, transformFunction: null }, allowDuplicates: { classPropertyName: "allowDuplicates", publicName: "allowDuplicates", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, validate: { classPropertyName: "validate", publicName: "validate", isSignal: true, isRequired: false, transformFunction: null }, parse: { classPropertyName: "parse", publicName: "parse", isSignal: true, isRequired: false, transformFunction: null }, tagVariant: { classPropertyName: "tagVariant", publicName: "tagVariant", isSignal: true, isRequired: false, transformFunction: null }, tagTone: { classPropertyName: "tagTone", publicName: "tagTone", isSignal: true, isRequired: false, transformFunction: null }, tagSize: { classPropertyName: "tagSize", publicName: "tagSize", isSignal: true, isRequired: false, transformFunction: null }, suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null }, debounceTime: { classPropertyName: "debounceTime", publicName: "debounceTime", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange", query: "query", added: "added", removed: "removed", rejected: "rejected" }, host: { properties: { "class": "className()" } }, providers: [{ provide: COMPONENT_NAME, useValue: 'tagInput' }], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "chipRefs", predicate: ["chip"], descendants: true, isSignal: true }, { propertyName: "listRef", first: true, predicate: ["listbox"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Focusout rides the bubbling event so the list closes only when focus\n leaves the whole field, not while moving between chips and the input. -->\n<div [class]=\"wrapperClass()\" (focusout)=\"onFocusOut($event)\">\n <uni-input-box [error]=\"showError()\" height=\"auto\">\n <ul [class]=\"fieldClass()\">\n @for (item of value(); track item.value; let i = $index) {\n <!-- The focusable element is the chip's own button; this <li> only\n receives keys bubbling up from it, so it must stay out of the tab\n order (same delegation the menu uses for its roving focus). -->\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n <li #chip (keydown)=\"onChipKeydown($event, i)\" (dblclick)=\"editChip(i)\">\n <uni-tag\n [label]=\"labelOf(item)\"\n [value]=\"item.value\"\n [avatarSrc]=\"item.avatarSrc\"\n [variant]=\"item.invalid ? 'warn' : tagVariant()\"\n [tone]=\"tagTone()\"\n [size]=\"tagSize() ?? componentOptions().chipSize ?? 'md'\"\n [invalid]=\"!!item.invalid\"\n [disabled]=\"!!item.disabled || disabled()\"\n [interactive]=\"true\"\n [removable]=\"!item.disabled && !disabled()\"\n [controlTabIndex]=\"-1\"\n (removed)=\"removeAt(i)\"\n />\n </li>\n }\n\n <li [class]=\"inputClass()\">\n <!-- The field is one tab stop: chips carry tabindex=\"-1\" and are\n entered with Backspace/ArrowLeft, so Tab never walks through\n eight recipients to reach the next control. -->\n <input\n #field\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n [class]=\"inputClass()\"\n [disabled]=\"disabled()\"\n [placeholder]=\"placeholder() ?? ''\"\n [attr.aria-label]=\"label()\"\n [attr.aria-expanded]=\"list.open()\"\n [attr.aria-controls]=\"list.listboxId\"\n [attr.aria-activedescendant]=\"list.activeDescendantId()\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onInputKeydown($event)\"\n (input)=\"onInput($any($event.target).value)\"\n (paste)=\"onPaste($event)\"\n (blur)=\"onBlur()\"\n />\n </li>\n </ul>\n </uni-input-box>\n\n @if (list.open()) {\n <ul\n #listbox\n [id]=\"list.listboxId\"\n role=\"listbox\"\n [attr.popover]=\"popupAttr\"\n [attr.aria-label]=\"label()\"\n [class]=\"listClass()\"\n >\n @for (suggestion of visibleSuggestions(); track suggestion.value; let i = $index) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <li\n role=\"option\"\n [id]=\"list.optionId(i)\"\n [class.active]=\"i === list.activeIndex()\"\n [attr.aria-selected]=\"i === list.activeIndex()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"selectSuggestion(suggestion)\"\n >\n {{ labelOf(suggestion) }}\n @if (suggestion.description) {\n <span [class]=\"srOnly\">{{ suggestion.description }}</span>\n }\n </li>\n }\n </ul>\n }\n\n <!-- Said once for the whole field, rather than every chip advertising it. -->\n <span [id]=\"hintId\" [class]=\"srOnly\">\n Press Backspace to reach the last entry, then Backspace again to remove it.\n </span>\n\n <!-- Adds and removes are otherwise silent for a screen reader. -->\n <span role=\"status\" aria-live=\"polite\" [class]=\"srOnly\">{{ announcer.message() }}</span>\n</div>\n", dependencies: [{ kind: "component", type: UniInputBoxComponent, selector: "uni-input-box", inputs: ["disabled", "error", "minWidth", "height"] }, { kind: "component", type: UniTagComponent, selector: "uni-tag", inputs: ["size", "tone", "label", "value", "maxWidth", "avatarSrc", "avatarName", "iconName", "symbolName", "dot", "removable", "interactive", "selected", "invalid", "disabled", "removeLabel", "controlTabIndex"], outputs: ["removed", "activated"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9741
10128
|
}
|
|
9742
10129
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniTagInputComponent, decorators: [{
|
|
9743
10130
|
type: Component,
|
|
9744
|
-
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'uni-tag-input', imports: [UniInputBoxComponent, UniTagComponent], providers: [{ provide: COMPONENT_NAME, useValue: 'tagInput' }], host: { '[class]': 'className()' }, template: "<!-- Focusout rides the bubbling event so the list closes only when focus\n leaves the whole field, not while moving between chips and the input. -->\n<div
|
|
9745
|
-
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], preset: [{ type: i0.Input, args: [{ isSignal: true, alias: "preset", required: false }] }], separators: [{ type: i0.Input, args: [{ isSignal: true, alias: "separators", required: false }] }], commitOnBlur: [{ type: i0.Input, args: [{ isSignal: true, alias: "commitOnBlur", required: false }] }], allowDuplicates: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowDuplicates", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], validate: [{ type: i0.Input, args: [{ isSignal: true, alias: "validate", required: false }] }], parse: [{ type: i0.Input, args: [{ isSignal: true, alias: "parse", required: false }] }], tagVariant: [{ type: i0.Input, args: [{ isSignal: true, alias: "tagVariant", required: false }] }], tagTone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tagTone", required: false }] }], tagSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "tagSize", required: false }] }], suggestions: [{ type: i0.Input, args: [{ isSignal: true, alias: "suggestions", required: false }] }], query: [{ type: i0.Output, args: ["query"] }], debounceTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "debounceTime", required: false }] }], added: [{ type: i0.Output, args: ["added"] }], removed: [{ type: i0.Output, args: ["removed"] }], rejected: [{ type: i0.Output, args: ["rejected"] }], inputRef: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], chipRefs: [{ type: i0.ViewChildren, args: ['chip', { isSignal: true }] }] } });
|
|
10131
|
+
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'uni-tag-input', imports: [UniInputBoxComponent, UniTagComponent], providers: [{ provide: COMPONENT_NAME, useValue: 'tagInput' }], host: { '[class]': 'className()' }, template: "<!-- Focusout rides the bubbling event so the list closes only when focus\n leaves the whole field, not while moving between chips and the input. -->\n<div [class]=\"wrapperClass()\" (focusout)=\"onFocusOut($event)\">\n <uni-input-box [error]=\"showError()\" height=\"auto\">\n <ul [class]=\"fieldClass()\">\n @for (item of value(); track item.value; let i = $index) {\n <!-- The focusable element is the chip's own button; this <li> only\n receives keys bubbling up from it, so it must stay out of the tab\n order (same delegation the menu uses for its roving focus). -->\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\n <li #chip (keydown)=\"onChipKeydown($event, i)\" (dblclick)=\"editChip(i)\">\n <uni-tag\n [label]=\"labelOf(item)\"\n [value]=\"item.value\"\n [avatarSrc]=\"item.avatarSrc\"\n [variant]=\"item.invalid ? 'warn' : tagVariant()\"\n [tone]=\"tagTone()\"\n [size]=\"tagSize() ?? componentOptions().chipSize ?? 'md'\"\n [invalid]=\"!!item.invalid\"\n [disabled]=\"!!item.disabled || disabled()\"\n [interactive]=\"true\"\n [removable]=\"!item.disabled && !disabled()\"\n [controlTabIndex]=\"-1\"\n (removed)=\"removeAt(i)\"\n />\n </li>\n }\n\n <li [class]=\"inputClass()\">\n <!-- The field is one tab stop: chips carry tabindex=\"-1\" and are\n entered with Backspace/ArrowLeft, so Tab never walks through\n eight recipients to reach the next control. -->\n <input\n #field\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n [class]=\"inputClass()\"\n [disabled]=\"disabled()\"\n [placeholder]=\"placeholder() ?? ''\"\n [attr.aria-label]=\"label()\"\n [attr.aria-expanded]=\"list.open()\"\n [attr.aria-controls]=\"list.listboxId\"\n [attr.aria-activedescendant]=\"list.activeDescendantId()\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.aria-invalid]=\"showError() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n (keydown)=\"onInputKeydown($event)\"\n (input)=\"onInput($any($event.target).value)\"\n (paste)=\"onPaste($event)\"\n (blur)=\"onBlur()\"\n />\n </li>\n </ul>\n </uni-input-box>\n\n @if (list.open()) {\n <ul\n #listbox\n [id]=\"list.listboxId\"\n role=\"listbox\"\n [attr.popover]=\"popupAttr\"\n [attr.aria-label]=\"label()\"\n [class]=\"listClass()\"\n >\n @for (suggestion of visibleSuggestions(); track suggestion.value; let i = $index) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <li\n role=\"option\"\n [id]=\"list.optionId(i)\"\n [class.active]=\"i === list.activeIndex()\"\n [attr.aria-selected]=\"i === list.activeIndex()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"selectSuggestion(suggestion)\"\n >\n {{ labelOf(suggestion) }}\n @if (suggestion.description) {\n <span [class]=\"srOnly\">{{ suggestion.description }}</span>\n }\n </li>\n }\n </ul>\n }\n\n <!-- Said once for the whole field, rather than every chip advertising it. -->\n <span [id]=\"hintId\" [class]=\"srOnly\">\n Press Backspace to reach the last entry, then Backspace again to remove it.\n </span>\n\n <!-- Adds and removes are otherwise silent for a screen reader. -->\n <span role=\"status\" aria-live=\"polite\" [class]=\"srOnly\">{{ announcer.message() }}</span>\n</div>\n" }]
|
|
10132
|
+
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], preset: [{ type: i0.Input, args: [{ isSignal: true, alias: "preset", required: false }] }], separators: [{ type: i0.Input, args: [{ isSignal: true, alias: "separators", required: false }] }], commitOnBlur: [{ type: i0.Input, args: [{ isSignal: true, alias: "commitOnBlur", required: false }] }], allowDuplicates: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowDuplicates", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], validate: [{ type: i0.Input, args: [{ isSignal: true, alias: "validate", required: false }] }], parse: [{ type: i0.Input, args: [{ isSignal: true, alias: "parse", required: false }] }], tagVariant: [{ type: i0.Input, args: [{ isSignal: true, alias: "tagVariant", required: false }] }], tagTone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tagTone", required: false }] }], tagSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "tagSize", required: false }] }], suggestions: [{ type: i0.Input, args: [{ isSignal: true, alias: "suggestions", required: false }] }], query: [{ type: i0.Output, args: ["query"] }], debounceTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "debounceTime", required: false }] }], added: [{ type: i0.Output, args: ["added"] }], removed: [{ type: i0.Output, args: ["removed"] }], rejected: [{ type: i0.Output, args: ["rejected"] }], inputRef: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], chipRefs: [{ type: i0.ViewChildren, args: ['chip', { isSignal: true }] }], listRef: [{ type: i0.ViewChild, args: ['listbox', { isSignal: true }] }] } });
|
|
9746
10133
|
|
|
9747
10134
|
/**
|
|
9748
10135
|
* UniTagInputComponent Barrel File
|
|
@@ -11036,7 +11423,9 @@ class UniTourComponent extends BaseComponent {
|
|
|
11036
11423
|
skipped = output();
|
|
11037
11424
|
calloutOpen = signal(false, ...(ngDevMode ? [{ debugName: "calloutOpen" }] : /* istanbul ignore next */ []));
|
|
11038
11425
|
satisfied = signal(true, ...(ngDevMode ? [{ debugName: "satisfied" }] : /* istanbul ignore next */ []));
|
|
11039
|
-
|
|
11426
|
+
/** Repeats must still be heard: the same gate message can come round
|
|
11427
|
+
again on a later step. */
|
|
11428
|
+
announcer = createAnnouncer();
|
|
11040
11429
|
resolvedTarget = signal(undefined, ...(ngDevMode ? [{ debugName: "resolvedTarget" }] : /* istanbul ignore next */ []));
|
|
11041
11430
|
presentedIndex = signal(null, ...(ngDevMode ? [{ debugName: "presentedIndex" }] : /* istanbul ignore next */ []));
|
|
11042
11431
|
gateCleanup = null;
|
|
@@ -11140,7 +11529,7 @@ class UniTourComponent extends BaseComponent {
|
|
|
11140
11529
|
this.advance();
|
|
11141
11530
|
}
|
|
11142
11531
|
else {
|
|
11143
|
-
this.
|
|
11532
|
+
this.announcer.announce('Next available');
|
|
11144
11533
|
}
|
|
11145
11534
|
});
|
|
11146
11535
|
this.gateCleanup = () => {
|
|
@@ -11208,11 +11597,11 @@ class UniTourComponent extends BaseComponent {
|
|
|
11208
11597
|
}, ...(ngDevMode ? [{ debugName: "dotsClassName" }] : /* istanbul ignore next */ []));
|
|
11209
11598
|
fractionClassName = css({ margin: '0 auto' });
|
|
11210
11599
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniTourComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11211
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniTourComponent, isStandalone: true, selector: "uni-tour", inputs: { steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: true, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null }, backLabel: { classPropertyName: "backLabel", publicName: "backLabel", isSignal: true, isRequired: false, transformFunction: null }, skipLabel: { classPropertyName: "skipLabel", publicName: "skipLabel", isSignal: true, isRequired: false, transformFunction: null }, doneLabel: { classPropertyName: "doneLabel", publicName: "doneLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { active: "activeChange", started: "started", stepChanged: "stepChanged", finished: "finished", skipped: "skipped" }, providers: [{ provide: COMPONENT_NAME, useValue: 'tour' }], usesInheritance: true, ngImport: i0, template: "<uni-callout\n [(open)]=\"calloutOpen\"\n [key]=\"currentStep()?.key ?? ''\"\n [target]=\"resolvedTarget()\"\n [placement]=\"currentStep()?.placement ?? 'bottom'\"\n [backdrop]=\"currentStep()?.backdrop\"\n [targetInteractive]=\"targetInteractive()\"\n [header]=\"currentStep()?.title ?? ''\"\n [ariaLabel]=\"stepAriaLabel()\"\n [closeLabel]=\"skipLabel()\"\n (dismissed)=\"onDismissed($event)\"\n (panelKeydown)=\"onPanelKeydown($event)\"\n>\n <p>{{ currentStep()?.body }}</p>\n <div callout-actions [class]=\"footerClassName()\">\n @if (index() > 0) {\n <button text-button variant=\"ghost\" (click)=\"back()\">{{ backLabel() }}</button>\n }\n @if (componentOptions().progressStyle === 'fraction') {\n <span aria-hidden=\"true\" [class]=\"fractionClassName\">{{ index() + 1 }} of {{ steps().length }}</span>\n } @else {\n <span aria-hidden=\"true\" [class]=\"dotsClassName()\">\n @for (step of steps(); track $index) {\n <i [class.on]=\"$index === index()\"></i>\n }\n </span>\n }\n <!-- A click-gate advances by using the target itself \u2014 a Next button\n would be a lie, so none renders. -->\n @if (!clickGate()) {\n <button text-button [disable]=\"!satisfied()\" (click)=\"advance()\">\n {{ isLast() ? doneLabel() : nextLabel() }}\n </button>\n }\n </div>\n</uni-callout>\n<!-- One live region per tour: gate unlocks are announced here. -->\n<span role=\"status\" [class]=\"statusClassName\">{{
|
|
11600
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: UniTourComponent, isStandalone: true, selector: "uni-tour", inputs: { steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: true, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null }, backLabel: { classPropertyName: "backLabel", publicName: "backLabel", isSignal: true, isRequired: false, transformFunction: null }, skipLabel: { classPropertyName: "skipLabel", publicName: "skipLabel", isSignal: true, isRequired: false, transformFunction: null }, doneLabel: { classPropertyName: "doneLabel", publicName: "doneLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { active: "activeChange", started: "started", stepChanged: "stepChanged", finished: "finished", skipped: "skipped" }, providers: [{ provide: COMPONENT_NAME, useValue: 'tour' }], usesInheritance: true, ngImport: i0, template: "<uni-callout\n [(open)]=\"calloutOpen\"\n [key]=\"currentStep()?.key ?? ''\"\n [target]=\"resolvedTarget()\"\n [placement]=\"currentStep()?.placement ?? 'bottom'\"\n [backdrop]=\"currentStep()?.backdrop\"\n [targetInteractive]=\"targetInteractive()\"\n [header]=\"currentStep()?.title ?? ''\"\n [ariaLabel]=\"stepAriaLabel()\"\n [closeLabel]=\"skipLabel()\"\n (dismissed)=\"onDismissed($event)\"\n (panelKeydown)=\"onPanelKeydown($event)\"\n>\n <p>{{ currentStep()?.body }}</p>\n <div callout-actions [class]=\"footerClassName()\">\n @if (index() > 0) {\n <button text-button variant=\"ghost\" (click)=\"back()\">{{ backLabel() }}</button>\n }\n @if (componentOptions().progressStyle === 'fraction') {\n <span aria-hidden=\"true\" [class]=\"fractionClassName\">{{ index() + 1 }} of {{ steps().length }}</span>\n } @else {\n <span aria-hidden=\"true\" [class]=\"dotsClassName()\">\n @for (step of steps(); track $index) {\n <i [class.on]=\"$index === index()\"></i>\n }\n </span>\n }\n <!-- A click-gate advances by using the target itself \u2014 a Next button\n would be a lie, so none renders. -->\n @if (!clickGate()) {\n <button text-button [disable]=\"!satisfied()\" (click)=\"advance()\">\n {{ isLast() ? doneLabel() : nextLabel() }}\n </button>\n }\n </div>\n</uni-callout>\n<!-- One live region per tour: gate unlocks are announced here. -->\n<span role=\"status\" [class]=\"statusClassName\">{{ announcer.message() }}</span>\n", dependencies: [{ kind: "component", type: UniButtonComponent, selector: "button[uni-text-button], button[text-button]", inputs: ["disable", "loading", "fullWidth", "symbolLeft", "symbolRight"] }, { kind: "component", type: UniCalloutComponent, selector: "uni-callout", inputs: ["open", "key", "target", "placement", "backdrop", "targetInteractive", "dismissible", "dismissOnBackdrop", "header", "arrow", "ariaLabel", "closeLabel"], outputs: ["openChange", "opened", "closed", "dismissed", "panelKeydown"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11212
11601
|
}
|
|
11213
11602
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UniTourComponent, decorators: [{
|
|
11214
11603
|
type: Component,
|
|
11215
|
-
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'uni-tour', imports: [UniButtonComponent, UniCalloutComponent], providers: [{ provide: COMPONENT_NAME, useValue: 'tour' }], template: "<uni-callout\n [(open)]=\"calloutOpen\"\n [key]=\"currentStep()?.key ?? ''\"\n [target]=\"resolvedTarget()\"\n [placement]=\"currentStep()?.placement ?? 'bottom'\"\n [backdrop]=\"currentStep()?.backdrop\"\n [targetInteractive]=\"targetInteractive()\"\n [header]=\"currentStep()?.title ?? ''\"\n [ariaLabel]=\"stepAriaLabel()\"\n [closeLabel]=\"skipLabel()\"\n (dismissed)=\"onDismissed($event)\"\n (panelKeydown)=\"onPanelKeydown($event)\"\n>\n <p>{{ currentStep()?.body }}</p>\n <div callout-actions [class]=\"footerClassName()\">\n @if (index() > 0) {\n <button text-button variant=\"ghost\" (click)=\"back()\">{{ backLabel() }}</button>\n }\n @if (componentOptions().progressStyle === 'fraction') {\n <span aria-hidden=\"true\" [class]=\"fractionClassName\">{{ index() + 1 }} of {{ steps().length }}</span>\n } @else {\n <span aria-hidden=\"true\" [class]=\"dotsClassName()\">\n @for (step of steps(); track $index) {\n <i [class.on]=\"$index === index()\"></i>\n }\n </span>\n }\n <!-- A click-gate advances by using the target itself \u2014 a Next button\n would be a lie, so none renders. -->\n @if (!clickGate()) {\n <button text-button [disable]=\"!satisfied()\" (click)=\"advance()\">\n {{ isLast() ? doneLabel() : nextLabel() }}\n </button>\n }\n </div>\n</uni-callout>\n<!-- One live region per tour: gate unlocks are announced here. -->\n<span role=\"status\" [class]=\"statusClassName\">{{
|
|
11604
|
+
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'uni-tour', imports: [UniButtonComponent, UniCalloutComponent], providers: [{ provide: COMPONENT_NAME, useValue: 'tour' }], template: "<uni-callout\n [(open)]=\"calloutOpen\"\n [key]=\"currentStep()?.key ?? ''\"\n [target]=\"resolvedTarget()\"\n [placement]=\"currentStep()?.placement ?? 'bottom'\"\n [backdrop]=\"currentStep()?.backdrop\"\n [targetInteractive]=\"targetInteractive()\"\n [header]=\"currentStep()?.title ?? ''\"\n [ariaLabel]=\"stepAriaLabel()\"\n [closeLabel]=\"skipLabel()\"\n (dismissed)=\"onDismissed($event)\"\n (panelKeydown)=\"onPanelKeydown($event)\"\n>\n <p>{{ currentStep()?.body }}</p>\n <div callout-actions [class]=\"footerClassName()\">\n @if (index() > 0) {\n <button text-button variant=\"ghost\" (click)=\"back()\">{{ backLabel() }}</button>\n }\n @if (componentOptions().progressStyle === 'fraction') {\n <span aria-hidden=\"true\" [class]=\"fractionClassName\">{{ index() + 1 }} of {{ steps().length }}</span>\n } @else {\n <span aria-hidden=\"true\" [class]=\"dotsClassName()\">\n @for (step of steps(); track $index) {\n <i [class.on]=\"$index === index()\"></i>\n }\n </span>\n }\n <!-- A click-gate advances by using the target itself \u2014 a Next button\n would be a lie, so none renders. -->\n @if (!clickGate()) {\n <button text-button [disable]=\"!satisfied()\" (click)=\"advance()\">\n {{ isLast() ? doneLabel() : nextLabel() }}\n </button>\n }\n </div>\n</uni-callout>\n<!-- One live region per tour: gate unlocks are announced here. -->\n<span role=\"status\" [class]=\"statusClassName\">{{ announcer.message() }}</span>\n" }]
|
|
11216
11605
|
}], ctorParameters: () => [], propDecorators: { steps: [{ type: i0.Input, args: [{ isSignal: true, alias: "steps", required: true }] }], active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }, { type: i0.Output, args: ["activeChange"] }], nextLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextLabel", required: false }] }], backLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "backLabel", required: false }] }], skipLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "skipLabel", required: false }] }], doneLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "doneLabel", required: false }] }], started: [{ type: i0.Output, args: ["started"] }], stepChanged: [{ type: i0.Output, args: ["stepChanged"] }], finished: [{ type: i0.Output, args: ["finished"] }], skipped: [{ type: i0.Output, args: ["skipped"] }] } });
|
|
11217
11606
|
|
|
11218
11607
|
/**
|
|
@@ -11225,5 +11614,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
|
|
|
11225
11614
|
* Generated bundle index. Do not edit.
|
|
11226
11615
|
*/
|
|
11227
11616
|
|
|
11228
|
-
export { BodyRenderDirective, ConfirmationDialogComponent, DragAndDropDirective, FOCUSABLE_SELECTOR, ListboxNavigation, LocalStorageService, NotificationService, NotificationsComponent, RippleDirective, TRANSFORM_ORIGINS, ThemeService, UNI_THEMES, UniAlertComponent, UniAppBarComponent, UniAvatarComponent, UniAvatarGroupComponent, UniBackgroundComponent, UniBadgeComponent, UniBaseDatasource, UniBoxComponent, UniBreadcrumbComponent, UniButtonComponent, UniButtonGroupComponent, UniCalendarComponent, UniCalloutComponent, UniCardComponent, UniCardContentComponent, UniCardHeaderComponent, UniCenterComponent, UniCheckboxComponent, UniComboboxComponent, UniDataSearchComponent, UniDataTableComponent, UniDateInputComponent, UniDateTimeInputComponent, UniDebounceInputComponent, UniDialogButtonsComponent, UniDialogComponent, UniDialogHeaderComponent, UniDividerComponent, UniDrawerComponent, UniDropdownComponent, UniExpandAreaComponent, UniExpandComponent, UniExpandToggleComponent, UniFileDropZoneComponent, UniGridAreaComponent, UniGridComponent, UniIconButtonComponent, UniIconComponent, UniInputBoxComponent, UniInputComponent, UniJsonViewComponent, UniMenuComponent, UniMultiSelectComponent, UniMultiSelectDropdownComponent, UniNotificationBadgeComponent, UniPaginatorComponent, UniPopoverComponent, UniProgressBarComponent, UniProgressGaugeComponent, UniRadioComponent, UniRecordDatasource, UniRowComponent, UniScrollAreaComponent, UniSearchInputComponent, UniSelectComponent, UniServerSideDatasource, UniSkeletonComponent, UniSliderComponent, UniSnackbarComponent, UniSortHeaderComponent, UniStackComponent, UniStatComponent, UniSymbolComponent, UniTabComponent, UniTabsComponent, UniTagComponent, UniTagInputComponent, UniTextComponent, UniTextareaComponent, UniThemeBuilderComponent, UniThemeSwitchComponent, UniTimeInputComponent, UniToggleComponent, UniTooltipComponent, UniTourComponent, UniWrapComponent, acceptableFile, addDays, addMonths, anchorArrowStyles, anchorStyles, buildMonthGrid, clearAnchorName, createListboxNavigation, dayOfWeek, daysInMonth, discreteOverlayTransition, focusableElements, formatDate, formatMonthHeading, formatTime, getFileExtension, inclusiveDayCount, isDivider, isToggleOpen, isValidDate, isoDate, joinDateTime, listboxPopupStyles, localeDatePlaceholder, localeDefaultHour12, localeFieldOrder, localeMonthNames, localeWeekStart, monthOf, motionSafe, newAnchorName, parseDateText, parseTimeText, resolveElement, resolveFocusTarget, restoreOverlayFocus, setAnchorName, splitDateTime, spotlightStyles, timeSlots, todayIso, uniqueId, useTimer, visuallyHidden, weekdayNames };
|
|
11617
|
+
export { BodyRenderDirective, ConfirmationDialogComponent, DragAndDropDirective, FOCUSABLE_SELECTOR, ListboxNavigation, LocalStorageService, NotificationService, NotificationsComponent, RippleDirective, TRANSFORM_ORIGINS, ThemeService, UNI_THEMES, UniAlertComponent, UniAppBarComponent, UniAvatarComponent, UniAvatarGroupComponent, UniBackgroundComponent, UniBadgeComponent, UniBaseDatasource, UniBoxComponent, UniBreadcrumbComponent, UniButtonComponent, UniButtonGroupComponent, UniCalendarComponent, UniCalloutComponent, UniCardComponent, UniCardContentComponent, UniCardHeaderComponent, UniCenterComponent, UniCheckboxComponent, UniComboboxComponent, UniDataSearchComponent, UniDataTableComponent, UniDateInputComponent, UniDateTimeInputComponent, UniDebounceInputComponent, UniDialogButtonsComponent, UniDialogComponent, UniDialogHeaderComponent, UniDividerComponent, UniDrawerComponent, UniDropdownComponent, UniExpandAreaComponent, UniExpandComponent, UniExpandToggleComponent, UniFileDropZoneComponent, UniGridAreaComponent, UniGridComponent, UniIconButtonComponent, UniIconComponent, UniInputBoxComponent, UniInputComponent, UniJsonViewComponent, UniMenuComponent, UniMultiSelectComponent, UniMultiSelectDropdownComponent, UniNotificationBadgeComponent, UniPaginatorComponent, UniPopoverComponent, UniProgressBarComponent, UniProgressGaugeComponent, UniRadioComponent, UniRecordDatasource, UniRowComponent, UniScrollAreaComponent, UniSearchInputComponent, UniSelectComponent, UniServerSideDatasource, UniSkeletonComponent, UniSliderComponent, UniSnackbarComponent, UniSortHeaderComponent, UniStackComponent, UniStatComponent, UniSymbolComponent, UniTabComponent, UniTabsComponent, UniTagComponent, UniTagInputComponent, UniTextComponent, UniTextareaComponent, UniThemeBuilderComponent, UniThemeSwitchComponent, UniTimeInputComponent, UniToggleComponent, UniTooltipComponent, UniTourComponent, UniWrapComponent, acceptableFile, addDays, addMonths, anchorArrowStyles, anchorStyles, buildMonthGrid, clearAnchorName, createAnnouncer, createListboxNavigation, dayOfWeek, daysInMonth, discreteOverlayTransition, focusableElements, formatDate, formatMonthHeading, formatTime, getFileExtension, inclusiveDayCount, isDivider, isToggleOpen, isValidDate, isoDate, joinDateTime, listboxPopupAttr, listboxPopupStyles, localeDatePlaceholder, localeDefaultHour12, localeFieldOrder, localeMonthNames, localeWeekStart, monthOf, motionSafe, newAnchorName, newListboxAnchor, parseDateText, parseTimeText, promoteListboxPopup, resolveElement, resolveFocusTarget, restoreOverlayFocus, setAnchorName, splitDateTime, spotlightStyles, supportsAnchoredPopup, timeSlots, todayIso, transformOriginFor, uniqueId, useTimer, visuallyHidden, weekdayNames };
|
|
11229
11618
|
//# sourceMappingURL=uni-design-system-uni-angular.mjs.map
|