@flyos/design-system 1.1.0 → 1.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.
|
@@ -44,9 +44,11 @@ import { CdkConnectedOverlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
|
|
|
44
44
|
* See skills/business-app-angular-remote.md § "Design-system singleton across
|
|
45
45
|
* the federation boundary".
|
|
46
46
|
*/
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
|
|
47
|
+
// Kept in sync with projects/design-system/package.json "version" — rewritten by
|
|
48
|
+
// tools/publish-library.ps1 at bump time, and asserted by the spec beside this file.
|
|
49
|
+
// Used only for the diagnostic message; the duplicate-instance detection itself is
|
|
50
|
+
// version-agnostic, so a stale literal misnames a fork rather than hiding one.
|
|
51
|
+
const FLY_DS_VERSION = '1.3.0';
|
|
50
52
|
const FLY_DS_REGISTRY_KEY = '__FLY_DS_INSTANCES__';
|
|
51
53
|
/**
|
|
52
54
|
* Records this design-system instance on the shared `scope` and returns the
|
|
@@ -1583,6 +1585,7 @@ const DS_BASELINE_LOCALES = {
|
|
|
1583
1585
|
'ui.action.confirm': 'Confirm',
|
|
1584
1586
|
'ui.action.dismiss': 'Dismiss',
|
|
1585
1587
|
'ui.action.fewerOptions': 'Fewer options',
|
|
1588
|
+
'ui.action.open': 'Open',
|
|
1586
1589
|
'ui.action.retry': 'Retry',
|
|
1587
1590
|
'ui.action.save': 'Save',
|
|
1588
1591
|
'ui.action.search': 'Search',
|
|
@@ -1592,7 +1595,9 @@ const DS_BASELINE_LOCALES = {
|
|
|
1592
1595
|
'ui.form.autoSaving': 'Auto-saving',
|
|
1593
1596
|
'ui.nav.breadcrumbs': 'Breadcrumbs',
|
|
1594
1597
|
'ui.nav.home': 'Home',
|
|
1598
|
+
'ui.nav.modules': 'Modules',
|
|
1595
1599
|
'ui.nav.selectModule': 'Select a module',
|
|
1600
|
+
'ui.nav.sections': 'Sections',
|
|
1596
1601
|
'ui.nav.switchModule': 'Switch module',
|
|
1597
1602
|
'ui.pagination.first': 'First page',
|
|
1598
1603
|
'ui.pagination.label': 'Pagination',
|
|
@@ -1928,6 +1933,7 @@ const DS_BASELINE_LOCALES = {
|
|
|
1928
1933
|
'ui.action.confirm': 'تأكيد',
|
|
1929
1934
|
'ui.action.dismiss': 'تجاهل',
|
|
1930
1935
|
'ui.action.fewerOptions': 'خيارات أقل',
|
|
1936
|
+
'ui.action.open': 'فتح',
|
|
1931
1937
|
'ui.action.retry': 'إعادة المحاولة',
|
|
1932
1938
|
'ui.action.save': 'حفظ',
|
|
1933
1939
|
'ui.action.search': 'بحث',
|
|
@@ -1937,7 +1943,9 @@ const DS_BASELINE_LOCALES = {
|
|
|
1937
1943
|
'ui.form.autoSaving': 'حفظ تلقائي',
|
|
1938
1944
|
'ui.nav.breadcrumbs': 'مسار التنقل',
|
|
1939
1945
|
'ui.nav.home': 'الرئيسية',
|
|
1946
|
+
'ui.nav.modules': 'الوحدات',
|
|
1940
1947
|
'ui.nav.selectModule': 'اختر وحدة',
|
|
1948
|
+
'ui.nav.sections': 'الأقسام',
|
|
1941
1949
|
'ui.nav.switchModule': 'تبديل الوحدة',
|
|
1942
1950
|
'ui.pagination.first': 'الصفحة الأولى',
|
|
1943
1951
|
'ui.pagination.label': 'تقسيم الصفحات',
|
|
@@ -2273,6 +2281,7 @@ const DS_BASELINE_LOCALES = {
|
|
|
2273
2281
|
'ui.action.confirm': 'Confirmer',
|
|
2274
2282
|
'ui.action.dismiss': 'Ignorer',
|
|
2275
2283
|
'ui.action.fewerOptions': 'Moins d\'options',
|
|
2284
|
+
'ui.action.open': 'Ouvrir',
|
|
2276
2285
|
'ui.action.retry': 'Réessayer',
|
|
2277
2286
|
'ui.action.save': 'Enregistrer',
|
|
2278
2287
|
'ui.action.search': 'Rechercher',
|
|
@@ -2282,7 +2291,9 @@ const DS_BASELINE_LOCALES = {
|
|
|
2282
2291
|
'ui.form.autoSaving': 'Enregistrement automatique',
|
|
2283
2292
|
'ui.nav.breadcrumbs': 'Fil d\'Ariane',
|
|
2284
2293
|
'ui.nav.home': 'Accueil',
|
|
2294
|
+
'ui.nav.modules': 'Modules',
|
|
2285
2295
|
'ui.nav.selectModule': 'Choisir un module',
|
|
2296
|
+
'ui.nav.sections': 'Sections',
|
|
2286
2297
|
'ui.nav.switchModule': 'Changer de module',
|
|
2287
2298
|
'ui.pagination.first': 'Première page',
|
|
2288
2299
|
'ui.pagination.label': 'Pagination',
|
|
@@ -2617,6 +2628,7 @@ const DS_BASELINE_LOCALES = {
|
|
|
2617
2628
|
'ui.action.confirm': 'تصدیق کریں',
|
|
2618
2629
|
'ui.action.dismiss': 'مسترد کریں',
|
|
2619
2630
|
'ui.action.fewerOptions': 'کم اختیارات',
|
|
2631
|
+
'ui.action.open': 'کھولیں',
|
|
2620
2632
|
'ui.action.retry': 'دوبارہ کوشش کریں',
|
|
2621
2633
|
'ui.action.save': 'محفوظ کریں',
|
|
2622
2634
|
'ui.action.search': 'تلاش کریں',
|
|
@@ -2626,7 +2638,9 @@ const DS_BASELINE_LOCALES = {
|
|
|
2626
2638
|
'ui.form.autoSaving': 'خودکار محفوظ ہو رہا ہے',
|
|
2627
2639
|
'ui.nav.breadcrumbs': 'بریڈکرمب',
|
|
2628
2640
|
'ui.nav.home': 'ہوم',
|
|
2641
|
+
'ui.nav.modules': 'ماڈیولز',
|
|
2629
2642
|
'ui.nav.selectModule': 'ماڈیول منتخب کریں',
|
|
2643
|
+
'ui.nav.sections': 'حصے',
|
|
2630
2644
|
'ui.nav.switchModule': 'ماڈیول تبدیل کریں',
|
|
2631
2645
|
'ui.pagination.first': 'پہلا صفحہ',
|
|
2632
2646
|
'ui.pagination.label': 'صفحہ بندی',
|
|
@@ -5357,6 +5371,22 @@ const MARGIN = 4;
|
|
|
5357
5371
|
* host's `getBoundingClientRect()`, so it escapes every overflow-clip and app-window
|
|
5358
5372
|
* bound. It flips placement + clamps to the viewport so it's always fully visible.
|
|
5359
5373
|
*
|
|
5374
|
+
* ## `data-tooltip` is the SAME primitive now (the global clipping fix)
|
|
5375
|
+
* `[data-tooltip]` used to be a CSS-only `::before`/`::after` pair in
|
|
5376
|
+
* `_app-surface-utilities.scss`. A pseudo-element is a child box of its host, so it is
|
|
5377
|
+
* clipped by ANY scrolling / `overflow: hidden` ancestor — which is why the boards
|
|
5378
|
+
* toolbar rail (a `overflow-y: auto` plate) rendered every tool tip cut off inside its
|
|
5379
|
+
* own 47px-wide column. No z-index can fix that: clipping is not a stacking question.
|
|
5380
|
+
* `position: fixed` on the pseudo would not fix it either, because the same plates carry
|
|
5381
|
+
* `backdrop-filter`, and a filtered ancestor is a containing block for fixed descendants.
|
|
5382
|
+
*
|
|
5383
|
+
* The fix is to have ONE tooltip implementation, and it is this one: the selector now
|
|
5384
|
+
* also matches `[data-tooltip]`, and when no `flyTooltip` text is bound the directive
|
|
5385
|
+
* reads the host's `data-tooltip` attribute at show time. Reading it lazily (rather than
|
|
5386
|
+
* binding it) is what lets components that write the attribute IMPERATIVELY — the DS icon
|
|
5387
|
+
* button resolves an i18n key into it — participate by simply listing this directive in
|
|
5388
|
+
* `hostDirectives`, with no input to keep in sync.
|
|
5389
|
+
*
|
|
5360
5390
|
* ## Behaviour
|
|
5361
5391
|
* - Shows on `mouseenter` AND `focus` (keyboard users), after `flyTooltipDelay` ms.
|
|
5362
5392
|
* - Hides immediately on `mouseleave` / `blur` / `Escape` / scroll / wheel / destroy.
|
|
@@ -5423,9 +5453,19 @@ class FlyTooltipDirective {
|
|
|
5423
5453
|
// Belt-and-braces alongside DestroyRef (a plain `new` in a test won't run the effect).
|
|
5424
5454
|
this.hide();
|
|
5425
5455
|
}
|
|
5426
|
-
/**
|
|
5456
|
+
/**
|
|
5457
|
+
* Trimmed text, or `''` when there's nothing meaningful to show.
|
|
5458
|
+
*
|
|
5459
|
+
* Falls back to the host's `data-tooltip` attribute — read from the DOM rather than through an
|
|
5460
|
+
* input, because the DS icon button writes it imperatively from a resolved i18n key (and re-writes
|
|
5461
|
+
* it on every locale change). A signal input could not see that; an attribute read at show time
|
|
5462
|
+
* always reports the current label.
|
|
5463
|
+
*/
|
|
5427
5464
|
normalizedText() {
|
|
5428
|
-
|
|
5465
|
+
const bound = (this.text() ?? '').trim();
|
|
5466
|
+
if (bound)
|
|
5467
|
+
return bound;
|
|
5468
|
+
return (this.host.nativeElement.getAttribute('data-tooltip') ?? '').trim();
|
|
5429
5469
|
}
|
|
5430
5470
|
scheduleShow() {
|
|
5431
5471
|
if (this.flyTooltipDisabled() || !this.normalizedText())
|
|
@@ -5593,12 +5633,12 @@ class FlyTooltipDirective {
|
|
|
5593
5633
|
this.doc.head.appendChild(style);
|
|
5594
5634
|
}
|
|
5595
5635
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyTooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
5596
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.19", type: FlyTooltipDirective, isStandalone: true, selector: "[flyTooltip]", inputs: { text: { classPropertyName: "text", publicName: "flyTooltip", isSignal: true, isRequired: false, transformFunction: null }, flyTooltipPlacement: { classPropertyName: "flyTooltipPlacement", publicName: "flyTooltipPlacement", isSignal: true, isRequired: false, transformFunction: null }, flyTooltipDisabled: { classPropertyName: "flyTooltipDisabled", publicName: "flyTooltipDisabled", isSignal: true, isRequired: false, transformFunction: null }, flyTooltipDelay: { classPropertyName: "flyTooltipDelay", publicName: "flyTooltipDelay", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "scheduleShow()", "focus": "scheduleShow()", "mouseleave": "hide()", "blur": "hide()" } }, ngImport: i0 });
|
|
5636
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.19", type: FlyTooltipDirective, isStandalone: true, selector: "[flyTooltip], [data-tooltip]", inputs: { text: { classPropertyName: "text", publicName: "flyTooltip", isSignal: true, isRequired: false, transformFunction: null }, flyTooltipPlacement: { classPropertyName: "flyTooltipPlacement", publicName: "flyTooltipPlacement", isSignal: true, isRequired: false, transformFunction: null }, flyTooltipDisabled: { classPropertyName: "flyTooltipDisabled", publicName: "flyTooltipDisabled", isSignal: true, isRequired: false, transformFunction: null }, flyTooltipDelay: { classPropertyName: "flyTooltipDelay", publicName: "flyTooltipDelay", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "scheduleShow()", "focus": "scheduleShow()", "mouseleave": "hide()", "blur": "hide()" } }, ngImport: i0 });
|
|
5597
5637
|
}
|
|
5598
5638
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyTooltipDirective, decorators: [{
|
|
5599
5639
|
type: Directive,
|
|
5600
5640
|
args: [{
|
|
5601
|
-
selector: '[flyTooltip]',
|
|
5641
|
+
selector: '[flyTooltip], [data-tooltip]',
|
|
5602
5642
|
standalone: true,
|
|
5603
5643
|
host: {
|
|
5604
5644
|
'(mouseenter)': 'scheduleShow()',
|
|
@@ -6913,7 +6953,7 @@ class FlyEmojiPickerComponent {
|
|
|
6913
6953
|
this.selectionChange.emit(next);
|
|
6914
6954
|
}
|
|
6915
6955
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyEmojiPickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6916
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyEmojiPickerComponent, isStandalone: true, selector: "fly-emoji-picker", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null }, categories: { classPropertyName: "categories", publicName: "categories", isSignal: true, isRequired: false, transformFunction: null }, defaultCategory: { classPropertyName: "defaultCategory", publicName: "defaultCategory", isSignal: true, isRequired: false, transformFunction: null }, skinTones: { classPropertyName: "skinTones", publicName: "skinTones", isSignal: true, isRequired: false, transformFunction: null }, skinTone: { classPropertyName: "skinTone", publicName: "skinTone", isSignal: true, isRequired: false, transformFunction: null }, showMore: { classPropertyName: "showMore", publicName: "showMore", isSignal: true, isRequired: false, transformFunction: null }, previewCount: { classPropertyName: "previewCount", publicName: "previewCount", isSignal: true, isRequired: false, transformFunction: null }, emojiAnimation: { classPropertyName: "emojiAnimation", publicName: "emojiAnimation", isSignal: true, isRequired: false, transformFunction: null }, dismissOnOutsidePress: { classPropertyName: "dismissOnOutsidePress", publicName: "dismissOnOutsidePress", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { stickerPicked: "stickerPicked", toggled: "toggled", selectionChange: "selectionChange", skinToneChange: "skinToneChange", dismissed: "dismissed" }, host: { properties: { "class.fly-emoji-picker--small": "size() === 'small'", "class.fly-emoji-picker--medium": "size() === 'medium'", "class.fly-emoji-picker--large": "size() === 'large'" } }, viewQueries: [{ propertyName: "searchRef", first: true, predicate: ["searchRef"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\r\n class=\"fly-emoji-picker\"\r\n [flyClickOutsideEnabled]=\"dismissOnOutsidePress()\"\r\n (flyClickOutside)=\"dismissed.emit()\"\r\n [attr.aria-label]=\"'common.label.emoji_picker' | translate\">\r\n <!-- Stickers mode only: the emoji grid is unchanged, stickers are an ADDITIONAL surface. -->\r\n @if (showTabs()) {\r\n <div\r\n class=\"fly-emoji-picker__tabs\"\r\n role=\"tablist\"\r\n [attr.aria-label]=\"'common.label.emoji_tabs' | translate\">\r\n <button\r\n type=\"button\"\r\n class=\"fly-emoji-picker__tab\"\r\n role=\"tab\"\r\n id=\"fly-emoji-tab-emoji\"\r\n aria-controls=\"fly-emoji-panel-emoji\"\r\n [class.is-active]=\"activeTab() === 'emoji'\"\r\n [attr.aria-selected]=\"activeTab() === 'emoji'\"\r\n [attr.tabindex]=\"activeTab() === 'emoji' ? 0 : -1\"\r\n (keydown)=\"onTabKeydown($event)\"\r\n (click)=\"selectTab('emoji')\">\r\n {{ 'common.label.emoji_tab_emoji' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fly-emoji-picker__tab\"\r\n role=\"tab\"\r\n id=\"fly-emoji-tab-stickers\"\r\n aria-controls=\"fly-emoji-panel-stickers\"\r\n [class.is-active]=\"activeTab() === 'stickers'\"\r\n [attr.aria-selected]=\"activeTab() === 'stickers'\"\r\n [attr.tabindex]=\"activeTab() === 'stickers' ? 0 : -1\"\r\n (keydown)=\"onTabKeydown($event)\"\r\n (click)=\"selectTab('stickers')\">\r\n {{ 'common.label.emoji_tab_stickers' | translate }}\r\n </button>\r\n </div>\r\n }\r\n\r\n @if (showTabs() && activeTab() === 'stickers') {\r\n <div\r\n class=\"fly-emoji-picker__stickers\"\r\n id=\"fly-emoji-panel-stickers\"\r\n role=\"tabpanel\"\r\n aria-labelledby=\"fly-emoji-tab-stickers\">\r\n @for (entry of stickers(); track entry.id) {\r\n <button\r\n type=\"button\"\r\n class=\"fly-emoji-picker__sticker\"\r\n [flyTooltip]=\"entry.label\"\r\n [attr.aria-label]=\"entry.label\"\r\n (pointerenter)=\"onCellHover(sticker)\"\r\n (pointerleave)=\"cancelHover()\"\r\n (click)=\"pickSticker(entry)\">\r\n <fly-animated-emoji #sticker [id]=\"entry.id\" [size]=\"64\" />\r\n </button>\r\n } @empty {\r\n <p class=\"fly-emoji-picker__empty\">{{ 'agent.lookup.no_results' | translate }}</p>\r\n }\r\n </div>\r\n }\r\n\r\n @if (!showTabs() || activeTab() === 'emoji') {\r\n <!-- Search + tone sit together as one chrome bar: the tone swatches are hands, and on their own row\r\n above the grid they read as pickable content rather than a setting. -->\r\n <div class=\"fly-emoji-picker__bar\">\r\n <input\r\n class=\"fly-emoji-picker__search\"\r\n type=\"text\"\r\n #searchRef\r\n [value]=\"query()\"\r\n (input)=\"onQueryInput(searchRef.value)\"\r\n [placeholder]=\"'common.label.search_emoji' | translate\"\r\n [attr.aria-label]=\"'common.label.search_emoji' | translate\"\r\n spellcheck=\"false\"\r\n autocomplete=\"off\" />\r\n\r\n @if (showToneStrip()) {\r\n <!-- Escape-to-close listener only \u2014 every actual control inside (trigger + options) is its\r\n own focusable button, so this wrapper itself doesn't need to be. -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\r\n <div\r\n class=\"fly-emoji-picker__tones\"\r\n [flyClickOutsideEnabled]=\"toneMenuOpen()\"\r\n (flyClickOutside)=\"toneMenuOpen.set(false)\"\r\n (keydown.escape)=\"toneMenuOpen.set(false)\">\r\n <button\r\n type=\"button\"\r\n class=\"fly-emoji-picker__tone-trigger\"\r\n aria-haspopup=\"listbox\"\r\n [attr.aria-expanded]=\"toneMenuOpen()\"\r\n [attr.aria-label]=\"'common.label.skin_tone' | translate\"\r\n [flyTooltip]=\"toneLabelKey(effectiveTone()) | translate\"\r\n (click)=\"toneMenuOpen.set(!toneMenuOpen())\">\r\n <span class=\"fly-emoji-picker__tone-glyph\">{{ toneSwatch(effectiveTone()) }}</span>\r\n <i class=\"pi pi-chevron-down fly-emoji-picker__tone-caret\" aria-hidden=\"true\"></i>\r\n </button>\r\n\r\n @if (toneMenuOpen()) {\r\n <div\r\n class=\"fly-emoji-picker__tone-menu\"\r\n role=\"listbox\"\r\n [attr.aria-label]=\"'common.label.skin_tone' | translate\">\r\n @for (tone of tones; track tone) {\r\n <button\r\n type=\"button\"\r\n class=\"fly-emoji-picker__tone-option\"\r\n role=\"option\"\r\n [class.is-active]=\"effectiveTone() === tone\"\r\n [attr.aria-selected]=\"effectiveTone() === tone\"\r\n [flyTooltip]=\"toneLabelKey(tone) | translate\"\r\n (click)=\"onToneOptionClick(tone)\">\r\n {{ toneSwatch(tone) }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- ONE scrolling list; each category is a separator label over its own grid. Tabs wrapped to three\r\n rows in a sidebar drawer and cost a click to reach any group. -->\r\n <div\r\n class=\"fly-emoji-picker__list\"\r\n role=\"listbox\"\r\n [attr.id]=\"showTabs() ? 'fly-emoji-panel-emoji' : null\"\r\n [attr.aria-labelledby]=\"showTabs() ? 'fly-emoji-tab-emoji' : null\"\r\n [attr.aria-multiselectable]=\"selectionMode() === 'multi'\">\r\n @for (section of sections(); track section.id) {\r\n <div class=\"fly-emoji-picker__section\" role=\"group\" [attr.aria-label]=\"sectionLabel(section)\">\r\n <h4 class=\"fly-emoji-picker__heading\">{{ sectionLabel(section) }}</h4>\r\n <div class=\"fly-emoji-picker__grid\">\r\n @for (cell of section.cells; track cell.entry.id) {\r\n <button\r\n type=\"button\"\r\n class=\"fly-emoji-picker__cell\"\r\n role=\"option\"\r\n [class.is-active]=\"cell.selected\"\r\n [attr.aria-selected]=\"cell.selected\"\r\n [flyTooltip]=\"cell.entry.label\"\r\n [attr.aria-label]=\"cell.entry.label\"\r\n (click)=\"pick(cell.entry)\">\r\n @if (section.animated) {\r\n <!-- Hover lives on the animated element, not the button: a template reference\r\n declared inside a control-flow block isn't visible to the block's parent. -->\r\n <fly-animated-emoji\r\n #anim\r\n class=\"fly-emoji-picker__glyph\"\r\n [id]=\"cell.entry.id\"\r\n [size]=\"20\"\r\n (pointerenter)=\"onCellHover(anim)\"\r\n (pointerleave)=\"cancelHover()\" />\r\n } @else {\r\n <span class=\"fly-emoji-picker__glyph\">{{ cell.glyph }}</span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n } @empty {\r\n <p class=\"fly-emoji-picker__empty\">{{ 'agent.lookup.no_results' | translate }}</p>\r\n }\r\n\r\n <!-- Lives INSIDE the scroller, as the last row, rather than pinned below it \u2014 a static\r\n footer row permanently ate into the vertical space actual emoji rows could use;\r\n scrolled into view instead, it only costs space once you reach the end. -->\r\n @if (hasMore()) {\r\n <button type=\"button\" class=\"fly-emoji-picker__more\" (click)=\"toggleExpanded()\">\r\n {{ (isExpanded() ? 'common.label.emoji_show_less' : 'common.label.emoji_show_more') | translate }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:block;block-size:100%;-webkit-backdrop-filter:blur(24px) saturate(130%);backdrop-filter:blur(24px) saturate(130%);--fly-emoji-cell: 36px;--fly-emoji-cell-gap: 6px;--fly-emoji-glyph: 17px;--fly-emoji-section-gap: 14px;--fly-emoji-bar-gap: 8px;--fly-emoji-search-font: 12px;--fly-emoji-search-padding: 8px 10px;--fly-emoji-heading-display: block}:host(.fly-emoji-picker--medium){--fly-emoji-cell: 30px;--fly-emoji-cell-gap: 5px;--fly-emoji-glyph: 16px;--fly-emoji-section-gap: 10px;--fly-emoji-bar-gap: 6px;--fly-emoji-search-font: 11.5px;--fly-emoji-search-padding: 6px 9px}:host(.fly-emoji-picker--small){--fly-emoji-cell: 24px;--fly-emoji-cell-gap: 3px;--fly-emoji-glyph: 15px;--fly-emoji-section-gap: 6px;--fly-emoji-bar-gap: 5px;--fly-emoji-search-font: 11px;--fly-emoji-search-padding: 4px 7px;--fly-emoji-heading-display: none;--fly-emoji-picker-list-max: 132px}.fly-emoji-picker{display:flex;flex-direction:column;gap:var(--fly-emoji-bar-gap);box-sizing:border-box;block-size:100%;color:var(--text-color, inherit)}.fly-emoji-picker__bar{display:flex;align-items:center;gap:10px}.fly-emoji-picker__search{flex:1 1 auto;min-inline-size:0;box-sizing:border-box;padding:var(--fly-emoji-search-padding);font:inherit;font-size:var(--fly-emoji-search-font);border:1px solid var(--surface-border, rgba(255, 255, 255, .12));border-radius:5px;background:transparent;color:var(--text-color, inherit);outline:none}.fly-emoji-picker__search:focus{border-color:var(--primary-color)}.fly-emoji-picker__list{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--fly-emoji-section-gap);min-block-size:0;max-block-size:var(--fly-emoji-picker-list-max, 320px);overflow-y:auto;padding-inline-end:4px}.fly-emoji-picker__section{display:flex;flex-direction:column;gap:6px}.fly-emoji-picker__heading{display:var(--fly-emoji-heading-display);position:sticky;inset-block-start:0;z-index:1;margin:0;padding-block:3px;font-size:10px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--text-color-secondary, rgba(235, 235, 245, .55));background:var(--surface-overlay, var(--surface-card, #1c1c1e))}.fly-emoji-picker__tones{position:relative;flex:0 0 auto}.fly-emoji-picker__tone-trigger{display:flex;align-items:center;gap:2px;inline-size:auto;block-size:22px;padding:0 4px;font-size:14px;line-height:1;border:1px solid var(--surface-border, rgba(255, 255, 255, .12));border-radius:5px;background:transparent;color:var(--text-color-secondary, rgba(235, 235, 245, .55));cursor:pointer;transition:background .1s ease,border-color .1s ease}.fly-emoji-picker__tone-trigger:hover{background:var(--surface-hover, rgba(255, 255, 255, .08))}.fly-emoji-picker__tone-trigger:focus-visible{outline:2px solid var(--primary-color);outline-offset:-1px}.fly-emoji-picker__tone-glyph{line-height:1}.fly-emoji-picker__tone-caret{font-size:8px}.fly-emoji-picker__tone-menu{position:absolute;inset-block-start:calc(100% + 4px);inset-inline-end:0;z-index:21;display:grid;grid-template-columns:repeat(3,1fr);gap:2px;padding:4px;background:var(--surface-overlay-strong, var(--surface-overlay, var(--surface-card, #1c1c1e)));border:1px solid var(--surface-border, rgba(255, 255, 255, .12));border-radius:8px;box-shadow:0 8px 24px #00000047}.fly-emoji-picker__tone-option{display:grid;place-items:center;inline-size:26px;block-size:26px;padding:0;font-size:15px;line-height:1;border:1px solid transparent;border-radius:5px;background:transparent;cursor:pointer;transition:background .1s ease,border-color .1s ease}.fly-emoji-picker__tone-option:hover{background:var(--surface-hover, rgba(255, 255, 255, .08))}.fly-emoji-picker__tone-option:focus-visible{outline:2px solid var(--primary-color);outline-offset:-1px}.fly-emoji-picker__tone-option.is-active{border-color:var(--primary-color);background:var(--surface-hover, rgba(255, 255, 255, .1))}.fly-emoji-picker__grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(var(--fly-emoji-cell),1fr));gap:var(--fly-emoji-cell-gap)}.fly-emoji-picker__cell{display:flex;align-items:center;justify-content:center;aspect-ratio:1;min-block-size:var(--fly-emoji-cell);padding:4px;border:1px solid transparent;border-radius:6px;background:transparent;color:var(--text-color, inherit);cursor:pointer;transition:background .1s ease,border-color .1s ease}.fly-emoji-picker__cell:hover{background:var(--surface-hover, rgba(255, 255, 255, .08));border-color:var(--surface-border, rgba(255, 255, 255, .12))}.fly-emoji-picker__cell:focus-visible{outline:2px solid var(--primary-color);outline-offset:-1px}.fly-emoji-picker__cell.is-active{border-color:var(--primary-color);background:var(--selection-bg, rgba(0, 113, 227, .24))}.fly-emoji-picker__glyph{direction:ltr;font-size:var(--fly-emoji-glyph);line-height:1}.fly-emoji-picker__more{align-self:flex-start;padding:3px 8px;font:inherit;font-size:11px;border:none;border-radius:999px;background:transparent;color:var(--primary-color);cursor:pointer}.fly-emoji-picker__more:hover{background:var(--surface-hover, rgba(255, 255, 255, .06))}.fly-emoji-picker__more:focus-visible{outline:2px solid var(--primary-color);outline-offset:1px}.fly-emoji-picker__empty{margin:0;padding:12px 4px;text-align:center;font-size:12px;color:var(--text-color-secondary, rgba(235, 235, 245, .5))}.fly-emoji-picker__tabs{display:flex;gap:4px;border-block-end:1px solid var(--surface-border, rgba(255, 255, 255, .12))}.fly-emoji-picker__tab{appearance:none;padding:6px 12px;font:inherit;font-size:12px;border:none;border-block-end:2px solid transparent;background:transparent;color:var(--text-color-secondary, rgba(235, 235, 245, .6));cursor:pointer}.fly-emoji-picker__tab.is-active{color:var(--text-color, inherit);border-block-end-color:var(--primary-color)}.fly-emoji-picker__tab:focus-visible{outline:2px solid var(--primary-color);outline-offset:-2px}.fly-emoji-picker__stickers{flex:1 1 auto;min-block-size:0;overflow-y:auto;display:grid;grid-template-columns:repeat(auto-fill,minmax(72px,1fr));gap:6px;padding:4px}.fly-emoji-picker__sticker{appearance:none;display:flex;align-items:center;justify-content:center;padding:4px;border:none;border-radius:10px;background:transparent;cursor:pointer}.fly-emoji-picker__sticker:hover,.fly-emoji-picker__sticker:focus-visible{background:var(--surface-hover, rgba(255, 255, 255, .08))}.fly-emoji-picker__sticker:focus-visible{outline:2px solid var(--primary-color);outline-offset:-2px}\n"], dependencies: [{ kind: "directive", type: FlyClickOutsideDirective, selector: "[flyClickOutside]", inputs: ["flyClickOutsideEnabled"], outputs: ["flyClickOutside"] }, { kind: "directive", type: FlyTooltipDirective, selector: "[flyTooltip]", inputs: ["flyTooltip", "flyTooltipPlacement", "flyTooltipDisabled", "flyTooltipDelay"] }, { kind: "component", type: FlyAnimatedEmojiComponent, selector: "fly-animated-emoji", inputs: ["id", "size", "autoplayOnFirstVisible", "playOnHover"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6956
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyEmojiPickerComponent, isStandalone: true, selector: "fly-emoji-picker", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null }, categories: { classPropertyName: "categories", publicName: "categories", isSignal: true, isRequired: false, transformFunction: null }, defaultCategory: { classPropertyName: "defaultCategory", publicName: "defaultCategory", isSignal: true, isRequired: false, transformFunction: null }, skinTones: { classPropertyName: "skinTones", publicName: "skinTones", isSignal: true, isRequired: false, transformFunction: null }, skinTone: { classPropertyName: "skinTone", publicName: "skinTone", isSignal: true, isRequired: false, transformFunction: null }, showMore: { classPropertyName: "showMore", publicName: "showMore", isSignal: true, isRequired: false, transformFunction: null }, previewCount: { classPropertyName: "previewCount", publicName: "previewCount", isSignal: true, isRequired: false, transformFunction: null }, emojiAnimation: { classPropertyName: "emojiAnimation", publicName: "emojiAnimation", isSignal: true, isRequired: false, transformFunction: null }, dismissOnOutsidePress: { classPropertyName: "dismissOnOutsidePress", publicName: "dismissOnOutsidePress", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { stickerPicked: "stickerPicked", toggled: "toggled", selectionChange: "selectionChange", skinToneChange: "skinToneChange", dismissed: "dismissed" }, host: { properties: { "class.fly-emoji-picker--small": "size() === 'small'", "class.fly-emoji-picker--medium": "size() === 'medium'", "class.fly-emoji-picker--large": "size() === 'large'" } }, viewQueries: [{ propertyName: "searchRef", first: true, predicate: ["searchRef"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\r\n class=\"fly-emoji-picker\"\r\n [flyClickOutsideEnabled]=\"dismissOnOutsidePress()\"\r\n (flyClickOutside)=\"dismissed.emit()\"\r\n [attr.aria-label]=\"'common.label.emoji_picker' | translate\">\r\n <!-- Stickers mode only: the emoji grid is unchanged, stickers are an ADDITIONAL surface. -->\r\n @if (showTabs()) {\r\n <div\r\n class=\"fly-emoji-picker__tabs\"\r\n role=\"tablist\"\r\n [attr.aria-label]=\"'common.label.emoji_tabs' | translate\">\r\n <button\r\n type=\"button\"\r\n class=\"fly-emoji-picker__tab\"\r\n role=\"tab\"\r\n id=\"fly-emoji-tab-emoji\"\r\n aria-controls=\"fly-emoji-panel-emoji\"\r\n [class.is-active]=\"activeTab() === 'emoji'\"\r\n [attr.aria-selected]=\"activeTab() === 'emoji'\"\r\n [attr.tabindex]=\"activeTab() === 'emoji' ? 0 : -1\"\r\n (keydown)=\"onTabKeydown($event)\"\r\n (click)=\"selectTab('emoji')\">\r\n {{ 'common.label.emoji_tab_emoji' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fly-emoji-picker__tab\"\r\n role=\"tab\"\r\n id=\"fly-emoji-tab-stickers\"\r\n aria-controls=\"fly-emoji-panel-stickers\"\r\n [class.is-active]=\"activeTab() === 'stickers'\"\r\n [attr.aria-selected]=\"activeTab() === 'stickers'\"\r\n [attr.tabindex]=\"activeTab() === 'stickers' ? 0 : -1\"\r\n (keydown)=\"onTabKeydown($event)\"\r\n (click)=\"selectTab('stickers')\">\r\n {{ 'common.label.emoji_tab_stickers' | translate }}\r\n </button>\r\n </div>\r\n }\r\n\r\n @if (showTabs() && activeTab() === 'stickers') {\r\n <div\r\n class=\"fly-emoji-picker__stickers\"\r\n id=\"fly-emoji-panel-stickers\"\r\n role=\"tabpanel\"\r\n aria-labelledby=\"fly-emoji-tab-stickers\">\r\n @for (entry of stickers(); track entry.id) {\r\n <button\r\n type=\"button\"\r\n class=\"fly-emoji-picker__sticker\"\r\n [flyTooltip]=\"entry.label\"\r\n [attr.aria-label]=\"entry.label\"\r\n (pointerenter)=\"onCellHover(sticker)\"\r\n (pointerleave)=\"cancelHover()\"\r\n (click)=\"pickSticker(entry)\">\r\n <fly-animated-emoji #sticker [id]=\"entry.id\" [size]=\"64\" />\r\n </button>\r\n } @empty {\r\n <p class=\"fly-emoji-picker__empty\">{{ 'agent.lookup.no_results' | translate }}</p>\r\n }\r\n </div>\r\n }\r\n\r\n @if (!showTabs() || activeTab() === 'emoji') {\r\n <!-- Search + tone sit together as one chrome bar: the tone swatches are hands, and on their own row\r\n above the grid they read as pickable content rather than a setting. -->\r\n <div class=\"fly-emoji-picker__bar\">\r\n <input\r\n class=\"fly-emoji-picker__search\"\r\n type=\"text\"\r\n #searchRef\r\n [value]=\"query()\"\r\n (input)=\"onQueryInput(searchRef.value)\"\r\n [placeholder]=\"'common.label.search_emoji' | translate\"\r\n [attr.aria-label]=\"'common.label.search_emoji' | translate\"\r\n spellcheck=\"false\"\r\n autocomplete=\"off\" />\r\n\r\n @if (showToneStrip()) {\r\n <!-- Escape-to-close listener only \u2014 every actual control inside (trigger + options) is its\r\n own focusable button, so this wrapper itself doesn't need to be. -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\r\n <div\r\n class=\"fly-emoji-picker__tones\"\r\n [flyClickOutsideEnabled]=\"toneMenuOpen()\"\r\n (flyClickOutside)=\"toneMenuOpen.set(false)\"\r\n (keydown.escape)=\"toneMenuOpen.set(false)\">\r\n <button\r\n type=\"button\"\r\n class=\"fly-emoji-picker__tone-trigger\"\r\n aria-haspopup=\"listbox\"\r\n [attr.aria-expanded]=\"toneMenuOpen()\"\r\n [attr.aria-label]=\"'common.label.skin_tone' | translate\"\r\n [flyTooltip]=\"toneLabelKey(effectiveTone()) | translate\"\r\n (click)=\"toneMenuOpen.set(!toneMenuOpen())\">\r\n <span class=\"fly-emoji-picker__tone-glyph\">{{ toneSwatch(effectiveTone()) }}</span>\r\n <i class=\"pi pi-chevron-down fly-emoji-picker__tone-caret\" aria-hidden=\"true\"></i>\r\n </button>\r\n\r\n @if (toneMenuOpen()) {\r\n <div\r\n class=\"fly-emoji-picker__tone-menu\"\r\n role=\"listbox\"\r\n [attr.aria-label]=\"'common.label.skin_tone' | translate\">\r\n @for (tone of tones; track tone) {\r\n <button\r\n type=\"button\"\r\n class=\"fly-emoji-picker__tone-option\"\r\n role=\"option\"\r\n [class.is-active]=\"effectiveTone() === tone\"\r\n [attr.aria-selected]=\"effectiveTone() === tone\"\r\n [flyTooltip]=\"toneLabelKey(tone) | translate\"\r\n (click)=\"onToneOptionClick(tone)\">\r\n {{ toneSwatch(tone) }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- ONE scrolling list; each category is a separator label over its own grid. Tabs wrapped to three\r\n rows in a sidebar drawer and cost a click to reach any group. -->\r\n <div\r\n class=\"fly-emoji-picker__list\"\r\n role=\"listbox\"\r\n [attr.id]=\"showTabs() ? 'fly-emoji-panel-emoji' : null\"\r\n [attr.aria-labelledby]=\"showTabs() ? 'fly-emoji-tab-emoji' : null\"\r\n [attr.aria-multiselectable]=\"selectionMode() === 'multi'\">\r\n @for (section of sections(); track section.id) {\r\n <div class=\"fly-emoji-picker__section\" role=\"group\" [attr.aria-label]=\"sectionLabel(section)\">\r\n <h4 class=\"fly-emoji-picker__heading\">{{ sectionLabel(section) }}</h4>\r\n <div class=\"fly-emoji-picker__grid\">\r\n @for (cell of section.cells; track cell.entry.id) {\r\n <button\r\n type=\"button\"\r\n class=\"fly-emoji-picker__cell\"\r\n role=\"option\"\r\n [class.is-active]=\"cell.selected\"\r\n [attr.aria-selected]=\"cell.selected\"\r\n [flyTooltip]=\"cell.entry.label\"\r\n [attr.aria-label]=\"cell.entry.label\"\r\n (click)=\"pick(cell.entry)\">\r\n @if (section.animated) {\r\n <!-- Hover lives on the animated element, not the button: a template reference\r\n declared inside a control-flow block isn't visible to the block's parent. -->\r\n <fly-animated-emoji\r\n #anim\r\n class=\"fly-emoji-picker__glyph\"\r\n [id]=\"cell.entry.id\"\r\n [size]=\"20\"\r\n (pointerenter)=\"onCellHover(anim)\"\r\n (pointerleave)=\"cancelHover()\" />\r\n } @else {\r\n <span class=\"fly-emoji-picker__glyph\">{{ cell.glyph }}</span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n } @empty {\r\n <p class=\"fly-emoji-picker__empty\">{{ 'agent.lookup.no_results' | translate }}</p>\r\n }\r\n\r\n <!-- Lives INSIDE the scroller, as the last row, rather than pinned below it \u2014 a static\r\n footer row permanently ate into the vertical space actual emoji rows could use;\r\n scrolled into view instead, it only costs space once you reach the end. -->\r\n @if (hasMore()) {\r\n <button type=\"button\" class=\"fly-emoji-picker__more\" (click)=\"toggleExpanded()\">\r\n {{ (isExpanded() ? 'common.label.emoji_show_less' : 'common.label.emoji_show_more') | translate }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:block;block-size:100%;-webkit-backdrop-filter:blur(24px) saturate(130%);backdrop-filter:blur(24px) saturate(130%);--fly-emoji-cell: 36px;--fly-emoji-cell-gap: 6px;--fly-emoji-glyph: 17px;--fly-emoji-section-gap: 14px;--fly-emoji-bar-gap: 8px;--fly-emoji-search-font: 12px;--fly-emoji-search-padding: 8px 10px;--fly-emoji-heading-display: block}:host(.fly-emoji-picker--medium){--fly-emoji-cell: 30px;--fly-emoji-cell-gap: 5px;--fly-emoji-glyph: 16px;--fly-emoji-section-gap: 10px;--fly-emoji-bar-gap: 6px;--fly-emoji-search-font: 11.5px;--fly-emoji-search-padding: 6px 9px}:host(.fly-emoji-picker--small){--fly-emoji-cell: 24px;--fly-emoji-cell-gap: 3px;--fly-emoji-glyph: 15px;--fly-emoji-section-gap: 6px;--fly-emoji-bar-gap: 5px;--fly-emoji-search-font: 11px;--fly-emoji-search-padding: 4px 7px;--fly-emoji-heading-display: none;--fly-emoji-picker-list-max: 132px}.fly-emoji-picker{display:flex;flex-direction:column;gap:var(--fly-emoji-bar-gap);box-sizing:border-box;block-size:100%;color:var(--text-color, inherit)}.fly-emoji-picker__bar{display:flex;align-items:center;gap:10px}.fly-emoji-picker__search{flex:1 1 auto;min-inline-size:0;box-sizing:border-box;padding:var(--fly-emoji-search-padding);font:inherit;font-size:var(--fly-emoji-search-font);border:1px solid var(--surface-border, rgba(255, 255, 255, .12));border-radius:5px;background:transparent;color:var(--text-color, inherit);outline:none}.fly-emoji-picker__search:focus{border-color:var(--primary-color)}.fly-emoji-picker__list{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--fly-emoji-section-gap);min-block-size:0;max-block-size:var(--fly-emoji-picker-list-max, 320px);overflow-y:auto;padding-inline-end:4px}.fly-emoji-picker__section{display:flex;flex-direction:column;gap:6px}.fly-emoji-picker__heading{display:var(--fly-emoji-heading-display);position:sticky;inset-block-start:0;z-index:1;margin:0;padding-block:3px;font-size:10px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--text-color-secondary, rgba(235, 235, 245, .55));background:var(--surface-overlay, var(--surface-card, #1c1c1e))}.fly-emoji-picker__tones{position:relative;flex:0 0 auto}.fly-emoji-picker__tone-trigger{display:flex;align-items:center;gap:2px;inline-size:auto;block-size:22px;padding:0 4px;font-size:14px;line-height:1;border:1px solid var(--surface-border, rgba(255, 255, 255, .12));border-radius:5px;background:transparent;color:var(--text-color-secondary, rgba(235, 235, 245, .55));cursor:pointer;transition:background .1s ease,border-color .1s ease}.fly-emoji-picker__tone-trigger:hover{background:var(--surface-hover, rgba(255, 255, 255, .08))}.fly-emoji-picker__tone-trigger:focus-visible{outline:2px solid var(--primary-color);outline-offset:-1px}.fly-emoji-picker__tone-glyph{line-height:1}.fly-emoji-picker__tone-caret{font-size:8px}.fly-emoji-picker__tone-menu{position:absolute;inset-block-start:calc(100% + 4px);inset-inline-end:0;z-index:21;display:grid;grid-template-columns:repeat(3,1fr);gap:2px;padding:4px;background:var(--surface-overlay-strong, var(--surface-overlay, var(--surface-card, #1c1c1e)));border:1px solid var(--surface-border, rgba(255, 255, 255, .12));border-radius:8px;box-shadow:0 8px 24px #00000047}.fly-emoji-picker__tone-option{display:grid;place-items:center;inline-size:26px;block-size:26px;padding:0;font-size:15px;line-height:1;border:1px solid transparent;border-radius:5px;background:transparent;cursor:pointer;transition:background .1s ease,border-color .1s ease}.fly-emoji-picker__tone-option:hover{background:var(--surface-hover, rgba(255, 255, 255, .08))}.fly-emoji-picker__tone-option:focus-visible{outline:2px solid var(--primary-color);outline-offset:-1px}.fly-emoji-picker__tone-option.is-active{border-color:var(--primary-color);background:var(--surface-hover, rgba(255, 255, 255, .1))}.fly-emoji-picker__grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(var(--fly-emoji-cell),1fr));gap:var(--fly-emoji-cell-gap)}.fly-emoji-picker__cell{display:flex;align-items:center;justify-content:center;aspect-ratio:1;min-block-size:var(--fly-emoji-cell);padding:4px;border:1px solid transparent;border-radius:6px;background:transparent;color:var(--text-color, inherit);cursor:pointer;transition:background .1s ease,border-color .1s ease}.fly-emoji-picker__cell:hover{background:var(--surface-hover, rgba(255, 255, 255, .08));border-color:var(--surface-border, rgba(255, 255, 255, .12))}.fly-emoji-picker__cell:focus-visible{outline:2px solid var(--primary-color);outline-offset:-1px}.fly-emoji-picker__cell.is-active{border-color:var(--primary-color);background:var(--selection-bg, rgba(0, 113, 227, .24))}.fly-emoji-picker__glyph{direction:ltr;font-size:var(--fly-emoji-glyph);line-height:1}.fly-emoji-picker__more{align-self:flex-start;padding:3px 8px;font:inherit;font-size:11px;border:none;border-radius:999px;background:transparent;color:var(--primary-color);cursor:pointer}.fly-emoji-picker__more:hover{background:var(--surface-hover, rgba(255, 255, 255, .06))}.fly-emoji-picker__more:focus-visible{outline:2px solid var(--primary-color);outline-offset:1px}.fly-emoji-picker__empty{margin:0;padding:12px 4px;text-align:center;font-size:12px;color:var(--text-color-secondary, rgba(235, 235, 245, .5))}.fly-emoji-picker__tabs{display:flex;gap:4px;border-block-end:1px solid var(--surface-border, rgba(255, 255, 255, .12))}.fly-emoji-picker__tab{appearance:none;padding:6px 12px;font:inherit;font-size:12px;border:none;border-block-end:2px solid transparent;background:transparent;color:var(--text-color-secondary, rgba(235, 235, 245, .6));cursor:pointer}.fly-emoji-picker__tab.is-active{color:var(--text-color, inherit);border-block-end-color:var(--primary-color)}.fly-emoji-picker__tab:focus-visible{outline:2px solid var(--primary-color);outline-offset:-2px}.fly-emoji-picker__stickers{flex:1 1 auto;min-block-size:0;overflow-y:auto;display:grid;grid-template-columns:repeat(auto-fill,minmax(72px,1fr));gap:6px;padding:4px}.fly-emoji-picker__sticker{appearance:none;display:flex;align-items:center;justify-content:center;padding:4px;border:none;border-radius:10px;background:transparent;cursor:pointer}.fly-emoji-picker__sticker:hover,.fly-emoji-picker__sticker:focus-visible{background:var(--surface-hover, rgba(255, 255, 255, .08))}.fly-emoji-picker__sticker:focus-visible{outline:2px solid var(--primary-color);outline-offset:-2px}\n"], dependencies: [{ kind: "directive", type: FlyClickOutsideDirective, selector: "[flyClickOutside]", inputs: ["flyClickOutsideEnabled"], outputs: ["flyClickOutside"] }, { kind: "directive", type: FlyTooltipDirective, selector: "[flyTooltip], [data-tooltip]", inputs: ["flyTooltip", "flyTooltipPlacement", "flyTooltipDisabled", "flyTooltipDelay"] }, { kind: "component", type: FlyAnimatedEmojiComponent, selector: "fly-animated-emoji", inputs: ["id", "size", "autoplayOnFirstVisible", "playOnHover"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6917
6957
|
}
|
|
6918
6958
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyEmojiPickerComponent, decorators: [{
|
|
6919
6959
|
type: Component,
|
|
@@ -17316,8 +17356,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
17316
17356
|
* Circular 34px icon-only button (ported from the legacy global
|
|
17317
17357
|
* `.circles-iconbtn` disc — both render identically until the P6 sweep).
|
|
17318
17358
|
*
|
|
17319
|
-
* `tooltipKey` resolves through {@link I18nService} and wires BOTH
|
|
17320
|
-
* `
|
|
17359
|
+
* `tooltipKey` resolves through {@link I18nService} and wires BOTH `data-tooltip` and
|
|
17360
|
+
* `aria-label`, re-resolving on locale change.
|
|
17361
|
+
*
|
|
17362
|
+
* The label is FLOATED by {@link FlyTooltipDirective} (a body-parented `position: fixed`
|
|
17363
|
+
* node), listed here as a host directive. It used to be a CSS `::before` on
|
|
17364
|
+
* `[data-tooltip]`, which any scrolling or `overflow: hidden` ancestor clipped — the
|
|
17365
|
+
* boards toolbar rail cut every tip off inside its own column. The directive reads the
|
|
17366
|
+
* attribute this component writes, so there is no input to keep in sync.
|
|
17321
17367
|
*/
|
|
17322
17368
|
class FlyIconButtonComponent {
|
|
17323
17369
|
i18n = inject(I18nService);
|
|
@@ -17350,11 +17396,11 @@ class FlyIconButtonComponent {
|
|
|
17350
17396
|
});
|
|
17351
17397
|
}
|
|
17352
17398
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyIconButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
17353
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.19", type: FlyIconButtonComponent, isStandalone: true, selector: "button[fly-icon-button]", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, tooltipKey: { classPropertyName: "tooltipKey", publicName: "tooltipKey", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-variant": "variant()", "class.on": "active()" } }, ngImport: i0, template: '<ng-content />', isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;flex-shrink:0;padding:0;border-radius:50%;background:var(--bg-2);border:1px solid var(--line);color:var(--ink-2);cursor:pointer;font-family:inherit;transition:background var(--t-state),border-color var(--t-state),color var(--t-state)}:host:hover{background:var(--bg-3);color:var(--ink);border-color:var(--line-2)}:host:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}:host:disabled{opacity:.5;cursor:not-allowed}:host ::ng-deep svg{width:16px;height:16px}:host .pi,:host ::ng-deep .pi{font-size:16px}:host(.on){background:var(--bg-3);border-color:var(--line-2);color:var(--ink)}:host([data-variant=primary]){background:var(--grad);border:0;color:var(--ink-inverse);box-shadow:var(--shadow-raised)}:host([data-variant=primary]):hover{background:var(--grad);border:0;color:var(--ink-inverse);filter:brightness(1.05);box-shadow:var(--shadow-accent)}:host([data-variant=danger]){color:var(--danger)}:host([data-variant=danger]):hover{background:var(--danger-bg);border-color:var(--danger-line);color:var(--danger)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
17399
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.19", type: FlyIconButtonComponent, isStandalone: true, selector: "button[fly-icon-button]", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, tooltipKey: { classPropertyName: "tooltipKey", publicName: "tooltipKey", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-variant": "variant()", "class.on": "active()" } }, hostDirectives: [{ directive: FlyTooltipDirective }], ngImport: i0, template: '<ng-content />', isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;flex-shrink:0;padding:0;border-radius:50%;background:var(--bg-2);border:1px solid var(--line);color:var(--ink-2);cursor:pointer;font-family:inherit;transition:background var(--t-state),border-color var(--t-state),color var(--t-state)}:host:hover{background:var(--bg-3);color:var(--ink);border-color:var(--line-2)}:host:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}:host:disabled{opacity:.5;cursor:not-allowed}:host ::ng-deep svg{width:16px;height:16px}:host .pi,:host ::ng-deep .pi{font-size:16px}:host(.on){background:var(--bg-3);border-color:var(--line-2);color:var(--ink)}:host([data-variant=primary]){background:var(--grad);border:0;color:var(--ink-inverse);box-shadow:var(--shadow-raised)}:host([data-variant=primary]):hover{background:var(--grad);border:0;color:var(--ink-inverse);filter:brightness(1.05);box-shadow:var(--shadow-accent)}:host([data-variant=danger]){color:var(--danger)}:host([data-variant=danger]):hover{background:var(--danger-bg);border-color:var(--danger-line);color:var(--danger)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
17354
17400
|
}
|
|
17355
17401
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyIconButtonComponent, decorators: [{
|
|
17356
17402
|
type: Component,
|
|
17357
|
-
args: [{ selector: 'button[fly-icon-button]', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
17403
|
+
args: [{ selector: 'button[fly-icon-button]', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, hostDirectives: [FlyTooltipDirective], host: {
|
|
17358
17404
|
'[attr.data-variant]': 'variant()',
|
|
17359
17405
|
'[class.on]': 'active()',
|
|
17360
17406
|
}, template: '<ng-content />', styles: [":host{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;flex-shrink:0;padding:0;border-radius:50%;background:var(--bg-2);border:1px solid var(--line);color:var(--ink-2);cursor:pointer;font-family:inherit;transition:background var(--t-state),border-color var(--t-state),color var(--t-state)}:host:hover{background:var(--bg-3);color:var(--ink);border-color:var(--line-2)}:host:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}:host:disabled{opacity:.5;cursor:not-allowed}:host ::ng-deep svg{width:16px;height:16px}:host .pi,:host ::ng-deep .pi{font-size:16px}:host(.on){background:var(--bg-3);border-color:var(--line-2);color:var(--ink)}:host([data-variant=primary]){background:var(--grad);border:0;color:var(--ink-inverse);box-shadow:var(--shadow-raised)}:host([data-variant=primary]):hover{background:var(--grad);border:0;color:var(--ink-inverse);filter:brightness(1.05);box-shadow:var(--shadow-accent)}:host([data-variant=danger]){color:var(--danger)}:host([data-variant=danger]):hover{background:var(--danger-bg);border-color:var(--danger-line);color:var(--danger)}\n"] }]
|
|
@@ -17513,11 +17559,11 @@ class StatusBadgeComponent {
|
|
|
17513
17559
|
return `common.status.${this.status().toLowerCase()}`;
|
|
17514
17560
|
}
|
|
17515
17561
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: StatusBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
17516
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: StatusBadgeComponent, isStandalone: true, selector: "fly-status-badge", inputs: { status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: true, transformFunction: null }, dot: { classPropertyName: "dot", publicName: "dot", isSignal: true, isRequired: false, transformFunction: null }, domain: { classPropertyName: "domain", publicName: "domain", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (dot()) {\r\n <!-- \"Status light\": a colour-coded dot with a soft concentric halo in the\r\n status colour. The label is shown on hover (
|
|
17562
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: StatusBadgeComponent, isStandalone: true, selector: "fly-status-badge", inputs: { status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: true, transformFunction: null }, dot: { classPropertyName: "dot", publicName: "dot", isSignal: true, isRequired: false, transformFunction: null }, domain: { classPropertyName: "domain", publicName: "domain", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (dot()) {\r\n <!-- \"Status light\": a colour-coded dot with a soft concentric halo in the\r\n status colour. The label is shown on hover (`flyTooltip`) and read by screen readers\r\n (aria-label) \u2014 compact, glanceable, and modern.\r\n `[flyTooltip]` and NOT `[attr.data-tooltip]`: Angular does not selector-match a directive\r\n against an `attr.`-prefixed binding, so the attribute form compiles to a bare attribute with\r\n nothing listening \u2014 which, now that the CSS pseudo-element tooltip is gone, would show no\r\n label at all. `data-tooltip` stays alongside it as the styling/test hook it always was. -->\r\n <span\r\n class=\"status-dot\"\r\n [ngClass]=\"'status-dot--' + statusClass()\"\r\n [flyTooltip]=\"labelKey() | translate\"\r\n [attr.data-tooltip]=\"labelKey() | translate\"\r\n [attr.aria-label]=\"labelKey() | translate\"\r\n role=\"img\"\r\n tabindex=\"0\"\r\n ></span>\r\n} @else {\r\n <span class=\"status-badge\" [ngClass]=\"'status-badge--' + statusClass()\">\r\n {{ labelKey() | translate }}\r\n </span>\r\n}\r\n", styles: ["@charset \"UTF-8\";.status-badge{display:inline-flex;align-items:center;padding:2px 10px;border-radius:999px;font-size:12px;font-weight:var(--fw-medium)}.status-dot{display:inline-block;inline-size:10px;block-size:10px;border-radius:50%;background:currentColor;box-shadow:0 0 0 3px color-mix(in srgb,currentColor 16%,transparent);cursor:default;transition:transform var(--t-state),box-shadow var(--t-state)}.status-dot:hover,.status-dot:focus-visible{transform:scale(1.18);box-shadow:0 0 0 4px color-mix(in srgb,currentColor 26%,transparent);outline:none}.status-dot--draft{color:var(--color-aeblack-500, var(--ink-3))}.status-dot--review{color:var(--color-aeorange-700, var(--warning-fg))}.status-dot--approved{color:var(--color-aegreen-800, var(--success))}.status-dot--published{color:var(--color-techblue-800, var(--st-approved))}.status-dot--archived{color:var(--color-aeblack-500, var(--ink-3))}.status-dot--planned{color:var(--color-techblue-800, var(--st-approved))}.status-dot--inprogress{color:var(--color-aeorange-700, var(--warning-fg))}.status-dot--completed{color:var(--color-aegreen-800, var(--success))}.status-dot--onhold{color:var(--color-aeorange-800, var(--warning-fg))}.status-dot--cancelled{color:var(--color-aered-800, var(--danger))}.status-badge--draft{background:var(--color-aeblack-100, var(--st-draft-bg));color:var(--color-aeblack-700, var(--st-draft))}.status-badge--review{background:var(--color-aeorange-100, var(--warning-bg));color:var(--color-aeorange-700, var(--warning-fg))}.status-badge--approved{background:var(--color-aegreen-100, var(--success-bg));color:var(--color-aegreen-800, var(--success))}.status-badge--published{background:var(--color-techblue-100, var(--st-approved-bg));color:var(--color-techblue-800, var(--st-approved))}.status-badge--archived{background:var(--color-aeblack-100, var(--st-draft-bg));color:var(--color-aeblack-500, var(--ink-3))}.status-badge--planned{background:var(--color-techblue-100, var(--st-approved-bg));color:var(--color-techblue-800, var(--st-approved))}.status-badge--inprogress{background:var(--color-aeorange-100, var(--warning-bg));color:var(--color-aeorange-700, var(--warning-fg))}.status-badge--completed{background:var(--color-aegreen-100, var(--success-bg));color:var(--color-aegreen-800, var(--success))}.status-badge--onhold{background:var(--color-aeorange-200, var(--warning-bg));color:var(--color-aeorange-800, var(--warning-fg))}.status-badge--cancelled{background:var(--color-aered-100, var(--danger-bg));color:var(--color-aered-800, var(--danger))}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: FlyTooltipDirective, selector: "[flyTooltip], [data-tooltip]", inputs: ["flyTooltip", "flyTooltipPlacement", "flyTooltipDisabled", "flyTooltipDelay"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
17517
17563
|
}
|
|
17518
17564
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: StatusBadgeComponent, decorators: [{
|
|
17519
17565
|
type: Component,
|
|
17520
|
-
args: [{ selector: 'fly-status-badge', standalone: true, imports: [NgClass, TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (dot()) {\r\n <!-- \"Status light\": a colour-coded dot with a soft concentric halo in the\r\n status colour. The label is shown on hover (
|
|
17566
|
+
args: [{ selector: 'fly-status-badge', standalone: true, imports: [NgClass, TranslatePipe, FlyTooltipDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (dot()) {\r\n <!-- \"Status light\": a colour-coded dot with a soft concentric halo in the\r\n status colour. The label is shown on hover (`flyTooltip`) and read by screen readers\r\n (aria-label) \u2014 compact, glanceable, and modern.\r\n `[flyTooltip]` and NOT `[attr.data-tooltip]`: Angular does not selector-match a directive\r\n against an `attr.`-prefixed binding, so the attribute form compiles to a bare attribute with\r\n nothing listening \u2014 which, now that the CSS pseudo-element tooltip is gone, would show no\r\n label at all. `data-tooltip` stays alongside it as the styling/test hook it always was. -->\r\n <span\r\n class=\"status-dot\"\r\n [ngClass]=\"'status-dot--' + statusClass()\"\r\n [flyTooltip]=\"labelKey() | translate\"\r\n [attr.data-tooltip]=\"labelKey() | translate\"\r\n [attr.aria-label]=\"labelKey() | translate\"\r\n role=\"img\"\r\n tabindex=\"0\"\r\n ></span>\r\n} @else {\r\n <span class=\"status-badge\" [ngClass]=\"'status-badge--' + statusClass()\">\r\n {{ labelKey() | translate }}\r\n </span>\r\n}\r\n", styles: ["@charset \"UTF-8\";.status-badge{display:inline-flex;align-items:center;padding:2px 10px;border-radius:999px;font-size:12px;font-weight:var(--fw-medium)}.status-dot{display:inline-block;inline-size:10px;block-size:10px;border-radius:50%;background:currentColor;box-shadow:0 0 0 3px color-mix(in srgb,currentColor 16%,transparent);cursor:default;transition:transform var(--t-state),box-shadow var(--t-state)}.status-dot:hover,.status-dot:focus-visible{transform:scale(1.18);box-shadow:0 0 0 4px color-mix(in srgb,currentColor 26%,transparent);outline:none}.status-dot--draft{color:var(--color-aeblack-500, var(--ink-3))}.status-dot--review{color:var(--color-aeorange-700, var(--warning-fg))}.status-dot--approved{color:var(--color-aegreen-800, var(--success))}.status-dot--published{color:var(--color-techblue-800, var(--st-approved))}.status-dot--archived{color:var(--color-aeblack-500, var(--ink-3))}.status-dot--planned{color:var(--color-techblue-800, var(--st-approved))}.status-dot--inprogress{color:var(--color-aeorange-700, var(--warning-fg))}.status-dot--completed{color:var(--color-aegreen-800, var(--success))}.status-dot--onhold{color:var(--color-aeorange-800, var(--warning-fg))}.status-dot--cancelled{color:var(--color-aered-800, var(--danger))}.status-badge--draft{background:var(--color-aeblack-100, var(--st-draft-bg));color:var(--color-aeblack-700, var(--st-draft))}.status-badge--review{background:var(--color-aeorange-100, var(--warning-bg));color:var(--color-aeorange-700, var(--warning-fg))}.status-badge--approved{background:var(--color-aegreen-100, var(--success-bg));color:var(--color-aegreen-800, var(--success))}.status-badge--published{background:var(--color-techblue-100, var(--st-approved-bg));color:var(--color-techblue-800, var(--st-approved))}.status-badge--archived{background:var(--color-aeblack-100, var(--st-draft-bg));color:var(--color-aeblack-500, var(--ink-3))}.status-badge--planned{background:var(--color-techblue-100, var(--st-approved-bg));color:var(--color-techblue-800, var(--st-approved))}.status-badge--inprogress{background:var(--color-aeorange-100, var(--warning-bg));color:var(--color-aeorange-700, var(--warning-fg))}.status-badge--completed{background:var(--color-aegreen-100, var(--success-bg));color:var(--color-aegreen-800, var(--success))}.status-badge--onhold{background:var(--color-aeorange-200, var(--warning-bg));color:var(--color-aeorange-800, var(--warning-fg))}.status-badge--cancelled{background:var(--color-aered-100, var(--danger-bg));color:var(--color-aered-800, var(--danger))}\n"] }]
|
|
17521
17567
|
}], propDecorators: { status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: true }] }], dot: [{ type: i0.Input, args: [{ isSignal: true, alias: "dot", required: false }] }], domain: [{ type: i0.Input, args: [{ isSignal: true, alias: "domain", required: false }] }] } });
|
|
17522
17568
|
|
|
17523
17569
|
// Class name and selector kept as `DashboardKpiComponent` / `fly-dashboard-kpi`
|
|
@@ -18017,11 +18063,11 @@ class FlyFilterPanelComponent {
|
|
|
18017
18063
|
/** Whether the `[filter-more]` advanced fields are revealed. */
|
|
18018
18064
|
showMore = signal(false, ...(ngDevMode ? [{ debugName: "showMore" }] : /* istanbul ignore next */ []));
|
|
18019
18065
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyFilterPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18020
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyFilterPanelComponent, isStandalone: true, selector: "fly-filter-panel", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: true, transformFunction: null }, titleKey: { classPropertyName: "titleKey", publicName: "titleKey", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null }, hasMore: { classPropertyName: "hasMore", publicName: "hasMore", isSignal: true, isRequired: false, transformFunction: null }, showSearchButton: { classPropertyName: "showSearchButton", publicName: "showSearchButton", isSignal: true, isRequired: false, transformFunction: null }, anchored: { classPropertyName: "anchored", publicName: "anchored", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cleared: "cleared", closed: "closed", searched: "searched" }, host: { properties: { "class.fp--anchored": "anchored()" } }, ngImport: i0, template: " @if (open()) {\r\n <div class=\"fp\" [attr.data-layout]=\"layout()\">\r\n <div class=\"fp__head\">\r\n <div class=\"fp__title\">{{ titleKey() | translate }}</div>\r\n <div class=\"fp__actions\">\r\n <button type=\"button\" class=\"fp__clear\" (click)=\"cleared.emit()\">\r\n {{ 'ui.action.clearFilters' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fp__close\"\r\n (click)=\"closed.emit()\"\r\n [attr.aria-label]=\"'ui.action.close' | translate\"\r\n >\u00D7</button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"fp__body\">\r\n <ng-content select=\"[filter-status]\" />\r\n\r\n <div class=\"fp__grid\">\r\n <ng-content />\r\n </div>\r\n\r\n @if (hasMore()) {\r\n <div class=\"fp__more\" [hidden]=\"!showMore()\">\r\n <div class=\"fp__grid\">\r\n <ng-content select=\"[filter-more]\" />\r\n </div>\r\n </div>\r\n <div class=\"fp__morebar\">\r\n <button\r\n type=\"button\"\r\n class=\"fp__morebtn\"\r\n (click)=\"showMore.set(!showMore())\"\r\n [attr.aria-expanded]=\"showMore()\"\r\n >\r\n <svg class=\"fp__moreico\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <path [attr.d]=\"showMore() ? 'M3.5 8h9' : 'M8 3.5v9M3.5 8h9'\" />\r\n </svg>\r\n {{ (showMore() ? 'ui.action.fewerOptions' : 'ui.action.addMoreOptions') | translate }}\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (showSearchButton()) {\r\n <div class=\"fp__footer\">\r\n <button type=\"button\" fly-button variant=\"primary\" (click)=\"searched.emit()\">\r\n {{ 'ui.action.search' | translate }}\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n \r\n", styles: ["
|
|
18066
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyFilterPanelComponent, isStandalone: true, selector: "fly-filter-panel", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: true, transformFunction: null }, titleKey: { classPropertyName: "titleKey", publicName: "titleKey", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null }, hasMore: { classPropertyName: "hasMore", publicName: "hasMore", isSignal: true, isRequired: false, transformFunction: null }, showSearchButton: { classPropertyName: "showSearchButton", publicName: "showSearchButton", isSignal: true, isRequired: false, transformFunction: null }, anchored: { classPropertyName: "anchored", publicName: "anchored", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cleared: "cleared", closed: "closed", searched: "searched" }, host: { properties: { "class.fp--anchored": "anchored()" } }, ngImport: i0, template: " @if (open()) {\r\n <div class=\"fp\" [attr.data-layout]=\"layout()\">\r\n <div class=\"fp__head\">\r\n <div class=\"fp__title\">{{ titleKey() | translate }}</div>\r\n <div class=\"fp__actions\">\r\n <button type=\"button\" class=\"fp__clear\" (click)=\"cleared.emit()\">\r\n {{ 'ui.action.clearFilters' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fp__close\"\r\n (click)=\"closed.emit()\"\r\n [attr.aria-label]=\"'ui.action.close' | translate\"\r\n >\u00D7</button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"fp__body\">\r\n <ng-content select=\"[filter-status]\" />\r\n\r\n <div class=\"fp__grid\">\r\n <ng-content />\r\n </div>\r\n\r\n @if (hasMore()) {\r\n <div class=\"fp__more\" [hidden]=\"!showMore()\">\r\n <div class=\"fp__grid\">\r\n <ng-content select=\"[filter-more]\" />\r\n </div>\r\n </div>\r\n <div class=\"fp__morebar\">\r\n <button\r\n type=\"button\"\r\n class=\"fp__morebtn\"\r\n (click)=\"showMore.set(!showMore())\"\r\n [attr.aria-expanded]=\"showMore()\"\r\n >\r\n <svg class=\"fp__moreico\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <path [attr.d]=\"showMore() ? 'M3.5 8h9' : 'M8 3.5v9M3.5 8h9'\" />\r\n </svg>\r\n {{ (showMore() ? 'ui.action.fewerOptions' : 'ui.action.addMoreOptions') | translate }}\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (showSearchButton()) {\r\n <div class=\"fp__footer\">\r\n <button type=\"button\" fly-button variant=\"primary\" (click)=\"searched.emit()\">\r\n {{ 'ui.action.search' | translate }}\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n \r\n", styles: ["@charset \"UTF-8\";:host{display:block;container-type:inline-size}.fp{margin-block-end:var(--sp-4);background:var(--bg-2);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-panel);overflow:hidden;animation:fly-fp-in var(--t-overlay)}:host(.fp--anchored){position:absolute;inset-block-start:calc(100% + var(--sp-2));inset-inline-end:0;z-index:var(--z-overlay);width:min(600px,100vw - 2 * var(--sp-4))}:host(.fp--anchored) .fp{margin-block-end:0;box-shadow:var(--shadow-filter)}:host(.fp--anchored) .fp__body{max-height:min(320px,44vh);overflow-y:auto}.fp__head{display:flex;align-items:center;justify-content:space-between;padding:var(--sp-3) var(--sp-4);border-block-end:1px solid var(--line-3);background:var(--bg-3)}.fp__title{font-size:var(--text-xs);font-weight:var(--fw-medium);letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3)}.fp__actions{display:flex;align-items:center;gap:var(--sp-1)}.fp__clear{border:0;background:transparent;font-size:12px;color:var(--ink-3);padding:var(--sp-1) var(--sp-2);border-radius:var(--r-sm);cursor:pointer;font-family:inherit;transition:background var(--t-state),color var(--t-state)}.fp__clear:hover{color:var(--ink);background:var(--bg-hover)}.fp__clear:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.fp__close{width:24px;height:24px;border:0;background:transparent;color:var(--ink-3);cursor:pointer;border-radius:var(--r-sm);font-size:var(--text-xl);line-height:1;display:grid;place-items:center}.fp__close:hover{color:var(--ink);background:var(--bg-hover)}.fp__close:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.fp ::ng-deep [filter-status]{display:flex;flex-direction:column;gap:var(--sp-2);padding:14px var(--sp-4);border-block-end:1px solid var(--line-3)}.fp__grid{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:14px var(--sp-4);padding:var(--sp-4)}@container (width <= 1180px){.fp[data-layout=grid] .fp__grid{grid-template-columns:repeat(4,minmax(0,1fr))}}@media(width<=1180px){.fp[data-layout=grid] .fp__grid{grid-template-columns:repeat(4,minmax(0,1fr))}}@container (width <= 820px){.fp[data-layout=grid] .fp__grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(width<=820px){.fp[data-layout=grid] .fp__grid{grid-template-columns:repeat(2,minmax(0,1fr))}}.fp[data-layout=rows] .fp__grid{grid-template-columns:1fr;gap:var(--sp-2)}.fp[data-layout=rows] ::ng-deep .fld{display:grid;grid-template-columns:minmax(110px,168px) 1fr;align-items:center;gap:var(--sp-1) var(--sp-4)}.fp[data-layout=rows] ::ng-deep .fld__l{margin:0;color:var(--ink-2)}.fp[data-layout=rows] ::ng-deep .fld__hint,.fp[data-layout=rows] ::ng-deep .fld__err{grid-column:2}@container (width <= 640px){.fp[data-layout=rows] ::ng-deep .fld{grid-template-columns:1fr}.fp[data-layout=rows] ::ng-deep .fld__hint,.fp[data-layout=rows] ::ng-deep .fld__err{grid-column:1}}@media(width<=640px){.fp[data-layout=rows] ::ng-deep .fld{grid-template-columns:1fr}.fp[data-layout=rows] ::ng-deep .fld__hint,.fp[data-layout=rows] ::ng-deep .fld__err{grid-column:1}}.fp__more{border-block-start:1px solid var(--line-3)}.fp__more .fp__grid{padding-block-start:var(--sp-3)}.fp__morebar{padding:0 var(--sp-4) var(--sp-3)}.fp__morebtn{display:inline-flex;align-items:center;gap:var(--sp-1);border:0;background:transparent;padding:var(--sp-1) var(--sp-2);border-radius:var(--r-sm);font-family:inherit;font-size:var(--text-sm);font-weight:var(--fw-medium);color:var(--accent);cursor:pointer;transition:background var(--t-state)}.fp__morebtn:hover{background:var(--bg-hover)}.fp__morebtn:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.fp__moreico{width:14px;height:14px;flex-shrink:0}.fp__footer{display:flex;justify-content:flex-end;padding:var(--sp-3) var(--sp-4);border-block-start:1px solid var(--line-3);background:var(--bg-3)}.fp__footer button{background:var(--grad);border:0;color:var(--ink-inverse);box-shadow:var(--shadow-raised)}.fp__footer button:hover{background:var(--grad);border:0;filter:brightness(1.05);box-shadow:var(--shadow-accent)}@keyframes fly-fp-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}\n"], dependencies: [{ kind: "component", type: FlyButtonComponent, selector: "button[fly-button], a[fly-button]", inputs: ["variant", "size", "loading"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
18021
18067
|
}
|
|
18022
18068
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyFilterPanelComponent, decorators: [{
|
|
18023
18069
|
type: Component,
|
|
18024
|
-
args: [{ selector: 'fly-filter-panel', standalone: true, imports: [TranslatePipe, FlyButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class.fp--anchored]': 'anchored()' }, template: " @if (open()) {\r\n <div class=\"fp\" [attr.data-layout]=\"layout()\">\r\n <div class=\"fp__head\">\r\n <div class=\"fp__title\">{{ titleKey() | translate }}</div>\r\n <div class=\"fp__actions\">\r\n <button type=\"button\" class=\"fp__clear\" (click)=\"cleared.emit()\">\r\n {{ 'ui.action.clearFilters' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fp__close\"\r\n (click)=\"closed.emit()\"\r\n [attr.aria-label]=\"'ui.action.close' | translate\"\r\n >\u00D7</button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"fp__body\">\r\n <ng-content select=\"[filter-status]\" />\r\n\r\n <div class=\"fp__grid\">\r\n <ng-content />\r\n </div>\r\n\r\n @if (hasMore()) {\r\n <div class=\"fp__more\" [hidden]=\"!showMore()\">\r\n <div class=\"fp__grid\">\r\n <ng-content select=\"[filter-more]\" />\r\n </div>\r\n </div>\r\n <div class=\"fp__morebar\">\r\n <button\r\n type=\"button\"\r\n class=\"fp__morebtn\"\r\n (click)=\"showMore.set(!showMore())\"\r\n [attr.aria-expanded]=\"showMore()\"\r\n >\r\n <svg class=\"fp__moreico\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <path [attr.d]=\"showMore() ? 'M3.5 8h9' : 'M8 3.5v9M3.5 8h9'\" />\r\n </svg>\r\n {{ (showMore() ? 'ui.action.fewerOptions' : 'ui.action.addMoreOptions') | translate }}\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (showSearchButton()) {\r\n <div class=\"fp__footer\">\r\n <button type=\"button\" fly-button variant=\"primary\" (click)=\"searched.emit()\">\r\n {{ 'ui.action.search' | translate }}\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n \r\n", styles: ["
|
|
18070
|
+
args: [{ selector: 'fly-filter-panel', standalone: true, imports: [TranslatePipe, FlyButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class.fp--anchored]': 'anchored()' }, template: " @if (open()) {\r\n <div class=\"fp\" [attr.data-layout]=\"layout()\">\r\n <div class=\"fp__head\">\r\n <div class=\"fp__title\">{{ titleKey() | translate }}</div>\r\n <div class=\"fp__actions\">\r\n <button type=\"button\" class=\"fp__clear\" (click)=\"cleared.emit()\">\r\n {{ 'ui.action.clearFilters' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fp__close\"\r\n (click)=\"closed.emit()\"\r\n [attr.aria-label]=\"'ui.action.close' | translate\"\r\n >\u00D7</button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"fp__body\">\r\n <ng-content select=\"[filter-status]\" />\r\n\r\n <div class=\"fp__grid\">\r\n <ng-content />\r\n </div>\r\n\r\n @if (hasMore()) {\r\n <div class=\"fp__more\" [hidden]=\"!showMore()\">\r\n <div class=\"fp__grid\">\r\n <ng-content select=\"[filter-more]\" />\r\n </div>\r\n </div>\r\n <div class=\"fp__morebar\">\r\n <button\r\n type=\"button\"\r\n class=\"fp__morebtn\"\r\n (click)=\"showMore.set(!showMore())\"\r\n [attr.aria-expanded]=\"showMore()\"\r\n >\r\n <svg class=\"fp__moreico\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <path [attr.d]=\"showMore() ? 'M3.5 8h9' : 'M8 3.5v9M3.5 8h9'\" />\r\n </svg>\r\n {{ (showMore() ? 'ui.action.fewerOptions' : 'ui.action.addMoreOptions') | translate }}\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (showSearchButton()) {\r\n <div class=\"fp__footer\">\r\n <button type=\"button\" fly-button variant=\"primary\" (click)=\"searched.emit()\">\r\n {{ 'ui.action.search' | translate }}\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n \r\n", styles: ["@charset \"UTF-8\";:host{display:block;container-type:inline-size}.fp{margin-block-end:var(--sp-4);background:var(--bg-2);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-panel);overflow:hidden;animation:fly-fp-in var(--t-overlay)}:host(.fp--anchored){position:absolute;inset-block-start:calc(100% + var(--sp-2));inset-inline-end:0;z-index:var(--z-overlay);width:min(600px,100vw - 2 * var(--sp-4))}:host(.fp--anchored) .fp{margin-block-end:0;box-shadow:var(--shadow-filter)}:host(.fp--anchored) .fp__body{max-height:min(320px,44vh);overflow-y:auto}.fp__head{display:flex;align-items:center;justify-content:space-between;padding:var(--sp-3) var(--sp-4);border-block-end:1px solid var(--line-3);background:var(--bg-3)}.fp__title{font-size:var(--text-xs);font-weight:var(--fw-medium);letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3)}.fp__actions{display:flex;align-items:center;gap:var(--sp-1)}.fp__clear{border:0;background:transparent;font-size:12px;color:var(--ink-3);padding:var(--sp-1) var(--sp-2);border-radius:var(--r-sm);cursor:pointer;font-family:inherit;transition:background var(--t-state),color var(--t-state)}.fp__clear:hover{color:var(--ink);background:var(--bg-hover)}.fp__clear:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.fp__close{width:24px;height:24px;border:0;background:transparent;color:var(--ink-3);cursor:pointer;border-radius:var(--r-sm);font-size:var(--text-xl);line-height:1;display:grid;place-items:center}.fp__close:hover{color:var(--ink);background:var(--bg-hover)}.fp__close:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.fp ::ng-deep [filter-status]{display:flex;flex-direction:column;gap:var(--sp-2);padding:14px var(--sp-4);border-block-end:1px solid var(--line-3)}.fp__grid{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:14px var(--sp-4);padding:var(--sp-4)}@container (width <= 1180px){.fp[data-layout=grid] .fp__grid{grid-template-columns:repeat(4,minmax(0,1fr))}}@media(width<=1180px){.fp[data-layout=grid] .fp__grid{grid-template-columns:repeat(4,minmax(0,1fr))}}@container (width <= 820px){.fp[data-layout=grid] .fp__grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(width<=820px){.fp[data-layout=grid] .fp__grid{grid-template-columns:repeat(2,minmax(0,1fr))}}.fp[data-layout=rows] .fp__grid{grid-template-columns:1fr;gap:var(--sp-2)}.fp[data-layout=rows] ::ng-deep .fld{display:grid;grid-template-columns:minmax(110px,168px) 1fr;align-items:center;gap:var(--sp-1) var(--sp-4)}.fp[data-layout=rows] ::ng-deep .fld__l{margin:0;color:var(--ink-2)}.fp[data-layout=rows] ::ng-deep .fld__hint,.fp[data-layout=rows] ::ng-deep .fld__err{grid-column:2}@container (width <= 640px){.fp[data-layout=rows] ::ng-deep .fld{grid-template-columns:1fr}.fp[data-layout=rows] ::ng-deep .fld__hint,.fp[data-layout=rows] ::ng-deep .fld__err{grid-column:1}}@media(width<=640px){.fp[data-layout=rows] ::ng-deep .fld{grid-template-columns:1fr}.fp[data-layout=rows] ::ng-deep .fld__hint,.fp[data-layout=rows] ::ng-deep .fld__err{grid-column:1}}.fp__more{border-block-start:1px solid var(--line-3)}.fp__more .fp__grid{padding-block-start:var(--sp-3)}.fp__morebar{padding:0 var(--sp-4) var(--sp-3)}.fp__morebtn{display:inline-flex;align-items:center;gap:var(--sp-1);border:0;background:transparent;padding:var(--sp-1) var(--sp-2);border-radius:var(--r-sm);font-family:inherit;font-size:var(--text-sm);font-weight:var(--fw-medium);color:var(--accent);cursor:pointer;transition:background var(--t-state)}.fp__morebtn:hover{background:var(--bg-hover)}.fp__morebtn:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.fp__moreico{width:14px;height:14px;flex-shrink:0}.fp__footer{display:flex;justify-content:flex-end;padding:var(--sp-3) var(--sp-4);border-block-start:1px solid var(--line-3);background:var(--bg-3)}.fp__footer button{background:var(--grad);border:0;color:var(--ink-inverse);box-shadow:var(--shadow-raised)}.fp__footer button:hover{background:var(--grad);border:0;filter:brightness(1.05);box-shadow:var(--shadow-accent)}@keyframes fly-fp-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}\n"] }]
|
|
18025
18071
|
}], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: true }] }], titleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleKey", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }], hasMore: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasMore", required: false }] }], showSearchButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSearchButton", required: false }] }], anchored: [{ type: i0.Input, args: [{ isSignal: true, alias: "anchored", required: false }] }], cleared: [{ type: i0.Output, args: ["cleared"] }], closed: [{ type: i0.Output, args: ["closed"] }], searched: [{ type: i0.Output, args: ["searched"] }] } });
|
|
18026
18072
|
|
|
18027
18073
|
/**
|
|
@@ -18161,11 +18207,11 @@ class FlyDataTableComponent {
|
|
|
18161
18207
|
this.sortChange.emit(nextSort(this.sort(), col.id));
|
|
18162
18208
|
}
|
|
18163
18209
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyDataTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18164
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyDataTableComponent, isStandalone: true, selector: "fly-data-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelKey: { classPropertyName: "ariaLabelKey", publicName: "ariaLabelKey", isSignal: true, isRequired: false, transformFunction: null }, sort: { classPropertyName: "sort", publicName: "sort", isSignal: true, isRequired: false, transformFunction: null }, emptyKey: { classPropertyName: "emptyKey", publicName: "emptyKey", isSignal: true, isRequired: false, transformFunction: null }, emptyIconClass: { classPropertyName: "emptyIconClass", publicName: "emptyIconClass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortChange: "sortChange", rowActivated: "rowActivated" }, queries: [{ propertyName: "cellTemplates", predicate: FlyCellDirective, isSignal: true }], ngImport: i0, template: "<table class=\"dt\" [attr.aria-label]=\"ariaLabelKey() ? (ariaLabelKey()! | translate) : null\">\r\n <thead>\r\n <tr>\r\n @for (col of columns(); track col.id) {\r\n <th\r\n scope=\"col\"\r\n [class.dt__th--end]=\"col.align === 'end'\"\r\n [attr.aria-sort]=\"headerAriaSort(col)\"\r\n >\r\n @if (col.sortable) {\r\n <button type=\"button\" class=\"dt__sort\" (click)=\"onHeaderClick(col)\">\r\n <span>{{ col.headerKey | translate }}</span>\r\n <span class=\"dt__sort-icon\" [attr.data-dir]=\"sortDirFor(col)\" aria-hidden=\"true\"></span>\r\n </button>\r\n } @else {\r\n {{ col.headerKey | translate }}\r\n }\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading()) {\r\n @for (i of skeletonRows; track i) {\r\n <tr class=\"dt__row dt__row--skel\">\r\n <td [attr.colspan]=\"columns().length\">\r\n <!-- shape=\"lines\" is the DS skeleton's no-chrome text shimmer\r\n (the kit's former shape=\"text\"); one line per collapsed row.\r\n No backticks in here: this is an INLINE template literal. -->\r\n <fly-skeleton shape=\"lines\" [lines]=\"1\" />\r\n </td>\r\n </tr>\r\n }\r\n } @else {\r\n @for (row of rows(); track $index) {\r\n <tr\r\n class=\"dt__row\"\r\n tabindex=\"0\"\r\n (click)=\"onRowActivate($event, row)\"\r\n (keydown.enter)=\"onRowActivate($event, row)\"\r\n >\r\n @for (col of columns(); track col.id) {\r\n <td\r\n [class.dt__td--end]=\"col.align === 'end'\"\r\n [class.mono]=\"col.kind === 'mono'\"\r\n [class.dt__td--date]=\"col.kind === 'date'\"\r\n [class.dt__td--num]=\"col.kind === 'number'\"\r\n [attr.data-label]=\"col.headerKey | translate\"\r\n >\r\n @if (templateFor(col.id); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: row }\" />\r\n } @else {\r\n @switch (col.kind ?? 'text') {\r\n @case ('date') {\r\n @if (cellValue(row, col); as value) {\r\n {{ $any(value) | date: 'yyyy-MM-dd' : 'UTC' }}\r\n } @else { \u2014 }\r\n }\r\n @default {\r\n {{ displayValue(row, col) }}\r\n }\r\n }\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n</table>\r\n@if (!loading() && rows().length === 0 && emptyKey()) {\r\n <fly-state-message kind=\"empty\" [messageKey]=\"emptyKey()\" [iconClass]=\"emptyIconClass()\" />\r\n}\r\n", styles: ["@charset \"UTF-8\";:host{display:block;background:var(--bg-2);border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--shadow-card)}.dt{width:100%;border-collapse:collapse;font-size:var(--text-base)}.dt thead th{text-align:start;padding:var(--sp-2) var(--sp-3);font-size:12px;font-weight:var(--fw-bold);text-transform:uppercase;letter-spacing:.03em;color:var(--ink-3);background:var(--bg-3);border-block-end:1px solid var(--line)}.dt__th--end{text-align:end}.dt__sort{display:inline-flex;align-items:center;gap:var(--sp-1);padding:0;border:0;background:transparent;font:inherit;letter-spacing:inherit;text-transform:inherit;color:inherit;cursor:pointer}.dt__sort:hover{color:var(--ink)}.dt__sort:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.dt__sort-icon{inline-size:0;block-size:0;border-inline:4px solid transparent;border-block-start:5px solid var(--ink-4);opacity:.45;transition:transform var(--t-state),opacity var(--t-state)}.dt__sort-icon[data-dir=asc]{opacity:1;border-block-start-color:var(--accent);transform:rotate(180deg)}.dt__sort-icon[data-dir=desc]{opacity:1;border-block-start-color:var(--accent)}.dt tbody td{height:var(--row-h);padding:var(--sp-2) var(--sp-3);border-block-end:1px solid var(--line-3);color:var(--ink);transition:background var(--t-state)}.dt tbody tr:last-child td{border-block-end:0}.dt__row{cursor:pointer}.dt__row:hover td{background:var(--bg-hover)}.dt__row:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px;outline-offset:-2px}.dt__row--skel{cursor:default}.dt__row--skel:hover td{background:transparent}.dt__td--end{text-align:end}.dt__td--date,.dt__td--num{color:var(--ink-3);font-size:var(--text-sm);font-variant-numeric:tabular-nums}@media(width<=720px){.dt thead{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.dt,.dt tbody,.dt tbody tr,.dt tbody td{display:block}.dt__row{padding:var(--sp-2) 0;border-block-end:1px solid var(--line-3)}.dt__row:last-child{border-block-end:0}.dt tbody td{display:flex;align-items:baseline;justify-content:space-between;gap:var(--sp-3);height:auto;border-block-end:0;padding:var(--sp-1) var(--sp-3);text-align:end}.dt tbody td:before{content:attr(data-label);flex-shrink:0;font-size:var(--text-xs);font-weight:var(--fw-medium);letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--ink-4);text-align:start}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: FlyStateMessageComponent, selector: "fly-state-message", inputs: ["kind", "messageKey", "iconClass", "retryLabelKey", "showRetry"], outputs: ["retried"] }, { kind: "component", type: FlySkeletonComponent, selector: "fly-skeleton", inputs: ["layout", "shape", "count", "lines", "animation", "fill", "messageKey", "announce"] }, { kind: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
18210
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyDataTableComponent, isStandalone: true, selector: "fly-data-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelKey: { classPropertyName: "ariaLabelKey", publicName: "ariaLabelKey", isSignal: true, isRequired: false, transformFunction: null }, sort: { classPropertyName: "sort", publicName: "sort", isSignal: true, isRequired: false, transformFunction: null }, emptyKey: { classPropertyName: "emptyKey", publicName: "emptyKey", isSignal: true, isRequired: false, transformFunction: null }, emptyIconClass: { classPropertyName: "emptyIconClass", publicName: "emptyIconClass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortChange: "sortChange", rowActivated: "rowActivated" }, queries: [{ propertyName: "cellTemplates", predicate: FlyCellDirective, isSignal: true }], ngImport: i0, template: "<table class=\"dt\" [attr.aria-label]=\"ariaLabelKey() ? (ariaLabelKey()! | translate) : null\">\r\n <thead>\r\n <tr>\r\n @for (col of columns(); track col.id) {\r\n <th\r\n scope=\"col\"\r\n [class.dt__th--end]=\"col.align === 'end'\"\r\n [attr.aria-sort]=\"headerAriaSort(col)\"\r\n >\r\n @if (col.sortable) {\r\n <button type=\"button\" class=\"dt__sort\" (click)=\"onHeaderClick(col)\">\r\n <span>{{ col.headerKey | translate }}</span>\r\n <span class=\"dt__sort-icon\" [attr.data-dir]=\"sortDirFor(col)\" aria-hidden=\"true\"></span>\r\n </button>\r\n } @else {\r\n {{ col.headerKey | translate }}\r\n }\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading()) {\r\n @for (i of skeletonRows; track i) {\r\n <tr class=\"dt__row dt__row--skel\">\r\n <td [attr.colspan]=\"columns().length\">\r\n <!-- shape=\"lines\" is the DS skeleton's no-chrome text shimmer\r\n (the kit's former shape=\"text\"); one line per collapsed row.\r\n No backticks in here: this is an INLINE template literal. -->\r\n <fly-skeleton shape=\"lines\" [lines]=\"1\" />\r\n </td>\r\n </tr>\r\n }\r\n } @else {\r\n @for (row of rows(); track $index) {\r\n <tr\r\n class=\"dt__row\"\r\n tabindex=\"0\"\r\n (click)=\"onRowActivate($event, row)\"\r\n (keydown.enter)=\"onRowActivate($event, row)\"\r\n >\r\n @for (col of columns(); track col.id) {\r\n <td\r\n [class.dt__td--end]=\"col.align === 'end'\"\r\n [class.mono]=\"col.kind === 'mono'\"\r\n [class.dt__td--date]=\"col.kind === 'date'\"\r\n [class.dt__td--num]=\"col.kind === 'number'\"\r\n [attr.data-label]=\"col.headerKey | translate\"\r\n >\r\n @if (templateFor(col.id); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: row }\" />\r\n } @else {\r\n @switch (col.kind ?? 'text') {\r\n @case ('date') {\r\n @if (cellValue(row, col); as value) {\r\n {{ $any(value) | date: 'yyyy-MM-dd' : 'UTC' }}\r\n } @else { \u2014 }\r\n }\r\n @default {\r\n {{ displayValue(row, col) }}\r\n }\r\n }\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n</table>\r\n@if (!loading() && rows().length === 0 && emptyKey()) {\r\n <fly-state-message kind=\"empty\" [messageKey]=\"emptyKey()\" [iconClass]=\"emptyIconClass()\" />\r\n}\r\n", styles: ["@charset \"UTF-8\";:host{display:block;background:var(--bg-2);border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--shadow-card);container-type:inline-size}.dt{width:100%;border-collapse:collapse;font-size:var(--text-base)}.dt thead th{text-align:start;padding:var(--sp-2) var(--sp-3);font-size:12px;font-weight:var(--fw-bold);text-transform:uppercase;letter-spacing:.03em;color:var(--ink-3);background:var(--bg-3);border-block-end:1px solid var(--line)}.dt__th--end{text-align:end}.dt__sort{display:inline-flex;align-items:center;gap:var(--sp-1);padding:0;border:0;background:transparent;font:inherit;letter-spacing:inherit;text-transform:inherit;color:inherit;cursor:pointer}.dt__sort:hover{color:var(--ink)}.dt__sort:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.dt__sort-icon{inline-size:0;block-size:0;border-inline:4px solid transparent;border-block-start:5px solid var(--ink-4);opacity:.45;transition:transform var(--t-state),opacity var(--t-state)}.dt__sort-icon[data-dir=asc]{opacity:1;border-block-start-color:var(--accent);transform:rotate(180deg)}.dt__sort-icon[data-dir=desc]{opacity:1;border-block-start-color:var(--accent)}.dt tbody td{height:var(--row-h);padding:var(--sp-2) var(--sp-3);border-block-end:1px solid var(--line-3);color:var(--ink);transition:background var(--t-state)}.dt tbody tr:last-child td{border-block-end:0}.dt__row{cursor:pointer}.dt__row:hover td{background:var(--bg-hover)}.dt__row:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px;outline-offset:-2px}.dt__row--skel{cursor:default}.dt__row--skel:hover td{background:transparent}.dt__td--end{text-align:end}.dt__td--date,.dt__td--num{color:var(--ink-3);font-size:var(--text-sm);font-variant-numeric:tabular-nums}@container (width <= 720px){.dt thead{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.dt,.dt tbody,.dt tbody tr,.dt tbody td{display:block}.dt__row{padding:var(--sp-2) 0;border-block-end:1px solid var(--line-3)}.dt__row:last-child{border-block-end:0}.dt tbody td{display:flex;align-items:baseline;justify-content:space-between;gap:var(--sp-3);height:auto;border-block-end:0;padding:var(--sp-1) var(--sp-3);text-align:end}.dt tbody td:before{content:attr(data-label);flex-shrink:0;font-size:var(--text-xs);font-weight:var(--fw-medium);letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--ink-4);text-align:start}}@media(width<=720px){.dt thead{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.dt,.dt tbody,.dt tbody tr,.dt tbody td{display:block}.dt__row{padding:var(--sp-2) 0;border-block-end:1px solid var(--line-3)}.dt__row:last-child{border-block-end:0}.dt tbody td{display:flex;align-items:baseline;justify-content:space-between;gap:var(--sp-3);height:auto;border-block-end:0;padding:var(--sp-1) var(--sp-3);text-align:end}.dt tbody td:before{content:attr(data-label);flex-shrink:0;font-size:var(--text-xs);font-weight:var(--fw-medium);letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--ink-4);text-align:start}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: FlyStateMessageComponent, selector: "fly-state-message", inputs: ["kind", "messageKey", "iconClass", "retryLabelKey", "showRetry"], outputs: ["retried"] }, { kind: "component", type: FlySkeletonComponent, selector: "fly-skeleton", inputs: ["layout", "shape", "count", "lines", "animation", "fill", "messageKey", "announce"] }, { kind: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
18165
18211
|
}
|
|
18166
18212
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyDataTableComponent, decorators: [{
|
|
18167
18213
|
type: Component,
|
|
18168
|
-
args: [{ selector: 'fly-data-table', standalone: true, imports: [DatePipe, NgTemplateOutlet, TranslatePipe, FlyStateMessageComponent, FlySkeletonComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<table class=\"dt\" [attr.aria-label]=\"ariaLabelKey() ? (ariaLabelKey()! | translate) : null\">\r\n <thead>\r\n <tr>\r\n @for (col of columns(); track col.id) {\r\n <th\r\n scope=\"col\"\r\n [class.dt__th--end]=\"col.align === 'end'\"\r\n [attr.aria-sort]=\"headerAriaSort(col)\"\r\n >\r\n @if (col.sortable) {\r\n <button type=\"button\" class=\"dt__sort\" (click)=\"onHeaderClick(col)\">\r\n <span>{{ col.headerKey | translate }}</span>\r\n <span class=\"dt__sort-icon\" [attr.data-dir]=\"sortDirFor(col)\" aria-hidden=\"true\"></span>\r\n </button>\r\n } @else {\r\n {{ col.headerKey | translate }}\r\n }\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading()) {\r\n @for (i of skeletonRows; track i) {\r\n <tr class=\"dt__row dt__row--skel\">\r\n <td [attr.colspan]=\"columns().length\">\r\n <!-- shape=\"lines\" is the DS skeleton's no-chrome text shimmer\r\n (the kit's former shape=\"text\"); one line per collapsed row.\r\n No backticks in here: this is an INLINE template literal. -->\r\n <fly-skeleton shape=\"lines\" [lines]=\"1\" />\r\n </td>\r\n </tr>\r\n }\r\n } @else {\r\n @for (row of rows(); track $index) {\r\n <tr\r\n class=\"dt__row\"\r\n tabindex=\"0\"\r\n (click)=\"onRowActivate($event, row)\"\r\n (keydown.enter)=\"onRowActivate($event, row)\"\r\n >\r\n @for (col of columns(); track col.id) {\r\n <td\r\n [class.dt__td--end]=\"col.align === 'end'\"\r\n [class.mono]=\"col.kind === 'mono'\"\r\n [class.dt__td--date]=\"col.kind === 'date'\"\r\n [class.dt__td--num]=\"col.kind === 'number'\"\r\n [attr.data-label]=\"col.headerKey | translate\"\r\n >\r\n @if (templateFor(col.id); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: row }\" />\r\n } @else {\r\n @switch (col.kind ?? 'text') {\r\n @case ('date') {\r\n @if (cellValue(row, col); as value) {\r\n {{ $any(value) | date: 'yyyy-MM-dd' : 'UTC' }}\r\n } @else { \u2014 }\r\n }\r\n @default {\r\n {{ displayValue(row, col) }}\r\n }\r\n }\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n</table>\r\n@if (!loading() && rows().length === 0 && emptyKey()) {\r\n <fly-state-message kind=\"empty\" [messageKey]=\"emptyKey()\" [iconClass]=\"emptyIconClass()\" />\r\n}\r\n", styles: ["@charset \"UTF-8\";:host{display:block;background:var(--bg-2);border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--shadow-card)}.dt{width:100%;border-collapse:collapse;font-size:var(--text-base)}.dt thead th{text-align:start;padding:var(--sp-2) var(--sp-3);font-size:12px;font-weight:var(--fw-bold);text-transform:uppercase;letter-spacing:.03em;color:var(--ink-3);background:var(--bg-3);border-block-end:1px solid var(--line)}.dt__th--end{text-align:end}.dt__sort{display:inline-flex;align-items:center;gap:var(--sp-1);padding:0;border:0;background:transparent;font:inherit;letter-spacing:inherit;text-transform:inherit;color:inherit;cursor:pointer}.dt__sort:hover{color:var(--ink)}.dt__sort:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.dt__sort-icon{inline-size:0;block-size:0;border-inline:4px solid transparent;border-block-start:5px solid var(--ink-4);opacity:.45;transition:transform var(--t-state),opacity var(--t-state)}.dt__sort-icon[data-dir=asc]{opacity:1;border-block-start-color:var(--accent);transform:rotate(180deg)}.dt__sort-icon[data-dir=desc]{opacity:1;border-block-start-color:var(--accent)}.dt tbody td{height:var(--row-h);padding:var(--sp-2) var(--sp-3);border-block-end:1px solid var(--line-3);color:var(--ink);transition:background var(--t-state)}.dt tbody tr:last-child td{border-block-end:0}.dt__row{cursor:pointer}.dt__row:hover td{background:var(--bg-hover)}.dt__row:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px;outline-offset:-2px}.dt__row--skel{cursor:default}.dt__row--skel:hover td{background:transparent}.dt__td--end{text-align:end}.dt__td--date,.dt__td--num{color:var(--ink-3);font-size:var(--text-sm);font-variant-numeric:tabular-nums}@media(width<=720px){.dt thead{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.dt,.dt tbody,.dt tbody tr,.dt tbody td{display:block}.dt__row{padding:var(--sp-2) 0;border-block-end:1px solid var(--line-3)}.dt__row:last-child{border-block-end:0}.dt tbody td{display:flex;align-items:baseline;justify-content:space-between;gap:var(--sp-3);height:auto;border-block-end:0;padding:var(--sp-1) var(--sp-3);text-align:end}.dt tbody td:before{content:attr(data-label);flex-shrink:0;font-size:var(--text-xs);font-weight:var(--fw-medium);letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--ink-4);text-align:start}}\n"] }]
|
|
18214
|
+
args: [{ selector: 'fly-data-table', standalone: true, imports: [DatePipe, NgTemplateOutlet, TranslatePipe, FlyStateMessageComponent, FlySkeletonComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<table class=\"dt\" [attr.aria-label]=\"ariaLabelKey() ? (ariaLabelKey()! | translate) : null\">\r\n <thead>\r\n <tr>\r\n @for (col of columns(); track col.id) {\r\n <th\r\n scope=\"col\"\r\n [class.dt__th--end]=\"col.align === 'end'\"\r\n [attr.aria-sort]=\"headerAriaSort(col)\"\r\n >\r\n @if (col.sortable) {\r\n <button type=\"button\" class=\"dt__sort\" (click)=\"onHeaderClick(col)\">\r\n <span>{{ col.headerKey | translate }}</span>\r\n <span class=\"dt__sort-icon\" [attr.data-dir]=\"sortDirFor(col)\" aria-hidden=\"true\"></span>\r\n </button>\r\n } @else {\r\n {{ col.headerKey | translate }}\r\n }\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading()) {\r\n @for (i of skeletonRows; track i) {\r\n <tr class=\"dt__row dt__row--skel\">\r\n <td [attr.colspan]=\"columns().length\">\r\n <!-- shape=\"lines\" is the DS skeleton's no-chrome text shimmer\r\n (the kit's former shape=\"text\"); one line per collapsed row.\r\n No backticks in here: this is an INLINE template literal. -->\r\n <fly-skeleton shape=\"lines\" [lines]=\"1\" />\r\n </td>\r\n </tr>\r\n }\r\n } @else {\r\n @for (row of rows(); track $index) {\r\n <tr\r\n class=\"dt__row\"\r\n tabindex=\"0\"\r\n (click)=\"onRowActivate($event, row)\"\r\n (keydown.enter)=\"onRowActivate($event, row)\"\r\n >\r\n @for (col of columns(); track col.id) {\r\n <td\r\n [class.dt__td--end]=\"col.align === 'end'\"\r\n [class.mono]=\"col.kind === 'mono'\"\r\n [class.dt__td--date]=\"col.kind === 'date'\"\r\n [class.dt__td--num]=\"col.kind === 'number'\"\r\n [attr.data-label]=\"col.headerKey | translate\"\r\n >\r\n @if (templateFor(col.id); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: row }\" />\r\n } @else {\r\n @switch (col.kind ?? 'text') {\r\n @case ('date') {\r\n @if (cellValue(row, col); as value) {\r\n {{ $any(value) | date: 'yyyy-MM-dd' : 'UTC' }}\r\n } @else { \u2014 }\r\n }\r\n @default {\r\n {{ displayValue(row, col) }}\r\n }\r\n }\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n</table>\r\n@if (!loading() && rows().length === 0 && emptyKey()) {\r\n <fly-state-message kind=\"empty\" [messageKey]=\"emptyKey()\" [iconClass]=\"emptyIconClass()\" />\r\n}\r\n", styles: ["@charset \"UTF-8\";:host{display:block;background:var(--bg-2);border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--shadow-card);container-type:inline-size}.dt{width:100%;border-collapse:collapse;font-size:var(--text-base)}.dt thead th{text-align:start;padding:var(--sp-2) var(--sp-3);font-size:12px;font-weight:var(--fw-bold);text-transform:uppercase;letter-spacing:.03em;color:var(--ink-3);background:var(--bg-3);border-block-end:1px solid var(--line)}.dt__th--end{text-align:end}.dt__sort{display:inline-flex;align-items:center;gap:var(--sp-1);padding:0;border:0;background:transparent;font:inherit;letter-spacing:inherit;text-transform:inherit;color:inherit;cursor:pointer}.dt__sort:hover{color:var(--ink)}.dt__sort:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.dt__sort-icon{inline-size:0;block-size:0;border-inline:4px solid transparent;border-block-start:5px solid var(--ink-4);opacity:.45;transition:transform var(--t-state),opacity var(--t-state)}.dt__sort-icon[data-dir=asc]{opacity:1;border-block-start-color:var(--accent);transform:rotate(180deg)}.dt__sort-icon[data-dir=desc]{opacity:1;border-block-start-color:var(--accent)}.dt tbody td{height:var(--row-h);padding:var(--sp-2) var(--sp-3);border-block-end:1px solid var(--line-3);color:var(--ink);transition:background var(--t-state)}.dt tbody tr:last-child td{border-block-end:0}.dt__row{cursor:pointer}.dt__row:hover td{background:var(--bg-hover)}.dt__row:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px;outline-offset:-2px}.dt__row--skel{cursor:default}.dt__row--skel:hover td{background:transparent}.dt__td--end{text-align:end}.dt__td--date,.dt__td--num{color:var(--ink-3);font-size:var(--text-sm);font-variant-numeric:tabular-nums}@container (width <= 720px){.dt thead{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.dt,.dt tbody,.dt tbody tr,.dt tbody td{display:block}.dt__row{padding:var(--sp-2) 0;border-block-end:1px solid var(--line-3)}.dt__row:last-child{border-block-end:0}.dt tbody td{display:flex;align-items:baseline;justify-content:space-between;gap:var(--sp-3);height:auto;border-block-end:0;padding:var(--sp-1) var(--sp-3);text-align:end}.dt tbody td:before{content:attr(data-label);flex-shrink:0;font-size:var(--text-xs);font-weight:var(--fw-medium);letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--ink-4);text-align:start}}@media(width<=720px){.dt thead{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.dt,.dt tbody,.dt tbody tr,.dt tbody td{display:block}.dt__row{padding:var(--sp-2) 0;border-block-end:1px solid var(--line-3)}.dt__row:last-child{border-block-end:0}.dt tbody td{display:flex;align-items:baseline;justify-content:space-between;gap:var(--sp-3);height:auto;border-block-end:0;padding:var(--sp-1) var(--sp-3);text-align:end}.dt tbody td:before{content:attr(data-label);flex-shrink:0;font-size:var(--text-xs);font-weight:var(--fw-medium);letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--ink-4);text-align:start}}\n"] }]
|
|
18169
18215
|
}], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: true }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], ariaLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabelKey", required: false }] }], sort: [{ type: i0.Input, args: [{ isSignal: true, alias: "sort", required: false }] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], rowActivated: [{ type: i0.Output, args: ["rowActivated"] }], emptyKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyKey", required: false }] }], emptyIconClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyIconClass", required: false }] }], cellTemplates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => FlyCellDirective), { isSignal: true }] }] } });
|
|
18170
18216
|
|
|
18171
18217
|
/**
|
|
@@ -18378,11 +18424,11 @@ class PageHeaderComponent {
|
|
|
18378
18424
|
return '#';
|
|
18379
18425
|
}
|
|
18380
18426
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: PageHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18381
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: PageHeaderComponent, isStandalone: true, selector: "fly-page-header", inputs: { variant: "variant", title: "title", titleKey: "titleKey", subtitle: "subtitle", subtitleKey: "subtitleKey", titleAr: "titleAr", eyebrow: "eyebrow", eyebrowKey: "eyebrowKey", metricValue: "metricValue", metricLabel: "metricLabel", metricLabelKey: "metricLabelKey", breadcrumbs: "breadcrumbs" }, outputs: { crumbClick: "crumbClick" }, ngImport: i0, template: "<header class=\"ph\" [ngClass]=\"'ph--' + variant\">\r\n <!-- \u2500\u2500\u2500 Breadcrumbs \u2500\u2500\u2500 -->\r\n @if (breadcrumbs?.length) {\r\n <nav class=\"crumbs\" [attr.aria-label]=\"'ui.nav.breadcrumbs' | translate\">\r\n @for (bc of breadcrumbs; track $index; let i = $index, last = $last) {\r\n @if (i > 0) {\r\n <span class=\"crumb__sep\" aria-hidden=\"true\">/</span>\r\n }\r\n @if (last || bc.ariaCurrent) {\r\n <span class=\"crumb crumb--active\" aria-current=\"page\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </span>\r\n } @else if (bc.onClick) {\r\n <button type=\"button\" class=\"crumb crumb--link\" (click)=\"onCrumb(bc)\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </button>\r\n } @else if (bc.link) {\r\n <a class=\"crumb crumb--link\" (click)=\"onCrumb(bc); $event.preventDefault()\" [attr.href]=\"hrefFor(bc)\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </a>\r\n } @else if (bc.href) {\r\n <a class=\"crumb crumb--link\" [attr.href]=\"bc.href\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </a>\r\n } @else {\r\n <span class=\"crumb\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </span>\r\n }\r\n }\r\n </nav>\r\n }\r\n\r\n <!-- \u2500\u2500\u2500 Title row \u2500\u2500\u2500 -->\r\n <div class=\"ph__row\">\r\n <div class=\"ph__l\">\r\n @if (eyebrow || eyebrowKey) {\r\n <div class=\"ph__eyebrow\">\r\n @if (eyebrow) { <span class=\"mono\">{{ eyebrow }}</span> }\r\n @if (eyebrowKey) { <span>{{ eyebrowKey | translate }}</span> }\r\n </div>\r\n }\r\n <h1 class=\"ph__title\" [ngClass]=\"{ 'ph__title--detail': variant === 'detail' }\">\r\n {{ titleKey ? (titleKey | translate) : title }}\r\n </h1>\r\n @if (subtitle || subtitleKey) {\r\n <p class=\"ph__sub\">{{ subtitleKey ? (subtitleKey | translate) : subtitle }}</p>\r\n }\r\n @if (titleAr) {\r\n <p class=\"ph__title-ar\">{{ titleAr }}</p>\r\n }\r\n </div>\r\n\r\n <div class=\"ph__r\">\r\n <!-- Right-side metric (listing) -->\r\n @if (metricValue || metricLabel || metricLabelKey) {\r\n <div class=\"ph__metric\">\r\n @if (metricValue) { <div class=\"ph__metric-v mono\">{{ metricValue }}</div> }\r\n <div class=\"ph__metric-l\">{{ metricLabelKey ? (metricLabelKey | translate) : metricLabel }}</div>\r\n </div>\r\n }\r\n\r\n <!-- Status chip (detail) stacked over the action button row. Listing/circles/module\r\n project no status, so this collapses to just the right-aligned action row.\r\n NOTE: a single [page-header-actions] slot \u2014 duplicating it across @if branches\r\n silently drops projected content in the non-first branch (Angular binds projection\r\n to the first declared matching <ng-content>). -->\r\n <div class=\"ph__hd-actions\">\r\n <ng-content select=\"[page-header-status]\"></ng-content>\r\n <div class=\"ph__hd-btns\">\r\n <ng-content select=\"[page-header-actions]\"></ng-content>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Default slot: anything the consumer wants directly below the title row\r\n (e.g. a detail-page stat bar). -->\r\n <ng-content></ng-content>\r\n</header>\r\n", styles: ["@charset \"UTF-8\";:host{display:block;margin-block-end:var(--sp-6)}.ph{display:flex;flex-direction:column;gap:0;color:var(--ink);font-family:var(--font-sans, var(--font-family, system-ui, sans-serif))}.crumbs{display:flex;align-items:center;gap:6px;flex-wrap:wrap;font-size:12px;margin-bottom:14px;color:var(--ink-3)}.crumb{font-size:12px;line-height:1.4;color:var(--ink-3);padding:2px 0;background:none;border:0;font-family:inherit;letter-spacing:-.005em;text-decoration:none}.crumb--link{cursor:pointer;transition:color var(--t-state)}.crumb--link:hover{color:var(--ink);text-decoration:underline;text-underline-offset:3px}.crumb--active{color:var(--ink);font-weight:var(--fw-medium);max-width:480px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.crumb__sep{color:var(--ink-4);font-size:11px;-webkit-user-select:none;user-select:none}.ph__row{display:flex;align-items:flex-end;justify-content:space-between;gap:32px;flex-wrap:wrap}.ph--detail .ph__row{align-items:flex-start}.ph__l{flex:1;min-width:0}.ph__r{display:flex;align-items:flex-end;gap:16px;flex-shrink:0}.ph--detail .ph__r{align-items:flex-end;flex-direction:column}.ph__eyebrow{display:inline-flex;align-items:center;gap:6px;font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-4);font-weight:var(--fw-medium);margin-bottom:4px}.ph__eyebrow .mono{font-size:10.5px;color:var(--ink-3);letter-spacing:.04em;font-family:var(--font-mono, ui-monospace, monospace)}.ph__title{margin:0 0 6px;font-size:32px;font-weight:var(--fw-semibold);letter-spacing:-.02em;line-height:1.1;color:var(--ink)}.ph__title--detail{font-size:28px;letter-spacing:-.02em;line-height:1.2;margin:0}.ph__sub{margin:0;font-size:13.5px;color:var(--ink-3)}.ph__title-ar{margin:6px 0 0;font-size:17px;color:var(--ink-3);font-family:Noto Kufi Arabic,sans-serif;letter-spacing:0;line-height:1.5;font-weight:var(--fw-medium)}.ph__metric{text-align:end}.ph__metric-v{font-family:var(--font-mono, ui-monospace, monospace);font-size:22px;font-weight:var(--fw-medium);letter-spacing:-.02em;color:var(--ink)}.ph__metric-l{font-size:11px;color:var(--ink-3);text-transform:uppercase;letter-spacing:.06em}.ph__hd-actions{display:flex;flex-direction:column;align-items:flex-end;gap:10px}.ph__hd-btns{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}.ph--listing,.ph--detail{margin-bottom:0}@media(max-width:980px){.ph__row{flex-direction:column;align-items:flex-start;gap:16px}.ph__r{align-items:flex-start;flex-direction:row;flex-wrap:wrap}.ph--detail .ph__r{flex-direction:row-reverse}.ph__title{font-size:26px}.ph__title--detail{font-size:24px}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
18427
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: PageHeaderComponent, isStandalone: true, selector: "fly-page-header", inputs: { variant: "variant", title: "title", titleKey: "titleKey", subtitle: "subtitle", subtitleKey: "subtitleKey", titleAr: "titleAr", eyebrow: "eyebrow", eyebrowKey: "eyebrowKey", metricValue: "metricValue", metricLabel: "metricLabel", metricLabelKey: "metricLabelKey", breadcrumbs: "breadcrumbs" }, outputs: { crumbClick: "crumbClick" }, ngImport: i0, template: "<header class=\"ph\" [ngClass]=\"'ph--' + variant\">\r\n <!-- \u2500\u2500\u2500 Breadcrumbs \u2500\u2500\u2500 -->\r\n @if (breadcrumbs?.length) {\r\n <nav class=\"crumbs\" [attr.aria-label]=\"'ui.nav.breadcrumbs' | translate\">\r\n @for (bc of breadcrumbs; track $index; let i = $index, last = $last) {\r\n @if (i > 0) {\r\n <span class=\"crumb__sep\" aria-hidden=\"true\">/</span>\r\n }\r\n @if (last || bc.ariaCurrent) {\r\n <span class=\"crumb crumb--active\" aria-current=\"page\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </span>\r\n } @else if (bc.onClick) {\r\n <button type=\"button\" class=\"crumb crumb--link\" (click)=\"onCrumb(bc)\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </button>\r\n } @else if (bc.link) {\r\n <a class=\"crumb crumb--link\" (click)=\"onCrumb(bc); $event.preventDefault()\" [attr.href]=\"hrefFor(bc)\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </a>\r\n } @else if (bc.href) {\r\n <a class=\"crumb crumb--link\" [attr.href]=\"bc.href\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </a>\r\n } @else {\r\n <span class=\"crumb\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </span>\r\n }\r\n }\r\n </nav>\r\n }\r\n\r\n <!-- \u2500\u2500\u2500 Title row \u2500\u2500\u2500 -->\r\n <div class=\"ph__row\">\r\n <div class=\"ph__l\">\r\n @if (eyebrow || eyebrowKey) {\r\n <div class=\"ph__eyebrow\">\r\n @if (eyebrow) { <span class=\"mono\">{{ eyebrow }}</span> }\r\n @if (eyebrowKey) { <span>{{ eyebrowKey | translate }}</span> }\r\n </div>\r\n }\r\n <h1 class=\"ph__title\" [ngClass]=\"{ 'ph__title--detail': variant === 'detail' }\">\r\n {{ titleKey ? (titleKey | translate) : title }}\r\n </h1>\r\n @if (subtitle || subtitleKey) {\r\n <p class=\"ph__sub\">{{ subtitleKey ? (subtitleKey | translate) : subtitle }}</p>\r\n }\r\n @if (titleAr) {\r\n <p class=\"ph__title-ar\">{{ titleAr }}</p>\r\n }\r\n </div>\r\n\r\n <div class=\"ph__r\">\r\n <!-- Right-side metric (listing) -->\r\n @if (metricValue || metricLabel || metricLabelKey) {\r\n <div class=\"ph__metric\">\r\n @if (metricValue) { <div class=\"ph__metric-v mono\">{{ metricValue }}</div> }\r\n <div class=\"ph__metric-l\">{{ metricLabelKey ? (metricLabelKey | translate) : metricLabel }}</div>\r\n </div>\r\n }\r\n\r\n <!-- Status chip (detail) stacked over the action button row. Listing/circles/module\r\n project no status, so this collapses to just the right-aligned action row.\r\n NOTE: a single [page-header-actions] slot \u2014 duplicating it across @if branches\r\n silently drops projected content in the non-first branch (Angular binds projection\r\n to the first declared matching <ng-content>). -->\r\n <div class=\"ph__hd-actions\">\r\n <ng-content select=\"[page-header-status]\"></ng-content>\r\n <div class=\"ph__hd-btns\">\r\n <ng-content select=\"[page-header-actions]\"></ng-content>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Default slot: anything the consumer wants directly below the title row\r\n (e.g. a detail-page stat bar). -->\r\n <ng-content></ng-content>\r\n</header>\r\n", styles: ["@charset \"UTF-8\";:host{display:block;margin-block-end:var(--sp-6);container-type:inline-size}.ph{display:flex;flex-direction:column;gap:0;color:var(--ink);font-family:var(--font-sans, var(--font-family, system-ui, sans-serif))}.crumbs{display:flex;align-items:center;gap:6px;flex-wrap:wrap;font-size:12px;margin-bottom:14px;color:var(--ink-3)}.crumb{font-size:12px;line-height:1.4;color:var(--ink-3);padding:2px 0;background:none;border:0;font-family:inherit;letter-spacing:-.005em;text-decoration:none}.crumb--link{cursor:pointer;transition:color var(--t-state)}.crumb--link:hover{color:var(--ink);text-decoration:underline;text-underline-offset:3px}.crumb--active{color:var(--ink);font-weight:var(--fw-medium);max-width:480px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.crumb__sep{color:var(--ink-4);font-size:11px;-webkit-user-select:none;user-select:none}.ph__row{display:flex;align-items:flex-end;justify-content:space-between;gap:32px;flex-wrap:wrap}.ph--detail .ph__row{align-items:flex-start}.ph__l{flex:1;min-width:0}.ph__r{display:flex;align-items:flex-end;gap:16px;flex-shrink:0}.ph--detail .ph__r{align-items:flex-end;flex-direction:column}.ph__eyebrow{display:inline-flex;align-items:center;gap:6px;font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-4);font-weight:var(--fw-medium);margin-bottom:4px}.ph__eyebrow .mono{font-size:10.5px;color:var(--ink-3);letter-spacing:.04em;font-family:var(--font-mono, ui-monospace, monospace)}.ph__title{margin:0 0 6px;font-size:32px;font-weight:var(--fw-semibold);letter-spacing:-.02em;line-height:1.1;color:var(--ink)}.ph__title--detail{font-size:28px;letter-spacing:-.02em;line-height:1.2;margin:0}.ph__sub{margin:0;font-size:13.5px;color:var(--ink-3)}.ph__title-ar{margin:6px 0 0;font-size:17px;color:var(--ink-3);font-family:Noto Kufi Arabic,sans-serif;letter-spacing:0;line-height:1.5;font-weight:var(--fw-medium)}.ph__metric{text-align:end}.ph__metric-v{font-family:var(--font-mono, ui-monospace, monospace);font-size:22px;font-weight:var(--fw-medium);letter-spacing:-.02em;color:var(--ink)}.ph__metric-l{font-size:11px;color:var(--ink-3);text-transform:uppercase;letter-spacing:.06em}.ph__hd-actions{display:flex;flex-direction:column;align-items:flex-end;gap:10px}.ph__hd-btns{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}.ph--listing,.ph--detail{margin-bottom:0}@container (max-width: 980px){.ph__row{flex-direction:column;align-items:flex-start;gap:16px}.ph__r{align-items:flex-start;flex-direction:row;flex-wrap:wrap}.ph--detail .ph__r{flex-direction:row-reverse}.ph__title{font-size:26px}.ph__title--detail{font-size:24px}}@media(max-width:980px){.ph__row{flex-direction:column;align-items:flex-start;gap:16px}.ph__r{align-items:flex-start;flex-direction:row;flex-wrap:wrap}.ph--detail .ph__r{flex-direction:row-reverse}.ph__title{font-size:26px}.ph__title--detail{font-size:24px}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
18382
18428
|
}
|
|
18383
18429
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: PageHeaderComponent, decorators: [{
|
|
18384
18430
|
type: Component,
|
|
18385
|
-
args: [{ selector: 'fly-page-header', standalone: true, imports: [NgClass, TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<header class=\"ph\" [ngClass]=\"'ph--' + variant\">\r\n <!-- \u2500\u2500\u2500 Breadcrumbs \u2500\u2500\u2500 -->\r\n @if (breadcrumbs?.length) {\r\n <nav class=\"crumbs\" [attr.aria-label]=\"'ui.nav.breadcrumbs' | translate\">\r\n @for (bc of breadcrumbs; track $index; let i = $index, last = $last) {\r\n @if (i > 0) {\r\n <span class=\"crumb__sep\" aria-hidden=\"true\">/</span>\r\n }\r\n @if (last || bc.ariaCurrent) {\r\n <span class=\"crumb crumb--active\" aria-current=\"page\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </span>\r\n } @else if (bc.onClick) {\r\n <button type=\"button\" class=\"crumb crumb--link\" (click)=\"onCrumb(bc)\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </button>\r\n } @else if (bc.link) {\r\n <a class=\"crumb crumb--link\" (click)=\"onCrumb(bc); $event.preventDefault()\" [attr.href]=\"hrefFor(bc)\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </a>\r\n } @else if (bc.href) {\r\n <a class=\"crumb crumb--link\" [attr.href]=\"bc.href\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </a>\r\n } @else {\r\n <span class=\"crumb\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </span>\r\n }\r\n }\r\n </nav>\r\n }\r\n\r\n <!-- \u2500\u2500\u2500 Title row \u2500\u2500\u2500 -->\r\n <div class=\"ph__row\">\r\n <div class=\"ph__l\">\r\n @if (eyebrow || eyebrowKey) {\r\n <div class=\"ph__eyebrow\">\r\n @if (eyebrow) { <span class=\"mono\">{{ eyebrow }}</span> }\r\n @if (eyebrowKey) { <span>{{ eyebrowKey | translate }}</span> }\r\n </div>\r\n }\r\n <h1 class=\"ph__title\" [ngClass]=\"{ 'ph__title--detail': variant === 'detail' }\">\r\n {{ titleKey ? (titleKey | translate) : title }}\r\n </h1>\r\n @if (subtitle || subtitleKey) {\r\n <p class=\"ph__sub\">{{ subtitleKey ? (subtitleKey | translate) : subtitle }}</p>\r\n }\r\n @if (titleAr) {\r\n <p class=\"ph__title-ar\">{{ titleAr }}</p>\r\n }\r\n </div>\r\n\r\n <div class=\"ph__r\">\r\n <!-- Right-side metric (listing) -->\r\n @if (metricValue || metricLabel || metricLabelKey) {\r\n <div class=\"ph__metric\">\r\n @if (metricValue) { <div class=\"ph__metric-v mono\">{{ metricValue }}</div> }\r\n <div class=\"ph__metric-l\">{{ metricLabelKey ? (metricLabelKey | translate) : metricLabel }}</div>\r\n </div>\r\n }\r\n\r\n <!-- Status chip (detail) stacked over the action button row. Listing/circles/module\r\n project no status, so this collapses to just the right-aligned action row.\r\n NOTE: a single [page-header-actions] slot \u2014 duplicating it across @if branches\r\n silently drops projected content in the non-first branch (Angular binds projection\r\n to the first declared matching <ng-content>). -->\r\n <div class=\"ph__hd-actions\">\r\n <ng-content select=\"[page-header-status]\"></ng-content>\r\n <div class=\"ph__hd-btns\">\r\n <ng-content select=\"[page-header-actions]\"></ng-content>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Default slot: anything the consumer wants directly below the title row\r\n (e.g. a detail-page stat bar). -->\r\n <ng-content></ng-content>\r\n</header>\r\n", styles: ["@charset \"UTF-8\";:host{display:block;margin-block-end:var(--sp-6)}.ph{display:flex;flex-direction:column;gap:0;color:var(--ink);font-family:var(--font-sans, var(--font-family, system-ui, sans-serif))}.crumbs{display:flex;align-items:center;gap:6px;flex-wrap:wrap;font-size:12px;margin-bottom:14px;color:var(--ink-3)}.crumb{font-size:12px;line-height:1.4;color:var(--ink-3);padding:2px 0;background:none;border:0;font-family:inherit;letter-spacing:-.005em;text-decoration:none}.crumb--link{cursor:pointer;transition:color var(--t-state)}.crumb--link:hover{color:var(--ink);text-decoration:underline;text-underline-offset:3px}.crumb--active{color:var(--ink);font-weight:var(--fw-medium);max-width:480px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.crumb__sep{color:var(--ink-4);font-size:11px;-webkit-user-select:none;user-select:none}.ph__row{display:flex;align-items:flex-end;justify-content:space-between;gap:32px;flex-wrap:wrap}.ph--detail .ph__row{align-items:flex-start}.ph__l{flex:1;min-width:0}.ph__r{display:flex;align-items:flex-end;gap:16px;flex-shrink:0}.ph--detail .ph__r{align-items:flex-end;flex-direction:column}.ph__eyebrow{display:inline-flex;align-items:center;gap:6px;font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-4);font-weight:var(--fw-medium);margin-bottom:4px}.ph__eyebrow .mono{font-size:10.5px;color:var(--ink-3);letter-spacing:.04em;font-family:var(--font-mono, ui-monospace, monospace)}.ph__title{margin:0 0 6px;font-size:32px;font-weight:var(--fw-semibold);letter-spacing:-.02em;line-height:1.1;color:var(--ink)}.ph__title--detail{font-size:28px;letter-spacing:-.02em;line-height:1.2;margin:0}.ph__sub{margin:0;font-size:13.5px;color:var(--ink-3)}.ph__title-ar{margin:6px 0 0;font-size:17px;color:var(--ink-3);font-family:Noto Kufi Arabic,sans-serif;letter-spacing:0;line-height:1.5;font-weight:var(--fw-medium)}.ph__metric{text-align:end}.ph__metric-v{font-family:var(--font-mono, ui-monospace, monospace);font-size:22px;font-weight:var(--fw-medium);letter-spacing:-.02em;color:var(--ink)}.ph__metric-l{font-size:11px;color:var(--ink-3);text-transform:uppercase;letter-spacing:.06em}.ph__hd-actions{display:flex;flex-direction:column;align-items:flex-end;gap:10px}.ph__hd-btns{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}.ph--listing,.ph--detail{margin-bottom:0}@media(max-width:980px){.ph__row{flex-direction:column;align-items:flex-start;gap:16px}.ph__r{align-items:flex-start;flex-direction:row;flex-wrap:wrap}.ph--detail .ph__r{flex-direction:row-reverse}.ph__title{font-size:26px}.ph__title--detail{font-size:24px}}\n"] }]
|
|
18431
|
+
args: [{ selector: 'fly-page-header', standalone: true, imports: [NgClass, TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<header class=\"ph\" [ngClass]=\"'ph--' + variant\">\r\n <!-- \u2500\u2500\u2500 Breadcrumbs \u2500\u2500\u2500 -->\r\n @if (breadcrumbs?.length) {\r\n <nav class=\"crumbs\" [attr.aria-label]=\"'ui.nav.breadcrumbs' | translate\">\r\n @for (bc of breadcrumbs; track $index; let i = $index, last = $last) {\r\n @if (i > 0) {\r\n <span class=\"crumb__sep\" aria-hidden=\"true\">/</span>\r\n }\r\n @if (last || bc.ariaCurrent) {\r\n <span class=\"crumb crumb--active\" aria-current=\"page\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </span>\r\n } @else if (bc.onClick) {\r\n <button type=\"button\" class=\"crumb crumb--link\" (click)=\"onCrumb(bc)\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </button>\r\n } @else if (bc.link) {\r\n <a class=\"crumb crumb--link\" (click)=\"onCrumb(bc); $event.preventDefault()\" [attr.href]=\"hrefFor(bc)\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </a>\r\n } @else if (bc.href) {\r\n <a class=\"crumb crumb--link\" [attr.href]=\"bc.href\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </a>\r\n } @else {\r\n <span class=\"crumb\">\r\n {{ bc.labelKey ? (bc.labelKey | translate) : bc.label }}\r\n </span>\r\n }\r\n }\r\n </nav>\r\n }\r\n\r\n <!-- \u2500\u2500\u2500 Title row \u2500\u2500\u2500 -->\r\n <div class=\"ph__row\">\r\n <div class=\"ph__l\">\r\n @if (eyebrow || eyebrowKey) {\r\n <div class=\"ph__eyebrow\">\r\n @if (eyebrow) { <span class=\"mono\">{{ eyebrow }}</span> }\r\n @if (eyebrowKey) { <span>{{ eyebrowKey | translate }}</span> }\r\n </div>\r\n }\r\n <h1 class=\"ph__title\" [ngClass]=\"{ 'ph__title--detail': variant === 'detail' }\">\r\n {{ titleKey ? (titleKey | translate) : title }}\r\n </h1>\r\n @if (subtitle || subtitleKey) {\r\n <p class=\"ph__sub\">{{ subtitleKey ? (subtitleKey | translate) : subtitle }}</p>\r\n }\r\n @if (titleAr) {\r\n <p class=\"ph__title-ar\">{{ titleAr }}</p>\r\n }\r\n </div>\r\n\r\n <div class=\"ph__r\">\r\n <!-- Right-side metric (listing) -->\r\n @if (metricValue || metricLabel || metricLabelKey) {\r\n <div class=\"ph__metric\">\r\n @if (metricValue) { <div class=\"ph__metric-v mono\">{{ metricValue }}</div> }\r\n <div class=\"ph__metric-l\">{{ metricLabelKey ? (metricLabelKey | translate) : metricLabel }}</div>\r\n </div>\r\n }\r\n\r\n <!-- Status chip (detail) stacked over the action button row. Listing/circles/module\r\n project no status, so this collapses to just the right-aligned action row.\r\n NOTE: a single [page-header-actions] slot \u2014 duplicating it across @if branches\r\n silently drops projected content in the non-first branch (Angular binds projection\r\n to the first declared matching <ng-content>). -->\r\n <div class=\"ph__hd-actions\">\r\n <ng-content select=\"[page-header-status]\"></ng-content>\r\n <div class=\"ph__hd-btns\">\r\n <ng-content select=\"[page-header-actions]\"></ng-content>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Default slot: anything the consumer wants directly below the title row\r\n (e.g. a detail-page stat bar). -->\r\n <ng-content></ng-content>\r\n</header>\r\n", styles: ["@charset \"UTF-8\";:host{display:block;margin-block-end:var(--sp-6);container-type:inline-size}.ph{display:flex;flex-direction:column;gap:0;color:var(--ink);font-family:var(--font-sans, var(--font-family, system-ui, sans-serif))}.crumbs{display:flex;align-items:center;gap:6px;flex-wrap:wrap;font-size:12px;margin-bottom:14px;color:var(--ink-3)}.crumb{font-size:12px;line-height:1.4;color:var(--ink-3);padding:2px 0;background:none;border:0;font-family:inherit;letter-spacing:-.005em;text-decoration:none}.crumb--link{cursor:pointer;transition:color var(--t-state)}.crumb--link:hover{color:var(--ink);text-decoration:underline;text-underline-offset:3px}.crumb--active{color:var(--ink);font-weight:var(--fw-medium);max-width:480px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.crumb__sep{color:var(--ink-4);font-size:11px;-webkit-user-select:none;user-select:none}.ph__row{display:flex;align-items:flex-end;justify-content:space-between;gap:32px;flex-wrap:wrap}.ph--detail .ph__row{align-items:flex-start}.ph__l{flex:1;min-width:0}.ph__r{display:flex;align-items:flex-end;gap:16px;flex-shrink:0}.ph--detail .ph__r{align-items:flex-end;flex-direction:column}.ph__eyebrow{display:inline-flex;align-items:center;gap:6px;font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-4);font-weight:var(--fw-medium);margin-bottom:4px}.ph__eyebrow .mono{font-size:10.5px;color:var(--ink-3);letter-spacing:.04em;font-family:var(--font-mono, ui-monospace, monospace)}.ph__title{margin:0 0 6px;font-size:32px;font-weight:var(--fw-semibold);letter-spacing:-.02em;line-height:1.1;color:var(--ink)}.ph__title--detail{font-size:28px;letter-spacing:-.02em;line-height:1.2;margin:0}.ph__sub{margin:0;font-size:13.5px;color:var(--ink-3)}.ph__title-ar{margin:6px 0 0;font-size:17px;color:var(--ink-3);font-family:Noto Kufi Arabic,sans-serif;letter-spacing:0;line-height:1.5;font-weight:var(--fw-medium)}.ph__metric{text-align:end}.ph__metric-v{font-family:var(--font-mono, ui-monospace, monospace);font-size:22px;font-weight:var(--fw-medium);letter-spacing:-.02em;color:var(--ink)}.ph__metric-l{font-size:11px;color:var(--ink-3);text-transform:uppercase;letter-spacing:.06em}.ph__hd-actions{display:flex;flex-direction:column;align-items:flex-end;gap:10px}.ph__hd-btns{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}.ph--listing,.ph--detail{margin-bottom:0}@container (max-width: 980px){.ph__row{flex-direction:column;align-items:flex-start;gap:16px}.ph__r{align-items:flex-start;flex-direction:row;flex-wrap:wrap}.ph--detail .ph__r{flex-direction:row-reverse}.ph__title{font-size:26px}.ph__title--detail{font-size:24px}}@media(max-width:980px){.ph__row{flex-direction:column;align-items:flex-start;gap:16px}.ph__r{align-items:flex-start;flex-direction:row;flex-wrap:wrap}.ph--detail .ph__r{flex-direction:row-reverse}.ph__title{font-size:26px}.ph__title--detail{font-size:24px}}\n"] }]
|
|
18386
18432
|
}], propDecorators: { variant: [{
|
|
18387
18433
|
type: Input
|
|
18388
18434
|
}], title: [{
|
|
@@ -18461,6 +18507,302 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
18461
18507
|
`, styles: [":host{display:block}.sh{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:13px 16px;border-block-end:1px solid var(--line-3)}.sh__t{margin:0;font-size:13px;font-weight:var(--fw-semibold);color:var(--ink);letter-spacing:-.005em;min-width:0}.sh__a{display:inline-flex;align-items:center;gap:var(--sp-1);flex-shrink:0}.sh__a ::ng-deep a:not([fly-button]),.sh__a ::ng-deep button:not([fly-button],[fly-icon-button]){display:inline-flex;align-items:center;gap:5px;background:transparent;border:0;color:var(--accent);font-size:12px;font-weight:var(--fw-medium);cursor:pointer;padding:4px 6px;border-radius:var(--r-sm);font-family:inherit;text-decoration:none;transition:background var(--t-state)}.sh__a ::ng-deep a:not([fly-button]):hover,.sh__a ::ng-deep button:not([fly-button],[fly-icon-button]):hover{background:color-mix(in srgb,var(--accent-soft) 50%,transparent)}.sh__a ::ng-deep a:not([fly-button]):focus-visible,.sh__a ::ng-deep button:not([fly-button],[fly-icon-button]):focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}\n"] }]
|
|
18462
18508
|
}], propDecorators: { titleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleKey", required: false }] }] } });
|
|
18463
18509
|
|
|
18510
|
+
/**
|
|
18511
|
+
* Detail-page content card — the surface every panel and sidebar block on a detail
|
|
18512
|
+
* screen sits on: `card-surface` fill/hairline/radius/shadow, an optional
|
|
18513
|
+
* `fly-section-header`, and a padded body.
|
|
18514
|
+
*
|
|
18515
|
+
* Extracted because four detail screens (Circles signal + trend, Thoughts idea +
|
|
18516
|
+
* the six sibling detail pages) had each hand-rolled the identical
|
|
18517
|
+
* `.card` / `.card__body` / `.card__body--flush` recipe, and they drifted: some
|
|
18518
|
+
* carried the shadow, some didn't, and on the shell's translucent glass the ones
|
|
18519
|
+
* without it lost their edge and read as a lighter surface than their neighbours.
|
|
18520
|
+
*
|
|
18521
|
+
* ```html
|
|
18522
|
+
* <fly-detail-card titleKey="common.label.metadata">
|
|
18523
|
+
* <fly-meta [items]="rows()" />
|
|
18524
|
+
* </fly-detail-card>
|
|
18525
|
+
*
|
|
18526
|
+
* <!-- A child with its own list chrome shouldn't sit inside body padding. -->
|
|
18527
|
+
* <fly-detail-card titleKey="common.label.evidence" [flush]="true">
|
|
18528
|
+
* <button card-actions type="button" (click)="add()">Add</button>
|
|
18529
|
+
* <fly-evidence-panel [hideHeader]="true" />
|
|
18530
|
+
* </fly-detail-card>
|
|
18531
|
+
* ```
|
|
18532
|
+
*
|
|
18533
|
+
* With no `titleKey` and nothing projected into `[card-title]` the header is
|
|
18534
|
+
* omitted entirely, so the card also serves as a bare framed surface (a cover
|
|
18535
|
+
* image, a chart) without an empty header rule above it.
|
|
18536
|
+
*/
|
|
18537
|
+
class FlyDetailCardComponent {
|
|
18538
|
+
/** i18n key for the card title; alternatively project `[card-title]`. */
|
|
18539
|
+
titleKey = input(...(ngDevMode ? [undefined, { debugName: "titleKey" }] : /* istanbul ignore next */ []));
|
|
18540
|
+
/**
|
|
18541
|
+
* Set when the title arrives through `[card-title]` rather than `titleKey`.
|
|
18542
|
+
* Content projection cannot be *queried* for presence without a `contentChild`
|
|
18543
|
+
* on a directive the caller would also have to import, so this stays an
|
|
18544
|
+
* explicit flag — a header with neither is omitted rather than rendered empty.
|
|
18545
|
+
*/
|
|
18546
|
+
hasProjectedTitle = input(false, ...(ngDevMode ? [{ debugName: "hasProjectedTitle" }] : /* istanbul ignore next */ []));
|
|
18547
|
+
/** Drop the body padding — for a child that brings its own list/table chrome. */
|
|
18548
|
+
flush = input(false, ...(ngDevMode ? [{ debugName: "flush" }] : /* istanbul ignore next */ []));
|
|
18549
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyDetailCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18550
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyDetailCardComponent, isStandalone: true, selector: "fly-detail-card", inputs: { titleKey: { classPropertyName: "titleKey", publicName: "titleKey", isSignal: true, isRequired: false, transformFunction: null }, hasProjectedTitle: { classPropertyName: "hasProjectedTitle", publicName: "hasProjectedTitle", isSignal: true, isRequired: false, transformFunction: null }, flush: { classPropertyName: "flush", publicName: "flush", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
18551
|
+
@if (titleKey() || hasProjectedTitle()) {
|
|
18552
|
+
<fly-section-header [titleKey]="titleKey()">
|
|
18553
|
+
<ng-content select="[card-title]" ngProjectAs="[section-title]" />
|
|
18554
|
+
<ng-content select="[card-actions]" ngProjectAs="[section-actions]" />
|
|
18555
|
+
</fly-section-header>
|
|
18556
|
+
}
|
|
18557
|
+
<div class="dc__body" [class.dc__body--flush]="flush()">
|
|
18558
|
+
<ng-content />
|
|
18559
|
+
</div>
|
|
18560
|
+
`, isInline: true, styles: [":host{display:block;background:var(--bg-2);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-card);overflow:hidden}.dc__body{padding:var(--sp-3) var(--sp-4) var(--sp-4)}.dc__body--flush{padding:0}\n"], dependencies: [{ kind: "component", type: FlySectionHeaderComponent, selector: "fly-section-header", inputs: ["titleKey"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
18561
|
+
}
|
|
18562
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyDetailCardComponent, decorators: [{
|
|
18563
|
+
type: Component,
|
|
18564
|
+
args: [{ selector: 'fly-detail-card', standalone: true, imports: [FlySectionHeaderComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
18565
|
+
@if (titleKey() || hasProjectedTitle()) {
|
|
18566
|
+
<fly-section-header [titleKey]="titleKey()">
|
|
18567
|
+
<ng-content select="[card-title]" ngProjectAs="[section-title]" />
|
|
18568
|
+
<ng-content select="[card-actions]" ngProjectAs="[section-actions]" />
|
|
18569
|
+
</fly-section-header>
|
|
18570
|
+
}
|
|
18571
|
+
<div class="dc__body" [class.dc__body--flush]="flush()">
|
|
18572
|
+
<ng-content />
|
|
18573
|
+
</div>
|
|
18574
|
+
`, styles: [":host{display:block;background:var(--bg-2);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-card);overflow:hidden}.dc__body{padding:var(--sp-3) var(--sp-4) var(--sp-4)}.dc__body--flush{padding:0}\n"] }]
|
|
18575
|
+
}], propDecorators: { titleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleKey", required: false }] }], hasProjectedTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasProjectedTitle", required: false }] }], flush: [{ type: i0.Input, args: [{ isSignal: true, alias: "flush", required: false }] }] } });
|
|
18576
|
+
|
|
18577
|
+
/**
|
|
18578
|
+
* Roving-focus target for a radiogroup keydown. Pure so the wrap-around and
|
|
18579
|
+
* RTL mirroring are unit-testable without the DOM.
|
|
18580
|
+
*
|
|
18581
|
+
* - ArrowRight/ArrowDown advance, ArrowLeft/ArrowUp go back — horizontal
|
|
18582
|
+
* arrows mirror under RTL (visual "right" stays visual "right").
|
|
18583
|
+
* - Home/End jump to the edges.
|
|
18584
|
+
* - Returns null for any other key (caller must not preventDefault).
|
|
18585
|
+
* - With no current selection (current < 0) navigation starts from index 0.
|
|
18586
|
+
*/
|
|
18587
|
+
function nextSegmentIndex(current, key, length, rtl) {
|
|
18588
|
+
if (length === 0)
|
|
18589
|
+
return null;
|
|
18590
|
+
if (key === 'Home')
|
|
18591
|
+
return 0;
|
|
18592
|
+
if (key === 'End')
|
|
18593
|
+
return length - 1;
|
|
18594
|
+
const forward = key === 'ArrowDown' || key === (rtl ? 'ArrowLeft' : 'ArrowRight');
|
|
18595
|
+
const backward = key === 'ArrowUp' || key === (rtl ? 'ArrowRight' : 'ArrowLeft');
|
|
18596
|
+
if (!forward && !backward)
|
|
18597
|
+
return null;
|
|
18598
|
+
const base = current < 0 ? 0 : current;
|
|
18599
|
+
return forward ? (base + 1) % length : (base - 1 + length) % length;
|
|
18600
|
+
}
|
|
18601
|
+
|
|
18602
|
+
/**
|
|
18603
|
+
* Resolve which section is active.
|
|
18604
|
+
*
|
|
18605
|
+
* The fallback is the point of this function. A detail page's section list is
|
|
18606
|
+
* derived from the record — a scorecard tab only exists while the record has a
|
|
18607
|
+
* scorecard, an approvals tab only while an approval is open — so a selection made
|
|
18608
|
+
* on one record can name a section the NEXT record does not have. The remote-router
|
|
18609
|
+
* outlet reuses the component instance across `/x/:id` → `/x/:id` navigations, so
|
|
18610
|
+
* that is a routine occurrence, not an edge case, and the symptom is an empty panel
|
|
18611
|
+
* with no indication why.
|
|
18612
|
+
*
|
|
18613
|
+
* Returns the selection when it still exists, otherwise the first section, or null
|
|
18614
|
+
* when there are none.
|
|
18615
|
+
*/
|
|
18616
|
+
function resolveActiveSection(sections, selected) {
|
|
18617
|
+
if (sections.length === 0)
|
|
18618
|
+
return null;
|
|
18619
|
+
if (selected !== undefined && sections.some(s => s.id === selected))
|
|
18620
|
+
return selected;
|
|
18621
|
+
return sections[0].id;
|
|
18622
|
+
}
|
|
18623
|
+
|
|
18624
|
+
let nextShellUid = 0;
|
|
18625
|
+
/**
|
|
18626
|
+
* Detail-page body scaffold — an aside (icon rail + pinned cards) beside a panel
|
|
18627
|
+
* showing the active section.
|
|
18628
|
+
*
|
|
18629
|
+
* The anatomy comes from the Circles signal-detail screen and had been hand-copied
|
|
18630
|
+
* onto every detail page that wanted it, CSS and all. Each copy re-derived the same
|
|
18631
|
+
* four decisions and got a different subset right, so this owns them:
|
|
18632
|
+
*
|
|
18633
|
+
* - **The rail sits at the top of the aside, but AFTER the content in the DOM** —
|
|
18634
|
+
* a screen reader meets the record before its navigation, while sighted readers
|
|
18635
|
+
* get the rail where a sidebar nav belongs. `order` does the visual half.
|
|
18636
|
+
* - **The panel stretches to the grid row** (already `max(aside, panel)`), so a
|
|
18637
|
+
* short section's card ends where the aside ends at every window size. A `vh`
|
|
18638
|
+
* floor cannot do this — it ignores the aside and mismatches at every size.
|
|
18639
|
+
* - **Below 980px the rail becomes a horizontal bar** above the panel rather than
|
|
18640
|
+
* a 300px column squeezing the content.
|
|
18641
|
+
* - **The active tab is a solid accent plate with `--on-accent-fill` ink** — NOT
|
|
18642
|
+
* `--accent` on `--accent-soft`: the shell paints `--accent-soft` as a tint of
|
|
18643
|
+
* `--accent`, so that pairing renders the label in its own background colour.
|
|
18644
|
+
*
|
|
18645
|
+
* It also supplies the tablist a11y both hand-rolled rails were missing: proper
|
|
18646
|
+
* `role="tablist"`/`tab`/`tabpanel` wiring, a roving tabindex, and RTL-aware arrow
|
|
18647
|
+
* keys with Home/End (shared with `fly-tabs` via `nextSegmentIndex`).
|
|
18648
|
+
*
|
|
18649
|
+
* ```html
|
|
18650
|
+
* <fly-detail-shell [sections]="sections()" [(selected)]="section">
|
|
18651
|
+
* <ng-container detail-aside>
|
|
18652
|
+
* <fly-detail-card titleKey="common.label.summary">…</fly-detail-card>
|
|
18653
|
+
* </ng-container>
|
|
18654
|
+
*
|
|
18655
|
+
* @switch (activeSection()) {
|
|
18656
|
+
* @case ('metadata') { <fly-detail-card …/> }
|
|
18657
|
+
* }
|
|
18658
|
+
* </fly-detail-shell>
|
|
18659
|
+
* ```
|
|
18660
|
+
*
|
|
18661
|
+
* The default slot is the panel. Read back the resolved section with the two-way
|
|
18662
|
+
* `selected` — it self-corrects when the bound id names a section that no longer
|
|
18663
|
+
* exists (see {@link resolveActiveSection}).
|
|
18664
|
+
*/
|
|
18665
|
+
class FlyDetailShellComponent {
|
|
18666
|
+
i18n = inject(I18nService);
|
|
18667
|
+
uid = `fly-detail-shell-${nextShellUid++}`;
|
|
18668
|
+
rail = viewChild('rail', ...(ngDevMode ? [{ debugName: "rail" }] : /* istanbul ignore next */ []));
|
|
18669
|
+
/** The rail's sections, in order. Empty renders the aside + panel with no rail. */
|
|
18670
|
+
sections = input([], ...(ngDevMode ? [{ debugName: "sections" }] : /* istanbul ignore next */ []));
|
|
18671
|
+
/** Active section id (two-way). Unset/unknown resolves to the first section. */
|
|
18672
|
+
selected = model(...(ngDevMode ? [undefined, { debugName: "selected" }] : /* istanbul ignore next */ []));
|
|
18673
|
+
/** i18n key for the rail's `aria-label`. */
|
|
18674
|
+
sectionsLabelKey = input('ui.nav.sections', ...(ngDevMode ? [{ debugName: "sectionsLabelKey" }] : /* istanbul ignore next */ []));
|
|
18675
|
+
/** The section actually rendered — self-corrects, see {@link resolveActiveSection}. */
|
|
18676
|
+
activeId = computed(() => resolveActiveSection(this.sections(), this.selected()), ...(ngDevMode ? [{ debugName: "activeId" }] : /* istanbul ignore next */ []));
|
|
18677
|
+
tabId(id) {
|
|
18678
|
+
return `${this.uid}-tab-${id}`;
|
|
18679
|
+
}
|
|
18680
|
+
panelId() {
|
|
18681
|
+
return `${this.uid}-panel`;
|
|
18682
|
+
}
|
|
18683
|
+
select(id) {
|
|
18684
|
+
this.selected.set(id);
|
|
18685
|
+
}
|
|
18686
|
+
onKey(event) {
|
|
18687
|
+
const sections = this.sections();
|
|
18688
|
+
const current = sections.findIndex(s => s.id === this.activeId());
|
|
18689
|
+
// The rail is a vertical tablist that turns horizontal below 980px, and
|
|
18690
|
+
// nextSegmentIndex already serves both: Up/Down step unmirrored, Left/Right
|
|
18691
|
+
// mirror under RTL. Home/End jump to the edges.
|
|
18692
|
+
const next = nextSegmentIndex(current, event.key, sections.length, this.i18n.isRtl());
|
|
18693
|
+
if (next === null)
|
|
18694
|
+
return;
|
|
18695
|
+
event.preventDefault();
|
|
18696
|
+
this.select(sections[next].id);
|
|
18697
|
+
const buttons = this.rail()?.nativeElement.querySelectorAll('[role="tab"]');
|
|
18698
|
+
buttons?.[next]?.focus();
|
|
18699
|
+
}
|
|
18700
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyDetailShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18701
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyDetailShellComponent, isStandalone: true, selector: "fly-detail-shell", inputs: { sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, sectionsLabelKey: { classPropertyName: "sectionsLabelKey", publicName: "sectionsLabelKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selectedChange" }, viewQueries: [{ propertyName: "rail", first: true, predicate: ["rail"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
18702
|
+
<div class="ds__layout">
|
|
18703
|
+
<aside class="ds__aside">
|
|
18704
|
+
<div class="ds__pinned">
|
|
18705
|
+
<ng-content select="[detail-aside]" />
|
|
18706
|
+
</div>
|
|
18707
|
+
|
|
18708
|
+
@if (sections().length > 0) {
|
|
18709
|
+
<div
|
|
18710
|
+
#rail
|
|
18711
|
+
class="ds__rail"
|
|
18712
|
+
role="tablist"
|
|
18713
|
+
tabindex="-1"
|
|
18714
|
+
[attr.aria-orientation]="'vertical'"
|
|
18715
|
+
[attr.aria-label]="sectionsLabelKey() | translate"
|
|
18716
|
+
(keydown)="onKey($event)"
|
|
18717
|
+
>
|
|
18718
|
+
@for (s of sections(); track s.id) {
|
|
18719
|
+
<button
|
|
18720
|
+
type="button"
|
|
18721
|
+
class="ds__tab"
|
|
18722
|
+
role="tab"
|
|
18723
|
+
[id]="tabId(s.id)"
|
|
18724
|
+
[class.ds__tab--active]="activeId() === s.id"
|
|
18725
|
+
[attr.aria-selected]="activeId() === s.id"
|
|
18726
|
+
[attr.aria-controls]="panelId()"
|
|
18727
|
+
[attr.tabindex]="activeId() === s.id ? 0 : -1"
|
|
18728
|
+
[attr.title]="s.labelKey | translate"
|
|
18729
|
+
(click)="select(s.id)"
|
|
18730
|
+
>
|
|
18731
|
+
@if (s.icon) {
|
|
18732
|
+
<span class="pi {{ s.icon }} ds__tab-ico" aria-hidden="true"></span>
|
|
18733
|
+
}
|
|
18734
|
+
<span class="ds__tab-label">{{ s.labelKey | translate }}</span>
|
|
18735
|
+
</button>
|
|
18736
|
+
}
|
|
18737
|
+
</div>
|
|
18738
|
+
}
|
|
18739
|
+
</aside>
|
|
18740
|
+
|
|
18741
|
+
<div
|
|
18742
|
+
class="ds__panel"
|
|
18743
|
+
[id]="panelId()"
|
|
18744
|
+
[attr.role]="sections().length ? 'tabpanel' : null"
|
|
18745
|
+
[attr.aria-labelledby]="activeId() ? tabId(activeId()!) : null"
|
|
18746
|
+
>
|
|
18747
|
+
<ng-content />
|
|
18748
|
+
</div>
|
|
18749
|
+
</div>
|
|
18750
|
+
`, isInline: true, styles: [":host{display:block;container-type:inline-size}.ds__layout{display:grid;grid-template-columns:var(--fly-detail-aside, 300px) minmax(0,1fr);gap:var(--sp-4);align-items:start}.ds__aside{display:flex;flex-direction:column;gap:var(--sp-4);min-width:0}.ds__aside .ds__rail{order:-1}.ds__pinned{display:flex;flex-direction:column;gap:var(--sp-4);min-width:0}.ds__panel{display:flex;flex-direction:column;gap:var(--sp-4);min-width:0;align-self:stretch}.ds__panel>:only-child{flex:1}.ds__rail{display:flex;flex-direction:column;gap:var(--sp-1);padding:var(--sp-2);background:var(--bg-2);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-card)}.ds__tab{display:flex;align-items:center;gap:var(--sp-3);width:100%;padding:var(--sp-2);border:0;background:transparent;border-radius:var(--r-md);color:var(--ink-2);cursor:pointer;font-family:inherit;font-size:var(--text-sm);text-align:start;white-space:nowrap;overflow:hidden;transition:background var(--t-state),color var(--t-state)}.ds__tab:hover{background:var(--bg-hover);color:var(--ink)}.ds__tab:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.ds__tab--active{background:var(--accent-fill);color:var(--on-accent-fill);font-weight:var(--fw-semibold)}.ds__tab-ico{font-size:var(--text-md);flex-shrink:0;width:20px;text-align:center}.ds__tab-label{min-width:0;overflow:hidden;text-overflow:ellipsis}@container (max-width: 980px){.ds__layout{grid-template-columns:minmax(0,1fr)}.ds__rail{flex-direction:row;flex-wrap:wrap}.ds__tab{width:auto}}@media(max-width:980px){.ds__layout{grid-template-columns:minmax(0,1fr)}.ds__rail{flex-direction:row;flex-wrap:wrap}.ds__tab{width:auto}}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
18751
|
+
}
|
|
18752
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyDetailShellComponent, decorators: [{
|
|
18753
|
+
type: Component,
|
|
18754
|
+
args: [{ selector: 'fly-detail-shell', standalone: true, imports: [TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
18755
|
+
<div class="ds__layout">
|
|
18756
|
+
<aside class="ds__aside">
|
|
18757
|
+
<div class="ds__pinned">
|
|
18758
|
+
<ng-content select="[detail-aside]" />
|
|
18759
|
+
</div>
|
|
18760
|
+
|
|
18761
|
+
@if (sections().length > 0) {
|
|
18762
|
+
<div
|
|
18763
|
+
#rail
|
|
18764
|
+
class="ds__rail"
|
|
18765
|
+
role="tablist"
|
|
18766
|
+
tabindex="-1"
|
|
18767
|
+
[attr.aria-orientation]="'vertical'"
|
|
18768
|
+
[attr.aria-label]="sectionsLabelKey() | translate"
|
|
18769
|
+
(keydown)="onKey($event)"
|
|
18770
|
+
>
|
|
18771
|
+
@for (s of sections(); track s.id) {
|
|
18772
|
+
<button
|
|
18773
|
+
type="button"
|
|
18774
|
+
class="ds__tab"
|
|
18775
|
+
role="tab"
|
|
18776
|
+
[id]="tabId(s.id)"
|
|
18777
|
+
[class.ds__tab--active]="activeId() === s.id"
|
|
18778
|
+
[attr.aria-selected]="activeId() === s.id"
|
|
18779
|
+
[attr.aria-controls]="panelId()"
|
|
18780
|
+
[attr.tabindex]="activeId() === s.id ? 0 : -1"
|
|
18781
|
+
[attr.title]="s.labelKey | translate"
|
|
18782
|
+
(click)="select(s.id)"
|
|
18783
|
+
>
|
|
18784
|
+
@if (s.icon) {
|
|
18785
|
+
<span class="pi {{ s.icon }} ds__tab-ico" aria-hidden="true"></span>
|
|
18786
|
+
}
|
|
18787
|
+
<span class="ds__tab-label">{{ s.labelKey | translate }}</span>
|
|
18788
|
+
</button>
|
|
18789
|
+
}
|
|
18790
|
+
</div>
|
|
18791
|
+
}
|
|
18792
|
+
</aside>
|
|
18793
|
+
|
|
18794
|
+
<div
|
|
18795
|
+
class="ds__panel"
|
|
18796
|
+
[id]="panelId()"
|
|
18797
|
+
[attr.role]="sections().length ? 'tabpanel' : null"
|
|
18798
|
+
[attr.aria-labelledby]="activeId() ? tabId(activeId()!) : null"
|
|
18799
|
+
>
|
|
18800
|
+
<ng-content />
|
|
18801
|
+
</div>
|
|
18802
|
+
</div>
|
|
18803
|
+
`, styles: [":host{display:block;container-type:inline-size}.ds__layout{display:grid;grid-template-columns:var(--fly-detail-aside, 300px) minmax(0,1fr);gap:var(--sp-4);align-items:start}.ds__aside{display:flex;flex-direction:column;gap:var(--sp-4);min-width:0}.ds__aside .ds__rail{order:-1}.ds__pinned{display:flex;flex-direction:column;gap:var(--sp-4);min-width:0}.ds__panel{display:flex;flex-direction:column;gap:var(--sp-4);min-width:0;align-self:stretch}.ds__panel>:only-child{flex:1}.ds__rail{display:flex;flex-direction:column;gap:var(--sp-1);padding:var(--sp-2);background:var(--bg-2);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-card)}.ds__tab{display:flex;align-items:center;gap:var(--sp-3);width:100%;padding:var(--sp-2);border:0;background:transparent;border-radius:var(--r-md);color:var(--ink-2);cursor:pointer;font-family:inherit;font-size:var(--text-sm);text-align:start;white-space:nowrap;overflow:hidden;transition:background var(--t-state),color var(--t-state)}.ds__tab:hover{background:var(--bg-hover);color:var(--ink)}.ds__tab:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.ds__tab--active{background:var(--accent-fill);color:var(--on-accent-fill);font-weight:var(--fw-semibold)}.ds__tab-ico{font-size:var(--text-md);flex-shrink:0;width:20px;text-align:center}.ds__tab-label{min-width:0;overflow:hidden;text-overflow:ellipsis}@container (max-width: 980px){.ds__layout{grid-template-columns:minmax(0,1fr)}.ds__rail{flex-direction:row;flex-wrap:wrap}.ds__tab{width:auto}}@media(max-width:980px){.ds__layout{grid-template-columns:minmax(0,1fr)}.ds__rail{flex-direction:row;flex-wrap:wrap}.ds__tab{width:auto}}\n"] }]
|
|
18804
|
+
}], propDecorators: { rail: [{ type: i0.ViewChild, args: ['rail', { isSignal: true }] }], sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }, { type: i0.Output, args: ["selectedChange"] }], sectionsLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "sectionsLabelKey", required: false }] }] } });
|
|
18805
|
+
|
|
18464
18806
|
/** Every module across every section, in visual order. */
|
|
18465
18807
|
function flattenModules(sections) {
|
|
18466
18808
|
return sections.flatMap(s => s.modules);
|
|
@@ -18695,29 +19037,139 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
18695
19037
|
}], ctorParameters: () => [], propDecorators: { brandLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandLabelKey", required: false }] }], sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: false }] }], activeKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeKey", required: false }] }], footerLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerLabel", required: false }] }], moduleSelected: [{ type: i0.Output, args: ["moduleSelected"] }], brandSelected: [{ type: i0.Output, args: ["brandSelected"] }], icons: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => FlyModuleIconDirective), { isSignal: true }] }], rows: [{ type: i0.ViewChildren, args: ['row', { isSignal: true }] }], trigger: [{ type: i0.ViewChildren, args: ['trigger', { isSignal: true }] }] } });
|
|
18696
19038
|
|
|
18697
19039
|
/**
|
|
18698
|
-
*
|
|
18699
|
-
*
|
|
19040
|
+
* The section's card shape, applying the default when it declares none: the FIRST
|
|
19041
|
+
* section is the app's front door and gets tall feature cards; everything after it is
|
|
19042
|
+
* secondary and gets compact rows.
|
|
18700
19043
|
*
|
|
18701
|
-
*
|
|
18702
|
-
*
|
|
18703
|
-
*
|
|
18704
|
-
* - Returns null for any other key (caller must not preventDefault).
|
|
18705
|
-
* - With no current selection (current < 0) navigation starts from index 0.
|
|
19044
|
+
* Positional rather than required because the common case — one prominent section plus
|
|
19045
|
+
* a "supporting" tail — should need no configuration at all, and an app that wants
|
|
19046
|
+
* something else says so explicitly.
|
|
18706
19047
|
*/
|
|
18707
|
-
function
|
|
18708
|
-
|
|
18709
|
-
|
|
18710
|
-
|
|
18711
|
-
|
|
18712
|
-
|
|
18713
|
-
|
|
18714
|
-
|
|
18715
|
-
|
|
18716
|
-
|
|
19048
|
+
function sectionLayout(section, index) {
|
|
19049
|
+
return section.layout ?? (index === 0 ? 'feature' : 'compact');
|
|
19050
|
+
}
|
|
19051
|
+
/**
|
|
19052
|
+
* Which sections start expanded: every non-collapsible one, plus none of the
|
|
19053
|
+
* collapsible ones.
|
|
19054
|
+
*
|
|
19055
|
+
* Returned as a `Set` of indices rather than mutating the sections, so the input array
|
|
19056
|
+
* stays the app's immutable declaration and re-rendering with new data cannot resurrect
|
|
19057
|
+
* a stale open/closed state.
|
|
19058
|
+
*/
|
|
19059
|
+
function initialExpanded(sections) {
|
|
19060
|
+
const open = new Set();
|
|
19061
|
+
sections.forEach((s, i) => {
|
|
19062
|
+
if (!s.collapsible)
|
|
19063
|
+
open.add(i);
|
|
19064
|
+
});
|
|
19065
|
+
return open;
|
|
19066
|
+
}
|
|
19067
|
+
/**
|
|
19068
|
+
* The hint key for a collapsible section in its current state, or null when it has none.
|
|
19069
|
+
*
|
|
19070
|
+
* `collapsedHintKey` falls back to `hintKey` so an app that wants one message in both
|
|
19071
|
+
* states declares one key. A non-collapsible section never shows a hint — the hint
|
|
19072
|
+
* exists to explain what is hidden.
|
|
19073
|
+
*/
|
|
19074
|
+
function sectionHintKey(section, expanded) {
|
|
19075
|
+
if (!section.collapsible)
|
|
18717
19076
|
return null;
|
|
18718
|
-
|
|
18719
|
-
|
|
19077
|
+
return (expanded ? section.hintKey : (section.collapsedHintKey ?? section.hintKey)) ?? null;
|
|
19078
|
+
}
|
|
19079
|
+
|
|
19080
|
+
/**
|
|
19081
|
+
* `<fly-app-home>` — a business app's landing page: brand strip, hero, and one card
|
|
19082
|
+
* per module.
|
|
19083
|
+
*
|
|
19084
|
+
* The sibling of {@link FlyAppTopbarComponent}, and deliberately fed by the SAME
|
|
19085
|
+
* `FlyAppModuleSection[]`. An app declares its modules once; the switcher is how you
|
|
19086
|
+
* move between them once you are inside, this is the front door you arrive at. Two
|
|
19087
|
+
* registries would drift, and the drift would show as a module reachable from one and
|
|
19088
|
+
* not the other.
|
|
19089
|
+
*
|
|
19090
|
+
* ```html
|
|
19091
|
+
* <fly-app-home
|
|
19092
|
+
* brandLabelKey="common.label.thoughts"
|
|
19093
|
+
* titleKey="thoughts.home.title"
|
|
19094
|
+
* subtitleKey="thoughts.home.subtitle"
|
|
19095
|
+
* [sections]="navSections"
|
|
19096
|
+
* (moduleSelected)="open($event)">
|
|
19097
|
+
* <span app-home-brand><fly-thoughts-logo /></span>
|
|
19098
|
+
* <div app-home-actions><!-- locale / theme / profile --></div>
|
|
19099
|
+
* <ng-template flyModuleIcon="ideas"><svg …></svg></ng-template>
|
|
19100
|
+
* </fly-app-home>
|
|
19101
|
+
* ```
|
|
19102
|
+
*
|
|
19103
|
+
* Generalized from the Circles landing, whose layout was sound but whose content was
|
|
19104
|
+
* hardcoded — one inline `<svg>` and one `@if` per module, plus a bespoke card for each
|
|
19105
|
+
* non-module destination. Here every card is data, and a destination that is not really
|
|
19106
|
+
* a module (a gallery, a cross-cutting control room) is just another {@link FlyAppModule}
|
|
19107
|
+
* with a projected icon. That was the test of whether this abstraction was real.
|
|
19108
|
+
*
|
|
19109
|
+
* Icons reuse `flyModuleIcon` — the SAME directive the topbar takes — so an app that
|
|
19110
|
+
* renders both declares its icon templates once per surface, in the same syntax.
|
|
19111
|
+
*
|
|
19112
|
+
* a11y: cards are real `<button>`s in a labelled group; a collapsible section is a
|
|
19113
|
+
* disclosure (`aria-expanded` + `aria-controls`), and the region carries the section
|
|
19114
|
+
* heading. Layout is logical-property only, so it mirrors under `dir="rtl"` on its own —
|
|
19115
|
+
* the one exception is the chevron/arrow glyphs, which are directional by meaning and
|
|
19116
|
+
* flip explicitly.
|
|
19117
|
+
*/
|
|
19118
|
+
class FlyAppHomeComponent {
|
|
19119
|
+
/** i18n key for the brand name beside the mark. Omit to render the mark alone. */
|
|
19120
|
+
brandLabelKey = input(...(ngDevMode ? [undefined, { debugName: "brandLabelKey" }] : /* istanbul ignore next */ []));
|
|
19121
|
+
/** i18n key for the hero headline. */
|
|
19122
|
+
titleKey = input(...(ngDevMode ? [undefined, { debugName: "titleKey" }] : /* istanbul ignore next */ []));
|
|
19123
|
+
/** i18n key for the hero sub-line. */
|
|
19124
|
+
subtitleKey = input(...(ngDevMode ? [undefined, { debugName: "subtitleKey" }] : /* istanbul ignore next */ []));
|
|
19125
|
+
/** The app's modules, grouped. Same array the topbar takes. */
|
|
19126
|
+
sections = input([], ...(ngDevMode ? [{ debugName: "sections" }] : /* istanbul ignore next */ []));
|
|
19127
|
+
/** i18n key for the card group's `aria-label`. */
|
|
19128
|
+
modulesLabelKey = input('ui.nav.modules', ...(ngDevMode ? [{ debugName: "modulesLabelKey" }] : /* istanbul ignore next */ []));
|
|
19129
|
+
/** Emits the selected module's `key`. Disabled modules never emit. */
|
|
19130
|
+
moduleSelected = output();
|
|
19131
|
+
/** Emits when the brand is activated. */
|
|
19132
|
+
brandSelected = output();
|
|
19133
|
+
icons = contentChildren(FlyModuleIconDirective, ...(ngDevMode ? [{ debugName: "icons" }] : /* istanbul ignore next */ []));
|
|
19134
|
+
/**
|
|
19135
|
+
* Expanded section indices. Seeded from the inputs and then owned by the user —
|
|
19136
|
+
* `linkedSignal` semantics on purpose: re-declaring `sections` (a locale switch
|
|
19137
|
+
* re-evaluating labels, say) must not slam a section the user opened shut again.
|
|
19138
|
+
*/
|
|
19139
|
+
userToggled = signal(null, ...(ngDevMode ? [{ debugName: "userToggled" }] : /* istanbul ignore next */ []));
|
|
19140
|
+
expandedSet = computed(() => this.userToggled() ?? initialExpanded(this.sections()), ...(ngDevMode ? [{ debugName: "expandedSet" }] : /* istanbul ignore next */ []));
|
|
19141
|
+
/** Presentation-resolved sections, so the template stays declarative. */
|
|
19142
|
+
rows = computed(() => this.sections().map((section, index) => ({
|
|
19143
|
+
index,
|
|
19144
|
+
section,
|
|
19145
|
+
layout: sectionLayout(section, index),
|
|
19146
|
+
expanded: this.expandedSet().has(index),
|
|
19147
|
+
hintKey: sectionHintKey(section, this.expandedSet().has(index)),
|
|
19148
|
+
})), ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
|
|
19149
|
+
iconFor(key) {
|
|
19150
|
+
return this.icons().find(d => d.flyModuleIcon() === key)?.template;
|
|
19151
|
+
}
|
|
19152
|
+
toggle(index) {
|
|
19153
|
+
const next = new Set(this.expandedSet());
|
|
19154
|
+
if (!next.delete(index))
|
|
19155
|
+
next.add(index);
|
|
19156
|
+
this.userToggled.set(next);
|
|
19157
|
+
}
|
|
19158
|
+
select(module) {
|
|
19159
|
+
if (module.disabled)
|
|
19160
|
+
return;
|
|
19161
|
+
this.moduleSelected.emit(module.key);
|
|
19162
|
+
}
|
|
19163
|
+
sectionId(index) {
|
|
19164
|
+
return `fly-app-home-sec-${index}`;
|
|
19165
|
+
}
|
|
19166
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyAppHomeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
19167
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyAppHomeComponent, isStandalone: true, selector: "fly-app-home", inputs: { brandLabelKey: { classPropertyName: "brandLabelKey", publicName: "brandLabelKey", isSignal: true, isRequired: false, transformFunction: null }, titleKey: { classPropertyName: "titleKey", publicName: "titleKey", isSignal: true, isRequired: false, transformFunction: null }, subtitleKey: { classPropertyName: "subtitleKey", publicName: "subtitleKey", isSignal: true, isRequired: false, transformFunction: null }, sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: false, transformFunction: null }, modulesLabelKey: { classPropertyName: "modulesLabelKey", publicName: "modulesLabelKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { moduleSelected: "moduleSelected", brandSelected: "brandSelected" }, queries: [{ propertyName: "icons", predicate: FlyModuleIconDirective, isSignal: true }], ngImport: i0, template: "<div class=\"ah\">\n <header class=\"ah__util\">\n <button type=\"button\" class=\"ah__brand\" (click)=\"brandSelected.emit()\">\n <span class=\"ah__brand-mark\"><ng-content select=\"[app-home-brand]\" /></span>\n @if (brandLabelKey(); as key) {\n <span class=\"ah__brand-name\">{{ key | translate }}</span>\n }\n </button>\n <ng-content select=\"[app-home-actions]\" />\n </header>\n\n <main class=\"ah__main\">\n @if (titleKey() || subtitleKey()) {\n <section class=\"ah__hero\">\n @if (titleKey(); as key) {\n <h1 class=\"ah__title\">{{ key | translate }}</h1>\n }\n @if (subtitleKey(); as key) {\n <p class=\"ah__sub\">{{ key | translate }}</p>\n }\n </section>\n }\n\n @for (row of rows(); track row.index) {\n <section\n class=\"ah__sec\"\n [class.ah__sec--secondary]=\"row.index > 0\"\n [attr.aria-label]=\"row.section.titleKey ? null : (modulesLabelKey() | translate)\"\n >\n @if (row.section.titleKey; as titleKey) {\n @if (row.section.collapsible) {\n <button\n type=\"button\"\n class=\"ah__sec-hd\"\n (click)=\"toggle(row.index)\"\n [attr.aria-expanded]=\"row.expanded\"\n [attr.aria-controls]=\"sectionId(row.index)\"\n >\n <!-- Points end-ward when shut, down when open. `--open` wins over the RTL\n flip below because a downward chevron has no direction to mirror. -->\n <svg\n class=\"ah__sec-chev\"\n [class.ah__sec-chev--open]=\"row.expanded\"\n width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"\n >\n <polyline points=\"9 6 15 12 9 18\" />\n </svg>\n <span class=\"ah__sec-title\">{{ titleKey | translate }}</span>\n <span class=\"ah__sec-count\">{{ row.section.modules.length }}</span>\n @if (row.hintKey; as hint) {\n <span class=\"ah__sec-hint\">{{ hint | translate }}</span>\n }\n </button>\n } @else {\n <h2 class=\"ah__sec-title ah__sec-title--static\">{{ titleKey | translate }}</h2>\n }\n }\n\n @if (row.expanded) {\n <div class=\"ah__grid\" [class.ah__grid--compact]=\"row.layout === 'compact'\" [id]=\"sectionId(row.index)\">\n @for (mod of row.section.modules; track mod.key) {\n <button\n type=\"button\"\n class=\"ah__card\"\n [class.ah__card--compact]=\"row.layout === 'compact'\"\n [disabled]=\"mod.disabled\"\n (click)=\"select(mod)\"\n >\n <span class=\"ah__card-ico\">\n @if (iconFor(mod.key); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n } @else if (mod.iconClass) {\n <i [class]=\"mod.iconClass\" aria-hidden=\"true\"></i>\n }\n </span>\n\n @if (row.layout === 'compact') {\n <span class=\"ah__card-main\">\n <span class=\"ah__card-title\">{{ mod.labelKey | translate }}</span>\n @if (mod.descKey; as descKey) {\n <span class=\"ah__card-desc\">{{ descKey | translate }}</span>\n }\n </span>\n <svg\n class=\"ah__card-arrow\" width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2.6\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" aria-hidden=\"true\"\n >\n <polyline points=\"9 6 15 12 9 18\" />\n </svg>\n } @else {\n <span class=\"ah__card-title ah__card-title--feature\">{{ mod.labelKey | translate }}</span>\n @if (mod.descKey; as descKey) {\n <span class=\"ah__card-desc ah__card-desc--feature\">{{ descKey | translate }}</span>\n }\n <span class=\"ah__card-open\">\n {{ 'ui.action.open' | translate }}\n <svg\n class=\"ah__card-arrow\" width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2.6\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" aria-hidden=\"true\"\n >\n <polyline points=\"9 6 15 12 9 18\" />\n </svg>\n </span>\n }\n </button>\n }\n </div>\n }\n </section>\n }\n </main>\n</div>\n", styles: [":host{display:flex;flex-direction:column;min-height:100%;container-type:inline-size}.ah{display:flex;flex-direction:column;flex:1;min-height:100%}.ah__util{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-4);padding:var(--sp-4) var(--sp-6)}.ah__brand{display:inline-flex;align-items:center;gap:var(--sp-2);padding:0;border:0;background:none;color:var(--ink);font-family:inherit;cursor:pointer}.ah__brand:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.ah__brand-name{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__main{flex:1;inline-size:100%;max-inline-size:1120px;margin-inline:auto;padding:56px 40px;display:flex;flex-direction:column;justify-content:center;gap:44px}.ah__hero{max-inline-size:640px}.ah__title{margin:0 0 var(--sp-3);font-size:44px;font-weight:var(--fw-semibold);letter-spacing:-.03em;text-wrap:balance;background:linear-gradient(180deg,var(--ink),var(--ink-2));-webkit-background-clip:text;background-clip:text;color:transparent}.ah__sub{margin:0;max-inline-size:560px;font-size:var(--text-lg);line-height:1.55;color:var(--ink-3);text-wrap:pretty}.ah__sec{display:flex;flex-direction:column;gap:var(--sp-4)}.ah__sec--secondary{padding-block-start:28px;border-block-start:1px solid var(--line)}.ah__sec-hd{display:flex;align-items:center;gap:var(--sp-3);inline-size:100%;padding:0;background:none;border:0;cursor:pointer;font-family:inherit;color:var(--ink);text-align:start}.ah__sec-hd:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.ah__sec-chev{flex-shrink:0;color:var(--ink-3);transition:transform var(--t-overlay)}.ah__sec-title{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__sec-title--static{margin:0;color:var(--ink-3);font-size:var(--text-xs);letter-spacing:var(--tracking-wide);text-transform:uppercase}.ah__sec-count{display:inline-grid;place-items:center;min-inline-size:22px;block-size:20px;padding-inline:6px;border-radius:999px;background:var(--bg-3);border:1px solid var(--line);font-size:var(--text-2xs);font-weight:var(--fw-medium);color:var(--ink-3)}.ah__sec-hint{margin-inline-start:auto;font-size:var(--text-xs);color:var(--ink-3)}.ah__grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--sp-3)}.ah__card{display:flex;flex-direction:column;align-items:stretch;position:relative;overflow:hidden;text-align:start;padding:22px 22px 18px;background:var(--bg-2);border:1px solid var(--line);border-radius:var(--r-lg);color:inherit;font-family:inherit;cursor:pointer;transition:transform var(--t-overlay),box-shadow var(--t-overlay),border-color var(--t-overlay)}.ah__card:before{content:\"\";position:absolute;inset:0;pointer-events:none;border-radius:inherit;padding:1px;background:var(--grad);-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask-composite:exclude;opacity:0;transition:opacity var(--t-overlay)}.ah__card:hover:not(:disabled){transform:translateY(-2px);border-color:transparent;box-shadow:var(--shadow-filter)}.ah__card:hover:not(:disabled):before{opacity:1}.ah__card:focus-visible{outline:0;border-color:transparent;box-shadow:0 0 0 3px var(--accent-soft),var(--shadow-filter)}.ah__card:focus-visible:before{opacity:1}.ah__card:disabled{cursor:default;opacity:.5}.ah__card-ico{display:grid;place-items:center;inline-size:40px;block-size:40px;margin-block-end:18px;border-radius:11px;background:var(--bg-3);border:0;color:var(--ink);font-size:var(--icon-lg);transition:background var(--t-overlay),color var(--t-overlay)}.ah__card:hover:not(:disabled) .ah__card-ico,.ah__card:focus-visible .ah__card-ico{background:var(--grad);color:var(--ink-inverse)}.ah__card-title{font-size:var(--text-sm);font-weight:var(--fw-semibold);letter-spacing:-.01em;color:var(--ink)}.ah__card-title--feature{margin-block-end:4px;font-size:18px;letter-spacing:-.015em}.ah__card-desc{font-size:var(--text-xs);line-height:1.45;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ah__card-desc--feature{margin-block-end:18px;font-size:var(--text-sm);line-height:1.5;text-wrap:pretty;overflow:visible;white-space:normal}.ah__card-open{display:inline-flex;align-items:center;gap:4px;margin-block-start:auto;font-size:var(--text-2xs);color:var(--ink-3);transition:color var(--t-overlay),gap var(--t-overlay)}.ah__card:hover:not(:disabled) .ah__card-open,.ah__card:focus-visible .ah__card-open{color:var(--accent);gap:8px}.ah__card-arrow{flex-shrink:0;transition:color var(--t-overlay),transform var(--t-overlay)}.ah__card--compact{flex-direction:row;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4)}.ah__card--compact .ah__card-ico{inline-size:34px;block-size:34px;margin-block-end:0;flex-shrink:0;border-radius:9px;font-size:var(--icon-md)}.ah__card-main{display:flex;flex-direction:column;gap:2px;flex:1;min-inline-size:0}.ah__card--compact .ah__card-arrow{color:var(--ink-4)}.ah__card--compact:hover:not(:disabled) .ah__card-arrow{color:var(--accent);transform:translate(2px)}:host-context([dir=rtl]) .ah__card-arrow{transform:scaleX(-1)}:host-context([dir=rtl]) .ah__sec-chev:not(.ah__sec-chev--open){transform:scaleX(-1)}:host-context([dir=rtl]) .ah__card--compact:hover:not(:disabled) .ah__card-arrow{transform:scaleX(-1) translate(2px)}.ah__sec-chev--open{transform:rotate(90deg)}@container (width <= 900px){.ah__grid{grid-template-columns:repeat(2,minmax(0,1fr))}.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@media(width<=900px){.ah__grid{grid-template-columns:repeat(2,minmax(0,1fr))}.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@container (width <= 560px){.ah__grid{grid-template-columns:1fr}.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}@media(width<=560px){.ah__grid{grid-template-columns:1fr}.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
18720
19168
|
}
|
|
19169
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyAppHomeComponent, decorators: [{
|
|
19170
|
+
type: Component,
|
|
19171
|
+
args: [{ selector: 'fly-app-home', standalone: true, imports: [NgTemplateOutlet, TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ah\">\n <header class=\"ah__util\">\n <button type=\"button\" class=\"ah__brand\" (click)=\"brandSelected.emit()\">\n <span class=\"ah__brand-mark\"><ng-content select=\"[app-home-brand]\" /></span>\n @if (brandLabelKey(); as key) {\n <span class=\"ah__brand-name\">{{ key | translate }}</span>\n }\n </button>\n <ng-content select=\"[app-home-actions]\" />\n </header>\n\n <main class=\"ah__main\">\n @if (titleKey() || subtitleKey()) {\n <section class=\"ah__hero\">\n @if (titleKey(); as key) {\n <h1 class=\"ah__title\">{{ key | translate }}</h1>\n }\n @if (subtitleKey(); as key) {\n <p class=\"ah__sub\">{{ key | translate }}</p>\n }\n </section>\n }\n\n @for (row of rows(); track row.index) {\n <section\n class=\"ah__sec\"\n [class.ah__sec--secondary]=\"row.index > 0\"\n [attr.aria-label]=\"row.section.titleKey ? null : (modulesLabelKey() | translate)\"\n >\n @if (row.section.titleKey; as titleKey) {\n @if (row.section.collapsible) {\n <button\n type=\"button\"\n class=\"ah__sec-hd\"\n (click)=\"toggle(row.index)\"\n [attr.aria-expanded]=\"row.expanded\"\n [attr.aria-controls]=\"sectionId(row.index)\"\n >\n <!-- Points end-ward when shut, down when open. `--open` wins over the RTL\n flip below because a downward chevron has no direction to mirror. -->\n <svg\n class=\"ah__sec-chev\"\n [class.ah__sec-chev--open]=\"row.expanded\"\n width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"\n >\n <polyline points=\"9 6 15 12 9 18\" />\n </svg>\n <span class=\"ah__sec-title\">{{ titleKey | translate }}</span>\n <span class=\"ah__sec-count\">{{ row.section.modules.length }}</span>\n @if (row.hintKey; as hint) {\n <span class=\"ah__sec-hint\">{{ hint | translate }}</span>\n }\n </button>\n } @else {\n <h2 class=\"ah__sec-title ah__sec-title--static\">{{ titleKey | translate }}</h2>\n }\n }\n\n @if (row.expanded) {\n <div class=\"ah__grid\" [class.ah__grid--compact]=\"row.layout === 'compact'\" [id]=\"sectionId(row.index)\">\n @for (mod of row.section.modules; track mod.key) {\n <button\n type=\"button\"\n class=\"ah__card\"\n [class.ah__card--compact]=\"row.layout === 'compact'\"\n [disabled]=\"mod.disabled\"\n (click)=\"select(mod)\"\n >\n <span class=\"ah__card-ico\">\n @if (iconFor(mod.key); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n } @else if (mod.iconClass) {\n <i [class]=\"mod.iconClass\" aria-hidden=\"true\"></i>\n }\n </span>\n\n @if (row.layout === 'compact') {\n <span class=\"ah__card-main\">\n <span class=\"ah__card-title\">{{ mod.labelKey | translate }}</span>\n @if (mod.descKey; as descKey) {\n <span class=\"ah__card-desc\">{{ descKey | translate }}</span>\n }\n </span>\n <svg\n class=\"ah__card-arrow\" width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2.6\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" aria-hidden=\"true\"\n >\n <polyline points=\"9 6 15 12 9 18\" />\n </svg>\n } @else {\n <span class=\"ah__card-title ah__card-title--feature\">{{ mod.labelKey | translate }}</span>\n @if (mod.descKey; as descKey) {\n <span class=\"ah__card-desc ah__card-desc--feature\">{{ descKey | translate }}</span>\n }\n <span class=\"ah__card-open\">\n {{ 'ui.action.open' | translate }}\n <svg\n class=\"ah__card-arrow\" width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2.6\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" aria-hidden=\"true\"\n >\n <polyline points=\"9 6 15 12 9 18\" />\n </svg>\n </span>\n }\n </button>\n }\n </div>\n }\n </section>\n }\n </main>\n</div>\n", styles: [":host{display:flex;flex-direction:column;min-height:100%;container-type:inline-size}.ah{display:flex;flex-direction:column;flex:1;min-height:100%}.ah__util{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-4);padding:var(--sp-4) var(--sp-6)}.ah__brand{display:inline-flex;align-items:center;gap:var(--sp-2);padding:0;border:0;background:none;color:var(--ink);font-family:inherit;cursor:pointer}.ah__brand:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.ah__brand-name{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__main{flex:1;inline-size:100%;max-inline-size:1120px;margin-inline:auto;padding:56px 40px;display:flex;flex-direction:column;justify-content:center;gap:44px}.ah__hero{max-inline-size:640px}.ah__title{margin:0 0 var(--sp-3);font-size:44px;font-weight:var(--fw-semibold);letter-spacing:-.03em;text-wrap:balance;background:linear-gradient(180deg,var(--ink),var(--ink-2));-webkit-background-clip:text;background-clip:text;color:transparent}.ah__sub{margin:0;max-inline-size:560px;font-size:var(--text-lg);line-height:1.55;color:var(--ink-3);text-wrap:pretty}.ah__sec{display:flex;flex-direction:column;gap:var(--sp-4)}.ah__sec--secondary{padding-block-start:28px;border-block-start:1px solid var(--line)}.ah__sec-hd{display:flex;align-items:center;gap:var(--sp-3);inline-size:100%;padding:0;background:none;border:0;cursor:pointer;font-family:inherit;color:var(--ink);text-align:start}.ah__sec-hd:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.ah__sec-chev{flex-shrink:0;color:var(--ink-3);transition:transform var(--t-overlay)}.ah__sec-title{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__sec-title--static{margin:0;color:var(--ink-3);font-size:var(--text-xs);letter-spacing:var(--tracking-wide);text-transform:uppercase}.ah__sec-count{display:inline-grid;place-items:center;min-inline-size:22px;block-size:20px;padding-inline:6px;border-radius:999px;background:var(--bg-3);border:1px solid var(--line);font-size:var(--text-2xs);font-weight:var(--fw-medium);color:var(--ink-3)}.ah__sec-hint{margin-inline-start:auto;font-size:var(--text-xs);color:var(--ink-3)}.ah__grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--sp-3)}.ah__card{display:flex;flex-direction:column;align-items:stretch;position:relative;overflow:hidden;text-align:start;padding:22px 22px 18px;background:var(--bg-2);border:1px solid var(--line);border-radius:var(--r-lg);color:inherit;font-family:inherit;cursor:pointer;transition:transform var(--t-overlay),box-shadow var(--t-overlay),border-color var(--t-overlay)}.ah__card:before{content:\"\";position:absolute;inset:0;pointer-events:none;border-radius:inherit;padding:1px;background:var(--grad);-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask-composite:exclude;opacity:0;transition:opacity var(--t-overlay)}.ah__card:hover:not(:disabled){transform:translateY(-2px);border-color:transparent;box-shadow:var(--shadow-filter)}.ah__card:hover:not(:disabled):before{opacity:1}.ah__card:focus-visible{outline:0;border-color:transparent;box-shadow:0 0 0 3px var(--accent-soft),var(--shadow-filter)}.ah__card:focus-visible:before{opacity:1}.ah__card:disabled{cursor:default;opacity:.5}.ah__card-ico{display:grid;place-items:center;inline-size:40px;block-size:40px;margin-block-end:18px;border-radius:11px;background:var(--bg-3);border:0;color:var(--ink);font-size:var(--icon-lg);transition:background var(--t-overlay),color var(--t-overlay)}.ah__card:hover:not(:disabled) .ah__card-ico,.ah__card:focus-visible .ah__card-ico{background:var(--grad);color:var(--ink-inverse)}.ah__card-title{font-size:var(--text-sm);font-weight:var(--fw-semibold);letter-spacing:-.01em;color:var(--ink)}.ah__card-title--feature{margin-block-end:4px;font-size:18px;letter-spacing:-.015em}.ah__card-desc{font-size:var(--text-xs);line-height:1.45;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ah__card-desc--feature{margin-block-end:18px;font-size:var(--text-sm);line-height:1.5;text-wrap:pretty;overflow:visible;white-space:normal}.ah__card-open{display:inline-flex;align-items:center;gap:4px;margin-block-start:auto;font-size:var(--text-2xs);color:var(--ink-3);transition:color var(--t-overlay),gap var(--t-overlay)}.ah__card:hover:not(:disabled) .ah__card-open,.ah__card:focus-visible .ah__card-open{color:var(--accent);gap:8px}.ah__card-arrow{flex-shrink:0;transition:color var(--t-overlay),transform var(--t-overlay)}.ah__card--compact{flex-direction:row;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4)}.ah__card--compact .ah__card-ico{inline-size:34px;block-size:34px;margin-block-end:0;flex-shrink:0;border-radius:9px;font-size:var(--icon-md)}.ah__card-main{display:flex;flex-direction:column;gap:2px;flex:1;min-inline-size:0}.ah__card--compact .ah__card-arrow{color:var(--ink-4)}.ah__card--compact:hover:not(:disabled) .ah__card-arrow{color:var(--accent);transform:translate(2px)}:host-context([dir=rtl]) .ah__card-arrow{transform:scaleX(-1)}:host-context([dir=rtl]) .ah__sec-chev:not(.ah__sec-chev--open){transform:scaleX(-1)}:host-context([dir=rtl]) .ah__card--compact:hover:not(:disabled) .ah__card-arrow{transform:scaleX(-1) translate(2px)}.ah__sec-chev--open{transform:rotate(90deg)}@container (width <= 900px){.ah__grid{grid-template-columns:repeat(2,minmax(0,1fr))}.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@media(width<=900px){.ah__grid{grid-template-columns:repeat(2,minmax(0,1fr))}.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@container (width <= 560px){.ah__grid{grid-template-columns:1fr}.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}@media(width<=560px){.ah__grid{grid-template-columns:1fr}.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}\n"] }]
|
|
19172
|
+
}], propDecorators: { brandLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandLabelKey", required: false }] }], titleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleKey", required: false }] }], subtitleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitleKey", required: false }] }], sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: false }] }], modulesLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "modulesLabelKey", required: false }] }], moduleSelected: [{ type: i0.Output, args: ["moduleSelected"] }], brandSelected: [{ type: i0.Output, args: ["brandSelected"] }], icons: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => FlyModuleIconDirective), { isSignal: true }] }] } });
|
|
18721
19173
|
|
|
18722
19174
|
/**
|
|
18723
19175
|
* Resolve which tab is active: the selected id when it exists in the tab set,
|
|
@@ -20947,5 +21399,5 @@ const AUDIENCE_ERROR_CODES = {
|
|
|
20947
21399
|
* Generated bundle index. Do not edit.
|
|
20948
21400
|
*/
|
|
20949
21401
|
|
|
20950
|
-
export { AGENT_DRAG_MIME, AGENT_PAYLOAD_VERSION, APP_LOOKUP, AUDIENCE_ERROR_CODES, AUDIENCE_LIMITS, AUDIENCE_PRESETS, AUDIENCE_TERM_KINDS, AgentActionBus, AgentActionUnsupportedDispatchError, AgentCommandRegistry, AgentDropRegistry, AgentFlightAnimator, AgentLookupRegistry, AgentPayloadOversizeError, AudienceBuilderComponent, AuthService, BilingualFieldComponent, CRON_MODES, CRON_WEEKDAYS, ContextMenuComponent, DEFAULT_AGENT_PAYLOAD_LIMITS, DEFAULT_FLY_THEME_MODE, DS_BASELINE_LOCALES, DashboardKpiComponent, DialogResult, EntityLookupComponent, FLYOS_LAUNCH_EVENT, FLYOS_LAUNCH_REQUEST_EVENT, FLYOS_REMOTE_ROUTE_EVENT, FLY_ACCENT_PROPERTY, FLY_ADMIN_ROLES, FLY_CHUNK_RELOAD_FLAG, FLY_COMPACT_THRESHOLD, FLY_COUNTRIES, FLY_EMOJI_BY_ID, FLY_EMOJI_CATEGORIES, FLY_EMOJI_CATEGORY_BY_ID, FLY_EMOJI_DEFAULT_CATEGORIES, FLY_EMOJI_PACK, FLY_EMOJI_PACK_MISSING_MESSAGE, FLY_EMOJI_PREVIEW_COUNT, FLY_EMPTY_VALUE, FLY_LOCALE_CATALOG, FLY_NF_CACHE_HEAL_FLAG, FLY_RELOAD_DEBOUNCE_MS, FLY_REMOTE_BASE_PATH, FLY_REMOTE_CONTEXT_EVENT, FLY_REMOTE_CONTEXT_STORE_KEY, FLY_REMOTE_ROUTES, FLY_SEARCH_DEBOUNCE_MS, FLY_SKIN_TONES, FLY_STANDALONE_AUTH_CONFIG, FLY_THEME_MODE_IDS, FLY_WINDOW_HELP_HINT_EVENT, FLY_WINDOW_PAGE_TITLE_EVENT, FlyAchievementProgressComponent, FlyActionMenuComponent, FlyActionStackComponent, FlyAgentDraggableDirective, FlyAnimatedEmojiComponent, FlyAppTopbarComponent, FlyAuthLiveRefresh, FlyBadgeWallComponent, FlyBlockUiComponent, FlyBreadcrumbComponent, FlyButtonComponent, FlyBytesPipe, FlyCaptchaComponent, FlyCardActionsComponent, FlyCardBodyComponent, FlyCardComponent, FlyCardFooterComponent, FlyCardGridComponent, FlyCardMediaComponent, FlyCardMetaComponent, FlyCardStatusComponent, FlyCardTitleComponent, FlyCellDirective, FlyCheckboxComponent, FlyChipComponent, FlyChunkReloadErrorHandler, FlyClickOutsideDirective, FlyCollapsibleComponent, FlyCommentThreadComponent, FlyCompactNumberPipe, FlyConfirmDialogComponent, FlyControlDirective, FlyCronBuilderComponent, FlyDataTableComponent, FlyDatePipe, FlyDateTimePipe, FlyDebouncer, FlyDecimalNumberPipe, FlyDrawerComponent, FlyDurationPipe, FlyDynamicFormComponent, FlyEmojiPickerComponent, FlyFieldComponent, FlyFileUploadComponent, FlyFilterPanelComponent, FlyFormBannerComponent, FlyFormFooterComponent, FlyFormGridComponent, FlyFormSectionComponent, FlyFullNumberPipe, FlyGanttComponent, FlyHubClient, FlyIconButtonComponent, FlyIfAdminDirective, FlyIfRoleDirective, FlyImageUploadComponent, FlyLeaderboardComponent, FlyMetaListComponent, FlyModalComponent, FlyModerationQueueComponent, FlyModuleIconDirective, FlyPaginationComponent, FlyPeoplePickerComponent, FlyPointsTierComponent, FlyProgressComponent, FlyRelativeTimePipe, FlyRemoteContextService, FlyRemoteRouter, FlyRemoteRouterOutletComponent, FlySearchInputComponent, FlySectionHeaderComponent, FlySecureSrcDirective, FlySegmentedComponent, FlySelectComponent, FlySkeletonComponent, FlySliderComponent, FlySparklineComponent, FlySpinnerComponent, FlyStandaloneAuthCallbackComponent, FlyStandaloneAuthService, FlyStateMessageComponent, FlyDynamicFormComponent as FlySurveyFormComponent, FlyTabComponent, FlyTabsComponent, FlyTagsInputComponent, FlyThemeService, FlyTimePipe, FlyToastService, FlyToggleComponent, FlyTooltipDirective, FlyTreeNavComponent, FlyTypeaheadComponent, FlyWindowHelpService, FlyWindowTitleService, FlyosPendingLaunchesGlobalKey, FlyosShellHandlesLaunchRequestsGlobalKey, FlyosShellOwnsHistoryGlobalKey, GANTT_ZOOMS, I18nService, LAUNCH_CONTEXT, MessageBoxButtons, MessageBoxComponent, MessageBoxIcon, MessageBoxService, MockAuthService, OverlayStack, PRESENCE_COLORS, PageHeaderComponent, RTL_LOCALE_SET, SHARE_ORG_CHART_SYSTEM_KEY_APPS, SHARE_ORG_CHART_SYSTEM_KEY_DEFAULT, SHARE_PANEL_DEFAULT_FILE_LEVELS, STATE_DEFAULT_ICONS, STATE_DEFAULT_MESSAGE_KEYS, STEP_UP_CODE, STEP_UP_REAUTH_HANDLER, STEP_UP_RETURN_KEY, SUPPORTED_AGENT_PAYLOAD_VERSIONS, SharePanelComponent, SourceAppResolver, StandaloneWindowManagerService, StatusBadgeComponent, StepUpService, ToastHostComponent, TranslatePipe, WINDOW_DATA, WINDOW_HELP_HINT, WindowManagerService, applySkinTone, applySuggestion, ariaSort, buildCron, canConfirm, canGoNext, canGoPrev, captureFocus, clampPage, clampSliderValue, connectRemoteLaunch, enterActivatesNatively, filterGroup, filterSuggestions, findLocaleByDialect, findLocaleByPrefix, firstEnabledIndex, firstModuleIndex, flattenModules, flyAdminGuard, flyCaptchaBase64Utf8, flyCaptchaBuildToken, flyCaptchaSha256Hex, flyCompactNumber, flyDebounced, flyDecimalNumber, flyDownloadBlob, flyDuration, flyEmojiFor, flyEmojiIsTonable, flyEmojiPackUrl, flyExportFileName, flyFirstEnabledIndex, flyFormatBytes, flyFormatDate, flyFormatDateTime, flyFormatTime, flyFullNumber, flyNextEnabledIndex, flyNextSegmentIndex, flyRelativeTime, flyResolveActiveTab, flyRoleGuard, flySignedCompact, flySkinToneLabelKey, flyStandaloneAuthGuard, flyStandaloneAuthInterceptor, flyToDateOnly, hasAnyRoleIn, healNativeFederationCacheOnce, isAccentColor, isChunkLoadError, isFlyAuthStorePopulated, isNativeFederationCacheError, isRtlLocale, isRtlLocaleEntry, isValidCron, isValidSingleField, loadRemoteStyles, matchFlyRoutePattern, nextEnabledIndex, nextModuleIndex, nextSegmentIndex, nextSort, normalizeFlyTheme, normalizeRoles, overlayStack, parseCron, parseStepUpChallenge, parseTags, presenceColorFor, printConsoleSecurityWarning, provideFlyChunkReloadRecovery, provideFlyEmojiPack, provideFlyStandaloneAuth, reloadOnceForChunkError, requestAppLaunch, resolveActiveModule, resolveActiveTab, resolveCellValue, resolveStateIcon, resolveStateMessageKey, restoreFocus, sameTags, sliderTrackGradient, sparklinePath, sparklinePoints, stepUpInterceptor, stepUpReturnKey, trimAgentPayload, trimAgentString, unloadRemoteStyles, utf8ByteLength, validateAgentPayload, warnIfEmbeddedSessionMissing };
|
|
21402
|
+
export { AGENT_DRAG_MIME, AGENT_PAYLOAD_VERSION, APP_LOOKUP, AUDIENCE_ERROR_CODES, AUDIENCE_LIMITS, AUDIENCE_PRESETS, AUDIENCE_TERM_KINDS, AgentActionBus, AgentActionUnsupportedDispatchError, AgentCommandRegistry, AgentDropRegistry, AgentFlightAnimator, AgentLookupRegistry, AgentPayloadOversizeError, AudienceBuilderComponent, AuthService, BilingualFieldComponent, CRON_MODES, CRON_WEEKDAYS, ContextMenuComponent, DEFAULT_AGENT_PAYLOAD_LIMITS, DEFAULT_FLY_THEME_MODE, DS_BASELINE_LOCALES, DashboardKpiComponent, DialogResult, EntityLookupComponent, FLYOS_LAUNCH_EVENT, FLYOS_LAUNCH_REQUEST_EVENT, FLYOS_REMOTE_ROUTE_EVENT, FLY_ACCENT_PROPERTY, FLY_ADMIN_ROLES, FLY_CHUNK_RELOAD_FLAG, FLY_COMPACT_THRESHOLD, FLY_COUNTRIES, FLY_EMOJI_BY_ID, FLY_EMOJI_CATEGORIES, FLY_EMOJI_CATEGORY_BY_ID, FLY_EMOJI_DEFAULT_CATEGORIES, FLY_EMOJI_PACK, FLY_EMOJI_PACK_MISSING_MESSAGE, FLY_EMOJI_PREVIEW_COUNT, FLY_EMPTY_VALUE, FLY_LOCALE_CATALOG, FLY_NF_CACHE_HEAL_FLAG, FLY_RELOAD_DEBOUNCE_MS, FLY_REMOTE_BASE_PATH, FLY_REMOTE_CONTEXT_EVENT, FLY_REMOTE_CONTEXT_STORE_KEY, FLY_REMOTE_ROUTES, FLY_SEARCH_DEBOUNCE_MS, FLY_SKIN_TONES, FLY_STANDALONE_AUTH_CONFIG, FLY_THEME_MODE_IDS, FLY_WINDOW_HELP_HINT_EVENT, FLY_WINDOW_PAGE_TITLE_EVENT, FlyAchievementProgressComponent, FlyActionMenuComponent, FlyActionStackComponent, FlyAgentDraggableDirective, FlyAnimatedEmojiComponent, FlyAppHomeComponent, FlyAppTopbarComponent, FlyAuthLiveRefresh, FlyBadgeWallComponent, FlyBlockUiComponent, FlyBreadcrumbComponent, FlyButtonComponent, FlyBytesPipe, FlyCaptchaComponent, FlyCardActionsComponent, FlyCardBodyComponent, FlyCardComponent, FlyCardFooterComponent, FlyCardGridComponent, FlyCardMediaComponent, FlyCardMetaComponent, FlyCardStatusComponent, FlyCardTitleComponent, FlyCellDirective, FlyCheckboxComponent, FlyChipComponent, FlyChunkReloadErrorHandler, FlyClickOutsideDirective, FlyCollapsibleComponent, FlyCommentThreadComponent, FlyCompactNumberPipe, FlyConfirmDialogComponent, FlyControlDirective, FlyCronBuilderComponent, FlyDataTableComponent, FlyDatePipe, FlyDateTimePipe, FlyDebouncer, FlyDecimalNumberPipe, FlyDetailCardComponent, FlyDetailShellComponent, FlyDrawerComponent, FlyDurationPipe, FlyDynamicFormComponent, FlyEmojiPickerComponent, FlyFieldComponent, FlyFileUploadComponent, FlyFilterPanelComponent, FlyFormBannerComponent, FlyFormFooterComponent, FlyFormGridComponent, FlyFormSectionComponent, FlyFullNumberPipe, FlyGanttComponent, FlyHubClient, FlyIconButtonComponent, FlyIfAdminDirective, FlyIfRoleDirective, FlyImageUploadComponent, FlyLeaderboardComponent, FlyMetaListComponent, FlyModalComponent, FlyModerationQueueComponent, FlyModuleIconDirective, FlyPaginationComponent, FlyPeoplePickerComponent, FlyPointsTierComponent, FlyProgressComponent, FlyRelativeTimePipe, FlyRemoteContextService, FlyRemoteRouter, FlyRemoteRouterOutletComponent, FlySearchInputComponent, FlySectionHeaderComponent, FlySecureSrcDirective, FlySegmentedComponent, FlySelectComponent, FlySkeletonComponent, FlySliderComponent, FlySparklineComponent, FlySpinnerComponent, FlyStandaloneAuthCallbackComponent, FlyStandaloneAuthService, FlyStateMessageComponent, FlyDynamicFormComponent as FlySurveyFormComponent, FlyTabComponent, FlyTabsComponent, FlyTagsInputComponent, FlyThemeService, FlyTimePipe, FlyToastService, FlyToggleComponent, FlyTooltipDirective, FlyTreeNavComponent, FlyTypeaheadComponent, FlyWindowHelpService, FlyWindowTitleService, FlyosPendingLaunchesGlobalKey, FlyosShellHandlesLaunchRequestsGlobalKey, FlyosShellOwnsHistoryGlobalKey, GANTT_ZOOMS, I18nService, LAUNCH_CONTEXT, MessageBoxButtons, MessageBoxComponent, MessageBoxIcon, MessageBoxService, MockAuthService, OverlayStack, PRESENCE_COLORS, PageHeaderComponent, RTL_LOCALE_SET, SHARE_ORG_CHART_SYSTEM_KEY_APPS, SHARE_ORG_CHART_SYSTEM_KEY_DEFAULT, SHARE_PANEL_DEFAULT_FILE_LEVELS, STATE_DEFAULT_ICONS, STATE_DEFAULT_MESSAGE_KEYS, STEP_UP_CODE, STEP_UP_REAUTH_HANDLER, STEP_UP_RETURN_KEY, SUPPORTED_AGENT_PAYLOAD_VERSIONS, SharePanelComponent, SourceAppResolver, StandaloneWindowManagerService, StatusBadgeComponent, StepUpService, ToastHostComponent, TranslatePipe, WINDOW_DATA, WINDOW_HELP_HINT, WindowManagerService, applySkinTone, applySuggestion, ariaSort, buildCron, canConfirm, canGoNext, canGoPrev, captureFocus, clampPage, clampSliderValue, connectRemoteLaunch, enterActivatesNatively, filterGroup, filterSuggestions, findLocaleByDialect, findLocaleByPrefix, firstEnabledIndex, firstModuleIndex, flattenModules, flyAdminGuard, flyCaptchaBase64Utf8, flyCaptchaBuildToken, flyCaptchaSha256Hex, flyCompactNumber, flyDebounced, flyDecimalNumber, flyDownloadBlob, flyDuration, flyEmojiFor, flyEmojiIsTonable, flyEmojiPackUrl, flyExportFileName, flyFirstEnabledIndex, flyFormatBytes, flyFormatDate, flyFormatDateTime, flyFormatTime, flyFullNumber, flyNextEnabledIndex, flyNextSegmentIndex, flyRelativeTime, flyResolveActiveTab, flyRoleGuard, flySignedCompact, flySkinToneLabelKey, flyStandaloneAuthGuard, flyStandaloneAuthInterceptor, flyToDateOnly, hasAnyRoleIn, healNativeFederationCacheOnce, initialExpanded, isAccentColor, isChunkLoadError, isFlyAuthStorePopulated, isNativeFederationCacheError, isRtlLocale, isRtlLocaleEntry, isValidCron, isValidSingleField, loadRemoteStyles, matchFlyRoutePattern, nextEnabledIndex, nextModuleIndex, nextSegmentIndex, nextSort, normalizeFlyTheme, normalizeRoles, overlayStack, parseCron, parseStepUpChallenge, parseTags, presenceColorFor, printConsoleSecurityWarning, provideFlyChunkReloadRecovery, provideFlyEmojiPack, provideFlyStandaloneAuth, reloadOnceForChunkError, requestAppLaunch, resolveActiveModule, resolveActiveSection, resolveActiveTab, resolveCellValue, resolveStateIcon, resolveStateMessageKey, restoreFocus, sameTags, sectionHintKey, sectionLayout, sliderTrackGradient, sparklinePath, sparklinePoints, stepUpInterceptor, stepUpReturnKey, trimAgentPayload, trimAgentString, unloadRemoteStyles, utf8ByteLength, validateAgentPayload, warnIfEmbeddedSessionMissing };
|
|
20951
21403
|
//# sourceMappingURL=flyos-design-system.mjs.map
|