@truenas/ui-components 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Overlay, OverlayPositionBuilder, OverlayModule } from '@angular/cdk/overlay';
|
|
2
2
|
import { TemplatePortal, ComponentPortal, PortalModule } from '@angular/cdk/portal';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { input, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, InjectionToken, inject, Renderer2, ElementRef, effect, Directive, ViewContainerRef, output, viewChild, signal, untracked, isDevMode, forwardRef, model, afterNextRender, Injectable, contentChildren, HostListener, linkedSignal, contentChild, ChangeDetectorRef, DestroyRef, TemplateRef, isSignal, IterableDiffers,
|
|
4
|
+
import { input, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, InjectionToken, inject, Renderer2, ElementRef, effect, Directive, ViewContainerRef, output, viewChild, signal, untracked, isDevMode, forwardRef, model, afterNextRender, Injectable, contentChildren, Pipe, HostListener, linkedSignal, contentChild, ChangeDetectorRef, DestroyRef, TemplateRef, isSignal, IterableDiffers, ApplicationRef, EnvironmentInjector, createComponent, PLATFORM_ID } from '@angular/core';
|
|
5
5
|
import * as i1$3 from '@angular/forms';
|
|
6
6
|
import { NG_VALUE_ACCESSOR, FormsModule, NgControl, Validators } from '@angular/forms';
|
|
7
7
|
import { ComponentHarness, HarnessPredicate, TestKey } from '@angular/cdk/testing';
|
|
@@ -268,10 +268,20 @@ class TnAutocompleteComponent {
|
|
|
268
268
|
viewContainerRef = inject(ViewContainerRef);
|
|
269
269
|
/** Unique instance ID for ARIA linkage */
|
|
270
270
|
uid = `tn-autocomplete-${nextId$1++}`;
|
|
271
|
-
/**
|
|
271
|
+
/**
|
|
272
|
+
* All available options. The `label` is displayed; the `value` is committed
|
|
273
|
+
* to the form control. A written value is resolved back to its option's
|
|
274
|
+
* label for display — falling back to `String(value)` until the matching
|
|
275
|
+
* option is available, and upgraded once an async option load lands.
|
|
276
|
+
*/
|
|
272
277
|
options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
273
|
-
/**
|
|
274
|
-
|
|
278
|
+
/**
|
|
279
|
+
* Custom comparator for matching a written control value against option
|
|
280
|
+
* values during display resolution. Defaults to identity (`===`), which is
|
|
281
|
+
* right for primitive values; provide this when option values are objects.
|
|
282
|
+
* Mirrors `tn-select`'s `compareWith`.
|
|
283
|
+
*/
|
|
284
|
+
compareWith = input(undefined, ...(ngDevMode ? [{ debugName: "compareWith" }] : []));
|
|
275
285
|
/** Placeholder text for the input */
|
|
276
286
|
placeholder = input('Type to search...', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
|
|
277
287
|
/** Whether the input is disabled */
|
|
@@ -293,7 +303,7 @@ class TnAutocompleteComponent {
|
|
|
293
303
|
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
294
304
|
/** Text shown next to the spinner while `loading` is set. */
|
|
295
305
|
loadingText = input('Loading...', ...(ngDevMode ? [{ debugName: "loadingText" }] : []));
|
|
296
|
-
/** Custom filter function. Defaults to case-insensitive includes on
|
|
306
|
+
/** Custom filter function. Defaults to case-insensitive includes on the option label */
|
|
297
307
|
filterFn = input(undefined, ...(ngDevMode ? [{ debugName: "filterFn" }] : []));
|
|
298
308
|
/** Text shown when no options match the search */
|
|
299
309
|
noResultsText = input('No results found', ...(ngDevMode ? [{ debugName: "noResultsText" }] : []));
|
|
@@ -314,7 +324,7 @@ class TnAutocompleteComponent {
|
|
|
314
324
|
panelMaxHeight = input('320px', ...(ngDevMode ? [{ debugName: "panelMaxHeight" }] : []));
|
|
315
325
|
/** Test ID attribute */
|
|
316
326
|
testId = input(undefined, ...(ngDevMode ? [{ debugName: "testId" }] : []));
|
|
317
|
-
/** Emits
|
|
327
|
+
/** Emits the full option (label + value) when one is selected */
|
|
318
328
|
optionSelected = output();
|
|
319
329
|
/**
|
|
320
330
|
* Emits the search term as the user types (not on programmatic writes or
|
|
@@ -354,7 +364,7 @@ class TnAutocompleteComponent {
|
|
|
354
364
|
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
|
|
355
365
|
/** Index of the currently highlighted option for keyboard nav */
|
|
356
366
|
highlightedIndex = signal(-1, ...(ngDevMode ? [{ debugName: "highlightedIndex" }] : []));
|
|
357
|
-
/** The currently
|
|
367
|
+
/** The currently committed value (an option's `value`, or a custom-typed one) */
|
|
358
368
|
selectedValue = signal(null, ...(ngDevMode ? [{ debugName: "selectedValue" }] : []));
|
|
359
369
|
/** CVA disabled state from the form */
|
|
360
370
|
formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "formDisabled" }] : []));
|
|
@@ -365,7 +375,6 @@ class TnAutocompleteComponent {
|
|
|
365
375
|
const term = this.searchTerm();
|
|
366
376
|
const all = this.options();
|
|
367
377
|
const customFilter = this.filterFn();
|
|
368
|
-
const display = this.displayWith();
|
|
369
378
|
const max = this.maxResults();
|
|
370
379
|
if (!term) {
|
|
371
380
|
return all.slice(0, max);
|
|
@@ -373,7 +382,7 @@ class TnAutocompleteComponent {
|
|
|
373
382
|
const lowerTerm = term.toLowerCase();
|
|
374
383
|
const filtered = customFilter
|
|
375
384
|
? all.filter((opt) => customFilter(opt, term))
|
|
376
|
-
: all.filter((opt) =>
|
|
385
|
+
: all.filter((opt) => opt.label.toLowerCase().includes(lowerTerm));
|
|
377
386
|
return filtered.slice(0, max);
|
|
378
387
|
}, ...(ngDevMode ? [{ debugName: "filteredOptions" }] : []));
|
|
379
388
|
/** Whether there are any results to show */
|
|
@@ -392,7 +401,32 @@ class TnAutocompleteComponent {
|
|
|
392
401
|
lastOptionsCount = null;
|
|
393
402
|
/** Scroll distance (px) from the panel bottom that triggers `loadMore`. */
|
|
394
403
|
static loadMoreThresholdPx = 48;
|
|
404
|
+
/** Guards the object-without-compareWith warning so it fires only once. */
|
|
405
|
+
warnedAboutObjectCompare = false;
|
|
395
406
|
constructor() {
|
|
407
|
+
// A value written before its option loaded displays as the raw fallback —
|
|
408
|
+
// once options arrive (or are relabeled, e.g. a locale change), upgrade
|
|
409
|
+
// the text to the option's label. UPGRADE-ONLY: when no option matches
|
|
410
|
+
// (e.g. a server-search picker replaced `options` after a selection), the
|
|
411
|
+
// current text is left alone rather than downgraded back to the raw
|
|
412
|
+
// value. Skipped while the panel is open so active typing isn't clobbered.
|
|
413
|
+
effect(() => {
|
|
414
|
+
this.options();
|
|
415
|
+
this.compareWith();
|
|
416
|
+
untracked(() => {
|
|
417
|
+
if (this.isOpen()) {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
const value = this.selectedValue();
|
|
421
|
+
if (value === null || value === undefined) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
const match = this.options().find((opt) => this.valueMatches(opt.value, value));
|
|
425
|
+
if (match) {
|
|
426
|
+
this.searchTerm.set(match.label);
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
});
|
|
396
430
|
// A changed options COUNT means the consumer answered the last loadMore
|
|
397
431
|
// (or a new result set landed) — re-arm the emitter and request another
|
|
398
432
|
// page if the rows still don't fill the panel. Re-arming on length (not
|
|
@@ -440,7 +474,7 @@ class TnAutocompleteComponent {
|
|
|
440
474
|
writeValue(value) {
|
|
441
475
|
this.selectedValue.set(value);
|
|
442
476
|
if (value !== null && value !== undefined) {
|
|
443
|
-
this.searchTerm.set(this.
|
|
477
|
+
this.searchTerm.set(this.displayValue(value));
|
|
444
478
|
}
|
|
445
479
|
else {
|
|
446
480
|
this.searchTerm.set('');
|
|
@@ -459,7 +493,6 @@ class TnAutocompleteComponent {
|
|
|
459
493
|
onInput(event) {
|
|
460
494
|
const value = event.target.value;
|
|
461
495
|
this.searchTerm.set(value);
|
|
462
|
-
this.highlightedIndex.set(-1);
|
|
463
496
|
// A new term is a new pagination context — don't hold back its first page.
|
|
464
497
|
this.loadMorePending = false;
|
|
465
498
|
this.searchChange.emit(value);
|
|
@@ -471,6 +504,9 @@ class TnAutocompleteComponent {
|
|
|
471
504
|
// anchored position so it stays attached to the input.
|
|
472
505
|
this.overlayRef?.updatePosition();
|
|
473
506
|
}
|
|
507
|
+
// Typing is a fresh search, not navigation — no row is pre-highlighted.
|
|
508
|
+
// Set after open() so it overrides the committed-option seed below.
|
|
509
|
+
this.highlightedIndex.set(-1);
|
|
474
510
|
}
|
|
475
511
|
onFocus() {
|
|
476
512
|
if (!this.isDisabled()) {
|
|
@@ -486,8 +522,7 @@ class TnAutocompleteComponent {
|
|
|
486
522
|
}
|
|
487
523
|
if (this.requireSelection()) {
|
|
488
524
|
const term = this.searchTerm();
|
|
489
|
-
const
|
|
490
|
-
const match = this.options().find((opt) => display(opt).toLowerCase() === term.toLowerCase());
|
|
525
|
+
const match = this.options().find((opt) => !opt.disabled && opt.label.toLowerCase() === term.toLowerCase());
|
|
491
526
|
if (match) {
|
|
492
527
|
this.selectOption(match);
|
|
493
528
|
}
|
|
@@ -495,7 +530,7 @@ class TnAutocompleteComponent {
|
|
|
495
530
|
// Revert to last valid selection or clear
|
|
496
531
|
const current = this.selectedValue();
|
|
497
532
|
if (current !== null && current !== undefined) {
|
|
498
|
-
this.searchTerm.set(
|
|
533
|
+
this.searchTerm.set(this.displayValue(current));
|
|
499
534
|
}
|
|
500
535
|
else {
|
|
501
536
|
this.searchTerm.set('');
|
|
@@ -507,6 +542,9 @@ class TnAutocompleteComponent {
|
|
|
507
542
|
this.onTouched();
|
|
508
543
|
}
|
|
509
544
|
onOptionClick(option) {
|
|
545
|
+
if (option.disabled) {
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
510
548
|
this.selectOption(option);
|
|
511
549
|
}
|
|
512
550
|
onKeydown(event) {
|
|
@@ -518,21 +556,27 @@ class TnAutocompleteComponent {
|
|
|
518
556
|
this.open();
|
|
519
557
|
}
|
|
520
558
|
else {
|
|
521
|
-
this.highlightedIndex
|
|
522
|
-
|
|
559
|
+
const next = this.nextEnabledIndex(this.highlightedIndex(), 1);
|
|
560
|
+
if (next >= 0) {
|
|
561
|
+
this.highlightedIndex.set(next);
|
|
562
|
+
this.scrollToHighlighted();
|
|
563
|
+
}
|
|
523
564
|
}
|
|
524
565
|
break;
|
|
525
566
|
case 'ArrowUp':
|
|
526
567
|
event.preventDefault();
|
|
527
568
|
if (this.isOpen()) {
|
|
528
|
-
this.highlightedIndex
|
|
529
|
-
|
|
569
|
+
const prev = this.nextEnabledIndex(this.highlightedIndex(), -1);
|
|
570
|
+
if (prev >= 0) {
|
|
571
|
+
this.highlightedIndex.set(prev);
|
|
572
|
+
this.scrollToHighlighted();
|
|
573
|
+
}
|
|
530
574
|
}
|
|
531
575
|
break;
|
|
532
576
|
case 'Enter': {
|
|
533
577
|
event.preventDefault();
|
|
534
578
|
const idx = this.highlightedIndex();
|
|
535
|
-
if (this.isOpen() && idx >= 0 && idx < options.length) {
|
|
579
|
+
if (this.isOpen() && idx >= 0 && idx < options.length && !options[idx].disabled) {
|
|
536
580
|
this.selectOption(options[idx]);
|
|
537
581
|
}
|
|
538
582
|
else if (this.allowCustomValue()) {
|
|
@@ -547,7 +591,7 @@ class TnAutocompleteComponent {
|
|
|
547
591
|
// Escape means "cancel the draft": revert to the committed value's
|
|
548
592
|
// text so the upcoming blur doesn't commit the abandoned term.
|
|
549
593
|
const current = this.selectedValue();
|
|
550
|
-
this.searchTerm.set(current !== null && current !== undefined ? this.
|
|
594
|
+
this.searchTerm.set(current !== null && current !== undefined ? this.displayValue(current) : '');
|
|
551
595
|
}
|
|
552
596
|
this.close();
|
|
553
597
|
break;
|
|
@@ -596,7 +640,52 @@ class TnAutocompleteComponent {
|
|
|
596
640
|
this.loadMore.emit();
|
|
597
641
|
}
|
|
598
642
|
}
|
|
643
|
+
/**
|
|
644
|
+
* Whether `option` carries the committed value — drives `aria-selected` so
|
|
645
|
+
* assistive tech announces the current choice independently of the keyboard
|
|
646
|
+
* cursor (which is conveyed via `aria-activedescendant`).
|
|
647
|
+
*/
|
|
648
|
+
isOptionSelected(option) {
|
|
649
|
+
const value = this.selectedValue();
|
|
650
|
+
if (value === null || value === undefined) {
|
|
651
|
+
return false;
|
|
652
|
+
}
|
|
653
|
+
return this.valueMatches(option.value, value);
|
|
654
|
+
}
|
|
599
655
|
// ── Internal ──
|
|
656
|
+
/**
|
|
657
|
+
* Index of the committed value's option in the visible list, or -1 when
|
|
658
|
+
* nothing is committed or the match is absent/disabled. Used to seed the
|
|
659
|
+
* keyboard cursor when the panel opens.
|
|
660
|
+
*/
|
|
661
|
+
selectedOptionIndex() {
|
|
662
|
+
const value = this.selectedValue();
|
|
663
|
+
if (value === null || value === undefined) {
|
|
664
|
+
return -1;
|
|
665
|
+
}
|
|
666
|
+
return this.filteredOptions().findIndex((opt) => !opt.disabled && this.valueMatches(opt.value, value));
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Next selectable option index from `from` in `direction` (+1 down, -1 up),
|
|
670
|
+
* skipping disabled rows and wrapping around. `from` of -1 ("nothing
|
|
671
|
+
* highlighted") lands on the first row going down, the last going up.
|
|
672
|
+
* Returns -1 when every visible option is disabled.
|
|
673
|
+
*/
|
|
674
|
+
nextEnabledIndex(from, direction) {
|
|
675
|
+
const options = this.filteredOptions();
|
|
676
|
+
const count = options.length;
|
|
677
|
+
if (count === 0) {
|
|
678
|
+
return -1;
|
|
679
|
+
}
|
|
680
|
+
const start = from < 0 ? (direction === 1 ? -1 : 0) : from;
|
|
681
|
+
for (let step = 1; step <= count; step++) {
|
|
682
|
+
const idx = (((start + direction * step) % count) + count) % count;
|
|
683
|
+
if (!options[idx].disabled) {
|
|
684
|
+
return idx;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
return -1;
|
|
688
|
+
}
|
|
600
689
|
/**
|
|
601
690
|
* Commit the current search term as the value (allowCustomValue mode). A
|
|
602
691
|
* display match (case-insensitive, same as the requireSelection path)
|
|
@@ -605,25 +694,61 @@ class TnAutocompleteComponent {
|
|
|
605
694
|
*/
|
|
606
695
|
commitCustomValue() {
|
|
607
696
|
const term = this.searchTerm();
|
|
608
|
-
const display = this.displayWith();
|
|
609
697
|
const lowerTerm = term.toLowerCase();
|
|
610
|
-
const match = this.options().find((opt) =>
|
|
698
|
+
const match = this.options().find((opt) => !opt.disabled && opt.label.toLowerCase() === lowerTerm);
|
|
611
699
|
if (match) {
|
|
612
700
|
this.selectOption(match);
|
|
613
701
|
return;
|
|
614
702
|
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
703
|
+
// Best-effort guard: silent when options haven't loaded yet (the common
|
|
704
|
+
// async + allowCustomValue case), where the value type can't be known.
|
|
705
|
+
if (isDevMode() && term !== '' && this.options().some((opt) => typeof opt.value !== 'string')) {
|
|
706
|
+
console.warn('[tn-autocomplete] allowCustomValue committed free text into a control whose option '
|
|
707
|
+
+ 'values are not strings — custom values are only sound for string-valued autocompletes.');
|
|
618
708
|
}
|
|
619
709
|
const value = term === '' ? null : term;
|
|
620
710
|
this.selectedValue.set(value);
|
|
621
711
|
this.onChange(value);
|
|
622
712
|
}
|
|
713
|
+
/**
|
|
714
|
+
* Resolves a committed value back to its option's display label, falling
|
|
715
|
+
* back to the raw value's string until the matching option is available.
|
|
716
|
+
*/
|
|
717
|
+
displayValue(value) {
|
|
718
|
+
const match = this.options().find((opt) => this.valueMatches(opt.value, value));
|
|
719
|
+
return match ? match.label : String(value);
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Compares option values, honoring `compareWith` when provided. Without one,
|
|
723
|
+
* falls back to identity (`===`) — which never matches structurally-equal
|
|
724
|
+
* objects from different references, so display resolution and selection
|
|
725
|
+
* silently fail. Warn once on that misuse (unconditional, like `tn-select`,
|
|
726
|
+
* so prod monitoring catches it) and return `false` to make it loud.
|
|
727
|
+
*/
|
|
728
|
+
valueMatches(a, b) {
|
|
729
|
+
const comparator = this.compareWith();
|
|
730
|
+
if (comparator) {
|
|
731
|
+
return comparator(a, b);
|
|
732
|
+
}
|
|
733
|
+
if (a === b) {
|
|
734
|
+
return true;
|
|
735
|
+
}
|
|
736
|
+
if (typeof a === 'object' && typeof b === 'object' && a !== null && b !== null) {
|
|
737
|
+
if (!this.warnedAboutObjectCompare) {
|
|
738
|
+
this.warnedAboutObjectCompare = true;
|
|
739
|
+
console.warn('[tn-autocomplete] Comparing object option values without a `compareWith` input. ' +
|
|
740
|
+
'Identity comparison will not match structurally-equal objects from different ' +
|
|
741
|
+
'references, so the committed value will not resolve to its label. ' +
|
|
742
|
+
'Provide `[compareWith]="(a, b) => a?.id === b?.id"` (or similar).');
|
|
743
|
+
}
|
|
744
|
+
return false;
|
|
745
|
+
}
|
|
746
|
+
return false;
|
|
747
|
+
}
|
|
623
748
|
selectOption(option) {
|
|
624
|
-
this.selectedValue.set(option);
|
|
625
|
-
this.searchTerm.set(
|
|
626
|
-
this.onChange(option);
|
|
749
|
+
this.selectedValue.set(option.value);
|
|
750
|
+
this.searchTerm.set(option.label);
|
|
751
|
+
this.onChange(option.value);
|
|
627
752
|
this.optionSelected.emit(option);
|
|
628
753
|
this.close();
|
|
629
754
|
}
|
|
@@ -632,7 +757,13 @@ class TnAutocompleteComponent {
|
|
|
632
757
|
return;
|
|
633
758
|
}
|
|
634
759
|
this.isOpen.set(true);
|
|
760
|
+
// Seed the keyboard cursor on the committed option so ArrowDown resumes
|
|
761
|
+
// from the current value (and it scrolls into view). -1 when nothing is
|
|
762
|
+
// committed or the value has no visible, enabled option — e.g. a custom
|
|
763
|
+
// free-text value, or a value whose option hasn't loaded yet.
|
|
764
|
+
this.highlightedIndex.set(this.selectedOptionIndex());
|
|
635
765
|
this.attachOverlay();
|
|
766
|
+
this.scrollToHighlighted();
|
|
636
767
|
this.opened.emit();
|
|
637
768
|
}
|
|
638
769
|
close() {
|
|
@@ -697,13 +828,13 @@ class TnAutocompleteComponent {
|
|
|
697
828
|
}
|
|
698
829
|
}
|
|
699
830
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnAutocompleteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
700
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnAutocompleteComponent, isStandalone: true, selector: "tn-autocomplete", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null },
|
|
831
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnAutocompleteComponent, isStandalone: true, selector: "tn-autocomplete", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, requireSelection: { classPropertyName: "requireSelection", publicName: "requireSelection", isSignal: true, isRequired: false, transformFunction: null }, allowCustomValue: { classPropertyName: "allowCustomValue", publicName: "allowCustomValue", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingText: { classPropertyName: "loadingText", publicName: "loadingText", isSignal: true, isRequired: false, transformFunction: null }, filterFn: { classPropertyName: "filterFn", publicName: "filterFn", isSignal: true, isRequired: false, transformFunction: null }, noResultsText: { classPropertyName: "noResultsText", publicName: "noResultsText", isSignal: true, isRequired: false, transformFunction: null }, maxResults: { classPropertyName: "maxResults", publicName: "maxResults", isSignal: true, isRequired: false, transformFunction: null }, panelMaxHeight: { classPropertyName: "panelMaxHeight", publicName: "panelMaxHeight", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { optionSelected: "optionSelected", searchChange: "searchChange", loadMore: "loadMore", opened: "opened" }, providers: [
|
|
701
832
|
{
|
|
702
833
|
provide: NG_VALUE_ACCESSOR,
|
|
703
834
|
useExisting: forwardRef(() => TnAutocompleteComponent),
|
|
704
835
|
multi: true,
|
|
705
836
|
},
|
|
706
|
-
], viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["inputEl"], descendants: true, isSignal: true }, { propertyName: "dropdownTemplate", first: true, predicate: ["dropdownTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"tn-autocomplete\">\n <input\n #inputEl\n type=\"text\"\n class=\"tn-autocomplete__input\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n tnTestIdType=\"autocomplete\"\n autocomplete=\"off\"\n [tnTestId]=\"testId()\"\n [class.open]=\"isOpen()\"\n [class.disabled]=\"isDisabled()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [value]=\"searchTerm()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-autocomplete]=\"'list'\"\n [attr.aria-controls]=\"isOpen() ? uid + '-dropdown' : null\"\n [attr.aria-owns]=\"isOpen() ? uid + '-dropdown' : null\"\n [attr.aria-activedescendant]=\"highlightedIndex() >= 0 ? uid + '-option-' + highlightedIndex() : null\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onKeydown($event)\" />\n</div>\n\n<!-- Dropdown panel \u2014 portaled via CDK Overlay so it escapes parent\n overflow/clipping. Attach/detach (driven by open()/close()) controls\n visibility; the input keeps DOM focus throughout. -->\n<ng-template #dropdownTemplate>\n <div\n class=\"tn-autocomplete__dropdown\"\n [style.--tn-autocomplete-panel-max-height]=\"panelMaxHeightValue()\"\n (scroll)=\"onPanelScroll($event)\">\n\n <!-- Per ARIA, a listbox may only contain option/group children, so the\n loading and no-results rows live OUTSIDE it as live-region siblings.\n The listbox itself stays rendered (possibly empty) the whole time the\n panel is open, so the input's aria-controls always points at a real\n element \u2014 including the loading-with-no-results-yet state. -->\n <div role=\"listbox\" [attr.id]=\"uid + '-dropdown'\" [attr.aria-busy]=\"loading() ? true : null\">\n @if (hasResults()) {\n @for (option of filteredOptions(); track $index) {\n <div\n class=\"tn-autocomplete__option\"\n role=\"option\"\n tabindex=\"-1\"\n [class.highlighted]=\"highlightedIndex() === $index\"\n [attr.id]=\"uid + '-option-' + $index\"\n [attr.aria-selected]=\"
|
|
837
|
+
], viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["inputEl"], descendants: true, isSignal: true }, { propertyName: "dropdownTemplate", first: true, predicate: ["dropdownTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"tn-autocomplete\">\n <input\n #inputEl\n type=\"text\"\n class=\"tn-autocomplete__input\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n tnTestIdType=\"autocomplete\"\n autocomplete=\"off\"\n [tnTestId]=\"testId()\"\n [class.open]=\"isOpen()\"\n [class.disabled]=\"isDisabled()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [value]=\"searchTerm()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-autocomplete]=\"'list'\"\n [attr.aria-controls]=\"isOpen() ? uid + '-dropdown' : null\"\n [attr.aria-owns]=\"isOpen() ? uid + '-dropdown' : null\"\n [attr.aria-activedescendant]=\"highlightedIndex() >= 0 ? uid + '-option-' + highlightedIndex() : null\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onKeydown($event)\" />\n</div>\n\n<!-- Dropdown panel \u2014 portaled via CDK Overlay so it escapes parent\n overflow/clipping. Attach/detach (driven by open()/close()) controls\n visibility; the input keeps DOM focus throughout. -->\n<ng-template #dropdownTemplate>\n <div\n class=\"tn-autocomplete__dropdown\"\n [style.--tn-autocomplete-panel-max-height]=\"panelMaxHeightValue()\"\n (scroll)=\"onPanelScroll($event)\">\n\n <!-- Per ARIA, a listbox may only contain option/group children, so the\n loading and no-results rows live OUTSIDE it as live-region siblings.\n The listbox itself stays rendered (possibly empty) the whole time the\n panel is open, so the input's aria-controls always points at a real\n element \u2014 including the loading-with-no-results-yet state. -->\n <div role=\"listbox\" [attr.id]=\"uid + '-dropdown'\" [attr.aria-busy]=\"loading() ? true : null\">\n @if (hasResults()) {\n @for (option of filteredOptions(); track $index) {\n <div\n class=\"tn-autocomplete__option\"\n role=\"option\"\n tabindex=\"-1\"\n [class.highlighted]=\"highlightedIndex() === $index\"\n [class.disabled]=\"option.disabled\"\n [attr.id]=\"uid + '-option-' + $index\"\n [attr.aria-selected]=\"isOptionSelected(option)\"\n [attr.aria-disabled]=\"option.disabled ? true : null\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"onOptionClick(option)\"\n (keydown.enter)=\"onOptionClick(option)\">\n {{ option.label }}\n </div>\n }\n }\n </div>\n\n <div role=\"status\">\n @if (loading()) {\n <div class=\"tn-autocomplete__loading\">\n <tn-spinner [diameter]=\"16\" [strokeWidth]=\"2\" [ariaLabel]=\"loadingText()\" />\n <span>{{ loadingText() }}</span>\n </div>\n } @else if (!hasResults()) {\n <div class=\"tn-autocomplete__no-results\">\n {{ noResultsText() }}\n </div>\n }\n </div>\n </div>\n</ng-template>\n", styles: [".tn-autocomplete{position:relative;width:100%;font-family:var(--tn-font-family-body, \"Inter\"),sans-serif}.tn-autocomplete__input{display:block;width:100%;min-height:2.5rem;padding:.5rem .75rem;background-color:var(--tn-bg1, #ffffff);border:1px solid var(--tn-lines, #d1d5db);border-radius:.375rem;color:var(--tn-fg1, #212529);font-size:1rem;font-family:inherit;outline:none;box-sizing:border-box;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.tn-autocomplete__input::placeholder{color:var(--tn-alt-fg1, #999)}.tn-autocomplete__input:hover:not(.disabled){border-color:var(--tn-primary, #007bff)}.tn-autocomplete__input:focus-visible,.tn-autocomplete__input.open{border-color:var(--tn-primary, #007bff);box-shadow:0 0 0 2px color-mix(in srgb,var(--tn-primary, #007bff) 25%,transparent)}.tn-autocomplete__input.disabled{background-color:var(--tn-alt-bg1, #f8f9fa);color:var(--tn-fg2, #6c757d);cursor:not-allowed;opacity:.6}.tn-autocomplete__dropdown{background-color:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #d1d5db);border-radius:.375rem;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f;max-height:var(--tn-autocomplete-panel-max-height, 320px);overflow-y:auto;padding:.25rem 0}.tn-autocomplete__option{display:flex;align-items:center;padding:.5rem .75rem;cursor:pointer;color:var(--tn-fg1, #212529);transition:background-color .15s ease-in-out}.tn-autocomplete__option:hover:not(.disabled){background-color:var(--tn-alt-bg2, #f8f9fa)}.tn-autocomplete__option.highlighted{background-color:var(--tn-alt-bg1, #f8f9fa)}.tn-autocomplete__option.disabled{color:var(--tn-fg2, #6c757d);cursor:not-allowed;opacity:.6}.tn-autocomplete__no-results{padding:1rem .75rem;text-align:center;color:var(--tn-fg2, #6c757d);font-style:italic}@media(prefers-reduced-motion:reduce){.tn-autocomplete__input,.tn-autocomplete__option{transition:none}}.tn-autocomplete__loading{align-items:center;color:var(--tn-fg2, #6c757d);display:flex;font-size:.875rem;gap:.5rem;padding:.5rem .75rem}\n"], dependencies: [{ kind: "component", type: TnSpinnerComponent, selector: "tn-spinner", inputs: ["mode", "value", "diameter", "strokeWidth", "ariaLabel", "ariaLabelledby"] }, { kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }] });
|
|
707
838
|
}
|
|
708
839
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnAutocompleteComponent, decorators: [{
|
|
709
840
|
type: Component,
|
|
@@ -713,8 +844,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
|
|
|
713
844
|
useExisting: forwardRef(() => TnAutocompleteComponent),
|
|
714
845
|
multi: true,
|
|
715
846
|
},
|
|
716
|
-
], template: "<div class=\"tn-autocomplete\">\n <input\n #inputEl\n type=\"text\"\n class=\"tn-autocomplete__input\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n tnTestIdType=\"autocomplete\"\n autocomplete=\"off\"\n [tnTestId]=\"testId()\"\n [class.open]=\"isOpen()\"\n [class.disabled]=\"isDisabled()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [value]=\"searchTerm()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-autocomplete]=\"'list'\"\n [attr.aria-controls]=\"isOpen() ? uid + '-dropdown' : null\"\n [attr.aria-owns]=\"isOpen() ? uid + '-dropdown' : null\"\n [attr.aria-activedescendant]=\"highlightedIndex() >= 0 ? uid + '-option-' + highlightedIndex() : null\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onKeydown($event)\" />\n</div>\n\n<!-- Dropdown panel \u2014 portaled via CDK Overlay so it escapes parent\n overflow/clipping. Attach/detach (driven by open()/close()) controls\n visibility; the input keeps DOM focus throughout. -->\n<ng-template #dropdownTemplate>\n <div\n class=\"tn-autocomplete__dropdown\"\n [style.--tn-autocomplete-panel-max-height]=\"panelMaxHeightValue()\"\n (scroll)=\"onPanelScroll($event)\">\n\n <!-- Per ARIA, a listbox may only contain option/group children, so the\n loading and no-results rows live OUTSIDE it as live-region siblings.\n The listbox itself stays rendered (possibly empty) the whole time the\n panel is open, so the input's aria-controls always points at a real\n element \u2014 including the loading-with-no-results-yet state. -->\n <div role=\"listbox\" [attr.id]=\"uid + '-dropdown'\" [attr.aria-busy]=\"loading() ? true : null\">\n @if (hasResults()) {\n @for (option of filteredOptions(); track $index) {\n <div\n class=\"tn-autocomplete__option\"\n role=\"option\"\n tabindex=\"-1\"\n [class.highlighted]=\"highlightedIndex() === $index\"\n [attr.id]=\"uid + '-option-' + $index\"\n [attr.aria-selected]=\"
|
|
717
|
-
}], ctorParameters: () => [], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }],
|
|
847
|
+
], template: "<div class=\"tn-autocomplete\">\n <input\n #inputEl\n type=\"text\"\n class=\"tn-autocomplete__input\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n tnTestIdType=\"autocomplete\"\n autocomplete=\"off\"\n [tnTestId]=\"testId()\"\n [class.open]=\"isOpen()\"\n [class.disabled]=\"isDisabled()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [value]=\"searchTerm()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-autocomplete]=\"'list'\"\n [attr.aria-controls]=\"isOpen() ? uid + '-dropdown' : null\"\n [attr.aria-owns]=\"isOpen() ? uid + '-dropdown' : null\"\n [attr.aria-activedescendant]=\"highlightedIndex() >= 0 ? uid + '-option-' + highlightedIndex() : null\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onKeydown($event)\" />\n</div>\n\n<!-- Dropdown panel \u2014 portaled via CDK Overlay so it escapes parent\n overflow/clipping. Attach/detach (driven by open()/close()) controls\n visibility; the input keeps DOM focus throughout. -->\n<ng-template #dropdownTemplate>\n <div\n class=\"tn-autocomplete__dropdown\"\n [style.--tn-autocomplete-panel-max-height]=\"panelMaxHeightValue()\"\n (scroll)=\"onPanelScroll($event)\">\n\n <!-- Per ARIA, a listbox may only contain option/group children, so the\n loading and no-results rows live OUTSIDE it as live-region siblings.\n The listbox itself stays rendered (possibly empty) the whole time the\n panel is open, so the input's aria-controls always points at a real\n element \u2014 including the loading-with-no-results-yet state. -->\n <div role=\"listbox\" [attr.id]=\"uid + '-dropdown'\" [attr.aria-busy]=\"loading() ? true : null\">\n @if (hasResults()) {\n @for (option of filteredOptions(); track $index) {\n <div\n class=\"tn-autocomplete__option\"\n role=\"option\"\n tabindex=\"-1\"\n [class.highlighted]=\"highlightedIndex() === $index\"\n [class.disabled]=\"option.disabled\"\n [attr.id]=\"uid + '-option-' + $index\"\n [attr.aria-selected]=\"isOptionSelected(option)\"\n [attr.aria-disabled]=\"option.disabled ? true : null\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"onOptionClick(option)\"\n (keydown.enter)=\"onOptionClick(option)\">\n {{ option.label }}\n </div>\n }\n }\n </div>\n\n <div role=\"status\">\n @if (loading()) {\n <div class=\"tn-autocomplete__loading\">\n <tn-spinner [diameter]=\"16\" [strokeWidth]=\"2\" [ariaLabel]=\"loadingText()\" />\n <span>{{ loadingText() }}</span>\n </div>\n } @else if (!hasResults()) {\n <div class=\"tn-autocomplete__no-results\">\n {{ noResultsText() }}\n </div>\n }\n </div>\n </div>\n</ng-template>\n", styles: [".tn-autocomplete{position:relative;width:100%;font-family:var(--tn-font-family-body, \"Inter\"),sans-serif}.tn-autocomplete__input{display:block;width:100%;min-height:2.5rem;padding:.5rem .75rem;background-color:var(--tn-bg1, #ffffff);border:1px solid var(--tn-lines, #d1d5db);border-radius:.375rem;color:var(--tn-fg1, #212529);font-size:1rem;font-family:inherit;outline:none;box-sizing:border-box;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.tn-autocomplete__input::placeholder{color:var(--tn-alt-fg1, #999)}.tn-autocomplete__input:hover:not(.disabled){border-color:var(--tn-primary, #007bff)}.tn-autocomplete__input:focus-visible,.tn-autocomplete__input.open{border-color:var(--tn-primary, #007bff);box-shadow:0 0 0 2px color-mix(in srgb,var(--tn-primary, #007bff) 25%,transparent)}.tn-autocomplete__input.disabled{background-color:var(--tn-alt-bg1, #f8f9fa);color:var(--tn-fg2, #6c757d);cursor:not-allowed;opacity:.6}.tn-autocomplete__dropdown{background-color:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #d1d5db);border-radius:.375rem;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f;max-height:var(--tn-autocomplete-panel-max-height, 320px);overflow-y:auto;padding:.25rem 0}.tn-autocomplete__option{display:flex;align-items:center;padding:.5rem .75rem;cursor:pointer;color:var(--tn-fg1, #212529);transition:background-color .15s ease-in-out}.tn-autocomplete__option:hover:not(.disabled){background-color:var(--tn-alt-bg2, #f8f9fa)}.tn-autocomplete__option.highlighted{background-color:var(--tn-alt-bg1, #f8f9fa)}.tn-autocomplete__option.disabled{color:var(--tn-fg2, #6c757d);cursor:not-allowed;opacity:.6}.tn-autocomplete__no-results{padding:1rem .75rem;text-align:center;color:var(--tn-fg2, #6c757d);font-style:italic}@media(prefers-reduced-motion:reduce){.tn-autocomplete__input,.tn-autocomplete__option{transition:none}}.tn-autocomplete__loading{align-items:center;color:var(--tn-fg2, #6c757d);display:flex;font-size:.875rem;gap:.5rem;padding:.5rem .75rem}\n"] }]
|
|
848
|
+
}], ctorParameters: () => [], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], requireSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "requireSelection", required: false }] }], allowCustomValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowCustomValue", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingText", required: false }] }], filterFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterFn", required: false }] }], noResultsText: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultsText", required: false }] }], maxResults: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxResults", required: false }] }], panelMaxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelMaxHeight", required: false }] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }], optionSelected: [{ type: i0.Output, args: ["optionSelected"] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }], loadMore: [{ type: i0.Output, args: ["loadMore"] }], opened: [{ type: i0.Output, args: ["opened"] }], inputEl: [{ type: i0.ViewChild, args: ['inputEl', { isSignal: true }] }], dropdownTemplate: [{ type: i0.ViewChild, args: ['dropdownTemplate', { isSignal: true }] }] } });
|
|
718
849
|
|
|
719
850
|
/**
|
|
720
851
|
* Harness for interacting with tn-autocomplete in tests.
|
|
@@ -2006,6 +2137,162 @@ class TnBannerHarness extends ComponentHarness {
|
|
|
2006
2137
|
}
|
|
2007
2138
|
}
|
|
2008
2139
|
|
|
2140
|
+
const escapableChars = new Set(['*', '`', '\\']);
|
|
2141
|
+
function isWhitespace(char) {
|
|
2142
|
+
return char !== undefined && /\s/.test(char);
|
|
2143
|
+
}
|
|
2144
|
+
/**
|
|
2145
|
+
* Finds the index of the closing marker (`**` or `*`), honoring backslash
|
|
2146
|
+
* escapes and requiring a non-whitespace character right before the closer
|
|
2147
|
+
* so literal asterisks ("2 * 3", "*.tar") are left alone.
|
|
2148
|
+
*/
|
|
2149
|
+
function findEmphasisCloser(value, start, marker) {
|
|
2150
|
+
let i = start;
|
|
2151
|
+
while (i < value.length) {
|
|
2152
|
+
if (value[i] === '\\' && escapableChars.has(value[i + 1])) {
|
|
2153
|
+
i += 2;
|
|
2154
|
+
continue;
|
|
2155
|
+
}
|
|
2156
|
+
if (value.startsWith(marker, i) && !isWhitespace(value[i - 1])) {
|
|
2157
|
+
return i;
|
|
2158
|
+
}
|
|
2159
|
+
i++;
|
|
2160
|
+
}
|
|
2161
|
+
return -1;
|
|
2162
|
+
}
|
|
2163
|
+
/** Resolves backslash escapes (\*, \`, \\) to their literal characters. */
|
|
2164
|
+
function unescape(value) {
|
|
2165
|
+
let result = '';
|
|
2166
|
+
let i = 0;
|
|
2167
|
+
while (i < value.length) {
|
|
2168
|
+
if (value[i] === '\\' && escapableChars.has(value[i + 1])) {
|
|
2169
|
+
result += value[i + 1];
|
|
2170
|
+
i += 2;
|
|
2171
|
+
}
|
|
2172
|
+
else {
|
|
2173
|
+
result += value[i];
|
|
2174
|
+
i++;
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
return result;
|
|
2178
|
+
}
|
|
2179
|
+
/**
|
|
2180
|
+
* Parses a label string with lightweight markup into flat segments.
|
|
2181
|
+
*
|
|
2182
|
+
* Supported syntax:
|
|
2183
|
+
* - `**bold**` → strong segment
|
|
2184
|
+
* - `*italic*` → em segment
|
|
2185
|
+
* - `` `code` `` → code segment (content taken verbatim)
|
|
2186
|
+
* - `\*`, `` \` ``, `\\` → literal character
|
|
2187
|
+
*
|
|
2188
|
+
* Markup does not nest. Unmatched or whitespace-adjacent markers render
|
|
2189
|
+
* as literal text, so a malformed translation can never break rendering.
|
|
2190
|
+
*/
|
|
2191
|
+
function parseLabelMarkup(value) {
|
|
2192
|
+
const segments = [];
|
|
2193
|
+
let text = '';
|
|
2194
|
+
const flushText = () => {
|
|
2195
|
+
if (text) {
|
|
2196
|
+
segments.push({ type: 'text', text });
|
|
2197
|
+
text = '';
|
|
2198
|
+
}
|
|
2199
|
+
};
|
|
2200
|
+
let i = 0;
|
|
2201
|
+
while (i < value.length) {
|
|
2202
|
+
const char = value[i];
|
|
2203
|
+
if (char === '\\' && escapableChars.has(value[i + 1])) {
|
|
2204
|
+
text += value[i + 1];
|
|
2205
|
+
i += 2;
|
|
2206
|
+
continue;
|
|
2207
|
+
}
|
|
2208
|
+
if (char === '*') {
|
|
2209
|
+
const isBold = value[i + 1] === '*';
|
|
2210
|
+
const marker = isBold ? '**' : '*';
|
|
2211
|
+
const contentStart = i + marker.length;
|
|
2212
|
+
if (!isWhitespace(value[contentStart]) && value[contentStart] !== undefined) {
|
|
2213
|
+
const closer = findEmphasisCloser(value, contentStart, marker);
|
|
2214
|
+
if (closer > contentStart) {
|
|
2215
|
+
flushText();
|
|
2216
|
+
segments.push({
|
|
2217
|
+
type: isBold ? 'strong' : 'em',
|
|
2218
|
+
text: unescape(value.slice(contentStart, closer)),
|
|
2219
|
+
});
|
|
2220
|
+
i = closer + marker.length;
|
|
2221
|
+
continue;
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
text += marker;
|
|
2225
|
+
i += marker.length;
|
|
2226
|
+
continue;
|
|
2227
|
+
}
|
|
2228
|
+
if (char === '`') {
|
|
2229
|
+
const closer = value.indexOf('`', i + 1);
|
|
2230
|
+
if (closer > i + 1) {
|
|
2231
|
+
flushText();
|
|
2232
|
+
segments.push({ type: 'code', text: value.slice(i + 1, closer) });
|
|
2233
|
+
i = closer + 1;
|
|
2234
|
+
continue;
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
text += char;
|
|
2238
|
+
i++;
|
|
2239
|
+
}
|
|
2240
|
+
flushText();
|
|
2241
|
+
return segments;
|
|
2242
|
+
}
|
|
2243
|
+
function escapeHtml(value) {
|
|
2244
|
+
return value
|
|
2245
|
+
.replace(/&/g, '&')
|
|
2246
|
+
.replace(/</g, '<')
|
|
2247
|
+
.replace(/>/g, '>')
|
|
2248
|
+
.replace(/"/g, '"')
|
|
2249
|
+
.replace(/'/g, ''');
|
|
2250
|
+
}
|
|
2251
|
+
/**
|
|
2252
|
+
* Renders label markup to an HTML string safe for [innerHTML] binding:
|
|
2253
|
+
* all text is HTML-escaped and only <strong>, <em> and <code> are emitted.
|
|
2254
|
+
*/
|
|
2255
|
+
function labelMarkupToHtml(value) {
|
|
2256
|
+
return parseLabelMarkup(value)
|
|
2257
|
+
.map((segment) => {
|
|
2258
|
+
const escaped = escapeHtml(segment.text);
|
|
2259
|
+
return segment.type === 'text' ? escaped : `<${segment.type}>${escaped}</${segment.type}>`;
|
|
2260
|
+
})
|
|
2261
|
+
.join('');
|
|
2262
|
+
}
|
|
2263
|
+
/**
|
|
2264
|
+
* Strips label markup, returning plain text for contexts where HTML is not
|
|
2265
|
+
* rendered (aria-label, title attributes, tooltips).
|
|
2266
|
+
*/
|
|
2267
|
+
function labelMarkupToText(value) {
|
|
2268
|
+
return parseLabelMarkup(value)
|
|
2269
|
+
.map((segment) => segment.text)
|
|
2270
|
+
.join('');
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2273
|
+
/**
|
|
2274
|
+
* Renders lightweight label markup (**bold**, *italic*, `code`) to HTML
|
|
2275
|
+
* for [innerHTML] binding. Text is HTML-escaped and only strong/em/code
|
|
2276
|
+
* tags are emitted, so the output is safe by construction.
|
|
2277
|
+
*/
|
|
2278
|
+
class LabelMarkupPipe {
|
|
2279
|
+
transform(label) {
|
|
2280
|
+
if (!label) {
|
|
2281
|
+
return '';
|
|
2282
|
+
}
|
|
2283
|
+
return labelMarkupToHtml(label);
|
|
2284
|
+
}
|
|
2285
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LabelMarkupPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
2286
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: LabelMarkupPipe, isStandalone: true, name: "tnLabelMarkup" });
|
|
2287
|
+
}
|
|
2288
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LabelMarkupPipe, decorators: [{
|
|
2289
|
+
type: Pipe,
|
|
2290
|
+
args: [{
|
|
2291
|
+
name: 'tnLabelMarkup',
|
|
2292
|
+
standalone: true,
|
|
2293
|
+
}]
|
|
2294
|
+
}] });
|
|
2295
|
+
|
|
2009
2296
|
class TnButtonComponent {
|
|
2010
2297
|
size = 'large';
|
|
2011
2298
|
primary = input(false, ...(ngDevMode ? [{ debugName: "primary" }] : []));
|
|
@@ -2120,11 +2407,11 @@ class TnButtonComponent {
|
|
|
2120
2407
|
host.focus = (options) => inner.focus(options);
|
|
2121
2408
|
}
|
|
2122
2409
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2123
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnButtonComponent, isStandalone: true, selector: "tn-button", inputs: { primary: { classPropertyName: "primary", publicName: "primary", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, backgroundColor: { classPropertyName: "backgroundColor", publicName: "backgroundColor", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null }, href: { classPropertyName: "href", publicName: "href", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null }, queryParams: { classPropertyName: "queryParams", publicName: "queryParams", isSignal: true, isRequired: false, transformFunction: null }, fragment: { classPropertyName: "fragment", publicName: "fragment", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null }, rel: { classPropertyName: "rel", publicName: "rel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClick: "onClick" }, viewQueries: [{ propertyName: "innerRef", first: true, predicate: ["button"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (isRouterLink()) {\n <a\n #button\n tnTestIdType=\"button\"\n [ngClass]=\"classes()\"\n [ngStyle]=\"{ 'background-color': backgroundColor() }\"\n [routerLink]=\"disabled() ? null : routerLink()\"\n [queryParams]=\"queryParams()\"\n [fragment]=\"fragment()\"\n [target]=\"target()\"\n [rel]=\"rel()\"\n [attr.aria-disabled]=\"disabled() ? 'true' : null\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.tabindex]=\"disabled() ? -1 : null\"\n [class.is-disabled]=\"disabled()\"\n [tnTestId]=\"testId()\"\n (click)=\"handleAnchorClick($event)\"\n >\n
|
|
2410
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnButtonComponent, isStandalone: true, selector: "tn-button", inputs: { primary: { classPropertyName: "primary", publicName: "primary", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, backgroundColor: { classPropertyName: "backgroundColor", publicName: "backgroundColor", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null }, href: { classPropertyName: "href", publicName: "href", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null }, queryParams: { classPropertyName: "queryParams", publicName: "queryParams", isSignal: true, isRequired: false, transformFunction: null }, fragment: { classPropertyName: "fragment", publicName: "fragment", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null }, rel: { classPropertyName: "rel", publicName: "rel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClick: "onClick" }, viewQueries: [{ propertyName: "innerRef", first: true, predicate: ["button"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (isRouterLink()) {\n <a\n #button\n tnTestIdType=\"button\"\n [ngClass]=\"classes()\"\n [ngStyle]=\"{ 'background-color': backgroundColor() }\"\n [routerLink]=\"disabled() ? null : routerLink()\"\n [queryParams]=\"queryParams()\"\n [fragment]=\"fragment()\"\n [target]=\"target()\"\n [rel]=\"rel()\"\n [attr.aria-disabled]=\"disabled() ? 'true' : null\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.tabindex]=\"disabled() ? -1 : null\"\n [class.is-disabled]=\"disabled()\"\n [tnTestId]=\"testId()\"\n (click)=\"handleAnchorClick($event)\"\n >\n <span [innerHTML]=\"label() | tnLabelMarkup\"></span>\n </a>\n} @else if (isAnchor()) {\n <a\n #button\n tnTestIdType=\"button\"\n [ngClass]=\"classes()\"\n [ngStyle]=\"{ 'background-color': backgroundColor() }\"\n [attr.href]=\"disabled() ? null : href()\"\n [target]=\"target()\"\n [rel]=\"rel()\"\n [attr.aria-disabled]=\"disabled() ? 'true' : null\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.tabindex]=\"disabled() ? -1 : null\"\n [class.is-disabled]=\"disabled()\"\n [tnTestId]=\"testId()\"\n (click)=\"handleAnchorClick($event)\"\n >\n <span [innerHTML]=\"label() | tnLabelMarkup\"></span>\n </a>\n} @else {\n <button\n #button\n tnTestIdType=\"button\"\n [attr.type]=\"type()\"\n [ngClass]=\"classes()\"\n [ngStyle]=\"{ 'background-color': backgroundColor() }\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"ariaLabel()\"\n [tnTestId]=\"testId()\"\n (click)=\"onClick.emit($event)\"\n >\n <span [innerHTML]=\"label() | tnLabelMarkup\"></span>\n </button>\n}\n", styles: [":host{display:inline-block;width:fit-content;justify-self:center}.storybook-button ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.storybook-button{display:inline-block;cursor:pointer;border:0;font-weight:500;line-height:1;font-family:IBM Plex Sans,Helvetica Neue,Helvetica,Arial,sans-serif}.storybook-button:disabled,.storybook-button.is-disabled{opacity:.5;cursor:not-allowed;pointer-events:none}a.storybook-button{text-decoration:none;text-align:center}.button-primary{background-color:var(--tn-primary);color:var(--tn-primary-txt)}.button-default{box-shadow:#00000026 0 0 0 1px inset;background-color:var(--tn-btn-default-bg);color:var(--tn-btn-default-txt)}.button-outline-primary{background-color:transparent;border:1px solid var(--tn-primary);color:var(--tn-primary);transition:background-color .2s ease-in-out,border-color .2s ease-in-out,color .2s ease-in-out}.button-outline-primary:hover{background-color:var(--tn-primary);border:1px solid var(--tn-primary);color:var(--tn-primary-txt)}.button-outline-default{background-color:transparent;border:1px solid var(--tn-lines, #e5e7eb);color:var(--tn-fg1, #000000);transition:background-color .2s ease-in-out,border-color .2s ease-in-out,color .2s ease-in-out}.button-outline-default:hover{background-color:var(--tn-btn-default-bg);border:1px solid var(--tn-btn-default-bg);color:var(--tn-btn-default-txt);box-shadow:#00000026 0 0 0 1px inset}.button-warn{background-color:var(--tn-red);color:#fff}.button-outline-warn{background-color:transparent;border:1px solid var(--tn-red);color:var(--tn-red);transition:background-color .2s ease-in-out,border-color .2s ease-in-out,color .2s ease-in-out}.button-outline-warn:hover{background-color:var(--tn-red);border:1px solid var(--tn-red);color:#fff}.storybook-button--small{padding:10px 16px;font-size:12px}.storybook-button--medium{padding:11px 20px;font-size:14px}.storybook-button--large{padding:12px 24px;font-size:1rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }, { kind: "pipe", type: LabelMarkupPipe, name: "tnLabelMarkup" }] });
|
|
2124
2411
|
}
|
|
2125
2412
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnButtonComponent, decorators: [{
|
|
2126
2413
|
type: Component,
|
|
2127
|
-
args: [{ selector: 'tn-button', standalone: true, imports: [CommonModule, RouterLink, TnTestIdDirective], template: "@if (isRouterLink()) {\n <a\n #button\n tnTestIdType=\"button\"\n [ngClass]=\"classes()\"\n [ngStyle]=\"{ 'background-color': backgroundColor() }\"\n [routerLink]=\"disabled() ? null : routerLink()\"\n [queryParams]=\"queryParams()\"\n [fragment]=\"fragment()\"\n [target]=\"target()\"\n [rel]=\"rel()\"\n [attr.aria-disabled]=\"disabled() ? 'true' : null\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.tabindex]=\"disabled() ? -1 : null\"\n [class.is-disabled]=\"disabled()\"\n [tnTestId]=\"testId()\"\n (click)=\"handleAnchorClick($event)\"\n >\n
|
|
2414
|
+
args: [{ selector: 'tn-button', standalone: true, imports: [CommonModule, RouterLink, TnTestIdDirective, LabelMarkupPipe], template: "@if (isRouterLink()) {\n <a\n #button\n tnTestIdType=\"button\"\n [ngClass]=\"classes()\"\n [ngStyle]=\"{ 'background-color': backgroundColor() }\"\n [routerLink]=\"disabled() ? null : routerLink()\"\n [queryParams]=\"queryParams()\"\n [fragment]=\"fragment()\"\n [target]=\"target()\"\n [rel]=\"rel()\"\n [attr.aria-disabled]=\"disabled() ? 'true' : null\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.tabindex]=\"disabled() ? -1 : null\"\n [class.is-disabled]=\"disabled()\"\n [tnTestId]=\"testId()\"\n (click)=\"handleAnchorClick($event)\"\n >\n <span [innerHTML]=\"label() | tnLabelMarkup\"></span>\n </a>\n} @else if (isAnchor()) {\n <a\n #button\n tnTestIdType=\"button\"\n [ngClass]=\"classes()\"\n [ngStyle]=\"{ 'background-color': backgroundColor() }\"\n [attr.href]=\"disabled() ? null : href()\"\n [target]=\"target()\"\n [rel]=\"rel()\"\n [attr.aria-disabled]=\"disabled() ? 'true' : null\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.tabindex]=\"disabled() ? -1 : null\"\n [class.is-disabled]=\"disabled()\"\n [tnTestId]=\"testId()\"\n (click)=\"handleAnchorClick($event)\"\n >\n <span [innerHTML]=\"label() | tnLabelMarkup\"></span>\n </a>\n} @else {\n <button\n #button\n tnTestIdType=\"button\"\n [attr.type]=\"type()\"\n [ngClass]=\"classes()\"\n [ngStyle]=\"{ 'background-color': backgroundColor() }\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"ariaLabel()\"\n [tnTestId]=\"testId()\"\n (click)=\"onClick.emit($event)\"\n >\n <span [innerHTML]=\"label() | tnLabelMarkup\"></span>\n </button>\n}\n", styles: [":host{display:inline-block;width:fit-content;justify-self:center}.storybook-button ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.storybook-button{display:inline-block;cursor:pointer;border:0;font-weight:500;line-height:1;font-family:IBM Plex Sans,Helvetica Neue,Helvetica,Arial,sans-serif}.storybook-button:disabled,.storybook-button.is-disabled{opacity:.5;cursor:not-allowed;pointer-events:none}a.storybook-button{text-decoration:none;text-align:center}.button-primary{background-color:var(--tn-primary);color:var(--tn-primary-txt)}.button-default{box-shadow:#00000026 0 0 0 1px inset;background-color:var(--tn-btn-default-bg);color:var(--tn-btn-default-txt)}.button-outline-primary{background-color:transparent;border:1px solid var(--tn-primary);color:var(--tn-primary);transition:background-color .2s ease-in-out,border-color .2s ease-in-out,color .2s ease-in-out}.button-outline-primary:hover{background-color:var(--tn-primary);border:1px solid var(--tn-primary);color:var(--tn-primary-txt)}.button-outline-default{background-color:transparent;border:1px solid var(--tn-lines, #e5e7eb);color:var(--tn-fg1, #000000);transition:background-color .2s ease-in-out,border-color .2s ease-in-out,color .2s ease-in-out}.button-outline-default:hover{background-color:var(--tn-btn-default-bg);border:1px solid var(--tn-btn-default-bg);color:var(--tn-btn-default-txt);box-shadow:#00000026 0 0 0 1px inset}.button-warn{background-color:var(--tn-red);color:#fff}.button-outline-warn{background-color:transparent;border:1px solid var(--tn-red);color:var(--tn-red);transition:background-color .2s ease-in-out,border-color .2s ease-in-out,color .2s ease-in-out}.button-outline-warn:hover{background-color:var(--tn-red);border:1px solid var(--tn-red);color:#fff}.storybook-button--small{padding:10px 16px;font-size:12px}.storybook-button--medium{padding:11px 20px;font-size:14px}.storybook-button--large{padding:12px 24px;font-size:1rem}\n"] }]
|
|
2128
2415
|
}], propDecorators: { primary: [{ type: i0.Input, args: [{ isSignal: true, alias: "primary", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], backgroundColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "backgroundColor", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }], href: [{ type: i0.Input, args: [{ isSignal: true, alias: "href", required: false }] }], routerLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLink", required: false }] }], queryParams: [{ type: i0.Input, args: [{ isSignal: true, alias: "queryParams", required: false }] }], fragment: [{ type: i0.Input, args: [{ isSignal: true, alias: "fragment", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }], rel: [{ type: i0.Input, args: [{ isSignal: true, alias: "rel", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], onClick: [{ type: i0.Output, args: ["onClick"] }], innerRef: [{ type: i0.ViewChild, args: ['button', { isSignal: true }] }] } });
|
|
2129
2416
|
|
|
2130
2417
|
/**
|
|
@@ -3837,6 +4124,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
|
|
|
3837
4124
|
}]
|
|
3838
4125
|
}], ctorParameters: () => [] });
|
|
3839
4126
|
|
|
4127
|
+
/**
|
|
4128
|
+
* Strips lightweight label markup (**bold**, *italic*, `code`), returning
|
|
4129
|
+
* plain text for attribute contexts such as aria-label and title.
|
|
4130
|
+
*/
|
|
4131
|
+
class LabelTextPipe {
|
|
4132
|
+
transform(label) {
|
|
4133
|
+
if (!label) {
|
|
4134
|
+
return '';
|
|
4135
|
+
}
|
|
4136
|
+
return labelMarkupToText(label);
|
|
4137
|
+
}
|
|
4138
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LabelTextPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
4139
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: LabelTextPipe, isStandalone: true, name: "tnLabelText" });
|
|
4140
|
+
}
|
|
4141
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LabelTextPipe, decorators: [{
|
|
4142
|
+
type: Pipe,
|
|
4143
|
+
args: [{
|
|
4144
|
+
name: 'tnLabelText',
|
|
4145
|
+
standalone: true,
|
|
4146
|
+
}]
|
|
4147
|
+
}] });
|
|
4148
|
+
|
|
3840
4149
|
class TnChipComponent {
|
|
3841
4150
|
chipEl = viewChild.required('chipEl');
|
|
3842
4151
|
label = input('Chip', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
@@ -3891,11 +4200,11 @@ class TnChipComponent {
|
|
|
3891
4200
|
}
|
|
3892
4201
|
}
|
|
3893
4202
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnChipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3894
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnChipComponent, isStandalone: true, selector: "tn-chip", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClose: "onClose", onClick: "onClick" }, viewQueries: [{ propertyName: "chipEl", first: true, predicate: ["chipEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #chipEl\n role=\"button\"\n tnTestIdType=\"chip\"\n [ngClass]=\"classes()\"\n [tnTestId]=\"testId()\"\n [attr.aria-label]=\"label()\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n (click)=\"handleClick($event)\"\n (keydown)=\"handleKeyDown($event)\"\n>\n @if (icon()) {\n <tn-icon class=\"tn-chip__icon\" size=\"sm\" [name]=\"icon()!\" />\n }\n <span class=\"tn-chip__label\"
|
|
4203
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnChipComponent, isStandalone: true, selector: "tn-chip", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClose: "onClose", onClick: "onClick" }, viewQueries: [{ propertyName: "chipEl", first: true, predicate: ["chipEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #chipEl\n role=\"button\"\n tnTestIdType=\"chip\"\n [ngClass]=\"classes()\"\n [tnTestId]=\"testId()\"\n [attr.aria-label]=\"label() | tnLabelText\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n (click)=\"handleClick($event)\"\n (keydown)=\"handleKeyDown($event)\"\n>\n @if (icon()) {\n <tn-icon class=\"tn-chip__icon\" size=\"sm\" [name]=\"icon()!\" />\n }\n <span class=\"tn-chip__label\" [innerHTML]=\"label() | tnLabelMarkup\"></span>\n @if (closable()) {\n <button\n type=\"button\"\n class=\"tn-chip__close\"\n [attr.aria-label]=\"'Remove ' + (label() | tnLabelText)\"\n [disabled]=\"disabled()\"\n (click)=\"handleClose($event)\"\n >\n <span class=\"tn-chip__close-icon\">\u00D7</span>\n </button>\n }\n</div>", styles: [".tn-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border-radius:16px;font-family:var(--tn-font-family-body);font-size:14px;font-weight:500;line-height:1.2;cursor:pointer;transition:all .2s ease-in-out;border:1px solid transparent;outline:none;-webkit-user-select:none;user-select:none}.tn-chip:focus-visible{outline:2px solid var(--tn-primary);outline-offset:2px}.tn-chip:hover:not(.tn-chip--disabled){transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}.tn-chip--primary{background-color:var(--tn-primary);color:var(--tn-primary-txt);border-color:var(--tn-primary)}.tn-chip--primary:hover:not(.tn-chip--disabled){background-color:var(--tn-blue);border-color:var(--tn-blue)}.tn-chip--secondary{background-color:var(--tn-alt-bg1);color:var(--tn-alt-fg2);border-color:var(--tn-alt-bg2)}.tn-chip--secondary:hover:not(.tn-chip--disabled){background-color:var(--tn-alt-bg2);border-color:var(--tn-accent)}.tn-chip--accent{background-color:var(--tn-accent);color:var(--tn-fg1);border-color:var(--tn-accent)}.tn-chip--accent:hover:not(.tn-chip--disabled){background-color:var(--tn-alt-bg2);border-color:var(--tn-alt-bg2)}.tn-chip--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.tn-chip--closable{padding-right:8px}.tn-chip__icon{display:flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:12px}.tn-chip__label ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-chip__label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px}.tn-chip__close{display:flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;margin:0;border:none;border-radius:50%;background-color:#fff3;color:inherit;cursor:pointer;transition:background-color .2s ease-in-out;outline:none}.tn-chip__close:hover:not(:disabled){background-color:#ffffff4d}.tn-chip__close:focus-visible{outline:1px solid currentColor;outline-offset:1px}.tn-chip__close:disabled{cursor:not-allowed;opacity:.5}.tn-chip__close-icon{font-size:14px;font-weight:700;line-height:1}.tn-dark .tn-chip--secondary .tn-chip__close{background-color:#0003}.tn-dark .tn-chip--secondary .tn-chip__close:hover:not(:disabled){background-color:#0000004d}.high-contrast .tn-chip{border-width:2px}.high-contrast .tn-chip:focus-visible{outline-width:3px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: A11yModule }, { kind: "component", type: TnIconComponent, selector: "tn-icon", inputs: ["name", "size", "color", "tooltip", "ariaLabel", "library", "testId", "fullSize", "customSize"] }, { kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }, { kind: "pipe", type: LabelMarkupPipe, name: "tnLabelMarkup" }, { kind: "pipe", type: LabelTextPipe, name: "tnLabelText" }] });
|
|
3895
4204
|
}
|
|
3896
4205
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnChipComponent, decorators: [{
|
|
3897
4206
|
type: Component,
|
|
3898
|
-
args: [{ selector: 'tn-chip', standalone: true, imports: [CommonModule, A11yModule, TnIconComponent, TnTestIdDirective], template: "<div\n #chipEl\n role=\"button\"\n tnTestIdType=\"chip\"\n [ngClass]=\"classes()\"\n [tnTestId]=\"testId()\"\n [attr.aria-label]=\"label()\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n (click)=\"handleClick($event)\"\n (keydown)=\"handleKeyDown($event)\"\n>\n @if (icon()) {\n <tn-icon class=\"tn-chip__icon\" size=\"sm\" [name]=\"icon()!\" />\n }\n <span class=\"tn-chip__label\"
|
|
4207
|
+
args: [{ selector: 'tn-chip', standalone: true, imports: [CommonModule, A11yModule, TnIconComponent, TnTestIdDirective, LabelMarkupPipe, LabelTextPipe], template: "<div\n #chipEl\n role=\"button\"\n tnTestIdType=\"chip\"\n [ngClass]=\"classes()\"\n [tnTestId]=\"testId()\"\n [attr.aria-label]=\"label() | tnLabelText\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n (click)=\"handleClick($event)\"\n (keydown)=\"handleKeyDown($event)\"\n>\n @if (icon()) {\n <tn-icon class=\"tn-chip__icon\" size=\"sm\" [name]=\"icon()!\" />\n }\n <span class=\"tn-chip__label\" [innerHTML]=\"label() | tnLabelMarkup\"></span>\n @if (closable()) {\n <button\n type=\"button\"\n class=\"tn-chip__close\"\n [attr.aria-label]=\"'Remove ' + (label() | tnLabelText)\"\n [disabled]=\"disabled()\"\n (click)=\"handleClose($event)\"\n >\n <span class=\"tn-chip__close-icon\">\u00D7</span>\n </button>\n }\n</div>", styles: [".tn-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border-radius:16px;font-family:var(--tn-font-family-body);font-size:14px;font-weight:500;line-height:1.2;cursor:pointer;transition:all .2s ease-in-out;border:1px solid transparent;outline:none;-webkit-user-select:none;user-select:none}.tn-chip:focus-visible{outline:2px solid var(--tn-primary);outline-offset:2px}.tn-chip:hover:not(.tn-chip--disabled){transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}.tn-chip--primary{background-color:var(--tn-primary);color:var(--tn-primary-txt);border-color:var(--tn-primary)}.tn-chip--primary:hover:not(.tn-chip--disabled){background-color:var(--tn-blue);border-color:var(--tn-blue)}.tn-chip--secondary{background-color:var(--tn-alt-bg1);color:var(--tn-alt-fg2);border-color:var(--tn-alt-bg2)}.tn-chip--secondary:hover:not(.tn-chip--disabled){background-color:var(--tn-alt-bg2);border-color:var(--tn-accent)}.tn-chip--accent{background-color:var(--tn-accent);color:var(--tn-fg1);border-color:var(--tn-accent)}.tn-chip--accent:hover:not(.tn-chip--disabled){background-color:var(--tn-alt-bg2);border-color:var(--tn-alt-bg2)}.tn-chip--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.tn-chip--closable{padding-right:8px}.tn-chip__icon{display:flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:12px}.tn-chip__label ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-chip__label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px}.tn-chip__close{display:flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;margin:0;border:none;border-radius:50%;background-color:#fff3;color:inherit;cursor:pointer;transition:background-color .2s ease-in-out;outline:none}.tn-chip__close:hover:not(:disabled){background-color:#ffffff4d}.tn-chip__close:focus-visible{outline:1px solid currentColor;outline-offset:1px}.tn-chip__close:disabled{cursor:not-allowed;opacity:.5}.tn-chip__close-icon{font-size:14px;font-weight:700;line-height:1}.tn-dark .tn-chip--secondary .tn-chip__close{background-color:#0003}.tn-dark .tn-chip--secondary .tn-chip__close:hover:not(:disabled){background-color:#0000004d}.high-contrast .tn-chip{border-width:2px}.high-contrast .tn-chip:focus-visible{outline-width:3px}\n"] }]
|
|
3899
4208
|
}], propDecorators: { chipEl: [{ type: i0.ViewChild, args: ['chipEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], closable: [{ type: i0.Input, args: [{ isSignal: true, alias: "closable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }], onClose: [{ type: i0.Output, args: ["onClose"] }], onClick: [{ type: i0.Output, args: ["onClick"] }] } });
|
|
3900
4209
|
|
|
3901
4210
|
class TnCardHeaderDirective {
|
|
@@ -4309,7 +4618,7 @@ class TnMenuPanelComponent {
|
|
|
4309
4618
|
return item.id;
|
|
4310
4619
|
}
|
|
4311
4620
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnMenuPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4312
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnMenuPanelComponent, isStandalone: true, selector: "tn-menu-panel", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, projectedItems: { classPropertyName: "projectedItems", publicName: "projectedItems", isSignal: true, isRequired: false, transformFunction: null }, nested: { classPropertyName: "nested", publicName: "nested", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"tn-menu\" cdkMenu tnMenuActivateHover [class.tn-menu--nested]=\"nested()\">\n <!--\n Projected <tn-menu-item> entries (root panel only) render as sibling\n cdkMenuItem buttons so they participate in CdkMenu's keyboard navigation\n (arrow keys, Home/End, type-ahead) alongside the items() array below.\n -->\n @for (projected of projectedItems(); track projected) {\n <button\n cdkMenuItem\n class=\"tn-menu-item\"\n type=\"button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"projected.resolvedTestId()\"\n [disabled]=\"projected.disabled()\"\n [cdkMenuItemDisabled]=\"projected.disabled()\"\n [class.disabled]=\"projected.disabled()\"\n [class.tn-menu-item--selected]=\"projected.selected()\"\n [attr.aria-current]=\"projected.selected() ? 'true' : null\"\n (click)=\"onProjectedClick(projected, $event)\"\n >\n @if (projected.label() !== undefined) {\n @if (projected.icon()) {\n <tn-icon size=\"sm\" class=\"tn-menu-item-icon\" [name]=\"projected.icon()!\" [library]=\"projected.iconLibrary()\" />\n }\n <span class=\"tn-menu-item-label\"
|
|
4621
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnMenuPanelComponent, isStandalone: true, selector: "tn-menu-panel", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, projectedItems: { classPropertyName: "projectedItems", publicName: "projectedItems", isSignal: true, isRequired: false, transformFunction: null }, nested: { classPropertyName: "nested", publicName: "nested", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"tn-menu\" cdkMenu tnMenuActivateHover [class.tn-menu--nested]=\"nested()\">\n <!--\n Projected <tn-menu-item> entries (root panel only) render as sibling\n cdkMenuItem buttons so they participate in CdkMenu's keyboard navigation\n (arrow keys, Home/End, type-ahead) alongside the items() array below.\n -->\n @for (projected of projectedItems(); track projected) {\n <button\n cdkMenuItem\n class=\"tn-menu-item\"\n type=\"button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"projected.resolvedTestId()\"\n [disabled]=\"projected.disabled()\"\n [cdkMenuItemDisabled]=\"projected.disabled()\"\n [class.disabled]=\"projected.disabled()\"\n [class.tn-menu-item--selected]=\"projected.selected()\"\n [attr.aria-current]=\"projected.selected() ? 'true' : null\"\n (click)=\"onProjectedClick(projected, $event)\"\n >\n @if (projected.label() !== undefined) {\n @if (projected.icon()) {\n <tn-icon size=\"sm\" class=\"tn-menu-item-icon\" [name]=\"projected.icon()!\" [library]=\"projected.iconLibrary()\" />\n }\n <span class=\"tn-menu-item-label\" [innerHTML]=\"projected.label() | tnLabelMarkup\"></span>\n @if (projected.shortcut()) {\n <span class=\"tn-menu-item-shortcut\">{{ projected.shortcut() }}</span>\n }\n } @else {\n <ng-container [ngTemplateOutlet]=\"projected.content()\" />\n }\n </button>\n }\n\n @for (item of items(); track trackByItemId($index, item)) {\n @if (item.separator) {\n <div class=\"tn-menu-separator\" role=\"separator\"></div>\n } @else if (!item.children || item.children.length === 0) {\n <button\n cdkMenuItem\n class=\"tn-menu-item\"\n type=\"button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"resolvedItemTestId(item)\"\n [disabled]=\"item.disabled\"\n [cdkMenuItemDisabled]=\"!!item.disabled\"\n [class.disabled]=\"item.disabled\"\n [class.tn-menu-item--selected]=\"item.selected\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n (click)=\"onItemClick(item)\"\n >\n @if (item.icon) {\n <tn-icon size=\"sm\" class=\"tn-menu-item-icon\" [name]=\"item.icon!\" [library]=\"item.iconLibrary\" />\n }\n <span class=\"tn-menu-item-label\" [innerHTML]=\"item.label | tnLabelMarkup\"></span>\n @if (item.shortcut) {\n <span class=\"tn-menu-item-shortcut\">{{ item.shortcut }}</span>\n }\n </button>\n } @else {\n <button\n cdkMenuItem\n class=\"tn-menu-item tn-menu-item--nested\"\n type=\"button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"resolvedItemTestId(item)\"\n [cdkMenuTriggerFor]=\"submenuTpl\"\n [disabled]=\"item.disabled\"\n [cdkMenuItemDisabled]=\"!!item.disabled\"\n [class.disabled]=\"item.disabled\"\n [class.tn-menu-item--selected]=\"item.selected\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n >\n @if (item.icon) {\n <tn-icon size=\"sm\" class=\"tn-menu-item-icon\" [name]=\"item.icon!\" [library]=\"item.iconLibrary\" />\n }\n <span class=\"tn-menu-item-label\" [innerHTML]=\"item.label | tnLabelMarkup\"></span>\n @if (item.shortcut) {\n <span class=\"tn-menu-item-shortcut\">{{ item.shortcut }}</span>\n }\n <span class=\"tn-menu-item-arrow\">\u25B6</span>\n </button>\n\n <ng-template #submenuTpl>\n <tn-menu-panel [items]=\"item.children!\" [nested]=\"true\" />\n </ng-template>\n }\n }\n</div>\n", styles: [".tn-menu-container{display:inline-block;position:relative}.tn-menu-container.tn-menu-container--context{display:block;width:100%;height:100%;cursor:context-menu}.tn-menu-trigger{display:flex;align-items:center;gap:8px;padding:8px 16px;background:var(--tn-bg1, #ffffff);border:1px solid var(--tn-lines, #e0e0e0);border-radius:4px;color:var(--tn-fg1, #333333);cursor:pointer;font-size:14px;transition:all .2s ease}.tn-menu-trigger:hover:not(.disabled){background:var(--tn-bg2, #f5f5f5);border-color:var(--tn-lines, #cccccc)}.tn-menu-trigger:focus{outline:2px solid var(--tn-primary, #007bff);outline-offset:2px}.tn-menu-trigger.disabled{opacity:.5;cursor:not-allowed}.tn-menu-arrow{font-size:12px;transition:transform .2s ease}.tn-menu-arrow.tn-menu-arrow--up{transform:rotate(180deg)}.tn-menu{display:flex;flex-direction:column;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #e0e0e0);border-radius:4px;box-shadow:0 8px 24px #00000026,0 4px 8px #0000001a;min-width:160px;max-width:300px;padding:4px 0;z-index:1000}.tn-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 16px;border:none;background:transparent;color:var(--tn-fg1, #333333);cursor:pointer;font-size:14px;text-align:left;transition:background-color .2s ease}.tn-menu-item:hover:not(.disabled){background:var(--tn-alt-bg2, #e8f4fd)!important}.tn-menu-item:focus{outline:none;background:var(--tn-alt-bg2, #e8f4fd)}.tn-menu-item[aria-selected=true]{background:var(--tn-alt-bg2, #e8f4fd)}.tn-menu-item.tn-menu-item--selected{background:var(--tn-alt-bg2, #e8f4fd);font-weight:600;color:var(--tn-primary, #007bff)}.tn-menu-item.disabled{opacity:.5;cursor:not-allowed}.tn-menu-item.disabled:hover{background:transparent!important}.tn-menu-item-icon{font-size:1rem;width:16px;text-align:center}.tn-menu-item-label ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-menu-item-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tn-menu-item-shortcut{font-size:12px;color:var(--tn-fg2, #666666);margin-left:auto;padding-left:16px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-weight:400;opacity:.7}.tn-menu-item-arrow{font-size:10px;margin-left:8px;color:var(--tn-fg2, #666666);transition:transform .2s ease;flex-shrink:0}.tn-menu-item--nested{position:relative}.tn-menu-item--nested:hover .tn-menu-item-arrow{color:var(--tn-fg1, #333333)}.tn-menu-separator{height:1px;background:var(--tn-lines, #e0e0e0);margin:4px 0}.tn-menu--nested{margin-left:4px;box-shadow:0 8px 24px #00000026,0 4px 8px #0000001a;border-radius:4px}.tn-menu-context-content{width:100%;height:100%}.tn-menu-context-content:hover:before{content:\"\";position:absolute;inset:0;background:rgba(var(--tn-primary-rgb, 0, 123, 255),.05);pointer-events:none;border:1px dashed rgba(var(--tn-primary-rgb, 0, 123, 255),.3);border-radius:4px}\n"], dependencies: [{ kind: "component", type: i0.forwardRef(() => TnMenuPanelComponent), selector: "tn-menu-panel", inputs: ["items", "projectedItems", "nested"] }, { kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "directive", type: i0.forwardRef(() => i1$2.NgTemplateOutlet), selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i0.forwardRef(() => CdkMenu), selector: "[cdkMenu]", outputs: ["closed"], exportAs: ["cdkMenu"] }, { kind: "directive", type: i0.forwardRef(() => CdkMenuItem), selector: "[cdkMenuItem]", inputs: ["cdkMenuItemDisabled", "cdkMenuitemTypeaheadLabel"], outputs: ["cdkMenuItemTriggered"], exportAs: ["cdkMenuItem"] }, { kind: "directive", type: i0.forwardRef(() => CdkMenuTrigger), selector: "[cdkMenuTriggerFor]", inputs: ["cdkMenuTriggerFor", "cdkMenuPosition", "cdkMenuTriggerData", "cdkMenuTriggerTransformOriginOn"], outputs: ["cdkMenuOpened", "cdkMenuClosed"], exportAs: ["cdkMenuTriggerFor"] }, { kind: "component", type: i0.forwardRef(() => TnIconComponent), selector: "tn-icon", inputs: ["name", "size", "color", "tooltip", "ariaLabel", "library", "testId", "fullSize", "customSize"] }, { kind: "directive", type: i0.forwardRef(() => TnTestIdDirective), selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }, { kind: "directive", type: i0.forwardRef(() => TnMenuActivateHoverDirective), selector: "[tnMenuActivateHover]" }, { kind: "pipe", type: i0.forwardRef(() => LabelMarkupPipe), name: "tnLabelMarkup" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4313
4622
|
}
|
|
4314
4623
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnMenuPanelComponent, decorators: [{
|
|
4315
4624
|
type: Component,
|
|
@@ -4321,8 +4630,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
|
|
|
4321
4630
|
TnIconComponent,
|
|
4322
4631
|
TnTestIdDirective,
|
|
4323
4632
|
TnMenuActivateHoverDirective,
|
|
4633
|
+
LabelMarkupPipe,
|
|
4324
4634
|
forwardRef(() => TnMenuPanelComponent),
|
|
4325
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"tn-menu\" cdkMenu tnMenuActivateHover [class.tn-menu--nested]=\"nested()\">\n <!--\n Projected <tn-menu-item> entries (root panel only) render as sibling\n cdkMenuItem buttons so they participate in CdkMenu's keyboard navigation\n (arrow keys, Home/End, type-ahead) alongside the items() array below.\n -->\n @for (projected of projectedItems(); track projected) {\n <button\n cdkMenuItem\n class=\"tn-menu-item\"\n type=\"button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"projected.resolvedTestId()\"\n [disabled]=\"projected.disabled()\"\n [cdkMenuItemDisabled]=\"projected.disabled()\"\n [class.disabled]=\"projected.disabled()\"\n [class.tn-menu-item--selected]=\"projected.selected()\"\n [attr.aria-current]=\"projected.selected() ? 'true' : null\"\n (click)=\"onProjectedClick(projected, $event)\"\n >\n @if (projected.label() !== undefined) {\n @if (projected.icon()) {\n <tn-icon size=\"sm\" class=\"tn-menu-item-icon\" [name]=\"projected.icon()!\" [library]=\"projected.iconLibrary()\" />\n }\n <span class=\"tn-menu-item-label\"
|
|
4635
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"tn-menu\" cdkMenu tnMenuActivateHover [class.tn-menu--nested]=\"nested()\">\n <!--\n Projected <tn-menu-item> entries (root panel only) render as sibling\n cdkMenuItem buttons so they participate in CdkMenu's keyboard navigation\n (arrow keys, Home/End, type-ahead) alongside the items() array below.\n -->\n @for (projected of projectedItems(); track projected) {\n <button\n cdkMenuItem\n class=\"tn-menu-item\"\n type=\"button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"projected.resolvedTestId()\"\n [disabled]=\"projected.disabled()\"\n [cdkMenuItemDisabled]=\"projected.disabled()\"\n [class.disabled]=\"projected.disabled()\"\n [class.tn-menu-item--selected]=\"projected.selected()\"\n [attr.aria-current]=\"projected.selected() ? 'true' : null\"\n (click)=\"onProjectedClick(projected, $event)\"\n >\n @if (projected.label() !== undefined) {\n @if (projected.icon()) {\n <tn-icon size=\"sm\" class=\"tn-menu-item-icon\" [name]=\"projected.icon()!\" [library]=\"projected.iconLibrary()\" />\n }\n <span class=\"tn-menu-item-label\" [innerHTML]=\"projected.label() | tnLabelMarkup\"></span>\n @if (projected.shortcut()) {\n <span class=\"tn-menu-item-shortcut\">{{ projected.shortcut() }}</span>\n }\n } @else {\n <ng-container [ngTemplateOutlet]=\"projected.content()\" />\n }\n </button>\n }\n\n @for (item of items(); track trackByItemId($index, item)) {\n @if (item.separator) {\n <div class=\"tn-menu-separator\" role=\"separator\"></div>\n } @else if (!item.children || item.children.length === 0) {\n <button\n cdkMenuItem\n class=\"tn-menu-item\"\n type=\"button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"resolvedItemTestId(item)\"\n [disabled]=\"item.disabled\"\n [cdkMenuItemDisabled]=\"!!item.disabled\"\n [class.disabled]=\"item.disabled\"\n [class.tn-menu-item--selected]=\"item.selected\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n (click)=\"onItemClick(item)\"\n >\n @if (item.icon) {\n <tn-icon size=\"sm\" class=\"tn-menu-item-icon\" [name]=\"item.icon!\" [library]=\"item.iconLibrary\" />\n }\n <span class=\"tn-menu-item-label\" [innerHTML]=\"item.label | tnLabelMarkup\"></span>\n @if (item.shortcut) {\n <span class=\"tn-menu-item-shortcut\">{{ item.shortcut }}</span>\n }\n </button>\n } @else {\n <button\n cdkMenuItem\n class=\"tn-menu-item tn-menu-item--nested\"\n type=\"button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"resolvedItemTestId(item)\"\n [cdkMenuTriggerFor]=\"submenuTpl\"\n [disabled]=\"item.disabled\"\n [cdkMenuItemDisabled]=\"!!item.disabled\"\n [class.disabled]=\"item.disabled\"\n [class.tn-menu-item--selected]=\"item.selected\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n >\n @if (item.icon) {\n <tn-icon size=\"sm\" class=\"tn-menu-item-icon\" [name]=\"item.icon!\" [library]=\"item.iconLibrary\" />\n }\n <span class=\"tn-menu-item-label\" [innerHTML]=\"item.label | tnLabelMarkup\"></span>\n @if (item.shortcut) {\n <span class=\"tn-menu-item-shortcut\">{{ item.shortcut }}</span>\n }\n <span class=\"tn-menu-item-arrow\">\u25B6</span>\n </button>\n\n <ng-template #submenuTpl>\n <tn-menu-panel [items]=\"item.children!\" [nested]=\"true\" />\n </ng-template>\n }\n }\n</div>\n", styles: [".tn-menu-container{display:inline-block;position:relative}.tn-menu-container.tn-menu-container--context{display:block;width:100%;height:100%;cursor:context-menu}.tn-menu-trigger{display:flex;align-items:center;gap:8px;padding:8px 16px;background:var(--tn-bg1, #ffffff);border:1px solid var(--tn-lines, #e0e0e0);border-radius:4px;color:var(--tn-fg1, #333333);cursor:pointer;font-size:14px;transition:all .2s ease}.tn-menu-trigger:hover:not(.disabled){background:var(--tn-bg2, #f5f5f5);border-color:var(--tn-lines, #cccccc)}.tn-menu-trigger:focus{outline:2px solid var(--tn-primary, #007bff);outline-offset:2px}.tn-menu-trigger.disabled{opacity:.5;cursor:not-allowed}.tn-menu-arrow{font-size:12px;transition:transform .2s ease}.tn-menu-arrow.tn-menu-arrow--up{transform:rotate(180deg)}.tn-menu{display:flex;flex-direction:column;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #e0e0e0);border-radius:4px;box-shadow:0 8px 24px #00000026,0 4px 8px #0000001a;min-width:160px;max-width:300px;padding:4px 0;z-index:1000}.tn-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 16px;border:none;background:transparent;color:var(--tn-fg1, #333333);cursor:pointer;font-size:14px;text-align:left;transition:background-color .2s ease}.tn-menu-item:hover:not(.disabled){background:var(--tn-alt-bg2, #e8f4fd)!important}.tn-menu-item:focus{outline:none;background:var(--tn-alt-bg2, #e8f4fd)}.tn-menu-item[aria-selected=true]{background:var(--tn-alt-bg2, #e8f4fd)}.tn-menu-item.tn-menu-item--selected{background:var(--tn-alt-bg2, #e8f4fd);font-weight:600;color:var(--tn-primary, #007bff)}.tn-menu-item.disabled{opacity:.5;cursor:not-allowed}.tn-menu-item.disabled:hover{background:transparent!important}.tn-menu-item-icon{font-size:1rem;width:16px;text-align:center}.tn-menu-item-label ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-menu-item-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tn-menu-item-shortcut{font-size:12px;color:var(--tn-fg2, #666666);margin-left:auto;padding-left:16px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-weight:400;opacity:.7}.tn-menu-item-arrow{font-size:10px;margin-left:8px;color:var(--tn-fg2, #666666);transition:transform .2s ease;flex-shrink:0}.tn-menu-item--nested{position:relative}.tn-menu-item--nested:hover .tn-menu-item-arrow{color:var(--tn-fg1, #333333)}.tn-menu-separator{height:1px;background:var(--tn-lines, #e0e0e0);margin:4px 0}.tn-menu--nested{margin-left:4px;box-shadow:0 8px 24px #00000026,0 4px 8px #0000001a;border-radius:4px}.tn-menu-context-content{width:100%;height:100%}.tn-menu-context-content:hover:before{content:\"\";position:absolute;inset:0;background:rgba(var(--tn-primary-rgb, 0, 123, 255),.05);pointer-events:none;border:1px dashed rgba(var(--tn-primary-rgb, 0, 123, 255),.3);border-radius:4px}\n"] }]
|
|
4326
4636
|
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], projectedItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "projectedItems", required: false }] }], nested: [{ type: i0.Input, args: [{ isSignal: true, alias: "nested", required: false }] }] } });
|
|
4327
4637
|
|
|
4328
4638
|
class TnMenuComponent {
|
|
@@ -4449,11 +4759,11 @@ class TnMenuComponent {
|
|
|
4449
4759
|
}
|
|
4450
4760
|
}
|
|
4451
4761
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4452
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnMenuComponent, isStandalone: true, selector: "tn-menu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, contextMenu: { classPropertyName: "contextMenu", publicName: "contextMenu", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { menuItemClick: "menuItemClick", menuOpen: "menuOpen", menuClose: "menuClose" }, queries: [{ propertyName: "contentItems", predicate: TnMenuItemComponent, isSignal: true }], viewQueries: [{ propertyName: "menuTemplate", first: true, predicate: ["menuTemplate"], descendants: true, isSignal: true }, { propertyName: "contextMenuTemplate", first: true, predicate: ["contextMenuTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Context menu content slot: anything that isn't a projected <tn-menu-item> -->\n@if (contextMenu()) {\n <div class=\"tn-menu-context-content\" (contextmenu)=\"onContextMenu($event)\">\n <ng-content />\n </div>\n}\n\n<!-- Context menu template for overlay -->\n<ng-template #contextMenuTemplate>\n <tn-menu-panel [items]=\"items()\" />\n</ng-template>\n\n<!-- Regular menu template -->\n<ng-template #menuTemplate>\n <tn-menu-panel [items]=\"items()\" [projectedItems]=\"contentItems()\" />\n</ng-template>\n", styles: [".tn-menu-container{display:inline-block;position:relative}.tn-menu-container.tn-menu-container--context{display:block;width:100%;height:100%;cursor:context-menu}.tn-menu-trigger{display:flex;align-items:center;gap:8px;padding:8px 16px;background:var(--tn-bg1, #ffffff);border:1px solid var(--tn-lines, #e0e0e0);border-radius:4px;color:var(--tn-fg1, #333333);cursor:pointer;font-size:14px;transition:all .2s ease}.tn-menu-trigger:hover:not(.disabled){background:var(--tn-bg2, #f5f5f5);border-color:var(--tn-lines, #cccccc)}.tn-menu-trigger:focus{outline:2px solid var(--tn-primary, #007bff);outline-offset:2px}.tn-menu-trigger.disabled{opacity:.5;cursor:not-allowed}.tn-menu-arrow{font-size:12px;transition:transform .2s ease}.tn-menu-arrow.tn-menu-arrow--up{transform:rotate(180deg)}.tn-menu{display:flex;flex-direction:column;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #e0e0e0);border-radius:4px;box-shadow:0 8px 24px #00000026,0 4px 8px #0000001a;min-width:160px;max-width:300px;padding:4px 0;z-index:1000}.tn-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 16px;border:none;background:transparent;color:var(--tn-fg1, #333333);cursor:pointer;font-size:14px;text-align:left;transition:background-color .2s ease}.tn-menu-item:hover:not(.disabled){background:var(--tn-alt-bg2, #e8f4fd)!important}.tn-menu-item:focus{outline:none;background:var(--tn-alt-bg2, #e8f4fd)}.tn-menu-item[aria-selected=true]{background:var(--tn-alt-bg2, #e8f4fd)}.tn-menu-item.tn-menu-item--selected{background:var(--tn-alt-bg2, #e8f4fd);font-weight:600;color:var(--tn-primary, #007bff)}.tn-menu-item.disabled{opacity:.5;cursor:not-allowed}.tn-menu-item.disabled:hover{background:transparent!important}.tn-menu-item-icon{font-size:1rem;width:16px;text-align:center}.tn-menu-item-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tn-menu-item-shortcut{font-size:12px;color:var(--tn-fg2, #666666);margin-left:auto;padding-left:16px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-weight:400;opacity:.7}.tn-menu-item-arrow{font-size:10px;margin-left:8px;color:var(--tn-fg2, #666666);transition:transform .2s ease;flex-shrink:0}.tn-menu-item--nested{position:relative}.tn-menu-item--nested:hover .tn-menu-item-arrow{color:var(--tn-fg1, #333333)}.tn-menu-separator{height:1px;background:var(--tn-lines, #e0e0e0);margin:4px 0}.tn-menu--nested{margin-left:4px;box-shadow:0 8px 24px #00000026,0 4px 8px #0000001a;border-radius:4px}.tn-menu-context-content{width:100%;height:100%}.tn-menu-context-content:hover:before{content:\"\";position:absolute;inset:0;background:rgba(var(--tn-primary-rgb, 0, 123, 255),.05);pointer-events:none;border:1px dashed rgba(var(--tn-primary-rgb, 0, 123, 255),.3);border-radius:4px}\n"], dependencies: [{ kind: "component", type: TnMenuPanelComponent, selector: "tn-menu-panel", inputs: ["items", "projectedItems", "nested"] }] });
|
|
4762
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnMenuComponent, isStandalone: true, selector: "tn-menu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, contextMenu: { classPropertyName: "contextMenu", publicName: "contextMenu", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { menuItemClick: "menuItemClick", menuOpen: "menuOpen", menuClose: "menuClose" }, queries: [{ propertyName: "contentItems", predicate: TnMenuItemComponent, isSignal: true }], viewQueries: [{ propertyName: "menuTemplate", first: true, predicate: ["menuTemplate"], descendants: true, isSignal: true }, { propertyName: "contextMenuTemplate", first: true, predicate: ["contextMenuTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Context menu content slot: anything that isn't a projected <tn-menu-item> -->\n@if (contextMenu()) {\n <div class=\"tn-menu-context-content\" (contextmenu)=\"onContextMenu($event)\">\n <ng-content />\n </div>\n}\n\n<!-- Context menu template for overlay -->\n<ng-template #contextMenuTemplate>\n <tn-menu-panel [items]=\"items()\" />\n</ng-template>\n\n<!-- Regular menu template -->\n<ng-template #menuTemplate>\n <tn-menu-panel [items]=\"items()\" [projectedItems]=\"contentItems()\" />\n</ng-template>\n", styles: [".tn-menu-container{display:inline-block;position:relative}.tn-menu-container.tn-menu-container--context{display:block;width:100%;height:100%;cursor:context-menu}.tn-menu-trigger{display:flex;align-items:center;gap:8px;padding:8px 16px;background:var(--tn-bg1, #ffffff);border:1px solid var(--tn-lines, #e0e0e0);border-radius:4px;color:var(--tn-fg1, #333333);cursor:pointer;font-size:14px;transition:all .2s ease}.tn-menu-trigger:hover:not(.disabled){background:var(--tn-bg2, #f5f5f5);border-color:var(--tn-lines, #cccccc)}.tn-menu-trigger:focus{outline:2px solid var(--tn-primary, #007bff);outline-offset:2px}.tn-menu-trigger.disabled{opacity:.5;cursor:not-allowed}.tn-menu-arrow{font-size:12px;transition:transform .2s ease}.tn-menu-arrow.tn-menu-arrow--up{transform:rotate(180deg)}.tn-menu{display:flex;flex-direction:column;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #e0e0e0);border-radius:4px;box-shadow:0 8px 24px #00000026,0 4px 8px #0000001a;min-width:160px;max-width:300px;padding:4px 0;z-index:1000}.tn-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 16px;border:none;background:transparent;color:var(--tn-fg1, #333333);cursor:pointer;font-size:14px;text-align:left;transition:background-color .2s ease}.tn-menu-item:hover:not(.disabled){background:var(--tn-alt-bg2, #e8f4fd)!important}.tn-menu-item:focus{outline:none;background:var(--tn-alt-bg2, #e8f4fd)}.tn-menu-item[aria-selected=true]{background:var(--tn-alt-bg2, #e8f4fd)}.tn-menu-item.tn-menu-item--selected{background:var(--tn-alt-bg2, #e8f4fd);font-weight:600;color:var(--tn-primary, #007bff)}.tn-menu-item.disabled{opacity:.5;cursor:not-allowed}.tn-menu-item.disabled:hover{background:transparent!important}.tn-menu-item-icon{font-size:1rem;width:16px;text-align:center}.tn-menu-item-label ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-menu-item-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tn-menu-item-shortcut{font-size:12px;color:var(--tn-fg2, #666666);margin-left:auto;padding-left:16px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-weight:400;opacity:.7}.tn-menu-item-arrow{font-size:10px;margin-left:8px;color:var(--tn-fg2, #666666);transition:transform .2s ease;flex-shrink:0}.tn-menu-item--nested{position:relative}.tn-menu-item--nested:hover .tn-menu-item-arrow{color:var(--tn-fg1, #333333)}.tn-menu-separator{height:1px;background:var(--tn-lines, #e0e0e0);margin:4px 0}.tn-menu--nested{margin-left:4px;box-shadow:0 8px 24px #00000026,0 4px 8px #0000001a;border-radius:4px}.tn-menu-context-content{width:100%;height:100%}.tn-menu-context-content:hover:before{content:\"\";position:absolute;inset:0;background:rgba(var(--tn-primary-rgb, 0, 123, 255),.05);pointer-events:none;border:1px dashed rgba(var(--tn-primary-rgb, 0, 123, 255),.3);border-radius:4px}\n"], dependencies: [{ kind: "component", type: TnMenuPanelComponent, selector: "tn-menu-panel", inputs: ["items", "projectedItems", "nested"] }] });
|
|
4453
4763
|
}
|
|
4454
4764
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnMenuComponent, decorators: [{
|
|
4455
4765
|
type: Component,
|
|
4456
|
-
args: [{ selector: 'tn-menu', standalone: true, imports: [TnMenuPanelComponent], template: "<!-- Context menu content slot: anything that isn't a projected <tn-menu-item> -->\n@if (contextMenu()) {\n <div class=\"tn-menu-context-content\" (contextmenu)=\"onContextMenu($event)\">\n <ng-content />\n </div>\n}\n\n<!-- Context menu template for overlay -->\n<ng-template #contextMenuTemplate>\n <tn-menu-panel [items]=\"items()\" />\n</ng-template>\n\n<!-- Regular menu template -->\n<ng-template #menuTemplate>\n <tn-menu-panel [items]=\"items()\" [projectedItems]=\"contentItems()\" />\n</ng-template>\n", styles: [".tn-menu-container{display:inline-block;position:relative}.tn-menu-container.tn-menu-container--context{display:block;width:100%;height:100%;cursor:context-menu}.tn-menu-trigger{display:flex;align-items:center;gap:8px;padding:8px 16px;background:var(--tn-bg1, #ffffff);border:1px solid var(--tn-lines, #e0e0e0);border-radius:4px;color:var(--tn-fg1, #333333);cursor:pointer;font-size:14px;transition:all .2s ease}.tn-menu-trigger:hover:not(.disabled){background:var(--tn-bg2, #f5f5f5);border-color:var(--tn-lines, #cccccc)}.tn-menu-trigger:focus{outline:2px solid var(--tn-primary, #007bff);outline-offset:2px}.tn-menu-trigger.disabled{opacity:.5;cursor:not-allowed}.tn-menu-arrow{font-size:12px;transition:transform .2s ease}.tn-menu-arrow.tn-menu-arrow--up{transform:rotate(180deg)}.tn-menu{display:flex;flex-direction:column;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #e0e0e0);border-radius:4px;box-shadow:0 8px 24px #00000026,0 4px 8px #0000001a;min-width:160px;max-width:300px;padding:4px 0;z-index:1000}.tn-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 16px;border:none;background:transparent;color:var(--tn-fg1, #333333);cursor:pointer;font-size:14px;text-align:left;transition:background-color .2s ease}.tn-menu-item:hover:not(.disabled){background:var(--tn-alt-bg2, #e8f4fd)!important}.tn-menu-item:focus{outline:none;background:var(--tn-alt-bg2, #e8f4fd)}.tn-menu-item[aria-selected=true]{background:var(--tn-alt-bg2, #e8f4fd)}.tn-menu-item.tn-menu-item--selected{background:var(--tn-alt-bg2, #e8f4fd);font-weight:600;color:var(--tn-primary, #007bff)}.tn-menu-item.disabled{opacity:.5;cursor:not-allowed}.tn-menu-item.disabled:hover{background:transparent!important}.tn-menu-item-icon{font-size:1rem;width:16px;text-align:center}.tn-menu-item-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tn-menu-item-shortcut{font-size:12px;color:var(--tn-fg2, #666666);margin-left:auto;padding-left:16px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-weight:400;opacity:.7}.tn-menu-item-arrow{font-size:10px;margin-left:8px;color:var(--tn-fg2, #666666);transition:transform .2s ease;flex-shrink:0}.tn-menu-item--nested{position:relative}.tn-menu-item--nested:hover .tn-menu-item-arrow{color:var(--tn-fg1, #333333)}.tn-menu-separator{height:1px;background:var(--tn-lines, #e0e0e0);margin:4px 0}.tn-menu--nested{margin-left:4px;box-shadow:0 8px 24px #00000026,0 4px 8px #0000001a;border-radius:4px}.tn-menu-context-content{width:100%;height:100%}.tn-menu-context-content:hover:before{content:\"\";position:absolute;inset:0;background:rgba(var(--tn-primary-rgb, 0, 123, 255),.05);pointer-events:none;border:1px dashed rgba(var(--tn-primary-rgb, 0, 123, 255),.3);border-radius:4px}\n"] }]
|
|
4766
|
+
args: [{ selector: 'tn-menu', standalone: true, imports: [TnMenuPanelComponent], template: "<!-- Context menu content slot: anything that isn't a projected <tn-menu-item> -->\n@if (contextMenu()) {\n <div class=\"tn-menu-context-content\" (contextmenu)=\"onContextMenu($event)\">\n <ng-content />\n </div>\n}\n\n<!-- Context menu template for overlay -->\n<ng-template #contextMenuTemplate>\n <tn-menu-panel [items]=\"items()\" />\n</ng-template>\n\n<!-- Regular menu template -->\n<ng-template #menuTemplate>\n <tn-menu-panel [items]=\"items()\" [projectedItems]=\"contentItems()\" />\n</ng-template>\n", styles: [".tn-menu-container{display:inline-block;position:relative}.tn-menu-container.tn-menu-container--context{display:block;width:100%;height:100%;cursor:context-menu}.tn-menu-trigger{display:flex;align-items:center;gap:8px;padding:8px 16px;background:var(--tn-bg1, #ffffff);border:1px solid var(--tn-lines, #e0e0e0);border-radius:4px;color:var(--tn-fg1, #333333);cursor:pointer;font-size:14px;transition:all .2s ease}.tn-menu-trigger:hover:not(.disabled){background:var(--tn-bg2, #f5f5f5);border-color:var(--tn-lines, #cccccc)}.tn-menu-trigger:focus{outline:2px solid var(--tn-primary, #007bff);outline-offset:2px}.tn-menu-trigger.disabled{opacity:.5;cursor:not-allowed}.tn-menu-arrow{font-size:12px;transition:transform .2s ease}.tn-menu-arrow.tn-menu-arrow--up{transform:rotate(180deg)}.tn-menu{display:flex;flex-direction:column;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #e0e0e0);border-radius:4px;box-shadow:0 8px 24px #00000026,0 4px 8px #0000001a;min-width:160px;max-width:300px;padding:4px 0;z-index:1000}.tn-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 16px;border:none;background:transparent;color:var(--tn-fg1, #333333);cursor:pointer;font-size:14px;text-align:left;transition:background-color .2s ease}.tn-menu-item:hover:not(.disabled){background:var(--tn-alt-bg2, #e8f4fd)!important}.tn-menu-item:focus{outline:none;background:var(--tn-alt-bg2, #e8f4fd)}.tn-menu-item[aria-selected=true]{background:var(--tn-alt-bg2, #e8f4fd)}.tn-menu-item.tn-menu-item--selected{background:var(--tn-alt-bg2, #e8f4fd);font-weight:600;color:var(--tn-primary, #007bff)}.tn-menu-item.disabled{opacity:.5;cursor:not-allowed}.tn-menu-item.disabled:hover{background:transparent!important}.tn-menu-item-icon{font-size:1rem;width:16px;text-align:center}.tn-menu-item-label ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-menu-item-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tn-menu-item-shortcut{font-size:12px;color:var(--tn-fg2, #666666);margin-left:auto;padding-left:16px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-weight:400;opacity:.7}.tn-menu-item-arrow{font-size:10px;margin-left:8px;color:var(--tn-fg2, #666666);transition:transform .2s ease;flex-shrink:0}.tn-menu-item--nested{position:relative}.tn-menu-item--nested:hover .tn-menu-item-arrow{color:var(--tn-fg1, #333333)}.tn-menu-separator{height:1px;background:var(--tn-lines, #e0e0e0);margin:4px 0}.tn-menu--nested{margin-left:4px;box-shadow:0 8px 24px #00000026,0 4px 8px #0000001a;border-radius:4px}.tn-menu-context-content{width:100%;height:100%}.tn-menu-context-content:hover:before{content:\"\";position:absolute;inset:0;background:rgba(var(--tn-primary-rgb, 0, 123, 255),.05);pointer-events:none;border:1px dashed rgba(var(--tn-primary-rgb, 0, 123, 255),.3);border-radius:4px}\n"] }]
|
|
4457
4767
|
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], contextMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "contextMenu", required: false }] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }], menuItemClick: [{ type: i0.Output, args: ["menuItemClick"] }], menuOpen: [{ type: i0.Output, args: ["menuOpen"] }], menuClose: [{ type: i0.Output, args: ["menuClose"] }], menuTemplate: [{ type: i0.ViewChild, args: ['menuTemplate', { isSignal: true }] }], contextMenuTemplate: [{ type: i0.ViewChild, args: ['contextMenuTemplate', { isSignal: true }] }], contentItems: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TnMenuItemComponent), { isSignal: true }] }] } });
|
|
4458
4768
|
|
|
4459
4769
|
class TnSlideToggleComponent {
|
|
@@ -4546,17 +4856,17 @@ class TnSlideToggleComponent {
|
|
|
4546
4856
|
useExisting: forwardRef(() => TnSlideToggleComponent),
|
|
4547
4857
|
multi: true
|
|
4548
4858
|
}
|
|
4549
|
-
], viewQueries: [{ propertyName: "toggleEl", first: true, predicate: ["toggleEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div [ngClass]=\"classes()\">\n <label class=\"tn-slide-toggle__label\" tnTestIdType=\"toggle\" [for]=\"id\" [tnTestId]=\"testId()\">\n\n <!-- Label before toggle -->\n @if (label() && labelPosition() === 'before') {\n <span\n class=\"tn-slide-toggle__label-text tn-slide-toggle__label-text--before\"\n tabindex=\"0\"\n role=\"button\"\n (click)=\"onLabelClick()\"\n (keydown.enter)=\"onLabelClick()\"\n (keydown.space)=\"onLabelClick()\">\n
|
|
4859
|
+
], viewQueries: [{ propertyName: "toggleEl", first: true, predicate: ["toggleEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div [ngClass]=\"classes()\">\n <label class=\"tn-slide-toggle__label\" tnTestIdType=\"toggle\" [for]=\"id\" [tnTestId]=\"testId()\">\n\n <!-- Label before toggle -->\n @if (label() && labelPosition() === 'before') {\n <span\n class=\"tn-slide-toggle__label-text tn-slide-toggle__label-text--before\"\n tabindex=\"0\"\n role=\"button\"\n [innerHTML]=\"label() | tnLabelMarkup\"\n (click)=\"onLabelClick()\"\n (keydown.enter)=\"onLabelClick()\"\n (keydown.space)=\"onLabelClick()\">\n </span>\n }\n\n <!-- Toggle track and thumb -->\n <div class=\"tn-slide-toggle__bar\">\n <input\n #toggleEl\n type=\"checkbox\"\n class=\"tn-slide-toggle__input\"\n [id]=\"id\"\n [checked]=\"effectiveChecked()\"\n [disabled]=\"isDisabled()\"\n [required]=\"required()\"\n [attr.aria-label]=\"effectiveAriaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby()\"\n (change)=\"onToggleChange($event)\"\n />\n\n <div class=\"tn-slide-toggle__track\">\n <div class=\"tn-slide-toggle__track-fill\"></div>\n </div>\n\n <div class=\"tn-slide-toggle__thumb-container\">\n <div class=\"tn-slide-toggle__thumb\">\n <div class=\"tn-slide-toggle__ripple\"></div>\n <!-- State icon -->\n <div class=\"tn-slide-toggle__icon\">\n @if (effectiveChecked()) {\n <svg\n class=\"tn-slide-toggle__check-icon\"\n viewBox=\"0 0 24 24\"\n width=\"16\"\n height=\"16\">\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z\" fill=\"currentColor\"/>\n </svg>\n }\n @if (!effectiveChecked()) {\n <svg\n class=\"tn-slide-toggle__minus-icon\"\n viewBox=\"0 0 24 24\"\n width=\"16\"\n height=\"16\">\n <path d=\"M19 13H5v-2h14v2z\" fill=\"currentColor\"/>\n </svg>\n }\n </div>\n </div>\n </div>\n </div>\n\n <!-- Label after toggle -->\n @if (label() && labelPosition() === 'after') {\n <span\n class=\"tn-slide-toggle__label-text tn-slide-toggle__label-text--after\"\n tabindex=\"0\"\n role=\"button\"\n [innerHTML]=\"label() | tnLabelMarkup\"\n (click)=\"onLabelClick()\"\n (keydown.enter)=\"onLabelClick()\"\n (keydown.space)=\"onLabelClick()\">\n </span>\n }\n\n </label>\n</div>", styles: [".tn-slide-toggle{display:inline-flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;line-height:1;font-family:inherit}.tn-slide-toggle__label{display:flex;align-items:center;cursor:inherit}.tn-slide-toggle__label-text ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-slide-toggle__label-text{font-size:14px;line-height:1.4;color:var(--tn-fg1);transition:color .2s ease}.tn-slide-toggle__label-text--before{margin-right:8px}.tn-slide-toggle__label-text--after{margin-left:8px}.tn-slide-toggle__input{position:absolute;opacity:0;width:0;height:0;margin:0;pointer-events:none}.tn-slide-toggle__input:focus+.tn-slide-toggle__track{box-shadow:0 0 0 2px rgba(var(--tn-primary-rgb, 0, 123, 255),.2)}.tn-slide-toggle__bar{position:relative;display:flex;align-items:center;flex-shrink:0}.tn-slide-toggle__track{position:relative;width:52px;height:32px;border-radius:16px;background-color:var(--tn-lines);border:1px solid transparent;transition:background-color .2s ease,border-color .2s ease;overflow:hidden}.tn-slide-toggle__track-fill{position:absolute;inset:0;border-radius:inherit;background-color:var(--tn-primary, #007cba);opacity:0;transform:scaleX(0);transform-origin:left center;transition:opacity .2s ease,transform .2s ease}.tn-slide-toggle__thumb-container{position:absolute;top:50%;left:4px;transform:translateY(-50%);width:24px;height:24px;transition:transform .2s ease;z-index:1}.tn-slide-toggle__thumb{position:relative;width:24px;height:24px;border-radius:50%;background-color:var(--tn-bg2);border:1px solid var(--tn-lines);box-shadow:0 2px 4px #0003;transition:background-color .2s ease,border-color .2s ease,box-shadow .2s ease;display:flex;align-items:center;justify-content:center}.tn-slide-toggle__ripple{position:absolute;width:40px;height:40px;border-radius:50%;background-color:transparent;top:50%;left:50%;transform:translate(-50%,-50%);opacity:0;transition:opacity .2s ease,background-color .2s ease}.tn-slide-toggle__icon{position:relative;display:flex;align-items:center;justify-content:center;z-index:2;pointer-events:none}.tn-slide-toggle__check-icon,.tn-slide-toggle__minus-icon{transition:opacity .2s ease,transform .2s ease;color:var(--tn-fg2)}.tn-slide-toggle:hover:not(.tn-slide-toggle--disabled) .tn-slide-toggle__ripple{background-color:var(--tn-primary);opacity:.08}.tn-slide-toggle--checked .tn-slide-toggle__track{background-color:var(--tn-primary);opacity:.5}.tn-slide-toggle--checked .tn-slide-toggle__track-fill{opacity:1;transform:scaleX(1)}.tn-slide-toggle--checked .tn-slide-toggle__thumb-container{transform:translateY(-50%) translate(24px)}.tn-slide-toggle--checked .tn-slide-toggle__thumb{background-color:var(--tn-bg2);border-color:var(--tn-primary)}.tn-slide-toggle--checked .tn-slide-toggle__check-icon{color:var(--tn-primary)}.tn-slide-toggle--checked:hover:not(.tn-slide-toggle--disabled) .tn-slide-toggle__ripple{background-color:var(--tn-primary);opacity:.12}.tn-slide-toggle--disabled{cursor:not-allowed;opacity:.6}.tn-slide-toggle--disabled .tn-slide-toggle__label-text{color:var(--tn-alt-fg1)}.tn-slide-toggle--disabled .tn-slide-toggle__track{background-color:var(--tn-alt-bg1)}.tn-slide-toggle--disabled .tn-slide-toggle__thumb{background-color:var(--tn-alt-bg2);border-color:var(--tn-alt-bg1);box-shadow:none}.tn-slide-toggle--disabled.tn-slide-toggle--checked .tn-slide-toggle__track,.tn-slide-toggle--disabled.tn-slide-toggle--checked .tn-slide-toggle__track-fill{background-color:var(--tn-alt-bg1)}.tn-slide-toggle--disabled.tn-slide-toggle--checked .tn-slide-toggle__thumb{background-color:var(--tn-alt-bg2);border-color:var(--tn-alt-bg1)}.tn-slide-toggle--disabled.tn-slide-toggle--checked .tn-slide-toggle__check-icon{color:var(--tn-alt-fg1)}.tn-slide-toggle--disabled:hover .tn-slide-toggle__ripple{opacity:0}.tn-slide-toggle--accent{--tn-primary: var(--tn-accent)}.tn-slide-toggle--warn{--tn-primary: var(--tn-red)}.tn-slide-toggle .tn-slide-toggle__input:focus-visible+.tn-slide-toggle__track{outline:2px solid var(--tn-primary);outline-offset:2px}.tn-slide-toggle:active:not(.tn-slide-toggle--disabled) .tn-slide-toggle__ripple{background-color:var(--tn-primary);opacity:.16;transform:translate(-50%,-50%) scale(1.1)}@media(prefers-contrast:high){.tn-slide-toggle .tn-slide-toggle__track{border-color:var(--tn-fg1)}.tn-slide-toggle .tn-slide-toggle__thumb{border-width:2px}.tn-slide-toggle--disabled .tn-slide-toggle__track,.tn-slide-toggle--disabled .tn-slide-toggle__thumb{border-color:var(--tn-alt-fg1)}}@media(prefers-reduced-motion:reduce){.tn-slide-toggle .tn-slide-toggle__track,.tn-slide-toggle .tn-slide-toggle__track-fill,.tn-slide-toggle .tn-slide-toggle__thumb-container,.tn-slide-toggle .tn-slide-toggle__thumb,.tn-slide-toggle .tn-slide-toggle__ripple{transition:none}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }, { kind: "pipe", type: LabelMarkupPipe, name: "tnLabelMarkup" }] });
|
|
4550
4860
|
}
|
|
4551
4861
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnSlideToggleComponent, decorators: [{
|
|
4552
4862
|
type: Component,
|
|
4553
|
-
args: [{ selector: 'tn-slide-toggle', standalone: true, imports: [CommonModule, FormsModule, A11yModule, TnTestIdDirective], providers: [
|
|
4863
|
+
args: [{ selector: 'tn-slide-toggle', standalone: true, imports: [CommonModule, FormsModule, A11yModule, TnTestIdDirective, LabelMarkupPipe], providers: [
|
|
4554
4864
|
{
|
|
4555
4865
|
provide: NG_VALUE_ACCESSOR,
|
|
4556
4866
|
useExisting: forwardRef(() => TnSlideToggleComponent),
|
|
4557
4867
|
multi: true
|
|
4558
4868
|
}
|
|
4559
|
-
], template: "<div [ngClass]=\"classes()\">\n <label class=\"tn-slide-toggle__label\" tnTestIdType=\"toggle\" [for]=\"id\" [tnTestId]=\"testId()\">\n\n <!-- Label before toggle -->\n @if (label() && labelPosition() === 'before') {\n <span\n class=\"tn-slide-toggle__label-text tn-slide-toggle__label-text--before\"\n tabindex=\"0\"\n role=\"button\"\n (click)=\"onLabelClick()\"\n (keydown.enter)=\"onLabelClick()\"\n (keydown.space)=\"onLabelClick()\">\n
|
|
4869
|
+
], template: "<div [ngClass]=\"classes()\">\n <label class=\"tn-slide-toggle__label\" tnTestIdType=\"toggle\" [for]=\"id\" [tnTestId]=\"testId()\">\n\n <!-- Label before toggle -->\n @if (label() && labelPosition() === 'before') {\n <span\n class=\"tn-slide-toggle__label-text tn-slide-toggle__label-text--before\"\n tabindex=\"0\"\n role=\"button\"\n [innerHTML]=\"label() | tnLabelMarkup\"\n (click)=\"onLabelClick()\"\n (keydown.enter)=\"onLabelClick()\"\n (keydown.space)=\"onLabelClick()\">\n </span>\n }\n\n <!-- Toggle track and thumb -->\n <div class=\"tn-slide-toggle__bar\">\n <input\n #toggleEl\n type=\"checkbox\"\n class=\"tn-slide-toggle__input\"\n [id]=\"id\"\n [checked]=\"effectiveChecked()\"\n [disabled]=\"isDisabled()\"\n [required]=\"required()\"\n [attr.aria-label]=\"effectiveAriaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby()\"\n (change)=\"onToggleChange($event)\"\n />\n\n <div class=\"tn-slide-toggle__track\">\n <div class=\"tn-slide-toggle__track-fill\"></div>\n </div>\n\n <div class=\"tn-slide-toggle__thumb-container\">\n <div class=\"tn-slide-toggle__thumb\">\n <div class=\"tn-slide-toggle__ripple\"></div>\n <!-- State icon -->\n <div class=\"tn-slide-toggle__icon\">\n @if (effectiveChecked()) {\n <svg\n class=\"tn-slide-toggle__check-icon\"\n viewBox=\"0 0 24 24\"\n width=\"16\"\n height=\"16\">\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z\" fill=\"currentColor\"/>\n </svg>\n }\n @if (!effectiveChecked()) {\n <svg\n class=\"tn-slide-toggle__minus-icon\"\n viewBox=\"0 0 24 24\"\n width=\"16\"\n height=\"16\">\n <path d=\"M19 13H5v-2h14v2z\" fill=\"currentColor\"/>\n </svg>\n }\n </div>\n </div>\n </div>\n </div>\n\n <!-- Label after toggle -->\n @if (label() && labelPosition() === 'after') {\n <span\n class=\"tn-slide-toggle__label-text tn-slide-toggle__label-text--after\"\n tabindex=\"0\"\n role=\"button\"\n [innerHTML]=\"label() | tnLabelMarkup\"\n (click)=\"onLabelClick()\"\n (keydown.enter)=\"onLabelClick()\"\n (keydown.space)=\"onLabelClick()\">\n </span>\n }\n\n </label>\n</div>", styles: [".tn-slide-toggle{display:inline-flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;line-height:1;font-family:inherit}.tn-slide-toggle__label{display:flex;align-items:center;cursor:inherit}.tn-slide-toggle__label-text ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-slide-toggle__label-text{font-size:14px;line-height:1.4;color:var(--tn-fg1);transition:color .2s ease}.tn-slide-toggle__label-text--before{margin-right:8px}.tn-slide-toggle__label-text--after{margin-left:8px}.tn-slide-toggle__input{position:absolute;opacity:0;width:0;height:0;margin:0;pointer-events:none}.tn-slide-toggle__input:focus+.tn-slide-toggle__track{box-shadow:0 0 0 2px rgba(var(--tn-primary-rgb, 0, 123, 255),.2)}.tn-slide-toggle__bar{position:relative;display:flex;align-items:center;flex-shrink:0}.tn-slide-toggle__track{position:relative;width:52px;height:32px;border-radius:16px;background-color:var(--tn-lines);border:1px solid transparent;transition:background-color .2s ease,border-color .2s ease;overflow:hidden}.tn-slide-toggle__track-fill{position:absolute;inset:0;border-radius:inherit;background-color:var(--tn-primary, #007cba);opacity:0;transform:scaleX(0);transform-origin:left center;transition:opacity .2s ease,transform .2s ease}.tn-slide-toggle__thumb-container{position:absolute;top:50%;left:4px;transform:translateY(-50%);width:24px;height:24px;transition:transform .2s ease;z-index:1}.tn-slide-toggle__thumb{position:relative;width:24px;height:24px;border-radius:50%;background-color:var(--tn-bg2);border:1px solid var(--tn-lines);box-shadow:0 2px 4px #0003;transition:background-color .2s ease,border-color .2s ease,box-shadow .2s ease;display:flex;align-items:center;justify-content:center}.tn-slide-toggle__ripple{position:absolute;width:40px;height:40px;border-radius:50%;background-color:transparent;top:50%;left:50%;transform:translate(-50%,-50%);opacity:0;transition:opacity .2s ease,background-color .2s ease}.tn-slide-toggle__icon{position:relative;display:flex;align-items:center;justify-content:center;z-index:2;pointer-events:none}.tn-slide-toggle__check-icon,.tn-slide-toggle__minus-icon{transition:opacity .2s ease,transform .2s ease;color:var(--tn-fg2)}.tn-slide-toggle:hover:not(.tn-slide-toggle--disabled) .tn-slide-toggle__ripple{background-color:var(--tn-primary);opacity:.08}.tn-slide-toggle--checked .tn-slide-toggle__track{background-color:var(--tn-primary);opacity:.5}.tn-slide-toggle--checked .tn-slide-toggle__track-fill{opacity:1;transform:scaleX(1)}.tn-slide-toggle--checked .tn-slide-toggle__thumb-container{transform:translateY(-50%) translate(24px)}.tn-slide-toggle--checked .tn-slide-toggle__thumb{background-color:var(--tn-bg2);border-color:var(--tn-primary)}.tn-slide-toggle--checked .tn-slide-toggle__check-icon{color:var(--tn-primary)}.tn-slide-toggle--checked:hover:not(.tn-slide-toggle--disabled) .tn-slide-toggle__ripple{background-color:var(--tn-primary);opacity:.12}.tn-slide-toggle--disabled{cursor:not-allowed;opacity:.6}.tn-slide-toggle--disabled .tn-slide-toggle__label-text{color:var(--tn-alt-fg1)}.tn-slide-toggle--disabled .tn-slide-toggle__track{background-color:var(--tn-alt-bg1)}.tn-slide-toggle--disabled .tn-slide-toggle__thumb{background-color:var(--tn-alt-bg2);border-color:var(--tn-alt-bg1);box-shadow:none}.tn-slide-toggle--disabled.tn-slide-toggle--checked .tn-slide-toggle__track,.tn-slide-toggle--disabled.tn-slide-toggle--checked .tn-slide-toggle__track-fill{background-color:var(--tn-alt-bg1)}.tn-slide-toggle--disabled.tn-slide-toggle--checked .tn-slide-toggle__thumb{background-color:var(--tn-alt-bg2);border-color:var(--tn-alt-bg1)}.tn-slide-toggle--disabled.tn-slide-toggle--checked .tn-slide-toggle__check-icon{color:var(--tn-alt-fg1)}.tn-slide-toggle--disabled:hover .tn-slide-toggle__ripple{opacity:0}.tn-slide-toggle--accent{--tn-primary: var(--tn-accent)}.tn-slide-toggle--warn{--tn-primary: var(--tn-red)}.tn-slide-toggle .tn-slide-toggle__input:focus-visible+.tn-slide-toggle__track{outline:2px solid var(--tn-primary);outline-offset:2px}.tn-slide-toggle:active:not(.tn-slide-toggle--disabled) .tn-slide-toggle__ripple{background-color:var(--tn-primary);opacity:.16;transform:translate(-50%,-50%) scale(1.1)}@media(prefers-contrast:high){.tn-slide-toggle .tn-slide-toggle__track{border-color:var(--tn-fg1)}.tn-slide-toggle .tn-slide-toggle__thumb{border-width:2px}.tn-slide-toggle--disabled .tn-slide-toggle__track,.tn-slide-toggle--disabled .tn-slide-toggle__thumb{border-color:var(--tn-alt-fg1)}}@media(prefers-reduced-motion:reduce){.tn-slide-toggle .tn-slide-toggle__track,.tn-slide-toggle .tn-slide-toggle__track-fill,.tn-slide-toggle .tn-slide-toggle__thumb-container,.tn-slide-toggle .tn-slide-toggle__thumb,.tn-slide-toggle .tn-slide-toggle__ripple{transition:none}}\n"] }]
|
|
4560
4870
|
}], propDecorators: { toggleEl: [{ type: i0.ViewChild, args: ['toggleEl', { isSignal: true }] }], labelPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPosition", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaLabelledby: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabelledby", required: false }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }], change: [{ type: i0.Output, args: ["change"] }], toggleChange: [{ type: i0.Output, args: ["toggleChange"] }] } });
|
|
4561
4871
|
|
|
4562
4872
|
class TnCardComponent {
|
|
@@ -4960,17 +5270,17 @@ class TnCheckboxComponent {
|
|
|
4960
5270
|
useExisting: forwardRef(() => TnCheckboxComponent),
|
|
4961
5271
|
multi: true
|
|
4962
5272
|
}
|
|
4963
|
-
], queries: [{ propertyName: "labelContent", predicate: TnCheckboxLabelDirective, isSignal: true }], viewQueries: [{ propertyName: "checkboxEl", first: true, predicate: ["checkboxEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div [ngClass]=\"classes()\">\n <label class=\"tn-checkbox__label\" tnTestIdType=\"checkbox\" [for]=\"id\" [tnTestId]=\"testId()\">\n <input\n #checkboxEl\n type=\"checkbox\"\n class=\"tn-checkbox__input\"\n [id]=\"id\"\n [checked]=\"effectiveChecked()\"\n [disabled]=\"isDisabled()\"\n [required]=\"required()\"\n [indeterminate]=\"indeterminate()\"\n [attr.aria-label]=\"hasProjectedLabel() ? label() : null\"\n [attr.aria-describedby]=\"error() ? id + '-error' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n (change)=\"onCheckboxChange($event)\"\n />\n <span class=\"tn-checkbox__checkmark\"></span>\n @if (!hideLabel()) {\n <span class=\"tn-checkbox__text\">\n @if (hasProjectedLabel()) {\n <ng-content select=\"[tnCheckboxLabel]\" />\n } @else {\n
|
|
5273
|
+
], queries: [{ propertyName: "labelContent", predicate: TnCheckboxLabelDirective, isSignal: true }], viewQueries: [{ propertyName: "checkboxEl", first: true, predicate: ["checkboxEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div [ngClass]=\"classes()\">\n <label class=\"tn-checkbox__label\" tnTestIdType=\"checkbox\" [for]=\"id\" [tnTestId]=\"testId()\">\n <input\n #checkboxEl\n type=\"checkbox\"\n class=\"tn-checkbox__input\"\n [id]=\"id\"\n [checked]=\"effectiveChecked()\"\n [disabled]=\"isDisabled()\"\n [required]=\"required()\"\n [indeterminate]=\"indeterminate()\"\n [attr.aria-label]=\"hasProjectedLabel() ? (label() | tnLabelText) : null\"\n [attr.aria-describedby]=\"error() ? id + '-error' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n (change)=\"onCheckboxChange($event)\"\n />\n <span class=\"tn-checkbox__checkmark\"></span>\n @if (!hideLabel()) {\n <span class=\"tn-checkbox__text\">\n @if (hasProjectedLabel()) {\n <ng-content select=\"[tnCheckboxLabel]\" />\n } @else {\n <span [innerHTML]=\"label() | tnLabelMarkup\"></span>\n }\n </span>\n }\n </label>\n\n @if (error()) {\n <div\n class=\"tn-checkbox__error\"\n role=\"alert\"\n aria-live=\"polite\"\n [id]=\"id + '-error'\"\n >\n {{ error() }}\n </div>\n }\n</div>", styles: [".tn-checkbox{display:flex;flex-direction:column;gap:4px}.tn-checkbox__label{display:flex;align-items:center;gap:8px;cursor:pointer;-webkit-user-select:none;user-select:none;font-family:var(--tn-font-family-body, \"Inter\", sans-serif);font-size:14px;line-height:1.5;color:var(--tn-fg1, #333)}.tn-checkbox__label:hover:not(.tn-checkbox--disabled) .tn-checkbox__checkmark{border-color:var(--tn-primary, #0095d5)}.tn-checkbox__input{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.tn-checkbox__input:checked~.tn-checkbox__checkmark{background-color:var(--tn-primary, #0095d5);border-color:var(--tn-primary, #0095d5)}.tn-checkbox__input:checked~.tn-checkbox__checkmark:after{display:block}.tn-checkbox__input:indeterminate~.tn-checkbox__checkmark{background-color:var(--tn-primary, #0095d5);border-color:var(--tn-primary, #0095d5)}.tn-checkbox__input:indeterminate~.tn-checkbox__checkmark:after{display:block;content:\"\";left:4px;top:8px;width:8px;height:2px;background:var(--tn-primary-txt, #fff);border-radius:1px;transform:none}.tn-checkbox__input:focus~.tn-checkbox__checkmark{outline:2px solid var(--tn-primary, #0095d5);outline-offset:2px}.tn-checkbox__input:disabled~.tn-checkbox__checkmark{background-color:var(--tn-bg2, #f5f5f5);border-color:var(--tn-lines, #e0e0e0);cursor:not-allowed}.tn-checkbox__input:disabled:checked~.tn-checkbox__checkmark{background-color:var(--tn-lines, #e0e0e0);border-color:var(--tn-lines, #e0e0e0)}.tn-checkbox__checkmark{position:relative;height:16px;width:16px;background-color:var(--tn-bg1, #fff);border:1px solid var(--tn-lines, #ccc);border-radius:2px;transition:all .2s ease;flex-shrink:0}.tn-checkbox__checkmark:after{content:\"\";position:absolute;display:none;left:5px;top:2px;width:4px;height:8px;border:solid var(--tn-primary-txt, #fff);border-width:0 2px 2px 0;transform:rotate(45deg)}.tn-checkbox__text{flex:1;min-width:0}.tn-checkbox__text ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-checkbox__error{color:var(--tn-red, #dc2626);font-size:12px;font-family:var(--tn-font-family-body, \"Inter\", sans-serif);margin-top:4px;display:flex;align-items:center;gap:4px}.tn-checkbox--disabled .tn-checkbox__label{cursor:not-allowed;color:var(--tn-fg2, #666);opacity:.6}.tn-checkbox--disabled .tn-checkbox__text{color:var(--tn-fg2, #666)}.tn-checkbox--error .tn-checkbox__checkmark{border-color:var(--tn-red, #dc2626)}.tn-checkbox--indeterminate .tn-checkbox__checkmark{background-color:var(--tn-primary, #0095d5);border-color:var(--tn-primary, #0095d5)}.tn-checkbox__input:focus-visible~.tn-checkbox__checkmark{outline:2px solid var(--tn-primary, #0095d5);outline-offset:2px}@media(prefers-contrast:high){.tn-checkbox__checkmark{border-width:2px}}@media(prefers-reduced-motion:reduce){.tn-checkbox__checkmark{transition:none}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }, { kind: "pipe", type: LabelMarkupPipe, name: "tnLabelMarkup" }, { kind: "pipe", type: LabelTextPipe, name: "tnLabelText" }] });
|
|
4964
5274
|
}
|
|
4965
5275
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnCheckboxComponent, decorators: [{
|
|
4966
5276
|
type: Component,
|
|
4967
|
-
args: [{ selector: 'tn-checkbox', standalone: true, imports: [CommonModule, FormsModule, A11yModule, TnTestIdDirective], providers: [
|
|
5277
|
+
args: [{ selector: 'tn-checkbox', standalone: true, imports: [CommonModule, FormsModule, A11yModule, TnTestIdDirective, LabelMarkupPipe, LabelTextPipe], providers: [
|
|
4968
5278
|
{
|
|
4969
5279
|
provide: NG_VALUE_ACCESSOR,
|
|
4970
5280
|
useExisting: forwardRef(() => TnCheckboxComponent),
|
|
4971
5281
|
multi: true
|
|
4972
5282
|
}
|
|
4973
|
-
], template: "<div [ngClass]=\"classes()\">\n <label class=\"tn-checkbox__label\" tnTestIdType=\"checkbox\" [for]=\"id\" [tnTestId]=\"testId()\">\n <input\n #checkboxEl\n type=\"checkbox\"\n class=\"tn-checkbox__input\"\n [id]=\"id\"\n [checked]=\"effectiveChecked()\"\n [disabled]=\"isDisabled()\"\n [required]=\"required()\"\n [indeterminate]=\"indeterminate()\"\n [attr.aria-label]=\"hasProjectedLabel() ? label() : null\"\n [attr.aria-describedby]=\"error() ? id + '-error' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n (change)=\"onCheckboxChange($event)\"\n />\n <span class=\"tn-checkbox__checkmark\"></span>\n @if (!hideLabel()) {\n <span class=\"tn-checkbox__text\">\n @if (hasProjectedLabel()) {\n <ng-content select=\"[tnCheckboxLabel]\" />\n } @else {\n
|
|
5283
|
+
], template: "<div [ngClass]=\"classes()\">\n <label class=\"tn-checkbox__label\" tnTestIdType=\"checkbox\" [for]=\"id\" [tnTestId]=\"testId()\">\n <input\n #checkboxEl\n type=\"checkbox\"\n class=\"tn-checkbox__input\"\n [id]=\"id\"\n [checked]=\"effectiveChecked()\"\n [disabled]=\"isDisabled()\"\n [required]=\"required()\"\n [indeterminate]=\"indeterminate()\"\n [attr.aria-label]=\"hasProjectedLabel() ? (label() | tnLabelText) : null\"\n [attr.aria-describedby]=\"error() ? id + '-error' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n (change)=\"onCheckboxChange($event)\"\n />\n <span class=\"tn-checkbox__checkmark\"></span>\n @if (!hideLabel()) {\n <span class=\"tn-checkbox__text\">\n @if (hasProjectedLabel()) {\n <ng-content select=\"[tnCheckboxLabel]\" />\n } @else {\n <span [innerHTML]=\"label() | tnLabelMarkup\"></span>\n }\n </span>\n }\n </label>\n\n @if (error()) {\n <div\n class=\"tn-checkbox__error\"\n role=\"alert\"\n aria-live=\"polite\"\n [id]=\"id + '-error'\"\n >\n {{ error() }}\n </div>\n }\n</div>", styles: [".tn-checkbox{display:flex;flex-direction:column;gap:4px}.tn-checkbox__label{display:flex;align-items:center;gap:8px;cursor:pointer;-webkit-user-select:none;user-select:none;font-family:var(--tn-font-family-body, \"Inter\", sans-serif);font-size:14px;line-height:1.5;color:var(--tn-fg1, #333)}.tn-checkbox__label:hover:not(.tn-checkbox--disabled) .tn-checkbox__checkmark{border-color:var(--tn-primary, #0095d5)}.tn-checkbox__input{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.tn-checkbox__input:checked~.tn-checkbox__checkmark{background-color:var(--tn-primary, #0095d5);border-color:var(--tn-primary, #0095d5)}.tn-checkbox__input:checked~.tn-checkbox__checkmark:after{display:block}.tn-checkbox__input:indeterminate~.tn-checkbox__checkmark{background-color:var(--tn-primary, #0095d5);border-color:var(--tn-primary, #0095d5)}.tn-checkbox__input:indeterminate~.tn-checkbox__checkmark:after{display:block;content:\"\";left:4px;top:8px;width:8px;height:2px;background:var(--tn-primary-txt, #fff);border-radius:1px;transform:none}.tn-checkbox__input:focus~.tn-checkbox__checkmark{outline:2px solid var(--tn-primary, #0095d5);outline-offset:2px}.tn-checkbox__input:disabled~.tn-checkbox__checkmark{background-color:var(--tn-bg2, #f5f5f5);border-color:var(--tn-lines, #e0e0e0);cursor:not-allowed}.tn-checkbox__input:disabled:checked~.tn-checkbox__checkmark{background-color:var(--tn-lines, #e0e0e0);border-color:var(--tn-lines, #e0e0e0)}.tn-checkbox__checkmark{position:relative;height:16px;width:16px;background-color:var(--tn-bg1, #fff);border:1px solid var(--tn-lines, #ccc);border-radius:2px;transition:all .2s ease;flex-shrink:0}.tn-checkbox__checkmark:after{content:\"\";position:absolute;display:none;left:5px;top:2px;width:4px;height:8px;border:solid var(--tn-primary-txt, #fff);border-width:0 2px 2px 0;transform:rotate(45deg)}.tn-checkbox__text{flex:1;min-width:0}.tn-checkbox__text ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-checkbox__error{color:var(--tn-red, #dc2626);font-size:12px;font-family:var(--tn-font-family-body, \"Inter\", sans-serif);margin-top:4px;display:flex;align-items:center;gap:4px}.tn-checkbox--disabled .tn-checkbox__label{cursor:not-allowed;color:var(--tn-fg2, #666);opacity:.6}.tn-checkbox--disabled .tn-checkbox__text{color:var(--tn-fg2, #666)}.tn-checkbox--error .tn-checkbox__checkmark{border-color:var(--tn-red, #dc2626)}.tn-checkbox--indeterminate .tn-checkbox__checkmark{background-color:var(--tn-primary, #0095d5);border-color:var(--tn-primary, #0095d5)}.tn-checkbox__input:focus-visible~.tn-checkbox__checkmark{outline:2px solid var(--tn-primary, #0095d5);outline-offset:2px}@media(prefers-contrast:high){.tn-checkbox__checkmark{border-width:2px}}@media(prefers-reduced-motion:reduce){.tn-checkbox__checkmark{transition:none}}\n"] }]
|
|
4974
5284
|
}], propDecorators: { checkboxEl: [{ type: i0.ViewChild, args: ['checkboxEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hideLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }], change: [{ type: i0.Output, args: ["change"] }], labelContent: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TnCheckboxLabelDirective), { isSignal: true }] }] } });
|
|
4975
5285
|
|
|
4976
5286
|
/**
|
|
@@ -5249,17 +5559,17 @@ class TnRadioComponent {
|
|
|
5249
5559
|
useExisting: forwardRef(() => TnRadioComponent),
|
|
5250
5560
|
multi: true
|
|
5251
5561
|
}
|
|
5252
|
-
], viewQueries: [{ propertyName: "radioEl", first: true, predicate: ["radioEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div [ngClass]=\"classes()\">\n <label class=\"tn-radio__label\" tnTestIdType=\"radio\" [for]=\"id\" [tnTestId]=\"testId()\">\n <input\n #radioEl\n type=\"radio\"\n class=\"tn-radio__input\"\n [id]=\"id\"\n [name]=\"name()\"\n [value]=\"value()\"\n [checked]=\"checked\"\n [disabled]=\"isDisabled()\"\n [required]=\"required()\"\n [attr.aria-describedby]=\"error() ? id + '-error' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n (change)=\"onRadioChange($event)\"\n />\n <span class=\"tn-radio__checkmark\"></span>\n <span class=\"tn-radio__text\"
|
|
5562
|
+
], viewQueries: [{ propertyName: "radioEl", first: true, predicate: ["radioEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div [ngClass]=\"classes()\">\n <label class=\"tn-radio__label\" tnTestIdType=\"radio\" [for]=\"id\" [tnTestId]=\"testId()\">\n <input\n #radioEl\n type=\"radio\"\n class=\"tn-radio__input\"\n [id]=\"id\"\n [name]=\"name()\"\n [value]=\"value()\"\n [checked]=\"checked\"\n [disabled]=\"isDisabled()\"\n [required]=\"required()\"\n [attr.aria-describedby]=\"error() ? id + '-error' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n (change)=\"onRadioChange($event)\"\n />\n <span class=\"tn-radio__checkmark\"></span>\n <span class=\"tn-radio__text\" [innerHTML]=\"label() | tnLabelMarkup\"></span>\n </label>\n\n @if (error()) {\n <div\n class=\"tn-radio__error\"\n role=\"alert\"\n aria-live=\"polite\"\n [id]=\"id + '-error'\"\n >\n {{ error() }}\n </div>\n }\n</div>", styles: [".tn-radio{display:inline-block;margin-bottom:.5rem}.tn-radio__label{display:flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;gap:.5rem}.tn-radio__label:hover .tn-radio__checkmark{border-color:var(--tn-primary, #007cba)}.tn-radio__input{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.tn-radio__input:focus+.tn-radio__checkmark{outline:2px solid var(--tn-primary, #007cba);outline-offset:2px}.tn-radio__input:checked+.tn-radio__checkmark{border-color:var(--tn-primary, #007cba);background-color:var(--tn-primary, #007cba)}.tn-radio__input:checked+.tn-radio__checkmark:after{display:block}.tn-radio__input:disabled+.tn-radio__checkmark{border-color:var(--tn-lines, #e5e7eb);background-color:var(--tn-alt-bg1, #f8f9fa);cursor:not-allowed}.tn-radio__checkmark{position:relative;height:18px;width:18px;border:2px solid var(--tn-lines, #e5e7eb);border-radius:50%;background-color:transparent;transition:all .2s ease;flex-shrink:0}.tn-radio__checkmark:after{content:\"\";position:absolute;display:none;top:50%;left:50%;width:8px;height:8px;border-radius:50%;background-color:#fff;transform:translate(-50%,-50%)}.tn-radio__text ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-radio__text{color:var(--tn-fg1, #000000);font-size:14px;line-height:1.4}.tn-radio__error{margin-top:.25rem;font-size:12px;color:var(--tn-red, #dc3545)}.tn-radio--disabled .tn-radio__label{cursor:not-allowed;opacity:.6}.tn-radio--disabled .tn-radio__text{color:var(--tn-fg2, #6c757d)}.tn-radio--error .tn-radio__checkmark{border-color:var(--tn-red, #dc3545)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }, { kind: "pipe", type: LabelMarkupPipe, name: "tnLabelMarkup" }] });
|
|
5253
5563
|
}
|
|
5254
5564
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnRadioComponent, decorators: [{
|
|
5255
5565
|
type: Component,
|
|
5256
|
-
args: [{ selector: 'tn-radio', standalone: true, imports: [CommonModule, FormsModule, A11yModule, TnTestIdDirective], providers: [
|
|
5566
|
+
args: [{ selector: 'tn-radio', standalone: true, imports: [CommonModule, FormsModule, A11yModule, TnTestIdDirective, LabelMarkupPipe], providers: [
|
|
5257
5567
|
{
|
|
5258
5568
|
provide: NG_VALUE_ACCESSOR,
|
|
5259
5569
|
useExisting: forwardRef(() => TnRadioComponent),
|
|
5260
5570
|
multi: true
|
|
5261
5571
|
}
|
|
5262
|
-
], template: "<div [ngClass]=\"classes()\">\n <label class=\"tn-radio__label\" tnTestIdType=\"radio\" [for]=\"id\" [tnTestId]=\"testId()\">\n <input\n #radioEl\n type=\"radio\"\n class=\"tn-radio__input\"\n [id]=\"id\"\n [name]=\"name()\"\n [value]=\"value()\"\n [checked]=\"checked\"\n [disabled]=\"isDisabled()\"\n [required]=\"required()\"\n [attr.aria-describedby]=\"error() ? id + '-error' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n (change)=\"onRadioChange($event)\"\n />\n <span class=\"tn-radio__checkmark\"></span>\n <span class=\"tn-radio__text\"
|
|
5572
|
+
], template: "<div [ngClass]=\"classes()\">\n <label class=\"tn-radio__label\" tnTestIdType=\"radio\" [for]=\"id\" [tnTestId]=\"testId()\">\n <input\n #radioEl\n type=\"radio\"\n class=\"tn-radio__input\"\n [id]=\"id\"\n [name]=\"name()\"\n [value]=\"value()\"\n [checked]=\"checked\"\n [disabled]=\"isDisabled()\"\n [required]=\"required()\"\n [attr.aria-describedby]=\"error() ? id + '-error' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n (change)=\"onRadioChange($event)\"\n />\n <span class=\"tn-radio__checkmark\"></span>\n <span class=\"tn-radio__text\" [innerHTML]=\"label() | tnLabelMarkup\"></span>\n </label>\n\n @if (error()) {\n <div\n class=\"tn-radio__error\"\n role=\"alert\"\n aria-live=\"polite\"\n [id]=\"id + '-error'\"\n >\n {{ error() }}\n </div>\n }\n</div>", styles: [".tn-radio{display:inline-block;margin-bottom:.5rem}.tn-radio__label{display:flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;gap:.5rem}.tn-radio__label:hover .tn-radio__checkmark{border-color:var(--tn-primary, #007cba)}.tn-radio__input{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.tn-radio__input:focus+.tn-radio__checkmark{outline:2px solid var(--tn-primary, #007cba);outline-offset:2px}.tn-radio__input:checked+.tn-radio__checkmark{border-color:var(--tn-primary, #007cba);background-color:var(--tn-primary, #007cba)}.tn-radio__input:checked+.tn-radio__checkmark:after{display:block}.tn-radio__input:disabled+.tn-radio__checkmark{border-color:var(--tn-lines, #e5e7eb);background-color:var(--tn-alt-bg1, #f8f9fa);cursor:not-allowed}.tn-radio__checkmark{position:relative;height:18px;width:18px;border:2px solid var(--tn-lines, #e5e7eb);border-radius:50%;background-color:transparent;transition:all .2s ease;flex-shrink:0}.tn-radio__checkmark:after{content:\"\";position:absolute;display:none;top:50%;left:50%;width:8px;height:8px;border-radius:50%;background-color:#fff;transform:translate(-50%,-50%)}.tn-radio__text ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-radio__text{color:var(--tn-fg1, #000000);font-size:14px;line-height:1.4}.tn-radio__error{margin-top:.25rem;font-size:12px;color:var(--tn-red, #dc3545)}.tn-radio--disabled .tn-radio__label{cursor:not-allowed;opacity:.6}.tn-radio--disabled .tn-radio__text{color:var(--tn-fg2, #6c757d)}.tn-radio--error .tn-radio__checkmark{border-color:var(--tn-red, #dc3545)}\n"] }]
|
|
5263
5573
|
}], propDecorators: { radioEl: [{ type: i0.ViewChild, args: ['radioEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], change: [{ type: i0.Output, args: ["change"] }] } });
|
|
5264
5574
|
|
|
5265
5575
|
/**
|
|
@@ -5536,11 +5846,11 @@ class TnTabComponent {
|
|
|
5536
5846
|
return !!(this.hasIconContent() || this.iconTemplate() || this.icon());
|
|
5537
5847
|
}, ...(ngDevMode ? [{ debugName: "hasIcon" }] : []));
|
|
5538
5848
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5539
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnTabComponent, isStandalone: true, selector: "tn-tab", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, iconTemplate: { classPropertyName: "iconTemplate", publicName: "iconTemplate", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selected" }, queries: [{ propertyName: "iconContent", first: true, predicate: ["iconContent"], descendants: true, isSignal: true }], ngImport: i0, template: "<button\n role=\"tab\"\n type=\"button\"\n tnTestIdType=\"tab\"\n [ngClass]=\"classes()\"\n [tnTestId]=\"testId()\"\n [attr.aria-selected]=\"isActive()\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.tabindex]=\"tabIndex()\"\n [disabled]=\"disabled()\"\n (click)=\"onClick()\"\n (keydown)=\"onKeydown($event)\"\n>\n @if (hasIcon()) {\n <span class=\"tn-tab__icon\">\n @if (iconContent()) {\n <ng-container *ngTemplateOutlet=\"iconContent()\" />\n } @else if (iconTemplate()) {\n <ng-container *ngTemplateOutlet=\"iconTemplate()\" />\n } @else {\n <span [innerHTML]=\"icon()\"></span>\n }\n </span>\n }\n <span class=\"tn-tab__label\">\n
|
|
5849
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnTabComponent, isStandalone: true, selector: "tn-tab", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, iconTemplate: { classPropertyName: "iconTemplate", publicName: "iconTemplate", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selected" }, queries: [{ propertyName: "iconContent", first: true, predicate: ["iconContent"], descendants: true, isSignal: true }], ngImport: i0, template: "<button\n role=\"tab\"\n type=\"button\"\n tnTestIdType=\"tab\"\n [ngClass]=\"classes()\"\n [tnTestId]=\"testId()\"\n [attr.aria-selected]=\"isActive()\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.tabindex]=\"tabIndex()\"\n [disabled]=\"disabled()\"\n (click)=\"onClick()\"\n (keydown)=\"onKeydown($event)\"\n>\n @if (hasIcon()) {\n <span class=\"tn-tab__icon\">\n @if (iconContent()) {\n <ng-container *ngTemplateOutlet=\"iconContent()\" />\n } @else if (iconTemplate()) {\n <ng-container *ngTemplateOutlet=\"iconTemplate()\" />\n } @else {\n <span [innerHTML]=\"icon()\"></span>\n }\n </span>\n }\n <span class=\"tn-tab__label\">\n <span [innerHTML]=\"label() | tnLabelMarkup\"></span>\n <ng-content />\n </span>\n</button>", styles: [".tn-tab{display:flex;align-items:center;justify-content:flex-start;gap:8px;padding:12px 16px;border:none;border-bottom:none;background:transparent;color:var(--tn-fg2, #666);font-family:var(--tn-font-family-body, \"Inter\", sans-serif);font-size:14px;font-weight:500;line-height:1.5;cursor:pointer;white-space:nowrap;min-width:0;flex-shrink:0}.tn-tab:hover:not(.tn-tab--disabled):not(.tn-tab--active){background-color:var(--tn-alt-bg1, #f5f5f5);color:var(--tn-fg1, #333)}.tn-tab:focus-visible{outline:2px solid var(--tn-primary, #0095d5);outline-offset:-2px;border-radius:4px}.tn-tab--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.tn-tab__icon{display:flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:14px;flex-shrink:0}.tn-tab__label ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-tab__label{display:flex;align-items:center;min-width:0;text-overflow:ellipsis;overflow:hidden}@media(prefers-contrast:high){.tn-tab{border-width:3px}.tn-tab:focus-visible{outline-width:3px}}:host-context(.tn-tabs--vertical){width:100%}:host-context(.tn-tabs--vertical) .tn-tab{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }, { kind: "pipe", type: LabelMarkupPipe, name: "tnLabelMarkup" }] });
|
|
5540
5850
|
}
|
|
5541
5851
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnTabComponent, decorators: [{
|
|
5542
5852
|
type: Component,
|
|
5543
|
-
args: [{ selector: 'tn-tab', standalone: true, imports: [CommonModule, A11yModule, TnTestIdDirective], template: "<button\n role=\"tab\"\n type=\"button\"\n tnTestIdType=\"tab\"\n [ngClass]=\"classes()\"\n [tnTestId]=\"testId()\"\n [attr.aria-selected]=\"isActive()\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.tabindex]=\"tabIndex()\"\n [disabled]=\"disabled()\"\n (click)=\"onClick()\"\n (keydown)=\"onKeydown($event)\"\n>\n @if (hasIcon()) {\n <span class=\"tn-tab__icon\">\n @if (iconContent()) {\n <ng-container *ngTemplateOutlet=\"iconContent()\" />\n } @else if (iconTemplate()) {\n <ng-container *ngTemplateOutlet=\"iconTemplate()\" />\n } @else {\n <span [innerHTML]=\"icon()\"></span>\n }\n </span>\n }\n <span class=\"tn-tab__label\">\n
|
|
5853
|
+
args: [{ selector: 'tn-tab', standalone: true, imports: [CommonModule, A11yModule, TnTestIdDirective, LabelMarkupPipe], template: "<button\n role=\"tab\"\n type=\"button\"\n tnTestIdType=\"tab\"\n [ngClass]=\"classes()\"\n [tnTestId]=\"testId()\"\n [attr.aria-selected]=\"isActive()\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.tabindex]=\"tabIndex()\"\n [disabled]=\"disabled()\"\n (click)=\"onClick()\"\n (keydown)=\"onKeydown($event)\"\n>\n @if (hasIcon()) {\n <span class=\"tn-tab__icon\">\n @if (iconContent()) {\n <ng-container *ngTemplateOutlet=\"iconContent()\" />\n } @else if (iconTemplate()) {\n <ng-container *ngTemplateOutlet=\"iconTemplate()\" />\n } @else {\n <span [innerHTML]=\"icon()\"></span>\n }\n </span>\n }\n <span class=\"tn-tab__label\">\n <span [innerHTML]=\"label() | tnLabelMarkup\"></span>\n <ng-content />\n </span>\n</button>", styles: [".tn-tab{display:flex;align-items:center;justify-content:flex-start;gap:8px;padding:12px 16px;border:none;border-bottom:none;background:transparent;color:var(--tn-fg2, #666);font-family:var(--tn-font-family-body, \"Inter\", sans-serif);font-size:14px;font-weight:500;line-height:1.5;cursor:pointer;white-space:nowrap;min-width:0;flex-shrink:0}.tn-tab:hover:not(.tn-tab--disabled):not(.tn-tab--active){background-color:var(--tn-alt-bg1, #f5f5f5);color:var(--tn-fg1, #333)}.tn-tab:focus-visible{outline:2px solid var(--tn-primary, #0095d5);outline-offset:-2px;border-radius:4px}.tn-tab--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.tn-tab__icon{display:flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:14px;flex-shrink:0}.tn-tab__label ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-tab__label{display:flex;align-items:center;min-width:0;text-overflow:ellipsis;overflow:hidden}@media(prefers-contrast:high){.tn-tab{border-width:3px}.tn-tab:focus-visible{outline-width:3px}}:host-context(.tn-tabs--vertical){width:100%}:host-context(.tn-tabs--vertical) .tn-tab{width:100%}\n"] }]
|
|
5544
5854
|
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], iconTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconTemplate", required: false }] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }], selected: [{ type: i0.Output, args: ["selected"] }], iconContent: [{ type: i0.ContentChild, args: ['iconContent', { isSignal: true }] }] } });
|
|
5545
5855
|
|
|
5546
5856
|
class TnTabPanelComponent {
|
|
@@ -6850,11 +7160,11 @@ class TnFormFieldComponent {
|
|
|
6850
7160
|
return this.subscriptSizing() === 'fixed' || this.showError() || this.showHint();
|
|
6851
7161
|
}, ...(ngDevMode ? [{ debugName: "showSubscript" }] : []));
|
|
6852
7162
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnFormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6853
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnFormFieldComponent, isStandalone: true, selector: "tn-form-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null }, subscriptSizing: { classPropertyName: "subscriptSizing", publicName: "subscriptSizing", isSignal: true, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: true, isRequired: false, transformFunction: null }, tooltipPosition: { classPropertyName: "tooltipPosition", publicName: "tooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, errorMessages: { classPropertyName: "errorMessages", publicName: "errorMessages", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "control", first: true, predicate: NgControl, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"tn-form-field\" tnTestIdType=\"form-field\" [tnTestId]=\"testId()\">\n <!-- Label -->\n @if (label()) {\n <div class=\"tn-form-field-label-row\">\n <label class=\"tn-form-field-label\" [class.required]=\"showRequired()\">\n
|
|
7163
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnFormFieldComponent, isStandalone: true, selector: "tn-form-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null }, subscriptSizing: { classPropertyName: "subscriptSizing", publicName: "subscriptSizing", isSignal: true, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: true, isRequired: false, transformFunction: null }, tooltipPosition: { classPropertyName: "tooltipPosition", publicName: "tooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, errorMessages: { classPropertyName: "errorMessages", publicName: "errorMessages", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "control", first: true, predicate: NgControl, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"tn-form-field\" tnTestIdType=\"form-field\" [tnTestId]=\"testId()\">\n <!-- Label -->\n @if (label()) {\n <div class=\"tn-form-field-label-row\">\n <label class=\"tn-form-field-label\" [class.required]=\"showRequired()\">\n <span [innerHTML]=\"label() | tnLabelMarkup\"></span>\n @if (showRequired()) {\n <span class=\"required-asterisk\" aria-label=\"required\">*</span>\n }\n </label>\n @if (tooltip()) {\n <ng-container [ngTemplateOutlet]=\"tooltipButton\" />\n }\n </div>\n }\n\n <!-- Form Control Content -->\n <div\n class=\"tn-form-field-wrapper\"\n [class.tn-form-field-wrapper--inline]=\"showInlineExtras()\">\n <ng-content />\n @if (showInlineRequired()) {\n <span class=\"required-asterisk\" aria-label=\"required\">*</span>\n }\n @if (showInlineTooltip()) {\n <ng-container [ngTemplateOutlet]=\"tooltipButton\" />\n }\n </div>\n\n <!-- Hint or Error Message -->\n @if (showSubscript()) {\n <div class=\"tn-form-field-subscript\" [class.tn-form-field-subscript-dynamic]=\"subscriptSizing() === 'dynamic'\">\n @if (showError()) {\n <div\n class=\"tn-form-field-error\"\n role=\"alert\"\n aria-live=\"polite\">\n {{ errorMessage() }}\n </div>\n }\n @if (showHint()) {\n <div class=\"tn-form-field-hint\">\n {{ hint() }}\n </div>\n }\n </div>\n }\n</div>\n\n<ng-template #tooltipButton>\n <button\n type=\"button\"\n class=\"tn-form-field-tooltip\"\n [attr.aria-label]=\"tooltip()\"\n [tnTooltip]=\"tooltip()\"\n [tnTooltipPosition]=\"tooltipPosition()\">\n <tn-icon name=\"help-circle\" library=\"mdi\" size=\"sm\" />\n </button>\n</ng-template>\n", styles: [".tn-form-field{display:block;width:100%;font-family:var(--tn-font-family-body, \"Inter\"),sans-serif}.tn-form-field-label-row{display:flex;align-items:center;gap:.375rem;margin-bottom:.5rem}.tn-form-field-label{display:block;font-size:1rem;font-weight:400;color:var(--tn-fg1, #333);line-height:1.4}.tn-form-field-label ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-form-field-label.required .required-asterisk{color:var(--tn-error, #dc3545);margin-left:.25rem}.tn-form-field-tooltip{display:inline-flex;align-items:center;justify-content:center;padding:0;border:none;background:transparent;color:var(--tn-fg2, #6c757d);cursor:help;line-height:0}.tn-form-field-tooltip:hover,.tn-form-field-tooltip:focus-visible{color:var(--tn-primary, #007bff)}.tn-form-field-tooltip:focus-visible{outline:2px solid var(--tn-primary, #007bff);outline-offset:2px;border-radius:50%}.tn-form-field-wrapper{position:relative;width:100%;overflow:visible}.tn-form-field-wrapper :ng-deep .tn-select-container,.tn-form-field-wrapper :ng-deep .tn-input-container{margin-bottom:0}.tn-form-field-wrapper :ng-deep .tn-select-label,.tn-form-field-wrapper :ng-deep .tn-input-label{display:none}.tn-form-field-wrapper :ng-deep .tn-select-error,.tn-form-field-wrapper :ng-deep .tn-input-error{display:none}.tn-form-field-wrapper :ng-deep .tn-select-dropdown{z-index:1000}.tn-form-field-wrapper--inline{align-items:center;display:flex;gap:.375rem}.tn-form-field-wrapper--inline .required-asterisk{color:var(--tn-error, #dc3545)}.tn-form-field-subscript{min-height:1.25rem;margin-top:.25rem;font-size:.75rem;line-height:1.4}.tn-form-field-subscript-dynamic{min-height:0}.tn-form-field-error{color:var(--tn-error, #dc3545);margin:0}.tn-form-field-hint{color:var(--tn-fg2, #6c757d);margin:0}.tn-form-field-wrapper:has(:focus-visible) .tn-form-field-label{color:var(--tn-primary, #007bff)}.tn-form-field-wrapper:has(.error) .tn-form-field-label{color:var(--tn-error, #dc3545)}@media(prefers-reduced-motion:reduce){.tn-form-field-label{transition:none}}@media(prefers-contrast:high){.tn-form-field-label,.tn-form-field-error{font-weight:600}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }, { kind: "component", type: TnIconComponent, selector: "tn-icon", inputs: ["name", "size", "color", "tooltip", "ariaLabel", "library", "testId", "fullSize", "customSize"] }, { kind: "directive", type: TnTooltipDirective, selector: "[tnTooltip]", inputs: ["tnTooltip", "tnTooltipPosition", "tnTooltipDisabled", "tnTooltipShowDelay", "tnTooltipHideDelay", "tnTooltipClass"] }, { kind: "pipe", type: LabelMarkupPipe, name: "tnLabelMarkup" }] });
|
|
6854
7164
|
}
|
|
6855
7165
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnFormFieldComponent, decorators: [{
|
|
6856
7166
|
type: Component,
|
|
6857
|
-
args: [{ selector: 'tn-form-field', standalone: true, imports: [NgTemplateOutlet, TnTestIdDirective, TnIconComponent, TnTooltipDirective], template: "<div class=\"tn-form-field\" tnTestIdType=\"form-field\" [tnTestId]=\"testId()\">\n <!-- Label -->\n @if (label()) {\n <div class=\"tn-form-field-label-row\">\n <label class=\"tn-form-field-label\" [class.required]=\"showRequired()\">\n
|
|
7167
|
+
args: [{ selector: 'tn-form-field', standalone: true, imports: [NgTemplateOutlet, TnTestIdDirective, TnIconComponent, TnTooltipDirective, LabelMarkupPipe], template: "<div class=\"tn-form-field\" tnTestIdType=\"form-field\" [tnTestId]=\"testId()\">\n <!-- Label -->\n @if (label()) {\n <div class=\"tn-form-field-label-row\">\n <label class=\"tn-form-field-label\" [class.required]=\"showRequired()\">\n <span [innerHTML]=\"label() | tnLabelMarkup\"></span>\n @if (showRequired()) {\n <span class=\"required-asterisk\" aria-label=\"required\">*</span>\n }\n </label>\n @if (tooltip()) {\n <ng-container [ngTemplateOutlet]=\"tooltipButton\" />\n }\n </div>\n }\n\n <!-- Form Control Content -->\n <div\n class=\"tn-form-field-wrapper\"\n [class.tn-form-field-wrapper--inline]=\"showInlineExtras()\">\n <ng-content />\n @if (showInlineRequired()) {\n <span class=\"required-asterisk\" aria-label=\"required\">*</span>\n }\n @if (showInlineTooltip()) {\n <ng-container [ngTemplateOutlet]=\"tooltipButton\" />\n }\n </div>\n\n <!-- Hint or Error Message -->\n @if (showSubscript()) {\n <div class=\"tn-form-field-subscript\" [class.tn-form-field-subscript-dynamic]=\"subscriptSizing() === 'dynamic'\">\n @if (showError()) {\n <div\n class=\"tn-form-field-error\"\n role=\"alert\"\n aria-live=\"polite\">\n {{ errorMessage() }}\n </div>\n }\n @if (showHint()) {\n <div class=\"tn-form-field-hint\">\n {{ hint() }}\n </div>\n }\n </div>\n }\n</div>\n\n<ng-template #tooltipButton>\n <button\n type=\"button\"\n class=\"tn-form-field-tooltip\"\n [attr.aria-label]=\"tooltip()\"\n [tnTooltip]=\"tooltip()\"\n [tnTooltipPosition]=\"tooltipPosition()\">\n <tn-icon name=\"help-circle\" library=\"mdi\" size=\"sm\" />\n </button>\n</ng-template>\n", styles: [".tn-form-field{display:block;width:100%;font-family:var(--tn-font-family-body, \"Inter\"),sans-serif}.tn-form-field-label-row{display:flex;align-items:center;gap:.375rem;margin-bottom:.5rem}.tn-form-field-label{display:block;font-size:1rem;font-weight:400;color:var(--tn-fg1, #333);line-height:1.4}.tn-form-field-label ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-form-field-label.required .required-asterisk{color:var(--tn-error, #dc3545);margin-left:.25rem}.tn-form-field-tooltip{display:inline-flex;align-items:center;justify-content:center;padding:0;border:none;background:transparent;color:var(--tn-fg2, #6c757d);cursor:help;line-height:0}.tn-form-field-tooltip:hover,.tn-form-field-tooltip:focus-visible{color:var(--tn-primary, #007bff)}.tn-form-field-tooltip:focus-visible{outline:2px solid var(--tn-primary, #007bff);outline-offset:2px;border-radius:50%}.tn-form-field-wrapper{position:relative;width:100%;overflow:visible}.tn-form-field-wrapper :ng-deep .tn-select-container,.tn-form-field-wrapper :ng-deep .tn-input-container{margin-bottom:0}.tn-form-field-wrapper :ng-deep .tn-select-label,.tn-form-field-wrapper :ng-deep .tn-input-label{display:none}.tn-form-field-wrapper :ng-deep .tn-select-error,.tn-form-field-wrapper :ng-deep .tn-input-error{display:none}.tn-form-field-wrapper :ng-deep .tn-select-dropdown{z-index:1000}.tn-form-field-wrapper--inline{align-items:center;display:flex;gap:.375rem}.tn-form-field-wrapper--inline .required-asterisk{color:var(--tn-error, #dc3545)}.tn-form-field-subscript{min-height:1.25rem;margin-top:.25rem;font-size:.75rem;line-height:1.4}.tn-form-field-subscript-dynamic{min-height:0}.tn-form-field-error{color:var(--tn-error, #dc3545);margin:0}.tn-form-field-hint{color:var(--tn-fg2, #6c757d);margin:0}.tn-form-field-wrapper:has(:focus-visible) .tn-form-field-label{color:var(--tn-primary, #007bff)}.tn-form-field-wrapper:has(.error) .tn-form-field-label{color:var(--tn-error, #dc3545)}@media(prefers-reduced-motion:reduce){.tn-form-field-label{transition:none}}@media(prefers-contrast:high){.tn-form-field-label,.tn-form-field-error{font-weight:600}}\n"] }]
|
|
6858
7168
|
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }], subscriptSizing: [{ type: i0.Input, args: [{ isSignal: true, alias: "subscriptSizing", required: false }] }], tooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltip", required: false }] }], tooltipPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipPosition", required: false }] }], errorMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessages", required: false }] }], control: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NgControl), { isSignal: true }] }] } });
|
|
6859
7169
|
|
|
6860
7170
|
/**
|
|
@@ -14048,7 +14358,7 @@ class TnStepperComponent {
|
|
|
14048
14358
|
return index;
|
|
14049
14359
|
}
|
|
14050
14360
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnStepperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
14051
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnStepperComponent, isStandalone: true, selector: "tn-stepper", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, linear: { classPropertyName: "linear", publicName: "linear", isSignal: true, isRequired: false, transformFunction: null }, selectedIndex: { classPropertyName: "selectedIndex", publicName: "selectedIndex", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedIndex: "selectedIndexChange", selectionChange: "selectionChange", completed: "completed" }, host: { listeners: { "window:resize": "onWindowResize($event)" } }, queries: [{ propertyName: "steps", predicate: TnStepComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"tn-stepper\"\n tnTestIdType=\"stepper\"\n [class.tn-stepper--horizontal]=\"orientation() === 'horizontal' || (orientation() === 'auto' && isWideScreen())\"\n [class.tn-stepper--vertical]=\"orientation() === 'vertical' || (orientation() === 'auto' && !isWideScreen())\"\n [tnTestId]=\"testId()\">\n\n <!-- Step Headers -->\n <div class=\"tn-stepper__header\">\n @for (step of steps(); track $index; let i = $index) {\n <div class=\"tn-stepper__step-header\"\n tabindex=\"0\"\n role=\"button\"\n [class.tn-stepper__step-header--active]=\"selectedIndex() === i\"\n [class.tn-stepper__step-header--completed]=\"step.completed()\"\n [class.tn-stepper__step-header--error]=\"step.hasError()\"\n [class.tn-stepper__step-header--optional]=\"step.optional()\"\n (click)=\"selectStep(i)\"\n (keydown.enter)=\"selectStep(i)\"\n (keydown.space)=\"selectStep(i)\">\n\n <!-- Step Number/Icon -->\n <div class=\"tn-stepper__step-indicator\">\n @if (step.completed() && !step.hasError()) {\n <span class=\"tn-stepper__step-check\">\u2713</span>\n }\n @if (step.hasError()) {\n <span class=\"tn-stepper__step-error\">!</span>\n }\n @if (!step.completed() && !step.hasError()) {\n @if (step.icon()) {\n <span class=\"tn-stepper__step-icon\">{{ step.icon() }}</span>\n } @else {\n <span class=\"tn-stepper__step-number\">{{ i + 1 }}</span>\n }\n }\n </div>\n\n <!-- Step Label -->\n <div class=\"tn-stepper__step-label\">\n <div class=\"tn-stepper__step-title\"
|
|
14361
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnStepperComponent, isStandalone: true, selector: "tn-stepper", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, linear: { classPropertyName: "linear", publicName: "linear", isSignal: true, isRequired: false, transformFunction: null }, selectedIndex: { classPropertyName: "selectedIndex", publicName: "selectedIndex", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedIndex: "selectedIndexChange", selectionChange: "selectionChange", completed: "completed" }, host: { listeners: { "window:resize": "onWindowResize($event)" } }, queries: [{ propertyName: "steps", predicate: TnStepComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"tn-stepper\"\n tnTestIdType=\"stepper\"\n [class.tn-stepper--horizontal]=\"orientation() === 'horizontal' || (orientation() === 'auto' && isWideScreen())\"\n [class.tn-stepper--vertical]=\"orientation() === 'vertical' || (orientation() === 'auto' && !isWideScreen())\"\n [tnTestId]=\"testId()\">\n\n <!-- Step Headers -->\n <div class=\"tn-stepper__header\">\n @for (step of steps(); track $index; let i = $index) {\n <div class=\"tn-stepper__step-header\"\n tabindex=\"0\"\n role=\"button\"\n [class.tn-stepper__step-header--active]=\"selectedIndex() === i\"\n [class.tn-stepper__step-header--completed]=\"step.completed()\"\n [class.tn-stepper__step-header--error]=\"step.hasError()\"\n [class.tn-stepper__step-header--optional]=\"step.optional()\"\n (click)=\"selectStep(i)\"\n (keydown.enter)=\"selectStep(i)\"\n (keydown.space)=\"selectStep(i)\">\n\n <!-- Step Number/Icon -->\n <div class=\"tn-stepper__step-indicator\">\n @if (step.completed() && !step.hasError()) {\n <span class=\"tn-stepper__step-check\">\u2713</span>\n }\n @if (step.hasError()) {\n <span class=\"tn-stepper__step-error\">!</span>\n }\n @if (!step.completed() && !step.hasError()) {\n @if (step.icon()) {\n <span class=\"tn-stepper__step-icon\">{{ step.icon() }}</span>\n } @else {\n <span class=\"tn-stepper__step-number\">{{ i + 1 }}</span>\n }\n }\n </div>\n\n <!-- Step Label -->\n <div class=\"tn-stepper__step-label\">\n <div class=\"tn-stepper__step-title\" [innerHTML]=\"step.label() | tnLabelMarkup\"></div>\n @if (step.optional()) {\n <span class=\"tn-stepper__step-subtitle\">Optional</span>\n }\n </div>\n </div>\n\n <!-- Connector Line (except for last step) -->\n @if (i < steps().length - 1) {\n <div class=\"tn-stepper__connector\"></div>\n }\n }\n </div>\n\n <!-- Step Content -->\n <div class=\"tn-stepper__content\">\n @for (step of steps(); track $index; let i = $index) {\n @if (selectedIndex() === i) {\n <div class=\"tn-stepper__step-content\"\n [@stepTransition]=\"selectedIndex()\">\n <ng-container *ngTemplateOutlet=\"step.content()\" />\n </div>\n }\n }\n </div>\n</div>", styles: [".tn-stepper{display:flex;font-family:inherit;--step-diameter: 48px;--step-diameter-sm: 32px;--step-padding: 12px}.tn-stepper--horizontal{flex-direction:column}.tn-stepper--horizontal .tn-stepper__header{display:flex;justify-content:center;margin-bottom:32px;padding:0 16px}.tn-stepper--horizontal .tn-stepper__step-header{display:flex;flex-direction:column;align-items:center;text-align:center;cursor:pointer;transition:all .2s ease-in-out}.tn-stepper--horizontal .tn-stepper__step-header:not(.tn-stepper__step-header--active):hover .tn-stepper__step-indicator{transform:scale(.95)}.tn-stepper--horizontal .tn-stepper__connector{flex:1;height:2px;background:var(--tn-lines, #e5e7eb);margin:0 16px;position:relative;top:calc(var(--step-diameter) / 2)}.tn-stepper--vertical{flex-direction:row}.tn-stepper--vertical .tn-stepper__header{display:flex;flex-direction:column;width:280px;padding:16px;border-right:1px solid var(--tn-lines, #e5e7eb)}.tn-stepper--vertical .tn-stepper__step-header{display:flex;flex-direction:row;align-items:center;text-align:left;cursor:pointer;transition:all .2s ease-in-out;padding:var(--step-padding);border-radius:8px;margin-bottom:8px}.tn-stepper--vertical .tn-stepper__step-header:not(.tn-stepper__step-header--active):hover .tn-stepper__step-indicator{transform:scale(.95)}.tn-stepper--vertical .tn-stepper__step-header .tn-stepper__step-label{margin-left:12px;margin-top:0}.tn-stepper--vertical .tn-stepper__connector{width:2px;height:24px;background:var(--tn-lines, #e5e7eb);position:relative;left:calc(var(--step-diameter) / 2 + var(--step-padding));margin-bottom:8px}.tn-stepper--vertical .tn-stepper__content{flex:1;padding:16px}.tn-stepper__step-indicator{display:flex;align-items:center;justify-content:center;width:var(--step-diameter);height:var(--step-diameter);border-radius:50%;background:var(--tn-alt-bg1, #f8f9fa);color:var(--tn-alt-fg1, #495057);font-weight:400;font-size:14px;transition:all .2s ease-in-out;position:relative;transform:scale(.65)}.tn-stepper__step-number{font-weight:400}.tn-stepper__step-label{margin-top:8px}.tn-stepper__step-title ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-stepper__step-title{display:block;font-weight:400;font-size:14px;color:var(--tn-fg1, #000000);line-height:1.2}.tn-stepper__step-subtitle{display:block;font-size:12px;color:var(--tn-fg2, #6c757d);margin-top:2px}.tn-stepper__step-header--active .tn-stepper__step-indicator{background:var(--tn-primary, #007bff);color:var(--tn-primary-txt, #ffffff);transform:scale(1)}.tn-stepper__step-header--active .tn-stepper__step-title{color:var(--tn-fg2, #6c757d);font-weight:600}.tn-stepper__step-header--completed .tn-stepper__step-indicator{background:var(--tn-green, #28a745);color:#fff}.tn-stepper__step-header--completed .tn-stepper__step-check{font-size:1rem;font-weight:700}.tn-stepper__step-header--error .tn-stepper__step-indicator{background:var(--tn-red, #dc3545);color:#fff}.tn-stepper__step-header--error .tn-stepper__step-error{font-size:18px;font-weight:700}.tn-stepper__step-header--error .tn-stepper__step-title{color:var(--tn-fg1, #000000)}.tn-stepper__step-header--active.tn-stepper__step-header--error .tn-stepper__step-title{color:var(--tn-fg2, #6c757d);font-weight:600}.tn-stepper__step-header--optional .tn-stepper__step-indicator{border:2px dashed var(--tn-lines, #e5e7eb);background:transparent}.tn-stepper--horizontal .tn-stepper__step-header--completed+.tn-stepper__connector{background:var(--tn-green, #28a745)}.tn-stepper--horizontal .tn-stepper__step-header--completed+.tn-stepper__connector:after{content:\"\";position:absolute;top:0;left:0;right:0;height:100%;background:var(--tn-green, #28a745);animation:progressFill .3s ease-in-out}.tn-stepper--vertical .tn-stepper__step-header--completed+.tn-stepper__connector{background:var(--tn-green, #28a745)}.tn-stepper__content{min-height:200px}.tn-stepper__step-content{padding:16px;background:var(--tn-bg1, #ffffff);border-radius:8px;border:1px solid var(--tn-lines, #e5e7eb)}@keyframes progressFill{0%{width:0}to{width:100%}}.tn-stepper__step-header:focus{outline:2px solid var(--tn-primary, #007bff);outline-offset:2px}.tn-stepper__step-header:focus:not(:focus-visible){outline:none}@media(max-width:780px){.tn-stepper--vertical .tn-stepper__header{width:180px;border-right:none;border-bottom:1px solid var(--tn-lines, #e5e7eb);padding:16px 0}.tn-stepper--vertical .tn-stepper__step-header{flex-direction:column;align-items:center;text-align:center;min-width:80px;padding:8px 4px}.tn-stepper--vertical .tn-stepper__step-header .tn-stepper__step-label{margin-left:0;margin-top:8px}.tn-stepper--vertical .tn-stepper__connector{display:none}}@media(max-width:780px){.tn-stepper .tn-stepper__step-label{display:none}.tn-stepper .tn-stepper__step-indicator{width:var(--step-diameter-sm);height:var(--step-diameter-sm);font-size:12px}.tn-stepper--horizontal .tn-stepper__header{padding:0 8px}.tn-stepper--horizontal .tn-stepper__connector{top:calc(var(--step-diameter-sm) / 2);margin:0 8px}.tn-stepper--vertical .tn-stepper__header{width:60px}.tn-stepper--vertical .tn-stepper__step-header{padding:4px;margin-bottom:4px}.tn-stepper--vertical .tn-stepper__connector{left:calc(var(--step-diameter-sm) / 2 + 4px);height:16px;margin-bottom:4px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }, { kind: "pipe", type: LabelMarkupPipe, name: "tnLabelMarkup" }], animations: [
|
|
14052
14362
|
trigger('stepTransition', [
|
|
14053
14363
|
transition(':enter', [
|
|
14054
14364
|
style({ opacity: 0, transform: 'translateX(50px)' }),
|
|
@@ -14059,7 +14369,7 @@ class TnStepperComponent {
|
|
|
14059
14369
|
}
|
|
14060
14370
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnStepperComponent, decorators: [{
|
|
14061
14371
|
type: Component,
|
|
14062
|
-
args: [{ selector: 'tn-stepper', standalone: true, imports: [CommonModule, TnTestIdDirective], animations: [
|
|
14372
|
+
args: [{ selector: 'tn-stepper', standalone: true, imports: [CommonModule, TnTestIdDirective, LabelMarkupPipe], animations: [
|
|
14063
14373
|
trigger('stepTransition', [
|
|
14064
14374
|
transition(':enter', [
|
|
14065
14375
|
style({ opacity: 0, transform: 'translateX(50px)' }),
|
|
@@ -14068,7 +14378,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
|
|
|
14068
14378
|
])
|
|
14069
14379
|
], host: {
|
|
14070
14380
|
'(window:resize)': 'onWindowResize($event)'
|
|
14071
|
-
}, template: "<div class=\"tn-stepper\"\n tnTestIdType=\"stepper\"\n [class.tn-stepper--horizontal]=\"orientation() === 'horizontal' || (orientation() === 'auto' && isWideScreen())\"\n [class.tn-stepper--vertical]=\"orientation() === 'vertical' || (orientation() === 'auto' && !isWideScreen())\"\n [tnTestId]=\"testId()\">\n\n <!-- Step Headers -->\n <div class=\"tn-stepper__header\">\n @for (step of steps(); track $index; let i = $index) {\n <div class=\"tn-stepper__step-header\"\n tabindex=\"0\"\n role=\"button\"\n [class.tn-stepper__step-header--active]=\"selectedIndex() === i\"\n [class.tn-stepper__step-header--completed]=\"step.completed()\"\n [class.tn-stepper__step-header--error]=\"step.hasError()\"\n [class.tn-stepper__step-header--optional]=\"step.optional()\"\n (click)=\"selectStep(i)\"\n (keydown.enter)=\"selectStep(i)\"\n (keydown.space)=\"selectStep(i)\">\n\n <!-- Step Number/Icon -->\n <div class=\"tn-stepper__step-indicator\">\n @if (step.completed() && !step.hasError()) {\n <span class=\"tn-stepper__step-check\">\u2713</span>\n }\n @if (step.hasError()) {\n <span class=\"tn-stepper__step-error\">!</span>\n }\n @if (!step.completed() && !step.hasError()) {\n @if (step.icon()) {\n <span class=\"tn-stepper__step-icon\">{{ step.icon() }}</span>\n } @else {\n <span class=\"tn-stepper__step-number\">{{ i + 1 }}</span>\n }\n }\n </div>\n\n <!-- Step Label -->\n <div class=\"tn-stepper__step-label\">\n <div class=\"tn-stepper__step-title\"
|
|
14381
|
+
}, template: "<div class=\"tn-stepper\"\n tnTestIdType=\"stepper\"\n [class.tn-stepper--horizontal]=\"orientation() === 'horizontal' || (orientation() === 'auto' && isWideScreen())\"\n [class.tn-stepper--vertical]=\"orientation() === 'vertical' || (orientation() === 'auto' && !isWideScreen())\"\n [tnTestId]=\"testId()\">\n\n <!-- Step Headers -->\n <div class=\"tn-stepper__header\">\n @for (step of steps(); track $index; let i = $index) {\n <div class=\"tn-stepper__step-header\"\n tabindex=\"0\"\n role=\"button\"\n [class.tn-stepper__step-header--active]=\"selectedIndex() === i\"\n [class.tn-stepper__step-header--completed]=\"step.completed()\"\n [class.tn-stepper__step-header--error]=\"step.hasError()\"\n [class.tn-stepper__step-header--optional]=\"step.optional()\"\n (click)=\"selectStep(i)\"\n (keydown.enter)=\"selectStep(i)\"\n (keydown.space)=\"selectStep(i)\">\n\n <!-- Step Number/Icon -->\n <div class=\"tn-stepper__step-indicator\">\n @if (step.completed() && !step.hasError()) {\n <span class=\"tn-stepper__step-check\">\u2713</span>\n }\n @if (step.hasError()) {\n <span class=\"tn-stepper__step-error\">!</span>\n }\n @if (!step.completed() && !step.hasError()) {\n @if (step.icon()) {\n <span class=\"tn-stepper__step-icon\">{{ step.icon() }}</span>\n } @else {\n <span class=\"tn-stepper__step-number\">{{ i + 1 }}</span>\n }\n }\n </div>\n\n <!-- Step Label -->\n <div class=\"tn-stepper__step-label\">\n <div class=\"tn-stepper__step-title\" [innerHTML]=\"step.label() | tnLabelMarkup\"></div>\n @if (step.optional()) {\n <span class=\"tn-stepper__step-subtitle\">Optional</span>\n }\n </div>\n </div>\n\n <!-- Connector Line (except for last step) -->\n @if (i < steps().length - 1) {\n <div class=\"tn-stepper__connector\"></div>\n }\n }\n </div>\n\n <!-- Step Content -->\n <div class=\"tn-stepper__content\">\n @for (step of steps(); track $index; let i = $index) {\n @if (selectedIndex() === i) {\n <div class=\"tn-stepper__step-content\"\n [@stepTransition]=\"selectedIndex()\">\n <ng-container *ngTemplateOutlet=\"step.content()\" />\n </div>\n }\n }\n </div>\n</div>", styles: [".tn-stepper{display:flex;font-family:inherit;--step-diameter: 48px;--step-diameter-sm: 32px;--step-padding: 12px}.tn-stepper--horizontal{flex-direction:column}.tn-stepper--horizontal .tn-stepper__header{display:flex;justify-content:center;margin-bottom:32px;padding:0 16px}.tn-stepper--horizontal .tn-stepper__step-header{display:flex;flex-direction:column;align-items:center;text-align:center;cursor:pointer;transition:all .2s ease-in-out}.tn-stepper--horizontal .tn-stepper__step-header:not(.tn-stepper__step-header--active):hover .tn-stepper__step-indicator{transform:scale(.95)}.tn-stepper--horizontal .tn-stepper__connector{flex:1;height:2px;background:var(--tn-lines, #e5e7eb);margin:0 16px;position:relative;top:calc(var(--step-diameter) / 2)}.tn-stepper--vertical{flex-direction:row}.tn-stepper--vertical .tn-stepper__header{display:flex;flex-direction:column;width:280px;padding:16px;border-right:1px solid var(--tn-lines, #e5e7eb)}.tn-stepper--vertical .tn-stepper__step-header{display:flex;flex-direction:row;align-items:center;text-align:left;cursor:pointer;transition:all .2s ease-in-out;padding:var(--step-padding);border-radius:8px;margin-bottom:8px}.tn-stepper--vertical .tn-stepper__step-header:not(.tn-stepper__step-header--active):hover .tn-stepper__step-indicator{transform:scale(.95)}.tn-stepper--vertical .tn-stepper__step-header .tn-stepper__step-label{margin-left:12px;margin-top:0}.tn-stepper--vertical .tn-stepper__connector{width:2px;height:24px;background:var(--tn-lines, #e5e7eb);position:relative;left:calc(var(--step-diameter) / 2 + var(--step-padding));margin-bottom:8px}.tn-stepper--vertical .tn-stepper__content{flex:1;padding:16px}.tn-stepper__step-indicator{display:flex;align-items:center;justify-content:center;width:var(--step-diameter);height:var(--step-diameter);border-radius:50%;background:var(--tn-alt-bg1, #f8f9fa);color:var(--tn-alt-fg1, #495057);font-weight:400;font-size:14px;transition:all .2s ease-in-out;position:relative;transform:scale(.65)}.tn-stepper__step-number{font-weight:400}.tn-stepper__step-label{margin-top:8px}.tn-stepper__step-title ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-stepper__step-title{display:block;font-weight:400;font-size:14px;color:var(--tn-fg1, #000000);line-height:1.2}.tn-stepper__step-subtitle{display:block;font-size:12px;color:var(--tn-fg2, #6c757d);margin-top:2px}.tn-stepper__step-header--active .tn-stepper__step-indicator{background:var(--tn-primary, #007bff);color:var(--tn-primary-txt, #ffffff);transform:scale(1)}.tn-stepper__step-header--active .tn-stepper__step-title{color:var(--tn-fg2, #6c757d);font-weight:600}.tn-stepper__step-header--completed .tn-stepper__step-indicator{background:var(--tn-green, #28a745);color:#fff}.tn-stepper__step-header--completed .tn-stepper__step-check{font-size:1rem;font-weight:700}.tn-stepper__step-header--error .tn-stepper__step-indicator{background:var(--tn-red, #dc3545);color:#fff}.tn-stepper__step-header--error .tn-stepper__step-error{font-size:18px;font-weight:700}.tn-stepper__step-header--error .tn-stepper__step-title{color:var(--tn-fg1, #000000)}.tn-stepper__step-header--active.tn-stepper__step-header--error .tn-stepper__step-title{color:var(--tn-fg2, #6c757d);font-weight:600}.tn-stepper__step-header--optional .tn-stepper__step-indicator{border:2px dashed var(--tn-lines, #e5e7eb);background:transparent}.tn-stepper--horizontal .tn-stepper__step-header--completed+.tn-stepper__connector{background:var(--tn-green, #28a745)}.tn-stepper--horizontal .tn-stepper__step-header--completed+.tn-stepper__connector:after{content:\"\";position:absolute;top:0;left:0;right:0;height:100%;background:var(--tn-green, #28a745);animation:progressFill .3s ease-in-out}.tn-stepper--vertical .tn-stepper__step-header--completed+.tn-stepper__connector{background:var(--tn-green, #28a745)}.tn-stepper__content{min-height:200px}.tn-stepper__step-content{padding:16px;background:var(--tn-bg1, #ffffff);border-radius:8px;border:1px solid var(--tn-lines, #e5e7eb)}@keyframes progressFill{0%{width:0}to{width:100%}}.tn-stepper__step-header:focus{outline:2px solid var(--tn-primary, #007bff);outline-offset:2px}.tn-stepper__step-header:focus:not(:focus-visible){outline:none}@media(max-width:780px){.tn-stepper--vertical .tn-stepper__header{width:180px;border-right:none;border-bottom:1px solid var(--tn-lines, #e5e7eb);padding:16px 0}.tn-stepper--vertical .tn-stepper__step-header{flex-direction:column;align-items:center;text-align:center;min-width:80px;padding:8px 4px}.tn-stepper--vertical .tn-stepper__step-header .tn-stepper__step-label{margin-left:0;margin-top:8px}.tn-stepper--vertical .tn-stepper__connector{display:none}}@media(max-width:780px){.tn-stepper .tn-stepper__step-label{display:none}.tn-stepper .tn-stepper__step-indicator{width:var(--step-diameter-sm);height:var(--step-diameter-sm);font-size:12px}.tn-stepper--horizontal .tn-stepper__header{padding:0 8px}.tn-stepper--horizontal .tn-stepper__connector{top:calc(var(--step-diameter-sm) / 2);margin:0 8px}.tn-stepper--vertical .tn-stepper__header{width:60px}.tn-stepper--vertical .tn-stepper__step-header{padding:4px;margin-bottom:4px}.tn-stepper--vertical .tn-stepper__connector{left:calc(var(--step-diameter-sm) / 2 + 4px);height:16px;margin-bottom:4px}}\n"] }]
|
|
14072
14382
|
}], ctorParameters: () => [], propDecorators: { orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], linear: [{ type: i0.Input, args: [{ isSignal: true, alias: "linear", required: false }] }], selectedIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedIndex", required: false }] }, { type: i0.Output, args: ["selectedIndexChange"] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], completed: [{ type: i0.Output, args: ["completed"] }], steps: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TnStepComponent), { ...{ descendants: true }, isSignal: true }] }] } });
|
|
14073
14383
|
|
|
14074
14384
|
/**
|
|
@@ -15887,5 +16197,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
|
|
|
15887
16197
|
* Generated bundle index. Do not edit.
|
|
15888
16198
|
*/
|
|
15889
16199
|
|
|
15890
|
-
export { CommonShortcuts, DEFAULT_THEME, DiskIconComponent, DiskType, FileSizePipe, InputType, LIGHT_THEME, LinuxModifierKeys, LinuxShortcuts, ModifierKeys, QuickShortcuts, ShortcutBuilder, StripMntPrefixPipe, THEME_MAP, THEME_STORAGE_KEY, TN_FORM_FIELD_ERRORS, TN_TABLE_PAGER_DEFAULT_LABELS, TN_TABLE_PAGER_LABELS, TN_TEST_ATTR, TN_THEME_DEFINITIONS, TnAutocompleteComponent, TnAutocompleteHarness, TnBannerActionDirective, TnBannerComponent, TnBannerHarness, TnBrandedSpinnerComponent, TnButtonComponent, TnButtonHarness, TnButtonToggleComponent, TnButtonToggleGroupComponent, TnButtonToggleGroupHarness, TnButtonToggleHarness, TnCalendarComponent, TnCalendarHeaderComponent, TnCardComponent, TnCardHeaderDirective, TnCellDefDirective, TnCheckboxComponent, TnCheckboxHarness, TnCheckboxLabelDirective, TnChipComponent, TnConfirmDialogComponent, TnDateInputComponent, TnDateInputHarness, TnDateRangeInputComponent, TnDateRangeInputHarness, TnDetailRowDefDirective, TnDialog, TnDialogHarness, TnDialogShellComponent, TnDialogTesting, TnDividerComponent, TnDividerDirective, TnDrawerComponent, TnDrawerContainerComponent, TnDrawerContainerHarness, TnDrawerContentComponent, TnDrawerHarness, TnEmptyComponent, TnEmptyHarness, TnExpansionPanelComponent, TnExpansionPanelHarness, TnFilePickerComponent, TnFilePickerPopupComponent, TnFormFieldComponent, TnFormFieldHarness, TnHeaderCellDefDirective, TnIconButtonComponent, TnIconButtonHarness, TnIconComponent, TnIconHarness, TnIconRegistryService, TnIconTesting, TnInputComponent, TnInputDirective, TnInputHarness, TnKeyboardShortcutComponent, TnKeyboardShortcutService, TnListAvatarDirective, TnListComponent, TnListIconDirective, TnListItemComponent, TnListItemLineDirective, TnListItemPrimaryDirective, TnListItemSecondaryDirective, TnListItemTitleDirective, TnListItemTrailingDirective, TnListOptionComponent, TnListSubheaderComponent, TnMenuActivateHoverDirective, TnMenuComponent, TnMenuHarness, TnMenuItemComponent, TnMenuTesting, TnMenuTriggerDirective, TnMonthViewComponent, TnMultiYearViewComponent, TnNestedTreeNodeComponent, TnParticleProgressBarComponent, TnProgressBarComponent, TnRadioComponent, TnRadioHarness, TnSelectComponent, TnSelectHarness, TnSelectionListComponent, TnSidePanelActionDirective, TnSidePanelComponent, TnSidePanelHarness, TnSidePanelHeaderActionDirective, TnSlideToggleComponent, TnSlideToggleHarness, TnSliderComponent, TnSliderThumbDirective, TnSliderWithLabelDirective, TnSpinnerComponent, TnSpriteLoaderService, TnStepComponent, TnStepperComponent, TnTabComponent, TnTabHarness, TnTabPanelComponent, TnTabPanelHarness, TnTableColumnDirective, TnTableComponent, TnTableHarness, TnTablePagerComponent, TnTablePagerHarness, TnTabsComponent, TnTabsHarness, TnTestIdDirective, TnTheme, TnThemeService, TnTimeInputComponent, TnToastComponent, TnToastMock, TnToastPosition, TnToastRef, TnToastService, TnToastTesting, TnToastType, TnTooltipComponent, TnTooltipDirective, TnTreeComponent, TnTreeFlatDataSource, TnTreeFlattener, TnTreeNodeComponent, TnTreeNodeOutletDirective, TruncatePathPipe, WindowsModifierKeys, WindowsShortcuts, composeTestId, createLucideLibrary, createShortcut, defaultSpriteBasePath, defaultSpriteConfigPath, formatSize, kebabTestSegment, libIconMarker, parseSize, registerLucideIcons, scopeTestId, setupLucideIntegration, tnIconMarker, writeTestId };
|
|
16200
|
+
export { CommonShortcuts, DEFAULT_THEME, DiskIconComponent, DiskType, FileSizePipe, InputType, LIGHT_THEME, LabelMarkupPipe, LabelTextPipe, LinuxModifierKeys, LinuxShortcuts, ModifierKeys, QuickShortcuts, ShortcutBuilder, StripMntPrefixPipe, THEME_MAP, THEME_STORAGE_KEY, TN_FORM_FIELD_ERRORS, TN_TABLE_PAGER_DEFAULT_LABELS, TN_TABLE_PAGER_LABELS, TN_TEST_ATTR, TN_THEME_DEFINITIONS, TnAutocompleteComponent, TnAutocompleteHarness, TnBannerActionDirective, TnBannerComponent, TnBannerHarness, TnBrandedSpinnerComponent, TnButtonComponent, TnButtonHarness, TnButtonToggleComponent, TnButtonToggleGroupComponent, TnButtonToggleGroupHarness, TnButtonToggleHarness, TnCalendarComponent, TnCalendarHeaderComponent, TnCardComponent, TnCardHeaderDirective, TnCellDefDirective, TnCheckboxComponent, TnCheckboxHarness, TnCheckboxLabelDirective, TnChipComponent, TnConfirmDialogComponent, TnDateInputComponent, TnDateInputHarness, TnDateRangeInputComponent, TnDateRangeInputHarness, TnDetailRowDefDirective, TnDialog, TnDialogHarness, TnDialogShellComponent, TnDialogTesting, TnDividerComponent, TnDividerDirective, TnDrawerComponent, TnDrawerContainerComponent, TnDrawerContainerHarness, TnDrawerContentComponent, TnDrawerHarness, TnEmptyComponent, TnEmptyHarness, TnExpansionPanelComponent, TnExpansionPanelHarness, TnFilePickerComponent, TnFilePickerPopupComponent, TnFormFieldComponent, TnFormFieldHarness, TnHeaderCellDefDirective, TnIconButtonComponent, TnIconButtonHarness, TnIconComponent, TnIconHarness, TnIconRegistryService, TnIconTesting, TnInputComponent, TnInputDirective, TnInputHarness, TnKeyboardShortcutComponent, TnKeyboardShortcutService, TnListAvatarDirective, TnListComponent, TnListIconDirective, TnListItemComponent, TnListItemLineDirective, TnListItemPrimaryDirective, TnListItemSecondaryDirective, TnListItemTitleDirective, TnListItemTrailingDirective, TnListOptionComponent, TnListSubheaderComponent, TnMenuActivateHoverDirective, TnMenuComponent, TnMenuHarness, TnMenuItemComponent, TnMenuTesting, TnMenuTriggerDirective, TnMonthViewComponent, TnMultiYearViewComponent, TnNestedTreeNodeComponent, TnParticleProgressBarComponent, TnProgressBarComponent, TnRadioComponent, TnRadioHarness, TnSelectComponent, TnSelectHarness, TnSelectionListComponent, TnSidePanelActionDirective, TnSidePanelComponent, TnSidePanelHarness, TnSidePanelHeaderActionDirective, TnSlideToggleComponent, TnSlideToggleHarness, TnSliderComponent, TnSliderThumbDirective, TnSliderWithLabelDirective, TnSpinnerComponent, TnSpriteLoaderService, TnStepComponent, TnStepperComponent, TnTabComponent, TnTabHarness, TnTabPanelComponent, TnTabPanelHarness, TnTableColumnDirective, TnTableComponent, TnTableHarness, TnTablePagerComponent, TnTablePagerHarness, TnTabsComponent, TnTabsHarness, TnTestIdDirective, TnTheme, TnThemeService, TnTimeInputComponent, TnToastComponent, TnToastMock, TnToastPosition, TnToastRef, TnToastService, TnToastTesting, TnToastType, TnTooltipComponent, TnTooltipDirective, TnTreeComponent, TnTreeFlatDataSource, TnTreeFlattener, TnTreeNodeComponent, TnTreeNodeOutletDirective, TruncatePathPipe, WindowsModifierKeys, WindowsShortcuts, composeTestId, createLucideLibrary, createShortcut, defaultSpriteBasePath, defaultSpriteConfigPath, formatSize, kebabTestSegment, labelMarkupToHtml, labelMarkupToText, libIconMarker, parseLabelMarkup, parseSize, registerLucideIcons, scopeTestId, setupLucideIntegration, tnIconMarker, writeTestId };
|
|
15891
16201
|
//# sourceMappingURL=truenas-ui-components.mjs.map
|