monkey-style-guide 21.2.12 → 21.2.14

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.
@@ -2,7 +2,7 @@ import { trigger, state, style, transition, animate, keyframes } from '@angular/
2
2
  import * as i1 from '@angular/common';
3
3
  import { CommonModule, NgTemplateOutlet, CurrencyPipe, AsyncPipe } from '@angular/common';
4
4
  import * as i0 from '@angular/core';
5
- import { Injectable, input, Component, TemplateRef, inject, booleanAttribute, Input, HostBinding, ViewEncapsulation, output, InjectionToken, EventEmitter, Output, ViewContainerRef, ElementRef, NgZone, DestroyRef, Optional, Inject, Directive, LOCALE_ID, signal, computed, HostListener, effect, ContentChildren, ChangeDetectorRef, DEFAULT_CURRENCY_CODE, ContentChild, NgModule, ViewChild, ChangeDetectionStrategy, Injector, forwardRef, viewChild, model, afterNextRender, ViewChildren, contentChild, contentChildren, untracked, DOCUMENT } from '@angular/core';
5
+ import { Injectable, input, Component, TemplateRef, inject, booleanAttribute, Input, HostBinding, ViewEncapsulation, output, InjectionToken, EventEmitter, Output, ViewContainerRef, ElementRef, NgZone, DestroyRef, Optional, Inject, Directive, LOCALE_ID, signal, computed, HostListener, effect, ContentChildren, ChangeDetectorRef, DEFAULT_CURRENCY_CODE, ContentChild, NgModule, ViewChild, ChangeDetectionStrategy, Injector, forwardRef, viewChild, untracked, afterNextRender, ViewChildren, model, contentChild, contentChildren, DOCUMENT } from '@angular/core';
6
6
  import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
7
7
  import * as i1$1 from '@angular/forms';
8
8
  import { Validators, NgControl, FormsModule, ReactiveFormsModule, FormControlDirective, NgModel, FormControlName, FormGroupDirective, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
@@ -1325,6 +1325,42 @@ class MonkeyDictionaryService {
1325
1325
  'NOT-SELECTABLE': 'Esta linha não pode ser selecionada'
1326
1326
  }
1327
1327
  },
1328
+ 'FILTER-BAR': {
1329
+ ADD: 'Filtro',
1330
+ 'ADD-ARIA': 'Adicionar filtro',
1331
+ REMOVE: 'Remover filtro',
1332
+ CLEAR: 'Limpar filtros',
1333
+ SEARCH: 'Buscar filtro',
1334
+ 'SELECT-CONDITION': 'Selecione condição',
1335
+ SELECT: 'Selecione',
1336
+ CONFIRM: 'Confirmar',
1337
+ 'RANGE-FROM': 'Valor inicial',
1338
+ 'RANGE-TO': 'Valor final',
1339
+ SELECTED: '{count} selecionados',
1340
+ DATE: {
1341
+ 'WEEK-AFTER': '1 semana a partir de hoje',
1342
+ 'MONTH-AFTER': '1 mês a partir de hoje',
1343
+ 'QUARTER-AFTER': '3 meses a partir de hoje',
1344
+ 'WEEK-BEFORE': '1 semana antes de hoje',
1345
+ 'MONTH-BEFORE': '1 mês antes de hoje',
1346
+ 'QUARTER-BEFORE': '3 meses antes de hoje',
1347
+ CUSTOM: 'Personalizado'
1348
+ },
1349
+ OPERATOR: {
1350
+ EQ: 'É igual',
1351
+ NEQ: 'Não é igual',
1352
+ LIKE: 'Contém',
1353
+ NOT_LIKE: 'Não contém',
1354
+ STARTS_WITH: 'Começa com',
1355
+ ENDS_WITH: 'Termina com',
1356
+ IS_EMPTY: 'Vazio',
1357
+ BETWEEN: 'Entre',
1358
+ GT: 'Maior que',
1359
+ LT: 'Menor que',
1360
+ BEFORE: 'Antes de',
1361
+ AFTER: 'Depois de'
1362
+ }
1363
+ },
1328
1364
  'DATE-RANGE': {
1329
1365
  'START-DATE': 'Data de início',
1330
1366
  'END-DATE': 'Data de término',
@@ -1398,6 +1434,42 @@ class MonkeyDictionaryService {
1398
1434
  'NOT-SELECTABLE': 'Esta fila no se puede seleccionar'
1399
1435
  }
1400
1436
  },
1437
+ 'FILTER-BAR': {
1438
+ ADD: 'Filtro',
1439
+ 'ADD-ARIA': 'Agregar filtro',
1440
+ REMOVE: 'Eliminar filtro',
1441
+ CLEAR: 'Limpiar filtros',
1442
+ SEARCH: 'Buscar filtro',
1443
+ 'SELECT-CONDITION': 'Seleccione condición',
1444
+ SELECT: 'Seleccione',
1445
+ CONFIRM: 'Confirmar',
1446
+ 'RANGE-FROM': 'Valor inicial',
1447
+ 'RANGE-TO': 'Valor final',
1448
+ SELECTED: '{count} seleccionados',
1449
+ DATE: {
1450
+ 'WEEK-AFTER': '1 semana a partir de hoy',
1451
+ 'MONTH-AFTER': '1 mes a partir de hoy',
1452
+ 'QUARTER-AFTER': '3 meses a partir de hoy',
1453
+ 'WEEK-BEFORE': '1 semana antes de hoy',
1454
+ 'MONTH-BEFORE': '1 mes antes de hoy',
1455
+ 'QUARTER-BEFORE': '3 meses antes de hoy',
1456
+ CUSTOM: 'Personalizado'
1457
+ },
1458
+ OPERATOR: {
1459
+ EQ: 'Es igual',
1460
+ NEQ: 'No es igual',
1461
+ LIKE: 'Contiene',
1462
+ NOT_LIKE: 'No contiene',
1463
+ STARTS_WITH: 'Empieza con',
1464
+ ENDS_WITH: 'Termina con',
1465
+ IS_EMPTY: 'Vacío',
1466
+ BETWEEN: 'Entre',
1467
+ GT: 'Mayor que',
1468
+ LT: 'Menor que',
1469
+ BEFORE: 'Antes de',
1470
+ AFTER: 'Después de'
1471
+ }
1472
+ },
1401
1473
  'DATE-RANGE': {
1402
1474
  'START-DATE': 'Fecha de inicio',
1403
1475
  'END-DATE': 'Fecha de termino',
@@ -1471,6 +1543,42 @@ class MonkeyDictionaryService {
1471
1543
  'NOT-SELECTABLE': 'Esta fila no se puede seleccionar'
1472
1544
  }
1473
1545
  },
1546
+ 'FILTER-BAR': {
1547
+ ADD: 'Filtro',
1548
+ 'ADD-ARIA': 'Agregar filtro',
1549
+ REMOVE: 'Eliminar filtro',
1550
+ CLEAR: 'Limpiar filtros',
1551
+ SEARCH: 'Buscar filtro',
1552
+ 'SELECT-CONDITION': 'Seleccione condición',
1553
+ SELECT: 'Seleccione',
1554
+ CONFIRM: 'Confirmar',
1555
+ 'RANGE-FROM': 'Valor inicial',
1556
+ 'RANGE-TO': 'Valor final',
1557
+ SELECTED: '{count} seleccionados',
1558
+ DATE: {
1559
+ 'WEEK-AFTER': '1 semana a partir de hoy',
1560
+ 'MONTH-AFTER': '1 mes a partir de hoy',
1561
+ 'QUARTER-AFTER': '3 meses a partir de hoy',
1562
+ 'WEEK-BEFORE': '1 semana antes de hoy',
1563
+ 'MONTH-BEFORE': '1 mes antes de hoy',
1564
+ 'QUARTER-BEFORE': '3 meses antes de hoy',
1565
+ CUSTOM: 'Personalizado'
1566
+ },
1567
+ OPERATOR: {
1568
+ EQ: 'Es igual',
1569
+ NEQ: 'No es igual',
1570
+ LIKE: 'Contiene',
1571
+ NOT_LIKE: 'No contiene',
1572
+ STARTS_WITH: 'Empieza con',
1573
+ ENDS_WITH: 'Termina con',
1574
+ IS_EMPTY: 'Vacío',
1575
+ BETWEEN: 'Entre',
1576
+ GT: 'Mayor que',
1577
+ LT: 'Menor que',
1578
+ BEFORE: 'Antes de',
1579
+ AFTER: 'Después de'
1580
+ }
1581
+ },
1474
1582
  'DATE-RANGE': {
1475
1583
  'START-DATE': 'Fecha de inicio',
1476
1584
  'END-DATE': 'Fecha de termino',
@@ -1544,6 +1652,42 @@ class MonkeyDictionaryService {
1544
1652
  'NOT-SELECTABLE': 'This row cannot be selected'
1545
1653
  }
1546
1654
  },
1655
+ 'FILTER-BAR': {
1656
+ ADD: 'Filter',
1657
+ 'ADD-ARIA': 'Add filter',
1658
+ REMOVE: 'Remove filter',
1659
+ CLEAR: 'Clear filters',
1660
+ SEARCH: 'Search filter',
1661
+ 'SELECT-CONDITION': 'Select condition',
1662
+ SELECT: 'Select',
1663
+ CONFIRM: 'Confirm',
1664
+ 'RANGE-FROM': 'From',
1665
+ 'RANGE-TO': 'To',
1666
+ SELECTED: '{count} selected',
1667
+ DATE: {
1668
+ 'WEEK-AFTER': '1 week from today',
1669
+ 'MONTH-AFTER': '1 month from today',
1670
+ 'QUARTER-AFTER': '3 months from today',
1671
+ 'WEEK-BEFORE': '1 week before today',
1672
+ 'MONTH-BEFORE': '1 month before today',
1673
+ 'QUARTER-BEFORE': '3 months before today',
1674
+ CUSTOM: 'Custom'
1675
+ },
1676
+ OPERATOR: {
1677
+ EQ: 'Is equal to',
1678
+ NEQ: 'Is not equal to',
1679
+ LIKE: 'Contains',
1680
+ NOT_LIKE: 'Does not contain',
1681
+ STARTS_WITH: 'Starts with',
1682
+ ENDS_WITH: 'Ends with',
1683
+ IS_EMPTY: 'Is empty',
1684
+ BETWEEN: 'Between',
1685
+ GT: 'Greater than',
1686
+ LT: 'Less than',
1687
+ BEFORE: 'Before',
1688
+ AFTER: 'After'
1689
+ }
1690
+ },
1547
1691
  'DATE-RANGE': {
1548
1692
  'START-DATE': 'Start date',
1549
1693
  'END-DATE': 'End Date',
@@ -5644,1008 +5788,94 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
5644
5788
  * This style guide was developed by Monkey Exchange Team
5645
5789
  * MIT Licence
5646
5790
  ************************* */
5647
- class MonkeyRadioButtonComponent {
5648
- get classes() {
5649
- return `${this.position} ${this.size}`;
5650
- }
5651
- get disabled() {
5652
- if (this.ngControl && this.ngControl.disabled !== null) {
5653
- return this.ngControl.disabled;
5654
- }
5655
- return this._disabled;
5656
- }
5657
- set disabled(value) {
5658
- this._disabled = value;
5659
- if (this.focused) {
5660
- this.focused = false;
5661
- this.stateChanges.next();
5662
- }
5663
- }
5664
- get required() {
5665
- return this._required ?? this.ngControl?.control?.hasValidator(Validators.required) ?? false;
5666
- }
5667
- set required(value) {
5668
- this._required = value;
5669
- this.stateChanges.next();
5670
- }
5671
- set value(value) {
5672
- if (this._value !== value) {
5673
- this._value = value;
5674
- this._onChange(value);
5675
- }
5676
- }
5677
- get value() {
5678
- return this._value;
5679
- }
5680
- constructor(changeDetectorRef, formField) {
5681
- this.changeDetectorRef = changeDetectorRef;
5682
- this.formField = formField;
5683
- this.tabIndex = 0;
5684
- this.onChange = new EventEmitter();
5685
- this.onSearch = new EventEmitter();
5686
- this.position = 'horizontal';
5687
- this.size = 'lg';
5688
- this._value = null;
5689
- this._destroyRef = inject(DestroyRef);
5690
- this.idGenerator = inject(IdGenerator);
5691
- this.ngControl = inject(NgControl, { self: true, optional: true });
5692
- this._elementRef = inject(ElementRef);
5693
- this.focused = false;
5694
- this._disabled = false;
5695
- this.id = this.idGenerator.getId('monkey-radiobutton-');
5696
- this.stateChanges = new Subject();
5697
- this.type = 'radio-button';
5698
- this._onChange = () => { };
5699
- this._onTouched = () => { };
5700
- if (this.ngControl) {
5701
- this.ngControl.valueAccessor = this;
5702
- }
5703
- }
5704
- changeSelected() {
5705
- setTimeout(() => {
5706
- if (this.options) {
5707
- this.options.forEach((opt) => {
5708
- opt.onSelect(opt.value() === this.value);
5709
- });
5710
- }
5711
- this.changeDetectorRef.markForCheck();
5712
- });
5713
- }
5714
- initializeOptions() {
5715
- setTimeout(() => {
5716
- this.options?.forEach((option) => {
5717
- option.type = 'radio';
5718
- if (!option.action) {
5719
- option.action = this.selectOption.bind(this, option);
5720
- }
5721
- });
5722
- this.changeDetectorRef.markForCheck();
5723
- }, 0);
5724
- }
5725
- ngAfterContentInit() {
5726
- this.initializeOptions();
5727
- this.options.changes.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(() => {
5728
- this.initializeOptions();
5729
- this.changeSelected();
5730
- });
5731
- }
5732
- selectOption(option) {
5733
- if (!option.disabled && !this.disabled) {
5734
- this.value = option.value();
5735
- this._onChange(this.value);
5736
- this.onChange.emit(this.value);
5737
- this.options.forEach((opt) => {
5738
- opt.onSelect(opt.value() === this.value);
5739
- });
5740
- }
5741
- }
5742
- writeValue(value) {
5743
- this.value = value;
5744
- this.changeSelected();
5745
- }
5746
- onContainerClick(event) {
5747
- if (this.disabled)
5748
- return;
5749
- this._elementRef.nativeElement.focus();
5750
- }
5751
- _onFocus() {
5752
- if (!this.disabled) {
5753
- this.focused = true;
5754
- this._onTouched();
5755
- this.stateChanges.next();
5756
- }
5757
- }
5758
- _onBlur() {
5759
- this.focused = false;
5760
- this.stateChanges.next();
5761
- }
5762
- registerOnChange(fn) {
5763
- this._onChange = fn;
5764
- }
5765
- registerOnTouched(fn) {
5766
- this._onTouched = fn;
5767
- }
5768
- setDisabledState(isDisabled) {
5769
- this.disabled = isDisabled;
5770
- this.initializeOptions();
5771
- }
5772
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyRadioButtonComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: MonkeyFormFieldComponent, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
5773
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "21.2.4", type: MonkeyRadioButtonComponent, isStandalone: true, selector: "monkey-radiobutton", inputs: { tabIndex: "tabIndex", position: "position", size: "size", disabled: ["disabled", "disabled", booleanAttribute], required: ["required", "required", booleanAttribute], value: "value" }, outputs: { onChange: "onChange", onSearch: "onSearch" }, host: { attributes: { "data-testid": "monkey-radiobutton" }, listeners: { "focus": "_onFocus()", "blur": "_onBlur()" }, properties: { "class.mecx-disabled": "disabled", "class.mecx-radiobutton-focused": "focused", "attr.id": "id", "attr.tabindex": "disabled ? -1 : tabIndex", "class": "this.classes" }, classAttribute: "mecx-radiobutton" }, providers: [
5774
- // eslint-disable-next-line no-use-before-define
5775
- { provide: MonkeyFormFieldControl, useExisting: MonkeyRadioButtonComponent }
5776
- ], queries: [{ propertyName: "options", predicate: MonkeyOptionComponent }], ngImport: i0, template: "<ng-content />\r\n", styles: ["monkey-radiobutton{display:inline-flex;width:100%;min-width:0;position:relative;flex-wrap:wrap}monkey-radiobutton:focus-visible,monkey-radiobutton:focus{outline:none}monkey-radiobutton.vertical{flex-direction:column}monkey-radiobutton monkey-option{transition:none!important}monkey-radiobutton.mecx-disabled monkey-option{opacity:.5;pointer-events:none}monkey-radiobutton.mecx-disabled monkey-option:before{background:var(--mecx-color-white);border-color:var(--mecx-color-gray-400)}monkey-radiobutton.mecx-form-field-invalid{background:var(--mecx-color-error-700)}monkey-radiobutton.md monkey-option:before{width:16px;height:16px}monkey-radiobutton.sm monkey-option:before{width:14px;height:14px}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
5777
- }
5778
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyRadioButtonComponent, decorators: [{
5779
- type: Component,
5780
- args: [{ selector: 'monkey-radiobutton', imports: [ReactiveFormsModule, FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [
5781
- // eslint-disable-next-line no-use-before-define
5782
- { provide: MonkeyFormFieldControl, useExisting: MonkeyRadioButtonComponent }
5783
- ], host: {
5784
- 'data-testid': 'monkey-radiobutton',
5785
- class: 'mecx-radiobutton',
5786
- '[class.mecx-disabled]': 'disabled',
5787
- '[class.mecx-radiobutton-focused]': 'focused',
5788
- '[attr.id]': 'id',
5789
- '[attr.tabindex]': 'disabled ? -1 : tabIndex',
5790
- '(focus)': '_onFocus()',
5791
- '(blur)': '_onBlur()'
5792
- }, template: "<ng-content />\r\n", styles: ["monkey-radiobutton{display:inline-flex;width:100%;min-width:0;position:relative;flex-wrap:wrap}monkey-radiobutton:focus-visible,monkey-radiobutton:focus{outline:none}monkey-radiobutton.vertical{flex-direction:column}monkey-radiobutton monkey-option{transition:none!important}monkey-radiobutton.mecx-disabled monkey-option{opacity:.5;pointer-events:none}monkey-radiobutton.mecx-disabled monkey-option:before{background:var(--mecx-color-white);border-color:var(--mecx-color-gray-400)}monkey-radiobutton.mecx-form-field-invalid{background:var(--mecx-color-error-700)}monkey-radiobutton.md monkey-option:before{width:16px;height:16px}monkey-radiobutton.sm monkey-option:before{width:14px;height:14px}\n"] }]
5793
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: MonkeyFormFieldComponent, decorators: [{
5794
- type: Optional
5795
- }] }], propDecorators: { options: [{
5796
- type: ContentChildren,
5797
- args: [MonkeyOptionComponent]
5798
- }], tabIndex: [{
5799
- type: Input
5800
- }], onChange: [{
5801
- type: Output
5802
- }], onSearch: [{
5803
- type: Output
5804
- }], position: [{
5805
- type: Input
5806
- }], size: [{
5807
- type: Input
5808
- }], classes: [{
5809
- type: HostBinding,
5810
- args: ['class']
5811
- }], disabled: [{
5812
- type: Input,
5813
- args: [{ transform: booleanAttribute }]
5814
- }], required: [{
5815
- type: Input,
5816
- args: [{ transform: booleanAttribute }]
5817
- }], value: [{
5818
- type: Input
5819
- }] } });
5820
5791
 
5821
5792
  /** ************************
5822
5793
  * Copyright Monkey Exchange. All Rights Reserved
5823
5794
  * This style guide was developed by Monkey Exchange Team
5824
5795
  * MIT Licence
5825
5796
  ************************* */
5797
+ const CONDITIONS = {
5798
+ text: ['LIKE', 'NOT_LIKE', 'STARTS_WITH', 'ENDS_WITH', 'IS_EMPTY'],
5799
+ currency: ['EQ', 'NEQ', 'BETWEEN', 'GT', 'LT'],
5800
+ date: ['EQ', 'NEQ', 'BETWEEN', 'BEFORE', 'AFTER'],
5801
+ status: ['EQ', 'NEQ']
5802
+ };
5803
+ const NO_OPERAND = new Set(['IS_EMPTY']);
5804
+ const TWO_OPERANDS = new Set(['BETWEEN']);
5805
+ function conditionsOf(type) {
5806
+ return CONDITIONS[type] ?? [];
5807
+ }
5808
+ function arityOf(condition) {
5809
+ if (NO_OPERAND.has(condition))
5810
+ return 0;
5811
+ if (TWO_OPERANDS.has(condition))
5812
+ return 2;
5813
+ return 1;
5814
+ }
5815
+ function panelOf(type, condition) {
5816
+ if (!condition || arityOf(condition) === 0)
5817
+ return 'none';
5818
+ switch (type) {
5819
+ case 'status':
5820
+ return 'status';
5821
+ case 'date':
5822
+ return arityOf(condition) === 2 ? 'date-range' : 'date-day';
5823
+ default:
5824
+ return 'field';
5825
+ }
5826
+ }
5827
+ function isComplete(row) {
5828
+ return !!row.condition && row.operands.length === arityOf(row.condition);
5829
+ }
5830
+ function appliedFrom(rows) {
5831
+ return rows.filter(isComplete).map((row) => {
5832
+ return {
5833
+ key: row.key,
5834
+ label: row.label,
5835
+ type: row.type,
5836
+ condition: row.condition,
5837
+ operands: row.operands
5838
+ };
5839
+ });
5840
+ }
5841
+ function withCondition(row, condition) {
5842
+ const sameArity = arityOf(row.condition) === arityOf(condition);
5843
+ if (sameArity)
5844
+ return { ...row, condition };
5845
+ return { ...row, condition, operands: [] };
5846
+ }
5847
+ function withType(row, next) {
5848
+ const condition = conditionsOf(next.type).includes(row.condition)
5849
+ ? row.condition
5850
+ : '';
5851
+ return { ...next, condition, operands: [] };
5852
+ }
5826
5853
 
5827
5854
  /** ************************
5828
5855
  * Copyright Monkey Exchange. All Rights Reserved
5829
5856
  * This style guide was developed by Monkey Exchange Team
5830
5857
  * MIT Licence
5831
5858
  ************************* */
5832
- class MonkeyFilterBarComponent {
5833
- constructor() {
5834
- this._elementRef = inject(ElementRef);
5835
- this._service = inject(MonkeyFilterBarService);
5836
- this.key = input.required(...(ngDevMode ? [{ debugName: "key" }] : /* istanbul ignore next */ []));
5837
- this.config = input(...(ngDevMode ? [undefined, { debugName: "config" }] : /* istanbul ignore next */ []));
5838
- this.filtersChange = new EventEmitter();
5839
- this.searchChange = new EventEmitter();
5840
- this.showFilterMenu = false;
5841
- this.showDateSubmenu = false;
5842
- this.showFilterInput = false;
5843
- this.filterMenuTarget = null;
5844
- this.dateSubmenuTarget = null;
5845
- this.filterInputTarget = null;
5846
- this.isEditingFilter = false;
5847
- this.activeOption = signal(null, ...(ngDevMode ? [{ debugName: "activeOption" }] : /* istanbul ignore next */ []));
5848
- this.textValue = '';
5849
- this.currencyValue = null;
5850
- this.currencyMode = 'from';
5851
- this.statusValues = [];
5852
- this.dateRange = { startDate: '', endDate: '' };
5853
- this.showCustomDate = false;
5854
- this.serviceConfig = computed(() => {
5855
- const k = this.key();
5856
- return k ? this._service.getConfig(k) ?? this.config() : undefined;
5857
- }, ...(ngDevMode ? [{ debugName: "serviceConfig" }] : /* istanbul ignore next */ []));
5858
- this.activeFilters = computed(() => {
5859
- const k = this.key();
5860
- return k ? this._service.getActiveFilters(k) : [];
5861
- }, ...(ngDevMode ? [{ debugName: "activeFilters" }] : /* istanbul ignore next */ []));
5862
- this.searchValue = computed(() => {
5863
- const k = this.key();
5864
- return k ? this._service.getSearchValue(k) : '';
5865
- }, ...(ngDevMode ? [{ debugName: "searchValue" }] : /* istanbul ignore next */ []));
5866
- this.searchPlaceholder = computed(() => this.serviceConfig()?.searchPlaceholder ?? 'Pesquisar...', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
5867
- this.closeFilterMenu = () => {
5868
- this.showFilterMenu = false;
5869
- };
5870
- this.closeDateSubmenu = () => {
5871
- this.showDateSubmenu = false;
5872
- };
5873
- this.closeFilterInput = () => {
5874
- this.showFilterInput = false;
5875
- this.showCustomDate = false;
5876
- this.isEditingFilter = false;
5877
- this.activeOption.set(null);
5878
- this._resetInputState();
5879
- };
5880
- effect(() => {
5881
- const k = this.key();
5882
- const cfg = this.config();
5883
- if (k && cfg)
5884
- this._service.setConfig(k, cfg);
5885
- });
5886
- }
5887
- ngOnInit() {
5888
- const k = this.key();
5889
- const cfg = this.config();
5890
- if (k && cfg)
5891
- this._service.setConfig(k, cfg);
5892
- }
5893
- ngOnChanges(changes) {
5894
- const k = this.key();
5895
- const cfg = this.config();
5896
- if (k && cfg && (changes['key'] || changes['config'])) {
5897
- this._service.setConfig(k, cfg);
5898
- }
5899
- }
5900
- ngOnDestroy() { }
5901
- availableFilterOptions() {
5902
- const k = this.key();
5903
- return k ? this._service.availableFilterOptions(k) : [];
5904
- }
5905
- isFilterActive(filterKey) {
5906
- const k = this.key();
5907
- return k ? this._service.isFilterActive(k, filterKey) : false;
5908
- }
5909
- getOptionId(optionKey) {
5910
- return `filter-bar-opt-${this.key()}-${optionKey}`;
5911
- }
5912
- getActiveFilterId(filterKey) {
5913
- return `filter-bar-active-${this.key()}-${filterKey}`;
5914
- }
5915
- onShowFilterMenu(btn) {
5916
- this.filterMenuTarget = btn.element;
5917
- this.showFilterMenu = true;
5918
- }
5919
- onSelectOption(option) {
5920
- if (this.isFilterActive(option.key))
5921
- return;
5922
- this.activeOption.set(option);
5923
- const optEl = document.getElementById(this.getOptionId(option.key));
5924
- if (!optEl)
5925
- return;
5926
- if (option.type === 'date') {
5927
- this.dateSubmenuTarget = optEl;
5928
- this.showCustomDate = false;
5929
- this.showDateSubmenu = true;
5930
- }
5931
- else {
5932
- this.filterInputTarget = optEl;
5933
- this.isEditingFilter = false;
5934
- this._resetInputState();
5935
- this.showFilterInput = true;
5936
- }
5937
- }
5938
- onQuickDate(preset) {
5939
- const k = this.key();
5940
- const opt = this.activeOption();
5941
- if (!k || !opt || opt.type !== 'date')
5942
- return;
5943
- const today = new Date();
5944
- if (preset === 'custom') {
5945
- this.closeDateSubmenu();
5946
- this.showCustomDate = true;
5947
- this.dateRange = { startDate: '', endDate: '' };
5948
- this.filterInputTarget = this.dateSubmenuTarget;
5949
- this.showFilterInput = true;
5950
- return;
5951
- }
5952
- let start;
5953
- let end = today;
5954
- switch (preset) {
5955
- case '1-week-after':
5956
- start = today;
5957
- end = addDays(today, 7);
5958
- break;
5959
- case '1-month-after':
5960
- start = today;
5961
- end = addMonths(today, 1);
5962
- break;
5963
- case '3-months-after':
5964
- start = today;
5965
- end = addMonths(today, 3);
5966
- break;
5967
- case '1-week-before':
5968
- start = subDays(today, 7);
5969
- break;
5970
- case '1-month-before':
5971
- start = subMonths(today, 1);
5972
- break;
5973
- case '3-months-before':
5974
- start = subMonths(today, 3);
5975
- break;
5976
- default:
5977
- return;
5978
- }
5979
- const value = {
5980
- startDate: format(start, 'yyyy-MM-dd'),
5981
- endDate: format(end, 'yyyy-MM-dd')
5982
- };
5983
- this._service.addFilter(k, opt, value);
5984
- this.closeDateSubmenu();
5985
- this.closeFilterMenu();
5986
- this._emit();
5987
- }
5988
- onDateChange(event) {
5989
- this.dateRange = event;
5990
- if (event.startDate && event.endDate) {
5991
- setTimeout(() => this.onApply(), 100);
5992
- }
5993
- }
5994
- onStatusChange(val, checked) {
5995
- if (checked) {
5996
- if (!this.statusValues.includes(val))
5997
- this.statusValues = [...this.statusValues, val];
5998
- }
5999
- else {
6000
- this.statusValues = this.statusValues.filter((v) => v !== val);
6001
- }
6002
- }
6003
- onApply() {
6004
- const k = this.key();
6005
- const opt = this.activeOption();
6006
- if (!k || !opt)
6007
- return;
6008
- let value;
6009
- switch (opt.type) {
6010
- case 'text':
6011
- if (!this.textValue.trim())
6012
- return;
6013
- value = this.textValue.trim();
6014
- break;
6015
- case 'date':
6016
- if (!this.dateRange.startDate || !this.dateRange.endDate)
6017
- return;
6018
- value = { startDate: this.dateRange.startDate, endDate: this.dateRange.endDate };
6019
- break;
6020
- case 'currency': {
6021
- const raw = this.currencyValue;
6022
- if (raw === null || raw === undefined)
6023
- return;
6024
- value =
6025
- this.currencyMode === 'from'
6026
- ? { min: raw, max: undefined }
6027
- : { min: undefined, max: raw };
6028
- break;
6029
- }
6030
- case 'status':
6031
- if (this.statusValues.length === 0)
6032
- return;
6033
- value = [...this.statusValues];
6034
- break;
6035
- default:
6036
- return;
6037
- }
6038
- const isEditing = this._service.isFilterActive(k, opt.key);
6039
- if (isEditing) {
6040
- this._service.updateFilter(k, opt.key, opt, value);
6041
- }
6042
- else {
6043
- this._service.addFilter(k, opt, value);
6044
- }
6045
- this.closeFilterInput();
6046
- this.closeFilterMenu();
6047
- this._emit();
6048
- }
6049
- onEditFilter(filter) {
6050
- const k = this.key();
6051
- if (!k)
6052
- return;
6053
- const cfg = this.serviceConfig();
6054
- const opt = cfg?.filterOptions.find((o) => o.key === filter.key);
6055
- if (!opt)
6056
- return;
6057
- this.activeOption.set(opt);
6058
- switch (filter.type) {
6059
- case 'text':
6060
- this.textValue = filter.value;
6061
- break;
6062
- case 'date': {
6063
- const dv = filter.value;
6064
- this.dateRange = { startDate: dv.startDate ?? '', endDate: dv.endDate ?? '' };
6065
- this.showCustomDate = true;
6066
- break;
6067
- }
6068
- case 'currency': {
6069
- const cv = filter.value;
6070
- if (cv.min !== undefined) {
6071
- this.currencyMode = 'from';
6072
- this.currencyValue = cv.min;
6073
- }
6074
- else if (cv.max !== undefined) {
6075
- this.currencyMode = 'until';
6076
- this.currencyValue = cv.max;
6077
- }
6078
- break;
6079
- }
6080
- case 'status':
6081
- this.statusValues = [...(filter.value ?? [])];
6082
- break;
6083
- }
6084
- const tagEl = document.getElementById(this.getActiveFilterId(filter.key));
6085
- if (tagEl) {
6086
- this.filterInputTarget = tagEl;
6087
- this.isEditingFilter = true;
6088
- this.showFilterInput = true;
6089
- }
6090
- }
6091
- onRemoveFilter(filterKey, event) {
6092
- event.stopPropagation();
6093
- const k = this.key();
6094
- if (!k)
6095
- return;
6096
- this._service.removeFilter(k, filterKey);
6097
- this._emit();
6098
- }
6099
- onClearAll() {
6100
- const k = this.key();
6101
- if (!k)
6102
- return;
6103
- this._service.clearAllFilters(k);
6104
- this._emit();
6105
- }
6106
- onSearchChange(value) {
6107
- const k = this.key();
6108
- if (!k)
6109
- return;
6110
- this._service.setSearchValue(k, value);
6111
- this.searchChange.emit(value);
6112
- this._emit();
6113
- }
6114
- _resetInputState() {
6115
- this.textValue = '';
6116
- this.currencyValue = null;
6117
- this.currencyMode = 'from';
6118
- this.statusValues = [];
6119
- this.dateRange = { startDate: '', endDate: '' };
6120
- }
6121
- _emit() {
6122
- const k = this.key();
6123
- if (!k)
6124
- return;
6125
- const state = this._service.getState(k);
6126
- this.filtersChange.emit({ search: state.search, filters: state.filters });
6127
- }
6128
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6129
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyFilterBarComponent, isStandalone: true, selector: "monkey-filter-bar", inputs: { key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filtersChange: "filtersChange", searchChange: "searchChange" }, host: { properties: { "attr.data-testid": "'monkey-filter-bar'" }, classAttribute: "mecx-filter-bar" }, usesOnChanges: true, ngImport: i0, template: `
6130
- <!-- Top action bar -->
6131
- <div class="filter-bar-top-bar">
6132
- <monkey-form-field class="filter-bar-search-field" size="sm">
6133
- <input
6134
- type="text"
6135
- monkey-input
6136
- [placeholder]="searchPlaceholder()"
6137
- [ngModel]="searchValue()"
6138
- (ngModelChange)="onSearchChange($event)"
6139
- />
6140
- <monkey-prefix>
6141
- <i class="mk-i mk-i-search fs-md"></i>
6142
- </monkey-prefix>
6143
- </monkey-form-field>
6144
-
6145
- <monkey-button
6146
- #addFilterBtn
6147
- type="secondary"
6148
- size="sm"
6149
- (click)="onShowFilterMenu(addFilterBtn)"
6150
- >
6151
- <i class="mk-i mk-i-add-plus fs-md" first></i>
6152
- Adicionar Filtro
6153
- </monkey-button>
6154
-
6155
- <div class="filter-bar-extra-actions">
6156
- <ng-content></ng-content>
6157
- </div>
6158
- </div>
6159
-
6160
- <!-- Filter options popover -->
6161
- <ng-template
6162
- [monkeyPopover]="showFilterMenu"
6163
- [monkeyPopoverTarget]="filterMenuTarget"
6164
- [monkeyPopoverClosed]="closeFilterMenu"
6165
- monkeyPopoverDir="ltr"
6166
- [monkeyPopoverHideHeader]="true"
6167
- >
6168
- @for (
6169
- option of availableFilterOptions();
6170
- track option.key;
6171
- let i = $index;
6172
- let first = $first;
6173
- let last = $last
6174
- ) {
6175
- <div
6176
- [id]="getOptionId(option.key)"
6177
- class="filter-bar-option-item"
6178
- [class.first]="first"
6179
- [class.disabled]="isFilterActive(option.key)"
6180
- (click)="onSelectOption(option)"
6181
- >
6182
- @if (option.icon) {
6183
- <i [class]="'mk-i mk-i-' + option.icon + ' fs-md'"></i>
6184
- }
6185
- <span>{{ option.label }}</span>
6186
- @if (isFilterActive(option.key)) {
6187
- <i class="mk-i mk-i-check fs-sm filter-bar-active-check"></i>
6188
- }
6189
- </div>
6190
- @if (!last && availableFilterOptions()[i + 1]?.type !== option.type) {
6191
- <monkey-divider />
6192
- }
6193
- }
6194
- </ng-template>
6195
-
6196
- <!-- Date quick-pick submenu popover -->
6197
- <ng-template
6198
- [monkeyPopover]="showDateSubmenu"
6199
- [monkeyPopoverTarget]="dateSubmenuTarget"
6200
- [monkeyPopoverClosed]="closeDateSubmenu"
6201
- monkeyPopoverDir="rt"
6202
- [monkeyPopoverHideHeader]="true"
6203
- >
6204
- <div class="filter-bar-filter-panel">
6205
- <div class="filter-bar-filter-header">
6206
- @if (activeOption()?.icon) {
6207
- <i [class]="'mk-i mk-i-' + activeOption()!.icon + ' fs-md'"></i>
6208
- }
6209
- <span>{{ activeOption()?.label }}</span>
6210
- </div>
6211
-
6212
- <div class="filter-bar-option-item first" (click)="onQuickDate('1-week-after')">
6213
- 1 semana a partir de hoje
6214
- </div>
6215
- <div class="filter-bar-option-item" (click)="onQuickDate('1-month-after')">
6216
- 1 mês a partir de hoje
6217
- </div>
6218
- <div class="filter-bar-option-item" (click)="onQuickDate('3-months-after')">
6219
- 3 meses a partir de hoje
6220
- </div>
6221
- <div class="filter-bar-option-item" (click)="onQuickDate('1-week-before')">
6222
- 1 semana antes de hoje
6223
- </div>
6224
- <div class="filter-bar-option-item" (click)="onQuickDate('1-month-before')">
6225
- 1 mês antes de hoje
6226
- </div>
6227
- <div class="filter-bar-option-item" (click)="onQuickDate('3-months-before')">
6228
- 3 meses antes de hoje
6229
- </div>
6230
- <div class="filter-bar-option-item" (click)="onQuickDate('custom')">Personalizado</div>
6231
- </div>
6232
- </ng-template>
6233
-
6234
- <!-- Filter input popover (text / date / currency / status) -->
6235
- <ng-template
6236
- [monkeyPopover]="showFilterInput"
6237
- [monkeyPopoverTarget]="filterInputTarget"
6238
- [monkeyPopoverClosed]="closeFilterInput"
6239
- [monkeyPopoverDir]="isEditingFilter ? 'ltr' : 'rt'"
6240
- [monkeyPopoverHideHeader]="true"
6241
- >
6242
- <div class="filter-bar-filter-panel">
6243
- <div class="filter-bar-filter-header">
6244
- @if (activeOption()?.icon) {
6245
- <i [class]="'mk-i mk-i-' + activeOption()!.icon + ' fs-md'"></i>
6246
- }
6247
- <span>{{ activeOption()?.label }}</span>
6248
- </div>
6249
-
6250
- @if (activeOption(); as opt) {
6251
- @if (opt.type === 'text') {
6252
- <div class="filter-bar-filter-body">
6253
- <monkey-form-field size="sm">
6254
- <input
6255
- type="text"
6256
- monkey-input
6257
- [placeholder]="opt.placeholder || 'Digite o valor'"
6258
- [(ngModel)]="textValue"
6259
- (keyup.enter)="onApply()"
6260
- />
6261
- </monkey-form-field>
6262
- </div>
6263
- }
6264
-
6265
- @if (opt.type === 'date' && showCustomDate) {
6266
- <monkey-date-range
6267
- [startDate]="dateRange.startDate"
6268
- [endDate]="dateRange.endDate"
6269
- (onDate)="onDateChange($event)"
6270
- ></monkey-date-range>
6271
- }
6272
-
6273
- @if (opt.type === 'currency') {
6274
- <div class="filter-bar-currency-body">
6275
- <monkey-radiobutton [(ngModel)]="currencyMode" position="vertical" size="sm">
6276
- <monkey-option [value]="'from'">De</monkey-option>
6277
- <monkey-option [value]="'until'">Até</monkey-option>
6278
- </monkey-radiobutton>
6279
- <monkey-form-field size="sm">
6280
- <input
6281
- type="text"
6282
- monkey-input-currency
6283
- [placeholder]="currencyMode === 'from' ? 'Valor mínimo' : 'Valor máximo'"
6284
- [(ngModel)]="currencyValue"
6285
- (keyup.enter)="onApply()"
6286
- />
6287
- </monkey-form-field>
6288
- </div>
6289
- }
6290
-
6291
- @if (opt.type === 'status' && opt.statusOptions) {
6292
- <div class="filter-bar-status-body">
6293
- @for (s of opt.statusOptions; track s.value) {
6294
- <monkey-checkbox
6295
- [value]="statusValues.includes(s.value)"
6296
- (onChange)="onStatusChange(s.value, $event)"
6297
- size="sm"
6298
- >
6299
- {{ s.description }}
6300
- </monkey-checkbox>
6301
- }
6302
- </div>
6303
- }
6304
-
6305
- @if (opt.type !== 'date') {
6306
- <div class="filter-bar-filter-actions">
6307
- <monkey-button size="sm" type="secondary" (click)="closeFilterInput()">
6308
- Cancelar
6309
- </monkey-button>
6310
- <monkey-button size="sm" type="primary" (click)="onApply()">
6311
- Aplicar
6312
- </monkey-button>
6313
- </div>
6314
- }
6315
- }
6316
- </div>
6317
- </ng-template>
6318
-
6319
- <!-- Active filters row -->
6320
- @if (activeFilters().length > 0) {
6321
- <div class="filter-bar-active-bar">
6322
- <monkey-icon-button
6323
- type="secondary"
6324
- size="sm"
6325
- icon="trash"
6326
- (click)="onClearAll()"
6327
- ></monkey-icon-button>
6328
-
6329
- <div class="filter-bar-active-scroll">
6330
- @for (f of activeFilters(); track f.key) {
6331
- <div
6332
- class="filter-bar-filter-tag"
6333
- [id]="getActiveFilterId(f.key)"
6334
- (click)="onEditFilter(f)"
6335
- >
6336
- @if (f.icon) {
6337
- <i [class]="'mk-i mk-i-' + f.icon + ' fs-sm'"></i>
6338
- }
6339
- <span class="filter-bar-tag-label">{{ f.label }}:</span>
6340
- <span class="filter-bar-tag-value">{{ f.displayText }}</span>
6341
- <div class="filter-bar-tag-remove">
6342
- <monkey-icon-button
6343
- type="tertiary"
6344
- color="error"
6345
- size="sm"
6346
- icon="close"
6347
- (click)="onRemoveFilter(f.key, $event)"
6348
- ></monkey-icon-button>
6349
- </div>
6350
- </div>
6351
- }
6352
- </div>
6353
- </div>
6354
- }
6355
- `, isInline: true, styles: [":host{width:100%;display:flex;flex-direction:column}:host .filter-bar-top-bar{display:flex;gap:8px;width:100%}:host .filter-bar-top-bar monkey-button{flex-shrink:0;max-height:32px}:host .filter-bar-top-bar .filter-bar-search-field{flex:1;min-width:0;max-width:400px;display:unset}:host .filter-bar-top-bar .filter-bar-extra-actions{margin-left:auto}:host .filter-bar-active-bar{display:flex;align-items:center;gap:8px;width:100%;overflow:hidden}:host .filter-bar-active-bar monkey-icon-button{flex-shrink:0}:host .filter-bar-active-bar .filter-bar-active-scroll{display:flex;align-items:center;gap:8px;flex:1;min-width:0;overflow:auto hidden;scrollbar-width:thin;scrollbar-color:var(--mecx-color-gray-300) transparent}:host .filter-bar-active-bar .filter-bar-active-scroll::-webkit-scrollbar{height:4px}:host .filter-bar-active-bar .filter-bar-active-scroll::-webkit-scrollbar-track{background:transparent}:host .filter-bar-active-bar .filter-bar-active-scroll::-webkit-scrollbar-thumb{background:var(--mecx-color-gray-300);border-radius:2px}:host .filter-bar-active-bar .filter-bar-active-scroll .filter-bar-filter-tag{display:inline-flex;align-items:center;gap:6px;padding:0 0 0 10px;background:var(--mecx-color-gray-100);border-radius:8px;white-space:nowrap;flex-shrink:0;cursor:pointer;transition:background-color .2s ease;height:32px}:host .filter-bar-active-bar .filter-bar-active-scroll .filter-bar-filter-tag:hover{background:var(--mecx-color-gray-200)}:host .filter-bar-active-bar .filter-bar-active-scroll .filter-bar-filter-tag i{color:var(--mecx-color-gray-600);flex-shrink:0}:host .filter-bar-active-bar .filter-bar-active-scroll .filter-bar-filter-tag .filter-bar-tag-label{font-size:13px;font-weight:600;color:var(--mecx-color-gray-700);flex-shrink:0}:host .filter-bar-active-bar .filter-bar-active-scroll .filter-bar-filter-tag .filter-bar-tag-value{font-size:13px;color:var(--mecx-color-gray-900);max-width:180px;overflow:hidden;text-overflow:ellipsis}:host .filter-bar-active-bar .filter-bar-active-scroll .filter-bar-filter-tag .filter-bar-tag-remove{border-left:1px solid var(--mecx-color-gray-300);display:flex;align-items:center;height:100%}.filter-bar-option-item{cursor:pointer;display:flex;align-items:center;gap:8px;padding:8px 16px;color:var(--mecx-color-gray-900);font-size:14px;font-weight:400;line-height:24px;letter-spacing:.14px;-webkit-user-select:none;user-select:none}.filter-bar-option-item.first{border-top-left-radius:6px;border-top-right-radius:6px}.filter-bar-option-item:hover:not(.disabled){background-color:var(--mecx-color-gray-100)}.filter-bar-option-item.disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.filter-bar-option-item .filter-bar-active-check{margin-left:auto;color:var(--mecx-color-primary-500, var(--mecx-color-gray-700))}.filter-bar-filter-panel{display:flex;flex-direction:column;min-width:260px}.filter-bar-filter-panel .filter-bar-filter-header{display:flex;align-items:center;gap:6px;padding:8px 12px;border-bottom:1px solid var(--mecx-color-gray-200);font-size:14px;font-weight:600;line-height:24px;letter-spacing:.14px;color:var(--mecx-color-gray-700)}.filter-bar-filter-panel .filter-bar-filter-body{padding:8px 12px}.filter-bar-filter-panel .filter-bar-currency-body{display:flex;flex-direction:column;gap:8px;padding:8px 12px}.filter-bar-filter-panel .filter-bar-status-body{display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:10px;padding:12px 16px}.filter-bar-filter-panel monkey-date-range{border:unset;border-radius:unset}.filter-bar-filter-panel .filter-bar-filter-actions{display:flex;justify-content:space-between;gap:8px;padding:8px 12px;border-top:1px solid var(--mecx-color-gray-200)}.mk-i{display:flex}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MonkeyFormFieldModule }, { kind: "component", type: MonkeyFormFieldComponent, selector: "monkey-form-field", inputs: ["id", "hideAction", "enableClear", "size", "noFooterSpace", "displayOnly"], outputs: ["onDisplayOnlyChange"], exportAs: ["monkeyFormField"] }, { kind: "ngmodule", type: MonkeyInputModule }, { kind: "directive", type: MonkeyInputDirective, selector: "input[monkey-input],textarea[monkey-input]", inputs: ["name", "disabled", "id", "required", "type", "min", "max", "percent"], exportAs: ["monkeyInput"] }, { kind: "directive", type: MonkeyInputCurrencyDirective, selector: "input[monkey-input-currency]", inputs: ["name", "disabled", "id", "required", "type"], exportAs: ["monkeyInput"] }, { kind: "component", type: MonkeyButtonComponent, selector: "monkey-button", inputs: ["disabled", "color", "size", "type", "loading", "id"] }, { kind: "component", type: MonkeyOptionComponent, selector: "monkey-option", inputs: ["value", "disabled", "type", "selected"] }, { kind: "directive", type: MonkeyPopoverDirective, selector: "[monkeyPopover]", inputs: ["monkeyPopover", "monkeyPopoverClosed", "monkeyPopoverTarget", "monkeyPopoverMinwidth", "monkeyPopoverBackdrop", "monkeyPopoverWatch", "monkeyPopoverDir", "monkeyPopoverContextmenu", "monkeyPopoverHeight", "monkeyPopoverTitle", "monkeyPopoverActions", "monkeyPopoverHideClose", "monkeyPopoverHideHeader", "monkeyPopoverHideActions", "monkeyPopoverEnableAutofocus"] }, { kind: "component", type: MonkeyDateRangeComponent, selector: "monkey-date-range", inputs: ["startDate", "endDate", "hideQuickAction", "hideHeader", "hideActions", "hideSecondCalendar", "allowFastActionOnHeader", "minDate", "maxDate", "id"], outputs: ["onCancel", "onDate"] }, { kind: "component", type: MonkeyDividerComponent, selector: "monkey-divider", inputs: ["size", "vertical", "id"] }, { kind: "component", type: MonkeyRadioButtonComponent, selector: "monkey-radiobutton", inputs: ["tabIndex", "position", "size", "disabled", "required", "value"], outputs: ["onChange", "onSearch"] }, { kind: "component", type: MonkeyIconButtonComponent, selector: "monkey-icon-button", inputs: ["type", "size", "disabled", "icon", "loading", "color", "id"] }, { kind: "directive", type: MonkeyPrefixDirective, selector: "monkey-prefix" }, { kind: "component", type: MonkeyCheckboxComponent, selector: "monkey-checkbox", inputs: ["disabled", "indeterminate", "required", "showFooter", "size", "value"], outputs: ["onChange"] }] }); }
6356
- }
6357
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterBarComponent, decorators: [{
6358
- type: Component,
6359
- args: [{ selector: 'monkey-filter-bar', imports: [
6360
- CommonModule,
6361
- FormsModule,
6362
- ReactiveFormsModule,
6363
- MonkeyFormFieldModule,
6364
- MonkeyInputModule,
6365
- MonkeyButtonComponent,
6366
- MonkeyOptionComponent,
6367
- MonkeyPopoverDirective,
6368
- MonkeyDateRangeComponent,
6369
- MonkeyBadgeComponent,
6370
- MonkeyLabelDirective,
6371
- MonkeyDividerComponent,
6372
- MonkeyRadioButtonComponent,
6373
- MonkeyIconButtonComponent,
6374
- MonkeyPrefixDirective,
6375
- MonkeyCheckboxComponent
6376
- ], template: `
6377
- <!-- Top action bar -->
6378
- <div class="filter-bar-top-bar">
6379
- <monkey-form-field class="filter-bar-search-field" size="sm">
6380
- <input
6381
- type="text"
6382
- monkey-input
6383
- [placeholder]="searchPlaceholder()"
6384
- [ngModel]="searchValue()"
6385
- (ngModelChange)="onSearchChange($event)"
6386
- />
6387
- <monkey-prefix>
6388
- <i class="mk-i mk-i-search fs-md"></i>
6389
- </monkey-prefix>
6390
- </monkey-form-field>
6391
-
6392
- <monkey-button
6393
- #addFilterBtn
6394
- type="secondary"
6395
- size="sm"
6396
- (click)="onShowFilterMenu(addFilterBtn)"
6397
- >
6398
- <i class="mk-i mk-i-add-plus fs-md" first></i>
6399
- Adicionar Filtro
6400
- </monkey-button>
6401
-
6402
- <div class="filter-bar-extra-actions">
6403
- <ng-content></ng-content>
6404
- </div>
6405
- </div>
6406
-
6407
- <!-- Filter options popover -->
6408
- <ng-template
6409
- [monkeyPopover]="showFilterMenu"
6410
- [monkeyPopoverTarget]="filterMenuTarget"
6411
- [monkeyPopoverClosed]="closeFilterMenu"
6412
- monkeyPopoverDir="ltr"
6413
- [monkeyPopoverHideHeader]="true"
6414
- >
6415
- @for (
6416
- option of availableFilterOptions();
6417
- track option.key;
6418
- let i = $index;
6419
- let first = $first;
6420
- let last = $last
6421
- ) {
6422
- <div
6423
- [id]="getOptionId(option.key)"
6424
- class="filter-bar-option-item"
6425
- [class.first]="first"
6426
- [class.disabled]="isFilterActive(option.key)"
6427
- (click)="onSelectOption(option)"
6428
- >
6429
- @if (option.icon) {
6430
- <i [class]="'mk-i mk-i-' + option.icon + ' fs-md'"></i>
6431
- }
6432
- <span>{{ option.label }}</span>
6433
- @if (isFilterActive(option.key)) {
6434
- <i class="mk-i mk-i-check fs-sm filter-bar-active-check"></i>
6435
- }
6436
- </div>
6437
- @if (!last && availableFilterOptions()[i + 1]?.type !== option.type) {
6438
- <monkey-divider />
6439
- }
6440
- }
6441
- </ng-template>
6442
-
6443
- <!-- Date quick-pick submenu popover -->
6444
- <ng-template
6445
- [monkeyPopover]="showDateSubmenu"
6446
- [monkeyPopoverTarget]="dateSubmenuTarget"
6447
- [monkeyPopoverClosed]="closeDateSubmenu"
6448
- monkeyPopoverDir="rt"
6449
- [monkeyPopoverHideHeader]="true"
6450
- >
6451
- <div class="filter-bar-filter-panel">
6452
- <div class="filter-bar-filter-header">
6453
- @if (activeOption()?.icon) {
6454
- <i [class]="'mk-i mk-i-' + activeOption()!.icon + ' fs-md'"></i>
6455
- }
6456
- <span>{{ activeOption()?.label }}</span>
6457
- </div>
6458
-
6459
- <div class="filter-bar-option-item first" (click)="onQuickDate('1-week-after')">
6460
- 1 semana a partir de hoje
6461
- </div>
6462
- <div class="filter-bar-option-item" (click)="onQuickDate('1-month-after')">
6463
- 1 mês a partir de hoje
6464
- </div>
6465
- <div class="filter-bar-option-item" (click)="onQuickDate('3-months-after')">
6466
- 3 meses a partir de hoje
6467
- </div>
6468
- <div class="filter-bar-option-item" (click)="onQuickDate('1-week-before')">
6469
- 1 semana antes de hoje
6470
- </div>
6471
- <div class="filter-bar-option-item" (click)="onQuickDate('1-month-before')">
6472
- 1 mês antes de hoje
6473
- </div>
6474
- <div class="filter-bar-option-item" (click)="onQuickDate('3-months-before')">
6475
- 3 meses antes de hoje
6476
- </div>
6477
- <div class="filter-bar-option-item" (click)="onQuickDate('custom')">Personalizado</div>
6478
- </div>
6479
- </ng-template>
6480
-
6481
- <!-- Filter input popover (text / date / currency / status) -->
6482
- <ng-template
6483
- [monkeyPopover]="showFilterInput"
6484
- [monkeyPopoverTarget]="filterInputTarget"
6485
- [monkeyPopoverClosed]="closeFilterInput"
6486
- [monkeyPopoverDir]="isEditingFilter ? 'ltr' : 'rt'"
6487
- [monkeyPopoverHideHeader]="true"
6488
- >
6489
- <div class="filter-bar-filter-panel">
6490
- <div class="filter-bar-filter-header">
6491
- @if (activeOption()?.icon) {
6492
- <i [class]="'mk-i mk-i-' + activeOption()!.icon + ' fs-md'"></i>
6493
- }
6494
- <span>{{ activeOption()?.label }}</span>
6495
- </div>
6496
-
6497
- @if (activeOption(); as opt) {
6498
- @if (opt.type === 'text') {
6499
- <div class="filter-bar-filter-body">
6500
- <monkey-form-field size="sm">
6501
- <input
6502
- type="text"
6503
- monkey-input
6504
- [placeholder]="opt.placeholder || 'Digite o valor'"
6505
- [(ngModel)]="textValue"
6506
- (keyup.enter)="onApply()"
6507
- />
6508
- </monkey-form-field>
6509
- </div>
6510
- }
6511
-
6512
- @if (opt.type === 'date' && showCustomDate) {
6513
- <monkey-date-range
6514
- [startDate]="dateRange.startDate"
6515
- [endDate]="dateRange.endDate"
6516
- (onDate)="onDateChange($event)"
6517
- ></monkey-date-range>
6518
- }
6519
-
6520
- @if (opt.type === 'currency') {
6521
- <div class="filter-bar-currency-body">
6522
- <monkey-radiobutton [(ngModel)]="currencyMode" position="vertical" size="sm">
6523
- <monkey-option [value]="'from'">De</monkey-option>
6524
- <monkey-option [value]="'until'">Até</monkey-option>
6525
- </monkey-radiobutton>
6526
- <monkey-form-field size="sm">
6527
- <input
6528
- type="text"
6529
- monkey-input-currency
6530
- [placeholder]="currencyMode === 'from' ? 'Valor mínimo' : 'Valor máximo'"
6531
- [(ngModel)]="currencyValue"
6532
- (keyup.enter)="onApply()"
6533
- />
6534
- </monkey-form-field>
6535
- </div>
6536
- }
6537
-
6538
- @if (opt.type === 'status' && opt.statusOptions) {
6539
- <div class="filter-bar-status-body">
6540
- @for (s of opt.statusOptions; track s.value) {
6541
- <monkey-checkbox
6542
- [value]="statusValues.includes(s.value)"
6543
- (onChange)="onStatusChange(s.value, $event)"
6544
- size="sm"
6545
- >
6546
- {{ s.description }}
6547
- </monkey-checkbox>
6548
- }
6549
- </div>
6550
- }
6551
-
6552
- @if (opt.type !== 'date') {
6553
- <div class="filter-bar-filter-actions">
6554
- <monkey-button size="sm" type="secondary" (click)="closeFilterInput()">
6555
- Cancelar
6556
- </monkey-button>
6557
- <monkey-button size="sm" type="primary" (click)="onApply()">
6558
- Aplicar
6559
- </monkey-button>
6560
- </div>
6561
- }
6562
- }
6563
- </div>
6564
- </ng-template>
6565
-
6566
- <!-- Active filters row -->
6567
- @if (activeFilters().length > 0) {
6568
- <div class="filter-bar-active-bar">
6569
- <monkey-icon-button
6570
- type="secondary"
6571
- size="sm"
6572
- icon="trash"
6573
- (click)="onClearAll()"
6574
- ></monkey-icon-button>
6575
-
6576
- <div class="filter-bar-active-scroll">
6577
- @for (f of activeFilters(); track f.key) {
6578
- <div
6579
- class="filter-bar-filter-tag"
6580
- [id]="getActiveFilterId(f.key)"
6581
- (click)="onEditFilter(f)"
6582
- >
6583
- @if (f.icon) {
6584
- <i [class]="'mk-i mk-i-' + f.icon + ' fs-sm'"></i>
6585
- }
6586
- <span class="filter-bar-tag-label">{{ f.label }}:</span>
6587
- <span class="filter-bar-tag-value">{{ f.displayText }}</span>
6588
- <div class="filter-bar-tag-remove">
6589
- <monkey-icon-button
6590
- type="tertiary"
6591
- color="error"
6592
- size="sm"
6593
- icon="close"
6594
- (click)="onRemoveFilter(f.key, $event)"
6595
- ></monkey-icon-button>
6596
- </div>
6597
- </div>
6598
- }
6599
- </div>
6600
- </div>
6601
- }
6602
- `, host: {
6603
- '[attr.data-testid]': "'monkey-filter-bar'",
6604
- class: 'mecx-filter-bar'
6605
- }, styles: [":host{width:100%;display:flex;flex-direction:column}:host .filter-bar-top-bar{display:flex;gap:8px;width:100%}:host .filter-bar-top-bar monkey-button{flex-shrink:0;max-height:32px}:host .filter-bar-top-bar .filter-bar-search-field{flex:1;min-width:0;max-width:400px;display:unset}:host .filter-bar-top-bar .filter-bar-extra-actions{margin-left:auto}:host .filter-bar-active-bar{display:flex;align-items:center;gap:8px;width:100%;overflow:hidden}:host .filter-bar-active-bar monkey-icon-button{flex-shrink:0}:host .filter-bar-active-bar .filter-bar-active-scroll{display:flex;align-items:center;gap:8px;flex:1;min-width:0;overflow:auto hidden;scrollbar-width:thin;scrollbar-color:var(--mecx-color-gray-300) transparent}:host .filter-bar-active-bar .filter-bar-active-scroll::-webkit-scrollbar{height:4px}:host .filter-bar-active-bar .filter-bar-active-scroll::-webkit-scrollbar-track{background:transparent}:host .filter-bar-active-bar .filter-bar-active-scroll::-webkit-scrollbar-thumb{background:var(--mecx-color-gray-300);border-radius:2px}:host .filter-bar-active-bar .filter-bar-active-scroll .filter-bar-filter-tag{display:inline-flex;align-items:center;gap:6px;padding:0 0 0 10px;background:var(--mecx-color-gray-100);border-radius:8px;white-space:nowrap;flex-shrink:0;cursor:pointer;transition:background-color .2s ease;height:32px}:host .filter-bar-active-bar .filter-bar-active-scroll .filter-bar-filter-tag:hover{background:var(--mecx-color-gray-200)}:host .filter-bar-active-bar .filter-bar-active-scroll .filter-bar-filter-tag i{color:var(--mecx-color-gray-600);flex-shrink:0}:host .filter-bar-active-bar .filter-bar-active-scroll .filter-bar-filter-tag .filter-bar-tag-label{font-size:13px;font-weight:600;color:var(--mecx-color-gray-700);flex-shrink:0}:host .filter-bar-active-bar .filter-bar-active-scroll .filter-bar-filter-tag .filter-bar-tag-value{font-size:13px;color:var(--mecx-color-gray-900);max-width:180px;overflow:hidden;text-overflow:ellipsis}:host .filter-bar-active-bar .filter-bar-active-scroll .filter-bar-filter-tag .filter-bar-tag-remove{border-left:1px solid var(--mecx-color-gray-300);display:flex;align-items:center;height:100%}.filter-bar-option-item{cursor:pointer;display:flex;align-items:center;gap:8px;padding:8px 16px;color:var(--mecx-color-gray-900);font-size:14px;font-weight:400;line-height:24px;letter-spacing:.14px;-webkit-user-select:none;user-select:none}.filter-bar-option-item.first{border-top-left-radius:6px;border-top-right-radius:6px}.filter-bar-option-item:hover:not(.disabled){background-color:var(--mecx-color-gray-100)}.filter-bar-option-item.disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.filter-bar-option-item .filter-bar-active-check{margin-left:auto;color:var(--mecx-color-primary-500, var(--mecx-color-gray-700))}.filter-bar-filter-panel{display:flex;flex-direction:column;min-width:260px}.filter-bar-filter-panel .filter-bar-filter-header{display:flex;align-items:center;gap:6px;padding:8px 12px;border-bottom:1px solid var(--mecx-color-gray-200);font-size:14px;font-weight:600;line-height:24px;letter-spacing:.14px;color:var(--mecx-color-gray-700)}.filter-bar-filter-panel .filter-bar-filter-body{padding:8px 12px}.filter-bar-filter-panel .filter-bar-currency-body{display:flex;flex-direction:column;gap:8px;padding:8px 12px}.filter-bar-filter-panel .filter-bar-status-body{display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:10px;padding:12px 16px}.filter-bar-filter-panel monkey-date-range{border:unset;border-radius:unset}.filter-bar-filter-panel .filter-bar-filter-actions{display:flex;justify-content:space-between;gap:8px;padding:8px 12px;border-top:1px solid var(--mecx-color-gray-200)}.mk-i{display:flex}\n"] }]
6606
- }], ctorParameters: () => [], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], filtersChange: [{
6607
- type: Output
6608
- }], searchChange: [{
6609
- type: Output
6610
- }] } });
6611
-
6612
- /** ************************
6613
- * Copyright Monkey Exchange. All Rights Reserved
6614
- * This style guide was developed by Monkey Exchange Team
6615
- * MIT Licence
6616
- ************************* */
6617
-
6618
- /** ************************
6619
- * Copyright Monkey Exchange. All Rights Reserved
6620
- * This style guide was developed by Monkey Exchange Team
6621
- * MIT Licence
6622
- ************************* */
6623
-
6624
- /** ************************
6625
- * Copyright Monkey Exchange. All Rights Reserved
6626
- * This style guide was developed by Monkey Exchange Team
6627
- * MIT Licence
6628
- ************************* */
6629
- /**
6630
- * Shortest the thumb may get, in px — matches the `--mecx-spaces-medium`
6631
- * floor in the stylesheet. A very long list would otherwise give a 2px thumb,
6632
- * too small to grab.
6633
- */
6634
- const MIN_THUMB = 24;
6635
- /**
6636
- * A DRAWN scrollbar, not the native one styled — a native scrollbar can't
6637
- * live outside the element that scrolls (e.g. below a table's rows, next to
6638
- * its footer), and cross-browser track styling (radius, border) is
6639
- * inconsistent enough that matching a design exactly isn't reliable with
6640
- * `::-webkit-scrollbar`/`scrollbar-color` alone.
6641
- *
6642
- * It does NOT replace real scrolling: `target` keeps its own
6643
- * `overflow: auto`, so keyboard, wheel and trackpad scrolling all keep
6644
- * working — this is a draggable mirror drawn on top. That's also why it's
6645
- * `aria-hidden`: a screen reader user scrolls the real region, and a second
6646
- * widget announcing the same position would only add noise.
6647
- */
6648
- class MonkeyScrollbarComponent {
5859
+ /**
5860
+ * Shortest the thumb may get, in px — matches the `--mecx-spaces-medium`
5861
+ * floor in the stylesheet. A very long list would otherwise give a 2px thumb,
5862
+ * too small to grab.
5863
+ */
5864
+ const MIN_THUMB = 24;
5865
+ /**
5866
+ * A DRAWN scrollbar, not the native one styled — a native scrollbar can't
5867
+ * live outside the element that scrolls (e.g. below a table's rows, next to
5868
+ * its footer), and cross-browser track styling (radius, border) is
5869
+ * inconsistent enough that matching a design exactly isn't reliable with
5870
+ * `::-webkit-scrollbar`/`scrollbar-color` alone.
5871
+ *
5872
+ * It does NOT replace real scrolling: `target` keeps its own
5873
+ * `overflow: auto`, so keyboard, wheel and trackpad scrolling all keep
5874
+ * working this is a draggable mirror drawn on top. That's also why it's
5875
+ * `aria-hidden`: a screen reader user scrolls the real region, and a second
5876
+ * widget announcing the same position would only add noise.
5877
+ */
5878
+ class MonkeyScrollbarComponent {
6649
5879
  constructor() {
6650
5880
  this._zone = inject(NgZone);
6651
5881
  this.orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
@@ -6857,80 +6087,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
6857
6087
  * This style guide was developed by Monkey Exchange Team
6858
6088
  * MIT Licence
6859
6089
  ************************* */
6860
- /**
6861
- * The segmented row that replaces the trigger once the user has picked a
6862
- * filter. Two segments and a bin:
6863
- *
6864
- * [ icon Data de Emissão | 01/01/2025 - 31/01/2025 | 🗑 ]
6865
- * category value action
6866
- *
6867
- * How many segments there are is the consumer's decision — the value segment
6868
- * is projected as soon as there is something to answer:
6869
- *
6870
- * <monkey-filter-chip (remove)="drop()">
6871
- * <monkey-filter-segment icon="calendar-box" text="Data" readonlySegment />
6872
- * <monkey-filter-segment placeholder="Selecione" [(open)]="open" />
6873
- * </monkey-filter-chip>
6874
- *
6875
- * The chip carries NO `overflow: hidden`. It would clip the panels the
6876
- * segments open right below themselves; the ends are rounded by radius, not by
6877
- * clipping.
6878
- */
6879
6090
  class MonkeyFilterChipComponent {
6880
6091
  constructor() {
6881
- /** Icon font name of the remove action, without the `mk-i-` prefix. */
6882
6092
  this.removeIcon = input('trash', ...(ngDevMode ? [{ debugName: "removeIcon" }] : /* istanbul ignore next */ []));
6883
- this.removeLabel = input('Remover filtro', ...(ngDevMode ? [{ debugName: "removeLabel" }] : /* istanbul ignore next */ []));
6884
- this.remove = output();
6093
+ this.removeLabel = input('', ...(ngDevMode ? [{ debugName: "removeLabel" }] : /* istanbul ignore next */ []));
6094
+ this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
6095
+ this.onRemove = output();
6885
6096
  }
6886
6097
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterChipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6887
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: MonkeyFilterChipComponent, isStandalone: true, selector: "monkey-filter-chip", inputs: { removeIcon: { classPropertyName: "removeIcon", publicName: "removeIcon", isSignal: true, isRequired: false, transformFunction: null }, removeLabel: { classPropertyName: "removeLabel", publicName: "removeLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { remove: "remove" }, host: { attributes: { "data-testid": "monkey-filter-chip" }, classAttribute: "mecx-filter-chip" }, ngImport: i0, template: "<ng-content></ng-content>\n\n<!-- 2px of room around a 24px button = 28px, the same height as the segments.\n The numbers add up on their own, with nothing to compensate for. -->\n<span class=\"mecx-filter-chip-action\">\n <button\n class=\"mecx-filter-chip-remove\"\n type=\"button\"\n [attr.aria-label]=\"removeLabel()\"\n (click)=\"remove.emit()\"\n >\n <i class=\"mk-i mk-i-{{ removeIcon() }}\" aria-hidden=\"true\"></i>\n </button>\n</span>\n", styles: ["@charset \"UTF-8\";.mecx-filter-chip{--mecx-fbv2-duration-state: .15s;--mecx-fbv2-duration-enter: .2s;--mecx-fbv2-duration-exit: .15s;--mecx-fbv2-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-fbv2-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-fbv2-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-fbv2-scale-unfold: .94;--mecx-fbv2-travel-anchored: 4px;--mecx-fbv2-travel-slide: 16px;--mecx-fbv2-stagger: 25ms;--mecx-fbv2-control-height: 28px;--mecx-fbv2-pointer-target: 40px;--mecx-fbv2-radius: 8px;--mecx-fbv2-radius-item: 4px;--mecx-fbv2-fade-width: 48px}@media(prefers-reduced-motion:reduce){.mecx-filter-chip{--mecx-fbv2-duration-state: 1ms;--mecx-fbv2-duration-enter: 1ms;--mecx-fbv2-duration-exit: 1ms;--mecx-fbv2-scale-unfold: 1;--mecx-fbv2-travel-anchored: 0px;--mecx-fbv2-travel-slide: 0px;--mecx-fbv2-stagger: 0ms}}.mecx-filter-chip{display:inline-flex;align-items:center}.mecx-filter-chip>monkey-filter-segment:first-child .mecx-filter-segment-btn{border-top-left-radius:var(--mecx-fbv2-radius);border-bottom-left-radius:var(--mecx-fbv2-radius)}.mecx-filter-chip-action{display:inline-flex;align-items:center;height:var(--mecx-fbv2-control-height);padding:2px;box-sizing:border-box;background:var(--mecx-color-gray-50);border:1px solid var(--mecx-color-gray-500);border-top-right-radius:var(--mecx-fbv2-radius);border-bottom-right-radius:var(--mecx-fbv2-radius)}.mecx-filter-chip-remove{position:relative;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;background:transparent;border:none;border-radius:var(--mecx-fbv2-radius-item);color:var(--mecx-color-gray-700);cursor:pointer;outline:none;transition:background-color var(--mecx-fbv2-duration-state) var(--mecx-fbv2-ease-state)}.mecx-filter-chip-remove:after{content:\"\";position:absolute;inset:-6px -6px -6px 0}.mecx-filter-chip-remove .mk-i{display:flex;font-size:16px}.mecx-filter-chip-remove:hover{background-color:var(--mecx-color-gray-200);color:var(--mecx-color-error-main)}.mecx-filter-chip-remove:active{background-color:var(--mecx-color-gray-400)}.mecx-filter-chip-remove:focus-visible{outline:2px solid var(--mecx-color-gray-900);outline-offset:-2px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
6098
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: MonkeyFilterChipComponent, isStandalone: true, selector: "monkey-filter-chip", inputs: { removeIcon: { classPropertyName: "removeIcon", publicName: "removeIcon", isSignal: true, isRequired: false, transformFunction: null }, removeLabel: { classPropertyName: "removeLabel", publicName: "removeLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onRemove: "onRemove" }, host: { attributes: { "data-testid": "monkey-filter-chip" }, properties: { "class.mecx-filter-chip--disabled": "disabled()" }, classAttribute: "mecx-filter-chip" }, ngImport: i0, template: "<ng-content></ng-content>\n<span class=\"mecx-filter-chip-action\">\n <button\n class=\"mecx-filter-chip-remove\"\n type=\"button\"\n [disabled]=\"disabled() || null\"\n [attr.aria-label]=\"removeLabel()\"\n (click)=\"onRemove.emit()\"\n >\n <i class=\"mk-i mk-i-{{ removeIcon() }}\" aria-hidden=\"true\"></i>\n </button>\n</span>\n", styles: [".mecx-filter-chip{--mecx-filter-bar-duration-state: .15s;--mecx-filter-bar-duration-enter: .2s;--mecx-filter-bar-duration-exit: .15s;--mecx-filter-bar-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-filter-bar-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-filter-bar-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-filter-bar-scale-unfold: .94;--mecx-filter-bar-travel-anchored: 4px;--mecx-filter-bar-travel-slide: 16px;--mecx-filter-bar-stagger: 25ms;--mecx-filter-bar-control-height: 32px;--mecx-filter-bar-pointer-target: 40px;--mecx-filter-bar-reach: calc((var(--mecx-filter-bar-control-height) - var(--mecx-filter-bar-pointer-target)) / 2);--mecx-filter-bar-radius: 8px;--mecx-filter-bar-radius-item: 4px;--mecx-filter-bar-fade-width: 48px;--mecx-filter-bar-focus-reach: 4px;--mecx-filter-bar-z-raised: 1;--mecx-filter-bar-z-sticky: 2;--mecx-filter-bar-z-menu: 1000}@media(prefers-reduced-motion:reduce){.mecx-filter-chip{--mecx-filter-bar-duration-state: 1ms;--mecx-filter-bar-duration-enter: 1ms;--mecx-filter-bar-duration-exit: 1ms;--mecx-filter-bar-scale-unfold: 1;--mecx-filter-bar-travel-anchored: 0px;--mecx-filter-bar-travel-slide: 0px;--mecx-filter-bar-stagger: 0ms}}.mecx-filter-chip{display:inline-flex;align-items:center}.mecx-filter-chip>monkey-filter-segment:first-child .mecx-filter-segment-btn{border-top-left-radius:var(--mecx-filter-bar-radius);border-bottom-left-radius:var(--mecx-filter-bar-radius)}.mecx-filter-chip-action{display:inline-flex;align-items:center;height:var(--mecx-filter-bar-control-height);padding:2px;box-sizing:border-box;background:var(--mecx-color-gray-50);border:1px solid var(--mecx-color-gray-500);border-top-right-radius:var(--mecx-filter-bar-radius);border-bottom-right-radius:var(--mecx-filter-bar-radius)}.mecx-filter-chip--disabled .mecx-filter-chip-action{border-color:var(--mecx-color-gray-400)}.mecx-filter-chip-remove{--mecx-filter-bar-bin: 24px;--mecx-filter-bar-bin-reach: calc((var(--mecx-filter-bar-bin) - var(--mecx-filter-bar-pointer-target)) / 2);position:relative;display:inline-flex;align-items:center;justify-content:center;width:var(--mecx-filter-bar-bin);height:var(--mecx-filter-bar-bin);padding:0;background:transparent;border:none;border-radius:var(--mecx-filter-bar-radius-item);color:var(--mecx-color-gray-700);cursor:pointer;outline:none;transition:background-color var(--mecx-filter-bar-duration-state) var(--mecx-filter-bar-ease-state)}.mecx-filter-chip-remove:after{content:\"\";position:absolute;inset:var(--mecx-filter-bar-bin-reach) var(--mecx-filter-bar-bin-reach) var(--mecx-filter-bar-bin-reach) 0}.mecx-filter-chip-remove .mk-i{display:flex;font-size:16px}.mecx-filter-chip-remove:hover{background-color:var(--mecx-color-gray-200);color:var(--mecx-color-error-main)}.mecx-filter-chip-remove:active{background-color:var(--mecx-color-gray-400)}.mecx-filter-chip-remove:focus-visible{outline:2px solid var(--mecx-color-gray-900);outline-offset:-2px}.mecx-filter-chip-remove:disabled{background-color:transparent;color:var(--mecx-color-gray-400);cursor:not-allowed}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
6888
6099
  }
6889
6100
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterChipComponent, decorators: [{
6890
6101
  type: Component,
6891
6102
  args: [{ selector: 'monkey-filter-chip', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
6892
6103
  'data-testid': 'monkey-filter-chip',
6893
- class: 'mecx-filter-chip'
6894
- }, template: "<ng-content></ng-content>\n\n<!-- 2px of room around a 24px button = 28px, the same height as the segments.\n The numbers add up on their own, with nothing to compensate for. -->\n<span class=\"mecx-filter-chip-action\">\n <button\n class=\"mecx-filter-chip-remove\"\n type=\"button\"\n [attr.aria-label]=\"removeLabel()\"\n (click)=\"remove.emit()\"\n >\n <i class=\"mk-i mk-i-{{ removeIcon() }}\" aria-hidden=\"true\"></i>\n </button>\n</span>\n", styles: ["@charset \"UTF-8\";.mecx-filter-chip{--mecx-fbv2-duration-state: .15s;--mecx-fbv2-duration-enter: .2s;--mecx-fbv2-duration-exit: .15s;--mecx-fbv2-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-fbv2-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-fbv2-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-fbv2-scale-unfold: .94;--mecx-fbv2-travel-anchored: 4px;--mecx-fbv2-travel-slide: 16px;--mecx-fbv2-stagger: 25ms;--mecx-fbv2-control-height: 28px;--mecx-fbv2-pointer-target: 40px;--mecx-fbv2-radius: 8px;--mecx-fbv2-radius-item: 4px;--mecx-fbv2-fade-width: 48px}@media(prefers-reduced-motion:reduce){.mecx-filter-chip{--mecx-fbv2-duration-state: 1ms;--mecx-fbv2-duration-enter: 1ms;--mecx-fbv2-duration-exit: 1ms;--mecx-fbv2-scale-unfold: 1;--mecx-fbv2-travel-anchored: 0px;--mecx-fbv2-travel-slide: 0px;--mecx-fbv2-stagger: 0ms}}.mecx-filter-chip{display:inline-flex;align-items:center}.mecx-filter-chip>monkey-filter-segment:first-child .mecx-filter-segment-btn{border-top-left-radius:var(--mecx-fbv2-radius);border-bottom-left-radius:var(--mecx-fbv2-radius)}.mecx-filter-chip-action{display:inline-flex;align-items:center;height:var(--mecx-fbv2-control-height);padding:2px;box-sizing:border-box;background:var(--mecx-color-gray-50);border:1px solid var(--mecx-color-gray-500);border-top-right-radius:var(--mecx-fbv2-radius);border-bottom-right-radius:var(--mecx-fbv2-radius)}.mecx-filter-chip-remove{position:relative;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;background:transparent;border:none;border-radius:var(--mecx-fbv2-radius-item);color:var(--mecx-color-gray-700);cursor:pointer;outline:none;transition:background-color var(--mecx-fbv2-duration-state) var(--mecx-fbv2-ease-state)}.mecx-filter-chip-remove:after{content:\"\";position:absolute;inset:-6px -6px -6px 0}.mecx-filter-chip-remove .mk-i{display:flex;font-size:16px}.mecx-filter-chip-remove:hover{background-color:var(--mecx-color-gray-200);color:var(--mecx-color-error-main)}.mecx-filter-chip-remove:active{background-color:var(--mecx-color-gray-400)}.mecx-filter-chip-remove:focus-visible{outline:2px solid var(--mecx-color-gray-900);outline-offset:-2px}\n"] }]
6895
- }], propDecorators: { removeIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeIcon", required: false }] }], removeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeLabel", required: false }] }], remove: [{ type: i0.Output, args: ["remove"] }] } });
6104
+ class: 'mecx-filter-chip',
6105
+ '[class.mecx-filter-chip--disabled]': 'disabled()'
6106
+ }, template: "<ng-content></ng-content>\n<span class=\"mecx-filter-chip-action\">\n <button\n class=\"mecx-filter-chip-remove\"\n type=\"button\"\n [disabled]=\"disabled() || null\"\n [attr.aria-label]=\"removeLabel()\"\n (click)=\"onRemove.emit()\"\n >\n <i class=\"mk-i mk-i-{{ removeIcon() }}\" aria-hidden=\"true\"></i>\n </button>\n</span>\n", styles: [".mecx-filter-chip{--mecx-filter-bar-duration-state: .15s;--mecx-filter-bar-duration-enter: .2s;--mecx-filter-bar-duration-exit: .15s;--mecx-filter-bar-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-filter-bar-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-filter-bar-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-filter-bar-scale-unfold: .94;--mecx-filter-bar-travel-anchored: 4px;--mecx-filter-bar-travel-slide: 16px;--mecx-filter-bar-stagger: 25ms;--mecx-filter-bar-control-height: 32px;--mecx-filter-bar-pointer-target: 40px;--mecx-filter-bar-reach: calc((var(--mecx-filter-bar-control-height) - var(--mecx-filter-bar-pointer-target)) / 2);--mecx-filter-bar-radius: 8px;--mecx-filter-bar-radius-item: 4px;--mecx-filter-bar-fade-width: 48px;--mecx-filter-bar-focus-reach: 4px;--mecx-filter-bar-z-raised: 1;--mecx-filter-bar-z-sticky: 2;--mecx-filter-bar-z-menu: 1000}@media(prefers-reduced-motion:reduce){.mecx-filter-chip{--mecx-filter-bar-duration-state: 1ms;--mecx-filter-bar-duration-enter: 1ms;--mecx-filter-bar-duration-exit: 1ms;--mecx-filter-bar-scale-unfold: 1;--mecx-filter-bar-travel-anchored: 0px;--mecx-filter-bar-travel-slide: 0px;--mecx-filter-bar-stagger: 0ms}}.mecx-filter-chip{display:inline-flex;align-items:center}.mecx-filter-chip>monkey-filter-segment:first-child .mecx-filter-segment-btn{border-top-left-radius:var(--mecx-filter-bar-radius);border-bottom-left-radius:var(--mecx-filter-bar-radius)}.mecx-filter-chip-action{display:inline-flex;align-items:center;height:var(--mecx-filter-bar-control-height);padding:2px;box-sizing:border-box;background:var(--mecx-color-gray-50);border:1px solid var(--mecx-color-gray-500);border-top-right-radius:var(--mecx-filter-bar-radius);border-bottom-right-radius:var(--mecx-filter-bar-radius)}.mecx-filter-chip--disabled .mecx-filter-chip-action{border-color:var(--mecx-color-gray-400)}.mecx-filter-chip-remove{--mecx-filter-bar-bin: 24px;--mecx-filter-bar-bin-reach: calc((var(--mecx-filter-bar-bin) - var(--mecx-filter-bar-pointer-target)) / 2);position:relative;display:inline-flex;align-items:center;justify-content:center;width:var(--mecx-filter-bar-bin);height:var(--mecx-filter-bar-bin);padding:0;background:transparent;border:none;border-radius:var(--mecx-filter-bar-radius-item);color:var(--mecx-color-gray-700);cursor:pointer;outline:none;transition:background-color var(--mecx-filter-bar-duration-state) var(--mecx-filter-bar-ease-state)}.mecx-filter-chip-remove:after{content:\"\";position:absolute;inset:var(--mecx-filter-bar-bin-reach) var(--mecx-filter-bar-bin-reach) var(--mecx-filter-bar-bin-reach) 0}.mecx-filter-chip-remove .mk-i{display:flex;font-size:16px}.mecx-filter-chip-remove:hover{background-color:var(--mecx-color-gray-200);color:var(--mecx-color-error-main)}.mecx-filter-chip-remove:active{background-color:var(--mecx-color-gray-400)}.mecx-filter-chip-remove:focus-visible{outline:2px solid var(--mecx-color-gray-900);outline-offset:-2px}.mecx-filter-chip-remove:disabled{background-color:transparent;color:var(--mecx-color-gray-400);cursor:not-allowed}\n"] }]
6107
+ }], propDecorators: { removeIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeIcon", required: false }] }], removeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], onRemove: [{ type: i0.Output, args: ["onRemove"] }] } });
6896
6108
 
6897
6109
  /** ************************
6898
6110
  * Copyright Monkey Exchange. All Rights Reserved
6899
6111
  * This style guide was developed by Monkey Exchange Team
6900
6112
  * MIT Licence
6901
6113
  ************************* */
6902
- /**
6903
- * The panel every dropdown of monkey-filter-bar-v2 opens: a surface with an
6904
- * optional search field on top and the projected rows below it.
6905
- *
6906
- * Only the WIDTH changes from one panel to the next, and it is set from the
6907
- * bar's own stylesheet through a class on this host — the panel component has
6908
- * no opinion on how wide a company list should be.
6909
- *
6910
- * `width` and not `min-width` on those classes: each panel is a fixed-width
6911
- * frame in the design and a long label ellipsizes inside it. With a floor the
6912
- * content would win, and the measurement would turn into a suggestion.
6913
- */
6914
6114
  class MonkeyFilterMenuComponent {
6915
6115
  constructor() {
6116
+ this._zone = inject(NgZone);
6117
+ this._items = viewChild('items', ...(ngDevMode ? [{ debugName: "_items" }] : /* istanbul ignore next */ []));
6118
+ this._overflowing = signal(false, ...(ngDevMode ? [{ debugName: "_overflowing" }] : /* istanbul ignore next */ []));
6916
6119
  this.showSearch = input(false, { ...(ngDevMode ? { debugName: "showSearch" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
6917
- this.searchPlaceholder = input('Buscar', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
6918
- /** Lets the row list scroll instead of growing past the viewport. */
6120
+ this.searchPlaceholder = input('', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
6919
6121
  this.showScroll = input(true, { ...(ngDevMode ? { debugName: "showScroll" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
6920
- /** Ceiling of the scrolling list, in px. */
6921
6122
  this.maxHeight = input(240, ...(ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []));
6922
- this.searchChange = output();
6123
+ this.onSearchChange = output();
6923
6124
  this.searchValue = '';
6924
- this._zone = inject(NgZone);
6925
- this._items = viewChild('items', ...(ngDevMode ? [{ debugName: "_items" }] : /* istanbul ignore next */ []));
6926
- /** Is the list actually overflowing right now? */
6927
- this._overflowing = signal(false, ...(ngDevMode ? [{ debugName: "_overflowing" }] : /* istanbul ignore next */ []));
6928
- /**
6929
- * Draw the track only when the content OVERFLOWS.
6930
- *
6931
- * Tied to `showScroll` alone, a three-row panel lost 12px of width to a
6932
- * track that was never going to appear.
6933
- */
6934
6125
  this.scrolling = computed(() => {
6935
6126
  return this.showScroll() && this._overflowing();
6936
6127
  }, ...(ngDevMode ? [{ debugName: "scrolling" }] : /* istanbul ignore next */ []));
@@ -6938,9 +6129,6 @@ class MonkeyFilterMenuComponent {
6938
6129
  const items = this._items()?.nativeElement;
6939
6130
  if (!items)
6940
6131
  return;
6941
- // Outside the Angular zone: a zone-patched observer costs a global
6942
- // change-detection pass per callback, and the signal written below
6943
- // already schedules one by itself when the value actually changes.
6944
6132
  this._zone.runOutsideAngular(() => {
6945
6133
  this._observer = new ResizeObserver(() => {
6946
6134
  this._overflowing.set(items.scrollHeight - items.clientHeight > 1);
@@ -6951,66 +6139,55 @@ class MonkeyFilterMenuComponent {
6951
6139
  });
6952
6140
  });
6953
6141
  onCleanup(() => {
6954
- return this._disconnect();
6142
+ return this.disconnect();
6955
6143
  });
6956
6144
  });
6957
6145
  }
6146
+ disconnect() {
6147
+ this._observer?.disconnect();
6148
+ this._observer = undefined;
6149
+ }
6958
6150
  ngOnDestroy() {
6959
- this._disconnect();
6151
+ this.disconnect();
6960
6152
  }
6961
6153
  onSearchInput(value) {
6962
6154
  this.searchValue = value;
6963
- this.searchChange.emit(value);
6964
- }
6965
- _disconnect() {
6966
- this._observer?.disconnect();
6967
- this._observer = undefined;
6155
+ this.onSearchChange.emit(value);
6968
6156
  }
6969
6157
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6970
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyFilterMenuComponent, isStandalone: true, selector: "monkey-filter-menu", inputs: { showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, showScroll: { classPropertyName: "showScroll", publicName: "showScroll", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { searchChange: "searchChange" }, host: { attributes: { "data-testid": "monkey-filter-menu" }, classAttribute: "mecx-filter-menu" }, viewQueries: [{ propertyName: "_items", first: true, predicate: ["items"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Search \u2014 optional, no label and no footer -->\n@if (showSearch()) {\n <div class=\"mecx-filter-menu-search\">\n <monkey-form-field size=\"sm\">\n <input\n type=\"text\"\n monkey-input\n [placeholder]=\"searchPlaceholder()\"\n [ngModel]=\"searchValue\"\n (ngModelChange)=\"onSearchInput($event)\"\n />\n <monkey-prefix>\n <i class=\"mk-i mk-i-search fs-md\"></i>\n </monkey-prefix>\n </monkey-form-field>\n </div>\n}\n\n<!-- Projected rows. `--scroll` allows scrolling; `--scrolling` draws the track\n and hands it the right-hand breathing room, and only kicks in once the\n content really overflows \u2014 otherwise the panel reserves 20px for a bar\n that does not exist. -->\n<div\n #items\n class=\"mecx-filter-menu-items\"\n [class.mecx-filter-menu-items--scroll]=\"showScroll()\"\n [class.mecx-filter-menu-items--scrolling]=\"scrolling()\"\n [style.max-height.px]=\"showScroll() ? maxHeight() : null\"\n>\n <ng-content></ng-content>\n</div>\n", styles: ["@charset \"UTF-8\";.mecx-filter-menu{--mecx-fbv2-duration-state: .15s;--mecx-fbv2-duration-enter: .2s;--mecx-fbv2-duration-exit: .15s;--mecx-fbv2-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-fbv2-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-fbv2-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-fbv2-scale-unfold: .94;--mecx-fbv2-travel-anchored: 4px;--mecx-fbv2-travel-slide: 16px;--mecx-fbv2-stagger: 25ms;--mecx-fbv2-control-height: 28px;--mecx-fbv2-pointer-target: 40px;--mecx-fbv2-radius: 8px;--mecx-fbv2-radius-item: 4px;--mecx-fbv2-fade-width: 48px}@media(prefers-reduced-motion:reduce){.mecx-filter-menu{--mecx-fbv2-duration-state: 1ms;--mecx-fbv2-duration-enter: 1ms;--mecx-fbv2-duration-exit: 1ms;--mecx-fbv2-scale-unfold: 1;--mecx-fbv2-travel-anchored: 0px;--mecx-fbv2-travel-slide: 0px;--mecx-fbv2-stagger: 0ms}}.mecx-filter-menu{display:flex;flex-direction:column;min-width:158px;max-width:341px;background:var(--mecx-color-white);border:2px solid var(--mecx-color-gray-200);border-radius:var(--mecx-fbv2-radius);box-shadow:0 8px 12px -4px var(--mecx-color-box-shadow, rgba(47, 50, 55, .08));overflow:hidden;box-sizing:border-box}.mecx-filter-menu-search{padding:8px;border-bottom:2px solid var(--mecx-color-gray-200);flex-shrink:0}.mecx-filter-menu-search monkey-form-field{width:100%;display:block}.mecx-filter-menu-items{display:flex;flex-direction:column;padding:8px}.mecx-filter-menu-items--scroll{overflow-y:auto}.mecx-filter-menu-items--scrolling{scrollbar-gutter:stable;padding-right:0}.mecx-filter-menu-items--scrolling::-webkit-scrollbar{width:20px}.mecx-filter-menu-items--scrolling::-webkit-scrollbar-track{background:var(--mecx-color-gray-100);background-clip:padding-box;border-left:4px solid transparent;border-right:8px solid transparent;border-radius:8px 12px 12px 8px/4px;box-shadow:inset 0 0 0 1px var(--mecx-color-gray-400);margin:8px 0}.mecx-filter-menu-items--scrolling::-webkit-scrollbar-thumb{background:var(--mecx-color-gray-800);background-clip:padding-box;border-left:5px solid transparent;border-right:9px solid transparent;border-radius:8px 12px 12px 8px/3px}.mecx-filter-menu-items>monkey-divider{margin-block:4px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MonkeyFormFieldModule }, { kind: "component", type: MonkeyFormFieldComponent, selector: "monkey-form-field", inputs: ["id", "hideAction", "enableClear", "size", "noFooterSpace", "displayOnly"], outputs: ["onDisplayOnlyChange"], exportAs: ["monkeyFormField"] }, { kind: "ngmodule", type: MonkeyInputModule }, { kind: "directive", type: MonkeyInputDirective, selector: "input[monkey-input],textarea[monkey-input]", inputs: ["name", "disabled", "id", "required", "type", "min", "max", "percent"], exportAs: ["monkeyInput"] }, { kind: "directive", type: MonkeyPrefixDirective, selector: "monkey-prefix" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
6158
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyFilterMenuComponent, isStandalone: true, selector: "monkey-filter-menu", inputs: { showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, showScroll: { classPropertyName: "showScroll", publicName: "showScroll", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSearchChange: "onSearchChange" }, host: { attributes: { "data-testid": "monkey-filter-menu" }, classAttribute: "mecx-filter-menu" }, viewQueries: [{ propertyName: "_items", first: true, predicate: ["items"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (showSearch()) {\n <div class=\"mecx-filter-menu-search\">\n <monkey-form-field size=\"sm\" noFooterSpace>\n <input\n type=\"text\"\n monkey-input\n [placeholder]=\"searchPlaceholder()\"\n [ngModel]=\"searchValue\"\n (ngModelChange)=\"onSearchInput($event)\"\n />\n <monkey-prefix>\n <i class=\"mk-i mk-i-search fs-md\"></i>\n </monkey-prefix>\n </monkey-form-field>\n </div>\n}\n\n<div\n #items\n class=\"mecx-filter-menu-items\"\n [class.mecx-filter-menu-items--scroll]=\"showScroll()\"\n [class.mecx-filter-menu-items--scrolling]=\"scrolling()\"\n [style.max-height.px]=\"showScroll() ? maxHeight() : null\"\n>\n <ng-content></ng-content>\n</div>\n", styles: [".mecx-filter-menu{--mecx-filter-bar-duration-state: .15s;--mecx-filter-bar-duration-enter: .2s;--mecx-filter-bar-duration-exit: .15s;--mecx-filter-bar-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-filter-bar-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-filter-bar-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-filter-bar-scale-unfold: .94;--mecx-filter-bar-travel-anchored: 4px;--mecx-filter-bar-travel-slide: 16px;--mecx-filter-bar-stagger: 25ms;--mecx-filter-bar-control-height: 32px;--mecx-filter-bar-pointer-target: 40px;--mecx-filter-bar-reach: calc((var(--mecx-filter-bar-control-height) - var(--mecx-filter-bar-pointer-target)) / 2);--mecx-filter-bar-radius: 8px;--mecx-filter-bar-radius-item: 4px;--mecx-filter-bar-fade-width: 48px;--mecx-filter-bar-focus-reach: 4px;--mecx-filter-bar-z-raised: 1;--mecx-filter-bar-z-sticky: 2;--mecx-filter-bar-z-menu: 1000}@media(prefers-reduced-motion:reduce){.mecx-filter-menu{--mecx-filter-bar-duration-state: 1ms;--mecx-filter-bar-duration-enter: 1ms;--mecx-filter-bar-duration-exit: 1ms;--mecx-filter-bar-scale-unfold: 1;--mecx-filter-bar-travel-anchored: 0px;--mecx-filter-bar-travel-slide: 0px;--mecx-filter-bar-stagger: 0ms}}.mecx-filter-menu{display:flex;flex-direction:column;min-width:158px;max-width:341px;background:var(--mecx-color-white);border:2px solid var(--mecx-color-gray-200);border-radius:var(--mecx-filter-bar-radius);box-shadow:0 8px 12px -4px var(--mecx-color-box-shadow, rgba(47, 50, 55, .08));overflow:hidden;box-sizing:border-box}.mecx-filter-menu-search{padding:8px;border-bottom:2px solid var(--mecx-color-gray-200);flex-shrink:0}.mecx-filter-menu-search monkey-form-field{width:100%;display:block}.mecx-filter-menu-items{display:flex;flex-direction:column;padding:8px}.mecx-filter-menu-items--scroll{overflow-y:auto}.mecx-filter-menu-items--scrolling{scrollbar-gutter:stable;padding-right:0}.mecx-filter-menu-items--scrolling::-webkit-scrollbar{width:20px}.mecx-filter-menu-items--scrolling::-webkit-scrollbar-track{background:var(--mecx-color-gray-100);background-clip:padding-box;border-left:4px solid transparent;border-right:8px solid transparent;border-radius:8px 12px 12px 8px/4px;box-shadow:inset 0 0 0 1px var(--mecx-color-gray-400);margin:8px 0}.mecx-filter-menu-items--scrolling::-webkit-scrollbar-thumb{background:var(--mecx-color-gray-800);background-clip:padding-box;border-left:5px solid transparent;border-right:9px solid transparent;border-radius:8px 12px 12px 8px/3px}.mecx-filter-menu-items>monkey-divider{margin-block:4px}.mecx-filter-menu-items>*{flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MonkeyFormFieldModule }, { kind: "component", type: MonkeyFormFieldComponent, selector: "monkey-form-field", inputs: ["id", "hideAction", "enableClear", "size", "noFooterSpace", "displayOnly"], outputs: ["onDisplayOnlyChange"], exportAs: ["monkeyFormField"] }, { kind: "ngmodule", type: MonkeyInputModule }, { kind: "directive", type: MonkeyInputDirective, selector: "input[monkey-input],textarea[monkey-input]", inputs: ["name", "disabled", "id", "required", "type", "min", "max", "percent"], exportAs: ["monkeyInput"] }, { kind: "directive", type: MonkeyPrefixDirective, selector: "monkey-prefix" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
6971
6159
  }
6972
6160
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterMenuComponent, decorators: [{
6973
6161
  type: Component,
6974
6162
  args: [{ selector: 'monkey-filter-menu', imports: [FormsModule, MonkeyFormFieldModule, MonkeyInputModule, MonkeyPrefixDirective], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
6975
6163
  'data-testid': 'monkey-filter-menu',
6976
6164
  class: 'mecx-filter-menu'
6977
- }, template: "<!-- Search \u2014 optional, no label and no footer -->\n@if (showSearch()) {\n <div class=\"mecx-filter-menu-search\">\n <monkey-form-field size=\"sm\">\n <input\n type=\"text\"\n monkey-input\n [placeholder]=\"searchPlaceholder()\"\n [ngModel]=\"searchValue\"\n (ngModelChange)=\"onSearchInput($event)\"\n />\n <monkey-prefix>\n <i class=\"mk-i mk-i-search fs-md\"></i>\n </monkey-prefix>\n </monkey-form-field>\n </div>\n}\n\n<!-- Projected rows. `--scroll` allows scrolling; `--scrolling` draws the track\n and hands it the right-hand breathing room, and only kicks in once the\n content really overflows \u2014 otherwise the panel reserves 20px for a bar\n that does not exist. -->\n<div\n #items\n class=\"mecx-filter-menu-items\"\n [class.mecx-filter-menu-items--scroll]=\"showScroll()\"\n [class.mecx-filter-menu-items--scrolling]=\"scrolling()\"\n [style.max-height.px]=\"showScroll() ? maxHeight() : null\"\n>\n <ng-content></ng-content>\n</div>\n", styles: ["@charset \"UTF-8\";.mecx-filter-menu{--mecx-fbv2-duration-state: .15s;--mecx-fbv2-duration-enter: .2s;--mecx-fbv2-duration-exit: .15s;--mecx-fbv2-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-fbv2-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-fbv2-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-fbv2-scale-unfold: .94;--mecx-fbv2-travel-anchored: 4px;--mecx-fbv2-travel-slide: 16px;--mecx-fbv2-stagger: 25ms;--mecx-fbv2-control-height: 28px;--mecx-fbv2-pointer-target: 40px;--mecx-fbv2-radius: 8px;--mecx-fbv2-radius-item: 4px;--mecx-fbv2-fade-width: 48px}@media(prefers-reduced-motion:reduce){.mecx-filter-menu{--mecx-fbv2-duration-state: 1ms;--mecx-fbv2-duration-enter: 1ms;--mecx-fbv2-duration-exit: 1ms;--mecx-fbv2-scale-unfold: 1;--mecx-fbv2-travel-anchored: 0px;--mecx-fbv2-travel-slide: 0px;--mecx-fbv2-stagger: 0ms}}.mecx-filter-menu{display:flex;flex-direction:column;min-width:158px;max-width:341px;background:var(--mecx-color-white);border:2px solid var(--mecx-color-gray-200);border-radius:var(--mecx-fbv2-radius);box-shadow:0 8px 12px -4px var(--mecx-color-box-shadow, rgba(47, 50, 55, .08));overflow:hidden;box-sizing:border-box}.mecx-filter-menu-search{padding:8px;border-bottom:2px solid var(--mecx-color-gray-200);flex-shrink:0}.mecx-filter-menu-search monkey-form-field{width:100%;display:block}.mecx-filter-menu-items{display:flex;flex-direction:column;padding:8px}.mecx-filter-menu-items--scroll{overflow-y:auto}.mecx-filter-menu-items--scrolling{scrollbar-gutter:stable;padding-right:0}.mecx-filter-menu-items--scrolling::-webkit-scrollbar{width:20px}.mecx-filter-menu-items--scrolling::-webkit-scrollbar-track{background:var(--mecx-color-gray-100);background-clip:padding-box;border-left:4px solid transparent;border-right:8px solid transparent;border-radius:8px 12px 12px 8px/4px;box-shadow:inset 0 0 0 1px var(--mecx-color-gray-400);margin:8px 0}.mecx-filter-menu-items--scrolling::-webkit-scrollbar-thumb{background:var(--mecx-color-gray-800);background-clip:padding-box;border-left:5px solid transparent;border-right:9px solid transparent;border-radius:8px 12px 12px 8px/3px}.mecx-filter-menu-items>monkey-divider{margin-block:4px}\n"] }]
6978
- }], ctorParameters: () => [], propDecorators: { showSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSearch", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], showScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "showScroll", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }], _items: [{ type: i0.ViewChild, args: ['items', { isSignal: true }] }] } });
6165
+ }, template: "@if (showSearch()) {\n <div class=\"mecx-filter-menu-search\">\n <monkey-form-field size=\"sm\" noFooterSpace>\n <input\n type=\"text\"\n monkey-input\n [placeholder]=\"searchPlaceholder()\"\n [ngModel]=\"searchValue\"\n (ngModelChange)=\"onSearchInput($event)\"\n />\n <monkey-prefix>\n <i class=\"mk-i mk-i-search fs-md\"></i>\n </monkey-prefix>\n </monkey-form-field>\n </div>\n}\n\n<div\n #items\n class=\"mecx-filter-menu-items\"\n [class.mecx-filter-menu-items--scroll]=\"showScroll()\"\n [class.mecx-filter-menu-items--scrolling]=\"scrolling()\"\n [style.max-height.px]=\"showScroll() ? maxHeight() : null\"\n>\n <ng-content></ng-content>\n</div>\n", styles: [".mecx-filter-menu{--mecx-filter-bar-duration-state: .15s;--mecx-filter-bar-duration-enter: .2s;--mecx-filter-bar-duration-exit: .15s;--mecx-filter-bar-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-filter-bar-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-filter-bar-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-filter-bar-scale-unfold: .94;--mecx-filter-bar-travel-anchored: 4px;--mecx-filter-bar-travel-slide: 16px;--mecx-filter-bar-stagger: 25ms;--mecx-filter-bar-control-height: 32px;--mecx-filter-bar-pointer-target: 40px;--mecx-filter-bar-reach: calc((var(--mecx-filter-bar-control-height) - var(--mecx-filter-bar-pointer-target)) / 2);--mecx-filter-bar-radius: 8px;--mecx-filter-bar-radius-item: 4px;--mecx-filter-bar-fade-width: 48px;--mecx-filter-bar-focus-reach: 4px;--mecx-filter-bar-z-raised: 1;--mecx-filter-bar-z-sticky: 2;--mecx-filter-bar-z-menu: 1000}@media(prefers-reduced-motion:reduce){.mecx-filter-menu{--mecx-filter-bar-duration-state: 1ms;--mecx-filter-bar-duration-enter: 1ms;--mecx-filter-bar-duration-exit: 1ms;--mecx-filter-bar-scale-unfold: 1;--mecx-filter-bar-travel-anchored: 0px;--mecx-filter-bar-travel-slide: 0px;--mecx-filter-bar-stagger: 0ms}}.mecx-filter-menu{display:flex;flex-direction:column;min-width:158px;max-width:341px;background:var(--mecx-color-white);border:2px solid var(--mecx-color-gray-200);border-radius:var(--mecx-filter-bar-radius);box-shadow:0 8px 12px -4px var(--mecx-color-box-shadow, rgba(47, 50, 55, .08));overflow:hidden;box-sizing:border-box}.mecx-filter-menu-search{padding:8px;border-bottom:2px solid var(--mecx-color-gray-200);flex-shrink:0}.mecx-filter-menu-search monkey-form-field{width:100%;display:block}.mecx-filter-menu-items{display:flex;flex-direction:column;padding:8px}.mecx-filter-menu-items--scroll{overflow-y:auto}.mecx-filter-menu-items--scrolling{scrollbar-gutter:stable;padding-right:0}.mecx-filter-menu-items--scrolling::-webkit-scrollbar{width:20px}.mecx-filter-menu-items--scrolling::-webkit-scrollbar-track{background:var(--mecx-color-gray-100);background-clip:padding-box;border-left:4px solid transparent;border-right:8px solid transparent;border-radius:8px 12px 12px 8px/4px;box-shadow:inset 0 0 0 1px var(--mecx-color-gray-400);margin:8px 0}.mecx-filter-menu-items--scrolling::-webkit-scrollbar-thumb{background:var(--mecx-color-gray-800);background-clip:padding-box;border-left:5px solid transparent;border-right:9px solid transparent;border-radius:8px 12px 12px 8px/3px}.mecx-filter-menu-items>monkey-divider{margin-block:4px}.mecx-filter-menu-items>*{flex-shrink:0}\n"] }]
6166
+ }], ctorParameters: () => [], propDecorators: { _items: [{ type: i0.ViewChild, args: ['items', { isSignal: true }] }], showSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSearch", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], showScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "showScroll", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], onSearchChange: [{ type: i0.Output, args: ["onSearchChange"] }] } });
6979
6167
 
6980
6168
  /** ************************
6981
6169
  * Copyright Monkey Exchange. All Rights Reserved
6982
6170
  * This style guide was developed by Monkey Exchange Team
6983
6171
  * MIT Licence
6984
6172
  ************************* */
6985
- /**
6986
- * One row of a monkey-filter-menu.
6987
- *
6988
- * The ROW is the click target, which is why the checkbox inside it does not
6989
- * grow one of its own: the boxes sit 18px apart inside rows of 32px that touch
6990
- * each other, so a 40px floor on each would make two targets OVERLAP by 8px —
6991
- * inside rows that are already clickable end to end.
6992
- */
6993
6173
  class MonkeyFilterMenuItemComponent {
6994
6174
  constructor() {
6995
6175
  this.property = input('text', ...(ngDevMode ? [{ debugName: "property" }] : /* istanbul ignore next */ []));
6996
- /** Icon font name, without the `mk-i-` prefix. */
6997
6176
  this.leadIcon = input(null, ...(ngDevMode ? [{ debugName: "leadIcon" }] : /* istanbul ignore next */ []));
6998
6177
  this.label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
6999
- /** Secondary line under the label — a document number, a key. */
7000
6178
  this.description = input(null, ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
7001
6179
  this.checked = input(false, { ...(ngDevMode ? { debugName: "checked" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
7002
- /** Already answered elsewhere: the row shows a check and stops responding. */
7003
6180
  this.selected = input(false, { ...(ngDevMode ? { debugName: "selected" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
7004
6181
  this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
7005
- this.itemClick = output();
6182
+ this.onItemClick = output();
7006
6183
  }
7007
6184
  onClick() {
7008
6185
  if (this.disabled())
7009
6186
  return;
7010
- this.itemClick.emit();
6187
+ this.onItemClick.emit();
7011
6188
  }
7012
6189
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterMenuItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7013
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyFilterMenuItemComponent, isStandalone: true, selector: "monkey-filter-menu-item", inputs: { property: { classPropertyName: "property", publicName: "property", isSignal: true, isRequired: false, transformFunction: null }, leadIcon: { classPropertyName: "leadIcon", publicName: "leadIcon", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick" }, host: { attributes: { "data-testid": "monkey-filter-menu-item", "role": "option" }, listeners: { "click": "onClick()" }, properties: { "class.mecx-filter-menu-item--disabled": "disabled()", "class.mecx-filter-menu-item--selected": "selected()", "attr.aria-selected": "selected() || checked()", "attr.aria-disabled": "disabled() || null" }, classAttribute: "mecx-filter-menu-item" }, ngImport: i0, template: "@if (property() === 'checkbox') {\n <monkey-checkbox\n class=\"mecx-filter-menu-item-checkbox\"\n size=\"sm\"\n [value]=\"checked()\"\n [disabled]=\"disabled()\"\n [showFooter]=\"false\"\n ></monkey-checkbox>\n} @else if (leadIcon()) {\n <i class=\"mk-i mk-i-{{ leadIcon() }} mecx-filter-menu-item-icon\"></i>\n}\n\n<span class=\"mecx-filter-menu-item-text\">\n <span class=\"mecx-filter-menu-item-label\">{{ label() }}</span>\n @if (description()) {\n <span class=\"mecx-filter-menu-item-description\">{{ description() }}</span>\n }\n</span>\n\n<!-- The row was already answered somewhere else \u2014 the check says so without\n taking the row out of the list, which is what tells the user the filter\n they are looking for is already on. -->\n@if (selected()) {\n <i class=\"mk-i mk-i-check mecx-filter-menu-item-check\"></i>\n}\n", styles: ["@charset \"UTF-8\";.mecx-filter-menu-item{--mecx-fbv2-duration-state: .15s;--mecx-fbv2-duration-enter: .2s;--mecx-fbv2-duration-exit: .15s;--mecx-fbv2-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-fbv2-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-fbv2-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-fbv2-scale-unfold: .94;--mecx-fbv2-travel-anchored: 4px;--mecx-fbv2-travel-slide: 16px;--mecx-fbv2-stagger: 25ms;--mecx-fbv2-control-height: 28px;--mecx-fbv2-pointer-target: 40px;--mecx-fbv2-radius: 8px;--mecx-fbv2-radius-item: 4px;--mecx-fbv2-fade-width: 48px}@media(prefers-reduced-motion:reduce){.mecx-filter-menu-item{--mecx-fbv2-duration-state: 1ms;--mecx-fbv2-duration-enter: 1ms;--mecx-fbv2-duration-exit: 1ms;--mecx-fbv2-scale-unfold: 1;--mecx-fbv2-travel-anchored: 0px;--mecx-fbv2-travel-slide: 0px;--mecx-fbv2-stagger: 0ms}}.mecx-filter-menu-item{display:flex;align-items:center;gap:8px;padding:8px;background:var(--mecx-color-white);border-radius:var(--mecx-fbv2-radius-item);cursor:pointer;width:100%;box-sizing:border-box;-webkit-user-select:none;user-select:none;transition:background-color var(--mecx-fbv2-duration-state) var(--mecx-fbv2-ease-state),scale var(--mecx-fbv2-duration-state) var(--mecx-fbv2-ease-state)}.mecx-filter-menu-item:hover:not(.mecx-filter-menu-item--disabled){background-color:var(--mecx-color-gray-100)}.mecx-filter-menu-item:active:not(.mecx-filter-menu-item--disabled){scale:.99}.mecx-filter-menu-item--disabled{cursor:not-allowed}.mecx-filter-menu-item--disabled .mecx-filter-menu-item-label,.mecx-filter-menu-item--disabled .mecx-filter-menu-item-description,.mecx-filter-menu-item--disabled .mecx-filter-menu-item-icon{color:var(--mecx-color-gray-400)}.mecx-filter-menu-item-icon{display:flex;flex-shrink:0;font-size:16px;color:var(--mecx-color-gray-700)}.mecx-filter-menu-item-checkbox{flex-shrink:0;pointer-events:none}.mecx-filter-menu-item-text{display:flex;flex-direction:column;gap:4px;flex:1 0 0;min-width:0}.mecx-filter-menu-item-label{display:block;font-size:13px;font-weight:400;line-height:16px;letter-spacing:.02em;color:var(--mecx-color-gray-900);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mecx-filter-menu-item-description{display:block;font-size:13px;font-weight:400;line-height:16px;letter-spacing:.02em;color:var(--mecx-color-gray-700)}.mecx-filter-menu-item-check{display:flex;flex-shrink:0;font-size:12px;color:var(--mecx-color-theme-main)}\n"], dependencies: [{ kind: "component", type: MonkeyCheckboxComponent, selector: "monkey-checkbox", inputs: ["disabled", "indeterminate", "required", "showFooter", "size", "value"], outputs: ["onChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
6190
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyFilterMenuItemComponent, isStandalone: true, selector: "monkey-filter-menu-item", inputs: { property: { classPropertyName: "property", publicName: "property", isSignal: true, isRequired: false, transformFunction: null }, leadIcon: { classPropertyName: "leadIcon", publicName: "leadIcon", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onItemClick: "onItemClick" }, host: { attributes: { "data-testid": "monkey-filter-menu-item", "role": "option" }, listeners: { "click": "onClick()" }, properties: { "class.mecx-filter-menu-item--disabled": "disabled()", "class.mecx-filter-menu-item--selected": "selected()", "attr.aria-selected": "selected() || checked()", "attr.aria-disabled": "disabled() || null" }, classAttribute: "mecx-filter-menu-item" }, ngImport: i0, template: "@if (property() === 'checkbox') {\n <monkey-checkbox\n class=\"mecx-filter-menu-item-checkbox\"\n size=\"sm\"\n [value]=\"checked()\"\n [disabled]=\"disabled()\"\n [showFooter]=\"false\"\n ></monkey-checkbox>\n} @else if (leadIcon()) {\n <i class=\"mk-i mk-i-{{ leadIcon() }} mecx-filter-menu-item-icon\"></i>\n}\n\n<span class=\"mecx-filter-menu-item-text\">\n <span class=\"mecx-filter-menu-item-label\">{{ label() }}</span>\n @if (description()) {\n <span class=\"mecx-filter-menu-item-description\">{{ description() }}</span>\n }\n</span>\n@if (selected()) {\n <i class=\"mk-i mk-i-check mecx-filter-menu-item-check\"></i>\n}\n", styles: [".mecx-filter-menu-item{--mecx-filter-bar-duration-state: .15s;--mecx-filter-bar-duration-enter: .2s;--mecx-filter-bar-duration-exit: .15s;--mecx-filter-bar-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-filter-bar-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-filter-bar-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-filter-bar-scale-unfold: .94;--mecx-filter-bar-travel-anchored: 4px;--mecx-filter-bar-travel-slide: 16px;--mecx-filter-bar-stagger: 25ms;--mecx-filter-bar-control-height: 32px;--mecx-filter-bar-pointer-target: 40px;--mecx-filter-bar-reach: calc((var(--mecx-filter-bar-control-height) - var(--mecx-filter-bar-pointer-target)) / 2);--mecx-filter-bar-radius: 8px;--mecx-filter-bar-radius-item: 4px;--mecx-filter-bar-fade-width: 48px;--mecx-filter-bar-focus-reach: 4px;--mecx-filter-bar-z-raised: 1;--mecx-filter-bar-z-sticky: 2;--mecx-filter-bar-z-menu: 1000}@media(prefers-reduced-motion:reduce){.mecx-filter-menu-item{--mecx-filter-bar-duration-state: 1ms;--mecx-filter-bar-duration-enter: 1ms;--mecx-filter-bar-duration-exit: 1ms;--mecx-filter-bar-scale-unfold: 1;--mecx-filter-bar-travel-anchored: 0px;--mecx-filter-bar-travel-slide: 0px;--mecx-filter-bar-stagger: 0ms}}.mecx-filter-menu-item{display:flex;align-items:center;gap:8px;padding:8px;background:var(--mecx-color-white);border-radius:var(--mecx-filter-bar-radius-item);cursor:pointer;width:100%;box-sizing:border-box;-webkit-user-select:none;user-select:none;transition:background-color var(--mecx-filter-bar-duration-state) var(--mecx-filter-bar-ease-state),scale var(--mecx-filter-bar-duration-state) var(--mecx-filter-bar-ease-state)}.mecx-filter-menu-item:hover:not(.mecx-filter-menu-item--disabled){background-color:var(--mecx-color-gray-100)}.mecx-filter-menu-item:active:not(.mecx-filter-menu-item--disabled){scale:.99}.mecx-filter-menu-item--disabled{cursor:not-allowed}.mecx-filter-menu-item--disabled .mecx-filter-menu-item-label,.mecx-filter-menu-item--disabled .mecx-filter-menu-item-description,.mecx-filter-menu-item--disabled .mecx-filter-menu-item-icon{color:var(--mecx-color-gray-400)}.mecx-filter-menu-item-icon{display:flex;flex-shrink:0;font-size:16px;color:var(--mecx-color-gray-700)}.mecx-filter-menu-item-checkbox{flex-shrink:0;pointer-events:none}.mecx-filter-menu-item-text{display:flex;flex-direction:column;gap:4px;flex:1 0 0;min-width:0}.mecx-filter-menu-item-label{display:block;font-size:13px;font-weight:400;line-height:16px;letter-spacing:.02em;color:var(--mecx-color-gray-900);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mecx-filter-menu-item-description{display:block;font-size:13px;font-weight:400;line-height:16px;letter-spacing:.02em;color:var(--mecx-color-gray-700)}.mecx-filter-menu-item-check{display:flex;flex-shrink:0;font-size:12px;color:var(--mecx-color-theme-main)}\n"], dependencies: [{ kind: "component", type: MonkeyCheckboxComponent, selector: "monkey-checkbox", inputs: ["disabled", "indeterminate", "required", "showFooter", "size", "value"], outputs: ["onChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
7014
6191
  }
7015
6192
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterMenuItemComponent, decorators: [{
7016
6193
  type: Component,
@@ -7023,38 +6200,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
7023
6200
  '[attr.aria-selected]': 'selected() || checked()',
7024
6201
  '[attr.aria-disabled]': 'disabled() || null',
7025
6202
  '(click)': 'onClick()'
7026
- }, template: "@if (property() === 'checkbox') {\n <monkey-checkbox\n class=\"mecx-filter-menu-item-checkbox\"\n size=\"sm\"\n [value]=\"checked()\"\n [disabled]=\"disabled()\"\n [showFooter]=\"false\"\n ></monkey-checkbox>\n} @else if (leadIcon()) {\n <i class=\"mk-i mk-i-{{ leadIcon() }} mecx-filter-menu-item-icon\"></i>\n}\n\n<span class=\"mecx-filter-menu-item-text\">\n <span class=\"mecx-filter-menu-item-label\">{{ label() }}</span>\n @if (description()) {\n <span class=\"mecx-filter-menu-item-description\">{{ description() }}</span>\n }\n</span>\n\n<!-- The row was already answered somewhere else \u2014 the check says so without\n taking the row out of the list, which is what tells the user the filter\n they are looking for is already on. -->\n@if (selected()) {\n <i class=\"mk-i mk-i-check mecx-filter-menu-item-check\"></i>\n}\n", styles: ["@charset \"UTF-8\";.mecx-filter-menu-item{--mecx-fbv2-duration-state: .15s;--mecx-fbv2-duration-enter: .2s;--mecx-fbv2-duration-exit: .15s;--mecx-fbv2-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-fbv2-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-fbv2-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-fbv2-scale-unfold: .94;--mecx-fbv2-travel-anchored: 4px;--mecx-fbv2-travel-slide: 16px;--mecx-fbv2-stagger: 25ms;--mecx-fbv2-control-height: 28px;--mecx-fbv2-pointer-target: 40px;--mecx-fbv2-radius: 8px;--mecx-fbv2-radius-item: 4px;--mecx-fbv2-fade-width: 48px}@media(prefers-reduced-motion:reduce){.mecx-filter-menu-item{--mecx-fbv2-duration-state: 1ms;--mecx-fbv2-duration-enter: 1ms;--mecx-fbv2-duration-exit: 1ms;--mecx-fbv2-scale-unfold: 1;--mecx-fbv2-travel-anchored: 0px;--mecx-fbv2-travel-slide: 0px;--mecx-fbv2-stagger: 0ms}}.mecx-filter-menu-item{display:flex;align-items:center;gap:8px;padding:8px;background:var(--mecx-color-white);border-radius:var(--mecx-fbv2-radius-item);cursor:pointer;width:100%;box-sizing:border-box;-webkit-user-select:none;user-select:none;transition:background-color var(--mecx-fbv2-duration-state) var(--mecx-fbv2-ease-state),scale var(--mecx-fbv2-duration-state) var(--mecx-fbv2-ease-state)}.mecx-filter-menu-item:hover:not(.mecx-filter-menu-item--disabled){background-color:var(--mecx-color-gray-100)}.mecx-filter-menu-item:active:not(.mecx-filter-menu-item--disabled){scale:.99}.mecx-filter-menu-item--disabled{cursor:not-allowed}.mecx-filter-menu-item--disabled .mecx-filter-menu-item-label,.mecx-filter-menu-item--disabled .mecx-filter-menu-item-description,.mecx-filter-menu-item--disabled .mecx-filter-menu-item-icon{color:var(--mecx-color-gray-400)}.mecx-filter-menu-item-icon{display:flex;flex-shrink:0;font-size:16px;color:var(--mecx-color-gray-700)}.mecx-filter-menu-item-checkbox{flex-shrink:0;pointer-events:none}.mecx-filter-menu-item-text{display:flex;flex-direction:column;gap:4px;flex:1 0 0;min-width:0}.mecx-filter-menu-item-label{display:block;font-size:13px;font-weight:400;line-height:16px;letter-spacing:.02em;color:var(--mecx-color-gray-900);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mecx-filter-menu-item-description{display:block;font-size:13px;font-weight:400;line-height:16px;letter-spacing:.02em;color:var(--mecx-color-gray-700)}.mecx-filter-menu-item-check{display:flex;flex-shrink:0;font-size:12px;color:var(--mecx-color-theme-main)}\n"] }]
7027
- }], propDecorators: { property: [{ type: i0.Input, args: [{ isSignal: true, alias: "property", required: false }] }], leadIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "leadIcon", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }] } });
6203
+ }, template: "@if (property() === 'checkbox') {\n <monkey-checkbox\n class=\"mecx-filter-menu-item-checkbox\"\n size=\"sm\"\n [value]=\"checked()\"\n [disabled]=\"disabled()\"\n [showFooter]=\"false\"\n ></monkey-checkbox>\n} @else if (leadIcon()) {\n <i class=\"mk-i mk-i-{{ leadIcon() }} mecx-filter-menu-item-icon\"></i>\n}\n\n<span class=\"mecx-filter-menu-item-text\">\n <span class=\"mecx-filter-menu-item-label\">{{ label() }}</span>\n @if (description()) {\n <span class=\"mecx-filter-menu-item-description\">{{ description() }}</span>\n }\n</span>\n@if (selected()) {\n <i class=\"mk-i mk-i-check mecx-filter-menu-item-check\"></i>\n}\n", styles: [".mecx-filter-menu-item{--mecx-filter-bar-duration-state: .15s;--mecx-filter-bar-duration-enter: .2s;--mecx-filter-bar-duration-exit: .15s;--mecx-filter-bar-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-filter-bar-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-filter-bar-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-filter-bar-scale-unfold: .94;--mecx-filter-bar-travel-anchored: 4px;--mecx-filter-bar-travel-slide: 16px;--mecx-filter-bar-stagger: 25ms;--mecx-filter-bar-control-height: 32px;--mecx-filter-bar-pointer-target: 40px;--mecx-filter-bar-reach: calc((var(--mecx-filter-bar-control-height) - var(--mecx-filter-bar-pointer-target)) / 2);--mecx-filter-bar-radius: 8px;--mecx-filter-bar-radius-item: 4px;--mecx-filter-bar-fade-width: 48px;--mecx-filter-bar-focus-reach: 4px;--mecx-filter-bar-z-raised: 1;--mecx-filter-bar-z-sticky: 2;--mecx-filter-bar-z-menu: 1000}@media(prefers-reduced-motion:reduce){.mecx-filter-menu-item{--mecx-filter-bar-duration-state: 1ms;--mecx-filter-bar-duration-enter: 1ms;--mecx-filter-bar-duration-exit: 1ms;--mecx-filter-bar-scale-unfold: 1;--mecx-filter-bar-travel-anchored: 0px;--mecx-filter-bar-travel-slide: 0px;--mecx-filter-bar-stagger: 0ms}}.mecx-filter-menu-item{display:flex;align-items:center;gap:8px;padding:8px;background:var(--mecx-color-white);border-radius:var(--mecx-filter-bar-radius-item);cursor:pointer;width:100%;box-sizing:border-box;-webkit-user-select:none;user-select:none;transition:background-color var(--mecx-filter-bar-duration-state) var(--mecx-filter-bar-ease-state),scale var(--mecx-filter-bar-duration-state) var(--mecx-filter-bar-ease-state)}.mecx-filter-menu-item:hover:not(.mecx-filter-menu-item--disabled){background-color:var(--mecx-color-gray-100)}.mecx-filter-menu-item:active:not(.mecx-filter-menu-item--disabled){scale:.99}.mecx-filter-menu-item--disabled{cursor:not-allowed}.mecx-filter-menu-item--disabled .mecx-filter-menu-item-label,.mecx-filter-menu-item--disabled .mecx-filter-menu-item-description,.mecx-filter-menu-item--disabled .mecx-filter-menu-item-icon{color:var(--mecx-color-gray-400)}.mecx-filter-menu-item-icon{display:flex;flex-shrink:0;font-size:16px;color:var(--mecx-color-gray-700)}.mecx-filter-menu-item-checkbox{flex-shrink:0;pointer-events:none}.mecx-filter-menu-item-text{display:flex;flex-direction:column;gap:4px;flex:1 0 0;min-width:0}.mecx-filter-menu-item-label{display:block;font-size:13px;font-weight:400;line-height:16px;letter-spacing:.02em;color:var(--mecx-color-gray-900);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mecx-filter-menu-item-description{display:block;font-size:13px;font-weight:400;line-height:16px;letter-spacing:.02em;color:var(--mecx-color-gray-700)}.mecx-filter-menu-item-check{display:flex;flex-shrink:0;font-size:12px;color:var(--mecx-color-theme-main)}\n"] }]
6204
+ }], propDecorators: { property: [{ type: i0.Input, args: [{ isSignal: true, alias: "property", required: false }] }], leadIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "leadIcon", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], onItemClick: [{ type: i0.Output, args: ["onItemClick"] }] } });
7028
6205
 
7029
6206
  /** ************************
7030
6207
  * Copyright Monkey Exchange. All Rights Reserved
7031
6208
  * This style guide was developed by Monkey Exchange Team
7032
6209
  * MIT Licence
7033
6210
  ************************* */
7034
- /**
7035
- * Picks the panel's horizontal: align, FLIP, or butt against the edge.
7036
- *
7037
- * Three steps, in this order:
7038
- *
7039
- * 1. The preferred edge — the one `alignment` asks for.
7040
- * 2. The OPPOSITE edge, when the preferred one does not fit. Aligned to the
7041
- * start with no room to the right, the panel flips and ends where the
7042
- * trigger ends, growing back into the screen.
7043
- * 3. Clamped to the viewport, when not even flipped fits — i.e. when the
7044
- * panel is WIDER than the viewport. There is no good position then, and
7045
- * the fix is a narrower panel, not a better coordinate.
7046
- *
7047
- * Step 2 is the one that matters visually: nudging the panel just enough to
7048
- * fit leaves it misaligned with BOTH edges of the trigger, looking displaced
7049
- * for no reason. Flipped, it is still anchored to an edge — just the other one.
7050
- *
7051
- * A viewport of width 0 returns the preferred value without measuring. That is
7052
- * not defensive padding: jsdom reports `clientWidth: 0`, and measuring against
7053
- * zero would send every panel to the left edge.
7054
- */
7055
6211
  function horizontalOf(target, width, gap, alignment) {
7056
- // The horizontal gap is the panel's breathing room, not a one-sided border:
7057
- // aligned to the end it pushes inwards, which is the mirrored gesture.
7058
6212
  const atStart = target.left + gap;
7059
6213
  const atEnd = target.right - width - gap;
7060
6214
  const preferred = alignment === 'end' ? atEnd : atStart;
@@ -7071,19 +6225,6 @@ function horizontalOf(target, width, gap, alignment) {
7071
6225
  return opposite;
7072
6226
  return Math.max(0, Math.min(preferred, viewport - width));
7073
6227
  }
7074
- /**
7075
- * The offset the panel is applying to ITSELF.
7076
- *
7077
- * `getBoundingClientRect` includes the element's own translate, and the
7078
- * zero-measurement uses that rect to discover the containing block's origin.
7079
- * Without subtracting this share, the translate of the ENTRANCE animation is
7080
- * baked into `top` as if it were origin — and comes back out when the
7081
- * animation ends, taking the panel with it.
7082
- *
7083
- * Only `translate` matters. The `scale` of the same animation does not move
7084
- * the top edge, because the entrance fixes `transform-origin: top` and scales
7085
- * X by 1.
7086
- */
7087
6228
  function ownOffset(menu) {
7088
6229
  const raw = getComputedStyle(menu).translate;
7089
6230
  if (!raw || raw === 'none')
@@ -7091,26 +6232,6 @@ function ownOffset(menu) {
7091
6232
  const [x, y] = raw.split(' ');
7092
6233
  return { x: parseFloat(x) || 0, y: parseFloat(y ?? '') || 0 };
7093
6234
  }
7094
- /**
7095
- * Butts the panel against the requested side of the trigger.
7096
- *
7097
- * The breathing room stays in the stylesheet, as the panel's `margin`. It has
7098
- * to come back into the sum because the measurement ALREADY includes it:
7099
- * without adding it again the margin would cancel itself out and the panel
7100
- * would sit glued to the trigger.
7101
- *
7102
- * The containing block's origin comes out of the same sum without moving
7103
- * anything: with `top: T` applied, `rect.top = origin + T + translate`, so
7104
- * `origin = rect.top - T - translate`. All it takes is for the panel to have a
7105
- * known inline `top`, which `anchorMenu` guarantees the first time round.
7106
- *
7107
- * The earlier way to find the origin was to write `top: 0; left: 0`, measure,
7108
- * then write the final value. That was a round trip PER scroll event — dozens
7109
- * a second on an inertial scroll, each one throwing the panel into the corner
7110
- * and back with a forced layout read in between. The symptom is a panel
7111
- * flickering between the right place and the top of the window instead of
7112
- * following its trigger.
7113
- */
7114
6235
  function place(target, menu, gaps, alignment) {
7115
6236
  const own = ownOffset(menu);
7116
6237
  const appliedTop = parseFloat(menu.style.top) || 0;
@@ -7123,7 +6244,6 @@ function place(target, menu, gaps, alignment) {
7123
6244
  menu.style.top = `${y - originTop}px`;
7124
6245
  menu.style.left = `${x - originLeft}px`;
7125
6246
  }
7126
- /** The nearest ancestor that SCROLLS — it is the one clipping the trigger. */
7127
6247
  function scrollingAncestor(el) {
7128
6248
  let node = el.parentElement;
7129
6249
  while (node) {
@@ -7134,21 +6254,6 @@ function scrollingAncestor(el) {
7134
6254
  }
7135
6255
  return null;
7136
6256
  }
7137
- /**
7138
- * Has the trigger gone out of sight?
7139
- *
7140
- * A panel anchored to a trigger that is no longer on screen is worse than no
7141
- * panel at all: it hangs in the middle of the content with no visible anchor,
7142
- * and the user has no way of knowing what those options belong to.
7143
- *
7144
- * Two boundaries count: the window, and the CLIP of the ancestor that scrolls.
7145
- * The second is the one that catches a chip scrolling sideways out of the
7146
- * filter row — there the trigger's rect is still inside the window, and only
7147
- * the container knows it is gone.
7148
- *
7149
- * With no measurable viewport nothing is hidden: in jsdom `clientWidth` is 0,
7150
- * and closing every menu because of that would be worse than the defect.
7151
- */
7152
6257
  function outOfSight(trigger, target) {
7153
6258
  const vh = document.documentElement.clientHeight || 0;
7154
6259
  const vw = document.documentElement.clientWidth || 0;
@@ -7176,56 +6281,13 @@ function readGaps(menu) {
7176
6281
  left: parseFloat(style.marginLeft) || 0
7177
6282
  };
7178
6283
  }
7179
- /**
7180
- * Butts the panel against the trigger and KEEPS it there while anything
7181
- * scrolls. Returns the function that switches it all off.
7182
- *
7183
- * Anchoring and following are one job: a positioned panel that stops following
7184
- * is already wrong on the first scroll, and one that follows without having
7185
- * been positioned never reaches the right place.
7186
- *
7187
- * `capture: true` is not a detail: an element's `scroll` event does NOT
7188
- * bubble, so without the capture phase the filter row scrolling under the
7189
- * panel would go unnoticed and the panel would stay planted at the old spot.
7190
- *
7191
- * The margins are read once — they do not change. The ORIGIN does: if the page
7192
- * scrolls and the containing block is a transformed ancestor, it moves down
7193
- * with the trigger, and only re-measuring both keeps the sum standing.
7194
- *
7195
- * `transitionend` is there for one specific and expensive-to-find reason.
7196
- * While an ancestor's `translate` is ANIMATING it is a containing block; when
7197
- * the transition ends, it stops being one. A scroll that lands inside that
7198
- * window measures the transformed origin, and the sum stays wrong FOREVER —
7199
- * the panel is born displaced and nothing corrects it. That is exactly what
7200
- * happens here: the row scrolls to follow the new filter at the same instant
7201
- * the FLIP translates the slots.
7202
- *
7203
- * `animationend` closes the SAME window from the other side. The chip's
7204
- * entrance is not a transition, it is a `@keyframes` animating `translate`. A
7205
- * chip born with its panel already open — which is the normal case, because
7206
- * the value panel opens on its own — has that panel anchored against a slot
7207
- * that is still a containing block, and when the animation ends the slot stops
7208
- * being one: the same coordinates now resolve against the viewport and the
7209
- * panel jumps the slot's whole offset.
7210
- *
7211
- * The guard is `target.contains(menu)` rather than the animation's name. Only
7212
- * an ANCESTOR's animation changes the panel's containing block, so the right
7213
- * question is one of kinship — and it does not tie this helper to the list of
7214
- * keyframes used by whoever calls it.
7215
- */
7216
6284
  function anchorMenu(trigger, menu, alignment = 'start', onOutOfSight) {
7217
6285
  const gaps = readGaps(menu);
7218
- // A KNOWN starting point for the first measurement: with `top: auto` the
7219
- // panel sits at its static position, and the containing block's origin
7220
- // cannot be derived from that. Once only, before any paint — from then on
7221
- // `place` derives from the applied position and never moves the panel just
7222
- // to measure it.
7223
6286
  if (!menu.style.top) {
7224
6287
  menu.style.top = '0px';
7225
6288
  menu.style.left = '0px';
7226
6289
  }
7227
6290
  const reposition = () => {
7228
- // One read of the trigger per event, reused by both sums.
7229
6291
  const target = trigger.getBoundingClientRect();
7230
6292
  if (onOutOfSight && outOfSight(trigger, target)) {
7231
6293
  onOutOfSight();
@@ -7233,11 +6295,6 @@ function anchorMenu(trigger, menu, alignment = 'start', onOutOfSight) {
7233
6295
  }
7234
6296
  place(target, menu, gaps, alignment);
7235
6297
  };
7236
- // Only `translate` is of interest: it is the property that turns an ancestor
7237
- // into a containing block. Without the filter, every COLOUR transition in
7238
- // the document — and each hover on a chip is three — would fire a
7239
- // reposition with a forced layout read, leaving the panel trembling while
7240
- // the pointer wanders across the bar.
7241
6298
  const onTransitionEnd = (event) => {
7242
6299
  if (event.propertyName === 'translate')
7243
6300
  reposition();
@@ -7247,12 +6304,6 @@ function anchorMenu(trigger, menu, alignment = 'start', onOutOfSight) {
7247
6304
  if (node?.contains(menu))
7248
6305
  reposition();
7249
6306
  };
7250
- // The panel's own SIZE feeds the horizontal sum — it is what decides whether
7251
- // the preferred edge fits. A panel that CHANGES size after being anchored
7252
- // would otherwise stay at the position that fitted the old size, and that is
7253
- // not a rare case here: the date panel swaps its content on "Personalizado",
7254
- // trading a short shortcut list for the full date range, without recreating
7255
- // the element. Repositioning changes nobody's size, so there is no loop.
7256
6307
  const observer = new ResizeObserver(() => {
7257
6308
  reposition();
7258
6309
  });
@@ -7276,47 +6327,24 @@ function anchorMenu(trigger, menu, alignment = 'start', onOutOfSight) {
7276
6327
  * This style guide was developed by Monkey Exchange Team
7277
6328
  * MIT Licence
7278
6329
  ************************* */
7279
- /**
7280
- * One segment of a monkey-filter-chip.
7281
- *
7282
- * ONE component for the two roles the chip has — the category name and the
7283
- * answer. Both share the same state table, the same padding, the same
7284
- * typography and the same height; what changes between them is the content
7285
- * (the first has an icon) and the rounding of the ends, which belongs to the
7286
- * chip and not to the segment. Two components would be two copies of the same
7287
- * stylesheet waiting to drift apart.
7288
- *
7289
- * `filled` is not an input: it is `text() !== ''`. Letting the consumer
7290
- * declare "filled" with an empty text would be a state impossible to draw.
7291
- *
7292
- * The projected panel is `position: fixed` and anchored by script — see
7293
- * `anchored-menu.ts` for why an `absolute` one cannot survive inside a row
7294
- * that scrolls.
7295
- */
7296
6330
  class MonkeyFilterSegmentComponent {
7297
6331
  constructor() {
7298
- /** Category icon — usually only the chip's first segment has one. */
6332
+ this._hostEl = inject(ElementRef);
6333
+ this._menuEl = viewChild('menu', ...(ngDevMode ? [{ debugName: "_menuEl" }] : /* istanbul ignore next */ []));
7299
6334
  this.icon = input(null, ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
7300
- /** The chosen value. Empty means the segment is still waiting. */
7301
6335
  this.text = input('', ...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
7302
- /** Waiting text, in the complement colour. */
7303
6336
  this.placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
7304
- /** A segment with no panel to open. */
7305
6337
  this.readonlySegment = input(false, { ...(ngDevMode ? { debugName: "readonlySegment" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
7306
- this.open = model(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
7307
- this.segmentClick = output();
6338
+ this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
6339
+ this.open = input(false, { ...(ngDevMode ? { debugName: "open" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
6340
+ this.onOpenChange = output();
6341
+ this.onSegmentClick = output();
7308
6342
  this.filled = computed(() => {
7309
6343
  return this.text().length > 0;
7310
6344
  }, ...(ngDevMode ? [{ debugName: "filled" }] : /* istanbul ignore next */ []));
7311
- /** What is shown: the value when there is one, the waiting text when not. */
7312
6345
  this.label = computed(() => {
7313
6346
  return this.filled() ? this.text() : this.placeholder();
7314
6347
  }, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
7315
- this._hostEl = inject(ElementRef);
7316
- this._menuEl = viewChild('menu', ...(ngDevMode ? [{ debugName: "_menuEl" }] : /* istanbul ignore next */ []));
7317
- // The panel is `fixed` to escape the clip of the row that scrolls, and
7318
- // `fixed` follows nobody — the position is recomputed on every opening and
7319
- // kept by the listeners `anchorMenu` installs.
7320
6348
  effect((onCleanup) => {
7321
6349
  const menu = this._menuEl()?.nativeElement;
7322
6350
  if (!menu)
@@ -7324,47 +6352,37 @@ class MonkeyFilterSegmentComponent {
7324
6352
  onCleanup(anchorMenu(this._hostEl.nativeElement, menu, 'start'));
7325
6353
  });
7326
6354
  }
6355
+ focusButton() {
6356
+ this._hostEl.nativeElement.querySelector('.mecx-filter-segment-btn')?.focus();
6357
+ }
7327
6358
  toggle() {
7328
- this.segmentClick.emit();
6359
+ if (this.disabled())
6360
+ return;
6361
+ this.onSegmentClick.emit();
7329
6362
  if (this.readonlySegment())
7330
6363
  return;
7331
- this.open.set(!this.open());
6364
+ this.onOpenChange.emit(!this.open());
7332
6365
  }
7333
- /**
7334
- * A click outside closes. Without it the panel would only close by clicking
7335
- * the segment again — behaviour no system menu has, and which left two
7336
- * panels open at once on a row with several chips.
7337
- */
7338
6366
  onDocumentPointerdown(event) {
7339
6367
  if (!this.open())
7340
6368
  return;
7341
6369
  const target = event.target;
7342
6370
  if (target && this._hostEl.nativeElement.contains(target))
7343
6371
  return;
7344
- this.open.set(false);
6372
+ this.onOpenChange.emit(false);
7345
6373
  }
7346
- /**
7347
- * Escape closes and hands the focus back to the segment's button. Without
7348
- * the hand-back the focus falls to `<body>` and Tab restarts from the top of
7349
- * the page: whoever opened the panel from the keyboard loses their place in
7350
- * the middle of the row.
7351
- */
7352
6374
  onEscape() {
7353
6375
  if (!this.open())
7354
6376
  return;
7355
- this.open.set(false);
6377
+ this.onOpenChange.emit(false);
7356
6378
  this.focusButton();
7357
6379
  }
7358
- /** Closes and returns the focus. Public for whoever needs to close from outside. */
7359
6380
  closeAndFocus() {
7360
- this.open.set(false);
6381
+ this.onOpenChange.emit(false);
7361
6382
  this.focusButton();
7362
6383
  }
7363
- focusButton() {
7364
- this._hostEl.nativeElement.querySelector('.mecx-filter-segment-btn')?.focus();
7365
- }
7366
6384
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterSegmentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7367
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyFilterSegmentComponent, isStandalone: true, selector: "monkey-filter-segment", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, readonlySegment: { classPropertyName: "readonlySegment", publicName: "readonlySegment", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", segmentClick: "segmentClick" }, host: { attributes: { "data-testid": "monkey-filter-segment" }, listeners: { "document:pointerdown": "onDocumentPointerdown($event)", "document:keydown.escape": "onEscape()" }, properties: { "class.mecx-filter-segment--open": "open()", "class.mecx-filter-segment--filled": "filled()" }, classAttribute: "mecx-filter-segment" }, viewQueries: [{ propertyName: "_menuEl", first: true, predicate: ["menu"], descendants: true, isSignal: true }], ngImport: i0, template: "<button\n class=\"mecx-filter-segment-btn\"\n type=\"button\"\n [attr.aria-expanded]=\"readonlySegment() ? null : open()\"\n [attr.aria-haspopup]=\"readonlySegment() ? null : 'listbox'\"\n (click)=\"toggle()\"\n>\n @if (icon()) {\n <i class=\"mk-i mk-i-{{ icon() }} mecx-filter-segment-icon\" aria-hidden=\"true\"></i>\n }\n <span class=\"mecx-filter-segment-label\">{{ label() }}</span>\n</button>\n\n@if (open()) {\n <div\n #menu\n class=\"mecx-filter-segment-menu\"\n animate.enter=\"mecx-filter-segment-menu--entering\"\n animate.leave=\"mecx-filter-segment-menu--leaving\"\n >\n <ng-content></ng-content>\n </div>\n}\n", styles: ["@charset \"UTF-8\";@keyframes mecx-fbv2-surface-in{0%{opacity:0;scale:1 var(--mecx-fbv2-scale-unfold);translate:0 calc(var(--mecx-fbv2-travel-anchored) * -1)}}@keyframes mecx-fbv2-surface-out{to{opacity:0;scale:1 var(--mecx-fbv2-scale-unfold);translate:0 calc(var(--mecx-fbv2-travel-anchored) * -1)}}@keyframes mecx-fbv2-surface-item-in{0%{opacity:0;translate:0 calc(var(--mecx-fbv2-travel-anchored) * -1)}}.mecx-filter-segment{--mecx-fbv2-duration-state: .15s;--mecx-fbv2-duration-enter: .2s;--mecx-fbv2-duration-exit: .15s;--mecx-fbv2-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-fbv2-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-fbv2-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-fbv2-scale-unfold: .94;--mecx-fbv2-travel-anchored: 4px;--mecx-fbv2-travel-slide: 16px;--mecx-fbv2-stagger: 25ms;--mecx-fbv2-control-height: 28px;--mecx-fbv2-pointer-target: 40px;--mecx-fbv2-radius: 8px;--mecx-fbv2-radius-item: 4px;--mecx-fbv2-fade-width: 48px}@media(prefers-reduced-motion:reduce){.mecx-filter-segment{--mecx-fbv2-duration-state: 1ms;--mecx-fbv2-duration-enter: 1ms;--mecx-fbv2-duration-exit: 1ms;--mecx-fbv2-scale-unfold: 1;--mecx-fbv2-travel-anchored: 0px;--mecx-fbv2-travel-slide: 0px;--mecx-fbv2-stagger: 0ms}}.mecx-filter-segment{position:relative;display:inline-flex;margin-right:-1px}.mecx-filter-segment-btn{display:inline-flex;align-items:center;gap:4px;height:var(--mecx-fbv2-control-height);padding-inline:8px;box-sizing:border-box;background:var(--mecx-color-gray-50);border:1px solid var(--mecx-color-gray-500);border-radius:0;color:var(--mecx-color-gray-700);font-family:inherit;cursor:pointer;outline:none;white-space:nowrap;position:relative;transition:background-color var(--mecx-fbv2-duration-state) var(--mecx-fbv2-ease-state),border-color var(--mecx-fbv2-duration-state) var(--mecx-fbv2-ease-state),color var(--mecx-fbv2-duration-state) var(--mecx-fbv2-ease-state)}.mecx-filter-segment-btn:after{content:\"\";position:absolute;inset:-6px 0}.mecx-filter-segment-btn:hover{background-color:var(--mecx-color-gray-200)}.mecx-filter-segment-btn:active{background-color:var(--mecx-color-gray-400)}.mecx-filter-segment-btn:focus-visible{border-color:var(--mecx-color-gray-900)}.mecx-filter-segment-btn:hover,.mecx-filter-segment-btn:focus-visible{z-index:1}.mecx-filter-segment--open{z-index:1}.mecx-filter-segment--open .mecx-filter-segment-btn{background-color:var(--mecx-color-gray-200)}.mecx-filter-segment--filled .mecx-filter-segment-btn{color:var(--mecx-color-gray-900)}.mecx-filter-segment-icon{display:inline-flex;flex-shrink:0;font-size:16px;color:var(--mecx-color-gray-600)}.mecx-filter-segment-label{font-size:12px;font-weight:500;line-height:16px;letter-spacing:.02em;color:inherit}.mecx-filter-segment-menu{position:fixed;margin-top:4px;z-index:100}.mecx-filter-segment-menu--entering{transform-origin:top;animation:mecx-fbv2-surface-in var(--mecx-fbv2-duration-enter) var(--mecx-fbv2-ease-enter)}.mecx-filter-segment-menu--entering monkey-filter-menu-item,.mecx-filter-segment-menu--entering monkey-divider{animation:mecx-fbv2-surface-item-in var(--mecx-fbv2-duration-enter) var(--mecx-fbv2-ease-enter) both}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(1){animation-delay:calc(var(--mecx-fbv2-stagger) * 1)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(2){animation-delay:calc(var(--mecx-fbv2-stagger) * 2)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(3){animation-delay:calc(var(--mecx-fbv2-stagger) * 3)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(4){animation-delay:calc(var(--mecx-fbv2-stagger) * 4)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(5){animation-delay:calc(var(--mecx-fbv2-stagger) * 5)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(6){animation-delay:calc(var(--mecx-fbv2-stagger) * 6)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(7){animation-delay:calc(var(--mecx-fbv2-stagger) * 7)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(8){animation-delay:calc(var(--mecx-fbv2-stagger) * 8)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(n+8){animation-delay:calc(var(--mecx-fbv2-stagger) * 8)}.mecx-filter-segment-menu--leaving{transform-origin:top;animation:mecx-fbv2-surface-out var(--mecx-fbv2-duration-exit) var(--mecx-fbv2-ease-exit)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
6385
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyFilterSegmentComponent, isStandalone: true, selector: "monkey-filter-segment", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, readonlySegment: { classPropertyName: "readonlySegment", publicName: "readonlySegment", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onOpenChange: "onOpenChange", onSegmentClick: "onSegmentClick" }, host: { attributes: { "data-testid": "monkey-filter-segment" }, listeners: { "document:pointerdown": "onDocumentPointerdown($event)", "document:keydown.escape": "onEscape()" }, properties: { "class.mecx-filter-segment--open": "open()", "class.mecx-filter-segment--filled": "filled()", "class.mecx-filter-segment--disabled": "disabled()" }, classAttribute: "mecx-filter-segment" }, viewQueries: [{ propertyName: "_menuEl", first: true, predicate: ["menu"], descendants: true, isSignal: true }], ngImport: i0, template: "<button\n class=\"mecx-filter-segment-btn\"\n type=\"button\"\n [disabled]=\"disabled() || null\"\n [attr.aria-expanded]=\"readonlySegment() ? null : open()\"\n [attr.aria-haspopup]=\"readonlySegment() ? null : 'listbox'\"\n (click)=\"toggle()\"\n>\n @if (icon()) {\n <i class=\"mk-i mk-i-{{ icon() }} mecx-filter-segment-icon\" aria-hidden=\"true\"></i>\n }\n <span class=\"mecx-filter-segment-label\">{{ label() }}</span>\n</button>\n@if (open()) {\n <div\n #menu\n class=\"mecx-filter-segment-menu\"\n animate.enter=\"mecx-filter-segment-menu--entering\"\n animate.leave=\"mecx-filter-segment-menu--leaving\"\n >\n <ng-content></ng-content>\n </div>\n}\n", styles: ["@keyframes mecx-filter-bar-surface-in{0%{opacity:0;scale:1 var(--mecx-filter-bar-scale-unfold);translate:0 calc(var(--mecx-filter-bar-travel-anchored) * -1)}}@keyframes mecx-filter-bar-surface-out{to{opacity:0;scale:1 var(--mecx-filter-bar-scale-unfold);translate:0 calc(var(--mecx-filter-bar-travel-anchored) * -1)}}@keyframes mecx-filter-bar-surface-item-in{0%{opacity:0;translate:0 calc(var(--mecx-filter-bar-travel-anchored) * -1)}}.mecx-filter-segment{--mecx-filter-bar-duration-state: .15s;--mecx-filter-bar-duration-enter: .2s;--mecx-filter-bar-duration-exit: .15s;--mecx-filter-bar-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-filter-bar-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-filter-bar-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-filter-bar-scale-unfold: .94;--mecx-filter-bar-travel-anchored: 4px;--mecx-filter-bar-travel-slide: 16px;--mecx-filter-bar-stagger: 25ms;--mecx-filter-bar-control-height: 32px;--mecx-filter-bar-pointer-target: 40px;--mecx-filter-bar-reach: calc((var(--mecx-filter-bar-control-height) - var(--mecx-filter-bar-pointer-target)) / 2);--mecx-filter-bar-radius: 8px;--mecx-filter-bar-radius-item: 4px;--mecx-filter-bar-fade-width: 48px;--mecx-filter-bar-focus-reach: 4px;--mecx-filter-bar-z-raised: 1;--mecx-filter-bar-z-sticky: 2;--mecx-filter-bar-z-menu: 1000}@media(prefers-reduced-motion:reduce){.mecx-filter-segment{--mecx-filter-bar-duration-state: 1ms;--mecx-filter-bar-duration-enter: 1ms;--mecx-filter-bar-duration-exit: 1ms;--mecx-filter-bar-scale-unfold: 1;--mecx-filter-bar-travel-anchored: 0px;--mecx-filter-bar-travel-slide: 0px;--mecx-filter-bar-stagger: 0ms}}.mecx-filter-segment{position:relative;display:inline-flex;margin-right:-1px}.mecx-filter-segment-btn{display:inline-flex;align-items:center;gap:4px;height:var(--mecx-filter-bar-control-height);padding-inline:8px;box-sizing:border-box;background:var(--mecx-color-gray-50);border:1px solid var(--mecx-color-gray-500);border-radius:0;color:var(--mecx-color-gray-700);font-family:inherit;cursor:pointer;outline:none;white-space:nowrap;position:relative;transition:background-color var(--mecx-filter-bar-duration-state) var(--mecx-filter-bar-ease-state),border-color var(--mecx-filter-bar-duration-state) var(--mecx-filter-bar-ease-state),color var(--mecx-filter-bar-duration-state) var(--mecx-filter-bar-ease-state)}.mecx-filter-segment-btn:after{content:\"\";position:absolute;inset:var(--mecx-filter-bar-reach) 0}.mecx-filter-segment-btn:hover{background-color:var(--mecx-color-gray-200)}.mecx-filter-segment-btn:active{background-color:var(--mecx-color-gray-400)}.mecx-filter-segment-btn:focus-visible{border-color:var(--mecx-color-gray-900)}.mecx-filter-segment-btn:disabled{background-color:var(--mecx-color-gray-50);color:var(--mecx-color-gray-400);border-color:var(--mecx-color-gray-400);cursor:not-allowed}.mecx-filter-segment-btn:hover,.mecx-filter-segment-btn:focus-visible{z-index:var(--mecx-filter-bar-z-raised)}.mecx-filter-segment--open{z-index:var(--mecx-filter-bar-z-menu)}.mecx-filter-segment--open .mecx-filter-segment-btn{background-color:var(--mecx-color-gray-200)}.mecx-filter-segment--filled .mecx-filter-segment-btn{color:var(--mecx-color-gray-900)}.mecx-filter-segment--disabled .mecx-filter-segment-btn,.mecx-filter-segment--filled.mecx-filter-segment--disabled .mecx-filter-segment-btn{color:var(--mecx-color-gray-400)}.mecx-filter-segment-icon{display:inline-flex;flex-shrink:0;font-size:16px;color:var(--mecx-color-gray-600)}.mecx-filter-segment--disabled .mecx-filter-segment-icon{color:var(--mecx-color-gray-400)}.mecx-filter-segment-label{font-size:12px;font-weight:500;line-height:16px;letter-spacing:.02em;color:inherit}.mecx-filter-segment-menu{position:fixed;margin-top:4px;z-index:var(--mecx-filter-bar-z-menu)}.mecx-filter-segment-menu--entering{transform-origin:top;animation:mecx-filter-bar-surface-in var(--mecx-filter-bar-duration-enter) var(--mecx-filter-bar-ease-enter)}.mecx-filter-segment-menu--entering monkey-filter-menu-item,.mecx-filter-segment-menu--entering monkey-divider{animation:mecx-filter-bar-surface-item-in var(--mecx-filter-bar-duration-enter) var(--mecx-filter-bar-ease-enter) both}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(1){animation-delay:calc(var(--mecx-filter-bar-stagger) * 1)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(2){animation-delay:calc(var(--mecx-filter-bar-stagger) * 2)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(3){animation-delay:calc(var(--mecx-filter-bar-stagger) * 3)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(4){animation-delay:calc(var(--mecx-filter-bar-stagger) * 4)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(5){animation-delay:calc(var(--mecx-filter-bar-stagger) * 5)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(6){animation-delay:calc(var(--mecx-filter-bar-stagger) * 6)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(7){animation-delay:calc(var(--mecx-filter-bar-stagger) * 7)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(8){animation-delay:calc(var(--mecx-filter-bar-stagger) * 8)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(n+8){animation-delay:calc(var(--mecx-filter-bar-stagger) * 8)}.mecx-filter-segment-menu--leaving{transform-origin:top;animation:mecx-filter-bar-surface-out var(--mecx-filter-bar-duration-exit) var(--mecx-filter-bar-ease-exit)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
7368
6386
  }
7369
6387
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterSegmentComponent, decorators: [{
7370
6388
  type: Component,
@@ -7373,76 +6391,49 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
7373
6391
  class: 'mecx-filter-segment',
7374
6392
  '[class.mecx-filter-segment--open]': 'open()',
7375
6393
  '[class.mecx-filter-segment--filled]': 'filled()',
6394
+ '[class.mecx-filter-segment--disabled]': 'disabled()',
7376
6395
  '(document:pointerdown)': 'onDocumentPointerdown($event)',
7377
6396
  '(document:keydown.escape)': 'onEscape()'
7378
- }, template: "<button\n class=\"mecx-filter-segment-btn\"\n type=\"button\"\n [attr.aria-expanded]=\"readonlySegment() ? null : open()\"\n [attr.aria-haspopup]=\"readonlySegment() ? null : 'listbox'\"\n (click)=\"toggle()\"\n>\n @if (icon()) {\n <i class=\"mk-i mk-i-{{ icon() }} mecx-filter-segment-icon\" aria-hidden=\"true\"></i>\n }\n <span class=\"mecx-filter-segment-label\">{{ label() }}</span>\n</button>\n\n@if (open()) {\n <div\n #menu\n class=\"mecx-filter-segment-menu\"\n animate.enter=\"mecx-filter-segment-menu--entering\"\n animate.leave=\"mecx-filter-segment-menu--leaving\"\n >\n <ng-content></ng-content>\n </div>\n}\n", styles: ["@charset \"UTF-8\";@keyframes mecx-fbv2-surface-in{0%{opacity:0;scale:1 var(--mecx-fbv2-scale-unfold);translate:0 calc(var(--mecx-fbv2-travel-anchored) * -1)}}@keyframes mecx-fbv2-surface-out{to{opacity:0;scale:1 var(--mecx-fbv2-scale-unfold);translate:0 calc(var(--mecx-fbv2-travel-anchored) * -1)}}@keyframes mecx-fbv2-surface-item-in{0%{opacity:0;translate:0 calc(var(--mecx-fbv2-travel-anchored) * -1)}}.mecx-filter-segment{--mecx-fbv2-duration-state: .15s;--mecx-fbv2-duration-enter: .2s;--mecx-fbv2-duration-exit: .15s;--mecx-fbv2-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-fbv2-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-fbv2-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-fbv2-scale-unfold: .94;--mecx-fbv2-travel-anchored: 4px;--mecx-fbv2-travel-slide: 16px;--mecx-fbv2-stagger: 25ms;--mecx-fbv2-control-height: 28px;--mecx-fbv2-pointer-target: 40px;--mecx-fbv2-radius: 8px;--mecx-fbv2-radius-item: 4px;--mecx-fbv2-fade-width: 48px}@media(prefers-reduced-motion:reduce){.mecx-filter-segment{--mecx-fbv2-duration-state: 1ms;--mecx-fbv2-duration-enter: 1ms;--mecx-fbv2-duration-exit: 1ms;--mecx-fbv2-scale-unfold: 1;--mecx-fbv2-travel-anchored: 0px;--mecx-fbv2-travel-slide: 0px;--mecx-fbv2-stagger: 0ms}}.mecx-filter-segment{position:relative;display:inline-flex;margin-right:-1px}.mecx-filter-segment-btn{display:inline-flex;align-items:center;gap:4px;height:var(--mecx-fbv2-control-height);padding-inline:8px;box-sizing:border-box;background:var(--mecx-color-gray-50);border:1px solid var(--mecx-color-gray-500);border-radius:0;color:var(--mecx-color-gray-700);font-family:inherit;cursor:pointer;outline:none;white-space:nowrap;position:relative;transition:background-color var(--mecx-fbv2-duration-state) var(--mecx-fbv2-ease-state),border-color var(--mecx-fbv2-duration-state) var(--mecx-fbv2-ease-state),color var(--mecx-fbv2-duration-state) var(--mecx-fbv2-ease-state)}.mecx-filter-segment-btn:after{content:\"\";position:absolute;inset:-6px 0}.mecx-filter-segment-btn:hover{background-color:var(--mecx-color-gray-200)}.mecx-filter-segment-btn:active{background-color:var(--mecx-color-gray-400)}.mecx-filter-segment-btn:focus-visible{border-color:var(--mecx-color-gray-900)}.mecx-filter-segment-btn:hover,.mecx-filter-segment-btn:focus-visible{z-index:1}.mecx-filter-segment--open{z-index:1}.mecx-filter-segment--open .mecx-filter-segment-btn{background-color:var(--mecx-color-gray-200)}.mecx-filter-segment--filled .mecx-filter-segment-btn{color:var(--mecx-color-gray-900)}.mecx-filter-segment-icon{display:inline-flex;flex-shrink:0;font-size:16px;color:var(--mecx-color-gray-600)}.mecx-filter-segment-label{font-size:12px;font-weight:500;line-height:16px;letter-spacing:.02em;color:inherit}.mecx-filter-segment-menu{position:fixed;margin-top:4px;z-index:100}.mecx-filter-segment-menu--entering{transform-origin:top;animation:mecx-fbv2-surface-in var(--mecx-fbv2-duration-enter) var(--mecx-fbv2-ease-enter)}.mecx-filter-segment-menu--entering monkey-filter-menu-item,.mecx-filter-segment-menu--entering monkey-divider{animation:mecx-fbv2-surface-item-in var(--mecx-fbv2-duration-enter) var(--mecx-fbv2-ease-enter) both}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(1){animation-delay:calc(var(--mecx-fbv2-stagger) * 1)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(2){animation-delay:calc(var(--mecx-fbv2-stagger) * 2)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(3){animation-delay:calc(var(--mecx-fbv2-stagger) * 3)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(4){animation-delay:calc(var(--mecx-fbv2-stagger) * 4)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(5){animation-delay:calc(var(--mecx-fbv2-stagger) * 5)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(6){animation-delay:calc(var(--mecx-fbv2-stagger) * 6)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(7){animation-delay:calc(var(--mecx-fbv2-stagger) * 7)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(8){animation-delay:calc(var(--mecx-fbv2-stagger) * 8)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(n+8){animation-delay:calc(var(--mecx-fbv2-stagger) * 8)}.mecx-filter-segment-menu--leaving{transform-origin:top;animation:mecx-fbv2-surface-out var(--mecx-fbv2-duration-exit) var(--mecx-fbv2-ease-exit)}\n"] }]
7379
- }], ctorParameters: () => [], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], readonlySegment: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonlySegment", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], segmentClick: [{ type: i0.Output, args: ["segmentClick"] }], _menuEl: [{ type: i0.ViewChild, args: ['menu', { isSignal: true }] }] } });
6397
+ }, template: "<button\n class=\"mecx-filter-segment-btn\"\n type=\"button\"\n [disabled]=\"disabled() || null\"\n [attr.aria-expanded]=\"readonlySegment() ? null : open()\"\n [attr.aria-haspopup]=\"readonlySegment() ? null : 'listbox'\"\n (click)=\"toggle()\"\n>\n @if (icon()) {\n <i class=\"mk-i mk-i-{{ icon() }} mecx-filter-segment-icon\" aria-hidden=\"true\"></i>\n }\n <span class=\"mecx-filter-segment-label\">{{ label() }}</span>\n</button>\n@if (open()) {\n <div\n #menu\n class=\"mecx-filter-segment-menu\"\n animate.enter=\"mecx-filter-segment-menu--entering\"\n animate.leave=\"mecx-filter-segment-menu--leaving\"\n >\n <ng-content></ng-content>\n </div>\n}\n", styles: ["@keyframes mecx-filter-bar-surface-in{0%{opacity:0;scale:1 var(--mecx-filter-bar-scale-unfold);translate:0 calc(var(--mecx-filter-bar-travel-anchored) * -1)}}@keyframes mecx-filter-bar-surface-out{to{opacity:0;scale:1 var(--mecx-filter-bar-scale-unfold);translate:0 calc(var(--mecx-filter-bar-travel-anchored) * -1)}}@keyframes mecx-filter-bar-surface-item-in{0%{opacity:0;translate:0 calc(var(--mecx-filter-bar-travel-anchored) * -1)}}.mecx-filter-segment{--mecx-filter-bar-duration-state: .15s;--mecx-filter-bar-duration-enter: .2s;--mecx-filter-bar-duration-exit: .15s;--mecx-filter-bar-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-filter-bar-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-filter-bar-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-filter-bar-scale-unfold: .94;--mecx-filter-bar-travel-anchored: 4px;--mecx-filter-bar-travel-slide: 16px;--mecx-filter-bar-stagger: 25ms;--mecx-filter-bar-control-height: 32px;--mecx-filter-bar-pointer-target: 40px;--mecx-filter-bar-reach: calc((var(--mecx-filter-bar-control-height) - var(--mecx-filter-bar-pointer-target)) / 2);--mecx-filter-bar-radius: 8px;--mecx-filter-bar-radius-item: 4px;--mecx-filter-bar-fade-width: 48px;--mecx-filter-bar-focus-reach: 4px;--mecx-filter-bar-z-raised: 1;--mecx-filter-bar-z-sticky: 2;--mecx-filter-bar-z-menu: 1000}@media(prefers-reduced-motion:reduce){.mecx-filter-segment{--mecx-filter-bar-duration-state: 1ms;--mecx-filter-bar-duration-enter: 1ms;--mecx-filter-bar-duration-exit: 1ms;--mecx-filter-bar-scale-unfold: 1;--mecx-filter-bar-travel-anchored: 0px;--mecx-filter-bar-travel-slide: 0px;--mecx-filter-bar-stagger: 0ms}}.mecx-filter-segment{position:relative;display:inline-flex;margin-right:-1px}.mecx-filter-segment-btn{display:inline-flex;align-items:center;gap:4px;height:var(--mecx-filter-bar-control-height);padding-inline:8px;box-sizing:border-box;background:var(--mecx-color-gray-50);border:1px solid var(--mecx-color-gray-500);border-radius:0;color:var(--mecx-color-gray-700);font-family:inherit;cursor:pointer;outline:none;white-space:nowrap;position:relative;transition:background-color var(--mecx-filter-bar-duration-state) var(--mecx-filter-bar-ease-state),border-color var(--mecx-filter-bar-duration-state) var(--mecx-filter-bar-ease-state),color var(--mecx-filter-bar-duration-state) var(--mecx-filter-bar-ease-state)}.mecx-filter-segment-btn:after{content:\"\";position:absolute;inset:var(--mecx-filter-bar-reach) 0}.mecx-filter-segment-btn:hover{background-color:var(--mecx-color-gray-200)}.mecx-filter-segment-btn:active{background-color:var(--mecx-color-gray-400)}.mecx-filter-segment-btn:focus-visible{border-color:var(--mecx-color-gray-900)}.mecx-filter-segment-btn:disabled{background-color:var(--mecx-color-gray-50);color:var(--mecx-color-gray-400);border-color:var(--mecx-color-gray-400);cursor:not-allowed}.mecx-filter-segment-btn:hover,.mecx-filter-segment-btn:focus-visible{z-index:var(--mecx-filter-bar-z-raised)}.mecx-filter-segment--open{z-index:var(--mecx-filter-bar-z-menu)}.mecx-filter-segment--open .mecx-filter-segment-btn{background-color:var(--mecx-color-gray-200)}.mecx-filter-segment--filled .mecx-filter-segment-btn{color:var(--mecx-color-gray-900)}.mecx-filter-segment--disabled .mecx-filter-segment-btn,.mecx-filter-segment--filled.mecx-filter-segment--disabled .mecx-filter-segment-btn{color:var(--mecx-color-gray-400)}.mecx-filter-segment-icon{display:inline-flex;flex-shrink:0;font-size:16px;color:var(--mecx-color-gray-600)}.mecx-filter-segment--disabled .mecx-filter-segment-icon{color:var(--mecx-color-gray-400)}.mecx-filter-segment-label{font-size:12px;font-weight:500;line-height:16px;letter-spacing:.02em;color:inherit}.mecx-filter-segment-menu{position:fixed;margin-top:4px;z-index:var(--mecx-filter-bar-z-menu)}.mecx-filter-segment-menu--entering{transform-origin:top;animation:mecx-filter-bar-surface-in var(--mecx-filter-bar-duration-enter) var(--mecx-filter-bar-ease-enter)}.mecx-filter-segment-menu--entering monkey-filter-menu-item,.mecx-filter-segment-menu--entering monkey-divider{animation:mecx-filter-bar-surface-item-in var(--mecx-filter-bar-duration-enter) var(--mecx-filter-bar-ease-enter) both}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(1){animation-delay:calc(var(--mecx-filter-bar-stagger) * 1)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(2){animation-delay:calc(var(--mecx-filter-bar-stagger) * 2)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(3){animation-delay:calc(var(--mecx-filter-bar-stagger) * 3)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(4){animation-delay:calc(var(--mecx-filter-bar-stagger) * 4)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(5){animation-delay:calc(var(--mecx-filter-bar-stagger) * 5)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(6){animation-delay:calc(var(--mecx-filter-bar-stagger) * 6)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(7){animation-delay:calc(var(--mecx-filter-bar-stagger) * 7)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(8){animation-delay:calc(var(--mecx-filter-bar-stagger) * 8)}.mecx-filter-segment-menu--entering .mecx-filter-menu-items>:nth-child(n+8){animation-delay:calc(var(--mecx-filter-bar-stagger) * 8)}.mecx-filter-segment-menu--leaving{transform-origin:top;animation:mecx-filter-bar-surface-out var(--mecx-filter-bar-duration-exit) var(--mecx-filter-bar-ease-exit)}\n"] }]
6398
+ }], ctorParameters: () => [], propDecorators: { _menuEl: [{ type: i0.ViewChild, args: ['menu', { isSignal: true }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], readonlySegment: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonlySegment", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }], onOpenChange: [{ type: i0.Output, args: ["onOpenChange"] }], onSegmentClick: [{ type: i0.Output, args: ["onSegmentClick"] }] } });
7380
6399
 
7381
6400
  /** ************************
7382
6401
  * Copyright Monkey Exchange. All Rights Reserved
7383
6402
  * This style guide was developed by Monkey Exchange Team
7384
6403
  * MIT Licence
7385
6404
  ************************* */
7386
- /**
7387
- * The button that adds a filter, and the panel of categories it opens.
7388
- *
7389
- * It is always the LAST slot of the row. While the bar is empty the trigger is
7390
- * the CALL to action and earns its label; with filters on screen it becomes
7391
- * the ADDITION, and a 28px square is enough.
7392
- *
7393
- * Both are 28px tall — the same as a chip segment — because the button turns
7394
- * into a chip in place, and 1px of difference would show up as a jump at the
7395
- * moment of the swap.
7396
- */
7397
6405
  class MonkeyFilterTriggerComponent {
7398
6406
  constructor() {
6407
+ this._hostEl = inject(ElementRef);
6408
+ this._menuEl = viewChild('menu', ...(ngDevMode ? [{ debugName: "_menuEl" }] : /* istanbul ignore next */ []));
7399
6409
  this.variant = input('text', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
7400
- /** Icon font name, without the `mk-i-` prefix. */
7401
6410
  this.icon = input('filter', ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
7402
- this.text = input('Filtro', ...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
7403
- this.ariaLabel = input('Adicionar filtro', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
6411
+ this.text = input('', ...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
6412
+ this.ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
7404
6413
  this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
7405
- /**
7406
- * The panel leaves with no exit animation.
7407
- *
7408
- * It exists for ONE case: when the closing goes along with the trigger
7409
- * itself changing place. The panel is a child of the button, so it travels
7410
- * with it — and a fade on an element that has just teleported 160px does not
7411
- * read as an exit, it reads as a glitch. Closing by Escape or by an outside
7412
- * click is not that case and keeps its fade.
7413
- */
7414
6414
  this.immediateExit = input(false, { ...(ngDevMode ? { debugName: "immediateExit" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
7415
- this.open = model(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
7416
- /**
7417
- * `aria-label` only on the variant with no visible label. Where there is a
7418
- * label, an `aria-label` over it would swap the name the user reads for one
7419
- * they cannot see — breaking voice control and the "Label in Name" criterion.
7420
- */
6415
+ this.open = input(false, { ...(ngDevMode ? { debugName: "open" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
6416
+ this.alignment = input(null, ...(ngDevMode ? [{ debugName: "alignment" }] : /* istanbul ignore next */ []));
6417
+ this.onOpenChange = output();
7421
6418
  this.ariaLabelAttr = computed(() => {
7422
6419
  return this.variant() === 'icon' ? this.ariaLabel() || null : null;
7423
6420
  }, ...(ngDevMode ? [{ debugName: "ariaLabelAttr" }] : /* istanbul ignore next */ []));
7424
- this._hostEl = inject(ElementRef);
7425
- this._menuEl = viewChild('menu', ...(ngDevMode ? [{ debugName: "_menuEl" }] : /* istanbul ignore next */ []));
6421
+ this.menuAlignment = computed(() => {
6422
+ return this.alignment() ?? (this.variant() === 'text' ? 'start' : 'end');
6423
+ }, ...(ngDevMode ? [{ debugName: "menuAlignment" }] : /* istanbul ignore next */ []));
7426
6424
  effect((onCleanup) => {
7427
6425
  const menu = this._menuEl()?.nativeElement;
7428
6426
  if (!menu)
7429
6427
  return;
7430
- // Aligned to the END, so the panel's right edge meets the button's own
7431
- // however wide the button happens to be — the label and the square are
7432
- // very different widths and the panel must not jump between them.
7433
- //
7434
- // Going out of sight closes: a `fixed` panel anchored to a trigger that
7435
- // has scrolled away hangs in the middle of the content with no visible
7436
- // anchor.
7437
- onCleanup(anchorMenu(this._hostEl.nativeElement, menu, 'end', () => {
7438
- return this.open.set(false);
6428
+ onCleanup(anchorMenu(this._hostEl.nativeElement, menu, this.menuAlignment(), () => {
6429
+ return this.onOpenChange.emit(false);
7439
6430
  }));
7440
6431
  });
7441
6432
  }
7442
6433
  toggle() {
7443
6434
  if (this.disabled())
7444
6435
  return;
7445
- this.open.set(!this.open());
6436
+ this.onOpenChange.emit(!this.open());
7446
6437
  }
7447
6438
  onDocumentPointerdown(event) {
7448
6439
  if (!this.open())
@@ -7450,16 +6441,16 @@ class MonkeyFilterTriggerComponent {
7450
6441
  const target = event.target;
7451
6442
  if (target && this._hostEl.nativeElement.contains(target))
7452
6443
  return;
7453
- this.open.set(false);
6444
+ this.onOpenChange.emit(false);
7454
6445
  }
7455
6446
  onEscape() {
7456
6447
  if (!this.open())
7457
6448
  return;
7458
- this.open.set(false);
6449
+ this.onOpenChange.emit(false);
7459
6450
  this._hostEl.nativeElement.querySelector('.mecx-filter-trigger-btn')?.focus();
7460
6451
  }
7461
6452
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterTriggerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7462
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyFilterTriggerComponent, isStandalone: true, selector: "monkey-filter-trigger", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, immediateExit: { classPropertyName: "immediateExit", publicName: "immediateExit", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { attributes: { "data-testid": "monkey-filter-trigger" }, listeners: { "document:pointerdown": "onDocumentPointerdown($event)", "document:keydown.escape": "onEscape()" }, properties: { "class.mecx-filter-trigger--text": "variant() === \"text\"", "class.mecx-filter-trigger--icon": "variant() === \"icon\"", "class.mecx-filter-trigger--open": "open()" }, classAttribute: "mecx-filter-trigger" }, viewQueries: [{ propertyName: "_menuEl", first: true, predicate: ["menu"], descendants: true, isSignal: true }], ngImport: i0, template: "<button\n class=\"mecx-filter-trigger-btn\"\n type=\"button\"\n [disabled]=\"disabled() || null\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-label]=\"ariaLabelAttr()\"\n aria-haspopup=\"listbox\"\n (click)=\"toggle()\"\n>\n <!-- The glyph comes BEFORE the label, and there is no caret \u2014 the trigger is\n an action, not a select. -->\n <i class=\"mk-i mk-i-{{ icon() }} mecx-filter-trigger-icon\" aria-hidden=\"true\"></i>\n @if (variant() === 'text') {\n <span class=\"mecx-filter-trigger-text\">{{ text() }}</span>\n }\n</button>\n\n@if (open()) {\n <div\n #menu\n class=\"mecx-filter-trigger-menu\"\n animate.enter=\"mecx-filter-trigger-menu--entering\"\n [animate.leave]=\"immediateExit() ? '' : 'mecx-filter-trigger-menu--leaving'\"\n >\n <ng-content></ng-content>\n </div>\n}\n", styles: ["@keyframes mecx-fbv2-surface-in{0%{opacity:0;scale:1 var(--mecx-fbv2-scale-unfold);translate:0 calc(var(--mecx-fbv2-travel-anchored) * -1)}}@keyframes mecx-fbv2-surface-out{to{opacity:0;scale:1 var(--mecx-fbv2-scale-unfold);translate:0 calc(var(--mecx-fbv2-travel-anchored) * -1)}}@keyframes mecx-fbv2-surface-item-in{0%{opacity:0;translate:0 calc(var(--mecx-fbv2-travel-anchored) * -1)}}.mecx-filter-trigger{display:inline-flex;position:relative}.mecx-filter-trigger-btn{display:inline-flex;align-items:center;justify-content:center;gap:4px;height:var(--mecx-fbv2-control-height);box-sizing:border-box;background-color:var(--mecx-color-white);color:var(--mecx-color-gray-900);border:1px solid var(--mecx-color-gray-500);border-radius:var(--mecx-fbv2-radius);font-family:inherit;cursor:pointer;outline:none;white-space:nowrap;position:relative;transition:background-color var(--mecx-fbv2-duration-state) var(--mecx-fbv2-ease-state),color var(--mecx-fbv2-duration-state) var(--mecx-fbv2-ease-state)}.mecx-filter-trigger-btn:after{content:\"\";position:absolute;top:50%;left:50%;translate:-50% -50%;width:max(100%,var(--mecx-fbv2-pointer-target));height:max(100%,var(--mecx-fbv2-pointer-target))}.mecx-filter-trigger-btn:hover:not(:disabled){color:var(--mecx-color-theme-main)}.mecx-filter-trigger-btn:focus-visible{outline:2px solid var(--mecx-color-theme-main);outline-offset:1px}.mecx-filter-trigger-btn:disabled{background-color:transparent;border-color:transparent;color:var(--mecx-color-gray-400);cursor:not-allowed}.mecx-filter-trigger--open .mecx-filter-trigger-btn{color:var(--mecx-color-theme-main)}.mecx-filter-trigger--text .mecx-filter-trigger-btn{padding-inline:7px 11px}.mecx-filter-trigger--icon .mecx-filter-trigger-btn{width:var(--mecx-fbv2-control-height);padding-inline:0}.mecx-filter-trigger-icon{display:inline-flex;flex-shrink:0;font-size:16px}.mecx-filter-trigger-text{font-size:13px;font-weight:500;line-height:16px;letter-spacing:.03em}.mecx-filter-trigger-menu{position:fixed;margin-top:4px;z-index:100}.mecx-filter-trigger-menu--entering{transform-origin:top;animation:mecx-fbv2-surface-in var(--mecx-fbv2-duration-enter) var(--mecx-fbv2-ease-enter)}.mecx-filter-trigger-menu--entering monkey-filter-menu-item,.mecx-filter-trigger-menu--entering monkey-divider{animation:mecx-fbv2-surface-item-in var(--mecx-fbv2-duration-enter) var(--mecx-fbv2-ease-enter) both}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(1){animation-delay:calc(var(--mecx-fbv2-stagger) * 1)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(2){animation-delay:calc(var(--mecx-fbv2-stagger) * 2)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(3){animation-delay:calc(var(--mecx-fbv2-stagger) * 3)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(4){animation-delay:calc(var(--mecx-fbv2-stagger) * 4)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(5){animation-delay:calc(var(--mecx-fbv2-stagger) * 5)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(6){animation-delay:calc(var(--mecx-fbv2-stagger) * 6)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(7){animation-delay:calc(var(--mecx-fbv2-stagger) * 7)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(8){animation-delay:calc(var(--mecx-fbv2-stagger) * 8)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(n+8){animation-delay:calc(var(--mecx-fbv2-stagger) * 8)}.mecx-filter-trigger-menu--leaving{transform-origin:top;animation:mecx-fbv2-surface-out var(--mecx-fbv2-duration-exit) var(--mecx-fbv2-ease-exit)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
6453
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyFilterTriggerComponent, isStandalone: true, selector: "monkey-filter-trigger", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, immediateExit: { classPropertyName: "immediateExit", publicName: "immediateExit", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, alignment: { classPropertyName: "alignment", publicName: "alignment", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onOpenChange: "onOpenChange" }, host: { attributes: { "data-testid": "monkey-filter-trigger" }, listeners: { "document:pointerdown": "onDocumentPointerdown($event)", "document:keydown.escape": "onEscape()" }, properties: { "class.mecx-filter-trigger--text": "variant() === \"text\"", "class.mecx-filter-trigger--icon": "variant() === \"icon\"", "class.mecx-filter-trigger--open": "open()" }, classAttribute: "mecx-filter-trigger" }, viewQueries: [{ propertyName: "_menuEl", first: true, predicate: ["menu"], descendants: true, isSignal: true }], ngImport: i0, template: "<button\n class=\"mecx-filter-trigger-btn\"\n type=\"button\"\n [disabled]=\"disabled() || null\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-label]=\"ariaLabelAttr()\"\n aria-haspopup=\"listbox\"\n (click)=\"toggle()\"\n>\n <i class=\"mk-i mk-i-{{ icon() }} mecx-filter-trigger-icon\" aria-hidden=\"true\"></i>\n @if (variant() === 'text') {\n <span class=\"mecx-filter-trigger-text\">{{ text() }}</span>\n }\n</button>\n@if (open()) {\n <div\n #menu\n class=\"mecx-filter-trigger-menu\"\n animate.enter=\"mecx-filter-trigger-menu--entering\"\n [animate.leave]=\"immediateExit() ? '' : 'mecx-filter-trigger-menu--leaving'\"\n >\n <ng-content></ng-content>\n </div>\n}\n", styles: ["@keyframes mecx-filter-bar-surface-in{0%{opacity:0;scale:1 var(--mecx-filter-bar-scale-unfold);translate:0 calc(var(--mecx-filter-bar-travel-anchored) * -1)}}@keyframes mecx-filter-bar-surface-out{to{opacity:0;scale:1 var(--mecx-filter-bar-scale-unfold);translate:0 calc(var(--mecx-filter-bar-travel-anchored) * -1)}}@keyframes mecx-filter-bar-surface-item-in{0%{opacity:0;translate:0 calc(var(--mecx-filter-bar-travel-anchored) * -1)}}.mecx-filter-trigger{--mecx-filter-bar-duration-state: .15s;--mecx-filter-bar-duration-enter: .2s;--mecx-filter-bar-duration-exit: .15s;--mecx-filter-bar-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-filter-bar-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-filter-bar-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-filter-bar-scale-unfold: .94;--mecx-filter-bar-travel-anchored: 4px;--mecx-filter-bar-travel-slide: 16px;--mecx-filter-bar-stagger: 25ms;--mecx-filter-bar-control-height: 32px;--mecx-filter-bar-pointer-target: 40px;--mecx-filter-bar-reach: calc((var(--mecx-filter-bar-control-height) - var(--mecx-filter-bar-pointer-target)) / 2);--mecx-filter-bar-radius: 8px;--mecx-filter-bar-radius-item: 4px;--mecx-filter-bar-fade-width: 48px;--mecx-filter-bar-focus-reach: 4px;--mecx-filter-bar-z-raised: 1;--mecx-filter-bar-z-sticky: 2;--mecx-filter-bar-z-menu: 1000}@media(prefers-reduced-motion:reduce){.mecx-filter-trigger{--mecx-filter-bar-duration-state: 1ms;--mecx-filter-bar-duration-enter: 1ms;--mecx-filter-bar-duration-exit: 1ms;--mecx-filter-bar-scale-unfold: 1;--mecx-filter-bar-travel-anchored: 0px;--mecx-filter-bar-travel-slide: 0px;--mecx-filter-bar-stagger: 0ms}}.mecx-filter-trigger{display:inline-flex;position:relative}.mecx-filter-trigger-btn{display:inline-flex;align-items:center;justify-content:center;gap:4px;height:var(--mecx-filter-bar-control-height);box-sizing:border-box;background-color:var(--mecx-color-white);color:var(--mecx-color-gray-900);border:1px solid var(--mecx-color-gray-500);border-radius:var(--mecx-filter-bar-radius);font-family:inherit;cursor:pointer;outline:none;white-space:nowrap;position:relative;transition:background-color var(--mecx-filter-bar-duration-state) var(--mecx-filter-bar-ease-state),color var(--mecx-filter-bar-duration-state) var(--mecx-filter-bar-ease-state)}.mecx-filter-trigger-btn:after{content:\"\";position:absolute;top:50%;left:50%;translate:-50% -50%;width:max(100%,var(--mecx-filter-bar-pointer-target));height:max(100%,var(--mecx-filter-bar-pointer-target))}.mecx-filter-trigger-btn:hover:not(:disabled){color:var(--mecx-color-theme-main)}.mecx-filter-trigger-btn:focus-visible{outline:2px solid var(--mecx-color-theme-main);outline-offset:1px}.mecx-filter-trigger-btn:disabled{background-color:transparent;border-color:transparent;color:var(--mecx-color-gray-400);cursor:not-allowed}.mecx-filter-trigger--open{z-index:var(--mecx-filter-bar-z-menu)}.mecx-filter-trigger--open .mecx-filter-trigger-btn{color:var(--mecx-color-theme-main)}.mecx-filter-trigger--text .mecx-filter-trigger-btn{padding-inline:7px 11px}.mecx-filter-trigger--icon .mecx-filter-trigger-btn{width:var(--mecx-filter-bar-control-height);padding-inline:0}.mecx-filter-trigger-icon{display:inline-flex;flex-shrink:0;font-size:16px}.mecx-filter-trigger-text{font-size:13px;font-weight:500;line-height:16px;letter-spacing:.03em}.mecx-filter-trigger-menu{position:fixed;margin-top:4px;z-index:var(--mecx-filter-bar-z-menu)}.mecx-filter-trigger-menu--entering{transform-origin:top;animation:mecx-filter-bar-surface-in var(--mecx-filter-bar-duration-enter) var(--mecx-filter-bar-ease-enter)}.mecx-filter-trigger-menu--entering monkey-filter-menu-item,.mecx-filter-trigger-menu--entering monkey-divider{animation:mecx-filter-bar-surface-item-in var(--mecx-filter-bar-duration-enter) var(--mecx-filter-bar-ease-enter) both}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(1){animation-delay:calc(var(--mecx-filter-bar-stagger) * 1)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(2){animation-delay:calc(var(--mecx-filter-bar-stagger) * 2)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(3){animation-delay:calc(var(--mecx-filter-bar-stagger) * 3)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(4){animation-delay:calc(var(--mecx-filter-bar-stagger) * 4)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(5){animation-delay:calc(var(--mecx-filter-bar-stagger) * 5)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(6){animation-delay:calc(var(--mecx-filter-bar-stagger) * 6)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(7){animation-delay:calc(var(--mecx-filter-bar-stagger) * 7)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(8){animation-delay:calc(var(--mecx-filter-bar-stagger) * 8)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(n+8){animation-delay:calc(var(--mecx-filter-bar-stagger) * 8)}.mecx-filter-trigger-menu--leaving{transform-origin:top;animation:mecx-filter-bar-surface-out var(--mecx-filter-bar-duration-exit) var(--mecx-filter-bar-ease-exit)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
7463
6454
  }
7464
6455
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterTriggerComponent, decorators: [{
7465
6456
  type: Component,
@@ -7471,44 +6462,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
7471
6462
  '[class.mecx-filter-trigger--open]': 'open()',
7472
6463
  '(document:pointerdown)': 'onDocumentPointerdown($event)',
7473
6464
  '(document:keydown.escape)': 'onEscape()'
7474
- }, template: "<button\n class=\"mecx-filter-trigger-btn\"\n type=\"button\"\n [disabled]=\"disabled() || null\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-label]=\"ariaLabelAttr()\"\n aria-haspopup=\"listbox\"\n (click)=\"toggle()\"\n>\n <!-- The glyph comes BEFORE the label, and there is no caret \u2014 the trigger is\n an action, not a select. -->\n <i class=\"mk-i mk-i-{{ icon() }} mecx-filter-trigger-icon\" aria-hidden=\"true\"></i>\n @if (variant() === 'text') {\n <span class=\"mecx-filter-trigger-text\">{{ text() }}</span>\n }\n</button>\n\n@if (open()) {\n <div\n #menu\n class=\"mecx-filter-trigger-menu\"\n animate.enter=\"mecx-filter-trigger-menu--entering\"\n [animate.leave]=\"immediateExit() ? '' : 'mecx-filter-trigger-menu--leaving'\"\n >\n <ng-content></ng-content>\n </div>\n}\n", styles: ["@keyframes mecx-fbv2-surface-in{0%{opacity:0;scale:1 var(--mecx-fbv2-scale-unfold);translate:0 calc(var(--mecx-fbv2-travel-anchored) * -1)}}@keyframes mecx-fbv2-surface-out{to{opacity:0;scale:1 var(--mecx-fbv2-scale-unfold);translate:0 calc(var(--mecx-fbv2-travel-anchored) * -1)}}@keyframes mecx-fbv2-surface-item-in{0%{opacity:0;translate:0 calc(var(--mecx-fbv2-travel-anchored) * -1)}}.mecx-filter-trigger{display:inline-flex;position:relative}.mecx-filter-trigger-btn{display:inline-flex;align-items:center;justify-content:center;gap:4px;height:var(--mecx-fbv2-control-height);box-sizing:border-box;background-color:var(--mecx-color-white);color:var(--mecx-color-gray-900);border:1px solid var(--mecx-color-gray-500);border-radius:var(--mecx-fbv2-radius);font-family:inherit;cursor:pointer;outline:none;white-space:nowrap;position:relative;transition:background-color var(--mecx-fbv2-duration-state) var(--mecx-fbv2-ease-state),color var(--mecx-fbv2-duration-state) var(--mecx-fbv2-ease-state)}.mecx-filter-trigger-btn:after{content:\"\";position:absolute;top:50%;left:50%;translate:-50% -50%;width:max(100%,var(--mecx-fbv2-pointer-target));height:max(100%,var(--mecx-fbv2-pointer-target))}.mecx-filter-trigger-btn:hover:not(:disabled){color:var(--mecx-color-theme-main)}.mecx-filter-trigger-btn:focus-visible{outline:2px solid var(--mecx-color-theme-main);outline-offset:1px}.mecx-filter-trigger-btn:disabled{background-color:transparent;border-color:transparent;color:var(--mecx-color-gray-400);cursor:not-allowed}.mecx-filter-trigger--open .mecx-filter-trigger-btn{color:var(--mecx-color-theme-main)}.mecx-filter-trigger--text .mecx-filter-trigger-btn{padding-inline:7px 11px}.mecx-filter-trigger--icon .mecx-filter-trigger-btn{width:var(--mecx-fbv2-control-height);padding-inline:0}.mecx-filter-trigger-icon{display:inline-flex;flex-shrink:0;font-size:16px}.mecx-filter-trigger-text{font-size:13px;font-weight:500;line-height:16px;letter-spacing:.03em}.mecx-filter-trigger-menu{position:fixed;margin-top:4px;z-index:100}.mecx-filter-trigger-menu--entering{transform-origin:top;animation:mecx-fbv2-surface-in var(--mecx-fbv2-duration-enter) var(--mecx-fbv2-ease-enter)}.mecx-filter-trigger-menu--entering monkey-filter-menu-item,.mecx-filter-trigger-menu--entering monkey-divider{animation:mecx-fbv2-surface-item-in var(--mecx-fbv2-duration-enter) var(--mecx-fbv2-ease-enter) both}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(1){animation-delay:calc(var(--mecx-fbv2-stagger) * 1)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(2){animation-delay:calc(var(--mecx-fbv2-stagger) * 2)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(3){animation-delay:calc(var(--mecx-fbv2-stagger) * 3)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(4){animation-delay:calc(var(--mecx-fbv2-stagger) * 4)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(5){animation-delay:calc(var(--mecx-fbv2-stagger) * 5)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(6){animation-delay:calc(var(--mecx-fbv2-stagger) * 6)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(7){animation-delay:calc(var(--mecx-fbv2-stagger) * 7)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(8){animation-delay:calc(var(--mecx-fbv2-stagger) * 8)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(n+8){animation-delay:calc(var(--mecx-fbv2-stagger) * 8)}.mecx-filter-trigger-menu--leaving{transform-origin:top;animation:mecx-fbv2-surface-out var(--mecx-fbv2-duration-exit) var(--mecx-fbv2-ease-exit)}\n"] }]
7475
- }], ctorParameters: () => [], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], immediateExit: [{ type: i0.Input, args: [{ isSignal: true, alias: "immediateExit", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], _menuEl: [{ type: i0.ViewChild, args: ['menu', { isSignal: true }] }] } });
7476
-
7477
- /** ************************
7478
- * Copyright Monkey Exchange. All Rights Reserved
7479
- * This style guide was developed by Monkey Exchange Team
7480
- * MIT Licence
7481
- ************************* */
7482
- // ─── FLIP ───────────────────────────────────────────────────────────────────
7483
- // First, Last, Invert, Play: measure where the elements were, let the layout
7484
- // change, then put each one back at its old position with a `translate` and
7485
- // animate to zero. The result is that EVERYTHING slides from where it was,
7486
- // even though the browser repositioned all of it in one pass.
7487
- //
7488
- // Why it exists: when the bar's trigger turns into a chip, the whole row is
7489
- // rebuilt — the chip is born where the button was and the new button moves to
7490
- // the right. Without FLIP the only thing that can be animated is the chip
7491
- // coming in, and the neighbours jump. With it, the swap reads as a swap of
7492
- // PLACE.
7493
- //
7494
- // Two decisions that are not details:
7495
- //
7496
- // • Only `translate`. Transform and opacity compose on the GPU and skip
7497
- // layout and paint. The duration and the curve stay in the stylesheet, in
7498
- // `--mecx-fbv2-*` custom properties, and this file reads no motion value
7499
- // at all — that is how `prefers-reduced-motion` keeps working for free,
7500
- // because the media query redefines the properties themselves.
7501
- //
7502
- // • Forced reflow, NEVER requestAnimationFrame. In a hidden tab rAF does not
7503
- // fire: the elements would sit at the inverted position until the tab came
7504
- // back, which is worse than not animating. With the synchronous reflow the
7505
- // final state is always correct — in a hidden tab the transition simply
7506
- // does not run and the layout is already right.
7507
- /** Attribute that gives an element identity across the two measurements. */
6465
+ }, template: "<button\n class=\"mecx-filter-trigger-btn\"\n type=\"button\"\n [disabled]=\"disabled() || null\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-label]=\"ariaLabelAttr()\"\n aria-haspopup=\"listbox\"\n (click)=\"toggle()\"\n>\n <i class=\"mk-i mk-i-{{ icon() }} mecx-filter-trigger-icon\" aria-hidden=\"true\"></i>\n @if (variant() === 'text') {\n <span class=\"mecx-filter-trigger-text\">{{ text() }}</span>\n }\n</button>\n@if (open()) {\n <div\n #menu\n class=\"mecx-filter-trigger-menu\"\n animate.enter=\"mecx-filter-trigger-menu--entering\"\n [animate.leave]=\"immediateExit() ? '' : 'mecx-filter-trigger-menu--leaving'\"\n >\n <ng-content></ng-content>\n </div>\n}\n", styles: ["@keyframes mecx-filter-bar-surface-in{0%{opacity:0;scale:1 var(--mecx-filter-bar-scale-unfold);translate:0 calc(var(--mecx-filter-bar-travel-anchored) * -1)}}@keyframes mecx-filter-bar-surface-out{to{opacity:0;scale:1 var(--mecx-filter-bar-scale-unfold);translate:0 calc(var(--mecx-filter-bar-travel-anchored) * -1)}}@keyframes mecx-filter-bar-surface-item-in{0%{opacity:0;translate:0 calc(var(--mecx-filter-bar-travel-anchored) * -1)}}.mecx-filter-trigger{--mecx-filter-bar-duration-state: .15s;--mecx-filter-bar-duration-enter: .2s;--mecx-filter-bar-duration-exit: .15s;--mecx-filter-bar-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-filter-bar-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-filter-bar-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-filter-bar-scale-unfold: .94;--mecx-filter-bar-travel-anchored: 4px;--mecx-filter-bar-travel-slide: 16px;--mecx-filter-bar-stagger: 25ms;--mecx-filter-bar-control-height: 32px;--mecx-filter-bar-pointer-target: 40px;--mecx-filter-bar-reach: calc((var(--mecx-filter-bar-control-height) - var(--mecx-filter-bar-pointer-target)) / 2);--mecx-filter-bar-radius: 8px;--mecx-filter-bar-radius-item: 4px;--mecx-filter-bar-fade-width: 48px;--mecx-filter-bar-focus-reach: 4px;--mecx-filter-bar-z-raised: 1;--mecx-filter-bar-z-sticky: 2;--mecx-filter-bar-z-menu: 1000}@media(prefers-reduced-motion:reduce){.mecx-filter-trigger{--mecx-filter-bar-duration-state: 1ms;--mecx-filter-bar-duration-enter: 1ms;--mecx-filter-bar-duration-exit: 1ms;--mecx-filter-bar-scale-unfold: 1;--mecx-filter-bar-travel-anchored: 0px;--mecx-filter-bar-travel-slide: 0px;--mecx-filter-bar-stagger: 0ms}}.mecx-filter-trigger{display:inline-flex;position:relative}.mecx-filter-trigger-btn{display:inline-flex;align-items:center;justify-content:center;gap:4px;height:var(--mecx-filter-bar-control-height);box-sizing:border-box;background-color:var(--mecx-color-white);color:var(--mecx-color-gray-900);border:1px solid var(--mecx-color-gray-500);border-radius:var(--mecx-filter-bar-radius);font-family:inherit;cursor:pointer;outline:none;white-space:nowrap;position:relative;transition:background-color var(--mecx-filter-bar-duration-state) var(--mecx-filter-bar-ease-state),color var(--mecx-filter-bar-duration-state) var(--mecx-filter-bar-ease-state)}.mecx-filter-trigger-btn:after{content:\"\";position:absolute;top:50%;left:50%;translate:-50% -50%;width:max(100%,var(--mecx-filter-bar-pointer-target));height:max(100%,var(--mecx-filter-bar-pointer-target))}.mecx-filter-trigger-btn:hover:not(:disabled){color:var(--mecx-color-theme-main)}.mecx-filter-trigger-btn:focus-visible{outline:2px solid var(--mecx-color-theme-main);outline-offset:1px}.mecx-filter-trigger-btn:disabled{background-color:transparent;border-color:transparent;color:var(--mecx-color-gray-400);cursor:not-allowed}.mecx-filter-trigger--open{z-index:var(--mecx-filter-bar-z-menu)}.mecx-filter-trigger--open .mecx-filter-trigger-btn{color:var(--mecx-color-theme-main)}.mecx-filter-trigger--text .mecx-filter-trigger-btn{padding-inline:7px 11px}.mecx-filter-trigger--icon .mecx-filter-trigger-btn{width:var(--mecx-filter-bar-control-height);padding-inline:0}.mecx-filter-trigger-icon{display:inline-flex;flex-shrink:0;font-size:16px}.mecx-filter-trigger-text{font-size:13px;font-weight:500;line-height:16px;letter-spacing:.03em}.mecx-filter-trigger-menu{position:fixed;margin-top:4px;z-index:var(--mecx-filter-bar-z-menu)}.mecx-filter-trigger-menu--entering{transform-origin:top;animation:mecx-filter-bar-surface-in var(--mecx-filter-bar-duration-enter) var(--mecx-filter-bar-ease-enter)}.mecx-filter-trigger-menu--entering monkey-filter-menu-item,.mecx-filter-trigger-menu--entering monkey-divider{animation:mecx-filter-bar-surface-item-in var(--mecx-filter-bar-duration-enter) var(--mecx-filter-bar-ease-enter) both}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(1){animation-delay:calc(var(--mecx-filter-bar-stagger) * 1)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(2){animation-delay:calc(var(--mecx-filter-bar-stagger) * 2)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(3){animation-delay:calc(var(--mecx-filter-bar-stagger) * 3)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(4){animation-delay:calc(var(--mecx-filter-bar-stagger) * 4)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(5){animation-delay:calc(var(--mecx-filter-bar-stagger) * 5)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(6){animation-delay:calc(var(--mecx-filter-bar-stagger) * 6)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(7){animation-delay:calc(var(--mecx-filter-bar-stagger) * 7)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(8){animation-delay:calc(var(--mecx-filter-bar-stagger) * 8)}.mecx-filter-trigger-menu--entering .mecx-filter-menu-items>:nth-child(n+8){animation-delay:calc(var(--mecx-filter-bar-stagger) * 8)}.mecx-filter-trigger-menu--leaving{transform-origin:top;animation:mecx-filter-bar-surface-out var(--mecx-filter-bar-duration-exit) var(--mecx-filter-bar-ease-exit)}\n"] }]
6466
+ }], ctorParameters: () => [], propDecorators: { _menuEl: [{ type: i0.ViewChild, args: ['menu', { isSignal: true }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], immediateExit: [{ type: i0.Input, args: [{ isSignal: true, alias: "immediateExit", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }], alignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "alignment", required: false }] }], onOpenChange: [{ type: i0.Output, args: ["onOpenChange"] }] } });
6467
+
6468
+ /** ************************
6469
+ * Copyright Monkey Exchange. All Rights Reserved
6470
+ * This style guide was developed by Monkey Exchange Team
6471
+ * MIT Licence
6472
+ ************************* */
7508
6473
  const FLIP_ATTR = 'data-flip-id';
7509
- /**
7510
- * Where each identified element is RIGHT NOW. Call before changing the state.
7511
- */
7512
6474
  function measureFlip(container) {
7513
6475
  const before = new Map();
7514
6476
  container.querySelectorAll(`[${FLIP_ATTR}]`).forEach((el) => {
@@ -7518,12 +6480,6 @@ function measureFlip(container) {
7518
6480
  });
7519
6481
  return before;
7520
6482
  }
7521
- /**
7522
- * Puts every element back at the measured position and releases the
7523
- * transition. Call AFTER the DOM already reflects the new state.
7524
- *
7525
- * @param frozenClass class that zeroes the transition on the inverted frame
7526
- */
7527
6483
  function animateFlip(container, before, frozenClass) {
7528
6484
  const moved = [];
7529
6485
  container.querySelectorAll(`[${FLIP_ATTR}]`).forEach((el) => {
@@ -7531,9 +6487,6 @@ function animateFlip(container, before, frozenClass) {
7531
6487
  if (!id)
7532
6488
  return;
7533
6489
  const from = before.get(id);
7534
- // No previous measurement means the element was BORN just now. It does not
7535
- // slide from anywhere — it comes in through its own entrance animation,
7536
- // which is a different movement.
7537
6490
  if (!from)
7538
6491
  return;
7539
6492
  const to = el.getBoundingClientRect();
@@ -7547,11 +6500,6 @@ function animateFlip(container, before, frozenClass) {
7547
6500
  });
7548
6501
  if (moved.length === 0)
7549
6502
  return;
7550
- // This read is mandatory and is not a hack: it forces the browser to compute
7551
- // style with the inverted translate ALREADY applied. Without it the two
7552
- // writes (invert and release) collapse into the same pass and nothing
7553
- // animates.
7554
- // eslint-disable-next-line no-void
7555
6503
  void container.offsetWidth;
7556
6504
  moved.forEach((el) => {
7557
6505
  el.classList.remove(frozenClass);
@@ -7564,29 +6512,7 @@ function animateFlip(container, before, frozenClass) {
7564
6512
  * This style guide was developed by Monkey Exchange Team
7565
6513
  * MIT Licence
7566
6514
  ************************* */
7567
- // ─── "Has the app painted yet?" ─────────────────────────────────────────────
7568
- // A single shared boolean, so that components which animate on ENTERING the
7569
- // DOM do not animate when they were already there at the first paint.
7570
- //
7571
- // Why it exists: `animate.enter` fires on the initial render of the view, not
7572
- // only when the consumer mounts the component later. A filter bar that opens
7573
- // with filters already seeded by the consumer would replay the whole row's
7574
- // entrance on every page load and on every F5, for chips that were always
7575
- // there. Users read that as the page still assembling itself.
7576
- //
7577
- // Why it cannot be solved inside the component: a per-instance signal does not
7578
- // work. `animate.enter` is evaluated at the moment of INSERTION, and at that
7579
- // moment the instance has just been created — any flag of its own is still
7580
- // false, so the chip would simply never animate. "Has painted" is a notion of
7581
- // the PAGE, not of the component.
7582
- //
7583
- // The double rAF is the usual pattern: the first frame schedules, the second
7584
- // runs after the browser has painted.
7585
- /** False until the browser paints the first frame. Read-only for consumers. */
7586
6515
  let painted = false;
7587
- // There is no `requestAnimationFrame` under SSR — and no animation to suppress
7588
- // either, because the server does not paint. It stays false, and the client
7589
- // reschedules on hydration.
7590
6516
  if (typeof requestAnimationFrame === 'function') {
7591
6517
  requestAnimationFrame(() => {
7592
6518
  requestAnimationFrame(() => {
@@ -7594,16 +6520,6 @@ if (typeof requestAnimationFrame === 'function') {
7594
6520
  });
7595
6521
  });
7596
6522
  }
7597
- /**
7598
- * Has the page painted its first frame?
7599
- *
7600
- * Use it to decide whether an `animate.enter` should apply:
7601
- *
7602
- * [animate.enter]="appPainted() ? 'mecx-x--entering' : ''"
7603
- *
7604
- * A component already on screen at the first paint comes in without animation;
7605
- * one the consumer mounts later animates normally.
7606
- */
7607
6523
  function appPainted() {
7608
6524
  return painted;
7609
6525
  }
@@ -7613,710 +6529,572 @@ function appPainted() {
7613
6529
  * This style guide was developed by Monkey Exchange Team
7614
6530
  * MIT Licence
7615
6531
  ************************* */
7616
- // ─── monkey-filter-bar-v2 ───────────────────────────────────────────────────
7617
- // A restyle of monkey-filter-bar: the same contract, the same service and the
7618
- // same state, drawn as the segmented row of the monkey-design-system filter
7619
- // bar.
7620
- //
7621
- // WHAT IS THE SAME as monkey-filter-bar, deliberately this component is a
7622
- // drop-in replacement and a consumer swaps the tag without touching anything
7623
- // else:
7624
- //
7625
- // · `key` + `config` in, `filtersChange` + `searchChange` out
7626
- // · MonkeyFilterBarService owns the state, keyed by `key`
7627
- // · the four filter types (text · date · currency · status) and the same
7628
- // answers for each: date shortcuts and a custom range, currency as a
7629
- // from/until with one amount, status as a multiple choice
7630
- // · nothing is written to the service until the answer is CONFIRMED, except
7631
- // for the date shortcuts, where the click on the row already is the answer
7632
- //
7633
- // WHAT CHANGES is the drawing and the movement:
7634
- //
7635
- // · the active filter becomes a two-segment CHIP instead of a tag. The
7636
- // second segment is the edit affordance the tag used to be, and clicking
7637
- // it reopens exactly the panel that filled it.
7638
- // · the add-filter button lives at the END of the row and swaps variants:
7639
- // while the bar is empty it is the CALL to action and carries the label;
7640
- // with filters on screen it becomes a 28px `+`, because then it no longer
7641
- // opens "the filters", it ADDS one more.
7642
- // · the row SCROLLS horizontally instead of wrapping. Wrapping would push
7643
- // everything below the bar down by one line on every filter added;
7644
- // scrolling keeps the height stable.
7645
- // · every change of the row is animated by FLIP (see flip.ts). Each step
7646
- // changes the width of the whole row, and without FLIP only the new piece
7647
- // would move while everything else jumped.
7648
- //
7649
- // The bar OWNS the state and the animation. The pieces below it —
7650
- // monkey-filter-chip, monkey-filter-segment, monkey-filter-trigger,
7651
- // monkey-filter-menu — know nothing about the progression: each one only draws
7652
- // what it is given.
7653
- /** Class that freezes the transition on the FLIP's inverted frame. */
7654
- const FROZEN = 'mecx-filter-bar-v2-slot--frozen';
7655
- class MonkeyFilterBarV2Component {
6532
+ const DATE_SHORTCUTS = [
6533
+ { key: 'WEEK-AFTER', resolve: (t) => ({ start: t, end: addDays(t, 7) }) },
6534
+ { key: 'MONTH-AFTER', resolve: (t) => ({ start: t, end: addMonths(t, 1) }) },
6535
+ { key: 'QUARTER-AFTER', resolve: (t) => ({ start: t, end: addMonths(t, 3) }) },
6536
+ { key: 'WEEK-BEFORE', resolve: (t) => ({ start: subDays(t, 7), end: t }) },
6537
+ { key: 'MONTH-BEFORE', resolve: (t) => ({ start: subMonths(t, 1), end: t }) },
6538
+ { key: 'QUARTER-BEFORE', resolve: (t) => ({ start: subMonths(t, 3), end: t }) }
6539
+ ];
6540
+ const FROZEN = 'mecx-filter-bar-slot--frozen';
6541
+ const OPERAND_DATE_FORMAT = 'yyyy-MM-dd';
6542
+ const DEFAULT_DISPLAY_FORMAT = 'MM/dd/yyyy';
6543
+ class MonkeyFilterBarComponent {
7656
6544
  constructor() {
7657
- this._service = inject(MonkeyFilterBarService);
7658
6545
  this._hostEl = inject(ElementRef);
7659
6546
  this._injector = inject(Injector);
7660
- /** Storage key of this bar's state inside MonkeyFilterBarService. */
7661
- this.key = input.required(...(ngDevMode ? [{ debugName: "key" }] : /* istanbul ignore next */ []));
6547
+ this._text = toSignal(inject(MonkeyDictionaryService).get('FILTER-BAR'));
6548
+ this._commitTimer = null;
6549
+ this._reported = signal([], ...(ngDevMode ? [{ debugName: "_reported" }] : /* istanbul ignore next */ []));
7662
6550
  this.config = input(...(ngDevMode ? [undefined, { debugName: "config" }] : /* istanbul ignore next */ []));
7663
- /** Label of the trigger while the bar is still empty. */
7664
- this.addFilterLabel = input('Filtro', ...(ngDevMode ? [{ debugName: "addFilterLabel" }] : /* istanbul ignore next */ []));
7665
- this.clearAllLabel = input('Limpar filtros', ...(ngDevMode ? [{ debugName: "clearAllLabel" }] : /* istanbul ignore next */ []));
7666
- this.filtersChange = output();
7667
- this.searchChange = output();
7668
- /** A chip seeded by the consumer does not animate; one the user made does. */
6551
+ this.filters = input([], ...(ngDevMode ? [{ debugName: "filters" }] : /* istanbul ignore next */ []));
6552
+ this.onFiltersChange = output();
6553
+ this.dateFormat = input(DEFAULT_DISPLAY_FORMAT, ...(ngDevMode ? [{ debugName: "dateFormat" }] : /* istanbul ignore next */ []));
6554
+ this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
6555
+ this.debounce = input(0, ...(ngDevMode ? [{ debugName: "debounce" }] : /* istanbul ignore next */ []));
7669
6556
  this.appPainted = appPainted;
7670
- // ── State ────────────────────────────────────────────────────────────────
7671
- /**
7672
- * The filter being built — chosen from the trigger, not yet confirmed, so
7673
- * not yet in the service.
7674
- *
7675
- * It exists so the chip can be BORN where the trigger was, which is the
7676
- * whole point of the row's animation, without the bar reporting a filter
7677
- * that has no answer. Closing the panel without confirming drops it again:
7678
- * monkey-filter-bar has no half-filled state and neither does this one.
7679
- */
7680
- this.pending = signal(null, ...(ngDevMode ? [{ debugName: "pending" }] : /* istanbul ignore next */ []));
6557
+ this.rows = signal([], ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
7681
6558
  this.openPanel = signal(null, ...(ngDevMode ? [{ debugName: "openPanel" }] : /* istanbul ignore next */ []));
7682
6559
  this.triggerOpen = signal(false, ...(ngDevMode ? [{ debugName: "triggerOpen" }] : /* istanbul ignore next */ []));
7683
- /**
7684
- * The filter whose date panel is showing the CALENDAR instead of the
7685
- * shortcuts, or `null`.
7686
- *
7687
- * It is the same panel, anchored to the same segment — "Personalizado" only
7688
- * swaps its content. No modal: the dialog would be almost all frame around a
7689
- * calendar, and frame is not an answer to anything.
7690
- */
7691
6560
  this.calendarOpen = signal(null, ...(ngDevMode ? [{ debugName: "calendarOpen" }] : /* istanbul ignore next */ []));
7692
- /** Search of the category panel. */
7693
6561
  this.categorySearch = signal('', ...(ngDevMode ? [{ debugName: "categorySearch" }] : /* istanbul ignore next */ []));
7694
- /**
7695
- * Turns off the fade on the trigger's panel. It is written BEFORE the
7696
- * mutation on purpose: `animate.leave` is read the instant the node leaves,
7697
- * and turning it on afterwards would arrive too late.
7698
- */
7699
6562
  this.immediateTriggerExit = signal(false, ...(ngDevMode ? [{ debugName: "immediateTriggerExit" }] : /* istanbul ignore next */ []));
7700
- // Draft answers of the open panel. They are plain fields and not signals:
7701
- // they are bound with `[(ngModel)]`, so the template writes them directly,
7702
- // and nothing else in the view is derived from them.
7703
6563
  this.textValue = '';
6564
+ this.textValue2 = '';
7704
6565
  this.currencyValue = null;
7705
- this.currencyMode = 'from';
6566
+ this.currencyValue2 = null;
7706
6567
  this.statusValues = [];
7707
6568
  this.dateRange = { startDate: '', endDate: '' };
7708
- // ── Derived ──────────────────────────────────────────────────────────────
7709
- this.serviceConfig = computed(() => {
7710
- const k = this.key();
7711
- return k ? this._service.getConfig(k) ?? this.config() : undefined;
7712
- }, ...(ngDevMode ? [{ debugName: "serviceConfig" }] : /* istanbul ignore next */ []));
7713
- this.activeFilters = computed(() => {
7714
- const k = this.key();
7715
- return k ? this._service.getActiveFilters(k) : [];
7716
- }, ...(ngDevMode ? [{ debugName: "activeFilters" }] : /* istanbul ignore next */ []));
7717
- this.searchValue = computed(() => {
7718
- const k = this.key();
7719
- return k ? this._service.getSearchValue(k) : '';
7720
- }, ...(ngDevMode ? [{ debugName: "searchValue" }] : /* istanbul ignore next */ []));
7721
- this.searchPlaceholder = computed(() => {
7722
- return this.serviceConfig()?.searchPlaceholder ?? 'Pesquisar...';
7723
- }, ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
7724
- /** The slots of the row, in order: the confirmed ones, then the draft. */
7725
- this.rows = computed(() => {
7726
- const confirmed = this.activeFilters().map((f) => {
7727
- return {
7728
- key: f.key,
7729
- label: f.label,
7730
- icon: f.icon,
7731
- type: f.type,
7732
- value: f.displayText,
7733
- pending: false
7734
- };
6569
+ this.dayValue = '';
6570
+ this.options = computed(() => this.config()?.filterOptions ?? [], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
6571
+ this.labels = computed(() => {
6572
+ const text = this._text();
6573
+ return {
6574
+ add: text?.ADD ?? '',
6575
+ addAria: text?.['ADD-ARIA'] ?? '',
6576
+ clear: text?.CLEAR ?? '',
6577
+ search: text?.SEARCH ?? '',
6578
+ selectCondition: text?.['SELECT-CONDITION'] ?? '',
6579
+ select: text?.SELECT ?? '',
6580
+ confirm: text?.CONFIRM ?? '',
6581
+ rangeFrom: text?.['RANGE-FROM'] ?? '',
6582
+ rangeTo: text?.['RANGE-TO'] ?? '',
6583
+ remove: text?.REMOVE ?? ''
6584
+ };
6585
+ }, ...(ngDevMode ? [{ debugName: "labels" }] : /* istanbul ignore next */ []));
6586
+ this.dateShortcuts = computed(() => {
6587
+ const date = this._text()?.DATE ?? {};
6588
+ return [...DATE_SHORTCUTS.map((shortcut) => shortcut.key), 'CUSTOM'].map((key) => {
6589
+ return { key, label: date[key] ?? '' };
7735
6590
  });
7736
- const draft = this.pending();
7737
- if (!draft)
7738
- return confirmed;
7739
- return [
7740
- ...confirmed,
7741
- {
7742
- key: draft.key,
7743
- label: draft.label,
7744
- icon: draft.icon,
7745
- type: draft.type,
7746
- value: '',
7747
- pending: true
7748
- }
7749
- ];
7750
- }, ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
7751
- /**
7752
- * What the TRIGGER offers: only what can still be added.
7753
- *
7754
- * This is monkey-filter-bar's rule — a filter already on the row is not on
7755
- * offer, because the bar holds one filter per key.
7756
- */
6591
+ }, ...(ngDevMode ? [{ debugName: "dateShortcuts" }] : /* istanbul ignore next */ []));
7757
6592
  this.addOptions = computed(() => {
7758
- const k = this.key();
7759
- const available = k ? this._service.availableFilterOptions(k) : [];
7760
- return this._matchingSearch(available);
6593
+ const taken = new Set(this.rows().map((row) => row.key));
6594
+ return this.matchingSearch(this.options().filter((option) => !taken.has(option.key)));
7761
6595
  }, ...(ngDevMode ? [{ debugName: "addOptions" }] : /* istanbul ignore next */ []));
7762
- /**
7763
- * What a chip's CATEGORY segment offers: the whole list.
7764
- *
7765
- * A different list from the trigger's on purpose. Here the question is "what
7766
- * else could this chip be", so the current category has to be visible it
7767
- * is the one carrying the check — and the other filters already on the row
7768
- * are shown greyed out rather than hidden, which is what tells the user the
7769
- * category they were looking for is already in use.
7770
- */
7771
- this.changeOptions = computed(() => {
7772
- return this._matchingSearch(this.serviceConfig()?.filterOptions ?? []);
7773
- }, ...(ngDevMode ? [{ debugName: "changeOptions" }] : /* istanbul ignore next */ []));
7774
- /**
7775
- * While the bar is empty the trigger is the CALL and earns the label. With
7776
- * filters on screen a 28px square is enough.
7777
- */
6596
+ this.canAddFilter = computed(() => {
6597
+ const taken = new Set(this.rows().map((row) => row.key));
6598
+ return this.options().some((option) => !taken.has(option.key));
6599
+ }, ...(ngDevMode ? [{ debugName: "canAddFilter" }] : /* istanbul ignore next */ []));
6600
+ this.changeOptions = computed(() => this.matchingSearch(this.options()), ...(ngDevMode ? [{ debugName: "changeOptions" }] : /* istanbul ignore next */ []));
7778
6601
  this.triggerVariant = computed(() => {
7779
6602
  return this.rows().length === 0 ? 'text' : 'icon';
7780
6603
  }, ...(ngDevMode ? [{ debugName: "triggerVariant" }] : /* istanbul ignore next */ []));
7781
- /**
7782
- * The glyph of the collapsed trigger is a `+`, not the funnel.
7783
- *
7784
- * The variant says what the button IS; the glyph says what it DOES. With
7785
- * filters already on screen the button does not open "the filters", it ADDS
7786
- * one more — and a funnel there reads as the wrong thing. With the bar empty
7787
- * the funnel is exact.
7788
- */
7789
6604
  this.triggerIcon = computed(() => {
7790
6605
  return this.rows().length === 0 ? 'filter' : 'add-plus';
7791
6606
  }, ...(ngDevMode ? [{ debugName: "triggerIcon" }] : /* istanbul ignore next */ []));
7792
- /**
7793
- * The FLIP identity changes along with the variant, and that is the fix: the
7794
- * text trigger is REMOVED and the icon one is BORN in its place, instead of
7795
- * one button sliding to the right. Before this, the button dragged along the
7796
- * panel that was closing — the list vanished travelling sideways.
7797
- *
7798
- * From the second filter on the identity holds, and then the `+` really does
7799
- * slide: that movement is what says "the row grew".
7800
- */
7801
6607
  this.triggerFlipId = computed(() => {
7802
6608
  return this.rows().length === 0 ? 'trigger-text' : 'trigger-icon';
7803
6609
  }, ...(ngDevMode ? [{ debugName: "triggerFlipId" }] : /* istanbul ignore next */ []));
7804
- // The config is registered in the service by the same key the state uses,
7805
- // so any other consumer of the service sees the same option list. An
7806
- // effect and not ngOnInit/ngOnChanges: `key` and `config` are signal
7807
- // inputs, so one reactive registration covers the first value and every
7808
- // one after it.
7809
6610
  effect(() => {
7810
- const k = this.key();
7811
- const cfg = this.config();
7812
- if (k && cfg)
7813
- this._service.setConfig(k, cfg);
6611
+ const incoming = this.filters();
6612
+ untracked(() => {
6613
+ if (this.sameAsRows(incoming))
6614
+ return;
6615
+ this._reported.set(incoming);
6616
+ this.rows.set(incoming.map((filter) => {
6617
+ const option = this.options().find((item) => item.key === filter.key);
6618
+ return {
6619
+ key: filter.key,
6620
+ label: filter.label,
6621
+ icon: option?.icon,
6622
+ type: filter.type,
6623
+ condition: filter.condition,
6624
+ operands: filter.operands
6625
+ };
6626
+ }));
6627
+ });
6628
+ });
6629
+ effect(() => {
6630
+ if (!this.disabled())
6631
+ return;
6632
+ untracked(() => {
6633
+ this.triggerOpen.set(false);
6634
+ this.closePanel();
6635
+ });
6636
+ });
6637
+ inject(DestroyRef).onDestroy(() => this.cancelCommit());
6638
+ }
6639
+ askForAnswer(row) {
6640
+ if (isComplete(row)) {
6641
+ this.resetDraft();
6642
+ this.openPanel.set(null);
6643
+ return;
6644
+ }
6645
+ this.seedDraft(row);
6646
+ this.openPanel.set({ key: row.key, part: 'value' });
6647
+ }
6648
+ seedDraft(row) {
6649
+ this.resetDraft();
6650
+ this.calendarOpen.set(null);
6651
+ const [first, second] = row.operands;
6652
+ switch (this.panelFor(row)) {
6653
+ case 'status':
6654
+ this.statusValues = first?.kind === 'selection' ? [...first.values] : [];
6655
+ break;
6656
+ case 'field':
6657
+ if (row.type === 'currency') {
6658
+ this.currencyValue = first?.kind === 'number' ? first.value : null;
6659
+ this.currencyValue2 = second?.kind === 'number' ? second.value : null;
6660
+ }
6661
+ else {
6662
+ this.textValue = first?.kind === 'text' ? first.value : '';
6663
+ this.textValue2 = second?.kind === 'text' ? second.value : '';
6664
+ }
6665
+ break;
6666
+ case 'date-day':
6667
+ this.dayValue = first?.kind === 'date' ? first.value : '';
6668
+ break;
6669
+ case 'date-range':
6670
+ this.dateRange = {
6671
+ startDate: first?.kind === 'date' ? first.value : '',
6672
+ endDate: second?.kind === 'date' ? second.value : ''
6673
+ };
6674
+ if (this.dateRange.startDate)
6675
+ this.calendarOpen.set(row.key);
6676
+ break;
6677
+ default:
6678
+ break;
6679
+ }
6680
+ }
6681
+ readDraft(row) {
6682
+ const range = this.isRange(row);
6683
+ switch (this.panelFor(row)) {
6684
+ case 'status': {
6685
+ if (this.statusValues.length === 0)
6686
+ return null;
6687
+ return [{ kind: 'selection', values: [...this.statusValues] }];
6688
+ }
6689
+ case 'field': {
6690
+ if (row.type === 'currency') {
6691
+ const from = this.currencyValue;
6692
+ if (from === null || from === undefined)
6693
+ return null;
6694
+ if (!range)
6695
+ return [{ kind: 'number', value: from }];
6696
+ const to = this.currencyValue2;
6697
+ if (to === null || to === undefined)
6698
+ return null;
6699
+ const [low, high] = from <= to ? [from, to] : [to, from];
6700
+ return [
6701
+ { kind: 'number', value: low },
6702
+ { kind: 'number', value: high }
6703
+ ];
6704
+ }
6705
+ const text = this.textValue.trim();
6706
+ if (!text)
6707
+ return null;
6708
+ if (!range)
6709
+ return [{ kind: 'text', value: text }];
6710
+ const text2 = this.textValue2.trim();
6711
+ if (!text2)
6712
+ return null;
6713
+ return [
6714
+ { kind: 'text', value: text },
6715
+ { kind: 'text', value: text2 }
6716
+ ];
6717
+ }
6718
+ case 'date-day': {
6719
+ if (!this.dayValue)
6720
+ return null;
6721
+ return [{ kind: 'date', value: this.dayValue }];
6722
+ }
6723
+ case 'date-range': {
6724
+ const { startDate, endDate } = this.dateRange;
6725
+ if (!startDate || !endDate)
6726
+ return null;
6727
+ return [
6728
+ { kind: 'date', value: startDate },
6729
+ { kind: 'date', value: endDate }
6730
+ ];
6731
+ }
6732
+ default:
6733
+ return null;
6734
+ }
6735
+ }
6736
+ money(value) {
6737
+ return value.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });
6738
+ }
6739
+ showDate(iso) {
6740
+ if (!iso)
6741
+ return '';
6742
+ const parsed = parseISO(iso);
6743
+ if (Number.isNaN(parsed.getTime()))
6744
+ return iso;
6745
+ return format(parsed, this.dateFormat() || DEFAULT_DISPLAY_FORMAT);
6746
+ }
6747
+ open(key, part) {
6748
+ this.openPanel.set({ key, part });
6749
+ }
6750
+ closePanel() {
6751
+ this.openPanel.set(null);
6752
+ this.calendarOpen.set(null);
6753
+ this.resetDraft();
6754
+ }
6755
+ optionFor(optionKey) {
6756
+ return this.options().find((option) => option.key === optionKey);
6757
+ }
6758
+ matchingSearch(options) {
6759
+ const term = this.categorySearch().trim().toLowerCase();
6760
+ if (!term)
6761
+ return [...options];
6762
+ return options.filter((option) => option.label.toLowerCase().includes(term));
6763
+ }
6764
+ resetDraft() {
6765
+ this.textValue = '';
6766
+ this.textValue2 = '';
6767
+ this.currencyValue = null;
6768
+ this.currencyValue2 = null;
6769
+ this.statusValues = [];
6770
+ this.dateRange = { startDate: '', endDate: '' };
6771
+ this.dayValue = '';
6772
+ }
6773
+ sameAsRows(incoming) {
6774
+ const current = appliedFrom(this.rows());
6775
+ if (current.length !== incoming.length)
6776
+ return false;
6777
+ return current.every((filter, index) => {
6778
+ const other = incoming[index];
6779
+ return (filter.key === other.key &&
6780
+ filter.condition === other.condition &&
6781
+ JSON.stringify(filter.operands) === JSON.stringify(other.operands));
6782
+ });
6783
+ }
6784
+ commit() {
6785
+ this.cancelCommit();
6786
+ if (this.sameAsRows(this._reported()))
6787
+ return;
6788
+ const wait = this.debounce();
6789
+ if (wait <= 0) {
6790
+ this.publish();
6791
+ return;
6792
+ }
6793
+ this._commitTimer = setTimeout(() => {
6794
+ this._commitTimer = null;
6795
+ this.publish();
6796
+ }, wait);
6797
+ }
6798
+ publish() {
6799
+ const applied = appliedFrom(this.rows());
6800
+ this._reported.set(applied);
6801
+ this.onFiltersChange.emit(applied);
6802
+ }
6803
+ cancelCommit() {
6804
+ if (this._commitTimer === null)
6805
+ return;
6806
+ clearTimeout(this._commitTimer);
6807
+ this._commitTimer = null;
6808
+ }
6809
+ releaseFromFlow(container, leaving) {
6810
+ leaving.forEach((id) => {
6811
+ const slot = container.querySelector(`[${FLIP_ATTR}="${id}"]`);
6812
+ if (!slot)
6813
+ return;
6814
+ slot.style.left = `${slot.offsetLeft}px`;
6815
+ slot.style.top = `${slot.offsetTop}px`;
6816
+ slot.style.position = 'absolute';
7814
6817
  });
7815
6818
  }
7816
- // ── Queries used by the template ─────────────────────────────────────────
6819
+ followEnd(container) {
6820
+ const row = container.querySelector('.mecx-filter-bar-row');
6821
+ if (!row)
6822
+ return;
6823
+ const last = this.lastMovingSlot(row);
6824
+ if (!last)
6825
+ return;
6826
+ const room = parseFloat(getComputedStyle(row).paddingInlineEnd) || 0;
6827
+ const excess = last.getBoundingClientRect().right + room - row.getBoundingClientRect().right;
6828
+ if (excess <= 0)
6829
+ return;
6830
+ row.scrollLeft += excess;
6831
+ }
6832
+ lastMovingSlot(row) {
6833
+ const slots = Array.from(row.querySelectorAll(`[${FLIP_ATTR}]`));
6834
+ for (let index = slots.length - 1; index >= 0; index -= 1) {
6835
+ if (getComputedStyle(slots[index]).position !== 'sticky')
6836
+ return slots[index];
6837
+ }
6838
+ return null;
6839
+ }
6840
+ withFlip(mutate, options = {}) {
6841
+ const { leaving = [], follow = true } = options;
6842
+ const container = this._hostEl.nativeElement;
6843
+ const before = measureFlip(container);
6844
+ this.releaseFromFlow(container, leaving);
6845
+ mutate();
6846
+ afterNextRender(() => {
6847
+ if (follow)
6848
+ this.followEnd(container);
6849
+ animateFlip(container, before, FROZEN);
6850
+ this.immediateTriggerExit.set(false);
6851
+ }, { injector: this._injector });
6852
+ }
6853
+ operatorLabel(operator) {
6854
+ if (!operator)
6855
+ return '';
6856
+ return this._text()?.OPERATOR?.[operator] ?? '';
6857
+ }
7817
6858
  isOpen(rowKey, part) {
7818
6859
  const panel = this.openPanel();
7819
6860
  return !!panel && panel.key === rowKey && panel.part === part;
7820
6861
  }
7821
6862
  isFilterActive(optionKey) {
7822
- const k = this.key();
7823
- return k ? this._service.isFilterActive(k, optionKey) : false;
6863
+ return this.rows().some((row) => row.key === optionKey);
7824
6864
  }
7825
- /** A divider goes where the type changes relative to the row above. */
7826
6865
  needsDivider(options, index) {
7827
6866
  return index > 0 && options[index].type !== options[index - 1].type;
7828
6867
  }
6868
+ conditionsFor(row) {
6869
+ return conditionsOf(row.type);
6870
+ }
6871
+ panelFor(row) {
6872
+ return panelOf(row.type, row.condition);
6873
+ }
6874
+ hasValueSegment(row) {
6875
+ return this.panelFor(row) !== 'none';
6876
+ }
6877
+ isRange(row) {
6878
+ return arityOf(row.condition) === 2;
6879
+ }
6880
+ displayOf(row) {
6881
+ const [first, second] = row.operands;
6882
+ switch (this.panelFor(row)) {
6883
+ case 'status': {
6884
+ if (first?.kind !== 'selection' || first.values.length === 0)
6885
+ return '';
6886
+ if (first.values.length > 1) {
6887
+ return (this._text()?.SELECTED ?? '').replace('{count}', String(first.values.length));
6888
+ }
6889
+ const option = this.statusOptionsOf(row).find((item) => item.value === first.values[0]);
6890
+ return option?.description ?? first.values[0];
6891
+ }
6892
+ case 'field': {
6893
+ const write = (operand) => {
6894
+ if (operand?.kind === 'number')
6895
+ return this.money(operand.value);
6896
+ if (operand?.kind === 'text')
6897
+ return operand.value;
6898
+ return '';
6899
+ };
6900
+ if (!this.isRange(row))
6901
+ return write(first);
6902
+ return `${write(first)} – ${write(second)}`;
6903
+ }
6904
+ case 'date-day':
6905
+ return first?.kind === 'date' ? this.showDate(first.value) : '';
6906
+ case 'date-range': {
6907
+ if (first?.kind !== 'date' || second?.kind !== 'date')
6908
+ return '';
6909
+ return `${this.showDate(first.value)} – ${this.showDate(second.value)}`;
6910
+ }
6911
+ default:
6912
+ return '';
6913
+ }
6914
+ }
7829
6915
  valuePlaceholder(row) {
7830
- return this._optionFor(row.key)?.placeholder ?? 'Selecione';
6916
+ return this.optionFor(row.key)?.placeholder ?? this.labels().select;
7831
6917
  }
7832
6918
  statusOptionsOf(row) {
7833
- return this._optionFor(row.key)?.statusOptions ?? [];
6919
+ return this.optionFor(row.key)?.statusOptions ?? [];
7834
6920
  }
7835
6921
  minDateOf(row) {
7836
- return this._optionFor(row.key)?.minDate ?? '';
6922
+ return this.optionFor(row.key)?.minDate ?? '';
7837
6923
  }
7838
6924
  maxDateOf(row) {
7839
- return this._optionFor(row.key)?.maxDate ?? '';
6925
+ return this.optionFor(row.key)?.maxDate ?? '';
7840
6926
  }
7841
- // ── Progression ──────────────────────────────────────────────────────────
7842
- /**
7843
- * `index` is the position in the list the template walked — the one the
7844
- * search filtered. Indexing the full list would pick the wrong option.
7845
- */
7846
6927
  onSelectCategory(index) {
7847
6928
  const option = this.addOptions()[index];
7848
6929
  if (!option)
7849
6930
  return;
7850
- // Choosing a category swaps the trigger's VARIANT (text → icon) and with
7851
- // it its place in the row. The panel is a child of the button and would
7852
- // travel along.
7853
6931
  this.immediateTriggerExit.set(true);
7854
- this._withFlip(() => {
6932
+ this.withFlip(() => {
7855
6933
  this.triggerOpen.set(false);
7856
6934
  this.categorySearch.set('');
7857
- this._resetDraft();
6935
+ this.resetDraft();
7858
6936
  this.calendarOpen.set(null);
7859
- this.pending.set(option);
7860
- // The answer panel is born ALREADY OPEN: the user asked for this filter,
7861
- // and making them click the fresh chip to be asked for a value would
7862
- // charge twice for one decision.
7863
- this.openPanel.set({ key: option.key, part: 'value' });
6937
+ this.rows.update((rows) => [
6938
+ ...rows,
6939
+ {
6940
+ key: option.key,
6941
+ label: option.label,
6942
+ icon: option.icon,
6943
+ type: option.type,
6944
+ condition: '',
6945
+ operands: []
6946
+ }
6947
+ ]);
6948
+ this.openPanel.set({ key: option.key, part: 'condition' });
7864
6949
  });
7865
6950
  }
7866
- /**
7867
- * Swaps the category of a chip that already exists, from its first segment.
7868
- *
7869
- * The answer always falls: it belongs to the old category's domain — a list
7870
- * of statuses means nothing inside a date range — so the chip goes back to
7871
- * waiting, with its value panel open.
7872
- */
7873
6951
  onChangeCategory(row, index) {
7874
6952
  const option = this.changeOptions()[index];
7875
6953
  if (!option)
7876
6954
  return;
7877
- // The same category: nothing to swap, so the click just moves on to the
7878
- // answer, which is the only thing left to change.
7879
6955
  if (option.key === row.key) {
7880
- this._openValuePanel(row);
6956
+ this.open(row.key, 'condition');
7881
6957
  return;
7882
6958
  }
7883
6959
  if (this.isFilterActive(option.key))
7884
6960
  return;
7885
- this._withFlip(() => {
7886
- const k = this.key();
7887
- if (k && !row.pending)
7888
- this._service.removeFilter(k, row.key);
7889
- this._resetDraft();
6961
+ this.withFlip(() => {
6962
+ this.resetDraft();
7890
6963
  this.calendarOpen.set(null);
7891
6964
  this.categorySearch.set('');
7892
- this.pending.set(option);
7893
- this.openPanel.set({ key: option.key, part: 'value' });
7894
- },
7895
- // The slot keyed by the old category disappears either way — a new chip
7896
- // is born under the new key — so it always leaves through the ghost.
7897
- { leaving: [row.key], follow: false });
7898
- if (!row.pending)
7899
- this._emit();
6965
+ const next = withType(row, {
6966
+ key: option.key,
6967
+ label: option.label,
6968
+ icon: option.icon,
6969
+ type: option.type
6970
+ });
6971
+ this.rows.update((rows) => rows.map((item) => (item.key === row.key ? next : item)));
6972
+ if (next.condition)
6973
+ this.askForAnswer(next);
6974
+ else
6975
+ this.openPanel.set({ key: next.key, part: 'condition' });
6976
+ }, { leaving: [row.key], follow: false });
6977
+ this.commit();
6978
+ }
6979
+ onSelectCondition(row, condition) {
6980
+ const next = withCondition(row, condition);
6981
+ this.withFlip(() => {
6982
+ this.rows.update((rows) => rows.map((item) => (item.key === row.key ? next : item)));
6983
+ this.calendarOpen.set(null);
6984
+ this.askForAnswer(next);
6985
+ });
6986
+ this.commit();
7900
6987
  }
7901
- /**
7902
- * Opening the trigger closes whatever chip panel was open: only one panel is
7903
- * ever on screen, and a draft chip whose panel was abandoned goes with it.
7904
- */
7905
6988
  onTriggerOpenChange(open) {
7906
6989
  this.categorySearch.set('');
7907
6990
  this.triggerOpen.set(open);
7908
6991
  if (!open)
7909
6992
  return;
7910
- if (this.pending()) {
7911
- this._dropPending();
7912
- return;
7913
- }
7914
6993
  this.openPanel.set(null);
7915
6994
  this.calendarOpen.set(null);
7916
- this._resetDraft();
6995
+ this.resetDraft();
7917
6996
  }
7918
6997
  onCategoryOpenChange(row, open) {
7919
6998
  this.categorySearch.set('');
7920
6999
  if (!open) {
7921
- this._closePanel(row);
7000
+ this.closePanel();
7001
+ return;
7002
+ }
7003
+ this.triggerOpen.set(false);
7004
+ this.open(row.key, 'category');
7005
+ }
7006
+ onConditionOpenChange(row, open) {
7007
+ if (!open) {
7008
+ this.closePanel();
7922
7009
  return;
7923
7010
  }
7924
7011
  this.triggerOpen.set(false);
7925
- this.openPanel.set({ key: row.key, part: 'category' });
7012
+ this.open(row.key, 'condition');
7926
7013
  }
7927
7014
  onValueOpenChange(row, open) {
7928
7015
  if (!open) {
7929
- this._closePanel(row);
7016
+ this.closePanel();
7930
7017
  return;
7931
7018
  }
7932
7019
  this.triggerOpen.set(false);
7933
- this._openValuePanel(row);
7020
+ this.seedDraft(row);
7021
+ this.open(row.key, 'value');
7934
7022
  }
7935
- // ── Date ─────────────────────────────────────────────────────────────────
7936
- /**
7937
- * The same shortcuts monkey-filter-bar offers. "Personalizado" is the only
7938
- * one that does not resolve the interval on its own: it swaps the panel's
7939
- * content for the calendar, in the same place.
7940
- */
7941
- onQuickDate(row, preset) {
7942
- const option = this._optionFor(row.key);
7943
- if (!option || option.type !== 'date')
7023
+ onQuickDate(row, key) {
7024
+ if (row.type !== 'date')
7944
7025
  return;
7945
- if (preset === 'custom') {
7026
+ if (key === 'CUSTOM') {
7946
7027
  this.dateRange = { startDate: '', endDate: '' };
7947
7028
  this.calendarOpen.set(row.key);
7948
7029
  return;
7949
7030
  }
7950
- const today = new Date();
7951
- let start = today;
7952
- let end = today;
7953
- switch (preset) {
7954
- case '1-week-after':
7955
- end = addDays(today, 7);
7956
- break;
7957
- case '1-month-after':
7958
- end = addMonths(today, 1);
7959
- break;
7960
- case '3-months-after':
7961
- end = addMonths(today, 3);
7962
- break;
7963
- case '1-week-before':
7964
- start = subDays(today, 7);
7965
- break;
7966
- case '1-month-before':
7967
- start = subMonths(today, 1);
7968
- break;
7969
- case '3-months-before':
7970
- start = subMonths(today, 3);
7971
- break;
7972
- default:
7973
- return;
7974
- }
7031
+ const shortcut = DATE_SHORTCUTS.find((item) => item.key === key);
7032
+ if (!shortcut)
7033
+ return;
7034
+ const { start, end } = shortcut.resolve(new Date());
7975
7035
  this.dateRange = {
7976
- startDate: format(start, 'yyyy-MM-dd'),
7977
- endDate: format(end, 'yyyy-MM-dd')
7036
+ startDate: format(start, OPERAND_DATE_FORMAT),
7037
+ endDate: format(end, OPERAND_DATE_FORMAT)
7978
7038
  };
7979
7039
  this.onApply(row);
7980
7040
  }
7981
7041
  onDateChange(row, event) {
7982
7042
  this.dateRange = event;
7983
7043
  if (event.startDate && event.endDate) {
7984
- // The 100ms is monkey-filter-bar's own: the date range emits while it is
7985
- // still settling its own state, and applying inside that turn would
7986
- // close the panel from under it.
7987
- setTimeout(() => {
7988
- return this.onApply(row);
7989
- }, 100);
7990
- }
7991
- }
7992
- /** Cancel inside the calendar goes back to the shortcuts, panel still open. */
7993
- onBackToShortcuts() {
7994
- this.calendarOpen.set(null);
7995
- }
7996
- // ── Answers ──────────────────────────────────────────────────────────────
7997
- onStatusChange(value, checked) {
7998
- if (checked) {
7999
- if (!this.statusValues.includes(value))
8000
- this.statusValues = [...this.statusValues, value];
8001
- return;
8002
- }
8003
- this.statusValues = this.statusValues.filter((v) => {
8004
- return v !== value;
8005
- });
8006
- }
8007
- onToggleStatus(value) {
8008
- this.onStatusChange(value, !this.statusValues.includes(value));
8009
- }
8010
- /**
8011
- * The one place where an answer is written. Same validation as
8012
- * monkey-filter-bar: an empty answer is not an answer, and the panel stays
8013
- * open instead of writing a filter with nothing in it.
8014
- */
8015
- onApply(row) {
8016
- const k = this.key();
8017
- const option = this._optionFor(row.key);
8018
- if (!k || !option)
8019
- return;
8020
- let value;
8021
- switch (option.type) {
8022
- case 'text':
8023
- if (!this.textValue.trim())
8024
- return;
8025
- value = this.textValue.trim();
8026
- break;
8027
- case 'date':
8028
- if (!this.dateRange.startDate || !this.dateRange.endDate)
8029
- return;
8030
- value = { startDate: this.dateRange.startDate, endDate: this.dateRange.endDate };
8031
- break;
8032
- case 'currency': {
8033
- const raw = this.currencyValue;
8034
- if (raw === null || raw === undefined)
8035
- return;
8036
- value = this.currencyMode === 'from' ? { min: raw } : { max: raw };
8037
- break;
8038
- }
8039
- case 'status':
8040
- if (this.statusValues.length === 0)
8041
- return;
8042
- value = [...this.statusValues];
8043
- break;
8044
- default:
8045
- return;
8046
- }
8047
- this._withFlip(() => {
8048
- if (this._service.isFilterActive(k, option.key)) {
8049
- this._service.updateFilter(k, option.key, option, value);
8050
- }
8051
- else {
8052
- this._service.addFilter(k, option, value);
8053
- }
8054
- this.pending.set(null);
8055
- this.openPanel.set(null);
8056
- this.calendarOpen.set(null);
8057
- this._resetDraft();
8058
- });
8059
- this._emit();
8060
- }
8061
- onRemove(row) {
8062
- const k = this.key();
8063
- if (!k)
8064
- return;
8065
- // Does not follow the end: the row shrank, and jumping to the end after
8066
- // deleting something is disorienting — the eye is on the hole that was
8067
- // left, not on the queue.
8068
- this._withFlip(() => {
8069
- if (row.pending) {
8070
- this.pending.set(null);
8071
- }
8072
- else {
8073
- this._service.removeFilter(k, row.key);
8074
- }
8075
- if (this.openPanel()?.key === row.key)
8076
- this.openPanel.set(null);
8077
- if (this.calendarOpen() === row.key)
8078
- this.calendarOpen.set(null);
8079
- this._resetDraft();
8080
- }, { leaving: [row.key], follow: false });
8081
- if (!row.pending)
8082
- this._emit();
8083
- }
8084
- /** Zeroes the whole bar. The trigger goes back to being the call with a label. */
8085
- onClearAll() {
8086
- const k = this.key();
8087
- if (!k)
8088
- return;
8089
- const leaving = this.rows().map((row) => {
8090
- return row.key;
8091
- });
8092
- this._withFlip(() => {
8093
- this._service.clearAllFilters(k);
8094
- this.pending.set(null);
8095
- this.openPanel.set(null);
8096
- this.calendarOpen.set(null);
8097
- this._resetDraft();
8098
- }, { leaving, follow: false });
8099
- this._emit();
8100
- }
8101
- onSearchChange(value) {
8102
- const k = this.key();
8103
- if (!k)
8104
- return;
8105
- this._service.setSearchValue(k, value);
8106
- this.searchChange.emit(value);
8107
- this._emit();
8108
- }
8109
- // ── Panel bookkeeping ────────────────────────────────────────────────────
8110
- /**
8111
- * Opens a chip's answer panel, pre-filled with the answer it already holds —
8112
- * this is the edit path the active-filter tag used to be.
8113
- */
8114
- _openValuePanel(row) {
8115
- this._resetDraft();
8116
- this.calendarOpen.set(null);
8117
- const k = this.key();
8118
- const filter = k
8119
- ? this._service.getActiveFilters(k).find((f) => {
8120
- return f.key === row.key;
8121
- })
8122
- : undefined;
8123
- if (filter) {
8124
- switch (filter.type) {
8125
- case 'text':
8126
- this.textValue = filter.value;
8127
- break;
8128
- case 'date': {
8129
- const range = filter.value;
8130
- this.dateRange = { startDate: range.startDate ?? '', endDate: range.endDate ?? '' };
8131
- // Editing a date goes straight to the calendar: the shortcuts are the
8132
- // way IN, and there is nothing to pick from them once an interval
8133
- // already exists.
8134
- this.calendarOpen.set(row.key);
8135
- break;
8136
- }
8137
- case 'currency': {
8138
- const amount = filter.value;
8139
- if (amount.min !== undefined) {
8140
- this.currencyMode = 'from';
8141
- this.currencyValue = amount.min;
8142
- }
8143
- else if (amount.max !== undefined) {
8144
- this.currencyMode = 'until';
8145
- this.currencyValue = amount.max;
8146
- }
8147
- break;
8148
- }
8149
- case 'status':
8150
- this.statusValues = [...(filter.value ?? [])];
8151
- break;
8152
- default:
8153
- break;
8154
- }
8155
- }
8156
- this.openPanel.set({ key: row.key, part: 'value' });
8157
- }
8158
- /**
8159
- * Closing the value panel of a chip that was never confirmed drops the chip:
8160
- * monkey-filter-bar adds nothing until Apply, and a chip left on the row
8161
- * with no answer would be a state it does not have.
8162
- *
8163
- * Closing the panel of a CONFIRMED chip changes no width — the segment shows
8164
- * the same text it did before — so that path needs no FLIP.
8165
- */
8166
- _closePanel(row) {
8167
- if (!this.isOpen(row.key, 'category') && !this.isOpen(row.key, 'value'))
8168
- return;
8169
- if (row.pending) {
8170
- this._dropPending();
8171
- return;
8172
- }
8173
- this.openPanel.set(null);
8174
- this.calendarOpen.set(null);
8175
- this._resetDraft();
8176
- }
8177
- /** Takes the draft chip off the row, ghost and all. */
8178
- _dropPending() {
8179
- const draft = this.pending();
8180
- if (!draft)
8181
- return;
8182
- this._withFlip(() => {
8183
- this.pending.set(null);
8184
- this.openPanel.set(null);
8185
- this.calendarOpen.set(null);
8186
- this._resetDraft();
8187
- }, { leaving: [draft.key], follow: false });
8188
- }
8189
- _optionFor(optionKey) {
8190
- return this.serviceConfig()?.filterOptions.find((o) => {
8191
- return o.key === optionKey;
8192
- });
8193
- }
8194
- _matchingSearch(options) {
8195
- const term = this.categorySearch().trim().toLowerCase();
8196
- if (!term)
8197
- return [...options];
8198
- return options.filter((o) => {
8199
- return o.label.toLowerCase().includes(term);
8200
- });
7044
+ setTimeout(() => this.onApply(row), 100);
7045
+ }
8201
7046
  }
8202
- _resetDraft() {
8203
- this.textValue = '';
8204
- this.currencyValue = null;
8205
- this.currencyMode = 'from';
8206
- this.statusValues = [];
8207
- this.dateRange = { startDate: '', endDate: '' };
7047
+ onBackToShortcuts() {
7048
+ this.calendarOpen.set(null);
8208
7049
  }
8209
- _emit() {
8210
- const k = this.key();
8211
- if (!k)
8212
- return;
8213
- const state = this._service.getState(k);
8214
- this.filtersChange.emit({ search: state.search, filters: state.filters });
7050
+ onToggleStatus(value) {
7051
+ this.statusValues = this.statusValues.includes(value)
7052
+ ? this.statusValues.filter((item) => item !== value)
7053
+ : [...this.statusValues, value];
8215
7054
  }
8216
- // ── Coordinating state and DOM ───────────────────────────────────────────
8217
- /**
8218
- * Takes the slots that are about to leave out of the flow, at the exact
8219
- * place where they are.
8220
- *
8221
- * This is done HERE and not by the `animate.leave` class because of ORDER:
8222
- * Angular only applies the exit class the instant it removes the node, and
8223
- * that happens AFTER the `afterNextRender` that runs the FLIP. The FLIP
8224
- * would then measure a layout that had not collapsed yet, see no
8225
- * displacement at all, and the neighbours would snap into their new place
8226
- * with no animation — the chip's exit worked and the neighbours' arrival did
8227
- * not.
8228
- *
8229
- * Released from the flow BEFORE the mutation, the row collapses in the same
8230
- * pass: the FLIP measures a real before and a real after, and the ghost
8231
- * fades out on top, in place. Explicit `left`/`top` are mandatory — the
8232
- * static position of an absolute element inside a flex container is the
8233
- * container's corner, not where the element was.
8234
- */
8235
- _releaseFromFlow(container, leaving) {
8236
- leaving.forEach((id) => {
8237
- const slot = container.querySelector(`[${FLIP_ATTR}="${id}"]`);
8238
- if (!slot)
8239
- return;
8240
- slot.style.left = `${slot.offsetLeft}px`;
8241
- slot.style.top = `${slot.offsetTop}px`;
8242
- slot.style.position = 'absolute';
7055
+ onApply(row) {
7056
+ const operands = this.readDraft(row);
7057
+ if (!operands)
7058
+ return;
7059
+ this.withFlip(() => {
7060
+ this.rows.update((rows) => {
7061
+ return rows.map((item) => (item.key === row.key ? { ...item, operands } : item));
7062
+ });
7063
+ this.openPanel.set(null);
7064
+ this.calendarOpen.set(null);
7065
+ this.resetDraft();
8243
7066
  });
7067
+ this.commit();
8244
7068
  }
8245
- /**
8246
- * Takes the row to the end of its travel, so that what has just come in is
8247
- * not left hidden and with it the trigger, which is always last in line.
8248
- *
8249
- * It runs BEFORE the "after" measurement on purpose. FLIP works in VIEWPORT
8250
- * coordinates, so scrolling first folds the scroll offset into the same sum:
8251
- * every piece slides from where the eye saw it to where it ended up, pan
8252
- * included. One single synchronised movement.
8253
- *
8254
- * It is also what makes `scroll-behavior: smooth` unnecessary, which has no
8255
- * token, guarantees nothing under reduced motion, and stalls in a throttled
8256
- * tab.
8257
- *
8258
- * The sum comes from the LAST SLOT, never from `scrollWidth`. `scrollWidth`
8259
- * at this instant is a poisoned measurement: the chip that has just been
8260
- * born brings its answer panel already open, and the panel has not been
8261
- * anchored yet — it is at its static position, far ahead, and counts as
8262
- * overflow. The scroll would go hundreds of pixels chasing a ghost, the FLIP
8263
- * would animate the whole row that distance, and the browser would clamp the
8264
- * scroll back when the panel got anchored — a hard jump with no animation,
8265
- * right in the middle of the chip's entrance.
8266
- *
8267
- * The slots do not have that problem: they are flow content, already at
8268
- * their final position on the first render, and none of them is `fixed`.
8269
- */
8270
- _followEnd(container) {
8271
- const row = container.querySelector('.mecx-filter-bar-v2-row');
8272
- if (!row)
8273
- return;
8274
- const slots = row.querySelectorAll(`[${FLIP_ATTR}]`);
8275
- const last = slots[slots.length - 1];
8276
- if (!last)
8277
- return;
8278
- // The breathing room at the end is padding INSIDE the row's box, so the
8279
- // usable right edge sits before it. Without discounting it, the trigger
8280
- // comes to rest exactly where the gradient dilutes it.
8281
- const room = parseFloat(getComputedStyle(row).paddingInlineEnd) || 0;
8282
- const excess = last.getBoundingClientRect().right + room - row.getBoundingClientRect().right;
8283
- // Only ever forward. With no overflow this is inert, and going backwards
8284
- // would drag the eye back at the moment the queue grew.
8285
- if (excess <= 0)
8286
- return;
8287
- row.scrollLeft += excess;
7069
+ onRemove(row) {
7070
+ this.withFlip(() => {
7071
+ this.rows.update((rows) => rows.filter((item) => item.key !== row.key));
7072
+ if (this.openPanel()?.key === row.key)
7073
+ this.openPanel.set(null);
7074
+ if (this.calendarOpen() === row.key)
7075
+ this.calendarOpen.set(null);
7076
+ this.resetDraft();
7077
+ }, { leaving: [row.key], follow: false });
7078
+ this.commit();
8288
7079
  }
8289
- /**
8290
- * Measures, lets the state change, then makes everything slide from its old
8291
- * position.
8292
- *
8293
- * `afterNextRender` and not a `setTimeout`: we need the first instant at
8294
- * which the DOM ALREADY reflects the new state, and that is exactly what it
8295
- * delivers.
8296
- */
8297
- _withFlip(mutate, options = {}) {
8298
- const { leaving = [], follow = true } = options;
8299
- const container = this._hostEl.nativeElement;
8300
- const before = measureFlip(container);
8301
- this._releaseFromFlow(container, leaving);
8302
- mutate();
8303
- afterNextRender(() => {
8304
- if (follow)
8305
- this._followEnd(container);
8306
- animateFlip(container, before, FROZEN);
8307
- // The panel is gone; the next close goes back to a normal fade.
8308
- this.immediateTriggerExit.set(false);
8309
- }, { injector: this._injector });
7080
+ onClearAll() {
7081
+ const leaving = this.rows().map((row) => row.key);
7082
+ this.withFlip(() => {
7083
+ this.rows.set([]);
7084
+ this.openPanel.set(null);
7085
+ this.calendarOpen.set(null);
7086
+ this.resetDraft();
7087
+ }, { leaving, follow: false });
7088
+ this.commit();
8310
7089
  }
8311
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterBarV2Component, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8312
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyFilterBarV2Component, isStandalone: true, selector: "monkey-filter-bar-v2", inputs: { key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, addFilterLabel: { classPropertyName: "addFilterLabel", publicName: "addFilterLabel", isSignal: true, isRequired: false, transformFunction: null }, clearAllLabel: { classPropertyName: "clearAllLabel", publicName: "clearAllLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filtersChange: "filtersChange", searchChange: "searchChange" }, host: { attributes: { "data-testid": "monkey-filter-bar-v2" }, classAttribute: "mecx-filter-bar-v2" }, ngImport: i0, template: "<!-- Top row: the free-text search and whatever the consumer projects. Kept\n from monkey-filter-bar \u2014 the search is part of this bar's contract\n (`searchChange`), not of the chip row. -->\n<div class=\"mecx-filter-bar-v2-top\">\n <monkey-form-field class=\"mecx-filter-bar-v2-search\" size=\"sm\">\n <input\n type=\"text\"\n monkey-input\n [placeholder]=\"searchPlaceholder()\"\n [ngModel]=\"searchValue()\"\n (ngModelChange)=\"onSearchChange($event)\"\n />\n <monkey-prefix>\n <i class=\"mk-i mk-i-search fs-md\"></i>\n </monkey-prefix>\n </monkey-form-field>\n\n <div class=\"mecx-filter-bar-v2-extra\">\n <ng-content></ng-content>\n </div>\n</div>\n\n<div class=\"mecx-filter-bar-v2-line\">\n <div #rowEl class=\"mecx-filter-bar-v2-row\">\n @for (f of rows(); track f.key) {\n <span\n class=\"mecx-filter-bar-v2-slot\"\n [attr.data-flip-id]=\"f.key\"\n [animate.enter]=\"appPainted() ? 'mecx-filter-bar-v2-slot--entering' : ''\"\n animate.leave=\"mecx-filter-bar-v2-slot--leaving\"\n >\n <monkey-filter-chip (remove)=\"onRemove(f)\">\n <!-- 1 \u00B7 Category \u2014 opens the same list as the trigger, so the user\n can move a filter to another field without deleting it and\n starting over.\n\n The list is repeated here and further down on purpose, and it\n should NOT become a shared <ng-template>: the two differ in what\n they offer (only what can be added, vs. the whole list), in what\n counts as selected, and in what the click does. Sharing the\n markup would mean threading three parameters through a context\n object to save fifteen lines. -->\n <monkey-filter-segment\n [icon]=\"f.icon ?? null\"\n [text]=\"f.label\"\n [open]=\"isOpen(f.key, 'category')\"\n (openChange)=\"onCategoryOpenChange(f, $event)\"\n >\n <!-- Guarded by the same condition the segment uses to show its\n panel. Projected content is created with the view that\n DECLARES it, not with the one that renders it, so without this\n every chip would build both of its panels \u2014 menus, rows,\n fields and all \u2014 and keep them alive while closed. -->\n @if (isOpen(f.key, 'category')) {\n <monkey-filter-menu\n class=\"mecx-filter-bar-v2-menu-categories\"\n [showSearch]=\"true\"\n searchPlaceholder=\"Buscar filtro\"\n (searchChange)=\"categorySearch.set($event)\"\n >\n @for (opt of changeOptions(); track opt.key; let i = $index) {\n @if (needsDivider(changeOptions(), i)) {\n <monkey-divider />\n }\n <monkey-filter-menu-item\n [leadIcon]=\"opt.icon ?? null\"\n [label]=\"opt.label\"\n [selected]=\"opt.key === f.key\"\n [disabled]=\"opt.key !== f.key && isFilterActive(opt.key)\"\n (itemClick)=\"onChangeCategory(f, i)\"\n />\n }\n </monkey-filter-menu>\n }\n </monkey-filter-segment>\n\n <!-- 2 \u00B7 Value \u2014 the panel it opens is decided by the filter type,\n and it is the same panel that the chip's answer came from. That\n is what makes clicking a chip an EDIT instead of a restart. -->\n <monkey-filter-segment\n [placeholder]=\"valuePlaceholder(f)\"\n [text]=\"f.value\"\n [open]=\"isOpen(f.key, 'value')\"\n (openChange)=\"onValueOpenChange(f, $event)\"\n >\n @if (isOpen(f.key, 'value')) {\n @switch (f.type) {\n <!-- status \u2014 a multiple choice, so the answer is only written\n on Confirmar. Ticking a box is not yet a decision. -->\n @case ('status') {\n <monkey-filter-menu class=\"mecx-filter-bar-v2-menu-status\" [showSearch]=\"false\">\n @for (s of statusOptionsOf(f); track s.value) {\n <monkey-filter-menu-item\n property=\"checkbox\"\n [label]=\"s.description\"\n [checked]=\"statusValues.includes(s.value)\"\n (itemClick)=\"onToggleStatus(s.value)\"\n />\n }\n <div class=\"mecx-filter-bar-v2-panel-actions\">\n <monkey-button type=\"secondary\" size=\"sm\" (click)=\"onApply(f)\">\n Confirmar\n </monkey-button>\n </div>\n </monkey-filter-menu>\n }\n\n <!-- date \u2014 the shortcuts are the way in and the calendar is\n the detour. \"Personalizado\" swaps the CONTENT of this\n panel, which stays anchored to the same segment: no modal,\n because the dialog was almost all frame around a calendar\n and the segment already knows how to hang anything. The\n footer here is the date range's own, and Cancelar goes\n back to the shortcuts. -->\n @case ('date') {\n @if (calendarOpen() === f.key) {\n <monkey-date-range\n class=\"mecx-filter-bar-v2-calendar\"\n [startDate]=\"dateRange.startDate\"\n [endDate]=\"dateRange.endDate\"\n [minDate]=\"minDateOf(f)\"\n [maxDate]=\"maxDateOf(f)\"\n (onDate)=\"onDateChange(f, $event)\"\n (onCancel)=\"onBackToShortcuts()\"\n ></monkey-date-range>\n } @else {\n <monkey-filter-menu [showSearch]=\"false\">\n <monkey-filter-menu-item\n label=\"1 semana a partir de hoje\"\n (itemClick)=\"onQuickDate(f, '1-week-after')\"\n />\n <monkey-filter-menu-item\n label=\"1 m\u00EAs a partir de hoje\"\n (itemClick)=\"onQuickDate(f, '1-month-after')\"\n />\n <monkey-filter-menu-item\n label=\"3 meses a partir de hoje\"\n (itemClick)=\"onQuickDate(f, '3-months-after')\"\n />\n <monkey-filter-menu-item\n label=\"1 semana antes de hoje\"\n (itemClick)=\"onQuickDate(f, '1-week-before')\"\n />\n <monkey-filter-menu-item\n label=\"1 m\u00EAs antes de hoje\"\n (itemClick)=\"onQuickDate(f, '1-month-before')\"\n />\n <monkey-filter-menu-item\n label=\"3 meses antes de hoje\"\n (itemClick)=\"onQuickDate(f, '3-months-before')\"\n />\n <monkey-filter-menu-item\n label=\"Personalizado\"\n (itemClick)=\"onQuickDate(f, 'custom')\"\n />\n </monkey-filter-menu>\n }\n }\n\n <!-- currency \u2014 one amount and the side it applies to. The\n label lives inside the field, which is what lets the panel\n close in 238px instead of spending a line on a title. -->\n @case ('currency') {\n <monkey-filter-menu class=\"mecx-filter-bar-v2-menu-field\" [showSearch]=\"false\">\n <div class=\"mecx-filter-bar-v2-field\">\n <monkey-radiobutton [(ngModel)]=\"currencyMode\" position=\"vertical\" size=\"sm\">\n <monkey-option [value]=\"'from'\">De</monkey-option>\n <monkey-option [value]=\"'until'\">At\u00E9</monkey-option>\n </monkey-radiobutton>\n\n <monkey-form-field size=\"sm\">\n <monkey-label>{{ f.label }}</monkey-label>\n <input\n type=\"text\"\n monkey-input-currency\n [placeholder]=\"currencyMode === 'from' ? 'Valor m\u00EDnimo' : 'Valor m\u00E1ximo'\"\n [(ngModel)]=\"currencyValue\"\n (keyup.enter)=\"onApply(f)\"\n />\n </monkey-form-field>\n\n <monkey-button type=\"secondary\" size=\"sm\" (click)=\"onApply(f)\">\n Confirmar\n </monkey-button>\n </div>\n </monkey-filter-menu>\n }\n\n <!-- text \u2014 a single field, so the answer is the text itself. -->\n @default {\n <monkey-filter-menu class=\"mecx-filter-bar-v2-menu-field\" [showSearch]=\"false\">\n <div class=\"mecx-filter-bar-v2-field\">\n <monkey-form-field size=\"sm\">\n <monkey-label>{{ f.label }}</monkey-label>\n <input\n type=\"text\"\n monkey-input\n [placeholder]=\"valuePlaceholder(f)\"\n [(ngModel)]=\"textValue\"\n (keyup.enter)=\"onApply(f)\"\n />\n </monkey-form-field>\n\n <monkey-button type=\"secondary\" size=\"sm\" (click)=\"onApply(f)\">\n Confirmar\n </monkey-button>\n </div>\n </monkey-filter-menu>\n }\n }\n }\n </monkey-filter-segment>\n </monkey-filter-chip>\n </span>\n }\n\n <!-- The trigger is the last slot of the row. Its FLIP identity changes\n along with the variant (see triggerFlipId): with the bar empty it is\n the labelled \"Filtro\" and it goes away with the first filter; the \"+\"\n that takes its place inherits no position, so there is no button\n sliding along and dragging the panel that is closing. -->\n <span class=\"mecx-filter-bar-v2-slot\" [attr.data-flip-id]=\"triggerFlipId()\">\n <monkey-filter-trigger\n [variant]=\"triggerVariant()\"\n [icon]=\"triggerIcon()\"\n [text]=\"addFilterLabel()\"\n [immediateExit]=\"immediateTriggerExit()\"\n [open]=\"triggerOpen()\"\n (openChange)=\"onTriggerOpenChange($event)\"\n >\n @if (triggerOpen()) {\n <monkey-filter-menu\n class=\"mecx-filter-bar-v2-menu-categories\"\n [showSearch]=\"true\"\n searchPlaceholder=\"Buscar filtro\"\n (searchChange)=\"categorySearch.set($event)\"\n >\n @for (opt of addOptions(); track opt.key; let i = $index) {\n @if (needsDivider(addOptions(), i)) {\n <monkey-divider />\n }\n <monkey-filter-menu-item\n [leadIcon]=\"opt.icon ?? null\"\n [label]=\"opt.label\"\n (itemClick)=\"onSelectCategory(i)\"\n />\n }\n </monkey-filter-menu>\n }\n </monkey-filter-trigger>\n </span>\n </div>\n\n <!-- Gradient plus action. The gradient exists so the chips FADE OUT as they\n pass underneath instead of being cut off hard by the edge of what\n scrolls. -->\n @if (rows().length > 0) {\n <div class=\"mecx-filter-bar-v2-actions\">\n <monkey-button type=\"tertiary\" size=\"sm\" (click)=\"onClearAll()\">\n {{ clearAllLabel() }}\n </monkey-button>\n </div>\n }\n</div>\n\n<!-- Drawn bar plus divider. The bar hides itself when there is nothing to\n scroll, so filters existing is enough for it to be mounted. -->\n@if (rows().length > 0) {\n <monkey-scrollbar orientation=\"horizontal\" size=\"small\" [target]=\"rowEl\" />\n <monkey-divider />\n}\n", styles: ["@charset \"UTF-8\";.mecx-filter-bar-v2{--mecx-fbv2-duration-state: .15s;--mecx-fbv2-duration-enter: .2s;--mecx-fbv2-duration-exit: .15s;--mecx-fbv2-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-fbv2-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-fbv2-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-fbv2-scale-unfold: .94;--mecx-fbv2-travel-anchored: 4px;--mecx-fbv2-travel-slide: 16px;--mecx-fbv2-stagger: 25ms;--mecx-fbv2-control-height: 28px;--mecx-fbv2-pointer-target: 40px;--mecx-fbv2-radius: 8px;--mecx-fbv2-radius-item: 4px;--mecx-fbv2-fade-width: 48px}@media(prefers-reduced-motion:reduce){.mecx-filter-bar-v2{--mecx-fbv2-duration-state: 1ms;--mecx-fbv2-duration-enter: 1ms;--mecx-fbv2-duration-exit: 1ms;--mecx-fbv2-scale-unfold: 1;--mecx-fbv2-travel-anchored: 0px;--mecx-fbv2-travel-slide: 0px;--mecx-fbv2-stagger: 0ms}}.mecx-filter-bar-v2{display:flex;flex-direction:column;gap:8px;width:100%;background:var(--mecx-color-white)}.mecx-filter-bar-v2-top{display:flex;align-items:center;gap:8px;width:100%}.mecx-filter-bar-v2-search{flex:1;min-width:0;max-width:400px;display:block}.mecx-filter-bar-v2-extra{margin-left:auto;display:flex;align-items:center;gap:8px}.mecx-filter-bar-v2-line{display:flex;align-items:center;width:100%}.mecx-filter-bar-v2-row{display:flex;align-items:center;gap:8px;flex:1 0 0;min-width:0;overflow-x:auto;position:relative;min-height:var(--mecx-fbv2-pointer-target);padding-inline-end:var(--mecx-fbv2-fade-width);scrollbar-width:none;-ms-overflow-style:none}.mecx-filter-bar-v2-row::-webkit-scrollbar{width:0;height:0}.mecx-filter-bar-v2-actions{position:relative;display:flex;align-items:center;justify-content:flex-end;align-self:stretch;flex-shrink:0;padding-left:var(--mecx-fbv2-fade-width);background:var(--mecx-color-white)}.mecx-filter-bar-v2-actions:before{content:\"\";position:absolute;inset-block:0;right:100%;width:var(--mecx-fbv2-fade-width);background:linear-gradient(to right,transparent,var(--mecx-color-white));pointer-events:none}.mecx-filter-bar-v2-slot{display:inline-flex;flex-shrink:0;transition:translate var(--mecx-fbv2-duration-enter) var(--mecx-fbv2-ease-enter)}.mecx-filter-bar-v2-slot--frozen{transition-duration:0s}@keyframes mecx-filter-bar-v2-slot-in{0%{opacity:0;translate:calc(var(--mecx-fbv2-travel-slide) * -1) 0}}@keyframes mecx-filter-bar-v2-slot-out{to{opacity:0;translate:calc(var(--mecx-fbv2-travel-slide) * -1) 0}}.mecx-filter-bar-v2-slot--leaving{position:absolute;pointer-events:none;animation:mecx-filter-bar-v2-slot-out var(--mecx-fbv2-duration-exit) var(--mecx-fbv2-ease-exit) both}.mecx-filter-bar-v2-slot--entering{animation:mecx-filter-bar-v2-slot-in var(--mecx-fbv2-duration-enter) var(--mecx-fbv2-ease-enter);position:relative;z-index:1}.mecx-filter-menu.mecx-filter-bar-v2-menu-categories{width:198px}.mecx-filter-menu.mecx-filter-bar-v2-menu-status{width:225px}.mecx-filter-menu.mecx-filter-bar-v2-menu-field{width:238px}.mecx-filter-bar-v2-field{display:flex;flex-direction:column;gap:8px;width:100%;box-sizing:border-box}.mecx-filter-bar-v2-field monkey-form-field{display:block;width:100%}.mecx-filter-bar-v2-field monkey-button,.mecx-filter-bar-v2-field monkey-button .mecx-button{width:100%}.mecx-filter-bar-v2-panel-actions{display:flex;margin-top:8px;padding-top:8px;border-top:1px solid var(--mecx-color-gray-200)}.mecx-filter-bar-v2-panel-actions monkey-button,.mecx-filter-bar-v2-panel-actions monkey-button .mecx-button{width:100%}.mecx-filter-bar-v2-calendar{display:block;background:var(--mecx-color-white);border-radius:var(--mecx-fbv2-radius);box-shadow:0 8px 12px -4px var(--mecx-color-box-shadow, rgba(47, 50, 55, .08))}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MonkeyButtonComponent, selector: "monkey-button", inputs: ["disabled", "color", "size", "type", "loading", "id"] }, { kind: "component", type: MonkeyDateRangeComponent, selector: "monkey-date-range", inputs: ["startDate", "endDate", "hideQuickAction", "hideHeader", "hideActions", "hideSecondCalendar", "allowFastActionOnHeader", "minDate", "maxDate", "id"], outputs: ["onCancel", "onDate"] }, { kind: "component", type: MonkeyDividerComponent, selector: "monkey-divider", inputs: ["size", "vertical", "id"] }, { kind: "component", type: MonkeyFilterChipComponent, selector: "monkey-filter-chip", inputs: ["removeIcon", "removeLabel"], outputs: ["remove"] }, { kind: "component", type: MonkeyFilterMenuComponent, selector: "monkey-filter-menu", inputs: ["showSearch", "searchPlaceholder", "showScroll", "maxHeight"], outputs: ["searchChange"] }, { kind: "component", type: MonkeyFilterMenuItemComponent, selector: "monkey-filter-menu-item", inputs: ["property", "leadIcon", "label", "description", "checked", "selected", "disabled"], outputs: ["itemClick"] }, { kind: "component", type: MonkeyFilterSegmentComponent, selector: "monkey-filter-segment", inputs: ["icon", "text", "placeholder", "readonlySegment", "open"], outputs: ["openChange", "segmentClick"] }, { kind: "component", type: MonkeyFilterTriggerComponent, selector: "monkey-filter-trigger", inputs: ["variant", "icon", "text", "ariaLabel", "disabled", "immediateExit", "open"], outputs: ["openChange"] }, { kind: "ngmodule", type: MonkeyFormFieldModule }, { kind: "component", type: MonkeyFormFieldComponent, selector: "monkey-form-field", inputs: ["id", "hideAction", "enableClear", "size", "noFooterSpace", "displayOnly"], outputs: ["onDisplayOnlyChange"], exportAs: ["monkeyFormField"] }, { kind: "ngmodule", type: MonkeyInputModule }, { kind: "directive", type: MonkeyInputDirective, selector: "input[monkey-input],textarea[monkey-input]", inputs: ["name", "disabled", "id", "required", "type", "min", "max", "percent"], exportAs: ["monkeyInput"] }, { kind: "directive", type: MonkeyInputCurrencyDirective, selector: "input[monkey-input-currency]", inputs: ["name", "disabled", "id", "required", "type"], exportAs: ["monkeyInput"] }, { kind: "directive", type: MonkeyLabelDirective, selector: "monkey-label" }, { kind: "component", type: MonkeyOptionComponent, selector: "monkey-option", inputs: ["value", "disabled", "type", "selected"] }, { kind: "directive", type: MonkeyPrefixDirective, selector: "monkey-prefix" }, { kind: "component", type: MonkeyRadioButtonComponent, selector: "monkey-radiobutton", inputs: ["tabIndex", "position", "size", "disabled", "required", "value"], outputs: ["onChange", "onSearch"] }, { kind: "component", type: MonkeyScrollbarComponent, selector: "monkey-scrollbar", inputs: ["orientation", "size", "target"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
7090
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7091
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyFilterBarComponent, isStandalone: true, selector: "monkey-filter-bar", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, debounce: { classPropertyName: "debounce", publicName: "debounce", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onFiltersChange: "onFiltersChange" }, host: { attributes: { "data-testid": "monkey-filter-bar" }, properties: { "class.mecx-filter-bar--disabled": "disabled()" }, classAttribute: "mecx-filter-bar" }, ngImport: i0, template: "<div class=\"mecx-filter-bar-line\">\n <div #rowEl class=\"mecx-filter-bar-row\">\n @for (f of rows(); track f.key) {\n <span\n class=\"mecx-filter-bar-slot\"\n [attr.data-flip-id]=\"f.key\"\n [animate.enter]=\"appPainted() ? 'mecx-filter-bar-slot--entering' : ''\"\n animate.leave=\"mecx-filter-bar-slot--leaving\"\n >\n <monkey-filter-chip\n [removeLabel]=\"labels().remove\"\n [disabled]=\"disabled()\"\n (onRemove)=\"onRemove(f)\"\n >\n <monkey-filter-segment\n [icon]=\"f.icon ?? null\"\n [text]=\"f.label\"\n [disabled]=\"disabled()\"\n [open]=\"isOpen(f.key, 'category')\"\n (onOpenChange)=\"onCategoryOpenChange(f, $event)\"\n >\n @if (isOpen(f.key, 'category')) {\n <monkey-filter-menu\n class=\"mecx-filter-bar-menu-categories\"\n [showSearch]=\"true\"\n [searchPlaceholder]=\"labels().search\"\n (onSearchChange)=\"categorySearch.set($event)\"\n >\n @for (opt of changeOptions(); track opt.key; let i = $index) {\n @if (needsDivider(changeOptions(), i)) {\n <monkey-divider />\n }\n <monkey-filter-menu-item\n [leadIcon]=\"opt.icon ?? null\"\n [label]=\"opt.label\"\n [selected]=\"opt.key === f.key\"\n [disabled]=\"opt.key !== f.key && isFilterActive(opt.key)\"\n (onItemClick)=\"onChangeCategory(f, i)\"\n />\n }\n </monkey-filter-menu>\n }\n </monkey-filter-segment>\n <monkey-filter-segment\n [placeholder]=\"labels().selectCondition\"\n [text]=\"operatorLabel(f.condition)\"\n [disabled]=\"disabled()\"\n [open]=\"isOpen(f.key, 'condition')\"\n (onOpenChange)=\"onConditionOpenChange(f, $event)\"\n >\n @if (isOpen(f.key, 'condition')) {\n <monkey-filter-menu class=\"mecx-filter-bar-menu-conditions\" [showSearch]=\"false\">\n @for (c of conditionsFor(f); track c) {\n <monkey-filter-menu-item\n [label]=\"operatorLabel(c)\"\n [selected]=\"c === f.condition\"\n (onItemClick)=\"onSelectCondition(f, c)\"\n />\n }\n </monkey-filter-menu>\n }\n </monkey-filter-segment>\n @if (hasValueSegment(f)) {\n <monkey-filter-segment\n [placeholder]=\"valuePlaceholder(f)\"\n [text]=\"displayOf(f)\"\n [disabled]=\"disabled()\"\n [open]=\"isOpen(f.key, 'value')\"\n (onOpenChange)=\"onValueOpenChange(f, $event)\"\n >\n @if (isOpen(f.key, 'value')) {\n @switch (panelFor(f)) {\n @case ('status') {\n <monkey-filter-menu class=\"mecx-filter-bar-menu-status\" [showSearch]=\"false\">\n @for (s of statusOptionsOf(f); track s.value) {\n <monkey-filter-menu-item\n property=\"checkbox\"\n [label]=\"s.description\"\n [checked]=\"statusValues.includes(s.value)\"\n (onItemClick)=\"onToggleStatus(s.value)\"\n />\n }\n <div class=\"mecx-filter-bar-panel-actions\">\n <monkey-button type=\"secondary\" size=\"sm\" (click)=\"onApply(f)\">\n {{ labels().confirm }}\n </monkey-button>\n </div>\n </monkey-filter-menu>\n }\n\n @case ('date-day') {\n <monkey-filter-menu class=\"mecx-filter-bar-menu-field\" [showSearch]=\"false\">\n <div class=\"mecx-filter-bar-field\">\n <label class=\"mecx-filter-bar-field-row\">\n <span class=\"mecx-filter-bar-field-label\">{{ f.label }}</span>\n <monkey-form-field size=\"sm\" noFooterSpace>\n <input\n type=\"date\"\n monkey-input\n [(ngModel)]=\"dayValue\"\n (keyup.enter)=\"onApply(f)\"\n />\n </monkey-form-field>\n </label>\n <monkey-button type=\"secondary\" size=\"sm\" (click)=\"onApply(f)\">\n {{ labels().confirm }}\n </monkey-button>\n </div>\n </monkey-filter-menu>\n }\n\n @case ('date-range') {\n @if (calendarOpen() === f.key) {\n <monkey-date-range\n class=\"mecx-filter-bar-calendar\"\n [startDate]=\"dateRange.startDate\"\n [endDate]=\"dateRange.endDate\"\n [minDate]=\"minDateOf(f)\"\n [maxDate]=\"maxDateOf(f)\"\n (onDate)=\"onDateChange(f, $event)\"\n (onCancel)=\"onBackToShortcuts()\"\n ></monkey-date-range>\n } @else {\n <monkey-filter-menu [showSearch]=\"false\">\n @for (shortcut of dateShortcuts(); track shortcut.key) {\n <monkey-filter-menu-item\n [label]=\"shortcut.label\"\n (onItemClick)=\"onQuickDate(f, shortcut.key)\"\n />\n }\n </monkey-filter-menu>\n }\n }\n\n @default {\n <monkey-filter-menu class=\"mecx-filter-bar-menu-field\" [showSearch]=\"false\">\n <div class=\"mecx-filter-bar-field\">\n @if (f.type === 'currency') {\n <label class=\"mecx-filter-bar-field-row\">\n <span class=\"mecx-filter-bar-field-label\">\n {{ isRange(f) ? labels().rangeFrom : f.label }}\n </span>\n <monkey-form-field size=\"sm\" noFooterSpace>\n <input\n type=\"text\"\n monkey-input-currency\n [(ngModel)]=\"currencyValue\"\n (keyup.enter)=\"onApply(f)\"\n />\n </monkey-form-field>\n </label>\n @if (isRange(f)) {\n <label class=\"mecx-filter-bar-field-row\">\n <span class=\"mecx-filter-bar-field-label\">{{ labels().rangeTo }}</span>\n <monkey-form-field size=\"sm\" noFooterSpace>\n <input\n type=\"text\"\n monkey-input-currency\n [(ngModel)]=\"currencyValue2\"\n (keyup.enter)=\"onApply(f)\"\n />\n </monkey-form-field>\n </label>\n }\n } @else {\n <label class=\"mecx-filter-bar-field-row\">\n <span class=\"mecx-filter-bar-field-label\">\n {{ isRange(f) ? labels().rangeFrom : f.label }}\n </span>\n <monkey-form-field size=\"sm\" noFooterSpace>\n <input\n type=\"text\"\n monkey-input\n [placeholder]=\"valuePlaceholder(f)\"\n [(ngModel)]=\"textValue\"\n (keyup.enter)=\"onApply(f)\"\n />\n </monkey-form-field>\n </label>\n @if (isRange(f)) {\n <label class=\"mecx-filter-bar-field-row\">\n <span class=\"mecx-filter-bar-field-label\">{{ labels().rangeTo }}</span>\n <monkey-form-field size=\"sm\" noFooterSpace>\n <input\n type=\"text\"\n monkey-input\n [(ngModel)]=\"textValue2\"\n (keyup.enter)=\"onApply(f)\"\n />\n </monkey-form-field>\n </label>\n }\n }\n\n <monkey-button type=\"secondary\" size=\"sm\" (click)=\"onApply(f)\">\n {{ labels().confirm }}\n </monkey-button>\n </div>\n </monkey-filter-menu>\n }\n }\n }\n </monkey-filter-segment>\n }\n </monkey-filter-chip>\n </span>\n }\n\n @if (canAddFilter()) {\n <span\n class=\"mecx-filter-bar-slot mecx-filter-bar-slot--trigger\"\n [attr.data-flip-id]=\"triggerFlipId()\"\n >\n <monkey-filter-trigger\n [variant]=\"triggerVariant()\"\n [icon]=\"triggerIcon()\"\n [text]=\"labels().add\"\n [ariaLabel]=\"labels().addAria\"\n [disabled]=\"disabled()\"\n [immediateExit]=\"immediateTriggerExit()\"\n [open]=\"triggerOpen()\"\n (onOpenChange)=\"onTriggerOpenChange($event)\"\n >\n @if (triggerOpen()) {\n <monkey-filter-menu\n class=\"mecx-filter-bar-menu-categories\"\n [showSearch]=\"true\"\n [searchPlaceholder]=\"labels().search\"\n (onSearchChange)=\"categorySearch.set($event)\"\n >\n @for (opt of addOptions(); track opt.key; let i = $index) {\n @if (needsDivider(addOptions(), i)) {\n <monkey-divider />\n }\n <monkey-filter-menu-item\n [leadIcon]=\"opt.icon ?? null\"\n [label]=\"opt.label\"\n (onItemClick)=\"onSelectCategory(i)\"\n />\n }\n </monkey-filter-menu>\n }\n </monkey-filter-trigger>\n </span>\n }\n </div>\n @if (rows().length > 0) {\n <monkey-scrollbar\n class=\"mecx-filter-bar-bar\"\n orientation=\"horizontal\"\n size=\"small\"\n [target]=\"rowEl\"\n />\n }\n\n <div class=\"mecx-filter-bar-tail\">\n @if (rows().length > 0) {\n <div class=\"mecx-filter-bar-actions\">\n <monkey-button type=\"tertiary\" size=\"sm\" [disabled]=\"disabled()\" (click)=\"onClearAll()\">\n {{ labels().clear }}\n </monkey-button>\n </div>\n }\n\n <div class=\"mecx-filter-bar-extra\">\n <ng-content></ng-content>\n </div>\n </div>\n</div>\n@if (rows().length > 0) {\n <monkey-divider />\n}\n", styles: [".mecx-filter-bar{--mecx-filter-bar-duration-state: .15s;--mecx-filter-bar-duration-enter: .2s;--mecx-filter-bar-duration-exit: .15s;--mecx-filter-bar-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-filter-bar-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-filter-bar-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-filter-bar-scale-unfold: .94;--mecx-filter-bar-travel-anchored: 4px;--mecx-filter-bar-travel-slide: 16px;--mecx-filter-bar-stagger: 25ms;--mecx-filter-bar-control-height: 32px;--mecx-filter-bar-pointer-target: 40px;--mecx-filter-bar-reach: calc((var(--mecx-filter-bar-control-height) - var(--mecx-filter-bar-pointer-target)) / 2);--mecx-filter-bar-radius: 8px;--mecx-filter-bar-radius-item: 4px;--mecx-filter-bar-fade-width: 48px;--mecx-filter-bar-focus-reach: 4px;--mecx-filter-bar-z-raised: 1;--mecx-filter-bar-z-sticky: 2;--mecx-filter-bar-z-menu: 1000}@media(prefers-reduced-motion:reduce){.mecx-filter-bar{--mecx-filter-bar-duration-state: 1ms;--mecx-filter-bar-duration-enter: 1ms;--mecx-filter-bar-duration-exit: 1ms;--mecx-filter-bar-scale-unfold: 1;--mecx-filter-bar-travel-anchored: 0px;--mecx-filter-bar-travel-slide: 0px;--mecx-filter-bar-stagger: 0ms}}.mecx-filter-bar{display:flex;flex-direction:column;gap:8px;width:100%;background:var(--mecx-color-white)}.mecx-filter-bar-top{display:flex;align-items:center;gap:8px;width:100%}.mecx-filter-bar-search{flex:1;min-width:0;max-width:400px;display:block}.mecx-filter-bar-extra{margin-left:auto;display:flex;align-items:center;flex-wrap:wrap;gap:8px}.mecx-filter-bar-extra:empty{display:none}.mecx-filter-bar-line{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:\"row tail\" \"bar bar\";align-items:center;row-gap:8px;width:100%}.mecx-filter-bar-bar{grid-area:bar;min-width:0}.mecx-filter-bar-tail{grid-area:tail;display:flex;align-items:center;min-width:0}.mecx-filter-bar-row{grid-area:row;display:flex;align-items:center;gap:8px;min-width:0;overflow-x:auto;position:relative;min-height:var(--mecx-filter-bar-pointer-target);margin-inline-start:calc(var(--mecx-filter-bar-focus-reach) * -1);padding-inline:var(--mecx-filter-bar-focus-reach) var(--mecx-filter-bar-fade-width);scroll-padding-inline-start:var(--mecx-filter-bar-focus-reach);scrollbar-width:none;-ms-overflow-style:none}.mecx-filter-bar-row::-webkit-scrollbar{width:0;height:0}.mecx-filter-bar--disabled .mecx-filter-bar-row{cursor:default}.mecx-filter-bar-actions{position:relative;display:flex;align-items:center;justify-content:flex-end;align-self:stretch;flex-shrink:0;padding-left:var(--mecx-filter-bar-fade-width);background:var(--mecx-color-white)}.mecx-filter-bar-actions:before{content:\"\";position:absolute;inset-block:0;right:100%;width:var(--mecx-filter-bar-fade-width);background:linear-gradient(to right,transparent,var(--mecx-color-white));pointer-events:none}.mecx-filter-bar-slot{display:inline-flex;flex-shrink:0;transition:translate var(--mecx-filter-bar-duration-enter) var(--mecx-filter-bar-ease-enter)}.mecx-filter-bar-slot--frozen{transition-duration:0s}@keyframes mecx-filter-bar-slot-in{0%{opacity:0;translate:calc(var(--mecx-filter-bar-travel-slide) * -1) 0}}@keyframes mecx-filter-bar-slot-out{to{opacity:0;translate:calc(var(--mecx-filter-bar-travel-slide) * -1) 0}}.mecx-filter-bar-slot--leaving{position:absolute;pointer-events:none;animation:mecx-filter-bar-slot-out var(--mecx-filter-bar-duration-exit) var(--mecx-filter-bar-ease-exit) both}.mecx-filter-bar-slot--entering{animation:mecx-filter-bar-slot-in var(--mecx-filter-bar-duration-enter) var(--mecx-filter-bar-ease-enter);position:relative;z-index:var(--mecx-filter-bar-z-raised)}.mecx-filter-bar-slot:has(.mecx-filter-segment--open),.mecx-filter-bar-slot:has(.mecx-filter-trigger--open){z-index:var(--mecx-filter-bar-z-menu)}.mecx-filter-menu.mecx-filter-bar-menu-categories{width:220px}.mecx-filter-menu.mecx-filter-bar-menu-status{width:225px}.mecx-filter-menu.mecx-filter-bar-menu-field{width:238px}.mecx-filter-bar-field{display:flex;flex-direction:column;gap:8px;width:100%;box-sizing:border-box}.mecx-filter-bar-field monkey-form-field{display:block;width:100%}.mecx-filter-bar-field monkey-button,.mecx-filter-bar-field monkey-button .mecx-button{width:100%}.mecx-filter-bar-field-row{display:flex;flex-direction:column;gap:4px;width:100%;cursor:pointer}.mecx-filter-bar-field-label{color:var(--mecx-color-gray-900);font-size:14px;font-weight:400;line-height:24px;letter-spacing:.14px}.mecx-filter-bar-panel-actions{display:flex;margin-top:8px;padding-top:8px;border-top:1px solid var(--mecx-color-gray-200)}.mecx-filter-bar-panel-actions monkey-button,.mecx-filter-bar-panel-actions monkey-button .mecx-button{width:100%}.mecx-filter-bar-calendar{display:block;background:var(--mecx-color-white);border-radius:var(--mecx-filter-bar-radius);box-shadow:0 8px 12px -4px var(--mecx-color-box-shadow, rgba(47, 50, 55, .08))}@media(max-width:767.98px){.mecx-filter-bar-line{grid-template-columns:minmax(0,1fr);grid-template-areas:\"row\" \"bar\" \"tail\";position:relative}.mecx-filter-bar-slot--trigger{position:sticky;right:0;z-index:var(--mecx-filter-bar-z-sticky)}.mecx-filter-bar-row{margin-inline-end:calc(var(--mecx-filter-bar-focus-reach) * -1);padding-inline-end:var(--mecx-filter-bar-focus-reach)}.mecx-filter-bar-actions{padding-left:0;align-self:auto;background:none;position:static}.mecx-filter-bar-actions:before{right:var(--mecx-filter-bar-control-height);bottom:auto;height:var(--mecx-filter-bar-pointer-target)}}\n/*!\n* Bootstrap Grid v5.3.7 (https://getbootstrap.com/)\n* Copyright 2011-2025 The Bootstrap Authors\n* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n*/\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MonkeyButtonComponent, selector: "monkey-button", inputs: ["disabled", "color", "size", "type", "loading", "id"] }, { kind: "component", type: MonkeyDateRangeComponent, selector: "monkey-date-range", inputs: ["startDate", "endDate", "hideQuickAction", "hideHeader", "hideActions", "hideSecondCalendar", "allowFastActionOnHeader", "minDate", "maxDate", "id"], outputs: ["onCancel", "onDate"] }, { kind: "component", type: MonkeyDividerComponent, selector: "monkey-divider", inputs: ["size", "vertical", "id"] }, { kind: "component", type: MonkeyFilterChipComponent, selector: "monkey-filter-chip", inputs: ["removeIcon", "removeLabel", "disabled"], outputs: ["onRemove"] }, { kind: "component", type: MonkeyFilterMenuComponent, selector: "monkey-filter-menu", inputs: ["showSearch", "searchPlaceholder", "showScroll", "maxHeight"], outputs: ["onSearchChange"] }, { kind: "component", type: MonkeyFilterMenuItemComponent, selector: "monkey-filter-menu-item", inputs: ["property", "leadIcon", "label", "description", "checked", "selected", "disabled"], outputs: ["onItemClick"] }, { kind: "component", type: MonkeyFilterSegmentComponent, selector: "monkey-filter-segment", inputs: ["icon", "text", "placeholder", "readonlySegment", "disabled", "open"], outputs: ["onOpenChange", "onSegmentClick"] }, { kind: "component", type: MonkeyFilterTriggerComponent, selector: "monkey-filter-trigger", inputs: ["variant", "icon", "text", "ariaLabel", "disabled", "immediateExit", "open", "alignment"], outputs: ["onOpenChange"] }, { kind: "ngmodule", type: MonkeyFormFieldModule }, { kind: "component", type: MonkeyFormFieldComponent, selector: "monkey-form-field", inputs: ["id", "hideAction", "enableClear", "size", "noFooterSpace", "displayOnly"], outputs: ["onDisplayOnlyChange"], exportAs: ["monkeyFormField"] }, { kind: "ngmodule", type: MonkeyInputModule }, { kind: "directive", type: MonkeyInputDirective, selector: "input[monkey-input],textarea[monkey-input]", inputs: ["name", "disabled", "id", "required", "type", "min", "max", "percent"], exportAs: ["monkeyInput"] }, { kind: "directive", type: MonkeyInputCurrencyDirective, selector: "input[monkey-input-currency]", inputs: ["name", "disabled", "id", "required", "type"], exportAs: ["monkeyInput"] }, { kind: "component", type: MonkeyScrollbarComponent, selector: "monkey-scrollbar", inputs: ["orientation", "size", "target"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
8313
7092
  }
8314
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterBarV2Component, decorators: [{
7093
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterBarComponent, decorators: [{
8315
7094
  type: Component,
8316
- args: [{ selector: 'monkey-filter-bar-v2', imports: [
7095
+ args: [{ selector: 'monkey-filter-bar', imports: [
8317
7096
  FormsModule,
8318
7097
  MonkeyButtonComponent,
8319
- MonkeyCheckboxComponent,
8320
7098
  MonkeyDateRangeComponent,
8321
7099
  MonkeyDividerComponent,
8322
7100
  MonkeyFilterChipComponent,
@@ -8326,16 +7104,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
8326
7104
  MonkeyFilterTriggerComponent,
8327
7105
  MonkeyFormFieldModule,
8328
7106
  MonkeyInputModule,
8329
- MonkeyLabelDirective,
8330
- MonkeyOptionComponent,
8331
- MonkeyPrefixDirective,
8332
- MonkeyRadioButtonComponent,
8333
7107
  MonkeyScrollbarComponent
8334
7108
  ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
8335
- 'data-testid': 'monkey-filter-bar-v2',
8336
- class: 'mecx-filter-bar-v2'
8337
- }, template: "<!-- Top row: the free-text search and whatever the consumer projects. Kept\n from monkey-filter-bar \u2014 the search is part of this bar's contract\n (`searchChange`), not of the chip row. -->\n<div class=\"mecx-filter-bar-v2-top\">\n <monkey-form-field class=\"mecx-filter-bar-v2-search\" size=\"sm\">\n <input\n type=\"text\"\n monkey-input\n [placeholder]=\"searchPlaceholder()\"\n [ngModel]=\"searchValue()\"\n (ngModelChange)=\"onSearchChange($event)\"\n />\n <monkey-prefix>\n <i class=\"mk-i mk-i-search fs-md\"></i>\n </monkey-prefix>\n </monkey-form-field>\n\n <div class=\"mecx-filter-bar-v2-extra\">\n <ng-content></ng-content>\n </div>\n</div>\n\n<div class=\"mecx-filter-bar-v2-line\">\n <div #rowEl class=\"mecx-filter-bar-v2-row\">\n @for (f of rows(); track f.key) {\n <span\n class=\"mecx-filter-bar-v2-slot\"\n [attr.data-flip-id]=\"f.key\"\n [animate.enter]=\"appPainted() ? 'mecx-filter-bar-v2-slot--entering' : ''\"\n animate.leave=\"mecx-filter-bar-v2-slot--leaving\"\n >\n <monkey-filter-chip (remove)=\"onRemove(f)\">\n <!-- 1 \u00B7 Category \u2014 opens the same list as the trigger, so the user\n can move a filter to another field without deleting it and\n starting over.\n\n The list is repeated here and further down on purpose, and it\n should NOT become a shared <ng-template>: the two differ in what\n they offer (only what can be added, vs. the whole list), in what\n counts as selected, and in what the click does. Sharing the\n markup would mean threading three parameters through a context\n object to save fifteen lines. -->\n <monkey-filter-segment\n [icon]=\"f.icon ?? null\"\n [text]=\"f.label\"\n [open]=\"isOpen(f.key, 'category')\"\n (openChange)=\"onCategoryOpenChange(f, $event)\"\n >\n <!-- Guarded by the same condition the segment uses to show its\n panel. Projected content is created with the view that\n DECLARES it, not with the one that renders it, so without this\n every chip would build both of its panels \u2014 menus, rows,\n fields and all \u2014 and keep them alive while closed. -->\n @if (isOpen(f.key, 'category')) {\n <monkey-filter-menu\n class=\"mecx-filter-bar-v2-menu-categories\"\n [showSearch]=\"true\"\n searchPlaceholder=\"Buscar filtro\"\n (searchChange)=\"categorySearch.set($event)\"\n >\n @for (opt of changeOptions(); track opt.key; let i = $index) {\n @if (needsDivider(changeOptions(), i)) {\n <monkey-divider />\n }\n <monkey-filter-menu-item\n [leadIcon]=\"opt.icon ?? null\"\n [label]=\"opt.label\"\n [selected]=\"opt.key === f.key\"\n [disabled]=\"opt.key !== f.key && isFilterActive(opt.key)\"\n (itemClick)=\"onChangeCategory(f, i)\"\n />\n }\n </monkey-filter-menu>\n }\n </monkey-filter-segment>\n\n <!-- 2 \u00B7 Value \u2014 the panel it opens is decided by the filter type,\n and it is the same panel that the chip's answer came from. That\n is what makes clicking a chip an EDIT instead of a restart. -->\n <monkey-filter-segment\n [placeholder]=\"valuePlaceholder(f)\"\n [text]=\"f.value\"\n [open]=\"isOpen(f.key, 'value')\"\n (openChange)=\"onValueOpenChange(f, $event)\"\n >\n @if (isOpen(f.key, 'value')) {\n @switch (f.type) {\n <!-- status \u2014 a multiple choice, so the answer is only written\n on Confirmar. Ticking a box is not yet a decision. -->\n @case ('status') {\n <monkey-filter-menu class=\"mecx-filter-bar-v2-menu-status\" [showSearch]=\"false\">\n @for (s of statusOptionsOf(f); track s.value) {\n <monkey-filter-menu-item\n property=\"checkbox\"\n [label]=\"s.description\"\n [checked]=\"statusValues.includes(s.value)\"\n (itemClick)=\"onToggleStatus(s.value)\"\n />\n }\n <div class=\"mecx-filter-bar-v2-panel-actions\">\n <monkey-button type=\"secondary\" size=\"sm\" (click)=\"onApply(f)\">\n Confirmar\n </monkey-button>\n </div>\n </monkey-filter-menu>\n }\n\n <!-- date \u2014 the shortcuts are the way in and the calendar is\n the detour. \"Personalizado\" swaps the CONTENT of this\n panel, which stays anchored to the same segment: no modal,\n because the dialog was almost all frame around a calendar\n and the segment already knows how to hang anything. The\n footer here is the date range's own, and Cancelar goes\n back to the shortcuts. -->\n @case ('date') {\n @if (calendarOpen() === f.key) {\n <monkey-date-range\n class=\"mecx-filter-bar-v2-calendar\"\n [startDate]=\"dateRange.startDate\"\n [endDate]=\"dateRange.endDate\"\n [minDate]=\"minDateOf(f)\"\n [maxDate]=\"maxDateOf(f)\"\n (onDate)=\"onDateChange(f, $event)\"\n (onCancel)=\"onBackToShortcuts()\"\n ></monkey-date-range>\n } @else {\n <monkey-filter-menu [showSearch]=\"false\">\n <monkey-filter-menu-item\n label=\"1 semana a partir de hoje\"\n (itemClick)=\"onQuickDate(f, '1-week-after')\"\n />\n <monkey-filter-menu-item\n label=\"1 m\u00EAs a partir de hoje\"\n (itemClick)=\"onQuickDate(f, '1-month-after')\"\n />\n <monkey-filter-menu-item\n label=\"3 meses a partir de hoje\"\n (itemClick)=\"onQuickDate(f, '3-months-after')\"\n />\n <monkey-filter-menu-item\n label=\"1 semana antes de hoje\"\n (itemClick)=\"onQuickDate(f, '1-week-before')\"\n />\n <monkey-filter-menu-item\n label=\"1 m\u00EAs antes de hoje\"\n (itemClick)=\"onQuickDate(f, '1-month-before')\"\n />\n <monkey-filter-menu-item\n label=\"3 meses antes de hoje\"\n (itemClick)=\"onQuickDate(f, '3-months-before')\"\n />\n <monkey-filter-menu-item\n label=\"Personalizado\"\n (itemClick)=\"onQuickDate(f, 'custom')\"\n />\n </monkey-filter-menu>\n }\n }\n\n <!-- currency \u2014 one amount and the side it applies to. The\n label lives inside the field, which is what lets the panel\n close in 238px instead of spending a line on a title. -->\n @case ('currency') {\n <monkey-filter-menu class=\"mecx-filter-bar-v2-menu-field\" [showSearch]=\"false\">\n <div class=\"mecx-filter-bar-v2-field\">\n <monkey-radiobutton [(ngModel)]=\"currencyMode\" position=\"vertical\" size=\"sm\">\n <monkey-option [value]=\"'from'\">De</monkey-option>\n <monkey-option [value]=\"'until'\">At\u00E9</monkey-option>\n </monkey-radiobutton>\n\n <monkey-form-field size=\"sm\">\n <monkey-label>{{ f.label }}</monkey-label>\n <input\n type=\"text\"\n monkey-input-currency\n [placeholder]=\"currencyMode === 'from' ? 'Valor m\u00EDnimo' : 'Valor m\u00E1ximo'\"\n [(ngModel)]=\"currencyValue\"\n (keyup.enter)=\"onApply(f)\"\n />\n </monkey-form-field>\n\n <monkey-button type=\"secondary\" size=\"sm\" (click)=\"onApply(f)\">\n Confirmar\n </monkey-button>\n </div>\n </monkey-filter-menu>\n }\n\n <!-- text \u2014 a single field, so the answer is the text itself. -->\n @default {\n <monkey-filter-menu class=\"mecx-filter-bar-v2-menu-field\" [showSearch]=\"false\">\n <div class=\"mecx-filter-bar-v2-field\">\n <monkey-form-field size=\"sm\">\n <monkey-label>{{ f.label }}</monkey-label>\n <input\n type=\"text\"\n monkey-input\n [placeholder]=\"valuePlaceholder(f)\"\n [(ngModel)]=\"textValue\"\n (keyup.enter)=\"onApply(f)\"\n />\n </monkey-form-field>\n\n <monkey-button type=\"secondary\" size=\"sm\" (click)=\"onApply(f)\">\n Confirmar\n </monkey-button>\n </div>\n </monkey-filter-menu>\n }\n }\n }\n </monkey-filter-segment>\n </monkey-filter-chip>\n </span>\n }\n\n <!-- The trigger is the last slot of the row. Its FLIP identity changes\n along with the variant (see triggerFlipId): with the bar empty it is\n the labelled \"Filtro\" and it goes away with the first filter; the \"+\"\n that takes its place inherits no position, so there is no button\n sliding along and dragging the panel that is closing. -->\n <span class=\"mecx-filter-bar-v2-slot\" [attr.data-flip-id]=\"triggerFlipId()\">\n <monkey-filter-trigger\n [variant]=\"triggerVariant()\"\n [icon]=\"triggerIcon()\"\n [text]=\"addFilterLabel()\"\n [immediateExit]=\"immediateTriggerExit()\"\n [open]=\"triggerOpen()\"\n (openChange)=\"onTriggerOpenChange($event)\"\n >\n @if (triggerOpen()) {\n <monkey-filter-menu\n class=\"mecx-filter-bar-v2-menu-categories\"\n [showSearch]=\"true\"\n searchPlaceholder=\"Buscar filtro\"\n (searchChange)=\"categorySearch.set($event)\"\n >\n @for (opt of addOptions(); track opt.key; let i = $index) {\n @if (needsDivider(addOptions(), i)) {\n <monkey-divider />\n }\n <monkey-filter-menu-item\n [leadIcon]=\"opt.icon ?? null\"\n [label]=\"opt.label\"\n (itemClick)=\"onSelectCategory(i)\"\n />\n }\n </monkey-filter-menu>\n }\n </monkey-filter-trigger>\n </span>\n </div>\n\n <!-- Gradient plus action. The gradient exists so the chips FADE OUT as they\n pass underneath instead of being cut off hard by the edge of what\n scrolls. -->\n @if (rows().length > 0) {\n <div class=\"mecx-filter-bar-v2-actions\">\n <monkey-button type=\"tertiary\" size=\"sm\" (click)=\"onClearAll()\">\n {{ clearAllLabel() }}\n </monkey-button>\n </div>\n }\n</div>\n\n<!-- Drawn bar plus divider. The bar hides itself when there is nothing to\n scroll, so filters existing is enough for it to be mounted. -->\n@if (rows().length > 0) {\n <monkey-scrollbar orientation=\"horizontal\" size=\"small\" [target]=\"rowEl\" />\n <monkey-divider />\n}\n", styles: ["@charset \"UTF-8\";.mecx-filter-bar-v2{--mecx-fbv2-duration-state: .15s;--mecx-fbv2-duration-enter: .2s;--mecx-fbv2-duration-exit: .15s;--mecx-fbv2-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-fbv2-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-fbv2-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-fbv2-scale-unfold: .94;--mecx-fbv2-travel-anchored: 4px;--mecx-fbv2-travel-slide: 16px;--mecx-fbv2-stagger: 25ms;--mecx-fbv2-control-height: 28px;--mecx-fbv2-pointer-target: 40px;--mecx-fbv2-radius: 8px;--mecx-fbv2-radius-item: 4px;--mecx-fbv2-fade-width: 48px}@media(prefers-reduced-motion:reduce){.mecx-filter-bar-v2{--mecx-fbv2-duration-state: 1ms;--mecx-fbv2-duration-enter: 1ms;--mecx-fbv2-duration-exit: 1ms;--mecx-fbv2-scale-unfold: 1;--mecx-fbv2-travel-anchored: 0px;--mecx-fbv2-travel-slide: 0px;--mecx-fbv2-stagger: 0ms}}.mecx-filter-bar-v2{display:flex;flex-direction:column;gap:8px;width:100%;background:var(--mecx-color-white)}.mecx-filter-bar-v2-top{display:flex;align-items:center;gap:8px;width:100%}.mecx-filter-bar-v2-search{flex:1;min-width:0;max-width:400px;display:block}.mecx-filter-bar-v2-extra{margin-left:auto;display:flex;align-items:center;gap:8px}.mecx-filter-bar-v2-line{display:flex;align-items:center;width:100%}.mecx-filter-bar-v2-row{display:flex;align-items:center;gap:8px;flex:1 0 0;min-width:0;overflow-x:auto;position:relative;min-height:var(--mecx-fbv2-pointer-target);padding-inline-end:var(--mecx-fbv2-fade-width);scrollbar-width:none;-ms-overflow-style:none}.mecx-filter-bar-v2-row::-webkit-scrollbar{width:0;height:0}.mecx-filter-bar-v2-actions{position:relative;display:flex;align-items:center;justify-content:flex-end;align-self:stretch;flex-shrink:0;padding-left:var(--mecx-fbv2-fade-width);background:var(--mecx-color-white)}.mecx-filter-bar-v2-actions:before{content:\"\";position:absolute;inset-block:0;right:100%;width:var(--mecx-fbv2-fade-width);background:linear-gradient(to right,transparent,var(--mecx-color-white));pointer-events:none}.mecx-filter-bar-v2-slot{display:inline-flex;flex-shrink:0;transition:translate var(--mecx-fbv2-duration-enter) var(--mecx-fbv2-ease-enter)}.mecx-filter-bar-v2-slot--frozen{transition-duration:0s}@keyframes mecx-filter-bar-v2-slot-in{0%{opacity:0;translate:calc(var(--mecx-fbv2-travel-slide) * -1) 0}}@keyframes mecx-filter-bar-v2-slot-out{to{opacity:0;translate:calc(var(--mecx-fbv2-travel-slide) * -1) 0}}.mecx-filter-bar-v2-slot--leaving{position:absolute;pointer-events:none;animation:mecx-filter-bar-v2-slot-out var(--mecx-fbv2-duration-exit) var(--mecx-fbv2-ease-exit) both}.mecx-filter-bar-v2-slot--entering{animation:mecx-filter-bar-v2-slot-in var(--mecx-fbv2-duration-enter) var(--mecx-fbv2-ease-enter);position:relative;z-index:1}.mecx-filter-menu.mecx-filter-bar-v2-menu-categories{width:198px}.mecx-filter-menu.mecx-filter-bar-v2-menu-status{width:225px}.mecx-filter-menu.mecx-filter-bar-v2-menu-field{width:238px}.mecx-filter-bar-v2-field{display:flex;flex-direction:column;gap:8px;width:100%;box-sizing:border-box}.mecx-filter-bar-v2-field monkey-form-field{display:block;width:100%}.mecx-filter-bar-v2-field monkey-button,.mecx-filter-bar-v2-field monkey-button .mecx-button{width:100%}.mecx-filter-bar-v2-panel-actions{display:flex;margin-top:8px;padding-top:8px;border-top:1px solid var(--mecx-color-gray-200)}.mecx-filter-bar-v2-panel-actions monkey-button,.mecx-filter-bar-v2-panel-actions monkey-button .mecx-button{width:100%}.mecx-filter-bar-v2-calendar{display:block;background:var(--mecx-color-white);border-radius:var(--mecx-fbv2-radius);box-shadow:0 8px 12px -4px var(--mecx-color-box-shadow, rgba(47, 50, 55, .08))}\n"] }]
8338
- }], ctorParameters: () => [], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], addFilterLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "addFilterLabel", required: false }] }], clearAllLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearAllLabel", required: false }] }], filtersChange: [{ type: i0.Output, args: ["filtersChange"] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }] } });
7109
+ 'data-testid': 'monkey-filter-bar',
7110
+ class: 'mecx-filter-bar',
7111
+ '[class.mecx-filter-bar--disabled]': 'disabled()'
7112
+ }, template: "<div class=\"mecx-filter-bar-line\">\n <div #rowEl class=\"mecx-filter-bar-row\">\n @for (f of rows(); track f.key) {\n <span\n class=\"mecx-filter-bar-slot\"\n [attr.data-flip-id]=\"f.key\"\n [animate.enter]=\"appPainted() ? 'mecx-filter-bar-slot--entering' : ''\"\n animate.leave=\"mecx-filter-bar-slot--leaving\"\n >\n <monkey-filter-chip\n [removeLabel]=\"labels().remove\"\n [disabled]=\"disabled()\"\n (onRemove)=\"onRemove(f)\"\n >\n <monkey-filter-segment\n [icon]=\"f.icon ?? null\"\n [text]=\"f.label\"\n [disabled]=\"disabled()\"\n [open]=\"isOpen(f.key, 'category')\"\n (onOpenChange)=\"onCategoryOpenChange(f, $event)\"\n >\n @if (isOpen(f.key, 'category')) {\n <monkey-filter-menu\n class=\"mecx-filter-bar-menu-categories\"\n [showSearch]=\"true\"\n [searchPlaceholder]=\"labels().search\"\n (onSearchChange)=\"categorySearch.set($event)\"\n >\n @for (opt of changeOptions(); track opt.key; let i = $index) {\n @if (needsDivider(changeOptions(), i)) {\n <monkey-divider />\n }\n <monkey-filter-menu-item\n [leadIcon]=\"opt.icon ?? null\"\n [label]=\"opt.label\"\n [selected]=\"opt.key === f.key\"\n [disabled]=\"opt.key !== f.key && isFilterActive(opt.key)\"\n (onItemClick)=\"onChangeCategory(f, i)\"\n />\n }\n </monkey-filter-menu>\n }\n </monkey-filter-segment>\n <monkey-filter-segment\n [placeholder]=\"labels().selectCondition\"\n [text]=\"operatorLabel(f.condition)\"\n [disabled]=\"disabled()\"\n [open]=\"isOpen(f.key, 'condition')\"\n (onOpenChange)=\"onConditionOpenChange(f, $event)\"\n >\n @if (isOpen(f.key, 'condition')) {\n <monkey-filter-menu class=\"mecx-filter-bar-menu-conditions\" [showSearch]=\"false\">\n @for (c of conditionsFor(f); track c) {\n <monkey-filter-menu-item\n [label]=\"operatorLabel(c)\"\n [selected]=\"c === f.condition\"\n (onItemClick)=\"onSelectCondition(f, c)\"\n />\n }\n </monkey-filter-menu>\n }\n </monkey-filter-segment>\n @if (hasValueSegment(f)) {\n <monkey-filter-segment\n [placeholder]=\"valuePlaceholder(f)\"\n [text]=\"displayOf(f)\"\n [disabled]=\"disabled()\"\n [open]=\"isOpen(f.key, 'value')\"\n (onOpenChange)=\"onValueOpenChange(f, $event)\"\n >\n @if (isOpen(f.key, 'value')) {\n @switch (panelFor(f)) {\n @case ('status') {\n <monkey-filter-menu class=\"mecx-filter-bar-menu-status\" [showSearch]=\"false\">\n @for (s of statusOptionsOf(f); track s.value) {\n <monkey-filter-menu-item\n property=\"checkbox\"\n [label]=\"s.description\"\n [checked]=\"statusValues.includes(s.value)\"\n (onItemClick)=\"onToggleStatus(s.value)\"\n />\n }\n <div class=\"mecx-filter-bar-panel-actions\">\n <monkey-button type=\"secondary\" size=\"sm\" (click)=\"onApply(f)\">\n {{ labels().confirm }}\n </monkey-button>\n </div>\n </monkey-filter-menu>\n }\n\n @case ('date-day') {\n <monkey-filter-menu class=\"mecx-filter-bar-menu-field\" [showSearch]=\"false\">\n <div class=\"mecx-filter-bar-field\">\n <label class=\"mecx-filter-bar-field-row\">\n <span class=\"mecx-filter-bar-field-label\">{{ f.label }}</span>\n <monkey-form-field size=\"sm\" noFooterSpace>\n <input\n type=\"date\"\n monkey-input\n [(ngModel)]=\"dayValue\"\n (keyup.enter)=\"onApply(f)\"\n />\n </monkey-form-field>\n </label>\n <monkey-button type=\"secondary\" size=\"sm\" (click)=\"onApply(f)\">\n {{ labels().confirm }}\n </monkey-button>\n </div>\n </monkey-filter-menu>\n }\n\n @case ('date-range') {\n @if (calendarOpen() === f.key) {\n <monkey-date-range\n class=\"mecx-filter-bar-calendar\"\n [startDate]=\"dateRange.startDate\"\n [endDate]=\"dateRange.endDate\"\n [minDate]=\"minDateOf(f)\"\n [maxDate]=\"maxDateOf(f)\"\n (onDate)=\"onDateChange(f, $event)\"\n (onCancel)=\"onBackToShortcuts()\"\n ></monkey-date-range>\n } @else {\n <monkey-filter-menu [showSearch]=\"false\">\n @for (shortcut of dateShortcuts(); track shortcut.key) {\n <monkey-filter-menu-item\n [label]=\"shortcut.label\"\n (onItemClick)=\"onQuickDate(f, shortcut.key)\"\n />\n }\n </monkey-filter-menu>\n }\n }\n\n @default {\n <monkey-filter-menu class=\"mecx-filter-bar-menu-field\" [showSearch]=\"false\">\n <div class=\"mecx-filter-bar-field\">\n @if (f.type === 'currency') {\n <label class=\"mecx-filter-bar-field-row\">\n <span class=\"mecx-filter-bar-field-label\">\n {{ isRange(f) ? labels().rangeFrom : f.label }}\n </span>\n <monkey-form-field size=\"sm\" noFooterSpace>\n <input\n type=\"text\"\n monkey-input-currency\n [(ngModel)]=\"currencyValue\"\n (keyup.enter)=\"onApply(f)\"\n />\n </monkey-form-field>\n </label>\n @if (isRange(f)) {\n <label class=\"mecx-filter-bar-field-row\">\n <span class=\"mecx-filter-bar-field-label\">{{ labels().rangeTo }}</span>\n <monkey-form-field size=\"sm\" noFooterSpace>\n <input\n type=\"text\"\n monkey-input-currency\n [(ngModel)]=\"currencyValue2\"\n (keyup.enter)=\"onApply(f)\"\n />\n </monkey-form-field>\n </label>\n }\n } @else {\n <label class=\"mecx-filter-bar-field-row\">\n <span class=\"mecx-filter-bar-field-label\">\n {{ isRange(f) ? labels().rangeFrom : f.label }}\n </span>\n <monkey-form-field size=\"sm\" noFooterSpace>\n <input\n type=\"text\"\n monkey-input\n [placeholder]=\"valuePlaceholder(f)\"\n [(ngModel)]=\"textValue\"\n (keyup.enter)=\"onApply(f)\"\n />\n </monkey-form-field>\n </label>\n @if (isRange(f)) {\n <label class=\"mecx-filter-bar-field-row\">\n <span class=\"mecx-filter-bar-field-label\">{{ labels().rangeTo }}</span>\n <monkey-form-field size=\"sm\" noFooterSpace>\n <input\n type=\"text\"\n monkey-input\n [(ngModel)]=\"textValue2\"\n (keyup.enter)=\"onApply(f)\"\n />\n </monkey-form-field>\n </label>\n }\n }\n\n <monkey-button type=\"secondary\" size=\"sm\" (click)=\"onApply(f)\">\n {{ labels().confirm }}\n </monkey-button>\n </div>\n </monkey-filter-menu>\n }\n }\n }\n </monkey-filter-segment>\n }\n </monkey-filter-chip>\n </span>\n }\n\n @if (canAddFilter()) {\n <span\n class=\"mecx-filter-bar-slot mecx-filter-bar-slot--trigger\"\n [attr.data-flip-id]=\"triggerFlipId()\"\n >\n <monkey-filter-trigger\n [variant]=\"triggerVariant()\"\n [icon]=\"triggerIcon()\"\n [text]=\"labels().add\"\n [ariaLabel]=\"labels().addAria\"\n [disabled]=\"disabled()\"\n [immediateExit]=\"immediateTriggerExit()\"\n [open]=\"triggerOpen()\"\n (onOpenChange)=\"onTriggerOpenChange($event)\"\n >\n @if (triggerOpen()) {\n <monkey-filter-menu\n class=\"mecx-filter-bar-menu-categories\"\n [showSearch]=\"true\"\n [searchPlaceholder]=\"labels().search\"\n (onSearchChange)=\"categorySearch.set($event)\"\n >\n @for (opt of addOptions(); track opt.key; let i = $index) {\n @if (needsDivider(addOptions(), i)) {\n <monkey-divider />\n }\n <monkey-filter-menu-item\n [leadIcon]=\"opt.icon ?? null\"\n [label]=\"opt.label\"\n (onItemClick)=\"onSelectCategory(i)\"\n />\n }\n </monkey-filter-menu>\n }\n </monkey-filter-trigger>\n </span>\n }\n </div>\n @if (rows().length > 0) {\n <monkey-scrollbar\n class=\"mecx-filter-bar-bar\"\n orientation=\"horizontal\"\n size=\"small\"\n [target]=\"rowEl\"\n />\n }\n\n <div class=\"mecx-filter-bar-tail\">\n @if (rows().length > 0) {\n <div class=\"mecx-filter-bar-actions\">\n <monkey-button type=\"tertiary\" size=\"sm\" [disabled]=\"disabled()\" (click)=\"onClearAll()\">\n {{ labels().clear }}\n </monkey-button>\n </div>\n }\n\n <div class=\"mecx-filter-bar-extra\">\n <ng-content></ng-content>\n </div>\n </div>\n</div>\n@if (rows().length > 0) {\n <monkey-divider />\n}\n", styles: [".mecx-filter-bar{--mecx-filter-bar-duration-state: .15s;--mecx-filter-bar-duration-enter: .2s;--mecx-filter-bar-duration-exit: .15s;--mecx-filter-bar-ease-state: cubic-bezier(.25, .46, .45, .94);--mecx-filter-bar-ease-enter: cubic-bezier(.32, .72, 0, 1);--mecx-filter-bar-ease-exit: cubic-bezier(.4, 0, 1, 1);--mecx-filter-bar-scale-unfold: .94;--mecx-filter-bar-travel-anchored: 4px;--mecx-filter-bar-travel-slide: 16px;--mecx-filter-bar-stagger: 25ms;--mecx-filter-bar-control-height: 32px;--mecx-filter-bar-pointer-target: 40px;--mecx-filter-bar-reach: calc((var(--mecx-filter-bar-control-height) - var(--mecx-filter-bar-pointer-target)) / 2);--mecx-filter-bar-radius: 8px;--mecx-filter-bar-radius-item: 4px;--mecx-filter-bar-fade-width: 48px;--mecx-filter-bar-focus-reach: 4px;--mecx-filter-bar-z-raised: 1;--mecx-filter-bar-z-sticky: 2;--mecx-filter-bar-z-menu: 1000}@media(prefers-reduced-motion:reduce){.mecx-filter-bar{--mecx-filter-bar-duration-state: 1ms;--mecx-filter-bar-duration-enter: 1ms;--mecx-filter-bar-duration-exit: 1ms;--mecx-filter-bar-scale-unfold: 1;--mecx-filter-bar-travel-anchored: 0px;--mecx-filter-bar-travel-slide: 0px;--mecx-filter-bar-stagger: 0ms}}.mecx-filter-bar{display:flex;flex-direction:column;gap:8px;width:100%;background:var(--mecx-color-white)}.mecx-filter-bar-top{display:flex;align-items:center;gap:8px;width:100%}.mecx-filter-bar-search{flex:1;min-width:0;max-width:400px;display:block}.mecx-filter-bar-extra{margin-left:auto;display:flex;align-items:center;flex-wrap:wrap;gap:8px}.mecx-filter-bar-extra:empty{display:none}.mecx-filter-bar-line{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:\"row tail\" \"bar bar\";align-items:center;row-gap:8px;width:100%}.mecx-filter-bar-bar{grid-area:bar;min-width:0}.mecx-filter-bar-tail{grid-area:tail;display:flex;align-items:center;min-width:0}.mecx-filter-bar-row{grid-area:row;display:flex;align-items:center;gap:8px;min-width:0;overflow-x:auto;position:relative;min-height:var(--mecx-filter-bar-pointer-target);margin-inline-start:calc(var(--mecx-filter-bar-focus-reach) * -1);padding-inline:var(--mecx-filter-bar-focus-reach) var(--mecx-filter-bar-fade-width);scroll-padding-inline-start:var(--mecx-filter-bar-focus-reach);scrollbar-width:none;-ms-overflow-style:none}.mecx-filter-bar-row::-webkit-scrollbar{width:0;height:0}.mecx-filter-bar--disabled .mecx-filter-bar-row{cursor:default}.mecx-filter-bar-actions{position:relative;display:flex;align-items:center;justify-content:flex-end;align-self:stretch;flex-shrink:0;padding-left:var(--mecx-filter-bar-fade-width);background:var(--mecx-color-white)}.mecx-filter-bar-actions:before{content:\"\";position:absolute;inset-block:0;right:100%;width:var(--mecx-filter-bar-fade-width);background:linear-gradient(to right,transparent,var(--mecx-color-white));pointer-events:none}.mecx-filter-bar-slot{display:inline-flex;flex-shrink:0;transition:translate var(--mecx-filter-bar-duration-enter) var(--mecx-filter-bar-ease-enter)}.mecx-filter-bar-slot--frozen{transition-duration:0s}@keyframes mecx-filter-bar-slot-in{0%{opacity:0;translate:calc(var(--mecx-filter-bar-travel-slide) * -1) 0}}@keyframes mecx-filter-bar-slot-out{to{opacity:0;translate:calc(var(--mecx-filter-bar-travel-slide) * -1) 0}}.mecx-filter-bar-slot--leaving{position:absolute;pointer-events:none;animation:mecx-filter-bar-slot-out var(--mecx-filter-bar-duration-exit) var(--mecx-filter-bar-ease-exit) both}.mecx-filter-bar-slot--entering{animation:mecx-filter-bar-slot-in var(--mecx-filter-bar-duration-enter) var(--mecx-filter-bar-ease-enter);position:relative;z-index:var(--mecx-filter-bar-z-raised)}.mecx-filter-bar-slot:has(.mecx-filter-segment--open),.mecx-filter-bar-slot:has(.mecx-filter-trigger--open){z-index:var(--mecx-filter-bar-z-menu)}.mecx-filter-menu.mecx-filter-bar-menu-categories{width:220px}.mecx-filter-menu.mecx-filter-bar-menu-status{width:225px}.mecx-filter-menu.mecx-filter-bar-menu-field{width:238px}.mecx-filter-bar-field{display:flex;flex-direction:column;gap:8px;width:100%;box-sizing:border-box}.mecx-filter-bar-field monkey-form-field{display:block;width:100%}.mecx-filter-bar-field monkey-button,.mecx-filter-bar-field monkey-button .mecx-button{width:100%}.mecx-filter-bar-field-row{display:flex;flex-direction:column;gap:4px;width:100%;cursor:pointer}.mecx-filter-bar-field-label{color:var(--mecx-color-gray-900);font-size:14px;font-weight:400;line-height:24px;letter-spacing:.14px}.mecx-filter-bar-panel-actions{display:flex;margin-top:8px;padding-top:8px;border-top:1px solid var(--mecx-color-gray-200)}.mecx-filter-bar-panel-actions monkey-button,.mecx-filter-bar-panel-actions monkey-button .mecx-button{width:100%}.mecx-filter-bar-calendar{display:block;background:var(--mecx-color-white);border-radius:var(--mecx-filter-bar-radius);box-shadow:0 8px 12px -4px var(--mecx-color-box-shadow, rgba(47, 50, 55, .08))}@media(max-width:767.98px){.mecx-filter-bar-line{grid-template-columns:minmax(0,1fr);grid-template-areas:\"row\" \"bar\" \"tail\";position:relative}.mecx-filter-bar-slot--trigger{position:sticky;right:0;z-index:var(--mecx-filter-bar-z-sticky)}.mecx-filter-bar-row{margin-inline-end:calc(var(--mecx-filter-bar-focus-reach) * -1);padding-inline-end:var(--mecx-filter-bar-focus-reach)}.mecx-filter-bar-actions{padding-left:0;align-self:auto;background:none;position:static}.mecx-filter-bar-actions:before{right:var(--mecx-filter-bar-control-height);bottom:auto;height:var(--mecx-filter-bar-pointer-target)}}\n/*!\n* Bootstrap Grid v5.3.7 (https://getbootstrap.com/)\n* Copyright 2011-2025 The Bootstrap Authors\n* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n*/\n"] }]
7113
+ }], ctorParameters: () => [], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }], onFiltersChange: [{ type: i0.Output, args: ["onFiltersChange"] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], debounce: [{ type: i0.Input, args: [{ isSignal: true, alias: "debounce", required: false }] }] } });
8339
7114
 
8340
7115
  /** ************************
8341
7116
  * Copyright Monkey Exchange. All Rights Reserved
@@ -10735,6 +9510,191 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
10735
9510
  * MIT Licence
10736
9511
  ************************* */
10737
9512
 
9513
+ /** ************************
9514
+ * Copyright Monkey Exchange. All Rights Reserved
9515
+ * This style guide was developed by Monkey Exchange Team
9516
+ * MIT Licence
9517
+ ************************* */
9518
+ class MonkeyRadioButtonComponent {
9519
+ get classes() {
9520
+ return `${this.position} ${this.size}`;
9521
+ }
9522
+ get disabled() {
9523
+ if (this.ngControl && this.ngControl.disabled !== null) {
9524
+ return this.ngControl.disabled;
9525
+ }
9526
+ return this._disabled;
9527
+ }
9528
+ set disabled(value) {
9529
+ this._disabled = value;
9530
+ if (this.focused) {
9531
+ this.focused = false;
9532
+ this.stateChanges.next();
9533
+ }
9534
+ }
9535
+ get required() {
9536
+ return this._required ?? this.ngControl?.control?.hasValidator(Validators.required) ?? false;
9537
+ }
9538
+ set required(value) {
9539
+ this._required = value;
9540
+ this.stateChanges.next();
9541
+ }
9542
+ set value(value) {
9543
+ if (this._value !== value) {
9544
+ this._value = value;
9545
+ this._onChange(value);
9546
+ }
9547
+ }
9548
+ get value() {
9549
+ return this._value;
9550
+ }
9551
+ constructor(changeDetectorRef, formField) {
9552
+ this.changeDetectorRef = changeDetectorRef;
9553
+ this.formField = formField;
9554
+ this.tabIndex = 0;
9555
+ this.onChange = new EventEmitter();
9556
+ this.onSearch = new EventEmitter();
9557
+ this.position = 'horizontal';
9558
+ this.size = 'lg';
9559
+ this._value = null;
9560
+ this._destroyRef = inject(DestroyRef);
9561
+ this.idGenerator = inject(IdGenerator);
9562
+ this.ngControl = inject(NgControl, { self: true, optional: true });
9563
+ this._elementRef = inject(ElementRef);
9564
+ this.focused = false;
9565
+ this._disabled = false;
9566
+ this.id = this.idGenerator.getId('monkey-radiobutton-');
9567
+ this.stateChanges = new Subject();
9568
+ this.type = 'radio-button';
9569
+ this._onChange = () => { };
9570
+ this._onTouched = () => { };
9571
+ if (this.ngControl) {
9572
+ this.ngControl.valueAccessor = this;
9573
+ }
9574
+ }
9575
+ changeSelected() {
9576
+ setTimeout(() => {
9577
+ if (this.options) {
9578
+ this.options.forEach((opt) => {
9579
+ opt.onSelect(opt.value() === this.value);
9580
+ });
9581
+ }
9582
+ this.changeDetectorRef.markForCheck();
9583
+ });
9584
+ }
9585
+ initializeOptions() {
9586
+ setTimeout(() => {
9587
+ this.options?.forEach((option) => {
9588
+ option.type = 'radio';
9589
+ if (!option.action) {
9590
+ option.action = this.selectOption.bind(this, option);
9591
+ }
9592
+ });
9593
+ this.changeDetectorRef.markForCheck();
9594
+ }, 0);
9595
+ }
9596
+ ngAfterContentInit() {
9597
+ this.initializeOptions();
9598
+ this.options.changes.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(() => {
9599
+ this.initializeOptions();
9600
+ this.changeSelected();
9601
+ });
9602
+ }
9603
+ selectOption(option) {
9604
+ if (!option.disabled && !this.disabled) {
9605
+ this.value = option.value();
9606
+ this._onChange(this.value);
9607
+ this.onChange.emit(this.value);
9608
+ this.options.forEach((opt) => {
9609
+ opt.onSelect(opt.value() === this.value);
9610
+ });
9611
+ }
9612
+ }
9613
+ writeValue(value) {
9614
+ this.value = value;
9615
+ this.changeSelected();
9616
+ }
9617
+ onContainerClick(event) {
9618
+ if (this.disabled)
9619
+ return;
9620
+ this._elementRef.nativeElement.focus();
9621
+ }
9622
+ _onFocus() {
9623
+ if (!this.disabled) {
9624
+ this.focused = true;
9625
+ this._onTouched();
9626
+ this.stateChanges.next();
9627
+ }
9628
+ }
9629
+ _onBlur() {
9630
+ this.focused = false;
9631
+ this.stateChanges.next();
9632
+ }
9633
+ registerOnChange(fn) {
9634
+ this._onChange = fn;
9635
+ }
9636
+ registerOnTouched(fn) {
9637
+ this._onTouched = fn;
9638
+ }
9639
+ setDisabledState(isDisabled) {
9640
+ this.disabled = isDisabled;
9641
+ this.initializeOptions();
9642
+ }
9643
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyRadioButtonComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: MonkeyFormFieldComponent, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
9644
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "21.2.4", type: MonkeyRadioButtonComponent, isStandalone: true, selector: "monkey-radiobutton", inputs: { tabIndex: "tabIndex", position: "position", size: "size", disabled: ["disabled", "disabled", booleanAttribute], required: ["required", "required", booleanAttribute], value: "value" }, outputs: { onChange: "onChange", onSearch: "onSearch" }, host: { attributes: { "data-testid": "monkey-radiobutton" }, listeners: { "focus": "_onFocus()", "blur": "_onBlur()" }, properties: { "class.mecx-disabled": "disabled", "class.mecx-radiobutton-focused": "focused", "attr.id": "id", "attr.tabindex": "disabled ? -1 : tabIndex", "class": "this.classes" }, classAttribute: "mecx-radiobutton" }, providers: [
9645
+ // eslint-disable-next-line no-use-before-define
9646
+ { provide: MonkeyFormFieldControl, useExisting: MonkeyRadioButtonComponent }
9647
+ ], queries: [{ propertyName: "options", predicate: MonkeyOptionComponent }], ngImport: i0, template: "<ng-content />\r\n", styles: ["monkey-radiobutton{display:inline-flex;width:100%;min-width:0;position:relative;flex-wrap:wrap}monkey-radiobutton:focus-visible,monkey-radiobutton:focus{outline:none}monkey-radiobutton.vertical{flex-direction:column}monkey-radiobutton monkey-option{transition:none!important}monkey-radiobutton.mecx-disabled monkey-option{opacity:.5;pointer-events:none}monkey-radiobutton.mecx-disabled monkey-option:before{background:var(--mecx-color-white);border-color:var(--mecx-color-gray-400)}monkey-radiobutton.mecx-form-field-invalid{background:var(--mecx-color-error-700)}monkey-radiobutton.md monkey-option:before{width:16px;height:16px}monkey-radiobutton.sm monkey-option:before{width:14px;height:14px}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
9648
+ }
9649
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyRadioButtonComponent, decorators: [{
9650
+ type: Component,
9651
+ args: [{ selector: 'monkey-radiobutton', imports: [ReactiveFormsModule, FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [
9652
+ // eslint-disable-next-line no-use-before-define
9653
+ { provide: MonkeyFormFieldControl, useExisting: MonkeyRadioButtonComponent }
9654
+ ], host: {
9655
+ 'data-testid': 'monkey-radiobutton',
9656
+ class: 'mecx-radiobutton',
9657
+ '[class.mecx-disabled]': 'disabled',
9658
+ '[class.mecx-radiobutton-focused]': 'focused',
9659
+ '[attr.id]': 'id',
9660
+ '[attr.tabindex]': 'disabled ? -1 : tabIndex',
9661
+ '(focus)': '_onFocus()',
9662
+ '(blur)': '_onBlur()'
9663
+ }, template: "<ng-content />\r\n", styles: ["monkey-radiobutton{display:inline-flex;width:100%;min-width:0;position:relative;flex-wrap:wrap}monkey-radiobutton:focus-visible,monkey-radiobutton:focus{outline:none}monkey-radiobutton.vertical{flex-direction:column}monkey-radiobutton monkey-option{transition:none!important}monkey-radiobutton.mecx-disabled monkey-option{opacity:.5;pointer-events:none}monkey-radiobutton.mecx-disabled monkey-option:before{background:var(--mecx-color-white);border-color:var(--mecx-color-gray-400)}monkey-radiobutton.mecx-form-field-invalid{background:var(--mecx-color-error-700)}monkey-radiobutton.md monkey-option:before{width:16px;height:16px}monkey-radiobutton.sm monkey-option:before{width:14px;height:14px}\n"] }]
9664
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: MonkeyFormFieldComponent, decorators: [{
9665
+ type: Optional
9666
+ }] }], propDecorators: { options: [{
9667
+ type: ContentChildren,
9668
+ args: [MonkeyOptionComponent]
9669
+ }], tabIndex: [{
9670
+ type: Input
9671
+ }], onChange: [{
9672
+ type: Output
9673
+ }], onSearch: [{
9674
+ type: Output
9675
+ }], position: [{
9676
+ type: Input
9677
+ }], size: [{
9678
+ type: Input
9679
+ }], classes: [{
9680
+ type: HostBinding,
9681
+ args: ['class']
9682
+ }], disabled: [{
9683
+ type: Input,
9684
+ args: [{ transform: booleanAttribute }]
9685
+ }], required: [{
9686
+ type: Input,
9687
+ args: [{ transform: booleanAttribute }]
9688
+ }], value: [{
9689
+ type: Input
9690
+ }] } });
9691
+
9692
+ /** ************************
9693
+ * Copyright Monkey Exchange. All Rights Reserved
9694
+ * This style guide was developed by Monkey Exchange Team
9695
+ * MIT Licence
9696
+ ************************* */
9697
+
10738
9698
  /** ************************
10739
9699
  * Copyright Monkey Exchange. All Rights Reserved
10740
9700
  * This style guide was developed by Monkey Exchange Team
@@ -13020,5 +11980,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
13020
11980
  * Generated bundle index. Do not edit.
13021
11981
  */
13022
11982
 
13023
- export { MECX_COUNTRY_ISO_CODE, MECX_GOOGLE_API_KEY, MECX_I18N_WRAPPER, MECX_MODAL_DATA, MECX_MODAL_DEFAULT_CONFIG, MECX_POPOVER_OPTIONS, MonkeyAccordionComponent, MonkeyActionBarComponent, MonkeyAlertComponent, MonkeyAutocompleteAddressComponent, MonkeyAutocompleteComponent, MonkeyAvatarComponent, MonkeyBadgeComponent, MonkeyBadgeDirective, MonkeyBreadcrumbComponent, MonkeyButtonComponent, MonkeyCheckboxComponent, MonkeyComplexFilterBarComponent, MonkeyDateRangeComponent, MonkeyDictionaryService, MonkeyDisplayDirective, MonkeyDividerComponent, MonkeyDownloadButtonComponent, MonkeyEcxAddressService, MonkeyErrorDirective, MonkeyFilterBarComponent, MonkeyFilterBarService, MonkeyFilterBarV2Component, MonkeyFilterChipComponent, MonkeyFilterMenuComponent, MonkeyFilterMenuItemComponent, MonkeyFilterSegmentComponent, MonkeyFilterTriggerComponent, MonkeyFormDirective, MonkeyFormFieldComponent, MonkeyFormFieldControl, MonkeyFormFieldModule, MonkeyHelperDirective, MonkeyIconButtonComponent, MonkeyInfoDirective, MonkeyInputCodeComponent, MonkeyInputCurrencyDirective, MonkeyInputDateRangeComponent, MonkeyInputDirective, MonkeyInputModule, MonkeyInputPhoneComponent, MonkeyInputUploadComponent, MonkeyLabelDirective, MonkeyModalActionsDirective, MonkeyModalComponent, MonkeyModalConfig, MonkeyModalContentDirective, MonkeyModalModule, MonkeyModalRef, MonkeyModalService, MonkeyModalSubtitleDirective, MonkeyModalTitleDirective, MonkeyOptionComponent, MonkeyPaginationActionComponent, MonkeyPaginationLabelComponent, MonkeyPaginationSizeComponent, MonkeyPassNumberComponent, MonkeyPassSecretNumberComponent, MonkeyPopoverContentComponent, MonkeyPopoverDirective, MonkeyPrefixDirective, MonkeyRadioButtonComponent, MonkeyScrollbarComponent, MonkeySecurityLevelComponent, MonkeySelectComponent, MonkeyStatusComponent, MonkeyStepComponent, MonkeyStepperComponent, MonkeyStepperModule, MonkeyStepperService, MonkeySuffixDirective, MonkeyTabComponent, MonkeyTabLinkDirective, MonkeyTableCellDirective, MonkeyTableColumnDirective, MonkeyTableComponent, MonkeyTableEmptyDirective, MonkeyTableHeaderCellDirective, MonkeyTableLoadingDirective, MonkeyTableRowDetailDirective, MonkeyTabsComponent, MonkeyTabsModule, MonkeyToastComponent, MonkeyToastRef, MonkeyToastService, MonkeyToggleComponent, MonkeyToggleLineButtonComponent, MonkeyToggleLineComponent, MonkeyTooltipComponent, MonkeyTooltipDirective, MonkeyUserProfileButtonComponent, MonkeyUserProfileComponent, addKeys, ariaSortOf, getCurrencySymbol, indexAtOffset, injectTokenWithWarning, interpolate, mergeOrder, offsetOfIndex, removeKeys, sameColumnState, selectionState, sortByOrder, toPx, toggleKey, totalHeight };
11983
+ export { MECX_COUNTRY_ISO_CODE, MECX_GOOGLE_API_KEY, MECX_I18N_WRAPPER, MECX_MODAL_DATA, MECX_MODAL_DEFAULT_CONFIG, MECX_POPOVER_OPTIONS, MonkeyAccordionComponent, MonkeyActionBarComponent, MonkeyAlertComponent, MonkeyAutocompleteAddressComponent, MonkeyAutocompleteComponent, MonkeyAvatarComponent, MonkeyBadgeComponent, MonkeyBadgeDirective, MonkeyBreadcrumbComponent, MonkeyButtonComponent, MonkeyCheckboxComponent, MonkeyComplexFilterBarComponent, MonkeyDateRangeComponent, MonkeyDictionaryService, MonkeyDisplayDirective, MonkeyDividerComponent, MonkeyDownloadButtonComponent, MonkeyEcxAddressService, MonkeyErrorDirective, MonkeyFilterBarComponent, MonkeyFilterBarService, MonkeyFilterChipComponent, MonkeyFilterMenuComponent, MonkeyFilterMenuItemComponent, MonkeyFilterSegmentComponent, MonkeyFilterTriggerComponent, MonkeyFormDirective, MonkeyFormFieldComponent, MonkeyFormFieldControl, MonkeyFormFieldModule, MonkeyHelperDirective, MonkeyIconButtonComponent, MonkeyInfoDirective, MonkeyInputCodeComponent, MonkeyInputCurrencyDirective, MonkeyInputDateRangeComponent, MonkeyInputDirective, MonkeyInputModule, MonkeyInputPhoneComponent, MonkeyInputUploadComponent, MonkeyLabelDirective, MonkeyModalActionsDirective, MonkeyModalComponent, MonkeyModalConfig, MonkeyModalContentDirective, MonkeyModalModule, MonkeyModalRef, MonkeyModalService, MonkeyModalSubtitleDirective, MonkeyModalTitleDirective, MonkeyOptionComponent, MonkeyPaginationActionComponent, MonkeyPaginationLabelComponent, MonkeyPaginationSizeComponent, MonkeyPassNumberComponent, MonkeyPassSecretNumberComponent, MonkeyPopoverContentComponent, MonkeyPopoverDirective, MonkeyPrefixDirective, MonkeyRadioButtonComponent, MonkeyScrollbarComponent, MonkeySecurityLevelComponent, MonkeySelectComponent, MonkeyStatusComponent, MonkeyStepComponent, MonkeyStepperComponent, MonkeyStepperModule, MonkeyStepperService, MonkeySuffixDirective, MonkeyTabComponent, MonkeyTabLinkDirective, MonkeyTableCellDirective, MonkeyTableColumnDirective, MonkeyTableComponent, MonkeyTableEmptyDirective, MonkeyTableHeaderCellDirective, MonkeyTableLoadingDirective, MonkeyTableRowDetailDirective, MonkeyTabsComponent, MonkeyTabsModule, MonkeyToastComponent, MonkeyToastRef, MonkeyToastService, MonkeyToggleComponent, MonkeyToggleLineButtonComponent, MonkeyToggleLineComponent, MonkeyTooltipComponent, MonkeyTooltipDirective, MonkeyUserProfileButtonComponent, MonkeyUserProfileComponent, addKeys, appliedFrom, ariaSortOf, arityOf, conditionsOf, getCurrencySymbol, indexAtOffset, injectTokenWithWarning, interpolate, isComplete, mergeOrder, offsetOfIndex, panelOf, removeKeys, sameColumnState, selectionState, sortByOrder, toPx, toggleKey, totalHeight, withCondition, withType };
13024
11984
  //# sourceMappingURL=monkey-style-guide.mjs.map