@ngneers/controls 0.0.1-next.0 → 0.0.1-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/ngneers-controls-api-ng.mjs +11 -18
- package/fesm2022/ngneers-controls-api-ng.mjs.map +1 -1
- package/fesm2022/ngneers-controls-api-resize.mjs +7 -0
- package/fesm2022/ngneers-controls-api-resize.mjs.map +1 -1
- package/fesm2022/ngneers-controls-badge.mjs +160 -0
- package/fesm2022/ngneers-controls-badge.mjs.map +1 -0
- package/fesm2022/ngneers-controls-base.mjs +85 -8
- package/fesm2022/ngneers-controls-base.mjs.map +1 -1
- package/fesm2022/{ngneers-controls-calendar-time-CJT5AFlA.mjs → ngneers-controls-calendar-time-paM6WVpV.mjs} +2 -2
- package/fesm2022/{ngneers-controls-calendar-time-CJT5AFlA.mjs.map → ngneers-controls-calendar-time-paM6WVpV.mjs.map} +1 -1
- package/fesm2022/ngneers-controls-calendar.mjs +13 -6
- package/fesm2022/ngneers-controls-calendar.mjs.map +1 -1
- package/fesm2022/ngneers-controls-checkbox.mjs +3 -3
- package/fesm2022/ngneers-controls-checkbox.mjs.map +1 -1
- package/fesm2022/ngneers-controls-color-picker.mjs +336 -0
- package/fesm2022/ngneers-controls-color-picker.mjs.map +1 -0
- package/fesm2022/ngneers-controls-default-icons.mjs +5 -0
- package/fesm2022/ngneers-controls-default-icons.mjs.map +1 -1
- package/fesm2022/ngneers-controls-directives.mjs +64 -7
- package/fesm2022/ngneers-controls-directives.mjs.map +1 -1
- package/fesm2022/ngneers-controls-edit-inplace.mjs +15 -5
- package/fesm2022/ngneers-controls-edit-inplace.mjs.map +1 -1
- package/fesm2022/ngneers-controls-errors.mjs +203 -148
- package/fesm2022/ngneers-controls-errors.mjs.map +1 -1
- package/fesm2022/ngneers-controls-filter.mjs +2 -2
- package/fesm2022/ngneers-controls-filter.mjs.map +1 -1
- package/fesm2022/ngneers-controls-hint.mjs +18 -1
- package/fesm2022/ngneers-controls-hint.mjs.map +1 -1
- package/fesm2022/ngneers-controls-i18n-translations-de.mjs +17 -0
- package/fesm2022/ngneers-controls-i18n-translations-de.mjs.map +1 -1
- package/fesm2022/ngneers-controls-i18n-translations-en.mjs +19 -0
- package/fesm2022/ngneers-controls-i18n-translations-en.mjs.map +1 -1
- package/fesm2022/ngneers-controls-icon.mjs +23 -6
- package/fesm2022/ngneers-controls-icon.mjs.map +1 -1
- package/fesm2022/ngneers-controls-input-field.mjs +18 -2
- package/fesm2022/ngneers-controls-input-field.mjs.map +1 -1
- package/fesm2022/ngneers-controls-input.mjs +49 -9
- package/fesm2022/ngneers-controls-input.mjs.map +1 -1
- package/fesm2022/ngneers-controls-list-box.mjs +2 -2
- package/fesm2022/ngneers-controls-list-box.mjs.map +1 -1
- package/fesm2022/ngneers-controls-mask-input.mjs +4 -1
- package/fesm2022/ngneers-controls-mask-input.mjs.map +1 -1
- package/fesm2022/ngneers-controls-number-input.mjs +4 -4
- package/fesm2022/ngneers-controls-number-input.mjs.map +1 -1
- package/fesm2022/ngneers-controls-otp.mjs +263 -0
- package/fesm2022/ngneers-controls-otp.mjs.map +1 -0
- package/fesm2022/ngneers-controls-paginator.mjs +36 -9
- package/fesm2022/ngneers-controls-paginator.mjs.map +1 -1
- package/fesm2022/ngneers-controls-radio.mjs +4 -4
- package/fesm2022/ngneers-controls-radio.mjs.map +1 -1
- package/fesm2022/ngneers-controls-rating.mjs +180 -0
- package/fesm2022/ngneers-controls-rating.mjs.map +1 -0
- package/fesm2022/ngneers-controls-scroll-shadow.mjs +33 -7
- package/fesm2022/ngneers-controls-scroll-shadow.mjs.map +1 -1
- package/fesm2022/ngneers-controls-scroller.mjs +4 -2
- package/fesm2022/ngneers-controls-scroller.mjs.map +1 -1
- package/fesm2022/ngneers-controls-select-button.mjs +2 -1
- package/fesm2022/ngneers-controls-select-button.mjs.map +1 -1
- package/fesm2022/ngneers-controls-select.mjs +24 -4
- package/fesm2022/ngneers-controls-select.mjs.map +1 -1
- package/fesm2022/ngneers-controls-slider.mjs +3 -3
- package/fesm2022/ngneers-controls-slider.mjs.map +1 -1
- package/fesm2022/ngneers-controls-splitter.mjs +43 -12
- package/fesm2022/ngneers-controls-splitter.mjs.map +1 -1
- package/fesm2022/ngneers-controls-stepper.mjs +142 -0
- package/fesm2022/ngneers-controls-stepper.mjs.map +1 -0
- package/fesm2022/ngneers-controls-switch.mjs +3 -3
- package/fesm2022/ngneers-controls-switch.mjs.map +1 -1
- package/fesm2022/ngneers-controls-table.mjs +282 -15
- package/fesm2022/ngneers-controls-table.mjs.map +1 -1
- package/fesm2022/ngneers-controls-tabs.mjs +2 -2
- package/fesm2022/ngneers-controls-tabs.mjs.map +1 -1
- package/fesm2022/ngneers-controls-toggle-button.mjs +3 -3
- package/fesm2022/ngneers-controls-toggle-button.mjs.map +1 -1
- package/fesm2022/ngneers-controls-tooltip.mjs +16 -28
- package/fesm2022/ngneers-controls-tooltip.mjs.map +1 -1
- package/fesm2022/ngneers-controls-tree.mjs +2 -2
- package/fesm2022/ngneers-controls-tree.mjs.map +1 -1
- package/fesm2022/ngneers-controls-utils.mjs +138 -1
- package/fesm2022/ngneers-controls-utils.mjs.map +1 -1
- package/package.json +22 -2
- package/types/ngneers-controls-api-ng.d.ts +12 -9
- package/types/ngneers-controls-badge.d.ts +67 -0
- package/types/ngneers-controls-base.d.ts +61 -4
- package/types/ngneers-controls-breadcrumb.d.ts +17 -0
- package/types/ngneers-controls-calendar.d.ts +24 -6
- package/types/ngneers-controls-chip.d.ts +17 -0
- package/types/ngneers-controls-color-picker.d.ts +119 -0
- package/types/ngneers-controls-dialog.d.ts +17 -0
- package/types/ngneers-controls-directives.d.ts +31 -2
- package/types/ngneers-controls-drawer.d.ts +17 -0
- package/types/ngneers-controls-edit-inplace.d.ts +23 -0
- package/types/ngneers-controls-errors.d.ts +105 -16
- package/types/ngneers-controls-filter.d.ts +30 -13
- package/types/ngneers-controls-hint.d.ts +8 -1
- package/types/ngneers-controls-i18n-translations-de.d.ts +17 -0
- package/types/ngneers-controls-i18n-translations-en.d.ts +17 -0
- package/types/ngneers-controls-i18n.d.ts +17 -0
- package/types/ngneers-controls-icon.d.ts +2 -2
- package/types/ngneers-controls-input-field.d.ts +28 -2
- package/types/ngneers-controls-input.d.ts +35 -3
- package/types/ngneers-controls-list-box.d.ts +17 -0
- package/types/ngneers-controls-mask-input.d.ts +17 -0
- package/types/ngneers-controls-otp.d.ts +262 -0
- package/types/ngneers-controls-paginator.d.ts +34 -3
- package/types/ngneers-controls-rating.d.ts +69 -0
- package/types/ngneers-controls-scroll-shadow.d.ts +11 -2
- package/types/ngneers-controls-scroller.d.ts +3 -1
- package/types/ngneers-controls-select.d.ts +30 -3
- package/types/ngneers-controls-snackbar.d.ts +17 -0
- package/types/ngneers-controls-splitter.d.ts +26 -2
- package/types/ngneers-controls-state.d.ts +2 -2
- package/types/ngneers-controls-stepper.d.ts +68 -0
- package/types/ngneers-controls-table.d.ts +276 -169
- package/types/ngneers-controls-toast.d.ts +17 -0
- package/types/ngneers-controls-tooltip.d.ts +0 -1
- package/types/ngneers-controls-tree.d.ts +17 -0
- package/types/ngneers-controls-upload.d.ts +17 -0
- package/types/ngneers-controls-utils.d.ts +27 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, DestroyRef, signal, afterNextRender, InjectionToken, forwardRef, ElementRef, Injector, input, booleanAttribute, computed, viewChildren, effect, Directive, isDevMode, model } from '@angular/core';
|
|
2
|
+
import { inject, DestroyRef, signal, afterNextRender, InjectionToken, forwardRef, ElementRef, Injector, input, booleanAttribute, computed, viewChildren, effect, Directive, isDevMode, model, output } from '@angular/core';
|
|
3
3
|
import { setInputSignalValue, effectWithPrevious, classSignal, generateElementId } from '@ngneers/controls/utils-ng';
|
|
4
|
-
import { Platform, injectThemeTemplate, injectThemeControlKinds, injectThemeColors, getAppliedClasses } from '@ngneers/controls/api/ng';
|
|
4
|
+
import { Platform, injectThemeTemplate, injectThemeControlDefaults, injectThemeControlKinds, injectThemeColors, getAppliedClasses } from '@ngneers/controls/api/ng';
|
|
5
5
|
import { toggleClass, getPropertyIfExists, objectKeys } from '@ngneers/controls/utils';
|
|
6
6
|
|
|
7
7
|
const NGN_INSTANCE_KEY = '__ngneers_control_instance__';
|
|
@@ -97,6 +97,14 @@ class NgnBase {
|
|
|
97
97
|
* Overridden with `true` by input, mask-input, calendar, select, ….
|
|
98
98
|
*/
|
|
99
99
|
isFieldControl = false;
|
|
100
|
+
/**
|
|
101
|
+
* Whether the control holds no user-entered content. Field controls override
|
|
102
|
+
* this from their eager entry state — not {@link isFieldControl}'s `value`,
|
|
103
|
+
* which can lag behind typing until the entry is valid (mask-input, calendar)
|
|
104
|
+
* — so a wrapping `ngn-input-field` can float its label reliably.
|
|
105
|
+
*/
|
|
106
|
+
empty = signal(false, /* @ts-ignore */
|
|
107
|
+
...(ngDevMode ? [{ debugName: "empty" }] : /* istanbul ignore next */ []));
|
|
100
108
|
/**
|
|
101
109
|
* Hook for placing focus/selection from a pointer event that originated in the
|
|
102
110
|
* surrounding field (or the control itself). The default does nothing and
|
|
@@ -266,12 +274,19 @@ class NgnBase {
|
|
|
266
274
|
injectThemeTemplate(template, hostClass) {
|
|
267
275
|
const opts = { unstyled: this.unstyled };
|
|
268
276
|
const theme = injectThemeTemplate(template, opts);
|
|
277
|
+
const defaults = injectThemeControlDefaults(theme.scope)();
|
|
269
278
|
const kinds = injectThemeControlKinds(theme.scope)();
|
|
270
|
-
if (
|
|
279
|
+
if (defaults.kind !== undefined) {
|
|
280
|
+
this._defaultKind.set(defaults.kind);
|
|
281
|
+
}
|
|
282
|
+
else if (kinds.length) {
|
|
271
283
|
this._defaultKind.set(kinds[0]);
|
|
272
284
|
}
|
|
273
285
|
const colors = injectThemeColors(theme.scope)();
|
|
274
|
-
if (
|
|
286
|
+
if (defaults.color !== undefined) {
|
|
287
|
+
this._defaultColor.set(defaults.color);
|
|
288
|
+
}
|
|
289
|
+
else if (colors.length) {
|
|
275
290
|
this._defaultColor.set(colors[0]);
|
|
276
291
|
}
|
|
277
292
|
if (hostClass !== undefined) {
|
|
@@ -569,6 +584,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
|
|
|
569
584
|
args: [{ selector: '[ptInt]' }]
|
|
570
585
|
}], ctorParameters: () => [], propDecorators: { ptInt: [{ type: i0.Input, args: [{ isSignal: true, alias: "ptInt", required: true }] }], ptClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "ptClass", required: false }] }], ptDep: [{ type: i0.Input, args: [{ isSignal: true, alias: "ptDep", required: false }] }] } });
|
|
571
586
|
|
|
587
|
+
/**
|
|
588
|
+
* Gates a raw invalid flag by an {@link NgnInvalidTrigger} against the given
|
|
589
|
+
* interaction state. Shared by {@link ValueControlBase} and `NgnInput`.
|
|
590
|
+
*/
|
|
591
|
+
function resolveInvalidState(invalid, trigger, touched, dirty) {
|
|
592
|
+
if (!invalid) {
|
|
593
|
+
return false;
|
|
594
|
+
}
|
|
595
|
+
switch (trigger) {
|
|
596
|
+
case 'immediate':
|
|
597
|
+
return true;
|
|
598
|
+
case 'never':
|
|
599
|
+
return false;
|
|
600
|
+
case 'dirty':
|
|
601
|
+
return dirty;
|
|
602
|
+
case 'touched':
|
|
603
|
+
default:
|
|
604
|
+
return touched;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
572
607
|
class ValueControlBase extends NgnBase {
|
|
573
608
|
/**
|
|
574
609
|
* The label for the control.
|
|
@@ -588,10 +623,28 @@ class ValueControlBase extends NgnBase {
|
|
|
588
623
|
inputId = input(generateElementId(), /* @ts-ignore */
|
|
589
624
|
...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
|
|
590
625
|
/**
|
|
591
|
-
*
|
|
626
|
+
* The raw invalid flag. A bound signal-forms field writes it in from the
|
|
627
|
+
* field's validity (`FormUiControl` `invalid` input); the app may also set it
|
|
628
|
+
* explicitly. Whether it actually *shows* is gated by {@link invalidOn} — map
|
|
629
|
+
* the theme's invalid part (and any `aria-invalid`) to {@link invalidState},
|
|
630
|
+
* not this.
|
|
592
631
|
* @default false
|
|
593
632
|
*/
|
|
594
633
|
invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
634
|
+
/**
|
|
635
|
+
* When the control surfaces its invalid styling. The control owns this timing
|
|
636
|
+
* (independent of `ngnErrors`, which governs only the error *message*).
|
|
637
|
+
* @default touched
|
|
638
|
+
*/
|
|
639
|
+
invalidOn = input('touched', /* @ts-ignore */
|
|
640
|
+
...(ngDevMode ? [{ debugName: "invalidOn" }] : /* istanbul ignore next */ []));
|
|
641
|
+
/**
|
|
642
|
+
* The invalid state the theme should render: {@link invalid} gated by
|
|
643
|
+
* {@link invalidOn} against {@link touched} / {@link dirty}. Controls map their
|
|
644
|
+
* theme `invalid` part (and any `aria-invalid`) to this.
|
|
645
|
+
*/
|
|
646
|
+
invalidState = computed(() => resolveInvalidState(this.invalid(), this.invalidOn(), this.touched(), this.dirty()), /* @ts-ignore */
|
|
647
|
+
...(ngDevMode ? [{ debugName: "invalidState" }] : /* istanbul ignore next */ []));
|
|
595
648
|
/**
|
|
596
649
|
* The value of the control.
|
|
597
650
|
*/
|
|
@@ -602,19 +655,43 @@ class ValueControlBase extends NgnBase {
|
|
|
602
655
|
*/
|
|
603
656
|
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
604
657
|
readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
658
|
+
/**
|
|
659
|
+
* The touched state. A bound signal-forms field writes it in via the
|
|
660
|
+
* `FormUiControl` `touched` input; the control writes it out through
|
|
661
|
+
* {@link markTouched} on blur.
|
|
662
|
+
*/
|
|
605
663
|
touched = model(false, /* @ts-ignore */
|
|
606
664
|
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
607
665
|
dirty = input(false, { ...(ngDevMode ? { debugName: "dirty" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
666
|
+
/**
|
|
667
|
+
* Emits when focus leaves the control (the `FormUiControl` `touch` contract).
|
|
668
|
+
* The `Field` directive listens to this to mark the bound field touched — it's
|
|
669
|
+
* the only channel signal forms observes for blur, so plain `touched` writes
|
|
670
|
+
* don't reach the field.
|
|
671
|
+
*/
|
|
672
|
+
touch = output();
|
|
673
|
+
/**
|
|
674
|
+
* Marks the control touched: flips {@link touched} for local / no-form
|
|
675
|
+
* consumers (e.g. `ngnErrors`) and emits {@link touch} so a bound signal-forms
|
|
676
|
+
* field is marked touched too. Each control calls this from its own blur/close
|
|
677
|
+
* logic — composite controls with an out-of-DOM overlay (select, calendar)
|
|
678
|
+
* call it from their popover-aware blur, so opening the overlay isn't mistaken
|
|
679
|
+
* for a blur.
|
|
680
|
+
*/
|
|
681
|
+
markTouched() {
|
|
682
|
+
this.touched.set(true);
|
|
683
|
+
this.touch.emit();
|
|
684
|
+
}
|
|
608
685
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ValueControlBase, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
609
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.5", type: ValueControlBase, isStandalone: true, inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, labelledBy: { classPropertyName: "labelledBy", publicName: "labelledBy", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, usesInheritance: true, ngImport: i0 });
|
|
686
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.5", type: ValueControlBase, isStandalone: true, inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, labelledBy: { classPropertyName: "labelledBy", publicName: "labelledBy", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, invalidOn: { classPropertyName: "invalidOn", publicName: "invalidOn", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange", touch: "touch" }, usesInheritance: true, ngImport: i0 });
|
|
610
687
|
}
|
|
611
688
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ValueControlBase, decorators: [{
|
|
612
689
|
type: Directive
|
|
613
|
-
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], labelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelledBy", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], 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 }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }] } });
|
|
690
|
+
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], labelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelledBy", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], invalidOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidOn", required: false }] }], 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 }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }] } });
|
|
614
691
|
|
|
615
692
|
/**
|
|
616
693
|
* Generated bundle index. Do not edit.
|
|
617
694
|
*/
|
|
618
695
|
|
|
619
|
-
export { NGN_CONTROL, NgnBase, NgnPt, NgnPtEngine, ValueControlBase, getNearestNgnInstance, getNearestNgnInstanceSig, getNgnInstance, provideSelf, setNgnInstance };
|
|
696
|
+
export { NGN_CONTROL, NgnBase, NgnPt, NgnPtEngine, ValueControlBase, getNearestNgnInstance, getNearestNgnInstanceSig, getNgnInstance, provideSelf, resolveInvalidState, setNgnInstance };
|
|
620
697
|
//# sourceMappingURL=ngneers-controls-base.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngneers-controls-base.mjs","sources":["../../src/base/ngn-instance.ts","../../src/base/base.ts","../../src/base/passthrough/pt-engine.ts","../../src/base/passthrough/pt.ts","../../src/base/value-control-base.ts","../../src/base/ngneers-controls-base.ts"],"sourcesContent":["import { afterNextRender, DestroyRef, inject, signal, type Signal, Type } from '@angular/core';\n\nimport type { AnyNgnBase, FullAnyNgnBase } from './base';\n\nconst NGN_INSTANCE_KEY = '__ngneers_control_instance__';\n\nfunction elementWithInstance(\n element: HTMLElement\n): HTMLElement & { [NGN_INSTANCE_KEY]?: AnyNgnBase } {\n return element as HTMLElement & { [NGN_INSTANCE_KEY]?: FullAnyNgnBase };\n}\n\nexport function setNgnInstance(element: HTMLElement, instance: AnyNgnBase): void {\n elementWithInstance(element)[NGN_INSTANCE_KEY] = instance;\n inject(DestroyRef).onDestroy(() => {\n delete elementWithInstance(element)[NGN_INSTANCE_KEY];\n });\n}\n\nexport function getNgnInstance(element: HTMLElement): FullAnyNgnBase {\n return elementWithInstance(element)[NGN_INSTANCE_KEY] as FullAnyNgnBase;\n}\n\nexport function getNearestNgnInstance<T extends Type<Omit<AnyNgnBase, 'kind'>>>(\n element: HTMLElement,\n kind?: T\n): InstanceType<T> | null {\n let current: HTMLElement | null = element;\n while (current) {\n const instance = elementWithInstance(current)[NGN_INSTANCE_KEY] as FullAnyNgnBase | undefined;\n if (instance && (!kind || instance instanceof kind)) {\n return instance as InstanceType<T>;\n }\n current = current.parentElement;\n }\n return null;\n}\n\nexport function getNearestNgnInstanceSig<T extends Type<AnyNgnBase>>(\n element: HTMLElement,\n kind?: T\n): Signal<InstanceType<T> | null> {\n const sig = signal<InstanceType<T> | null>(null);\n afterNextRender(() => {\n sig.set(getNearestNgnInstance(element, kind));\n });\n return sig;\n}\n","import {\n afterNextRender,\n booleanAttribute,\n computed,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n forwardRef,\n inject,\n InjectionToken,\n Injector,\n input,\n type InputSignal,\n type Provider,\n signal,\n type Signal,\n Type,\n viewChildren,\n} from '@angular/core';\nimport {\n type ControlTemplateInfo,\n injectThemeTemplate,\n injectThemeControlKinds,\n injectThemeColors,\n type AppliedThemeClassCfg,\n Platform,\n} from '@ngneers/controls/api/ng';\nimport { toggleClass } from '@ngneers/controls/utils';\nimport { effectWithPrevious, setInputSignalValue } from '@ngneers/controls/utils-ng';\n\nimport { setNgnInstance } from './ngn-instance';\nimport { type NgnPassthrough, NgnPtEngine } from './passthrough';\n\nimport type { CustomColor, CustomKind } from '@ngneers/controls-custom-types';\nimport type { ControlTemplate } from '@ngneers/controls-themes';\nimport type { ControlName, ThemeTemplate } from '@ngneers/controls-themes/templates';\n\nexport const NGN_CONTROL = new InjectionToken<NgnBase<never>>('NGN_CONTROL');\n\n// eslint-disable-next-line typescript/no-explicit-any\nexport type AnyNgnBase = NgnBaseSafe<any>;\nexport type NgnBaseSafe<T extends ControlName | null> = Omit<\n NgnBase<T>,\n 'kind' | 'appliedKind' | 'pt'\n>;\n\n/* eslint-disable typescript/no-explicit-any */\nexport type FullAnyNgnBase = Omit<NgnBase<any>, 'kind' | 'appliedKind' | 'pt'> & {\n kind: InputSignal<CustomKind<any> | undefined>;\n appliedKind: InputSignal<CustomKind<any> | undefined>;\n pt: InputSignal<NgnPassthrough<any> | undefined>;\n};\n/* eslint-enable typescript/no-explicit-any */\n\n/**\n * @internal\n * Provides the control itself for dependency injection.\n * @param control - The control class to provide.\n * @returns A provider for the control itself.\n */\nexport function provideSelf(control: Type<unknown>): Provider {\n return { provide: NGN_CONTROL, useExisting: forwardRef(() => control) };\n}\n\n@Directive({\n host: { class: 'ngn-control ngn-control-initializing' },\n})\nexport abstract class NgnBase<T extends ControlName | null> {\n protected abstract theme: ControlTemplateInfo<never> | null;\n\n private readonly _defaultKind = signal<CustomKind<T> | undefined>(undefined);\n private readonly _defaultColor = signal<CustomColor | undefined>(undefined);\n private readonly _kindOverride = signal<CustomKind<T> | undefined>(undefined);\n\n /**\n * The element reference for the host element.\n */\n public readonly element = inject<ElementRef<HTMLElement>>(ElementRef);\n /**\n * The injector for the component.\n */\n public readonly injector = inject(Injector);\n /**\n * If true, the control will not apply any theme styles.\n * The base styles of the control will still be applied.\n * @default false\n */\n public readonly unstyled = input(false, { transform: booleanAttribute });\n\n /**\n * Some controls support custom kinds for styling purposes.\n * The available kinds depend on the control and the theme used.\n *\n * TODO: link to custom types documentation\n */\n public readonly kind = input<CustomKind<T> | undefined>(undefined as never);\n public readonly color = input<CustomColor | undefined>(undefined as never);\n\n public readonly appliedKind = computed<CustomKind<T> | undefined>(\n () => this._kindOverride() ?? this.kind() ?? this._defaultKind()\n );\n public readonly appliedColor = computed<CustomColor | undefined>(\n () => this.color() ?? this._defaultColor()\n );\n\n /**\n * Custom passthrough attributes to apply to the control's theme classes and its dependencies.\n * This allows for fine-grained customization of attributes, styles and more.\n */\n public readonly pt = input<T extends string ? NgnPassthrough<T> : never>();\n\n /**\n * Marks a control as the primary value control of a surrounding field\n * (e.g. `ngn-input-field`). Fields resolve their projected control by\n * filtering for this flag, so auxiliary controls placed inside the field\n * (buttons, icons, spin buttons, …) never shadow the actual input.\n * Overridden with `true` by input, mask-input, calendar, select, ….\n */\n public readonly isFieldControl: boolean = false;\n\n /**\n * Hook for placing focus/selection from a pointer event that originated in the\n * surrounding field (or the control itself). The default does nothing and\n * returns `false`, signalling the surrounding field should fall back to its\n * primitive focusing. Controls that own internal focus placement (e.g.\n * mask-input) override this, act on the pointer location, and return `true`.\n */\n public focusFromPointer(_event: MouseEvent): boolean {\n return false;\n }\n\n /**\n * Hook for stepping the control's value (e.g. from `ngn-spin-buttons` or\n * other external steppers). The default does nothing and returns `false`.\n * Controls with a steppable value (e.g. number-input) override this, apply\n * the step and return `true`.\n * @param _direction - `1` to increment, `-1` to decrement.\n * @param _big - Whether to apply the control's big step (e.g. Shift+Arrow).\n */\n public stepValue(_direction: 1 | -1, _big = false): boolean {\n return false;\n }\n\n /**\n * Hook telling external steppers (e.g. `ngn-spin-buttons`) whether the value\n * can currently be stepped in the given direction. The default returns\n * `false`; controls overriding {@link stepValue} override this as well\n * (typically `false` at a min/max bound or while disabled/readonly).\n */\n public canStepValue(_direction: 1 | -1): boolean {\n return false;\n }\n\n /**\n * Hook for clearing the control's own value/state (e.g. from a surrounding\n * field's clear button). The default does nothing and returns `false`, so the\n * caller falls back to clearing the underlying DOM input. Controls that manage\n * their own value (e.g. mask-input) override this to reset and return `true`.\n */\n public clearValue(): boolean {\n return false;\n }\n\n /**\n * Temporarily overrides the authored kind without mutating the public input.\n * Intended for derived control states such as validation-driven hints.\n */\n protected setKindOverride(kind: CustomKind<T> | undefined): void {\n this._kindOverride.set(kind);\n }\n\n private readonly _childNgnControls = viewChildren(NGN_CONTROL);\n private readonly _afterLeaveCbs: (() => void)[] = [];\n\n constructor() {\n // `pt` is typed against this control's own `T`, which makes `this`\n // (NgnBase<T>) structurally incompatible with the type-erased AnyNgnBase\n // alias for an unconstrained/generic T. Safe: AnyNgnBase never reads `pt`\n // in a way that depends on the real T at the call site.\n setNgnInstance(this.element.nativeElement, this as unknown as AnyNgnBase);\n this.prepareAfterLeaveHook();\n effect(() => {\n // Propagate unstyled state to direct child controls, does not affect\n // custom user content passed into ng-content or projected templates.\n this._childNgnControls().forEach(child => {\n setInputSignalValue(child.unstyled, this.unstyled());\n });\n });\n\n this.initializeKindAndColorClasses();\n\n if (inject(Platform).isBrowser) {\n // Remove the initializing class after the first render to prevent FOUC.\n afterNextRender(() => {\n this.element.nativeElement.classList.remove('ngn-control-initializing');\n });\n } else {\n // Remove the initializing class immediately on the server to serve a complete initial HTML.\n this.element.nativeElement.classList.remove('ngn-control-initializing');\n }\n }\n\n /**\n * Prepares the after leave hook to be called when the control is destroyed\n * and its leave animation has finished.\n */\n private prepareAfterLeaveHook() {\n inject(DestroyRef).onDestroy(() => {\n if (typeof this.element.nativeElement.getAnimations !== 'function') {\n this.afterLeaveInternal();\n } else {\n NgnBase._enqueueLeaveCheck(this.element.nativeElement, () => this.afterLeaveInternal());\n }\n });\n }\n\n // --- Batched leave animation checking ---\n // Collects all destroyed components in the same frame into one queue,\n // then processes them in a single rAF to avoid layout thrashing from\n // interleaved getAnimations() calls and DOM mutations.\n\n private static _leaveQueue: { element: HTMLElement; callback: () => void }[] = [];\n private static _leaveRafScheduled = false;\n\n private static _enqueueLeaveCheck(element: HTMLElement, callback: () => void): void {\n NgnBase._leaveQueue.push({ element, callback });\n if (!NgnBase._leaveRafScheduled) {\n NgnBase._leaveRafScheduled = true;\n requestAnimationFrame(() => NgnBase._processLeaveQueue());\n }\n }\n\n private static _processLeaveQueue(): void {\n const queue = NgnBase._leaveQueue;\n NgnBase._leaveQueue = [];\n NgnBase._leaveRafScheduled = false;\n\n // Phase 1: Read all animations (batched queries — no interleaved mutations)\n const results: { animation: Animation | null; callback: () => void }[] = [];\n for (const { element, callback } of queue) {\n results.push({\n animation: NgnBase._findLeaveAnimation(element),\n callback,\n });\n }\n\n // Phase 2: Process results (no more style queries needed)\n for (const { animation, callback } of results) {\n if (!animation) {\n callback();\n } else {\n animation.finished\n .catch(() => {\n // ignore errors from animations being cancelled\n })\n .finally(() => {\n callback();\n });\n }\n }\n }\n\n /**\n * Recursively searches for a leave animation on the element and its parents.\n */\n private static _findLeaveAnimation(element: HTMLElement): Animation | null {\n const animations = element.getAnimations();\n const leaveAnimation = animations.find(\n a => a instanceof CSSAnimation && a.animationName.endsWith('-leave')\n );\n if (leaveAnimation) {\n return leaveAnimation;\n }\n if (element.parentElement) {\n return NgnBase._findLeaveAnimation(element.parentElement);\n }\n return null;\n }\n\n private afterLeaveInternal() {\n /**\n * After the control is hidden/removed from the DOM,\n * manually wipe the innerHTML to ensure no detached children remain\n * mapped to this component's LView slots in the browser's memory.\n * This is especially important for controls that use ng-content\n * or dynamically render child components.\n */\n this.element.nativeElement.innerHTML = '';\n this._afterLeaveCbs.forEach(cb => cb());\n this.afterLeave();\n }\n /**\n * Lifecycle hook that is called after the control has left (been removed from) the DOM.\n * Can be overridden by subclasses to perform custom actions after the leave animation.\n */\n protected afterLeave() {\n // Can be overridden by subclasses\n }\n\n /**\n * @internal\n */\n protected injectThemeTemplate<External extends boolean = false>(\n template: External extends true ? ControlTemplate : T extends string ? ThemeTemplate[T] : never,\n hostClass?: null extends T ? never : AppliedThemeClassCfg<T & string>\n ): ControlTemplateInfo<\n External extends true ? ControlTemplate : T extends string ? ThemeTemplate[T] : never\n > {\n const opts = { unstyled: this.unstyled };\n const theme = injectThemeTemplate(template, opts);\n\n const kinds = injectThemeControlKinds(theme.scope)();\n if (kinds.length) {\n this._defaultKind.set(kinds[0] as CustomKind<T>);\n }\n const colors = injectThemeColors(theme.scope)();\n if (colors.length) {\n this._defaultColor.set(colors[0] as CustomColor);\n }\n\n if (hostClass !== undefined) {\n // See constructor comment: `this` (NgnBase<T>) isn't structurally assignable\n // to NgnBaseSafe<T & string> for a generic T because `pt`'s type still\n // depends on T. Narrow the erasure to this control's own T & string, which\n // matches what NgnPtEngine actually needs here.\n new NgnPtEngine(this as unknown as NgnBaseSafe<T & string>, hostClass);\n }\n\n return theme as ControlTemplateInfo<\n External extends true ? ControlTemplate : T extends string ? ThemeTemplate[T] : never\n >;\n }\n\n /**\n * Toggles the kind and color theme classes based on the current values of the kind and color inputs.\n */\n private initializeKindAndColorClasses() {\n this.initializeAutoThemeClasses('kind', this.appliedKind);\n this.initializeAutoThemeClasses('color', this.appliedColor);\n }\n\n /**\n * Initializes automatic theme class toggling for a given prefix based on the provided string signal.\n *\n * ⚠️ Caution: This method assumes that the control's theme supports classes with the given prefix.\n *\n * ⚠️ Caution: Make sure the signal provides only string or nullish values.\n *\n * @param prefix The prefix for the theme class (e.g., 'kind' or 'color').\n * @param signal The signal that provides the current string value for the theme class.\n */\n protected initializeAutoThemeClasses(prefix: string, signal: Signal<unknown | undefined>) {\n const element = this.element.nativeElement;\n\n type ThemeClassToken = Parameters<ControlTemplateInfo<never>['class']>[0];\n /**\n * We can't know here whether the control has any kind or color classes,\n * so we cast explicitly to ThemeClassToken. In practice, controls without\n * kind or color classes will simply not toggle any classes as the input type does not allow it.\n */\n const classToken = (value: string): ThemeClassToken => value as unknown as ThemeClassToken;\n\n const togglePrefixedThemeClass = (prefix: string, value: unknown, enabled: boolean): void => {\n if (!value) {\n return;\n }\n const theme = this.theme;\n if (!theme) {\n return;\n }\n toggleClass(element, theme.class(classToken(`${prefix}-${value}`)), enabled);\n };\n\n effectWithPrevious(signal, (current, previous) => {\n togglePrefixedThemeClass(prefix, previous, false);\n togglePrefixedThemeClass(prefix, current, true);\n });\n\n this._afterLeaveCbs.push(() => {\n togglePrefixedThemeClass(prefix, signal(), false);\n });\n }\n}\n","import { computed, DestroyRef, ElementRef, inject, type Signal, signal } from '@angular/core';\nimport {\n type ControlTemplateInfo,\n type AppliedThemeClassCfg,\n getAppliedClasses,\n} from '@ngneers/controls/api/ng';\nimport { getPropertyIfExists, objectKeys } from '@ngneers/controls/utils';\nimport { classSignal, effectWithPrevious } from '@ngneers/controls/utils-ng';\n\nimport type { AnyNgnPassthrough, PassthroughValue } from './types';\nimport type { NgnBase, NgnBaseSafe } from '../base';\nimport type { ControlName, ControlTemplate } from '@ngneers/controls-themes';\n\n/** Writable, string-valued properties of `CSSStyleDeclaration` (the camelCase CSS properties). */\ntype WritableStyleKey = Extract<keyof CSSStyleDeclaration, string> &\n {\n [K in keyof CSSStyleDeclaration]: CSSStyleDeclaration[K] extends string ? K : never;\n }[keyof CSSStyleDeclaration];\n\nexport class NgnPtEngine<T extends NgnBaseSafe<Name>, Name extends ControlName> {\n private readonly pt: Signal<NgnBase<Name>>;\n private readonly ptClass: Signal<\n AppliedThemeClassCfg<T extends NgnBaseSafe<infer A> ? (A extends null ? never : A) : never>\n >;\n\n private readonly _elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly _destroyRef = inject(DestroyRef);\n\n /** The passthrough values currently applied to the element, for teardown on destroy. */\n private _currentAppliedPts: ReturnType<NgnPtEngine<T, Name>['_appliedPts']>;\n\n private readonly classes = computed(() => {\n const pt = this.pt();\n if ('theme' in pt) {\n const theme = pt['theme'] as ControlTemplateInfo<ControlTemplate<Name>>;\n const res = getAppliedClasses(this.ptClass(), theme);\n return res;\n }\n return [];\n });\n\n private readonly _appliedPts = computed(() => {\n const pt = this.pt()?.pt() as AnyNgnPassthrough;\n if (!pt) {\n return;\n }\n const classes = this.classes();\n return classes.map(({ name: ptClass }) => {\n const classPt = getPropertyIfExists(pt, ptClass);\n return classPt;\n });\n });\n\n constructor(\n pt: Signal<T> | T,\n ptClass:\n | Signal<\n AppliedThemeClassCfg<\n T extends NgnBaseSafe<infer A> ? (A extends null ? never : A) : never\n >\n >\n | AppliedThemeClassCfg<T extends NgnBaseSafe<infer A> ? (A extends null ? never : A) : never>,\n options?: {\n /**\n * When `false`, the engine only toggles the resolved theme class(es) on the\n * element and does NOT apply the control's `pt` slice (styles/attributes/\n * classes/listeners) for those classes. Used for dependency-slot markers,\n * where the forwarded passthrough is applied through the nested control's\n * own engine rather than flatly on the host. Defaults to `true`.\n */\n applyPassthrough?: boolean;\n }\n ) {\n const sigPt = typeof pt === 'function' ? pt : signal(pt);\n const sigPtClass = typeof ptClass === 'function' ? ptClass : signal(ptClass);\n\n this.pt = sigPt as unknown as Signal<NgnBase<Name>>;\n this.ptClass = sigPtClass;\n\n const classes = computed(() => this.classes().map(c => c.class));\n classSignal(this._elementRef.nativeElement, classes);\n\n if (options?.applyPassthrough === false) {\n return;\n }\n\n effectWithPrevious(this._appliedPts, (current, previous) => {\n if (previous) {\n for (const classPt of previous) {\n if (!classPt) {\n continue;\n }\n this.removePreviousPtValues(classPt);\n }\n }\n if (current) {\n for (const classPt of current) {\n if (!classPt) {\n continue;\n }\n this.setNewPtValues(classPt);\n }\n }\n this._currentAppliedPts = current;\n });\n\n // Detach applied passthrough (notably event listeners) when the element is\n // destroyed, so nothing leaks past the control's lifetime.\n this._destroyRef.onDestroy(() => {\n if (!this._currentAppliedPts) {\n return;\n }\n for (const classPt of this._currentAppliedPts) {\n if (!classPt) {\n continue;\n }\n this.removePreviousPtValues(classPt);\n }\n });\n }\n\n private setNewPtValues(classPt: PassthroughValue) {\n if (classPt.$styles) {\n const keys = objectKeys(classPt.$styles);\n keys.forEach(key => {\n this._elementRef.nativeElement.style[key as WritableStyleKey] =\n (classPt.$styles?.[key] as string) || '';\n });\n }\n if (classPt.$attributes) {\n const keys = objectKeys(classPt.$attributes);\n keys.forEach(key => {\n this._elementRef.nativeElement.setAttribute(\n key as string,\n (classPt.$attributes?.[key] as string) || ''\n );\n });\n }\n if (classPt.$classes) {\n const arrayOfClasses = Array.isArray(classPt.$classes)\n ? classPt.$classes.flatMap(c => c.split(' '))\n : classPt.$classes.split(' ');\n arrayOfClasses.forEach(cls => {\n try {\n this._elementRef.nativeElement.classList.add(cls);\n } catch {\n console.warn(`Could not add class '${cls}' to element`, this._elementRef.nativeElement);\n }\n });\n }\n if (classPt.$listeners) {\n objectKeys(classPt.$listeners).forEach(eventName => {\n const handler = classPt.$listeners?.[eventName];\n if (!handler) {\n return;\n }\n this._elementRef.nativeElement.addEventListener(eventName, handler as any);\n });\n }\n }\n\n private removePreviousPtValues(classPt: PassthroughValue) {\n if (classPt.$styles) {\n const keys = objectKeys(classPt.$styles);\n keys.forEach(key => {\n this._elementRef.nativeElement.style[key as WritableStyleKey] = '';\n });\n }\n if (classPt.$attributes) {\n const keys = objectKeys(classPt.$attributes);\n keys.forEach(key => {\n this._elementRef.nativeElement.removeAttribute(key as string);\n });\n }\n if (classPt.$classes) {\n const arrayOfClasses = Array.isArray(classPt.$classes)\n ? classPt.$classes.flatMap(c => c.split(' '))\n : classPt.$classes.split(' ');\n arrayOfClasses.forEach(cls => {\n try {\n this._elementRef.nativeElement.classList.remove(cls);\n } catch {\n console.warn(\n `Could not remove class '${cls}' from element`,\n this._elementRef.nativeElement\n );\n }\n });\n }\n if (classPt.$listeners) {\n objectKeys(classPt.$listeners).forEach(eventName => {\n const listener = classPt.$listeners?.[eventName];\n if (!listener) {\n return;\n }\n this._elementRef.nativeElement.removeEventListener(eventName, listener as any);\n });\n }\n }\n}\n","import { computed, Directive, effect, inject, input, isDevMode } from '@angular/core';\nimport { setInputSignalValue } from '@ngneers/controls/utils-ng';\n\nimport { NGN_CONTROL } from '../base';\nimport { NgnPtEngine } from './pt-engine';\n\nimport type { AnyNgnPassthrough } from './types';\nimport type { FullAnyNgnBase, NgnBaseSafe } from '../base';\nimport type { AppliedThemeClassCfg } from '@ngneers/controls/api/ng';\nimport type { ControlName, ControlTemplate, ThemeTemplate } from '@ngneers/controls-themes';\n\n/** The control name backing a parent `NgnBaseSafe`, or `never` for a nameless base. */\ntype ParentName<T> = T extends NgnBaseSafe<infer A> ? (A extends null ? never : A) : never;\n\n/**\n * Union of the NON-projected dependency-slot class tokens declared on a control's\n * theme template — i.e. the valid `[ptDep]` targets for parent control `Name`.\n * Projected slots are excluded — they have no host element to bind `[ptDep]` to,\n * so accepting them would type-check a no-op.\n */\nexport type DepClass<Name extends ControlName> = ThemeTemplate[Name] extends ControlTemplate\n ? Exclude<ThemeTemplate[Name]['dependencies'][number], { projected: true }>['class']\n : never;\n\n// Internal passthrough directive; intentionally uses the non-prefixed `ptInt` selector.\n@Directive({ selector: '[ptInt]' })\nexport class NgnPt<T extends NgnBaseSafe<Name>, Name extends ControlName> {\n /** The parent control whose theme/passthrough this element pulls from. */\n public readonly ptInt = input.required<T>();\n /**\n * Parent-scope class token(s) applied to this element, along with the parent's\n * `pt` slice for those classes. Use for flat theme parts of the parent.\n */\n public readonly ptClass = input<AppliedThemeClassCfg<ParentName<T>>>();\n /**\n * Dependency-slot class on the parent. Applies the parent's marker class\n * (`{parentScope}-{ptDep}`) to this element and forwards the parent's\n * `pt[ptDep]` slice into the nested control that lives on this element, so the\n * nested control resolves it against its own theme.\n */\n public readonly ptDep = input<DepClass<ParentName<T>>>();\n\n /**\n * The nested control hosted on THIS element (present when `ptDep` targets a\n * control). `self: true` is essential: without it the injection climbs to an\n * ancestor control (e.g. the parent that owns `[ptInt]`), and the forwarding\n * effect would then overwrite the ancestor's `pt` instead of the child's.\n */\n private readonly _self = inject(NGN_CONTROL, {\n optional: true,\n self: true,\n }) as unknown as FullAnyNgnBase | null;\n\n /**\n * Flat class engine for `ptClass`: applies the parent's scope class(es) and the\n * matching `pt` slice to this element. A missing `ptClass` resolves to a no-op.\n */\n private readonly _classEngine = new NgnPtEngine(\n this.ptInt,\n computed(() => this.ptClass() ?? ({} as AppliedThemeClassCfg<ParentName<T>>))\n );\n\n /**\n * Marker engine for `ptDep`: applies ONLY the parent's `{parentScope}-{ptDep}`\n * class to this element (`applyPassthrough: false`). The forwarded slice is\n * applied separately, through the nested control's own engine.\n */\n private readonly _markerEngine = new NgnPtEngine(\n this.ptInt,\n computed(() => (this.ptDep() ?? {}) as AppliedThemeClassCfg<ParentName<T>>),\n { applyPassthrough: false }\n );\n\n /** The parent's `pt` slice for the current `ptDep` slot, or `undefined`. */\n private readonly _depSlice = computed<AnyNgnPassthrough | undefined>(() => {\n const dep = this.ptDep();\n if (!dep) {\n return undefined;\n }\n const parentPt = (this.ptInt() as unknown as FullAnyNgnBase).pt?.() as\n | Record<string, AnyNgnPassthrough>\n | undefined;\n return parentPt?.[dep as string];\n });\n\n constructor() {\n const self = this._self;\n if (!self) {\n // No nested control on this element (e.g. `ptDep` on a plain element): only\n // the marker class applies; there is no child theme to forward the slice to.\n // Warn (dev only) if a `ptDep` is actually set — read it in an effect, since\n // inputs are not yet resolved in the constructor.\n if (isDevMode()) {\n effect(() => {\n if (this.ptDep()) {\n console.warn(\n '[ptDep] is set but no nested control was found on this element; the parent' +\n \" dependency slice can't be forwarded. Did you forget to host a control here?\"\n );\n }\n });\n }\n return;\n }\n // Forward the parent's dependency slice into the nested control's own `pt`\n // input, so the child's existing engine(s) resolve it against its theme.\n // Reactive to parent `pt` changes; torn down with the directive/child. Writes\n // on every run (even `undefined`) so a slice that disappears (e.g. `ptDep`\n // cleared) clears the child's `pt` instead of leaving it stale; the child's\n // own engine already treats a falsy `pt` as a no-op.\n effect(() => {\n setInputSignalValue(self.pt, this._depSlice());\n });\n }\n}\n","import { booleanAttribute, Directive, input, model } from '@angular/core';\nimport { generateElementId } from '@ngneers/controls/utils-ng';\n\nimport { NgnBase } from './base';\n\nimport type { FormValueControl } from '@angular/forms/signals';\nimport type { ControlName } from '@ngneers/controls-themes/templates';\n\n@Directive()\nexport abstract class ValueControlBase<C extends ControlName, T>\n extends NgnBase<C>\n implements FormValueControl<T>\n{\n /**\n * The label for the control.\n */\n public readonly label = input<string | null>(null);\n /**\n * Sets the `aria-labelledby` attribute on the control.\n * @default null\n */\n public readonly labelledBy = input<string | null>(null);\n /**\n * The ID for the control\n * @default generateElementId()\n */\n public readonly inputId = input<string>(generateElementId());\n /**\n * Explicitly apply invalid state styling\n * @default false\n */\n public readonly invalid = input(false, { transform: booleanAttribute });\n /**\n * The value of the control.\n */\n public readonly value = model<T>(undefined as T);\n /**\n * Set the disabled state of the control.\n */\n public readonly disabled = input(false, { transform: booleanAttribute });\n\n public readonly readonly = input(false, { transform: booleanAttribute });\n\n public readonly touched = model(false);\n\n public readonly dirty = input(false, { transform: booleanAttribute });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;AAIA,MAAM,gBAAgB,GAAG,8BAA8B;AAEvD,SAAS,mBAAmB,CAC1B,OAAoB,EAAA;AAEpB,IAAA,OAAO,OAAgE;AACzE;AAEM,SAAU,cAAc,CAAC,OAAoB,EAAE,QAAoB,EAAA;IACvE,mBAAmB,CAAC,OAAO,CAAC,CAAC,gBAAgB,CAAC,GAAG,QAAQ;AACzD,IAAA,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAK;AAChC,QAAA,OAAO,mBAAmB,CAAC,OAAO,CAAC,CAAC,gBAAgB,CAAC;AACvD,IAAA,CAAC,CAAC;AACJ;AAEM,SAAU,cAAc,CAAC,OAAoB,EAAA;AACjD,IAAA,OAAO,mBAAmB,CAAC,OAAO,CAAC,CAAC,gBAAgB,CAAmB;AACzE;AAEM,SAAU,qBAAqB,CACnC,OAAoB,EACpB,IAAQ,EAAA;IAER,IAAI,OAAO,GAAuB,OAAO;IACzC,OAAO,OAAO,EAAE;QACd,MAAM,QAAQ,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC,gBAAgB,CAA+B;QAC7F,IAAI,QAAQ,KAAK,CAAC,IAAI,IAAI,QAAQ,YAAY,IAAI,CAAC,EAAE;AACnD,YAAA,OAAO,QAA2B;QACpC;AACA,QAAA,OAAO,GAAG,OAAO,CAAC,aAAa;IACjC;AACA,IAAA,OAAO,IAAI;AACb;AAEM,SAAU,wBAAwB,CACtC,OAAoB,EACpB,IAAQ,EAAA;AAER,IAAA,MAAM,GAAG,GAAG,MAAM,CAAyB,IAAI;4EAAC;IAChD,eAAe,CAAC,MAAK;QACnB,GAAG,CAAC,GAAG,CAAC,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC/C,IAAA,CAAC,CAAC;AACF,IAAA,OAAO,GAAG;AACZ;;MCTa,WAAW,GAAG,IAAI,cAAc,CAAiB,aAAa;AAe3E;AAEA;;;;;AAKG;AACG,SAAU,WAAW,CAAC,OAAsB,EAAA;AAChD,IAAA,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,CAAC,MAAM,OAAO,CAAC,EAAE;AACzE;MAKsB,OAAO,CAAA;IAGV,YAAY,GAAG,MAAM,CAA4B,SAAS;qFAAC;IAC3D,aAAa,GAAG,MAAM,CAA0B,SAAS;sFAAC;IAC1D,aAAa,GAAG,MAAM,CAA4B,SAAS;sFAAC;AAE7E;;AAEG;AACa,IAAA,OAAO,GAAG,MAAM,CAA0B,UAAU,CAAC;AACrE;;AAEG;AACa,IAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AAC3C;;;;AAIG;IACa,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;AAExE;;;;;AAKG;IACa,IAAI,GAAG,KAAK,CAA4B,SAAkB;6EAAC;IAC3D,KAAK,GAAG,KAAK,CAA0B,SAAkB;8EAAC;AAE1D,IAAA,WAAW,GAAG,QAAQ,CACpC,MAAM,IAAI,CAAC,aAAa,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,YAAY,EAAE;oFACjE;AACe,IAAA,YAAY,GAAG,QAAQ,CACrC,MAAM,IAAI,CAAC,KAAK,EAAE,IAAI,IAAI,CAAC,aAAa,EAAE;qFAC3C;AAED;;;AAGG;AACa,IAAA,EAAE,GAAG,KAAK;sFAAgD;AAE1E;;;;;;AAMG;IACa,cAAc,GAAY,KAAK;AAE/C;;;;;;AAMG;AACI,IAAA,gBAAgB,CAAC,MAAkB,EAAA;AACxC,QAAA,OAAO,KAAK;IACd;AAEA;;;;;;;AAOG;AACI,IAAA,SAAS,CAAC,UAAkB,EAAE,IAAI,GAAG,KAAK,EAAA;AAC/C,QAAA,OAAO,KAAK;IACd;AAEA;;;;;AAKG;AACI,IAAA,YAAY,CAAC,UAAkB,EAAA;AACpC,QAAA,OAAO,KAAK;IACd;AAEA;;;;;AAKG;IACI,UAAU,GAAA;AACf,QAAA,OAAO,KAAK;IACd;AAEA;;;AAGG;AACO,IAAA,eAAe,CAAC,IAA+B,EAAA;AACvD,QAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;IAC9B;IAEiB,iBAAiB,GAAG,YAAY,CAAC,WAAW;0FAAC;IAC7C,cAAc,GAAmB,EAAE;AAEpD,IAAA,WAAA,GAAA;;;;;QAKE,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,IAA6B,CAAC;QACzE,IAAI,CAAC,qBAAqB,EAAE;QAC5B,MAAM,CAAC,MAAK;;;YAGV,IAAI,CAAC,iBAAiB,EAAE,CAAC,OAAO,CAAC,KAAK,IAAG;gBACvC,mBAAmB,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;AACtD,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;QAEF,IAAI,CAAC,6BAA6B,EAAE;AAEpC,QAAA,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE;;YAE9B,eAAe,CAAC,MAAK;gBACnB,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,0BAA0B,CAAC;AACzE,YAAA,CAAC,CAAC;QACJ;aAAO;;YAEL,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,0BAA0B,CAAC;QACzE;IACF;AAEA;;;AAGG;IACK,qBAAqB,GAAA;AAC3B,QAAA,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAK;YAChC,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,aAAa,KAAK,UAAU,EAAE;gBAClE,IAAI,CAAC,kBAAkB,EAAE;YAC3B;iBAAO;AACL,gBAAA,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACzF;AACF,QAAA,CAAC,CAAC;IACJ;;;;;AAOQ,IAAA,OAAO,WAAW,GAAqD,EAAE;AACzE,IAAA,OAAO,kBAAkB,GAAG,KAAK;AAEjC,IAAA,OAAO,kBAAkB,CAAC,OAAoB,EAAE,QAAoB,EAAA;QAC1E,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AAC/C,QAAA,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE;AAC/B,YAAA,OAAO,CAAC,kBAAkB,GAAG,IAAI;YACjC,qBAAqB,CAAC,MAAM,OAAO,CAAC,kBAAkB,EAAE,CAAC;QAC3D;IACF;AAEQ,IAAA,OAAO,kBAAkB,GAAA;AAC/B,QAAA,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW;AACjC,QAAA,OAAO,CAAC,WAAW,GAAG,EAAE;AACxB,QAAA,OAAO,CAAC,kBAAkB,GAAG,KAAK;;QAGlC,MAAM,OAAO,GAA4D,EAAE;QAC3E,KAAK,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,KAAK,EAAE;YACzC,OAAO,CAAC,IAAI,CAAC;AACX,gBAAA,SAAS,EAAE,OAAO,CAAC,mBAAmB,CAAC,OAAO,CAAC;gBAC/C,QAAQ;AACT,aAAA,CAAC;QACJ;;QAGA,KAAK,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,OAAO,EAAE;YAC7C,IAAI,CAAC,SAAS,EAAE;AACd,gBAAA,QAAQ,EAAE;YACZ;iBAAO;AACL,gBAAA,SAAS,CAAC;qBACP,KAAK,CAAC,MAAK;;AAEZ,gBAAA,CAAC;qBACA,OAAO,CAAC,MAAK;AACZ,oBAAA,QAAQ,EAAE;AACZ,gBAAA,CAAC,CAAC;YACN;QACF;IACF;AAEA;;AAEG;IACK,OAAO,mBAAmB,CAAC,OAAoB,EAAA;AACrD,QAAA,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,EAAE;QAC1C,MAAM,cAAc,GAAG,UAAU,CAAC,IAAI,CACpC,CAAC,IAAI,CAAC,YAAY,YAAY,IAAI,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,CACrE;QACD,IAAI,cAAc,EAAE;AAClB,YAAA,OAAO,cAAc;QACvB;AACA,QAAA,IAAI,OAAO,CAAC,aAAa,EAAE;YACzB,OAAO,OAAO,CAAC,mBAAmB,CAAC,OAAO,CAAC,aAAa,CAAC;QAC3D;AACA,QAAA,OAAO,IAAI;IACb;IAEQ,kBAAkB,GAAA;AACxB;;;;;;AAMG;QACH,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,GAAG,EAAE;AACzC,QAAA,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC;QACvC,IAAI,CAAC,UAAU,EAAE;IACnB;AACA;;;AAGG;IACO,UAAU,GAAA;;IAEpB;AAEA;;AAEG;IACO,mBAAmB,CAC3B,QAA+F,EAC/F,SAAqE,EAAA;QAIrE,MAAM,IAAI,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE;QACxC,MAAM,KAAK,GAAG,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC;QAEjD,MAAM,KAAK,GAAG,uBAAuB,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;AACpD,QAAA,IAAI,KAAK,CAAC,MAAM,EAAE;YAChB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAkB,CAAC;QAClD;QACA,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;AAC/C,QAAA,IAAI,MAAM,CAAC,MAAM,EAAE;YACjB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAgB,CAAC;QAClD;AAEA,QAAA,IAAI,SAAS,KAAK,SAAS,EAAE;;;;;AAK3B,YAAA,IAAI,WAAW,CAAC,IAA0C,EAAE,SAAS,CAAC;QACxE;AAEA,QAAA,OAAO,KAEN;IACH;AAEA;;AAEG;IACK,6BAA6B,GAAA;QACnC,IAAI,CAAC,0BAA0B,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC;QACzD,IAAI,CAAC,0BAA0B,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC;IAC7D;AAEA;;;;;;;;;AASG;IACO,0BAA0B,CAAC,MAAc,EAAE,MAAmC,EAAA;AACtF,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa;AAG1C;;;;AAIG;QACH,MAAM,UAAU,GAAG,CAAC,KAAa,KAAsB,KAAmC;QAE1F,MAAM,wBAAwB,GAAG,CAAC,MAAc,EAAE,KAAc,EAAE,OAAgB,KAAU;YAC1F,IAAI,CAAC,KAAK,EAAE;gBACV;YACF;AACA,YAAA,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK;YACxB,IAAI,CAAC,KAAK,EAAE;gBACV;YACF;AACA,YAAA,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,MAAM,CAAA,CAAA,EAAI,KAAK,CAAA,CAAE,CAAC,CAAC,EAAE,OAAO,CAAC;AAC9E,QAAA,CAAC;QAED,kBAAkB,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAI;AAC/C,YAAA,wBAAwB,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC;AACjD,YAAA,wBAAwB,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AACjD,QAAA,CAAC,CAAC;AAEF,QAAA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,MAAK;YAC5B,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC;AACnD,QAAA,CAAC,CAAC;IACJ;uGA1ToB,OAAO,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAP,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,OAAO,+nBAwGuB,WAAW,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAxGzC,OAAO,EAAA,UAAA,EAAA,CAAA;kBAH5B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,IAAI,EAAE,EAAE,KAAK,EAAE,sCAAsC,EAAE;AACxD,iBAAA;seAyGmD,WAAW,CAAA,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;MCzJlD,WAAW,CAAA;AACL,IAAA,EAAE;AACF,IAAA,OAAO;AAIP,IAAA,WAAW,GAAG,MAAM,CAA0B,UAAU,CAAC;AACzD,IAAA,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC;;AAGzC,IAAA,kBAAkB;AAET,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAK;AACvC,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,EAAE;AACpB,QAAA,IAAI,OAAO,IAAI,EAAE,EAAE;AACjB,YAAA,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CAA+C;YACvE,MAAM,GAAG,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC;AACpD,YAAA,OAAO,GAAG;QACZ;AACA,QAAA,OAAO,EAAE;IACX,CAAC;gFAAC;AAEe,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;QAC3C,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,EAAuB;QAC/C,IAAI,CAAC,EAAE,EAAE;YACP;QACF;AACA,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE;QAC9B,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAI;YACvC,MAAM,OAAO,GAAG,mBAAmB,CAAC,EAAE,EAAE,OAAO,CAAC;AAChD,YAAA,OAAO,OAAO;AAChB,QAAA,CAAC,CAAC;IACJ,CAAC;oFAAC;AAEF,IAAA,WAAA,CACE,EAAiB,EACjB,OAM+F,EAC/F,OASC,EAAA;AAED,QAAA,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,UAAU,GAAG,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;AACxD,QAAA,MAAM,UAAU,GAAG,OAAO,OAAO,KAAK,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;AAE5E,QAAA,IAAI,CAAC,EAAE,GAAG,KAAyC;AACnD,QAAA,IAAI,CAAC,OAAO,GAAG,UAAU;QAEzB,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;oFAAC;QAChE,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE,OAAO,CAAC;AAEpD,QAAA,IAAI,OAAO,EAAE,gBAAgB,KAAK,KAAK,EAAE;YACvC;QACF;QAEA,kBAAkB,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAI;YACzD,IAAI,QAAQ,EAAE;AACZ,gBAAA,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;oBAC9B,IAAI,CAAC,OAAO,EAAE;wBACZ;oBACF;AACA,oBAAA,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC;gBACtC;YACF;YACA,IAAI,OAAO,EAAE;AACX,gBAAA,KAAK,MAAM,OAAO,IAAI,OAAO,EAAE;oBAC7B,IAAI,CAAC,OAAO,EAAE;wBACZ;oBACF;AACA,oBAAA,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC;gBAC9B;YACF;AACA,YAAA,IAAI,CAAC,kBAAkB,GAAG,OAAO;AACnC,QAAA,CAAC,CAAC;;;AAIF,QAAA,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,MAAK;AAC9B,YAAA,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE;gBAC5B;YACF;AACA,YAAA,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,kBAAkB,EAAE;gBAC7C,IAAI,CAAC,OAAO,EAAE;oBACZ;gBACF;AACA,gBAAA,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC;YACtC;AACF,QAAA,CAAC,CAAC;IACJ;AAEQ,IAAA,cAAc,CAAC,OAAyB,EAAA;AAC9C,QAAA,IAAI,OAAO,CAAC,OAAO,EAAE;YACnB,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC;AACxC,YAAA,IAAI,CAAC,OAAO,CAAC,GAAG,IAAG;gBACjB,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,KAAK,CAAC,GAAuB,CAAC;oBAC1D,OAAO,CAAC,OAAO,GAAG,GAAG,CAAY,IAAI,EAAE;AAC5C,YAAA,CAAC,CAAC;QACJ;AACA,QAAA,IAAI,OAAO,CAAC,WAAW,EAAE;YACvB,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC;AAC5C,YAAA,IAAI,CAAC,OAAO,CAAC,GAAG,IAAG;AACjB,gBAAA,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,YAAY,CACzC,GAAa,EACZ,OAAO,CAAC,WAAW,GAAG,GAAG,CAAY,IAAI,EAAE,CAC7C;AACH,YAAA,CAAC,CAAC;QACJ;AACA,QAAA,IAAI,OAAO,CAAC,QAAQ,EAAE;YACpB,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ;AACnD,kBAAE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;kBAC1C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC;AAC/B,YAAA,cAAc,CAAC,OAAO,CAAC,GAAG,IAAG;AAC3B,gBAAA,IAAI;oBACF,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;gBACnD;AAAE,gBAAA,MAAM;AACN,oBAAA,OAAO,CAAC,IAAI,CAAC,CAAA,qBAAA,EAAwB,GAAG,CAAA,YAAA,CAAc,EAAE,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC;gBACzF;AACF,YAAA,CAAC,CAAC;QACJ;AACA,QAAA,IAAI,OAAO,CAAC,UAAU,EAAE;YACtB,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,SAAS,IAAG;gBACjD,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;gBAC/C,IAAI,CAAC,OAAO,EAAE;oBACZ;gBACF;gBACA,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAc,CAAC;AAC5E,YAAA,CAAC,CAAC;QACJ;IACF;AAEQ,IAAA,sBAAsB,CAAC,OAAyB,EAAA;AACtD,QAAA,IAAI,OAAO,CAAC,OAAO,EAAE;YACnB,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC;AACxC,YAAA,IAAI,CAAC,OAAO,CAAC,GAAG,IAAG;gBACjB,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,KAAK,CAAC,GAAuB,CAAC,GAAG,EAAE;AACpE,YAAA,CAAC,CAAC;QACJ;AACA,QAAA,IAAI,OAAO,CAAC,WAAW,EAAE;YACvB,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC;AAC5C,YAAA,IAAI,CAAC,OAAO,CAAC,GAAG,IAAG;gBACjB,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,eAAe,CAAC,GAAa,CAAC;AAC/D,YAAA,CAAC,CAAC;QACJ;AACA,QAAA,IAAI,OAAO,CAAC,QAAQ,EAAE;YACpB,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ;AACnD,kBAAE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;kBAC1C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC;AAC/B,YAAA,cAAc,CAAC,OAAO,CAAC,GAAG,IAAG;AAC3B,gBAAA,IAAI;oBACF,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC;gBACtD;AAAE,gBAAA,MAAM;AACN,oBAAA,OAAO,CAAC,IAAI,CACV,CAAA,wBAAA,EAA2B,GAAG,CAAA,cAAA,CAAgB,EAC9C,IAAI,CAAC,WAAW,CAAC,aAAa,CAC/B;gBACH;AACF,YAAA,CAAC,CAAC;QACJ;AACA,QAAA,IAAI,OAAO,CAAC,UAAU,EAAE;YACtB,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,SAAS,IAAG;gBACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;gBAChD,IAAI,CAAC,QAAQ,EAAE;oBACb;gBACF;gBACA,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,mBAAmB,CAAC,SAAS,EAAE,QAAe,CAAC;AAChF,YAAA,CAAC,CAAC;QACJ;IACF;AACD;;AC/KD;MAEa,KAAK,CAAA;;IAEA,KAAK,GAAG,KAAK,CAAC,QAAQ;8EAAK;AAC3C;;;AAGG;AACa,IAAA,OAAO,GAAG,KAAK;2FAAuC;AACtE;;;;;AAKG;AACa,IAAA,KAAK,GAAG,KAAK;yFAA2B;AAExD;;;;;AAKG;AACc,IAAA,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE;AAC3C,QAAA,QAAQ,EAAE,IAAI;AACd,QAAA,IAAI,EAAE,IAAI;AACX,KAAA,CAAqC;AAEtC;;;AAGG;IACc,YAAY,GAAG,IAAI,WAAW,CAC7C,IAAI,CAAC,KAAK,EACV,QAAQ,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,IAAK,EAA0C,CAAC,CAC9E;AAED;;;;AAIG;AACc,IAAA,aAAa,GAAG,IAAI,WAAW,CAC9C,IAAI,CAAC,KAAK,EACV,QAAQ,CAAC,OAAO,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,CAAwC,CAAC,EAC3E,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAC5B;;AAGgB,IAAA,SAAS,GAAG,QAAQ,CAAgC,MAAK;AACxE,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE;QACxB,IAAI,CAAC,GAAG,EAAE;AACR,YAAA,OAAO,SAAS;QAClB;QACA,MAAM,QAAQ,GAAI,IAAI,CAAC,KAAK,EAAgC,CAAC,EAAE,IAElD;AACb,QAAA,OAAO,QAAQ,GAAG,GAAa,CAAC;IAClC,CAAC;kFAAC;AAEF,IAAA,WAAA,GAAA;AACE,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;QACvB,IAAI,CAAC,IAAI,EAAE;;;;;YAKT,IAAI,SAAS,EAAE,EAAE;gBACf,MAAM,CAAC,MAAK;AACV,oBAAA,IAAI,IAAI,CAAC,KAAK,EAAE,EAAE;wBAChB,OAAO,CAAC,IAAI,CACV,4EAA4E;AAC1E,4BAAA,8EAA8E,CACjF;oBACH;AACF,gBAAA,CAAC,CAAC;YACJ;YACA;QACF;;;;;;;QAOA,MAAM,CAAC,MAAK;YACV,mBAAmB,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;AAChD,QAAA,CAAC,CAAC;IACJ;uGAvFW,KAAK,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAL,KAAK,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,SAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAL,KAAK,EAAA,UAAA,EAAA,CAAA;kBADjB,SAAS;mBAAC,EAAE,QAAQ,EAAE,SAAS,EAAE;;;AChB5B,MAAgB,gBACpB,SAAQ,OAAU,CAAA;AAGlB;;AAEG;IACa,KAAK,GAAG,KAAK,CAAgB,IAAI;8EAAC;AAClD;;;AAGG;IACa,UAAU,GAAG,KAAK,CAAgB,IAAI;mFAAC;AACvD;;;AAGG;AACa,IAAA,OAAO,GAAG,KAAK,CAAS,iBAAiB,EAAE;gFAAC;AAC5D;;;AAGG;IACa,OAAO,GAAG,KAAK,CAAC,KAAK,+EAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;AACvE;;AAEG;IACa,KAAK,GAAG,KAAK,CAAI,SAAc;8EAAC;AAChD;;AAEG;IACa,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;IAExD,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;IAExD,OAAO,GAAG,KAAK,CAAC,KAAK;gFAAC;IAEtB,KAAK,GAAG,KAAK,CAAC,KAAK,6EAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;uGApCjD,gBAAgB,EAAA,IAAA,EAAA,IAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAhB,gBAAgB,EAAA,YAAA,EAAA,IAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,KAAA,EAAA,aAAA,EAAA,OAAA,EAAA,eAAA,EAAA,EAAA,eAAA,EAAA,IAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAhB,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBADrC;;;ACRD;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"ngneers-controls-base.mjs","sources":["../../src/base/ngn-instance.ts","../../src/base/base.ts","../../src/base/passthrough/pt-engine.ts","../../src/base/passthrough/pt.ts","../../src/base/value-control-base.ts","../../src/base/ngneers-controls-base.ts"],"sourcesContent":["import { afterNextRender, DestroyRef, inject, signal, type Signal, Type } from '@angular/core';\n\nimport type { AnyNgnBase, FullAnyNgnBase } from './base';\n\nconst NGN_INSTANCE_KEY = '__ngneers_control_instance__';\n\nfunction elementWithInstance(\n element: HTMLElement\n): HTMLElement & { [NGN_INSTANCE_KEY]?: AnyNgnBase } {\n return element as HTMLElement & { [NGN_INSTANCE_KEY]?: FullAnyNgnBase };\n}\n\nexport function setNgnInstance(element: HTMLElement, instance: AnyNgnBase): void {\n elementWithInstance(element)[NGN_INSTANCE_KEY] = instance;\n inject(DestroyRef).onDestroy(() => {\n delete elementWithInstance(element)[NGN_INSTANCE_KEY];\n });\n}\n\nexport function getNgnInstance(element: HTMLElement): FullAnyNgnBase {\n return elementWithInstance(element)[NGN_INSTANCE_KEY] as FullAnyNgnBase;\n}\n\nexport function getNearestNgnInstance<T extends Type<Omit<AnyNgnBase, 'kind'>>>(\n element: HTMLElement,\n kind?: T\n): InstanceType<T> | null {\n let current: HTMLElement | null = element;\n while (current) {\n const instance = elementWithInstance(current)[NGN_INSTANCE_KEY] as FullAnyNgnBase | undefined;\n if (instance && (!kind || instance instanceof kind)) {\n return instance as InstanceType<T>;\n }\n current = current.parentElement;\n }\n return null;\n}\n\nexport function getNearestNgnInstanceSig<T extends Type<AnyNgnBase>>(\n element: HTMLElement,\n kind?: T\n): Signal<InstanceType<T> | null> {\n const sig = signal<InstanceType<T> | null>(null);\n afterNextRender(() => {\n sig.set(getNearestNgnInstance(element, kind));\n });\n return sig;\n}\n","import {\n afterNextRender,\n booleanAttribute,\n computed,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n forwardRef,\n inject,\n InjectionToken,\n Injector,\n input,\n type InputSignal,\n type Provider,\n signal,\n type Signal,\n Type,\n viewChildren,\n} from '@angular/core';\nimport {\n type ControlTemplateInfo,\n injectThemeTemplate,\n injectThemeControlKinds,\n injectThemeControlDefaults,\n injectThemeColors,\n type AppliedThemeClassCfg,\n Platform,\n} from '@ngneers/controls/api/ng';\nimport { toggleClass } from '@ngneers/controls/utils';\nimport { effectWithPrevious, setInputSignalValue } from '@ngneers/controls/utils-ng';\n\nimport { setNgnInstance } from './ngn-instance';\nimport { type NgnPassthrough, NgnPtEngine } from './passthrough';\n\nimport type { CustomColor, CustomKind } from '@ngneers/controls-custom-types';\nimport type { ControlTemplate } from '@ngneers/controls-themes';\nimport type { ControlName, ThemeTemplate } from '@ngneers/controls-themes/templates';\n\nexport const NGN_CONTROL = new InjectionToken<NgnBase<never>>('NGN_CONTROL');\n\n// eslint-disable-next-line typescript/no-explicit-any\nexport type AnyNgnBase = NgnBaseSafe<any>;\nexport type NgnBaseSafe<T extends ControlName | null> = Omit<\n NgnBase<T>,\n 'kind' | 'appliedKind' | 'pt'\n>;\n\n/* eslint-disable typescript/no-explicit-any */\nexport type FullAnyNgnBase = Omit<NgnBase<any>, 'kind' | 'appliedKind' | 'pt'> & {\n kind: InputSignal<CustomKind<any> | undefined>;\n appliedKind: InputSignal<CustomKind<any> | undefined>;\n pt: InputSignal<NgnPassthrough<any> | undefined>;\n};\n/* eslint-enable typescript/no-explicit-any */\n\n/**\n * @internal\n * Provides the control itself for dependency injection.\n * @param control - The control class to provide.\n * @returns A provider for the control itself.\n */\nexport function provideSelf(control: Type<unknown>): Provider {\n return { provide: NGN_CONTROL, useExisting: forwardRef(() => control) };\n}\n\n@Directive({\n host: { class: 'ngn-control ngn-control-initializing' },\n})\nexport abstract class NgnBase<T extends ControlName | null> {\n protected abstract theme: ControlTemplateInfo<never> | null;\n\n private readonly _defaultKind = signal<CustomKind<T> | undefined>(undefined);\n private readonly _defaultColor = signal<CustomColor | undefined>(undefined);\n private readonly _kindOverride = signal<CustomKind<T> | undefined>(undefined);\n\n /**\n * The element reference for the host element.\n */\n public readonly element = inject<ElementRef<HTMLElement>>(ElementRef);\n /**\n * The injector for the component.\n */\n public readonly injector = inject(Injector);\n /**\n * If true, the control will not apply any theme styles.\n * The base styles of the control will still be applied.\n * @default false\n */\n public readonly unstyled = input(false, { transform: booleanAttribute });\n\n /**\n * Some controls support custom kinds for styling purposes.\n * The available kinds depend on the control and the theme used.\n *\n * TODO: link to custom types documentation\n */\n public readonly kind = input<CustomKind<T> | undefined>(undefined as never);\n public readonly color = input<CustomColor | undefined>(undefined as never);\n\n public readonly appliedKind = computed<CustomKind<T> | undefined>(\n () => this._kindOverride() ?? this.kind() ?? this._defaultKind()\n );\n public readonly appliedColor = computed<CustomColor | undefined>(\n () => this.color() ?? this._defaultColor()\n );\n\n /**\n * Custom passthrough attributes to apply to the control's theme classes and its dependencies.\n * This allows for fine-grained customization of attributes, styles and more.\n */\n public readonly pt = input<T extends string ? NgnPassthrough<T> : never>();\n\n /**\n * Marks a control as the primary value control of a surrounding field\n * (e.g. `ngn-input-field`). Fields resolve their projected control by\n * filtering for this flag, so auxiliary controls placed inside the field\n * (buttons, icons, spin buttons, …) never shadow the actual input.\n * Overridden with `true` by input, mask-input, calendar, select, ….\n */\n public readonly isFieldControl: boolean = false;\n\n /**\n * Whether the control holds no user-entered content. Field controls override\n * this from their eager entry state — not {@link isFieldControl}'s `value`,\n * which can lag behind typing until the entry is valid (mask-input, calendar)\n * — so a wrapping `ngn-input-field` can float its label reliably.\n */\n public readonly empty: Signal<boolean> = signal(false);\n\n /**\n * Hook for placing focus/selection from a pointer event that originated in the\n * surrounding field (or the control itself). The default does nothing and\n * returns `false`, signalling the surrounding field should fall back to its\n * primitive focusing. Controls that own internal focus placement (e.g.\n * mask-input) override this, act on the pointer location, and return `true`.\n */\n public focusFromPointer(_event: MouseEvent): boolean {\n return false;\n }\n\n /**\n * Hook for stepping the control's value (e.g. from `ngn-spin-buttons` or\n * other external steppers). The default does nothing and returns `false`.\n * Controls with a steppable value (e.g. number-input) override this, apply\n * the step and return `true`.\n * @param _direction - `1` to increment, `-1` to decrement.\n * @param _big - Whether to apply the control's big step (e.g. Shift+Arrow).\n */\n public stepValue(_direction: 1 | -1, _big = false): boolean {\n return false;\n }\n\n /**\n * Hook telling external steppers (e.g. `ngn-spin-buttons`) whether the value\n * can currently be stepped in the given direction. The default returns\n * `false`; controls overriding {@link stepValue} override this as well\n * (typically `false` at a min/max bound or while disabled/readonly).\n */\n public canStepValue(_direction: 1 | -1): boolean {\n return false;\n }\n\n /**\n * Hook for clearing the control's own value/state (e.g. from a surrounding\n * field's clear button). The default does nothing and returns `false`, so the\n * caller falls back to clearing the underlying DOM input. Controls that manage\n * their own value (e.g. mask-input) override this to reset and return `true`.\n */\n public clearValue(): boolean {\n return false;\n }\n\n /**\n * Temporarily overrides the authored kind without mutating the public input.\n * Intended for derived control states such as validation-driven hints.\n */\n protected setKindOverride(kind: CustomKind<T> | undefined): void {\n this._kindOverride.set(kind);\n }\n\n private readonly _childNgnControls = viewChildren(NGN_CONTROL);\n private readonly _afterLeaveCbs: (() => void)[] = [];\n\n constructor() {\n // `pt` is typed against this control's own `T`, which makes `this`\n // (NgnBase<T>) structurally incompatible with the type-erased AnyNgnBase\n // alias for an unconstrained/generic T. Safe: AnyNgnBase never reads `pt`\n // in a way that depends on the real T at the call site.\n setNgnInstance(this.element.nativeElement, this as unknown as AnyNgnBase);\n this.prepareAfterLeaveHook();\n effect(() => {\n // Propagate unstyled state to direct child controls, does not affect\n // custom user content passed into ng-content or projected templates.\n this._childNgnControls().forEach(child => {\n setInputSignalValue(child.unstyled, this.unstyled());\n });\n });\n\n this.initializeKindAndColorClasses();\n\n if (inject(Platform).isBrowser) {\n // Remove the initializing class after the first render to prevent FOUC.\n afterNextRender(() => {\n this.element.nativeElement.classList.remove('ngn-control-initializing');\n });\n } else {\n // Remove the initializing class immediately on the server to serve a complete initial HTML.\n this.element.nativeElement.classList.remove('ngn-control-initializing');\n }\n }\n\n /**\n * Prepares the after leave hook to be called when the control is destroyed\n * and its leave animation has finished.\n */\n private prepareAfterLeaveHook() {\n inject(DestroyRef).onDestroy(() => {\n if (typeof this.element.nativeElement.getAnimations !== 'function') {\n this.afterLeaveInternal();\n } else {\n NgnBase._enqueueLeaveCheck(this.element.nativeElement, () => this.afterLeaveInternal());\n }\n });\n }\n\n // --- Batched leave animation checking ---\n // Collects all destroyed components in the same frame into one queue,\n // then processes them in a single rAF to avoid layout thrashing from\n // interleaved getAnimations() calls and DOM mutations.\n\n private static _leaveQueue: { element: HTMLElement; callback: () => void }[] = [];\n private static _leaveRafScheduled = false;\n\n private static _enqueueLeaveCheck(element: HTMLElement, callback: () => void): void {\n NgnBase._leaveQueue.push({ element, callback });\n if (!NgnBase._leaveRafScheduled) {\n NgnBase._leaveRafScheduled = true;\n requestAnimationFrame(() => NgnBase._processLeaveQueue());\n }\n }\n\n private static _processLeaveQueue(): void {\n const queue = NgnBase._leaveQueue;\n NgnBase._leaveQueue = [];\n NgnBase._leaveRafScheduled = false;\n\n // Phase 1: Read all animations (batched queries — no interleaved mutations)\n const results: { animation: Animation | null; callback: () => void }[] = [];\n for (const { element, callback } of queue) {\n results.push({\n animation: NgnBase._findLeaveAnimation(element),\n callback,\n });\n }\n\n // Phase 2: Process results (no more style queries needed)\n for (const { animation, callback } of results) {\n if (!animation) {\n callback();\n } else {\n animation.finished\n .catch(() => {\n // ignore errors from animations being cancelled\n })\n .finally(() => {\n callback();\n });\n }\n }\n }\n\n /**\n * Recursively searches for a leave animation on the element and its parents.\n */\n private static _findLeaveAnimation(element: HTMLElement): Animation | null {\n const animations = element.getAnimations();\n const leaveAnimation = animations.find(\n a => a instanceof CSSAnimation && a.animationName.endsWith('-leave')\n );\n if (leaveAnimation) {\n return leaveAnimation;\n }\n if (element.parentElement) {\n return NgnBase._findLeaveAnimation(element.parentElement);\n }\n return null;\n }\n\n private afterLeaveInternal() {\n /**\n * After the control is hidden/removed from the DOM,\n * manually wipe the innerHTML to ensure no detached children remain\n * mapped to this component's LView slots in the browser's memory.\n * This is especially important for controls that use ng-content\n * or dynamically render child components.\n */\n this.element.nativeElement.innerHTML = '';\n this._afterLeaveCbs.forEach(cb => cb());\n this.afterLeave();\n }\n /**\n * Lifecycle hook that is called after the control has left (been removed from) the DOM.\n * Can be overridden by subclasses to perform custom actions after the leave animation.\n */\n protected afterLeave() {\n // Can be overridden by subclasses\n }\n\n /**\n * @internal\n */\n protected injectThemeTemplate<External extends boolean = false>(\n template: External extends true ? ControlTemplate : T extends string ? ThemeTemplate[T] : never,\n hostClass?: null extends T ? never : AppliedThemeClassCfg<T & string>\n ): ControlTemplateInfo<\n External extends true ? ControlTemplate : T extends string ? ThemeTemplate[T] : never\n > {\n const opts = { unstyled: this.unstyled };\n const theme = injectThemeTemplate(template, opts);\n\n const defaults = injectThemeControlDefaults(theme.scope)();\n const kinds = injectThemeControlKinds(theme.scope)();\n if (defaults.kind !== undefined) {\n this._defaultKind.set(defaults.kind as CustomKind<T>);\n } else if (kinds.length) {\n this._defaultKind.set(kinds[0] as CustomKind<T>);\n }\n const colors = injectThemeColors(theme.scope)();\n if (defaults.color !== undefined) {\n this._defaultColor.set(defaults.color as CustomColor);\n } else if (colors.length) {\n this._defaultColor.set(colors[0] as CustomColor);\n }\n\n if (hostClass !== undefined) {\n // See constructor comment: `this` (NgnBase<T>) isn't structurally assignable\n // to NgnBaseSafe<T & string> for a generic T because `pt`'s type still\n // depends on T. Narrow the erasure to this control's own T & string, which\n // matches what NgnPtEngine actually needs here.\n new NgnPtEngine(this as unknown as NgnBaseSafe<T & string>, hostClass);\n }\n\n return theme as ControlTemplateInfo<\n External extends true ? ControlTemplate : T extends string ? ThemeTemplate[T] : never\n >;\n }\n\n /**\n * Toggles the kind and color theme classes based on the current values of the kind and color inputs.\n */\n private initializeKindAndColorClasses() {\n this.initializeAutoThemeClasses('kind', this.appliedKind);\n this.initializeAutoThemeClasses('color', this.appliedColor);\n }\n\n /**\n * Initializes automatic theme class toggling for a given prefix based on the provided string signal.\n *\n * ⚠️ Caution: This method assumes that the control's theme supports classes with the given prefix.\n *\n * ⚠️ Caution: Make sure the signal provides only string or nullish values.\n *\n * @param prefix The prefix for the theme class (e.g., 'kind' or 'color').\n * @param signal The signal that provides the current string value for the theme class.\n */\n protected initializeAutoThemeClasses(prefix: string, signal: Signal<unknown | undefined>) {\n const element = this.element.nativeElement;\n\n type ThemeClassToken = Parameters<ControlTemplateInfo<never>['class']>[0];\n /**\n * We can't know here whether the control has any kind or color classes,\n * so we cast explicitly to ThemeClassToken. In practice, controls without\n * kind or color classes will simply not toggle any classes as the input type does not allow it.\n */\n const classToken = (value: string): ThemeClassToken => value as unknown as ThemeClassToken;\n\n const togglePrefixedThemeClass = (prefix: string, value: unknown, enabled: boolean): void => {\n if (!value) {\n return;\n }\n const theme = this.theme;\n if (!theme) {\n return;\n }\n toggleClass(element, theme.class(classToken(`${prefix}-${value}`)), enabled);\n };\n\n effectWithPrevious(signal, (current, previous) => {\n togglePrefixedThemeClass(prefix, previous, false);\n togglePrefixedThemeClass(prefix, current, true);\n });\n\n this._afterLeaveCbs.push(() => {\n togglePrefixedThemeClass(prefix, signal(), false);\n });\n }\n}\n","import { computed, DestroyRef, ElementRef, inject, type Signal, signal } from '@angular/core';\nimport {\n type ControlTemplateInfo,\n type AppliedThemeClassCfg,\n getAppliedClasses,\n} from '@ngneers/controls/api/ng';\nimport { getPropertyIfExists, objectKeys } from '@ngneers/controls/utils';\nimport { classSignal, effectWithPrevious } from '@ngneers/controls/utils-ng';\n\nimport type { AnyNgnPassthrough, PassthroughValue } from './types';\nimport type { NgnBase, NgnBaseSafe } from '../base';\nimport type { ControlName, ControlTemplate } from '@ngneers/controls-themes';\n\n/** Writable, string-valued properties of `CSSStyleDeclaration` (the camelCase CSS properties). */\ntype WritableStyleKey = Extract<keyof CSSStyleDeclaration, string> &\n {\n [K in keyof CSSStyleDeclaration]: CSSStyleDeclaration[K] extends string ? K : never;\n }[keyof CSSStyleDeclaration];\n\nexport class NgnPtEngine<T extends NgnBaseSafe<Name>, Name extends ControlName> {\n private readonly pt: Signal<NgnBase<Name>>;\n private readonly ptClass: Signal<\n AppliedThemeClassCfg<T extends NgnBaseSafe<infer A> ? (A extends null ? never : A) : never>\n >;\n\n private readonly _elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly _destroyRef = inject(DestroyRef);\n\n /** The passthrough values currently applied to the element, for teardown on destroy. */\n private _currentAppliedPts: ReturnType<NgnPtEngine<T, Name>['_appliedPts']>;\n\n private readonly classes = computed(() => {\n const pt = this.pt();\n if ('theme' in pt) {\n const theme = pt['theme'] as ControlTemplateInfo<ControlTemplate<Name>>;\n const res = getAppliedClasses(this.ptClass(), theme);\n return res;\n }\n return [];\n });\n\n private readonly _appliedPts = computed(() => {\n const pt = this.pt()?.pt() as AnyNgnPassthrough;\n if (!pt) {\n return;\n }\n const classes = this.classes();\n return classes.map(({ name: ptClass }) => {\n const classPt = getPropertyIfExists(pt, ptClass);\n return classPt;\n });\n });\n\n constructor(\n pt: Signal<T> | T,\n ptClass:\n | Signal<\n AppliedThemeClassCfg<\n T extends NgnBaseSafe<infer A> ? (A extends null ? never : A) : never\n >\n >\n | AppliedThemeClassCfg<T extends NgnBaseSafe<infer A> ? (A extends null ? never : A) : never>,\n options?: {\n /**\n * When `false`, the engine only toggles the resolved theme class(es) on the\n * element and does NOT apply the control's `pt` slice (styles/attributes/\n * classes/listeners) for those classes. Used for dependency-slot markers,\n * where the forwarded passthrough is applied through the nested control's\n * own engine rather than flatly on the host. Defaults to `true`.\n */\n applyPassthrough?: boolean;\n }\n ) {\n const sigPt = typeof pt === 'function' ? pt : signal(pt);\n const sigPtClass = typeof ptClass === 'function' ? ptClass : signal(ptClass);\n\n this.pt = sigPt as unknown as Signal<NgnBase<Name>>;\n this.ptClass = sigPtClass;\n\n const classes = computed(() => this.classes().map(c => c.class));\n classSignal(this._elementRef.nativeElement, classes);\n\n if (options?.applyPassthrough === false) {\n return;\n }\n\n effectWithPrevious(this._appliedPts, (current, previous) => {\n if (previous) {\n for (const classPt of previous) {\n if (!classPt) {\n continue;\n }\n this.removePreviousPtValues(classPt);\n }\n }\n if (current) {\n for (const classPt of current) {\n if (!classPt) {\n continue;\n }\n this.setNewPtValues(classPt);\n }\n }\n this._currentAppliedPts = current;\n });\n\n // Detach applied passthrough (notably event listeners) when the element is\n // destroyed, so nothing leaks past the control's lifetime.\n this._destroyRef.onDestroy(() => {\n if (!this._currentAppliedPts) {\n return;\n }\n for (const classPt of this._currentAppliedPts) {\n if (!classPt) {\n continue;\n }\n this.removePreviousPtValues(classPt);\n }\n });\n }\n\n private setNewPtValues(classPt: PassthroughValue) {\n if (classPt.$styles) {\n const keys = objectKeys(classPt.$styles);\n keys.forEach(key => {\n this._elementRef.nativeElement.style[key as WritableStyleKey] =\n (classPt.$styles?.[key] as string) || '';\n });\n }\n if (classPt.$attributes) {\n const keys = objectKeys(classPt.$attributes);\n keys.forEach(key => {\n this._elementRef.nativeElement.setAttribute(\n key as string,\n (classPt.$attributes?.[key] as string) || ''\n );\n });\n }\n if (classPt.$classes) {\n const arrayOfClasses = Array.isArray(classPt.$classes)\n ? classPt.$classes.flatMap(c => c.split(' '))\n : classPt.$classes.split(' ');\n arrayOfClasses.forEach(cls => {\n try {\n this._elementRef.nativeElement.classList.add(cls);\n } catch {\n console.warn(`Could not add class '${cls}' to element`, this._elementRef.nativeElement);\n }\n });\n }\n if (classPt.$listeners) {\n objectKeys(classPt.$listeners).forEach(eventName => {\n const handler = classPt.$listeners?.[eventName];\n if (!handler) {\n return;\n }\n this._elementRef.nativeElement.addEventListener(eventName, handler as any);\n });\n }\n }\n\n private removePreviousPtValues(classPt: PassthroughValue) {\n if (classPt.$styles) {\n const keys = objectKeys(classPt.$styles);\n keys.forEach(key => {\n this._elementRef.nativeElement.style[key as WritableStyleKey] = '';\n });\n }\n if (classPt.$attributes) {\n const keys = objectKeys(classPt.$attributes);\n keys.forEach(key => {\n this._elementRef.nativeElement.removeAttribute(key as string);\n });\n }\n if (classPt.$classes) {\n const arrayOfClasses = Array.isArray(classPt.$classes)\n ? classPt.$classes.flatMap(c => c.split(' '))\n : classPt.$classes.split(' ');\n arrayOfClasses.forEach(cls => {\n try {\n this._elementRef.nativeElement.classList.remove(cls);\n } catch {\n console.warn(\n `Could not remove class '${cls}' from element`,\n this._elementRef.nativeElement\n );\n }\n });\n }\n if (classPt.$listeners) {\n objectKeys(classPt.$listeners).forEach(eventName => {\n const listener = classPt.$listeners?.[eventName];\n if (!listener) {\n return;\n }\n this._elementRef.nativeElement.removeEventListener(eventName, listener as any);\n });\n }\n }\n}\n","import { computed, Directive, effect, inject, input, isDevMode } from '@angular/core';\nimport { setInputSignalValue } from '@ngneers/controls/utils-ng';\n\nimport { NGN_CONTROL } from '../base';\nimport { NgnPtEngine } from './pt-engine';\n\nimport type { AnyNgnPassthrough } from './types';\nimport type { FullAnyNgnBase, NgnBaseSafe } from '../base';\nimport type { AppliedThemeClassCfg } from '@ngneers/controls/api/ng';\nimport type { ControlName, ControlTemplate, ThemeTemplate } from '@ngneers/controls-themes';\n\n/** The control name backing a parent `NgnBaseSafe`, or `never` for a nameless base. */\ntype ParentName<T> = T extends NgnBaseSafe<infer A> ? (A extends null ? never : A) : never;\n\n/**\n * Union of the NON-projected dependency-slot class tokens declared on a control's\n * theme template — i.e. the valid `[ptDep]` targets for parent control `Name`.\n * Projected slots are excluded — they have no host element to bind `[ptDep]` to,\n * so accepting them would type-check a no-op.\n */\nexport type DepClass<Name extends ControlName> = ThemeTemplate[Name] extends ControlTemplate\n ? Exclude<ThemeTemplate[Name]['dependencies'][number], { projected: true }>['class']\n : never;\n\n// Internal passthrough directive; intentionally uses the non-prefixed `ptInt` selector.\n@Directive({ selector: '[ptInt]' })\nexport class NgnPt<T extends NgnBaseSafe<Name>, Name extends ControlName> {\n /** The parent control whose theme/passthrough this element pulls from. */\n public readonly ptInt = input.required<T>();\n /**\n * Parent-scope class token(s) applied to this element, along with the parent's\n * `pt` slice for those classes. Use for flat theme parts of the parent.\n */\n public readonly ptClass = input<AppliedThemeClassCfg<ParentName<T>>>();\n /**\n * Dependency-slot class on the parent. Applies the parent's marker class\n * (`{parentScope}-{ptDep}`) to this element and forwards the parent's\n * `pt[ptDep]` slice into the nested control that lives on this element, so the\n * nested control resolves it against its own theme.\n */\n public readonly ptDep = input<DepClass<ParentName<T>>>();\n\n /**\n * The nested control hosted on THIS element (present when `ptDep` targets a\n * control). `self: true` is essential: without it the injection climbs to an\n * ancestor control (e.g. the parent that owns `[ptInt]`), and the forwarding\n * effect would then overwrite the ancestor's `pt` instead of the child's.\n */\n private readonly _self = inject(NGN_CONTROL, {\n optional: true,\n self: true,\n }) as unknown as FullAnyNgnBase | null;\n\n /**\n * Flat class engine for `ptClass`: applies the parent's scope class(es) and the\n * matching `pt` slice to this element. A missing `ptClass` resolves to a no-op.\n */\n private readonly _classEngine = new NgnPtEngine(\n this.ptInt,\n computed(() => this.ptClass() ?? ({} as AppliedThemeClassCfg<ParentName<T>>))\n );\n\n /**\n * Marker engine for `ptDep`: applies ONLY the parent's `{parentScope}-{ptDep}`\n * class to this element (`applyPassthrough: false`). The forwarded slice is\n * applied separately, through the nested control's own engine.\n */\n private readonly _markerEngine = new NgnPtEngine(\n this.ptInt,\n computed(() => (this.ptDep() ?? {}) as AppliedThemeClassCfg<ParentName<T>>),\n { applyPassthrough: false }\n );\n\n /** The parent's `pt` slice for the current `ptDep` slot, or `undefined`. */\n private readonly _depSlice = computed<AnyNgnPassthrough | undefined>(() => {\n const dep = this.ptDep();\n if (!dep) {\n return undefined;\n }\n const parentPt = (this.ptInt() as unknown as FullAnyNgnBase).pt?.() as\n | Record<string, AnyNgnPassthrough>\n | undefined;\n return parentPt?.[dep as string];\n });\n\n constructor() {\n const self = this._self;\n if (!self) {\n // No nested control on this element (e.g. `ptDep` on a plain element): only\n // the marker class applies; there is no child theme to forward the slice to.\n // Warn (dev only) if a `ptDep` is actually set — read it in an effect, since\n // inputs are not yet resolved in the constructor.\n if (isDevMode()) {\n effect(() => {\n if (this.ptDep()) {\n console.warn(\n '[ptDep] is set but no nested control was found on this element; the parent' +\n \" dependency slice can't be forwarded. Did you forget to host a control here?\"\n );\n }\n });\n }\n return;\n }\n // Forward the parent's dependency slice into the nested control's own `pt`\n // input, so the child's existing engine(s) resolve it against its theme.\n // Reactive to parent `pt` changes; torn down with the directive/child. Writes\n // on every run (even `undefined`) so a slice that disappears (e.g. `ptDep`\n // cleared) clears the child's `pt` instead of leaving it stale; the child's\n // own engine already treats a falsy `pt` as a no-op.\n effect(() => {\n setInputSignalValue(self.pt, this._depSlice());\n });\n }\n}\n","import { booleanAttribute, computed, Directive, input, model, output } from '@angular/core';\nimport { generateElementId } from '@ngneers/controls/utils-ng';\n\nimport { NgnBase } from './base';\n\nimport type { FormValueControl } from '@angular/forms/signals';\nimport type { ControlName } from '@ngneers/controls-themes/templates';\n\n/**\n * When a control surfaces its invalid styling (border / `aria-invalid`):\n * - `touched` — after the user has blurred the control (default).\n * - `dirty` — once the value has changed.\n * - `immediate` — as soon as it is invalid (e.g. explicit `[invalid]`).\n * - `never` — never style invalid.\n */\nexport type NgnInvalidTrigger = 'touched' | 'dirty' | 'immediate' | 'never';\n\n/**\n * Gates a raw invalid flag by an {@link NgnInvalidTrigger} against the given\n * interaction state. Shared by {@link ValueControlBase} and `NgnInput`.\n */\nexport function resolveInvalidState(\n invalid: boolean,\n trigger: NgnInvalidTrigger,\n touched: boolean,\n dirty: boolean\n): boolean {\n if (!invalid) {\n return false;\n }\n switch (trigger) {\n case 'immediate':\n return true;\n case 'never':\n return false;\n case 'dirty':\n return dirty;\n case 'touched':\n default:\n return touched;\n }\n}\n\n@Directive()\nexport abstract class ValueControlBase<C extends ControlName, T>\n extends NgnBase<C>\n implements FormValueControl<T>\n{\n /**\n * The label for the control.\n */\n public readonly label = input<string | null>(null);\n /**\n * Sets the `aria-labelledby` attribute on the control.\n * @default null\n */\n public readonly labelledBy = input<string | null>(null);\n /**\n * The ID for the control\n * @default generateElementId()\n */\n public readonly inputId = input<string>(generateElementId());\n /**\n * The raw invalid flag. A bound signal-forms field writes it in from the\n * field's validity (`FormUiControl` `invalid` input); the app may also set it\n * explicitly. Whether it actually *shows* is gated by {@link invalidOn} — map\n * the theme's invalid part (and any `aria-invalid`) to {@link invalidState},\n * not this.\n * @default false\n */\n public readonly invalid = input(false, { transform: booleanAttribute });\n\n /**\n * When the control surfaces its invalid styling. The control owns this timing\n * (independent of `ngnErrors`, which governs only the error *message*).\n * @default touched\n */\n public readonly invalidOn = input<NgnInvalidTrigger>('touched');\n\n /**\n * The invalid state the theme should render: {@link invalid} gated by\n * {@link invalidOn} against {@link touched} / {@link dirty}. Controls map their\n * theme `invalid` part (and any `aria-invalid`) to this.\n */\n protected readonly invalidState = computed(() =>\n resolveInvalidState(this.invalid(), this.invalidOn(), this.touched(), this.dirty())\n );\n /**\n * The value of the control.\n */\n public readonly value = model<T>(undefined as T);\n /**\n * Set the disabled state of the control.\n */\n public readonly disabled = input(false, { transform: booleanAttribute });\n\n public readonly readonly = input(false, { transform: booleanAttribute });\n\n /**\n * The touched state. A bound signal-forms field writes it in via the\n * `FormUiControl` `touched` input; the control writes it out through\n * {@link markTouched} on blur.\n */\n public readonly touched = model(false);\n\n public readonly dirty = input(false, { transform: booleanAttribute });\n\n /**\n * Emits when focus leaves the control (the `FormUiControl` `touch` contract).\n * The `Field` directive listens to this to mark the bound field touched — it's\n * the only channel signal forms observes for blur, so plain `touched` writes\n * don't reach the field.\n */\n public readonly touch = output<void>();\n\n /**\n * Marks the control touched: flips {@link touched} for local / no-form\n * consumers (e.g. `ngnErrors`) and emits {@link touch} so a bound signal-forms\n * field is marked touched too. Each control calls this from its own blur/close\n * logic — composite controls with an out-of-DOM overlay (select, calendar)\n * call it from their popover-aware blur, so opening the overlay isn't mistaken\n * for a blur.\n */\n protected markTouched(): void {\n this.touched.set(true);\n this.touch.emit();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -63,7 +63,7 @@ class CalendarTime {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CalendarTime, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
66
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: CalendarTime, isStandalone: true, selector: "ngn-calendar-time", inputs: { component: { classPropertyName: "component", publicName: "component", isSignal: true, isRequired: true, transformFunction: null }, currentValue: { classPropertyName: "currentValue", publicName: "currentValue", isSignal: true, isRequired: true, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { timeChange: "timeChange" }, ngImport: i0, template: "<div>\n @if (isTouchDevice) {\n <ngn-input-field>\n <input\n type=\"time\"\n ngnInput\n [step]=\"showSeconds() ? 1 : 60\"\n [value]=\"value()\"\n (valueChange)=\"onValueChange($event || '')\"\n />\n </ngn-input-field>\n } @else {\n <ngn-input-field>\n <ngn-mask-input\n [mask]=\"mask()\"\n [value]=\"value()\"\n (valueChange)=\"onValueChange($event ?? '')\"\n />\n </ngn-input-field>\n }\n</div>\n", dependencies: [{ kind: "directive", type: NgnInput, selector: "input[ngnInput], textarea[ngnInput]", inputs: ["invalid", "value"], outputs: ["valueChange"], exportAs: ["ngnInput"] }, { kind: "component", type: NgnMaskInput, selector: "ngn-mask-input", inputs: ["mask"] }, { kind: "component", type: NgnInputField, selector: "ngn-input-field", inputs: ["label", "labelledBy", "labelKind", "inputId", "showClearButton", "iconClearButton", "tabindex", "invalid", "readonly", "disabled"] }] });
|
|
66
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: CalendarTime, isStandalone: true, selector: "ngn-calendar-time", inputs: { component: { classPropertyName: "component", publicName: "component", isSignal: true, isRequired: true, transformFunction: null }, currentValue: { classPropertyName: "currentValue", publicName: "currentValue", isSignal: true, isRequired: true, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { timeChange: "timeChange" }, ngImport: i0, template: "<div>\n @if (isTouchDevice) {\n <ngn-input-field>\n <input\n type=\"time\"\n ngnInput\n [step]=\"showSeconds() ? 1 : 60\"\n [value]=\"value()\"\n (valueChange)=\"onValueChange($event || '')\"\n />\n </ngn-input-field>\n } @else {\n <ngn-input-field>\n <ngn-mask-input\n [mask]=\"mask()\"\n [value]=\"value()\"\n (valueChange)=\"onValueChange($event ?? '')\"\n />\n </ngn-input-field>\n }\n</div>\n", dependencies: [{ kind: "directive", type: NgnInput, selector: "input[ngnInput], textarea[ngnInput]", inputs: ["invalid", "invalidOn", "touched", "value"], outputs: ["touchedChange", "valueChange", "touch"], exportAs: ["ngnInput"] }, { kind: "component", type: NgnMaskInput, selector: "ngn-mask-input", inputs: ["mask"] }, { kind: "component", type: NgnInputField, selector: "ngn-input-field", inputs: ["label", "labelledBy", "labelKind", "inputId", "showClearButton", "iconClearButton", "tabindex", "invalid", "readonly", "disabled"] }] });
|
|
67
67
|
}
|
|
68
68
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CalendarTime, decorators: [{
|
|
69
69
|
type: Component,
|
|
@@ -71,4 +71,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
|
|
|
71
71
|
}], propDecorators: { component: [{ type: i0.Input, args: [{ isSignal: true, alias: "component", required: true }] }], currentValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentValue", required: true }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: true }] }], timeChange: [{ type: i0.Output, args: ["timeChange"] }] } });
|
|
72
72
|
|
|
73
73
|
export { CalendarTime };
|
|
74
|
-
//# sourceMappingURL=ngneers-controls-calendar-time-
|
|
74
|
+
//# sourceMappingURL=ngneers-controls-calendar-time-paM6WVpV.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngneers-controls-calendar-time-
|
|
1
|
+
{"version":3,"file":"ngneers-controls-calendar-time-paM6WVpV.mjs","sources":["../../src/calendar/time/time.ts","../../src/calendar/time/time.html"],"sourcesContent":["import { Component, computed, inject, input, output } from '@angular/core';\nimport { Platform } from '@ngneers/controls/api/ng';\nimport { I18n } from '@ngneers/controls/i18n';\nimport { NgnInput } from '@ngneers/controls/input';\nimport { NgnInputField } from '@ngneers/controls/input-field';\nimport { DATE_TIME_MASKS, NgnMaskInput } from '@ngneers/controls/mask-input';\n\nimport type { NgnBaseSafe } from '@ngneers/controls/base';\n\n@Component({\n selector: 'ngn-calendar-time',\n templateUrl: './time.html',\n imports: [NgnInput, NgnMaskInput, NgnInputField],\n})\nexport class CalendarTime {\n protected readonly i18n = inject(I18n).translations;\n protected readonly isTouchDevice = inject(Platform).isTouchDevice();\n\n public readonly component = input.required<NgnBaseSafe<'calendar'>>();\n public readonly currentValue = input.required<Date | null>();\n public readonly showSeconds = input.required<boolean>();\n public readonly timeChange = output<Date | null>();\n public readonly mask = computed(() =>\n this.showSeconds() ? DATE_TIME_MASKS.time : DATE_TIME_MASKS.timeShort\n );\n\n protected readonly value = computed(() => {\n const currentValue = this.currentValue();\n if (!currentValue) return null;\n\n function padZero(num: number): string {\n return num < 10 ? `0${num}` : `${num}`;\n }\n\n const hours = padZero(currentValue.getHours());\n const minutes = padZero(currentValue.getMinutes());\n const seconds = padZero(currentValue.getSeconds());\n\n return this.showSeconds() ? `${hours}:${minutes}:${seconds}` : `${hours}:${minutes}`;\n });\n\n protected onValueChange(value: string) {\n if (!value) {\n this.timeChange.emit(null);\n return;\n }\n\n const [hours, minutes, seconds] = value.split(':').map(Number);\n\n if (hours === undefined || minutes === undefined) {\n throw new Error(`Invalid time value: ${value}`);\n }\n\n if (isNaN(hours)) {\n this.timeChange.emit(null);\n return;\n }\n\n const fixedMinutes = isNaN(minutes) ? 0 : minutes;\n\n const currentDate = this.currentValue();\n const newDate = new Date(currentDate || new Date());\n newDate.setHours(hours);\n newDate.setMinutes(fixedMinutes);\n\n if (this.showSeconds()) {\n const fixedSeconds = isNaN(seconds ?? 0) ? 0 : (seconds ?? 0);\n newDate.setSeconds(fixedSeconds);\n } else {\n newDate.setSeconds(0);\n }\n\n if (\n newDate.getMinutes() !== currentDate?.getMinutes() ||\n newDate.getHours() !== currentDate?.getHours() ||\n (this.showSeconds() && newDate.getSeconds() !== currentDate?.getSeconds())\n ) {\n this.timeChange.emit(newDate);\n }\n }\n}\n","<div>\n @if (isTouchDevice) {\n <ngn-input-field>\n <input\n type=\"time\"\n ngnInput\n [step]=\"showSeconds() ? 1 : 60\"\n [value]=\"value()\"\n (valueChange)=\"onValueChange($event || '')\"\n />\n </ngn-input-field>\n } @else {\n <ngn-input-field>\n <ngn-mask-input\n [mask]=\"mask()\"\n [value]=\"value()\"\n (valueChange)=\"onValueChange($event ?? '')\"\n />\n </ngn-input-field>\n }\n</div>\n"],"names":[],"mappings":"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"}
|
|
@@ -521,6 +521,10 @@ class NgnCalendar extends CalendarTemplates {
|
|
|
521
521
|
i18n = inject(I18n).translations;
|
|
522
522
|
isFieldControl = true;
|
|
523
523
|
theme = this.injectThemeTemplate(calendarControlTemplate);
|
|
524
|
+
// Mask emits emptiness per keystroke; `value` only lands once the date is
|
|
525
|
+
// complete, so float detection must read the mask, not `value`.
|
|
526
|
+
empty = computed(() => this._mask()?.empty() ?? this.value() == null, /* @ts-ignore */
|
|
527
|
+
...(ngDevMode ? [{ debugName: "empty" }] : /* istanbul ignore next */ []));
|
|
524
528
|
get anchorElement() {
|
|
525
529
|
return (this.element.nativeElement.closest('ngn-input-field') ??
|
|
526
530
|
this.element.nativeElement);
|
|
@@ -751,17 +755,20 @@ class NgnCalendar extends CalendarTemplates {
|
|
|
751
755
|
}
|
|
752
756
|
this.value.set(date);
|
|
753
757
|
}
|
|
758
|
+
// Popover panel focus lives outside the host, so a plain focusout can't tell a
|
|
759
|
+
// real blur from opening the calendar — mark touched from this popover-aware
|
|
760
|
+
// check instead.
|
|
754
761
|
potentiallyBlurred() {
|
|
755
762
|
setTimeout(() => {
|
|
756
763
|
if (this.element.nativeElement.contains(document.activeElement) || this._popover()?.open()) {
|
|
757
764
|
return;
|
|
758
765
|
}
|
|
759
|
-
this.
|
|
766
|
+
this.markTouched();
|
|
760
767
|
});
|
|
761
768
|
}
|
|
762
769
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnCalendar, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
763
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: NgnCalendar, isStandalone: true, selector: "ngn-calendar", inputs: { firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, showTime: { classPropertyName: "showTime", publicName: "showTime", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, inline: { classPropertyName: "inline", publicName: "inline", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.display": "\"block\"", "style.width": "inline() ? \"fit-content\" : \"100%\"", "attr.aria-invalid": "
|
|
764
|
-
import('./ngneers-controls-calendar-time-
|
|
770
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: NgnCalendar, isStandalone: true, selector: "ngn-calendar", inputs: { firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, showTime: { classPropertyName: "showTime", publicName: "showTime", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, inline: { classPropertyName: "inline", publicName: "inline", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.display": "\"block\"", "style.width": "inline() ? \"fit-content\" : \"100%\"", "attr.aria-invalid": "invalidState() ? \"true\" : null" } }, providers: [provideSelf(NgnCalendar)], viewQueries: [{ propertyName: "_popover", first: true, predicate: NgnPopover, descendants: true, isSignal: true }, { propertyName: "_mask", first: true, predicate: NgnMaskInput, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@if (inline()) {\n <ng-container *ngTemplateOutlet=\"calendar\"></ng-container>\n} @else {\n <div\n #field\n [ptInt]=\"this\"\n [ptClass]=\"{ 'input-field': true, invalid: invalidState() }\"\n [attr.aria-invalid]=\"invalidState() ? 'true' : null\"\n (click)=\"focusFromPointer($event)\"\n (keydown)=\"onKeyDown($event)\"\n (focusout)=\"potentiallyBlurred()\"\n [tabindex]=\"disabled() ? -1 : 0\"\n >\n <ngn-mask-input\n [ptInt]=\"this\"\n [ptDep]=\"'input'\"\n [label]=\"i18n['calendar_input']()\"\n [mask]=\"maskCfg()\"\n [invalid]=\"invalidState()\"\n [invalidOn]=\"'immediate'\"\n [value]=\"valueStr()\"\n (valueChange)=\"stringValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n />\n <ngn-icon defaultIcon=\"calendar-trigger\" [ptInt]=\"this\" [ptDep]=\"'trigger-icon'\" />\n </div>\n <ngn-popover\n #popover\n [ptInt]=\"this\"\n [ptDep]=\"'popover'\"\n [anchor]=\"anchorElement\"\n [id]=\"inputId() + '_popover'\"\n (closing)=\"potentiallyBlurred()\"\n >\n <ng-template #lazy>\n <ng-container *ngTemplateOutlet=\"calendar\"></ng-container>\n </ng-template>\n </ngn-popover>\n}\n\n<ng-template #calendar>\n <div\n [ptInt]=\"this\"\n [ptClass]=\"{\n root: true,\n inline: inline(),\n }\"\n >\n <ngn-calendar-days\n [component]=\"this\"\n [theme]=\"theme\"\n [year]=\"year()\"\n [month]=\"month()\"\n [currentValue]=\"value()\"\n [firstDayOfWeek]=\"firstDayOfWeek()\"\n (previousMonth)=\"previousMonth()\"\n (nextMonth)=\"nextMonth()\"\n (daySelected)=\"selectDay($event)\"\n (monthSelected)=\"selectMonth($event)\"\n (yearSelected)=\"selectYear($event)\"\n (timeChanged)=\"changeTime($event)\"\n [dayTemplate]=\"dayTemplate()\"\n [weekDayTemplate]=\"weekDayTemplate()\"\n [timeTemplate]=\"timeTemplate()\"\n [yearTemplate]=\"yearTemplate()\"\n [monthTemplate]=\"monthTemplate()\"\n [showTime]=\"showTime()\"\n [showSeconds]=\"showSeconds()\"\n (focusout)=\"potentiallyBlurred()\"\n />\n </div>\n</ng-template>\n<ng-template #defaultDayTemplate [ngnTemplate]=\"templateTypes.day\" let-day>\n {{ day.date }}\n</ng-template>\n\n<ng-template #defaultWeekDayTemplate [ngnTemplate]=\"templateTypes.weekDay\" let-weekDay>\n <span>\n {{ weekDay.translation }}\n </span>\n</ng-template>\n\n<ng-template #defaultTimeTemplate [ngnTemplate]=\"templateTypes.time\" let-time>\n @defer {\n <div [ptInt]=\"this\" [ptClass]=\"'time'\">\n <ngn-calendar-time\n [component]=\"this\"\n [currentValue]=\"time.time\"\n [showSeconds]=\"time.showSeconds\"\n (timeChange)=\"time.change($event)\"\n />\n </div>\n }\n</ng-template>\n\n<ng-template #defaultYearTemplate [ngnTemplate]=\"templateTypes.year\" let-y>\n @defer {\n <ngn-input-field [ptInt]=\"this\" [ptDep]=\"'current-year-field'\">\n <ngn-select\n [ptInt]=\"this\"\n [ptDep]=\"'current-year'\"\n [editable]=\"true\"\n [value]=\"year() + ''\"\n (valueChange)=\"y.change(+($event || 0))\"\n [options]=\"yearOptions\"\n [virtual]=\"true\"\n [itemHeight]=\"40\"\n [popoverOptions]=\"{ sizeConstraints: { maxHeight: '300px' } }\"\n [scrollToSelectedItemOnOpen]=\"'center'\"\n [editableAutoFilter]=\"false\"\n [tabindex]=\"-1\"\n >\n <input ngnInput type=\"number\" [attr.aria-label]=\"i18n['calendar_selectYear']()\" />\n </ngn-select>\n </ngn-input-field>\n }\n</ng-template>\n\n<ng-template #defaultMonthTemplate [ngnTemplate]=\"templateTypes.month\" let-m>\n @defer {\n <ngn-input-field [ptInt]=\"this\" [ptDep]=\"'current-month-field'\">\n <ngn-select\n [ptInt]=\"this\"\n [ptDep]=\"'current-month'\"\n [label]=\"i18n['calendar_selectMonth']()\"\n [value]=\"m.month\"\n (valueChange)=\"m.change($event!)\"\n [options]=\"monthOptions()\"\n [popoverOptions]=\"{\n sizeConstraints: { maxHeight: '300px', width: '130px', maxWidth: '130px' },\n }\"\n [scrollToSelectedItemOnOpen]=\"'center'\"\n [tabindex]=\"-1\"\n />\n </ngn-input-field>\n }\n</ng-template>\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgnTemplate, selector: "ng-template[ngnTemplate]", inputs: ["ngnTemplate"] }, { kind: "directive", type: NgnPt, selector: "[ptInt]", inputs: ["ptInt", "ptClass", "ptDep"] }, { kind: "component", type: NgnIcon, selector: "ngn-icon", inputs: ["defaultIcon", "icon"] }, { kind: "component", type: NgnPopover, selector: "ngn-popover", inputs: ["open", "anchor", "options", "hasShrinkableContent", "closeBy"], outputs: ["closed", "closing", "openChange"] }, { kind: "component", type: CalendarDays, selector: "ngn-calendar-days", inputs: ["component", "theme", "year", "month", "currentValue", "firstDayOfWeek", "dayTemplate", "weekDayTemplate", "timeTemplate", "yearTemplate", "monthTemplate", "showTime", "showSeconds"], outputs: ["previousMonth", "nextMonth", "daySelected", "yearSelected", "monthSelected", "timeChanged"] }, { kind: "component", type: NgnMaskInput, selector: "ngn-mask-input", inputs: ["mask"] }], deferBlockDependencies: [() => [NgnPt, /* @ts-ignore */
|
|
771
|
+
import('./ngneers-controls-calendar-time-paM6WVpV.mjs').then(m => m.CalendarTime)], () => [NgnPt, /* @ts-ignore */
|
|
765
772
|
import('@ngneers/controls/input').then(m => m.NgnInput), /* @ts-ignore */
|
|
766
773
|
import('@ngneers/controls/select').then(m => m.NgnSelect), /* @ts-ignore */
|
|
767
774
|
import('@ngneers/controls/input-field').then(m => m.NgnInputField)], () => [NgnPt, /* @ts-ignore */
|
|
@@ -769,7 +776,7 @@ class NgnCalendar extends CalendarTemplates {
|
|
|
769
776
|
import('@ngneers/controls/input-field').then(m => m.NgnInputField)]] });
|
|
770
777
|
}
|
|
771
778
|
i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "22.0.5", ngImport: i0, type: NgnCalendar, resolveDeferredDeps: () => [/* @ts-ignore */
|
|
772
|
-
import('./ngneers-controls-calendar-time-
|
|
779
|
+
import('./ngneers-controls-calendar-time-paM6WVpV.mjs').then(m => m.CalendarTime), /* @ts-ignore */
|
|
773
780
|
import('@ngneers/controls/input').then(m => m.NgnInput), /* @ts-ignore */
|
|
774
781
|
import('@ngneers/controls/select').then(m => m.NgnSelect), /* @ts-ignore */
|
|
775
782
|
import('@ngneers/controls/input-field').then(m => m.NgnInputField)], resolveMetadata: (CalendarTime, NgnInput, NgnSelect, NgnInputField) => ({ decorators: [{
|
|
@@ -789,8 +796,8 @@ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "22.0.5", ng
|
|
|
789
796
|
], providers: [provideSelf(NgnCalendar)], host: {
|
|
790
797
|
'[style.display]': '"block"',
|
|
791
798
|
'[style.width]': 'inline() ? "fit-content" : "100%"',
|
|
792
|
-
'[attr.aria-invalid]': '
|
|
793
|
-
}, template: "@if (inline()) {\n <ng-container *ngTemplateOutlet=\"calendar\"></ng-container>\n} @else {\n <div\n #field\n [ptInt]=\"this\"\n [ptClass]=\"{ 'input-field': true, invalid:
|
|
799
|
+
'[attr.aria-invalid]': 'invalidState() ? "true" : null',
|
|
800
|
+
}, template: "@if (inline()) {\n <ng-container *ngTemplateOutlet=\"calendar\"></ng-container>\n} @else {\n <div\n #field\n [ptInt]=\"this\"\n [ptClass]=\"{ 'input-field': true, invalid: invalidState() }\"\n [attr.aria-invalid]=\"invalidState() ? 'true' : null\"\n (click)=\"focusFromPointer($event)\"\n (keydown)=\"onKeyDown($event)\"\n (focusout)=\"potentiallyBlurred()\"\n [tabindex]=\"disabled() ? -1 : 0\"\n >\n <ngn-mask-input\n [ptInt]=\"this\"\n [ptDep]=\"'input'\"\n [label]=\"i18n['calendar_input']()\"\n [mask]=\"maskCfg()\"\n [invalid]=\"invalidState()\"\n [invalidOn]=\"'immediate'\"\n [value]=\"valueStr()\"\n (valueChange)=\"stringValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n />\n <ngn-icon defaultIcon=\"calendar-trigger\" [ptInt]=\"this\" [ptDep]=\"'trigger-icon'\" />\n </div>\n <ngn-popover\n #popover\n [ptInt]=\"this\"\n [ptDep]=\"'popover'\"\n [anchor]=\"anchorElement\"\n [id]=\"inputId() + '_popover'\"\n (closing)=\"potentiallyBlurred()\"\n >\n <ng-template #lazy>\n <ng-container *ngTemplateOutlet=\"calendar\"></ng-container>\n </ng-template>\n </ngn-popover>\n}\n\n<ng-template #calendar>\n <div\n [ptInt]=\"this\"\n [ptClass]=\"{\n root: true,\n inline: inline(),\n }\"\n >\n <ngn-calendar-days\n [component]=\"this\"\n [theme]=\"theme\"\n [year]=\"year()\"\n [month]=\"month()\"\n [currentValue]=\"value()\"\n [firstDayOfWeek]=\"firstDayOfWeek()\"\n (previousMonth)=\"previousMonth()\"\n (nextMonth)=\"nextMonth()\"\n (daySelected)=\"selectDay($event)\"\n (monthSelected)=\"selectMonth($event)\"\n (yearSelected)=\"selectYear($event)\"\n (timeChanged)=\"changeTime($event)\"\n [dayTemplate]=\"dayTemplate()\"\n [weekDayTemplate]=\"weekDayTemplate()\"\n [timeTemplate]=\"timeTemplate()\"\n [yearTemplate]=\"yearTemplate()\"\n [monthTemplate]=\"monthTemplate()\"\n [showTime]=\"showTime()\"\n [showSeconds]=\"showSeconds()\"\n (focusout)=\"potentiallyBlurred()\"\n />\n </div>\n</ng-template>\n<ng-template #defaultDayTemplate [ngnTemplate]=\"templateTypes.day\" let-day>\n {{ day.date }}\n</ng-template>\n\n<ng-template #defaultWeekDayTemplate [ngnTemplate]=\"templateTypes.weekDay\" let-weekDay>\n <span>\n {{ weekDay.translation }}\n </span>\n</ng-template>\n\n<ng-template #defaultTimeTemplate [ngnTemplate]=\"templateTypes.time\" let-time>\n @defer {\n <div [ptInt]=\"this\" [ptClass]=\"'time'\">\n <ngn-calendar-time\n [component]=\"this\"\n [currentValue]=\"time.time\"\n [showSeconds]=\"time.showSeconds\"\n (timeChange)=\"time.change($event)\"\n />\n </div>\n }\n</ng-template>\n\n<ng-template #defaultYearTemplate [ngnTemplate]=\"templateTypes.year\" let-y>\n @defer {\n <ngn-input-field [ptInt]=\"this\" [ptDep]=\"'current-year-field'\">\n <ngn-select\n [ptInt]=\"this\"\n [ptDep]=\"'current-year'\"\n [editable]=\"true\"\n [value]=\"year() + ''\"\n (valueChange)=\"y.change(+($event || 0))\"\n [options]=\"yearOptions\"\n [virtual]=\"true\"\n [itemHeight]=\"40\"\n [popoverOptions]=\"{ sizeConstraints: { maxHeight: '300px' } }\"\n [scrollToSelectedItemOnOpen]=\"'center'\"\n [editableAutoFilter]=\"false\"\n [tabindex]=\"-1\"\n >\n <input ngnInput type=\"number\" [attr.aria-label]=\"i18n['calendar_selectYear']()\" />\n </ngn-select>\n </ngn-input-field>\n }\n</ng-template>\n\n<ng-template #defaultMonthTemplate [ngnTemplate]=\"templateTypes.month\" let-m>\n @defer {\n <ngn-input-field [ptInt]=\"this\" [ptDep]=\"'current-month-field'\">\n <ngn-select\n [ptInt]=\"this\"\n [ptDep]=\"'current-month'\"\n [label]=\"i18n['calendar_selectMonth']()\"\n [value]=\"m.month\"\n (valueChange)=\"m.change($event!)\"\n [options]=\"monthOptions()\"\n [popoverOptions]=\"{\n sizeConstraints: { maxHeight: '300px', width: '130px', maxWidth: '130px' },\n }\"\n [scrollToSelectedItemOnOpen]=\"'center'\"\n [tabindex]=\"-1\"\n />\n </ngn-input-field>\n }\n</ng-template>\n" }]
|
|
794
801
|
}], ctorParameters: null, propDecorators: { firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], showTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTime", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], inline: [{ type: i0.Input, args: [{ isSignal: true, alias: "inline", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], _popover: [{ type: i0.ViewChild, args: [i0.forwardRef(() => NgnPopover), { isSignal: true }] }], _mask: [{ type: i0.ViewChild, args: [i0.forwardRef(() => NgnMaskInput), { isSignal: true }] }] } }) });
|
|
795
802
|
|
|
796
803
|
/**
|