monkey-style-guide 21.2.8 → 21.2.10

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, effect, HostListener, ContentChildren, ChangeDetectorRef, DEFAULT_CURRENCY_CODE, ContentChild, NgModule, ViewChild, ChangeDetectionStrategy, Injector, forwardRef, ViewChildren, viewChild, model, 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, model, afterNextRender, ViewChildren, contentChild, contentChildren, untracked, 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';
@@ -1653,6 +1653,146 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
1653
1653
  }]
1654
1654
  }] });
1655
1655
 
1656
+ /** ************************
1657
+ * Copyright Monkey Exchange. All Rights Reserved
1658
+ * This style guide was developed by Monkey Exchange Team
1659
+ * MIT Licence
1660
+ ************************* */
1661
+ class MonkeyButtonComponent {
1662
+ get id() {
1663
+ return this._id;
1664
+ }
1665
+ set id(value) {
1666
+ this._id = value || this._uid;
1667
+ }
1668
+ constructor() {
1669
+ this.color = 'default';
1670
+ this.size = 'md';
1671
+ this.type = 'primary';
1672
+ this.elementRef = inject(ElementRef);
1673
+ this._uid = inject(IdGenerator).getId('monkey-button-');
1674
+ // eslint-disable-next-line no-self-assign
1675
+ this.id = this.id;
1676
+ }
1677
+ onClick(event) {
1678
+ if (this.disabled) {
1679
+ event.stopPropagation();
1680
+ event.preventDefault();
1681
+ event.stopImmediatePropagation();
1682
+ }
1683
+ }
1684
+ get element() {
1685
+ return this.elementRef.nativeElement;
1686
+ }
1687
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1688
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyButtonComponent, isStandalone: true, selector: "monkey-button", inputs: { disabled: "disabled", color: "color", size: "size", type: "type", loading: "loading", id: "id" }, host: { attributes: { "data-testid": "monkey-button" }, listeners: { "click": "onClick($event)" }, properties: { "attr.id": "id", "id": "id", "attr.tabindex": "null" } }, ngImport: i0, template: "<button class=\"mecx-button {{ type }} {{ size }} {{ color }}\" [disabled]=\"disabled || loading\">\r\n <div class=\"content\">\r\n @if (!loading) {\r\n <ng-content select=\"[first]\"></ng-content>\r\n }\r\n <span><ng-content></ng-content></span>\r\n @if (!loading) {\r\n <ng-content select=\"[last]\"></ng-content>\r\n }\r\n @if (loading) {\r\n <util-icon class=\"mecx-button-loading\" name=\"loading\" />\r\n }\r\n </div>\r\n</button>\r\n", styles: ["monkey-button{display:inline-block}monkey-button.has-progress button:disabled{position:relative;overflow:hidden;border:2px solid var(--mecx-color-gray-400)}monkey-button.has-progress :is(.mecx-button){transition:none!important}monkey-button.has-progress :is(.mecx-button) :is(.content){transition:none!important}monkey-button .mecx-button{width:100%;display:flex;align-items:center;justify-content:center;border-radius:8px;cursor:pointer;transition:background-color .15s ease-out,color .15s ease-out}monkey-button .mecx-button .content{display:flex;align-items:center;justify-content:center;gap:var(--mecx-spaces-xs);padding:0px var(--mecx-spaces-small);flex-shrink:0;letter-spacing:.48px;font-weight:400;transition:transform .2s cubic-bezier(0,.5,.2,1)}monkey-button .mecx-button .content span{width:100%}monkey-button .mecx-button .content .mk-i{display:flex}monkey-button .mecx-button.secondary{border:2px solid var(--mecx-color-gray-400);background:var(--mecx-color-white)}monkey-button .mecx-button.secondary:disabled{border-width:1px}monkey-button .mecx-button:disabled{background:var(--mecx-color-gray-100)!important;color:var(--mecx-color-gray-400)!important;cursor:not-allowed!important}monkey-button .mecx-button:disabled.secondary{background:unset!important;border:1px solid var(--mecx-color-gray-400)!important}monkey-button .mecx-button .mecx-button-loading{display:flex;background:transparent}monkey-button .mecx-button .mecx-button-loading svg path{fill:var(--mecx-color-theme-main)}monkey-button .mecx-button.primary{color:var(--mecx-color-theme-contrast-main);background:var(--mecx-color-theme-main)}monkey-button .mecx-button.primary.error{color:var(--mecx-color-white);background:var(--mecx-color-error-500)}monkey-button .mecx-button.primary.success{color:var(--mecx-color-white);background:var(--mecx-color-success-500)}monkey-button .mecx-button.primary.black{background:var(--mecx-color-gray-900);color:var(--mecx-color-white)}monkey-button .mecx-button.primary:hover:not(:disabled){background:var(--mecx-color-theme-600)}monkey-button .mecx-button.primary:hover:not(:disabled) util-icon svg path{fill:var(--mecx-color-theme-600)}monkey-button .mecx-button.primary:hover:not(:disabled).error{background:var(--mecx-color-error-700)}monkey-button .mecx-button.primary:hover:not(:disabled).success{background:var(--mecx-color-success-700)}monkey-button .mecx-button.primary:hover:not(:disabled).black{background:var(--mecx-color-gray-700)}monkey-button .mecx-button.secondary:hover:not(:disabled){color:var(--mecx-color-theme-main)}monkey-button .mecx-button.secondary:hover:not(:disabled) util-icon svg path{fill:var(--mecx-color-theme-main)}monkey-button .mecx-button.secondary:hover:not(:disabled).error{color:var(--mecx-color-error-500)}monkey-button .mecx-button.secondary:hover:not(:disabled).success{color:var(--mecx-color-success-500)}monkey-button .mecx-button.tertiary{background:unset}monkey-button .mecx-button.tertiary span{text-decoration:underline}monkey-button .mecx-button.tertiary:disabled{background:unset!important;border-width:1px}monkey-button .mecx-button.tertiary:hover:not(:disabled){color:var(--mecx-color-theme-main)}monkey-button .mecx-button.tertiary:hover:not(:disabled) util-icon svg path{fill:var(--mecx-color-theme-main)}monkey-button .mecx-button.tertiary:hover:not(:disabled).error{color:var(--mecx-color-error-500)}monkey-button .mecx-button.tertiary:hover:not(:disabled).success{color:var(--mecx-color-success-500)}monkey-button .mecx-button.sm{height:32px}monkey-button .mecx-button.sm .mk-i{font-size:20px}monkey-button .mecx-button.md{height:40px}monkey-button .mecx-button.md .mk-i{font-size:22px}monkey-button .mecx-button.lg{height:48px;text-align:center;font-size:16px;font-style:normal;font-weight:400;line-height:24px;letter-spacing:.48px}monkey-button .mecx-button.lg .mk-i{font-size:24px}monkey-button .mecx-button.full-width{width:100%}monkey-button .mecx-button:focus-visible{outline:2px solid var(--mecx-color-theme-main);outline-offset:1px}monkey-button .mecx-button:focus-visible.error{outline-color:var(--mecx-color-error-500)}monkey-button .mecx-button:focus-visible.success{outline-color:var(--mecx-color-success-500)}monkey-button .mecx-button:active:not(:disabled){opacity:.8;outline:none}monkey-button .mecx-button:active:not(:disabled).primary{background:var(--mecx-color-theme-main)}monkey-button .mecx-button:active:not(:disabled).primary.error{background:var(--mecx-color-error-500)}monkey-button .mecx-button:active:not(:disabled).primary.success{background:var(--mecx-color-success-500)}monkey-button .mecx-button:active:not(:disabled) .content{transform:scale(.9)}:host:has(.mecx-button:active) .mecx-button{outline:unset;outline-offset:unset}\n"], dependencies: [{ kind: "component", type: UtilIconComponent, selector: "util-icon", inputs: ["name"] }], encapsulation: i0.ViewEncapsulation.None }); }
1689
+ }
1690
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyButtonComponent, decorators: [{
1691
+ type: Component,
1692
+ args: [{ encapsulation: ViewEncapsulation.None, imports: [UtilIconComponent], selector: 'monkey-button', standalone: true, host: {
1693
+ 'data-testid': 'monkey-button',
1694
+ '[attr.id]': 'id',
1695
+ '[id]': 'id',
1696
+ '[attr.tabindex]': 'null'
1697
+ }, template: "<button class=\"mecx-button {{ type }} {{ size }} {{ color }}\" [disabled]=\"disabled || loading\">\r\n <div class=\"content\">\r\n @if (!loading) {\r\n <ng-content select=\"[first]\"></ng-content>\r\n }\r\n <span><ng-content></ng-content></span>\r\n @if (!loading) {\r\n <ng-content select=\"[last]\"></ng-content>\r\n }\r\n @if (loading) {\r\n <util-icon class=\"mecx-button-loading\" name=\"loading\" />\r\n }\r\n </div>\r\n</button>\r\n", styles: ["monkey-button{display:inline-block}monkey-button.has-progress button:disabled{position:relative;overflow:hidden;border:2px solid var(--mecx-color-gray-400)}monkey-button.has-progress :is(.mecx-button){transition:none!important}monkey-button.has-progress :is(.mecx-button) :is(.content){transition:none!important}monkey-button .mecx-button{width:100%;display:flex;align-items:center;justify-content:center;border-radius:8px;cursor:pointer;transition:background-color .15s ease-out,color .15s ease-out}monkey-button .mecx-button .content{display:flex;align-items:center;justify-content:center;gap:var(--mecx-spaces-xs);padding:0px var(--mecx-spaces-small);flex-shrink:0;letter-spacing:.48px;font-weight:400;transition:transform .2s cubic-bezier(0,.5,.2,1)}monkey-button .mecx-button .content span{width:100%}monkey-button .mecx-button .content .mk-i{display:flex}monkey-button .mecx-button.secondary{border:2px solid var(--mecx-color-gray-400);background:var(--mecx-color-white)}monkey-button .mecx-button.secondary:disabled{border-width:1px}monkey-button .mecx-button:disabled{background:var(--mecx-color-gray-100)!important;color:var(--mecx-color-gray-400)!important;cursor:not-allowed!important}monkey-button .mecx-button:disabled.secondary{background:unset!important;border:1px solid var(--mecx-color-gray-400)!important}monkey-button .mecx-button .mecx-button-loading{display:flex;background:transparent}monkey-button .mecx-button .mecx-button-loading svg path{fill:var(--mecx-color-theme-main)}monkey-button .mecx-button.primary{color:var(--mecx-color-theme-contrast-main);background:var(--mecx-color-theme-main)}monkey-button .mecx-button.primary.error{color:var(--mecx-color-white);background:var(--mecx-color-error-500)}monkey-button .mecx-button.primary.success{color:var(--mecx-color-white);background:var(--mecx-color-success-500)}monkey-button .mecx-button.primary.black{background:var(--mecx-color-gray-900);color:var(--mecx-color-white)}monkey-button .mecx-button.primary:hover:not(:disabled){background:var(--mecx-color-theme-600)}monkey-button .mecx-button.primary:hover:not(:disabled) util-icon svg path{fill:var(--mecx-color-theme-600)}monkey-button .mecx-button.primary:hover:not(:disabled).error{background:var(--mecx-color-error-700)}monkey-button .mecx-button.primary:hover:not(:disabled).success{background:var(--mecx-color-success-700)}monkey-button .mecx-button.primary:hover:not(:disabled).black{background:var(--mecx-color-gray-700)}monkey-button .mecx-button.secondary:hover:not(:disabled){color:var(--mecx-color-theme-main)}monkey-button .mecx-button.secondary:hover:not(:disabled) util-icon svg path{fill:var(--mecx-color-theme-main)}monkey-button .mecx-button.secondary:hover:not(:disabled).error{color:var(--mecx-color-error-500)}monkey-button .mecx-button.secondary:hover:not(:disabled).success{color:var(--mecx-color-success-500)}monkey-button .mecx-button.tertiary{background:unset}monkey-button .mecx-button.tertiary span{text-decoration:underline}monkey-button .mecx-button.tertiary:disabled{background:unset!important;border-width:1px}monkey-button .mecx-button.tertiary:hover:not(:disabled){color:var(--mecx-color-theme-main)}monkey-button .mecx-button.tertiary:hover:not(:disabled) util-icon svg path{fill:var(--mecx-color-theme-main)}monkey-button .mecx-button.tertiary:hover:not(:disabled).error{color:var(--mecx-color-error-500)}monkey-button .mecx-button.tertiary:hover:not(:disabled).success{color:var(--mecx-color-success-500)}monkey-button .mecx-button.sm{height:32px}monkey-button .mecx-button.sm .mk-i{font-size:20px}monkey-button .mecx-button.md{height:40px}monkey-button .mecx-button.md .mk-i{font-size:22px}monkey-button .mecx-button.lg{height:48px;text-align:center;font-size:16px;font-style:normal;font-weight:400;line-height:24px;letter-spacing:.48px}monkey-button .mecx-button.lg .mk-i{font-size:24px}monkey-button .mecx-button.full-width{width:100%}monkey-button .mecx-button:focus-visible{outline:2px solid var(--mecx-color-theme-main);outline-offset:1px}monkey-button .mecx-button:focus-visible.error{outline-color:var(--mecx-color-error-500)}monkey-button .mecx-button:focus-visible.success{outline-color:var(--mecx-color-success-500)}monkey-button .mecx-button:active:not(:disabled){opacity:.8;outline:none}monkey-button .mecx-button:active:not(:disabled).primary{background:var(--mecx-color-theme-main)}monkey-button .mecx-button:active:not(:disabled).primary.error{background:var(--mecx-color-error-500)}monkey-button .mecx-button:active:not(:disabled).primary.success{background:var(--mecx-color-success-500)}monkey-button .mecx-button:active:not(:disabled) .content{transform:scale(.9)}:host:has(.mecx-button:active) .mecx-button{outline:unset;outline-offset:unset}\n"] }]
1698
+ }], ctorParameters: () => [], propDecorators: { disabled: [{
1699
+ type: Input
1700
+ }], color: [{
1701
+ type: Input
1702
+ }], size: [{
1703
+ type: Input
1704
+ }], type: [{
1705
+ type: Input
1706
+ }], loading: [{
1707
+ type: Input
1708
+ }], id: [{
1709
+ type: Input
1710
+ }], onClick: [{
1711
+ type: HostListener,
1712
+ args: ['click', ['$event']]
1713
+ }] } });
1714
+
1715
+ /** ************************
1716
+ * Copyright Monkey Exchange. All Rights Reserved
1717
+ * This style guide was developed by Monkey Exchange Team
1718
+ * MIT Licence
1719
+ ************************* */
1720
+
1721
+ /** ************************
1722
+ * Copyright Monkey Exchange. All Rights Reserved
1723
+ * This style guide was developed by Monkey Exchange Team
1724
+ * MIT Licence
1725
+ ************************* */
1726
+ class MonkeyToastComponent {
1727
+ get id() {
1728
+ return this._id;
1729
+ }
1730
+ set id(value) {
1731
+ this._id = value || this._uid;
1732
+ }
1733
+ get class() {
1734
+ return this.type;
1735
+ }
1736
+ constructor(host) {
1737
+ this.host = host;
1738
+ this.icon = 'close-circle';
1739
+ this.type = 'default';
1740
+ this.isClosable = false;
1741
+ this.onActionClick = new EventEmitter();
1742
+ this.onClose = new EventEmitter();
1743
+ this._uid = inject(IdGenerator).getId('monkey-toast-');
1744
+ // eslint-disable-next-line no-self-assign
1745
+ this.id = this.id;
1746
+ }
1747
+ close() {
1748
+ this.host.nativeElement.classList.add('closed');
1749
+ }
1750
+ onAnimationEnd(event) {
1751
+ if (event.animationName.includes('fade-out')) {
1752
+ this.onClose.emit(this.id);
1753
+ }
1754
+ }
1755
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyToastComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
1756
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyToastComponent, isStandalone: true, selector: "monkey-toast", inputs: { message: "message", icon: "icon", type: "type", isClosable: ["isClosable", "isClosable", booleanAttribute], actionLabel: "actionLabel", actionIcon: "actionIcon", id: "id" }, outputs: { onActionClick: "onActionClick", onClose: "onClose" }, host: { attributes: { "data-testid": "monkey-toast" }, listeners: { "animationend": "onAnimationEnd($event)" }, properties: { "attr.id": "id", "id": "id", "class": "this.class" } }, ngImport: i0, template: "<div class=\"monkey-toast-content\">\r\n @if (icon) {\r\n <i class=\"mk-i mk-i-{{icon}} lg\"></i>\r\n }\r\n <div>\r\n <div class=\"monkey-toast-message\">\r\n {{ message }}\r\n </div>\r\n @if (actionLabel) {\r\n <div class=\"monkey-toast-action\">\r\n <monkey-button\r\n class=\"monkey-toast-btn-action\"\r\n type=\"tertiary\"\r\n size=\"sm\"\r\n (click)=\"onActionClick.emit(id)\"\r\n >\r\n {{ actionLabel }}\r\n @if (actionIcon) {\r\n <i class=\"mk-i mk-i-{{actionIcon}} xs\" first></i>\r\n }\r\n </monkey-button>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n@if (isClosable) {\r\n <div class=\"monkey-toast-divider\"></div>\r\n <div class=\"monkey-toast-close\" (click)=\"close()\">\r\n <util-icon name=\"clear\" />\r\n </div>\r\n}\r\n", styles: ["monkey-toast{display:flex;align-items:start;min-width:300px;width:100%;gap:var(--mecx-spaces-medium);padding:var(--mecx-spaces-medium);box-shadow:0 8px 16px 0 var(--mecx-color-box-shadow);background-color:var(--mecx-color-gray-900);color:var(--mecx-color-white);border-radius:4px;max-width:450px;box-sizing:border-box;animation:fade-in .3s}monkey-toast.closed{animation:fade-out .1s}monkey-toast .monkey-toast-content{display:flex;gap:var(--mecx-spaces-xs);line-height:var(--mecx-lh-24);font-size:var(--mecx-fs-xxs);letter-spacing:.48px;flex-grow:1}monkey-toast .monkey-toast-action{margin:8px 0 0 -12px}monkey-toast .monkey-toast-action .monkey-toast-btn-action{margin:0!important}monkey-toast .monkey-toast-action .monkey-toast-btn-action .mecx-button{height:24px;color:var(--mecx-color-white)!important;outline-color:var(--mecx-color-white)}monkey-toast .monkey-toast-action .monkey-toast-btn-action .mecx-button .content{padding:12px 8px}monkey-toast .monkey-toast-action .monkey-toast-btn-action .mecx-button:hover{color:var(--mecx-color-white)!important}monkey-toast .monkey-toast-divider{width:1px;height:24px;opacity:.2;background-color:var(--mecx-color-white)}monkey-toast .monkey-toast-close{display:flex;align-items:center;justify-content:center;cursor:pointer}monkey-toast .monkey-toast-close svg *{fill:var(--mecx-color-white)!important}monkey-toast.success{background-color:var(--mecx-color-success-main)}monkey-toast.error{background-color:var(--mecx-color-error-700)}monkey-toast.question{background-color:var(--mecx-color-question-800)}monkey-toast.warning{background-color:var(--mecx-color-warning-main)}monkey-toast.warning .monkey-toast-divider{background-color:var(--mecx-color-gray-900)}monkey-toast.warning .monkey-toast-content{color:var(--mecx-color-gray-900)}monkey-toast.warning .monkey-toast-close svg *{fill:var(--mecx-color-gray-900)!important}monkey-toast.warning .monkey-toast-action .monkey-toast-btn-action .mecx-button{color:var(--mecx-color-gray-900)!important;outline-color:var(--mecx-color-gray-900)}monkey-toast.warning .monkey-toast-action .monkey-toast-btn-action .mecx-button:hover{color:var(--mecx-color-gray-900)!important}@keyframes fade-in{0%{transform:scale(.9);opacity:0}to{transform:scale(1);opacity:1}}@keyframes fade-out{to{transform:scale(.9);opacity:0}}\n"], dependencies: [{ kind: "component", type: MonkeyButtonComponent, selector: "monkey-button", inputs: ["disabled", "color", "size", "type", "loading", "id"] }, { kind: "component", type: UtilIconComponent, selector: "util-icon", inputs: ["name"] }], encapsulation: i0.ViewEncapsulation.None }); }
1757
+ }
1758
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyToastComponent, decorators: [{
1759
+ type: Component,
1760
+ args: [{ selector: 'monkey-toast', imports: [MonkeyButtonComponent, UtilIconComponent], encapsulation: ViewEncapsulation.None, host: {
1761
+ 'data-testid': 'monkey-toast',
1762
+ '(animationend)': 'onAnimationEnd($event)',
1763
+ '[attr.id]': 'id',
1764
+ '[id]': 'id'
1765
+ }, template: "<div class=\"monkey-toast-content\">\r\n @if (icon) {\r\n <i class=\"mk-i mk-i-{{icon}} lg\"></i>\r\n }\r\n <div>\r\n <div class=\"monkey-toast-message\">\r\n {{ message }}\r\n </div>\r\n @if (actionLabel) {\r\n <div class=\"monkey-toast-action\">\r\n <monkey-button\r\n class=\"monkey-toast-btn-action\"\r\n type=\"tertiary\"\r\n size=\"sm\"\r\n (click)=\"onActionClick.emit(id)\"\r\n >\r\n {{ actionLabel }}\r\n @if (actionIcon) {\r\n <i class=\"mk-i mk-i-{{actionIcon}} xs\" first></i>\r\n }\r\n </monkey-button>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n@if (isClosable) {\r\n <div class=\"monkey-toast-divider\"></div>\r\n <div class=\"monkey-toast-close\" (click)=\"close()\">\r\n <util-icon name=\"clear\" />\r\n </div>\r\n}\r\n", styles: ["monkey-toast{display:flex;align-items:start;min-width:300px;width:100%;gap:var(--mecx-spaces-medium);padding:var(--mecx-spaces-medium);box-shadow:0 8px 16px 0 var(--mecx-color-box-shadow);background-color:var(--mecx-color-gray-900);color:var(--mecx-color-white);border-radius:4px;max-width:450px;box-sizing:border-box;animation:fade-in .3s}monkey-toast.closed{animation:fade-out .1s}monkey-toast .monkey-toast-content{display:flex;gap:var(--mecx-spaces-xs);line-height:var(--mecx-lh-24);font-size:var(--mecx-fs-xxs);letter-spacing:.48px;flex-grow:1}monkey-toast .monkey-toast-action{margin:8px 0 0 -12px}monkey-toast .monkey-toast-action .monkey-toast-btn-action{margin:0!important}monkey-toast .monkey-toast-action .monkey-toast-btn-action .mecx-button{height:24px;color:var(--mecx-color-white)!important;outline-color:var(--mecx-color-white)}monkey-toast .monkey-toast-action .monkey-toast-btn-action .mecx-button .content{padding:12px 8px}monkey-toast .monkey-toast-action .monkey-toast-btn-action .mecx-button:hover{color:var(--mecx-color-white)!important}monkey-toast .monkey-toast-divider{width:1px;height:24px;opacity:.2;background-color:var(--mecx-color-white)}monkey-toast .monkey-toast-close{display:flex;align-items:center;justify-content:center;cursor:pointer}monkey-toast .monkey-toast-close svg *{fill:var(--mecx-color-white)!important}monkey-toast.success{background-color:var(--mecx-color-success-main)}monkey-toast.error{background-color:var(--mecx-color-error-700)}monkey-toast.question{background-color:var(--mecx-color-question-800)}monkey-toast.warning{background-color:var(--mecx-color-warning-main)}monkey-toast.warning .monkey-toast-divider{background-color:var(--mecx-color-gray-900)}monkey-toast.warning .monkey-toast-content{color:var(--mecx-color-gray-900)}monkey-toast.warning .monkey-toast-close svg *{fill:var(--mecx-color-gray-900)!important}monkey-toast.warning .monkey-toast-action .monkey-toast-btn-action .mecx-button{color:var(--mecx-color-gray-900)!important;outline-color:var(--mecx-color-gray-900)}monkey-toast.warning .monkey-toast-action .monkey-toast-btn-action .mecx-button:hover{color:var(--mecx-color-gray-900)!important}@keyframes fade-in{0%{transform:scale(.9);opacity:0}to{transform:scale(1);opacity:1}}@keyframes fade-out{to{transform:scale(.9);opacity:0}}\n"] }]
1766
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { message: [{
1767
+ type: Input
1768
+ }], icon: [{
1769
+ type: Input
1770
+ }], type: [{
1771
+ type: Input
1772
+ }], isClosable: [{
1773
+ type: Input,
1774
+ args: [{ transform: booleanAttribute }]
1775
+ }], actionLabel: [{
1776
+ type: Input
1777
+ }], actionIcon: [{
1778
+ type: Input
1779
+ }], onActionClick: [{
1780
+ type: Output
1781
+ }], onClose: [{
1782
+ type: Output
1783
+ }], id: [{
1784
+ type: Input
1785
+ }], class: [{
1786
+ type: HostBinding,
1787
+ args: ['class']
1788
+ }] } });
1789
+
1790
+ /** ************************
1791
+ * Copyright Monkey Exchange. All Rights Reserved
1792
+ * This style guide was developed by Monkey Exchange Team
1793
+ * MIT Licence
1794
+ ************************* */
1795
+
1656
1796
  class MonkeyToastRef {
1657
1797
  constructor(componentRef) {
1658
1798
  this.componentRef = componentRef;
@@ -3272,71 +3412,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
3272
3412
  * MIT Licence
3273
3413
  ************************* */
3274
3414
 
3275
- /** ************************
3276
- * Copyright Monkey Exchange. All Rights Reserved
3277
- * This style guide was developed by Monkey Exchange Team
3278
- * MIT Licence
3279
- ************************* */
3280
- class MonkeyButtonComponent {
3281
- get id() {
3282
- return this._id;
3283
- }
3284
- set id(value) {
3285
- this._id = value || this._uid;
3286
- }
3287
- constructor() {
3288
- this.color = 'default';
3289
- this.size = 'md';
3290
- this.type = 'primary';
3291
- this.elementRef = inject(ElementRef);
3292
- this._uid = inject(IdGenerator).getId('monkey-button-');
3293
- // eslint-disable-next-line no-self-assign
3294
- this.id = this.id;
3295
- }
3296
- onClick(event) {
3297
- if (this.disabled) {
3298
- event.stopPropagation();
3299
- event.preventDefault();
3300
- event.stopImmediatePropagation();
3301
- }
3302
- }
3303
- get element() {
3304
- return this.elementRef.nativeElement;
3305
- }
3306
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3307
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyButtonComponent, isStandalone: true, selector: "monkey-button", inputs: { disabled: "disabled", color: "color", size: "size", type: "type", loading: "loading", id: "id" }, host: { attributes: { "data-testid": "monkey-button" }, listeners: { "click": "onClick($event)" }, properties: { "attr.id": "id", "id": "id", "attr.tabindex": "null" } }, ngImport: i0, template: "<button class=\"mecx-button {{ type }} {{ size }} {{ color }}\" [disabled]=\"disabled || loading\">\r\n <div class=\"content\">\r\n @if (!loading) {\r\n <ng-content select=\"[first]\"></ng-content>\r\n }\r\n <span><ng-content></ng-content></span>\r\n @if (!loading) {\r\n <ng-content select=\"[last]\"></ng-content>\r\n }\r\n @if (loading) {\r\n <util-icon class=\"mecx-button-loading\" name=\"loading\" />\r\n }\r\n </div>\r\n</button>\r\n", styles: ["monkey-button{display:inline-block}monkey-button.has-progress button:disabled{position:relative;overflow:hidden;border:2px solid var(--mecx-color-gray-400)}monkey-button.has-progress :is(.mecx-button){transition:none!important}monkey-button.has-progress :is(.mecx-button) :is(.content){transition:none!important}monkey-button .mecx-button{width:100%;display:flex;align-items:center;justify-content:center;border-radius:8px;cursor:pointer;transition:background-color .15s ease-out,color .15s ease-out}monkey-button .mecx-button .content{display:flex;align-items:center;justify-content:center;gap:var(--mecx-spaces-xs);padding:0px var(--mecx-spaces-small);flex-shrink:0;letter-spacing:.48px;font-weight:400;transition:transform .2s cubic-bezier(0,.5,.2,1)}monkey-button .mecx-button .content span{width:100%}monkey-button .mecx-button .content .mk-i{display:flex}monkey-button .mecx-button.secondary{border:2px solid var(--mecx-color-gray-400);background:var(--mecx-color-white)}monkey-button .mecx-button.secondary:disabled{border-width:1px}monkey-button .mecx-button:disabled{background:var(--mecx-color-gray-100)!important;color:var(--mecx-color-gray-400)!important;cursor:not-allowed!important}monkey-button .mecx-button:disabled.secondary{background:unset!important;border:1px solid var(--mecx-color-gray-400)!important}monkey-button .mecx-button .mecx-button-loading{display:flex;background:transparent}monkey-button .mecx-button .mecx-button-loading svg path{fill:var(--mecx-color-theme-main)}monkey-button .mecx-button.primary{color:var(--mecx-color-theme-contrast-main);background:var(--mecx-color-theme-main)}monkey-button .mecx-button.primary.error{color:var(--mecx-color-white);background:var(--mecx-color-error-500)}monkey-button .mecx-button.primary.success{color:var(--mecx-color-white);background:var(--mecx-color-success-500)}monkey-button .mecx-button.primary.black{background:var(--mecx-color-gray-900);color:var(--mecx-color-white)}monkey-button .mecx-button.primary:hover:not(:disabled){background:var(--mecx-color-theme-600)}monkey-button .mecx-button.primary:hover:not(:disabled) util-icon svg path{fill:var(--mecx-color-theme-600)}monkey-button .mecx-button.primary:hover:not(:disabled).error{background:var(--mecx-color-error-700)}monkey-button .mecx-button.primary:hover:not(:disabled).success{background:var(--mecx-color-success-700)}monkey-button .mecx-button.primary:hover:not(:disabled).black{background:var(--mecx-color-gray-700)}monkey-button .mecx-button.secondary:hover:not(:disabled){color:var(--mecx-color-theme-main)}monkey-button .mecx-button.secondary:hover:not(:disabled) util-icon svg path{fill:var(--mecx-color-theme-main)}monkey-button .mecx-button.secondary:hover:not(:disabled).error{color:var(--mecx-color-error-500)}monkey-button .mecx-button.secondary:hover:not(:disabled).success{color:var(--mecx-color-success-500)}monkey-button .mecx-button.tertiary{background:unset}monkey-button .mecx-button.tertiary span{text-decoration:underline}monkey-button .mecx-button.tertiary:disabled{background:unset!important;border-width:1px}monkey-button .mecx-button.tertiary:hover:not(:disabled){color:var(--mecx-color-theme-main)}monkey-button .mecx-button.tertiary:hover:not(:disabled) util-icon svg path{fill:var(--mecx-color-theme-main)}monkey-button .mecx-button.tertiary:hover:not(:disabled).error{color:var(--mecx-color-error-500)}monkey-button .mecx-button.tertiary:hover:not(:disabled).success{color:var(--mecx-color-success-500)}monkey-button .mecx-button.sm{height:32px}monkey-button .mecx-button.sm .mk-i{font-size:20px}monkey-button .mecx-button.md{height:40px}monkey-button .mecx-button.md .mk-i{font-size:22px}monkey-button .mecx-button.lg{height:48px;text-align:center;font-size:16px;font-style:normal;font-weight:400;line-height:24px;letter-spacing:.48px}monkey-button .mecx-button.lg .mk-i{font-size:24px}monkey-button .mecx-button.full-width{width:100%}monkey-button .mecx-button:focus-visible{outline:2px solid var(--mecx-color-theme-main);outline-offset:1px}monkey-button .mecx-button:focus-visible.error{outline-color:var(--mecx-color-error-500)}monkey-button .mecx-button:focus-visible.success{outline-color:var(--mecx-color-success-500)}monkey-button .mecx-button:active:not(:disabled){opacity:.8;outline:none}monkey-button .mecx-button:active:not(:disabled).primary{background:var(--mecx-color-theme-main)}monkey-button .mecx-button:active:not(:disabled).primary.error{background:var(--mecx-color-error-500)}monkey-button .mecx-button:active:not(:disabled).primary.success{background:var(--mecx-color-success-500)}monkey-button .mecx-button:active:not(:disabled) .content{transform:scale(.9)}:host:has(.mecx-button:active) .mecx-button{outline:unset;outline-offset:unset}\n"], dependencies: [{ kind: "component", type: UtilIconComponent, selector: "util-icon", inputs: ["name"] }], encapsulation: i0.ViewEncapsulation.None }); }
3308
- }
3309
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyButtonComponent, decorators: [{
3310
- type: Component,
3311
- args: [{ encapsulation: ViewEncapsulation.None, imports: [UtilIconComponent], selector: 'monkey-button', standalone: true, host: {
3312
- 'data-testid': 'monkey-button',
3313
- '[attr.id]': 'id',
3314
- '[id]': 'id',
3315
- '[attr.tabindex]': 'null'
3316
- }, template: "<button class=\"mecx-button {{ type }} {{ size }} {{ color }}\" [disabled]=\"disabled || loading\">\r\n <div class=\"content\">\r\n @if (!loading) {\r\n <ng-content select=\"[first]\"></ng-content>\r\n }\r\n <span><ng-content></ng-content></span>\r\n @if (!loading) {\r\n <ng-content select=\"[last]\"></ng-content>\r\n }\r\n @if (loading) {\r\n <util-icon class=\"mecx-button-loading\" name=\"loading\" />\r\n }\r\n </div>\r\n</button>\r\n", styles: ["monkey-button{display:inline-block}monkey-button.has-progress button:disabled{position:relative;overflow:hidden;border:2px solid var(--mecx-color-gray-400)}monkey-button.has-progress :is(.mecx-button){transition:none!important}monkey-button.has-progress :is(.mecx-button) :is(.content){transition:none!important}monkey-button .mecx-button{width:100%;display:flex;align-items:center;justify-content:center;border-radius:8px;cursor:pointer;transition:background-color .15s ease-out,color .15s ease-out}monkey-button .mecx-button .content{display:flex;align-items:center;justify-content:center;gap:var(--mecx-spaces-xs);padding:0px var(--mecx-spaces-small);flex-shrink:0;letter-spacing:.48px;font-weight:400;transition:transform .2s cubic-bezier(0,.5,.2,1)}monkey-button .mecx-button .content span{width:100%}monkey-button .mecx-button .content .mk-i{display:flex}monkey-button .mecx-button.secondary{border:2px solid var(--mecx-color-gray-400);background:var(--mecx-color-white)}monkey-button .mecx-button.secondary:disabled{border-width:1px}monkey-button .mecx-button:disabled{background:var(--mecx-color-gray-100)!important;color:var(--mecx-color-gray-400)!important;cursor:not-allowed!important}monkey-button .mecx-button:disabled.secondary{background:unset!important;border:1px solid var(--mecx-color-gray-400)!important}monkey-button .mecx-button .mecx-button-loading{display:flex;background:transparent}monkey-button .mecx-button .mecx-button-loading svg path{fill:var(--mecx-color-theme-main)}monkey-button .mecx-button.primary{color:var(--mecx-color-theme-contrast-main);background:var(--mecx-color-theme-main)}monkey-button .mecx-button.primary.error{color:var(--mecx-color-white);background:var(--mecx-color-error-500)}monkey-button .mecx-button.primary.success{color:var(--mecx-color-white);background:var(--mecx-color-success-500)}monkey-button .mecx-button.primary.black{background:var(--mecx-color-gray-900);color:var(--mecx-color-white)}monkey-button .mecx-button.primary:hover:not(:disabled){background:var(--mecx-color-theme-600)}monkey-button .mecx-button.primary:hover:not(:disabled) util-icon svg path{fill:var(--mecx-color-theme-600)}monkey-button .mecx-button.primary:hover:not(:disabled).error{background:var(--mecx-color-error-700)}monkey-button .mecx-button.primary:hover:not(:disabled).success{background:var(--mecx-color-success-700)}monkey-button .mecx-button.primary:hover:not(:disabled).black{background:var(--mecx-color-gray-700)}monkey-button .mecx-button.secondary:hover:not(:disabled){color:var(--mecx-color-theme-main)}monkey-button .mecx-button.secondary:hover:not(:disabled) util-icon svg path{fill:var(--mecx-color-theme-main)}monkey-button .mecx-button.secondary:hover:not(:disabled).error{color:var(--mecx-color-error-500)}monkey-button .mecx-button.secondary:hover:not(:disabled).success{color:var(--mecx-color-success-500)}monkey-button .mecx-button.tertiary{background:unset}monkey-button .mecx-button.tertiary span{text-decoration:underline}monkey-button .mecx-button.tertiary:disabled{background:unset!important;border-width:1px}monkey-button .mecx-button.tertiary:hover:not(:disabled){color:var(--mecx-color-theme-main)}monkey-button .mecx-button.tertiary:hover:not(:disabled) util-icon svg path{fill:var(--mecx-color-theme-main)}monkey-button .mecx-button.tertiary:hover:not(:disabled).error{color:var(--mecx-color-error-500)}monkey-button .mecx-button.tertiary:hover:not(:disabled).success{color:var(--mecx-color-success-500)}monkey-button .mecx-button.sm{height:32px}monkey-button .mecx-button.sm .mk-i{font-size:20px}monkey-button .mecx-button.md{height:40px}monkey-button .mecx-button.md .mk-i{font-size:22px}monkey-button .mecx-button.lg{height:48px;text-align:center;font-size:16px;font-style:normal;font-weight:400;line-height:24px;letter-spacing:.48px}monkey-button .mecx-button.lg .mk-i{font-size:24px}monkey-button .mecx-button.full-width{width:100%}monkey-button .mecx-button:focus-visible{outline:2px solid var(--mecx-color-theme-main);outline-offset:1px}monkey-button .mecx-button:focus-visible.error{outline-color:var(--mecx-color-error-500)}monkey-button .mecx-button:focus-visible.success{outline-color:var(--mecx-color-success-500)}monkey-button .mecx-button:active:not(:disabled){opacity:.8;outline:none}monkey-button .mecx-button:active:not(:disabled).primary{background:var(--mecx-color-theme-main)}monkey-button .mecx-button:active:not(:disabled).primary.error{background:var(--mecx-color-error-500)}monkey-button .mecx-button:active:not(:disabled).primary.success{background:var(--mecx-color-success-500)}monkey-button .mecx-button:active:not(:disabled) .content{transform:scale(.9)}:host:has(.mecx-button:active) .mecx-button{outline:unset;outline-offset:unset}\n"] }]
3317
- }], ctorParameters: () => [], propDecorators: { disabled: [{
3318
- type: Input
3319
- }], color: [{
3320
- type: Input
3321
- }], size: [{
3322
- type: Input
3323
- }], type: [{
3324
- type: Input
3325
- }], loading: [{
3326
- type: Input
3327
- }], id: [{
3328
- type: Input
3329
- }], onClick: [{
3330
- type: HostListener,
3331
- args: ['click', ['$event']]
3332
- }] } });
3333
-
3334
- /** ************************
3335
- * Copyright Monkey Exchange. All Rights Reserved
3336
- * This style guide was developed by Monkey Exchange Team
3337
- * MIT Licence
3338
- ************************* */
3339
-
3340
3415
  /** ************************
3341
3416
  * Copyright Monkey Exchange. All Rights Reserved
3342
3417
  * This style guide was developed by Monkey Exchange Team
@@ -6551,57 +6626,1779 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
6551
6626
  * This style guide was developed by Monkey Exchange Team
6552
6627
  * MIT Licence
6553
6628
  ************************* */
6554
- class MonkeyInputCodeComponent {
6555
- get disabled() {
6556
- if (this.ngControl && this.ngControl.disabled !== null) {
6557
- return this.ngControl.disabled;
6558
- }
6559
- return this._disabled;
6560
- }
6561
- set disabled(value) {
6562
- this._disabled = value;
6563
- if (this.focused) {
6564
- this.focused = false;
6565
- this.stateChanges.next();
6566
- }
6567
- }
6568
- set value(value) {
6569
- if (this._value !== value && value !== undefined) {
6570
- this._value = value;
6571
- this._onChange(value);
6572
- this._onTouched();
6573
- }
6574
- }
6575
- get value() {
6576
- return this._value;
6577
- }
6578
- constructor(formField) {
6579
- this.formField = formField;
6580
- this.stateChanges = new Subject();
6581
- this.type = 'input-code';
6582
- this.currency = false;
6583
- this.percent = false;
6584
- this.id = inject(IdGenerator).getId('monkey-input-code-');
6585
- this._onChange = () => { };
6586
- this._onTouched = () => { };
6587
- this._value = null;
6588
- this.ngControl = inject(NgControl, { self: true, optional: true });
6589
- this.focused = false;
6590
- this.length = input(6, ...(ngDevMode ? [{ debugName: "length" }] : /* istanbul ignore next */ []));
6591
- this.inputType = input('numeric', ...(ngDevMode ? [{ debugName: "inputType" }] : /* istanbul ignore next */ []));
6592
- this.inputIndices = computed(() => {
6593
- return Array.from({ length: this.length() }, (_, i) => {
6594
- return '';
6595
- });
6596
- }, ...(ngDevMode ? [{ debugName: "inputIndices" }] : /* istanbul ignore next */ []));
6597
- this._disabled = false;
6598
- if (this.ngControl) {
6599
- this.ngControl.valueAccessor = this;
6600
- }
6601
- if (this.formField) {
6602
- this.formField.hideAction = true;
6603
- }
6604
- }
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 {
6649
+ constructor() {
6650
+ this._zone = inject(NgZone);
6651
+ this.orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
6652
+ this.size = input('medium', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
6653
+ /** The element that actually scrolls. */
6654
+ this.target = input.required(...(ngDevMode ? [{ debugName: "target" }] : /* istanbul ignore next */ []));
6655
+ this.trackEl = viewChild.required('track');
6656
+ /** Scrollable length of the content, in px. */
6657
+ this.total = signal(0, ...(ngDevMode ? [{ debugName: "total" }] : /* istanbul ignore next */ []));
6658
+ /** Visible length of the viewport, in px. */
6659
+ this.visible = signal(0, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
6660
+ /** How far the target is scrolled, in px. */
6661
+ this.scrolled = signal(0, ...(ngDevMode ? [{ debugName: "scrolled" }] : /* istanbul ignore next */ []));
6662
+ /** Length of the track the thumb slides along, in px. */
6663
+ this.trackLength = signal(0, ...(ngDevMode ? [{ debugName: "trackLength" }] : /* istanbul ignore next */ []));
6664
+ this.scrollable = computed(() => this.total() - this.visible() > 1, ...(ngDevMode ? [{ debugName: "scrollable" }] : /* istanbul ignore next */ []));
6665
+ this.thumbSize = computed(() => {
6666
+ const total = this.total();
6667
+ return `${total > 0 ? Math.min(1, this.visible() / total) * 100 : 100}%`;
6668
+ }, ...(ngDevMode ? [{ debugName: "thumbSize" }] : /* istanbul ignore next */ []));
6669
+ /**
6670
+ * A px distance, applied as a `translate`, not as `left`/`top`: moving the
6671
+ * thumb then costs a composited transform instead of a layout pass on every
6672
+ * scroll frame. It has to be px rather than a percentage of the thumb
6673
+ * because the thumb has a minimum length — once that kicks in, a
6674
+ * percentage of its own (clamped) size no longer maps to track distance.
6675
+ */
6676
+ this.thumbOffset = computed(() => {
6677
+ const total = this.total();
6678
+ const visible = this.visible();
6679
+ const track = this.trackLength();
6680
+ if (total <= 0 || track <= 0)
6681
+ return '0px';
6682
+ const thumb = Math.max(MIN_THUMB, (visible / total) * track);
6683
+ const free = Math.max(0, track - thumb);
6684
+ const progress = Math.min(1, Math.max(0, this.scrolled() / Math.max(1, total - visible)));
6685
+ return `${free * progress}px`;
6686
+ }, ...(ngDevMode ? [{ debugName: "thumbOffset" }] : /* istanbul ignore next */ []));
6687
+ /** Pending animation frame, 0 when none is queued. */
6688
+ this.frame = 0;
6689
+ /** Whether the cached lengths need re-reading on the next frame. */
6690
+ this.sizeStale = true;
6691
+ this.onScroll = () => this.schedule();
6692
+ /** Drag state. `null` = nobody is dragging. */
6693
+ this.drag = null;
6694
+ effect((onCleanup) => {
6695
+ const target = this.target();
6696
+ this.attach(target);
6697
+ onCleanup(() => this.detach());
6698
+ });
6699
+ }
6700
+ ngOnDestroy() {
6701
+ this.detach();
6702
+ }
6703
+ attach(target) {
6704
+ this.detach();
6705
+ this.observedTarget = target;
6706
+ // Outside the Angular zone: a zone-patched 'scroll' listener costs a full
6707
+ // global change-detection pass per event. The signals `measure()` writes
6708
+ // still schedule change detection by themselves.
6709
+ this._zone.runOutsideAngular(() => {
6710
+ target.addEventListener('scroll', this.onScroll, { passive: true });
6711
+ // The target AND its content: the bar should disappear when the content
6712
+ // shrinks, not only when the container itself is resized — a column
6713
+ // removed from the table doesn't resize the scrolling wrapper, only how
6714
+ // far it needs to scroll. The track too, so the thumb's px offset stays
6715
+ // right when the bar itself changes width.
6716
+ this.resizeObserver = new ResizeObserver(() => this.schedule(true));
6717
+ this.resizeObserver.observe(target);
6718
+ this.resizeObserver.observe(this.trackEl().nativeElement);
6719
+ Array.from(target.children).forEach((child) => this.resizeObserver?.observe(child));
6720
+ });
6721
+ this.sizeStale = true;
6722
+ this.measure();
6723
+ }
6724
+ detach() {
6725
+ this.observedTarget?.removeEventListener('scroll', this.onScroll);
6726
+ this.observedTarget = undefined;
6727
+ this.resizeObserver?.disconnect();
6728
+ this.resizeObserver = undefined;
6729
+ if (this.frame)
6730
+ cancelAnimationFrame(this.frame);
6731
+ this.frame = 0;
6732
+ }
6733
+ /**
6734
+ * Scroll events fire far more often than the screen refreshes, and each
6735
+ * measurement reads layout. Coalescing to one read per frame is what keeps
6736
+ * a long table from thrashing layout while it scrolls.
6737
+ */
6738
+ schedule(resized = false) {
6739
+ if (resized)
6740
+ this.sizeStale = true;
6741
+ if (this.frame)
6742
+ return;
6743
+ this.frame = this._zone.runOutsideAngular(() => {
6744
+ return requestAnimationFrame(() => {
6745
+ this.frame = 0;
6746
+ this.measure();
6747
+ });
6748
+ });
6749
+ }
6750
+ measure() {
6751
+ const target = this.observedTarget;
6752
+ if (!target)
6753
+ return;
6754
+ const horizontal = this.orientation() === 'horizontal';
6755
+ // Only the scroll offset changes while scrolling; the lengths can't, so
6756
+ // re-reading them per frame would force layout for nothing.
6757
+ if (this.sizeStale) {
6758
+ this.sizeStale = false;
6759
+ const track = this.trackEl().nativeElement;
6760
+ this.total.set(horizontal ? target.scrollWidth : target.scrollHeight);
6761
+ this.visible.set(horizontal ? target.clientWidth : target.clientHeight);
6762
+ this.trackLength.set(horizontal ? track.clientWidth : track.clientHeight);
6763
+ }
6764
+ this.scrolled.set(horizontal ? target.scrollLeft : target.scrollTop);
6765
+ }
6766
+ onPointerDown(event) {
6767
+ const target = this.observedTarget;
6768
+ if (!target || !this.scrollable())
6769
+ return;
6770
+ const horizontal = this.orientation() === 'horizontal';
6771
+ event.preventDefault();
6772
+ event.target.setPointerCapture(event.pointerId);
6773
+ this.drag = {
6774
+ start: horizontal ? event.clientX : event.clientY,
6775
+ initialScroll: horizontal ? target.scrollLeft : target.scrollTop
6776
+ };
6777
+ }
6778
+ onPointerMove(event) {
6779
+ const target = this.observedTarget;
6780
+ if (!this.drag || !target)
6781
+ return;
6782
+ const horizontal = this.orientation() === 'horizontal';
6783
+ const track = this.trackEl().nativeElement.getBoundingClientRect();
6784
+ const trackLength = horizontal ? track.width : track.height;
6785
+ if (trackLength <= 0)
6786
+ return;
6787
+ // One thumb pixel is worth (total / track) content pixels — without this
6788
+ // conversion, dragging moves at the wrong speed and the thumb drifts
6789
+ // away from the pointer.
6790
+ const total = horizontal ? target.scrollWidth : target.scrollHeight;
6791
+ const moved = (horizontal ? event.clientX : event.clientY) - this.drag.start;
6792
+ const destination = this.drag.initialScroll + moved * (total / trackLength);
6793
+ if (horizontal)
6794
+ target.scrollLeft = destination;
6795
+ else
6796
+ target.scrollTop = destination;
6797
+ }
6798
+ onPointerUp(event) {
6799
+ if (!this.drag)
6800
+ return;
6801
+ this.drag = null;
6802
+ event.target.releasePointerCapture?.(event.pointerId);
6803
+ }
6804
+ /** Clicking the track outside the thumb jumps the content there, centered on the click. */
6805
+ onTrackPointerDown(event) {
6806
+ const target = this.observedTarget;
6807
+ if (!target || !this.scrollable() || this.drag)
6808
+ return;
6809
+ const horizontal = this.orientation() === 'horizontal';
6810
+ const track = this.trackEl().nativeElement.getBoundingClientRect();
6811
+ const length = horizontal ? track.width : track.height;
6812
+ if (length <= 0)
6813
+ return;
6814
+ const point = horizontal ? event.clientX - track.left : event.clientY - track.top;
6815
+ const total = horizontal ? target.scrollWidth : target.scrollHeight;
6816
+ const visible = horizontal ? target.clientWidth : target.clientHeight;
6817
+ const destination = (point / length) * total - visible / 2;
6818
+ if (horizontal)
6819
+ target.scrollLeft = destination;
6820
+ else
6821
+ target.scrollTop = destination;
6822
+ }
6823
+ /**
6824
+ * Manual re-measure. Public on purpose: the automatic triggers (scroll,
6825
+ * ResizeObserver on the target and its children) cover what the browser
6826
+ * reports on its own — this is the escape hatch for what it doesn't, e.g.
6827
+ * a target swapped out from under the component.
6828
+ */
6829
+ remeasure() {
6830
+ this.sizeStale = true;
6831
+ this.measure();
6832
+ }
6833
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyScrollbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6834
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.4", type: MonkeyScrollbarComponent, isStandalone: true, selector: "monkey-scrollbar", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "aria-hidden": "true" }, properties: { "class.mecx-scrollbar--horizontal": "orientation() === 'horizontal'", "class.mecx-scrollbar--vertical": "orientation() === 'vertical'", "class.mecx-scrollbar--small": "size() === 'small'", "class.mecx-scrollbar--medium": "size() === 'medium'", "class.mecx-scrollbar--inert": "!scrollable()" }, classAttribute: "mecx-scrollbar" }, viewQueries: [{ propertyName: "trackEl", first: true, predicate: ["track"], descendants: true, isSignal: true }], ngImport: i0, template: "<div #track class=\"mecx-scrollbar-track\" (pointerdown)=\"onTrackPointerDown($event)\">\n <div\n class=\"mecx-scrollbar-thumb\"\n [style.--mecx-scrollbar-thumb-size]=\"thumbSize()\"\n [style.--mecx-scrollbar-thumb-offset]=\"thumbOffset()\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n ></div>\n</div>\n", styles: [".mecx-scrollbar{box-sizing:border-box;display:block;flex-shrink:0;background:var(--mecx-color-gray-100);border:1px solid var(--mecx-color-gray-500);border-radius:800px}.mecx-scrollbar--inert{display:none}.mecx-scrollbar-track{position:relative}.mecx-scrollbar-thumb{position:absolute;background:var(--mecx-color-gray-900);border-radius:800px;cursor:grab;touch-action:none;will-change:transform}.mecx-scrollbar-thumb:active{cursor:grabbing}.mecx-scrollbar--medium{--mecx-scrollbar-gap: 4px}.mecx-scrollbar--small{--mecx-scrollbar-gap: 0px}.mecx-scrollbar--horizontal{width:100%}.mecx-scrollbar--horizontal .mecx-scrollbar-track{width:100%;height:calc(6px + 2 * var(--mecx-scrollbar-gap))}.mecx-scrollbar--horizontal .mecx-scrollbar-thumb{inset-block:var(--mecx-scrollbar-gap);left:0;width:var(--mecx-scrollbar-thumb-size);min-width:var(--mecx-spaces-medium);transform:translate(var(--mecx-scrollbar-thumb-offset, 0px))}.mecx-scrollbar--vertical{align-self:stretch}.mecx-scrollbar--vertical .mecx-scrollbar-track{width:calc(6px + 2 * var(--mecx-scrollbar-gap));height:100%}.mecx-scrollbar--vertical .mecx-scrollbar-thumb{inset-inline:var(--mecx-scrollbar-gap);top:0;height:var(--mecx-scrollbar-thumb-size);min-height:var(--mecx-spaces-medium);transform:translateY(var(--mecx-scrollbar-thumb-offset, 0px))}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
6835
+ }
6836
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyScrollbarComponent, decorators: [{
6837
+ type: Component,
6838
+ args: [{ selector: 'monkey-scrollbar', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
6839
+ class: 'mecx-scrollbar',
6840
+ 'aria-hidden': 'true',
6841
+ '[class.mecx-scrollbar--horizontal]': "orientation() === 'horizontal'",
6842
+ '[class.mecx-scrollbar--vertical]': "orientation() === 'vertical'",
6843
+ '[class.mecx-scrollbar--small]': "size() === 'small'",
6844
+ '[class.mecx-scrollbar--medium]': "size() === 'medium'",
6845
+ '[class.mecx-scrollbar--inert]': '!scrollable()'
6846
+ }, template: "<div #track class=\"mecx-scrollbar-track\" (pointerdown)=\"onTrackPointerDown($event)\">\n <div\n class=\"mecx-scrollbar-thumb\"\n [style.--mecx-scrollbar-thumb-size]=\"thumbSize()\"\n [style.--mecx-scrollbar-thumb-offset]=\"thumbOffset()\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n ></div>\n</div>\n", styles: [".mecx-scrollbar{box-sizing:border-box;display:block;flex-shrink:0;background:var(--mecx-color-gray-100);border:1px solid var(--mecx-color-gray-500);border-radius:800px}.mecx-scrollbar--inert{display:none}.mecx-scrollbar-track{position:relative}.mecx-scrollbar-thumb{position:absolute;background:var(--mecx-color-gray-900);border-radius:800px;cursor:grab;touch-action:none;will-change:transform}.mecx-scrollbar-thumb:active{cursor:grabbing}.mecx-scrollbar--medium{--mecx-scrollbar-gap: 4px}.mecx-scrollbar--small{--mecx-scrollbar-gap: 0px}.mecx-scrollbar--horizontal{width:100%}.mecx-scrollbar--horizontal .mecx-scrollbar-track{width:100%;height:calc(6px + 2 * var(--mecx-scrollbar-gap))}.mecx-scrollbar--horizontal .mecx-scrollbar-thumb{inset-block:var(--mecx-scrollbar-gap);left:0;width:var(--mecx-scrollbar-thumb-size);min-width:var(--mecx-spaces-medium);transform:translate(var(--mecx-scrollbar-thumb-offset, 0px))}.mecx-scrollbar--vertical{align-self:stretch}.mecx-scrollbar--vertical .mecx-scrollbar-track{width:calc(6px + 2 * var(--mecx-scrollbar-gap));height:100%}.mecx-scrollbar--vertical .mecx-scrollbar-thumb{inset-inline:var(--mecx-scrollbar-gap);top:0;height:var(--mecx-scrollbar-thumb-size);min-height:var(--mecx-spaces-medium);transform:translateY(var(--mecx-scrollbar-thumb-offset, 0px))}\n"] }]
6847
+ }], ctorParameters: () => [], propDecorators: { orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: true }] }], trackEl: [{ type: i0.ViewChild, args: ['track', { isSignal: true }] }] } });
6848
+
6849
+ /** ************************
6850
+ * Copyright Monkey Exchange. All Rights Reserved
6851
+ * This style guide was developed by Monkey Exchange Team
6852
+ * MIT Licence
6853
+ ************************* */
6854
+
6855
+ /** ************************
6856
+ * Copyright Monkey Exchange. All Rights Reserved
6857
+ * This style guide was developed by Monkey Exchange Team
6858
+ * MIT Licence
6859
+ ************************* */
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
+ class MonkeyFilterChipComponent {
6880
+ constructor() {
6881
+ /** Icon font name of the remove action, without the `mk-i-` prefix. */
6882
+ 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();
6885
+ }
6886
+ 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 }); }
6888
+ }
6889
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterChipComponent, decorators: [{
6890
+ type: Component,
6891
+ args: [{ selector: 'monkey-filter-chip', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
6892
+ '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"] }] } });
6896
+
6897
+ /** ************************
6898
+ * Copyright Monkey Exchange. All Rights Reserved
6899
+ * This style guide was developed by Monkey Exchange Team
6900
+ * MIT Licence
6901
+ ************************* */
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
+ class MonkeyFilterMenuComponent {
6915
+ constructor() {
6916
+ 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. */
6919
+ this.showScroll = input(true, { ...(ngDevMode ? { debugName: "showScroll" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
6920
+ /** Ceiling of the scrolling list, in px. */
6921
+ this.maxHeight = input(240, ...(ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []));
6922
+ this.searchChange = output();
6923
+ 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
+ this.scrolling = computed(() => {
6935
+ return this.showScroll() && this._overflowing();
6936
+ }, ...(ngDevMode ? [{ debugName: "scrolling" }] : /* istanbul ignore next */ []));
6937
+ effect((onCleanup) => {
6938
+ const items = this._items()?.nativeElement;
6939
+ if (!items)
6940
+ 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
+ this._zone.runOutsideAngular(() => {
6945
+ this._observer = new ResizeObserver(() => {
6946
+ this._overflowing.set(items.scrollHeight - items.clientHeight > 1);
6947
+ });
6948
+ this._observer.observe(items);
6949
+ Array.from(items.children).forEach((child) => {
6950
+ return this._observer?.observe(child);
6951
+ });
6952
+ });
6953
+ onCleanup(() => {
6954
+ return this._disconnect();
6955
+ });
6956
+ });
6957
+ }
6958
+ ngOnDestroy() {
6959
+ this._disconnect();
6960
+ }
6961
+ onSearchInput(value) {
6962
+ this.searchValue = value;
6963
+ this.searchChange.emit(value);
6964
+ }
6965
+ _disconnect() {
6966
+ this._observer?.disconnect();
6967
+ this._observer = undefined;
6968
+ }
6969
+ 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 }); }
6971
+ }
6972
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterMenuComponent, decorators: [{
6973
+ type: Component,
6974
+ args: [{ selector: 'monkey-filter-menu', imports: [FormsModule, MonkeyFormFieldModule, MonkeyInputModule, MonkeyPrefixDirective], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
6975
+ 'data-testid': 'monkey-filter-menu',
6976
+ 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 }] }] } });
6979
+
6980
+ /** ************************
6981
+ * Copyright Monkey Exchange. All Rights Reserved
6982
+ * This style guide was developed by Monkey Exchange Team
6983
+ * MIT Licence
6984
+ ************************* */
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
+ class MonkeyFilterMenuItemComponent {
6994
+ constructor() {
6995
+ this.property = input('text', ...(ngDevMode ? [{ debugName: "property" }] : /* istanbul ignore next */ []));
6996
+ /** Icon font name, without the `mk-i-` prefix. */
6997
+ this.leadIcon = input(null, ...(ngDevMode ? [{ debugName: "leadIcon" }] : /* istanbul ignore next */ []));
6998
+ this.label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
6999
+ /** Secondary line under the label — a document number, a key. */
7000
+ this.description = input(null, ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
7001
+ 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
+ this.selected = input(false, { ...(ngDevMode ? { debugName: "selected" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
7004
+ this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
7005
+ this.itemClick = output();
7006
+ }
7007
+ onClick() {
7008
+ if (this.disabled())
7009
+ return;
7010
+ this.itemClick.emit();
7011
+ }
7012
+ 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 }); }
7014
+ }
7015
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterMenuItemComponent, decorators: [{
7016
+ type: Component,
7017
+ args: [{ selector: 'monkey-filter-menu-item', imports: [MonkeyCheckboxComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
7018
+ 'data-testid': 'monkey-filter-menu-item',
7019
+ class: 'mecx-filter-menu-item',
7020
+ role: 'option',
7021
+ '[class.mecx-filter-menu-item--disabled]': 'disabled()',
7022
+ '[class.mecx-filter-menu-item--selected]': 'selected()',
7023
+ '[attr.aria-selected]': 'selected() || checked()',
7024
+ '[attr.aria-disabled]': 'disabled() || null',
7025
+ '(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"] }] } });
7028
+
7029
+ /** ************************
7030
+ * Copyright Monkey Exchange. All Rights Reserved
7031
+ * This style guide was developed by Monkey Exchange Team
7032
+ * MIT Licence
7033
+ ************************* */
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
+ 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
+ const atStart = target.left + gap;
7059
+ const atEnd = target.right - width - gap;
7060
+ const preferred = alignment === 'end' ? atEnd : atStart;
7061
+ const viewport = document.documentElement.clientWidth || 0;
7062
+ if (viewport <= 0)
7063
+ return preferred;
7064
+ const fits = (x) => {
7065
+ return x >= 0 && x + width <= viewport;
7066
+ };
7067
+ if (fits(preferred))
7068
+ return preferred;
7069
+ const opposite = alignment === 'end' ? atStart : atEnd;
7070
+ if (fits(opposite))
7071
+ return opposite;
7072
+ return Math.max(0, Math.min(preferred, viewport - width));
7073
+ }
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
+ function ownOffset(menu) {
7088
+ const raw = getComputedStyle(menu).translate;
7089
+ if (!raw || raw === 'none')
7090
+ return { x: 0, y: 0 };
7091
+ const [x, y] = raw.split(' ');
7092
+ return { x: parseFloat(x) || 0, y: parseFloat(y ?? '') || 0 };
7093
+ }
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
+ function place(target, menu, gaps, alignment) {
7115
+ const own = ownOffset(menu);
7116
+ const appliedTop = parseFloat(menu.style.top) || 0;
7117
+ const appliedLeft = parseFloat(menu.style.left) || 0;
7118
+ const current = menu.getBoundingClientRect();
7119
+ const originTop = current.top - own.y - appliedTop;
7120
+ const originLeft = current.left - own.x - appliedLeft;
7121
+ const x = horizontalOf(target, current.width, gaps.left, alignment);
7122
+ const y = target.bottom + gaps.top;
7123
+ menu.style.top = `${y - originTop}px`;
7124
+ menu.style.left = `${x - originLeft}px`;
7125
+ }
7126
+ /** The nearest ancestor that SCROLLS — it is the one clipping the trigger. */
7127
+ function scrollingAncestor(el) {
7128
+ let node = el.parentElement;
7129
+ while (node) {
7130
+ const { overflowX, overflowY } = getComputedStyle(node);
7131
+ if (/(auto|scroll|hidden|clip)/.test(overflowX + overflowY))
7132
+ return node;
7133
+ node = node.parentElement;
7134
+ }
7135
+ return null;
7136
+ }
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
+ function outOfSight(trigger, target) {
7153
+ const vh = document.documentElement.clientHeight || 0;
7154
+ const vw = document.documentElement.clientWidth || 0;
7155
+ if (vh <= 0 || vw <= 0)
7156
+ return false;
7157
+ if (target.bottom <= 0 || target.top >= vh)
7158
+ return true;
7159
+ if (target.right <= 0 || target.left >= vw)
7160
+ return true;
7161
+ const scroller = scrollingAncestor(trigger);
7162
+ if (!scroller)
7163
+ return false;
7164
+ const rect = scroller.getBoundingClientRect();
7165
+ if (rect.width <= 0 || rect.height <= 0)
7166
+ return false;
7167
+ return (target.bottom <= rect.top ||
7168
+ target.top >= rect.bottom ||
7169
+ target.right <= rect.left ||
7170
+ target.left >= rect.right);
7171
+ }
7172
+ function readGaps(menu) {
7173
+ const style = getComputedStyle(menu);
7174
+ return {
7175
+ top: parseFloat(style.marginTop) || 0,
7176
+ left: parseFloat(style.marginLeft) || 0
7177
+ };
7178
+ }
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
+ function anchorMenu(trigger, menu, alignment = 'start', onOutOfSight) {
7217
+ 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
+ if (!menu.style.top) {
7224
+ menu.style.top = '0px';
7225
+ menu.style.left = '0px';
7226
+ }
7227
+ const reposition = () => {
7228
+ // One read of the trigger per event, reused by both sums.
7229
+ const target = trigger.getBoundingClientRect();
7230
+ if (onOutOfSight && outOfSight(trigger, target)) {
7231
+ onOutOfSight();
7232
+ return;
7233
+ }
7234
+ place(target, menu, gaps, alignment);
7235
+ };
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
+ const onTransitionEnd = (event) => {
7242
+ if (event.propertyName === 'translate')
7243
+ reposition();
7244
+ };
7245
+ const onAnimationEnd = (event) => {
7246
+ const node = event.target;
7247
+ if (node?.contains(menu))
7248
+ reposition();
7249
+ };
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
+ const observer = new ResizeObserver(() => {
7257
+ reposition();
7258
+ });
7259
+ observer.observe(menu);
7260
+ reposition();
7261
+ document.addEventListener('scroll', reposition, { capture: true, passive: true });
7262
+ document.addEventListener('transitionend', onTransitionEnd, { capture: true, passive: true });
7263
+ document.addEventListener('animationend', onAnimationEnd, { capture: true, passive: true });
7264
+ window.addEventListener('resize', reposition, { passive: true });
7265
+ return () => {
7266
+ observer.disconnect();
7267
+ document.removeEventListener('scroll', reposition, { capture: true });
7268
+ document.removeEventListener('transitionend', onTransitionEnd, { capture: true });
7269
+ document.removeEventListener('animationend', onAnimationEnd, { capture: true });
7270
+ window.removeEventListener('resize', reposition);
7271
+ };
7272
+ }
7273
+
7274
+ /** ************************
7275
+ * Copyright Monkey Exchange. All Rights Reserved
7276
+ * This style guide was developed by Monkey Exchange Team
7277
+ * MIT Licence
7278
+ ************************* */
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
+ class MonkeyFilterSegmentComponent {
7297
+ constructor() {
7298
+ /** Category icon — usually only the chip's first segment has one. */
7299
+ this.icon = input(null, ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
7300
+ /** The chosen value. Empty means the segment is still waiting. */
7301
+ this.text = input('', ...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
7302
+ /** Waiting text, in the complement colour. */
7303
+ this.placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
7304
+ /** A segment with no panel to open. */
7305
+ 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();
7308
+ this.filled = computed(() => {
7309
+ return this.text().length > 0;
7310
+ }, ...(ngDevMode ? [{ debugName: "filled" }] : /* istanbul ignore next */ []));
7311
+ /** What is shown: the value when there is one, the waiting text when not. */
7312
+ this.label = computed(() => {
7313
+ return this.filled() ? this.text() : this.placeholder();
7314
+ }, ...(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
+ effect((onCleanup) => {
7321
+ const menu = this._menuEl()?.nativeElement;
7322
+ if (!menu)
7323
+ return;
7324
+ onCleanup(anchorMenu(this._hostEl.nativeElement, menu, 'start'));
7325
+ });
7326
+ }
7327
+ toggle() {
7328
+ this.segmentClick.emit();
7329
+ if (this.readonlySegment())
7330
+ return;
7331
+ this.open.set(!this.open());
7332
+ }
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
+ onDocumentPointerdown(event) {
7339
+ if (!this.open())
7340
+ return;
7341
+ const target = event.target;
7342
+ if (target && this._hostEl.nativeElement.contains(target))
7343
+ return;
7344
+ this.open.set(false);
7345
+ }
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
+ onEscape() {
7353
+ if (!this.open())
7354
+ return;
7355
+ this.open.set(false);
7356
+ this.focusButton();
7357
+ }
7358
+ /** Closes and returns the focus. Public for whoever needs to close from outside. */
7359
+ closeAndFocus() {
7360
+ this.open.set(false);
7361
+ this.focusButton();
7362
+ }
7363
+ focusButton() {
7364
+ this._hostEl.nativeElement.querySelector('.mecx-filter-segment-btn')?.focus();
7365
+ }
7366
+ 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 }); }
7368
+ }
7369
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterSegmentComponent, decorators: [{
7370
+ type: Component,
7371
+ args: [{ selector: 'monkey-filter-segment', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
7372
+ 'data-testid': 'monkey-filter-segment',
7373
+ class: 'mecx-filter-segment',
7374
+ '[class.mecx-filter-segment--open]': 'open()',
7375
+ '[class.mecx-filter-segment--filled]': 'filled()',
7376
+ '(document:pointerdown)': 'onDocumentPointerdown($event)',
7377
+ '(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 }] }] } });
7380
+
7381
+ /** ************************
7382
+ * Copyright Monkey Exchange. All Rights Reserved
7383
+ * This style guide was developed by Monkey Exchange Team
7384
+ * MIT Licence
7385
+ ************************* */
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
+ class MonkeyFilterTriggerComponent {
7398
+ constructor() {
7399
+ this.variant = input('text', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
7400
+ /** Icon font name, without the `mk-i-` prefix. */
7401
+ 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 */ []));
7404
+ 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
+ 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
+ */
7421
+ this.ariaLabelAttr = computed(() => {
7422
+ return this.variant() === 'icon' ? this.ariaLabel() || null : null;
7423
+ }, ...(ngDevMode ? [{ debugName: "ariaLabelAttr" }] : /* istanbul ignore next */ []));
7424
+ this._hostEl = inject(ElementRef);
7425
+ this._menuEl = viewChild('menu', ...(ngDevMode ? [{ debugName: "_menuEl" }] : /* istanbul ignore next */ []));
7426
+ effect((onCleanup) => {
7427
+ const menu = this._menuEl()?.nativeElement;
7428
+ if (!menu)
7429
+ 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);
7439
+ }));
7440
+ });
7441
+ }
7442
+ toggle() {
7443
+ if (this.disabled())
7444
+ return;
7445
+ this.open.set(!this.open());
7446
+ }
7447
+ onDocumentPointerdown(event) {
7448
+ if (!this.open())
7449
+ return;
7450
+ const target = event.target;
7451
+ if (target && this._hostEl.nativeElement.contains(target))
7452
+ return;
7453
+ this.open.set(false);
7454
+ }
7455
+ onEscape() {
7456
+ if (!this.open())
7457
+ return;
7458
+ this.open.set(false);
7459
+ this._hostEl.nativeElement.querySelector('.mecx-filter-trigger-btn')?.focus();
7460
+ }
7461
+ 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 }); }
7463
+ }
7464
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterTriggerComponent, decorators: [{
7465
+ type: Component,
7466
+ args: [{ selector: 'monkey-filter-trigger', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
7467
+ 'data-testid': 'monkey-filter-trigger',
7468
+ class: 'mecx-filter-trigger',
7469
+ '[class.mecx-filter-trigger--text]': 'variant() === "text"',
7470
+ '[class.mecx-filter-trigger--icon]': 'variant() === "icon"',
7471
+ '[class.mecx-filter-trigger--open]': 'open()',
7472
+ '(document:pointerdown)': 'onDocumentPointerdown($event)',
7473
+ '(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. */
7508
+ const FLIP_ATTR = 'data-flip-id';
7509
+ /**
7510
+ * Where each identified element is RIGHT NOW. Call before changing the state.
7511
+ */
7512
+ function measureFlip(container) {
7513
+ const before = new Map();
7514
+ container.querySelectorAll(`[${FLIP_ATTR}]`).forEach((el) => {
7515
+ const id = el.getAttribute(FLIP_ATTR);
7516
+ if (id)
7517
+ before.set(id, el.getBoundingClientRect());
7518
+ });
7519
+ return before;
7520
+ }
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
+ function animateFlip(container, before, frozenClass) {
7528
+ const moved = [];
7529
+ container.querySelectorAll(`[${FLIP_ATTR}]`).forEach((el) => {
7530
+ const id = el.getAttribute(FLIP_ATTR);
7531
+ if (!id)
7532
+ return;
7533
+ 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
+ if (!from)
7538
+ return;
7539
+ const to = el.getBoundingClientRect();
7540
+ const dx = from.left - to.left;
7541
+ const dy = from.top - to.top;
7542
+ if (dx === 0 && dy === 0)
7543
+ return;
7544
+ el.classList.add(frozenClass);
7545
+ el.style.translate = `${dx}px ${dy}px`;
7546
+ moved.push(el);
7547
+ });
7548
+ if (moved.length === 0)
7549
+ 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
+ void container.offsetWidth;
7556
+ moved.forEach((el) => {
7557
+ el.classList.remove(frozenClass);
7558
+ el.style.translate = '';
7559
+ });
7560
+ }
7561
+
7562
+ /** ************************
7563
+ * Copyright Monkey Exchange. All Rights Reserved
7564
+ * This style guide was developed by Monkey Exchange Team
7565
+ * MIT Licence
7566
+ ************************* */
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
+ 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
+ if (typeof requestAnimationFrame === 'function') {
7591
+ requestAnimationFrame(() => {
7592
+ requestAnimationFrame(() => {
7593
+ painted = true;
7594
+ });
7595
+ });
7596
+ }
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
+ function appPainted() {
7608
+ return painted;
7609
+ }
7610
+
7611
+ /** ************************
7612
+ * Copyright Monkey Exchange. All Rights Reserved
7613
+ * This style guide was developed by Monkey Exchange Team
7614
+ * MIT Licence
7615
+ ************************* */
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 {
7656
+ constructor() {
7657
+ this._service = inject(MonkeyFilterBarService);
7658
+ this._hostEl = inject(ElementRef);
7659
+ 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 */ []));
7662
+ 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. */
7669
+ 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 */ []));
7681
+ this.openPanel = signal(null, ...(ngDevMode ? [{ debugName: "openPanel" }] : /* istanbul ignore next */ []));
7682
+ 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
+ this.calendarOpen = signal(null, ...(ngDevMode ? [{ debugName: "calendarOpen" }] : /* istanbul ignore next */ []));
7692
+ /** Search of the category panel. */
7693
+ 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
+ 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
+ this.textValue = '';
7704
+ this.currencyValue = null;
7705
+ this.currencyMode = 'from';
7706
+ this.statusValues = [];
7707
+ 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
+ };
7735
+ });
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
+ */
7757
+ this.addOptions = computed(() => {
7758
+ const k = this.key();
7759
+ const available = k ? this._service.availableFilterOptions(k) : [];
7760
+ return this._matchingSearch(available);
7761
+ }, ...(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
+ */
7778
+ this.triggerVariant = computed(() => {
7779
+ return this.rows().length === 0 ? 'text' : 'icon';
7780
+ }, ...(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
+ this.triggerIcon = computed(() => {
7790
+ return this.rows().length === 0 ? 'filter' : 'add-plus';
7791
+ }, ...(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
+ this.triggerFlipId = computed(() => {
7802
+ return this.rows().length === 0 ? 'trigger-text' : 'trigger-icon';
7803
+ }, ...(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
+ effect(() => {
7810
+ const k = this.key();
7811
+ const cfg = this.config();
7812
+ if (k && cfg)
7813
+ this._service.setConfig(k, cfg);
7814
+ });
7815
+ }
7816
+ // ── Queries used by the template ─────────────────────────────────────────
7817
+ isOpen(rowKey, part) {
7818
+ const panel = this.openPanel();
7819
+ return !!panel && panel.key === rowKey && panel.part === part;
7820
+ }
7821
+ isFilterActive(optionKey) {
7822
+ const k = this.key();
7823
+ return k ? this._service.isFilterActive(k, optionKey) : false;
7824
+ }
7825
+ /** A divider goes where the type changes relative to the row above. */
7826
+ needsDivider(options, index) {
7827
+ return index > 0 && options[index].type !== options[index - 1].type;
7828
+ }
7829
+ valuePlaceholder(row) {
7830
+ return this._optionFor(row.key)?.placeholder ?? 'Selecione';
7831
+ }
7832
+ statusOptionsOf(row) {
7833
+ return this._optionFor(row.key)?.statusOptions ?? [];
7834
+ }
7835
+ minDateOf(row) {
7836
+ return this._optionFor(row.key)?.minDate ?? '';
7837
+ }
7838
+ maxDateOf(row) {
7839
+ return this._optionFor(row.key)?.maxDate ?? '';
7840
+ }
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
+ onSelectCategory(index) {
7847
+ const option = this.addOptions()[index];
7848
+ if (!option)
7849
+ 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
+ this.immediateTriggerExit.set(true);
7854
+ this._withFlip(() => {
7855
+ this.triggerOpen.set(false);
7856
+ this.categorySearch.set('');
7857
+ this._resetDraft();
7858
+ 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' });
7864
+ });
7865
+ }
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
+ onChangeCategory(row, index) {
7874
+ const option = this.changeOptions()[index];
7875
+ if (!option)
7876
+ 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
+ if (option.key === row.key) {
7880
+ this._openValuePanel(row);
7881
+ return;
7882
+ }
7883
+ if (this.isFilterActive(option.key))
7884
+ return;
7885
+ this._withFlip(() => {
7886
+ const k = this.key();
7887
+ if (k && !row.pending)
7888
+ this._service.removeFilter(k, row.key);
7889
+ this._resetDraft();
7890
+ this.calendarOpen.set(null);
7891
+ 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();
7900
+ }
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
+ onTriggerOpenChange(open) {
7906
+ this.categorySearch.set('');
7907
+ this.triggerOpen.set(open);
7908
+ if (!open)
7909
+ return;
7910
+ if (this.pending()) {
7911
+ this._dropPending();
7912
+ return;
7913
+ }
7914
+ this.openPanel.set(null);
7915
+ this.calendarOpen.set(null);
7916
+ this._resetDraft();
7917
+ }
7918
+ onCategoryOpenChange(row, open) {
7919
+ this.categorySearch.set('');
7920
+ if (!open) {
7921
+ this._closePanel(row);
7922
+ return;
7923
+ }
7924
+ this.triggerOpen.set(false);
7925
+ this.openPanel.set({ key: row.key, part: 'category' });
7926
+ }
7927
+ onValueOpenChange(row, open) {
7928
+ if (!open) {
7929
+ this._closePanel(row);
7930
+ return;
7931
+ }
7932
+ this.triggerOpen.set(false);
7933
+ this._openValuePanel(row);
7934
+ }
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')
7944
+ return;
7945
+ if (preset === 'custom') {
7946
+ this.dateRange = { startDate: '', endDate: '' };
7947
+ this.calendarOpen.set(row.key);
7948
+ return;
7949
+ }
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
+ }
7975
+ this.dateRange = {
7976
+ startDate: format(start, 'yyyy-MM-dd'),
7977
+ endDate: format(end, 'yyyy-MM-dd')
7978
+ };
7979
+ this.onApply(row);
7980
+ }
7981
+ onDateChange(row, event) {
7982
+ this.dateRange = event;
7983
+ 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
+ });
8201
+ }
8202
+ _resetDraft() {
8203
+ this.textValue = '';
8204
+ this.currencyValue = null;
8205
+ this.currencyMode = 'from';
8206
+ this.statusValues = [];
8207
+ this.dateRange = { startDate: '', endDate: '' };
8208
+ }
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 });
8215
+ }
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';
8243
+ });
8244
+ }
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;
8288
+ }
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 });
8310
+ }
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 }); }
8313
+ }
8314
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyFilterBarV2Component, decorators: [{
8315
+ type: Component,
8316
+ args: [{ selector: 'monkey-filter-bar-v2', imports: [
8317
+ FormsModule,
8318
+ MonkeyButtonComponent,
8319
+ MonkeyCheckboxComponent,
8320
+ MonkeyDateRangeComponent,
8321
+ MonkeyDividerComponent,
8322
+ MonkeyFilterChipComponent,
8323
+ MonkeyFilterMenuComponent,
8324
+ MonkeyFilterMenuItemComponent,
8325
+ MonkeyFilterSegmentComponent,
8326
+ MonkeyFilterTriggerComponent,
8327
+ MonkeyFormFieldModule,
8328
+ MonkeyInputModule,
8329
+ MonkeyLabelDirective,
8330
+ MonkeyOptionComponent,
8331
+ MonkeyPrefixDirective,
8332
+ MonkeyRadioButtonComponent,
8333
+ MonkeyScrollbarComponent
8334
+ ], 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"] }] } });
8339
+
8340
+ /** ************************
8341
+ * Copyright Monkey Exchange. All Rights Reserved
8342
+ * This style guide was developed by Monkey Exchange Team
8343
+ * MIT Licence
8344
+ ************************* */
8345
+
8346
+ /** ************************
8347
+ * Copyright Monkey Exchange. All Rights Reserved
8348
+ * This style guide was developed by Monkey Exchange Team
8349
+ * MIT Licence
8350
+ ************************* */
8351
+ class MonkeyInputCodeComponent {
8352
+ get disabled() {
8353
+ if (this.ngControl && this.ngControl.disabled !== null) {
8354
+ return this.ngControl.disabled;
8355
+ }
8356
+ return this._disabled;
8357
+ }
8358
+ set disabled(value) {
8359
+ this._disabled = value;
8360
+ if (this.focused) {
8361
+ this.focused = false;
8362
+ this.stateChanges.next();
8363
+ }
8364
+ }
8365
+ set value(value) {
8366
+ if (this._value !== value && value !== undefined) {
8367
+ this._value = value;
8368
+ this._onChange(value);
8369
+ this._onTouched();
8370
+ }
8371
+ }
8372
+ get value() {
8373
+ return this._value;
8374
+ }
8375
+ constructor(formField) {
8376
+ this.formField = formField;
8377
+ this.stateChanges = new Subject();
8378
+ this.type = 'input-code';
8379
+ this.currency = false;
8380
+ this.percent = false;
8381
+ this.id = inject(IdGenerator).getId('monkey-input-code-');
8382
+ this._onChange = () => { };
8383
+ this._onTouched = () => { };
8384
+ this._value = null;
8385
+ this.ngControl = inject(NgControl, { self: true, optional: true });
8386
+ this.focused = false;
8387
+ this.length = input(6, ...(ngDevMode ? [{ debugName: "length" }] : /* istanbul ignore next */ []));
8388
+ this.inputType = input('numeric', ...(ngDevMode ? [{ debugName: "inputType" }] : /* istanbul ignore next */ []));
8389
+ this.inputIndices = computed(() => {
8390
+ return Array.from({ length: this.length() }, (_, i) => {
8391
+ return '';
8392
+ });
8393
+ }, ...(ngDevMode ? [{ debugName: "inputIndices" }] : /* istanbul ignore next */ []));
8394
+ this._disabled = false;
8395
+ if (this.ngControl) {
8396
+ this.ngControl.valueAccessor = this;
8397
+ }
8398
+ if (this.formField) {
8399
+ this.formField.hideAction = true;
8400
+ }
8401
+ }
6605
8402
  ngAfterViewInit() {
6606
8403
  if (this.formField) {
6607
8404
  const input = this.formField.elementRef.nativeElement.querySelector('.mecx-form-field-body');
@@ -8679,209 +10476,66 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
8679
10476
  * This style guide was developed by Monkey Exchange Team
8680
10477
  * MIT Licence
8681
10478
  ************************* */
8682
- class MonkeyPassNumberComponent {
8683
- get isDisabledNumbers() {
8684
- return this.selected?.length === 4;
8685
- }
8686
- get isDisabledClear() {
8687
- return this.selected?.length === 0;
8688
- }
8689
- get id() {
8690
- return this._id;
8691
- }
8692
- set id(value) {
8693
- this._id = value || this._uid;
8694
- }
8695
- constructor() {
8696
- this._uid = inject(IdGenerator).getId('monkey-pass-number-');
8697
- this.selected = [];
8698
- this.onChange = output();
8699
- // eslint-disable-next-line no-self-assign
8700
- this.id = this.id;
8701
- }
8702
- clear() {
8703
- this.selected = [];
8704
- this.onChange.emit(this.selected);
8705
- }
8706
- onPress(pin) {
8707
- if (this.selected.length < 4) {
8708
- this.selected.push(pin);
8709
- this.onChange.emit(this.selected);
8710
- }
8711
- }
8712
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyPassNumberComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8713
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyPassNumberComponent, isStandalone: true, selector: "monkey-pass-number", inputs: { disabled: "disabled", id: "id" }, outputs: { onChange: "onChange" }, host: { attributes: { "data-testid": "monkey-pass-number" }, properties: { "attr.id": "id", "id": "id" } }, ngImport: i0, template: `
8714
- <div class="pin-selected">
8715
- @for (input of [0, 1, 2, 3]; track input) {
8716
- <div class="pin-input">
8717
- {{ selected[input] }}
8718
- </div>
8719
- }
8720
- </div>
8721
- <div class="grid">
8722
- @for (pin of [1, 2, 3, 4, 5, 6, 7, 8, 9]; track pin) {
8723
- <monkey-button
8724
- size="lg"
8725
- (click)="onPress(pin)"
8726
- [disabled]="isDisabledNumbers || disabled"
8727
- color="black"
8728
- >
8729
- {{ pin }}
8730
- </monkey-button>
8731
- }
8732
- <div></div>
8733
- <monkey-button
8734
- size="lg"
8735
- (click)="onPress(0)"
8736
- [disabled]="isDisabledNumbers || disabled"
8737
- color="black"
8738
- >
8739
- 0
8740
- </monkey-button>
8741
- <monkey-button
8742
- size="lg"
8743
- type="secondary"
8744
- (click)="clear()"
8745
- [disabled]="isDisabledClear || disabled"
8746
- >
8747
- <i class="mk-i mk-i-delete"></i>
8748
- </monkey-button>
8749
- </div>
8750
- `, isInline: true, styles: [":host{display:flex;width:100%;max-width:250px;flex-direction:column;gap:1rem}:host .pin-selected{display:flex;align-items:center;justify-content:center;gap:8px}:host .pin-selected .pin-input{width:32px;height:32px;border:2px solid var(--mecx-color-gray-400);box-sizing:border-box;border-radius:4px;background-color:var(--mecx-color-white);display:flex;justify-content:center;align-items:center;line-height:24px;font-weight:600;font-size:14px;position:relative}:host .pin-selected .pin-input.filled:before{content:\"\";border-radius:50%;width:8px;height:8px;background-color:var(--mecx-color-gray-900);position:absolute;left:50%;top:50%;transform:translate(-50%,-50%)}:host .grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}\n"], dependencies: [{ kind: "component", type: MonkeyButtonComponent, selector: "monkey-button", inputs: ["disabled", "color", "size", "type", "loading", "id"] }] }); }
8751
- }
8752
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyPassNumberComponent, decorators: [{
8753
- type: Component,
8754
- args: [{ selector: 'monkey-pass-number', imports: [MonkeyButtonComponent], template: `
8755
- <div class="pin-selected">
8756
- @for (input of [0, 1, 2, 3]; track input) {
8757
- <div class="pin-input">
8758
- {{ selected[input] }}
8759
- </div>
8760
- }
8761
- </div>
8762
- <div class="grid">
8763
- @for (pin of [1, 2, 3, 4, 5, 6, 7, 8, 9]; track pin) {
8764
- <monkey-button
8765
- size="lg"
8766
- (click)="onPress(pin)"
8767
- [disabled]="isDisabledNumbers || disabled"
8768
- color="black"
8769
- >
8770
- {{ pin }}
8771
- </monkey-button>
8772
- }
8773
- <div></div>
8774
- <monkey-button
8775
- size="lg"
8776
- (click)="onPress(0)"
8777
- [disabled]="isDisabledNumbers || disabled"
8778
- color="black"
8779
- >
8780
- 0
8781
- </monkey-button>
8782
- <monkey-button
8783
- size="lg"
8784
- type="secondary"
8785
- (click)="clear()"
8786
- [disabled]="isDisabledClear || disabled"
8787
- >
8788
- <i class="mk-i mk-i-delete"></i>
8789
- </monkey-button>
8790
- </div>
8791
- `, host: {
8792
- 'data-testid': 'monkey-pass-number',
8793
- '[attr.id]': 'id',
8794
- '[id]': 'id'
8795
- }, styles: [":host{display:flex;width:100%;max-width:250px;flex-direction:column;gap:1rem}:host .pin-selected{display:flex;align-items:center;justify-content:center;gap:8px}:host .pin-selected .pin-input{width:32px;height:32px;border:2px solid var(--mecx-color-gray-400);box-sizing:border-box;border-radius:4px;background-color:var(--mecx-color-white);display:flex;justify-content:center;align-items:center;line-height:24px;font-weight:600;font-size:14px;position:relative}:host .pin-selected .pin-input.filled:before{content:\"\";border-radius:50%;width:8px;height:8px;background-color:var(--mecx-color-gray-900);position:absolute;left:50%;top:50%;transform:translate(-50%,-50%)}:host .grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}\n"] }]
8796
- }], ctorParameters: () => [], propDecorators: { disabled: [{
8797
- type: Input
8798
- }], onChange: [{ type: i0.Output, args: ["onChange"] }], id: [{
8799
- type: Input
8800
- }] } });
8801
-
8802
- /** ************************
8803
- * Copyright Monkey Exchange. All Rights Reserved
8804
- * This style guide was developed by Monkey Exchange Team
8805
- * MIT Licence
8806
- ************************* */
8807
- class MonkeyPassSecretNumberComponent {
8808
- get id() {
8809
- return this._id;
8810
- }
8811
- set id(value) {
8812
- this._id = value || this._uid;
8813
- }
10479
+ class MonkeyPassNumberComponent {
8814
10480
  get isDisabledNumbers() {
8815
10481
  return this.selected?.length === 4;
8816
10482
  }
8817
10483
  get isDisabledClear() {
8818
10484
  return this.selected?.length === 0;
8819
10485
  }
10486
+ get id() {
10487
+ return this._id;
10488
+ }
10489
+ set id(value) {
10490
+ this._id = value || this._uid;
10491
+ }
8820
10492
  constructor() {
8821
- this._uid = inject(IdGenerator).getId('monkey-pass-secret-number-');
8822
- this.orLabel = inject(MonkeyDictionaryService).get('OR');
8823
- this.pins = [];
10493
+ this._uid = inject(IdGenerator).getId('monkey-pass-number-');
8824
10494
  this.selected = [];
8825
10495
  this.onChange = output();
8826
10496
  // eslint-disable-next-line no-self-assign
8827
10497
  this.id = this.id;
8828
10498
  }
8829
- ngOnInit() {
8830
- const qtd = 10;
8831
- const pinPasswords = shuffle(new Array(qtd).fill(qtd).map((value, i) => {
8832
- return (value * i) / qtd;
8833
- }));
8834
- this.pins = pinPasswords
8835
- .map((value, index) => {
8836
- return {
8837
- first: value,
8838
- last: pinPasswords[pinPasswords.length - index - 1]
8839
- };
8840
- })
8841
- .slice(0, 5);
8842
- }
8843
10499
  clear() {
8844
10500
  this.selected = [];
8845
- this.onChange.emit(this.getPinPassword());
8846
- }
8847
- getPinPassword() {
8848
- const result = {
8849
- passNumber1: '',
8850
- passNumber2: '',
8851
- passNumber3: '',
8852
- passNumber4: ''
8853
- };
8854
- this.selected.forEach((value, index) => {
8855
- result[`passNumber${index + 1}`] = value;
8856
- });
8857
- return result;
10501
+ this.onChange.emit(this.selected);
8858
10502
  }
8859
10503
  onPress(pin) {
8860
10504
  if (this.selected.length < 4) {
8861
- this.selected.push(`${pin.first}${pin.last}`);
8862
- this.onChange.emit(this.getPinPassword());
10505
+ this.selected.push(pin);
10506
+ this.onChange.emit(this.selected);
8863
10507
  }
8864
10508
  }
8865
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyPassSecretNumberComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8866
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyPassSecretNumberComponent, isStandalone: true, selector: "monkey-pass-secret-number", inputs: { disabled: "disabled", id: "id" }, outputs: { onChange: "onChange" }, host: { attributes: { "data-testid": "monkey-pass-secret-number" }, properties: { "attr.id": "id", "id": "id" } }, ngImport: i0, template: `
10509
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyPassNumberComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
10510
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyPassNumberComponent, isStandalone: true, selector: "monkey-pass-number", inputs: { disabled: "disabled", id: "id" }, outputs: { onChange: "onChange" }, host: { attributes: { "data-testid": "monkey-pass-number" }, properties: { "attr.id": "id", "id": "id" } }, ngImport: i0, template: `
8867
10511
  <div class="pin-selected">
8868
10512
  @for (input of [0, 1, 2, 3]; track input) {
8869
- <div class="pin-input" [class.filled]="selected[input]"></div>
10513
+ <div class="pin-input">
10514
+ {{ selected[input] }}
10515
+ </div>
8870
10516
  }
8871
10517
  </div>
8872
10518
  <div class="grid">
8873
- @for (pin of pins; track pin) {
10519
+ @for (pin of [1, 2, 3, 4, 5, 6, 7, 8, 9]; track pin) {
8874
10520
  <monkey-button
8875
10521
  size="lg"
8876
10522
  (click)="onPress(pin)"
8877
10523
  [disabled]="isDisabledNumbers || disabled"
8878
10524
  color="black"
8879
10525
  >
8880
- {{ pin.first }} {{ orLabel | async }} {{ pin.last }}
10526
+ {{ pin }}
8881
10527
  </monkey-button>
8882
10528
  }
10529
+ <div></div>
10530
+ <monkey-button
10531
+ size="lg"
10532
+ (click)="onPress(0)"
10533
+ [disabled]="isDisabledNumbers || disabled"
10534
+ color="black"
10535
+ >
10536
+ 0
10537
+ </monkey-button>
8883
10538
  <monkey-button
8884
- data-testid="clear-button"
8885
10539
  size="lg"
8886
10540
  type="secondary"
8887
10541
  (click)="clear()"
@@ -8890,29 +10544,39 @@ class MonkeyPassSecretNumberComponent {
8890
10544
  <i class="mk-i mk-i-delete"></i>
8891
10545
  </monkey-button>
8892
10546
  </div>
8893
- `, isInline: true, styles: [":host{display:flex;width:100%;max-width:250px;flex-direction:column;gap:1rem}:host .pin-selected{display:flex;align-items:center;justify-content:center;gap:8px}:host .pin-selected .pin-input{width:32px;height:32px;border:2px solid var(--mecx-color-gray-400);box-sizing:border-box;border-radius:4px;background-color:var(--mecx-color-white);display:flex;justify-content:center;align-items:center;line-height:24px;font-weight:600;font-size:14px;position:relative}:host .pin-selected .pin-input.filled:before{content:\"\";border-radius:50%;width:8px;height:8px;background-color:var(--mecx-color-gray-900);position:absolute;left:50%;top:50%;transform:translate(-50%,-50%)}:host .grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}\n"], dependencies: [{ kind: "component", type: MonkeyButtonComponent, selector: "monkey-button", inputs: ["disabled", "color", "size", "type", "loading", "id"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
10547
+ `, isInline: true, styles: [":host{display:flex;width:100%;max-width:250px;flex-direction:column;gap:1rem}:host .pin-selected{display:flex;align-items:center;justify-content:center;gap:8px}:host .pin-selected .pin-input{width:32px;height:32px;border:2px solid var(--mecx-color-gray-400);box-sizing:border-box;border-radius:4px;background-color:var(--mecx-color-white);display:flex;justify-content:center;align-items:center;line-height:24px;font-weight:600;font-size:14px;position:relative}:host .pin-selected .pin-input.filled:before{content:\"\";border-radius:50%;width:8px;height:8px;background-color:var(--mecx-color-gray-900);position:absolute;left:50%;top:50%;transform:translate(-50%,-50%)}:host .grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}\n"], dependencies: [{ kind: "component", type: MonkeyButtonComponent, selector: "monkey-button", inputs: ["disabled", "color", "size", "type", "loading", "id"] }] }); }
8894
10548
  }
8895
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyPassSecretNumberComponent, decorators: [{
10549
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyPassNumberComponent, decorators: [{
8896
10550
  type: Component,
8897
- args: [{ selector: 'monkey-pass-secret-number', imports: [AsyncPipe, MonkeyButtonComponent], template: `
10551
+ args: [{ selector: 'monkey-pass-number', imports: [MonkeyButtonComponent], template: `
8898
10552
  <div class="pin-selected">
8899
10553
  @for (input of [0, 1, 2, 3]; track input) {
8900
- <div class="pin-input" [class.filled]="selected[input]"></div>
10554
+ <div class="pin-input">
10555
+ {{ selected[input] }}
10556
+ </div>
8901
10557
  }
8902
10558
  </div>
8903
10559
  <div class="grid">
8904
- @for (pin of pins; track pin) {
10560
+ @for (pin of [1, 2, 3, 4, 5, 6, 7, 8, 9]; track pin) {
8905
10561
  <monkey-button
8906
10562
  size="lg"
8907
10563
  (click)="onPress(pin)"
8908
10564
  [disabled]="isDisabledNumbers || disabled"
8909
10565
  color="black"
8910
10566
  >
8911
- {{ pin.first }} {{ orLabel | async }} {{ pin.last }}
10567
+ {{ pin }}
8912
10568
  </monkey-button>
8913
10569
  }
10570
+ <div></div>
10571
+ <monkey-button
10572
+ size="lg"
10573
+ (click)="onPress(0)"
10574
+ [disabled]="isDisabledNumbers || disabled"
10575
+ color="black"
10576
+ >
10577
+ 0
10578
+ </monkey-button>
8914
10579
  <monkey-button
8915
- data-testid="clear-button"
8916
10580
  size="lg"
8917
10581
  type="secondary"
8918
10582
  (click)="clear()"
@@ -8922,7 +10586,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
8922
10586
  </monkey-button>
8923
10587
  </div>
8924
10588
  `, host: {
8925
- 'data-testid': 'monkey-pass-secret-number',
10589
+ 'data-testid': 'monkey-pass-number',
8926
10590
  '[attr.id]': 'id',
8927
10591
  '[id]': 'id'
8928
10592
  }, styles: [":host{display:flex;width:100%;max-width:250px;flex-direction:column;gap:1rem}:host .pin-selected{display:flex;align-items:center;justify-content:center;gap:8px}:host .pin-selected .pin-input{width:32px;height:32px;border:2px solid var(--mecx-color-gray-400);box-sizing:border-box;border-radius:4px;background-color:var(--mecx-color-white);display:flex;justify-content:center;align-items:center;line-height:24px;font-weight:600;font-size:14px;position:relative}:host .pin-selected .pin-input.filled:before{content:\"\";border-radius:50%;width:8px;height:8px;background-color:var(--mecx-color-gray-900);position:absolute;left:50%;top:50%;transform:translate(-50%,-50%)}:host .grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}\n"] }]
@@ -8937,231 +10601,133 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
8937
10601
  * This style guide was developed by Monkey Exchange Team
8938
10602
  * MIT Licence
8939
10603
  ************************* */
8940
-
8941
- /** ************************
8942
- * Copyright Monkey Exchange. All Rights Reserved
8943
- * This style guide was developed by Monkey Exchange Team
8944
- * MIT Licence
8945
- ************************* */
8946
- /**
8947
- * Shortest the thumb may get, in px — matches the `--mecx-spaces-medium`
8948
- * floor in the stylesheet. A very long list would otherwise give a 2px thumb,
8949
- * too small to grab.
8950
- */
8951
- const MIN_THUMB = 24;
8952
- /**
8953
- * A DRAWN scrollbar, not the native one styled — a native scrollbar can't
8954
- * live outside the element that scrolls (e.g. below a table's rows, next to
8955
- * its footer), and cross-browser track styling (radius, border) is
8956
- * inconsistent enough that matching a design exactly isn't reliable with
8957
- * `::-webkit-scrollbar`/`scrollbar-color` alone.
8958
- *
8959
- * It does NOT replace real scrolling: `target` keeps its own
8960
- * `overflow: auto`, so keyboard, wheel and trackpad scrolling all keep
8961
- * working — this is a draggable mirror drawn on top. That's also why it's
8962
- * `aria-hidden`: a screen reader user scrolls the real region, and a second
8963
- * widget announcing the same position would only add noise.
8964
- */
8965
- class MonkeyScrollbarComponent {
8966
- constructor() {
8967
- this._zone = inject(NgZone);
8968
- this.orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
8969
- this.size = input('medium', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
8970
- /** The element that actually scrolls. */
8971
- this.target = input.required(...(ngDevMode ? [{ debugName: "target" }] : /* istanbul ignore next */ []));
8972
- this.trackEl = viewChild.required('track');
8973
- /** Scrollable length of the content, in px. */
8974
- this.total = signal(0, ...(ngDevMode ? [{ debugName: "total" }] : /* istanbul ignore next */ []));
8975
- /** Visible length of the viewport, in px. */
8976
- this.visible = signal(0, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
8977
- /** How far the target is scrolled, in px. */
8978
- this.scrolled = signal(0, ...(ngDevMode ? [{ debugName: "scrolled" }] : /* istanbul ignore next */ []));
8979
- /** Length of the track the thumb slides along, in px. */
8980
- this.trackLength = signal(0, ...(ngDevMode ? [{ debugName: "trackLength" }] : /* istanbul ignore next */ []));
8981
- this.scrollable = computed(() => this.total() - this.visible() > 1, ...(ngDevMode ? [{ debugName: "scrollable" }] : /* istanbul ignore next */ []));
8982
- this.thumbSize = computed(() => {
8983
- const total = this.total();
8984
- return `${total > 0 ? Math.min(1, this.visible() / total) * 100 : 100}%`;
8985
- }, ...(ngDevMode ? [{ debugName: "thumbSize" }] : /* istanbul ignore next */ []));
8986
- /**
8987
- * A px distance, applied as a `translate`, not as `left`/`top`: moving the
8988
- * thumb then costs a composited transform instead of a layout pass on every
8989
- * scroll frame. It has to be px rather than a percentage of the thumb
8990
- * because the thumb has a minimum length — once that kicks in, a
8991
- * percentage of its own (clamped) size no longer maps to track distance.
8992
- */
8993
- this.thumbOffset = computed(() => {
8994
- const total = this.total();
8995
- const visible = this.visible();
8996
- const track = this.trackLength();
8997
- if (total <= 0 || track <= 0)
8998
- return '0px';
8999
- const thumb = Math.max(MIN_THUMB, (visible / total) * track);
9000
- const free = Math.max(0, track - thumb);
9001
- const progress = Math.min(1, Math.max(0, this.scrolled() / Math.max(1, total - visible)));
9002
- return `${free * progress}px`;
9003
- }, ...(ngDevMode ? [{ debugName: "thumbOffset" }] : /* istanbul ignore next */ []));
9004
- /** Pending animation frame, 0 when none is queued. */
9005
- this.frame = 0;
9006
- /** Whether the cached lengths need re-reading on the next frame. */
9007
- this.sizeStale = true;
9008
- this.onScroll = () => this.schedule();
9009
- /** Drag state. `null` = nobody is dragging. */
9010
- this.drag = null;
9011
- effect((onCleanup) => {
9012
- const target = this.target();
9013
- this.attach(target);
9014
- onCleanup(() => this.detach());
9015
- });
9016
- }
9017
- ngOnDestroy() {
9018
- this.detach();
9019
- }
9020
- attach(target) {
9021
- this.detach();
9022
- this.observedTarget = target;
9023
- // Outside the Angular zone: a zone-patched 'scroll' listener costs a full
9024
- // global change-detection pass per event. The signals `measure()` writes
9025
- // still schedule change detection by themselves.
9026
- this._zone.runOutsideAngular(() => {
9027
- target.addEventListener('scroll', this.onScroll, { passive: true });
9028
- // The target AND its content: the bar should disappear when the content
9029
- // shrinks, not only when the container itself is resized — a column
9030
- // removed from the table doesn't resize the scrolling wrapper, only how
9031
- // far it needs to scroll. The track too, so the thumb's px offset stays
9032
- // right when the bar itself changes width.
9033
- this.resizeObserver = new ResizeObserver(() => this.schedule(true));
9034
- this.resizeObserver.observe(target);
9035
- this.resizeObserver.observe(this.trackEl().nativeElement);
9036
- Array.from(target.children).forEach((child) => this.resizeObserver?.observe(child));
9037
- });
9038
- this.sizeStale = true;
9039
- this.measure();
9040
- }
9041
- detach() {
9042
- this.observedTarget?.removeEventListener('scroll', this.onScroll);
9043
- this.observedTarget = undefined;
9044
- this.resizeObserver?.disconnect();
9045
- this.resizeObserver = undefined;
9046
- if (this.frame)
9047
- cancelAnimationFrame(this.frame);
9048
- this.frame = 0;
9049
- }
9050
- /**
9051
- * Scroll events fire far more often than the screen refreshes, and each
9052
- * measurement reads layout. Coalescing to one read per frame is what keeps
9053
- * a long table from thrashing layout while it scrolls.
9054
- */
9055
- schedule(resized = false) {
9056
- if (resized)
9057
- this.sizeStale = true;
9058
- if (this.frame)
9059
- return;
9060
- this.frame = this._zone.runOutsideAngular(() => {
9061
- return requestAnimationFrame(() => {
9062
- this.frame = 0;
9063
- this.measure();
9064
- });
9065
- });
9066
- }
9067
- measure() {
9068
- const target = this.observedTarget;
9069
- if (!target)
9070
- return;
9071
- const horizontal = this.orientation() === 'horizontal';
9072
- // Only the scroll offset changes while scrolling; the lengths can't, so
9073
- // re-reading them per frame would force layout for nothing.
9074
- if (this.sizeStale) {
9075
- this.sizeStale = false;
9076
- const track = this.trackEl().nativeElement;
9077
- this.total.set(horizontal ? target.scrollWidth : target.scrollHeight);
9078
- this.visible.set(horizontal ? target.clientWidth : target.clientHeight);
9079
- this.trackLength.set(horizontal ? track.clientWidth : track.clientHeight);
9080
- }
9081
- this.scrolled.set(horizontal ? target.scrollLeft : target.scrollTop);
10604
+ class MonkeyPassSecretNumberComponent {
10605
+ get id() {
10606
+ return this._id;
9082
10607
  }
9083
- onPointerDown(event) {
9084
- const target = this.observedTarget;
9085
- if (!target || !this.scrollable())
9086
- return;
9087
- const horizontal = this.orientation() === 'horizontal';
9088
- event.preventDefault();
9089
- event.target.setPointerCapture(event.pointerId);
9090
- this.drag = {
9091
- start: horizontal ? event.clientX : event.clientY,
9092
- initialScroll: horizontal ? target.scrollLeft : target.scrollTop
9093
- };
10608
+ set id(value) {
10609
+ this._id = value || this._uid;
9094
10610
  }
9095
- onPointerMove(event) {
9096
- const target = this.observedTarget;
9097
- if (!this.drag || !target)
9098
- return;
9099
- const horizontal = this.orientation() === 'horizontal';
9100
- const track = this.trackEl().nativeElement.getBoundingClientRect();
9101
- const trackLength = horizontal ? track.width : track.height;
9102
- if (trackLength <= 0)
9103
- return;
9104
- // One thumb pixel is worth (total / track) content pixels — without this
9105
- // conversion, dragging moves at the wrong speed and the thumb drifts
9106
- // away from the pointer.
9107
- const total = horizontal ? target.scrollWidth : target.scrollHeight;
9108
- const moved = (horizontal ? event.clientX : event.clientY) - this.drag.start;
9109
- const destination = this.drag.initialScroll + moved * (total / trackLength);
9110
- if (horizontal)
9111
- target.scrollLeft = destination;
9112
- else
9113
- target.scrollTop = destination;
10611
+ get isDisabledNumbers() {
10612
+ return this.selected?.length === 4;
9114
10613
  }
9115
- onPointerUp(event) {
9116
- if (!this.drag)
9117
- return;
9118
- this.drag = null;
9119
- event.target.releasePointerCapture?.(event.pointerId);
10614
+ get isDisabledClear() {
10615
+ return this.selected?.length === 0;
9120
10616
  }
9121
- /** Clicking the track outside the thumb jumps the content there, centered on the click. */
9122
- onTrackPointerDown(event) {
9123
- const target = this.observedTarget;
9124
- if (!target || !this.scrollable() || this.drag)
9125
- return;
9126
- const horizontal = this.orientation() === 'horizontal';
9127
- const track = this.trackEl().nativeElement.getBoundingClientRect();
9128
- const length = horizontal ? track.width : track.height;
9129
- if (length <= 0)
9130
- return;
9131
- const point = horizontal ? event.clientX - track.left : event.clientY - track.top;
9132
- const total = horizontal ? target.scrollWidth : target.scrollHeight;
9133
- const visible = horizontal ? target.clientWidth : target.clientHeight;
9134
- const destination = (point / length) * total - visible / 2;
9135
- if (horizontal)
9136
- target.scrollLeft = destination;
9137
- else
9138
- target.scrollTop = destination;
10617
+ constructor() {
10618
+ this._uid = inject(IdGenerator).getId('monkey-pass-secret-number-');
10619
+ this.orLabel = inject(MonkeyDictionaryService).get('OR');
10620
+ this.pins = [];
10621
+ this.selected = [];
10622
+ this.onChange = output();
10623
+ // eslint-disable-next-line no-self-assign
10624
+ this.id = this.id;
9139
10625
  }
9140
- /**
9141
- * Manual re-measure. Public on purpose: the automatic triggers (scroll,
9142
- * ResizeObserver on the target and its children) cover what the browser
9143
- * reports on its own — this is the escape hatch for what it doesn't, e.g.
9144
- * a target swapped out from under the component.
9145
- */
9146
- remeasure() {
9147
- this.sizeStale = true;
9148
- this.measure();
10626
+ ngOnInit() {
10627
+ const qtd = 10;
10628
+ const pinPasswords = shuffle(new Array(qtd).fill(qtd).map((value, i) => {
10629
+ return (value * i) / qtd;
10630
+ }));
10631
+ this.pins = pinPasswords
10632
+ .map((value, index) => {
10633
+ return {
10634
+ first: value,
10635
+ last: pinPasswords[pinPasswords.length - index - 1]
10636
+ };
10637
+ })
10638
+ .slice(0, 5);
9149
10639
  }
9150
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyScrollbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
9151
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.4", type: MonkeyScrollbarComponent, isStandalone: true, selector: "monkey-scrollbar", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "aria-hidden": "true" }, properties: { "class.mecx-scrollbar--horizontal": "orientation() === 'horizontal'", "class.mecx-scrollbar--vertical": "orientation() === 'vertical'", "class.mecx-scrollbar--small": "size() === 'small'", "class.mecx-scrollbar--medium": "size() === 'medium'", "class.mecx-scrollbar--inert": "!scrollable()" }, classAttribute: "mecx-scrollbar" }, viewQueries: [{ propertyName: "trackEl", first: true, predicate: ["track"], descendants: true, isSignal: true }], ngImport: i0, template: "<div #track class=\"mecx-scrollbar-track\" (pointerdown)=\"onTrackPointerDown($event)\">\n <div\n class=\"mecx-scrollbar-thumb\"\n [style.--mecx-scrollbar-thumb-size]=\"thumbSize()\"\n [style.--mecx-scrollbar-thumb-offset]=\"thumbOffset()\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n ></div>\n</div>\n", styles: [".mecx-scrollbar{box-sizing:border-box;display:block;flex-shrink:0;background:var(--mecx-color-gray-100);border:1px solid var(--mecx-color-gray-500);border-radius:800px}.mecx-scrollbar--inert{display:none}.mecx-scrollbar-track{position:relative}.mecx-scrollbar-thumb{position:absolute;background:var(--mecx-color-gray-900);border-radius:800px;cursor:grab;touch-action:none;will-change:transform}.mecx-scrollbar-thumb:active{cursor:grabbing}.mecx-scrollbar--medium{--mecx-scrollbar-gap: 4px}.mecx-scrollbar--small{--mecx-scrollbar-gap: 0px}.mecx-scrollbar--horizontal{width:100%}.mecx-scrollbar--horizontal .mecx-scrollbar-track{width:100%;height:calc(6px + 2 * var(--mecx-scrollbar-gap))}.mecx-scrollbar--horizontal .mecx-scrollbar-thumb{inset-block:var(--mecx-scrollbar-gap);left:0;width:var(--mecx-scrollbar-thumb-size);min-width:var(--mecx-spaces-medium);transform:translate(var(--mecx-scrollbar-thumb-offset, 0px))}.mecx-scrollbar--vertical{align-self:stretch}.mecx-scrollbar--vertical .mecx-scrollbar-track{width:calc(6px + 2 * var(--mecx-scrollbar-gap));height:100%}.mecx-scrollbar--vertical .mecx-scrollbar-thumb{inset-inline:var(--mecx-scrollbar-gap);top:0;height:var(--mecx-scrollbar-thumb-size);min-height:var(--mecx-spaces-medium);transform:translateY(var(--mecx-scrollbar-thumb-offset, 0px))}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
10640
+ clear() {
10641
+ this.selected = [];
10642
+ this.onChange.emit(this.getPinPassword());
10643
+ }
10644
+ getPinPassword() {
10645
+ const result = {
10646
+ passNumber1: '',
10647
+ passNumber2: '',
10648
+ passNumber3: '',
10649
+ passNumber4: ''
10650
+ };
10651
+ this.selected.forEach((value, index) => {
10652
+ result[`passNumber${index + 1}`] = value;
10653
+ });
10654
+ return result;
10655
+ }
10656
+ onPress(pin) {
10657
+ if (this.selected.length < 4) {
10658
+ this.selected.push(`${pin.first}${pin.last}`);
10659
+ this.onChange.emit(this.getPinPassword());
10660
+ }
10661
+ }
10662
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyPassSecretNumberComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
10663
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyPassSecretNumberComponent, isStandalone: true, selector: "monkey-pass-secret-number", inputs: { disabled: "disabled", id: "id" }, outputs: { onChange: "onChange" }, host: { attributes: { "data-testid": "monkey-pass-secret-number" }, properties: { "attr.id": "id", "id": "id" } }, ngImport: i0, template: `
10664
+ <div class="pin-selected">
10665
+ @for (input of [0, 1, 2, 3]; track input) {
10666
+ <div class="pin-input" [class.filled]="selected[input]"></div>
10667
+ }
10668
+ </div>
10669
+ <div class="grid">
10670
+ @for (pin of pins; track pin) {
10671
+ <monkey-button
10672
+ size="lg"
10673
+ (click)="onPress(pin)"
10674
+ [disabled]="isDisabledNumbers || disabled"
10675
+ color="black"
10676
+ >
10677
+ {{ pin.first }} {{ orLabel | async }} {{ pin.last }}
10678
+ </monkey-button>
10679
+ }
10680
+ <monkey-button
10681
+ data-testid="clear-button"
10682
+ size="lg"
10683
+ type="secondary"
10684
+ (click)="clear()"
10685
+ [disabled]="isDisabledClear || disabled"
10686
+ >
10687
+ <i class="mk-i mk-i-delete"></i>
10688
+ </monkey-button>
10689
+ </div>
10690
+ `, isInline: true, styles: [":host{display:flex;width:100%;max-width:250px;flex-direction:column;gap:1rem}:host .pin-selected{display:flex;align-items:center;justify-content:center;gap:8px}:host .pin-selected .pin-input{width:32px;height:32px;border:2px solid var(--mecx-color-gray-400);box-sizing:border-box;border-radius:4px;background-color:var(--mecx-color-white);display:flex;justify-content:center;align-items:center;line-height:24px;font-weight:600;font-size:14px;position:relative}:host .pin-selected .pin-input.filled:before{content:\"\";border-radius:50%;width:8px;height:8px;background-color:var(--mecx-color-gray-900);position:absolute;left:50%;top:50%;transform:translate(-50%,-50%)}:host .grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}\n"], dependencies: [{ kind: "component", type: MonkeyButtonComponent, selector: "monkey-button", inputs: ["disabled", "color", "size", "type", "loading", "id"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
9152
10691
  }
9153
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyScrollbarComponent, decorators: [{
10692
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyPassSecretNumberComponent, decorators: [{
9154
10693
  type: Component,
9155
- args: [{ selector: 'monkey-scrollbar', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
9156
- class: 'mecx-scrollbar',
9157
- 'aria-hidden': 'true',
9158
- '[class.mecx-scrollbar--horizontal]': "orientation() === 'horizontal'",
9159
- '[class.mecx-scrollbar--vertical]': "orientation() === 'vertical'",
9160
- '[class.mecx-scrollbar--small]': "size() === 'small'",
9161
- '[class.mecx-scrollbar--medium]': "size() === 'medium'",
9162
- '[class.mecx-scrollbar--inert]': '!scrollable()'
9163
- }, template: "<div #track class=\"mecx-scrollbar-track\" (pointerdown)=\"onTrackPointerDown($event)\">\n <div\n class=\"mecx-scrollbar-thumb\"\n [style.--mecx-scrollbar-thumb-size]=\"thumbSize()\"\n [style.--mecx-scrollbar-thumb-offset]=\"thumbOffset()\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n ></div>\n</div>\n", styles: [".mecx-scrollbar{box-sizing:border-box;display:block;flex-shrink:0;background:var(--mecx-color-gray-100);border:1px solid var(--mecx-color-gray-500);border-radius:800px}.mecx-scrollbar--inert{display:none}.mecx-scrollbar-track{position:relative}.mecx-scrollbar-thumb{position:absolute;background:var(--mecx-color-gray-900);border-radius:800px;cursor:grab;touch-action:none;will-change:transform}.mecx-scrollbar-thumb:active{cursor:grabbing}.mecx-scrollbar--medium{--mecx-scrollbar-gap: 4px}.mecx-scrollbar--small{--mecx-scrollbar-gap: 0px}.mecx-scrollbar--horizontal{width:100%}.mecx-scrollbar--horizontal .mecx-scrollbar-track{width:100%;height:calc(6px + 2 * var(--mecx-scrollbar-gap))}.mecx-scrollbar--horizontal .mecx-scrollbar-thumb{inset-block:var(--mecx-scrollbar-gap);left:0;width:var(--mecx-scrollbar-thumb-size);min-width:var(--mecx-spaces-medium);transform:translate(var(--mecx-scrollbar-thumb-offset, 0px))}.mecx-scrollbar--vertical{align-self:stretch}.mecx-scrollbar--vertical .mecx-scrollbar-track{width:calc(6px + 2 * var(--mecx-scrollbar-gap));height:100%}.mecx-scrollbar--vertical .mecx-scrollbar-thumb{inset-inline:var(--mecx-scrollbar-gap);top:0;height:var(--mecx-scrollbar-thumb-size);min-height:var(--mecx-spaces-medium);transform:translateY(var(--mecx-scrollbar-thumb-offset, 0px))}\n"] }]
9164
- }], ctorParameters: () => [], propDecorators: { orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: true }] }], trackEl: [{ type: i0.ViewChild, args: ['track', { isSignal: true }] }] } });
10694
+ args: [{ selector: 'monkey-pass-secret-number', imports: [AsyncPipe, MonkeyButtonComponent], template: `
10695
+ <div class="pin-selected">
10696
+ @for (input of [0, 1, 2, 3]; track input) {
10697
+ <div class="pin-input" [class.filled]="selected[input]"></div>
10698
+ }
10699
+ </div>
10700
+ <div class="grid">
10701
+ @for (pin of pins; track pin) {
10702
+ <monkey-button
10703
+ size="lg"
10704
+ (click)="onPress(pin)"
10705
+ [disabled]="isDisabledNumbers || disabled"
10706
+ color="black"
10707
+ >
10708
+ {{ pin.first }} {{ orLabel | async }} {{ pin.last }}
10709
+ </monkey-button>
10710
+ }
10711
+ <monkey-button
10712
+ data-testid="clear-button"
10713
+ size="lg"
10714
+ type="secondary"
10715
+ (click)="clear()"
10716
+ [disabled]="isDisabledClear || disabled"
10717
+ >
10718
+ <i class="mk-i mk-i-delete"></i>
10719
+ </monkey-button>
10720
+ </div>
10721
+ `, host: {
10722
+ 'data-testid': 'monkey-pass-secret-number',
10723
+ '[attr.id]': 'id',
10724
+ '[id]': 'id'
10725
+ }, styles: [":host{display:flex;width:100%;max-width:250px;flex-direction:column;gap:1rem}:host .pin-selected{display:flex;align-items:center;justify-content:center;gap:8px}:host .pin-selected .pin-input{width:32px;height:32px;border:2px solid var(--mecx-color-gray-400);box-sizing:border-box;border-radius:4px;background-color:var(--mecx-color-white);display:flex;justify-content:center;align-items:center;line-height:24px;font-weight:600;font-size:14px;position:relative}:host .pin-selected .pin-input.filled:before{content:\"\";border-radius:50%;width:8px;height:8px;background-color:var(--mecx-color-gray-900);position:absolute;left:50%;top:50%;transform:translate(-50%,-50%)}:host .grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}\n"] }]
10726
+ }], ctorParameters: () => [], propDecorators: { disabled: [{
10727
+ type: Input
10728
+ }], onChange: [{ type: i0.Output, args: ["onChange"] }], id: [{
10729
+ type: Input
10730
+ }] } });
9165
10731
 
9166
10732
  /** ************************
9167
10733
  * Copyright Monkey Exchange. All Rights Reserved
@@ -9883,7 +11449,7 @@ const DEFAULT_MAX_VISIBLE_ROWS = 20;
9883
11449
  const DEFAULT_SKELETON_ROWS = 5;
9884
11450
  const WINDOW_BUFFER = 6;
9885
11451
  const VIRTUAL_SCREENFULS = 3;
9886
- const VIRTUAL_MIN_ROWS = 100;
11452
+ const VIRTUAL_MIN_ROWS = 19;
9887
11453
  class MonkeyTableComponent {
9888
11454
  constructor() {
9889
11455
  this.virtualStrategy = new MonkeyTableVirtualScroll();
@@ -9919,7 +11485,16 @@ class MonkeyTableComponent {
9919
11485
  ? 'left'
9920
11486
  : 'none';
9921
11487
  const control = (kind, px, pinned) => {
9922
- return { kind, key: `__${kind}`, column: null, width: `${px}px`, px, pinned, offset: 0, align: 'start' };
11488
+ return {
11489
+ kind,
11490
+ key: `__${kind}`,
11491
+ column: null,
11492
+ width: `${px}px`,
11493
+ px,
11494
+ pinned,
11495
+ offset: 0,
11496
+ align: 'start'
11497
+ };
9923
11498
  };
9924
11499
  const slots = [];
9925
11500
  if (this.selectionMode() !== 'none') {
@@ -10720,81 +12295,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
10720
12295
  }]
10721
12296
  }] });
10722
12297
 
10723
- /** ************************
10724
- * Copyright Monkey Exchange. All Rights Reserved
10725
- * This style guide was developed by Monkey Exchange Team
10726
- * MIT Licence
10727
- ************************* */
10728
- class MonkeyToastComponent {
10729
- get id() {
10730
- return this._id;
10731
- }
10732
- set id(value) {
10733
- this._id = value || this._uid;
10734
- }
10735
- get class() {
10736
- return this.type;
10737
- }
10738
- constructor(host) {
10739
- this.host = host;
10740
- this.icon = 'close-circle';
10741
- this.type = 'default';
10742
- this.isClosable = false;
10743
- this.onActionClick = new EventEmitter();
10744
- this.onClose = new EventEmitter();
10745
- this._uid = inject(IdGenerator).getId('monkey-toast-');
10746
- // eslint-disable-next-line no-self-assign
10747
- this.id = this.id;
10748
- }
10749
- close() {
10750
- this.host.nativeElement.classList.add('closed');
10751
- }
10752
- onAnimationEnd(event) {
10753
- if (event.animationName.includes('fade-out')) {
10754
- this.onClose.emit(this.id);
10755
- }
10756
- }
10757
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyToastComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
10758
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: MonkeyToastComponent, isStandalone: true, selector: "monkey-toast", inputs: { message: "message", icon: "icon", type: "type", isClosable: ["isClosable", "isClosable", booleanAttribute], actionLabel: "actionLabel", actionIcon: "actionIcon", id: "id" }, outputs: { onActionClick: "onActionClick", onClose: "onClose" }, host: { attributes: { "data-testid": "monkey-toast" }, listeners: { "animationend": "onAnimationEnd($event)" }, properties: { "attr.id": "id", "id": "id", "class": "this.class" } }, ngImport: i0, template: "<div class=\"monkey-toast-content\">\r\n @if (icon) {\r\n <i class=\"mk-i mk-i-{{icon}} lg\"></i>\r\n }\r\n <div>\r\n <div class=\"monkey-toast-message\">\r\n {{ message }}\r\n </div>\r\n @if (actionLabel) {\r\n <div class=\"monkey-toast-action\">\r\n <monkey-button\r\n class=\"monkey-toast-btn-action\"\r\n type=\"tertiary\"\r\n size=\"sm\"\r\n (click)=\"onActionClick.emit(id)\"\r\n >\r\n {{ actionLabel }}\r\n @if (actionIcon) {\r\n <i class=\"mk-i mk-i-{{actionIcon}} xs\" first></i>\r\n }\r\n </monkey-button>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n@if (isClosable) {\r\n <div class=\"monkey-toast-divider\"></div>\r\n <div class=\"monkey-toast-close\" (click)=\"close()\">\r\n <util-icon name=\"clear\" />\r\n </div>\r\n}\r\n", styles: ["monkey-toast{display:flex;align-items:start;min-width:300px;width:100%;gap:var(--mecx-spaces-medium);padding:var(--mecx-spaces-medium);box-shadow:0 8px 16px 0 var(--mecx-color-box-shadow);background-color:var(--mecx-color-gray-900);color:var(--mecx-color-white);border-radius:4px;max-width:450px;box-sizing:border-box;animation:fade-in .3s}monkey-toast.closed{animation:fade-out .1s}monkey-toast .monkey-toast-content{display:flex;gap:var(--mecx-spaces-xs);line-height:var(--mecx-lh-24);font-size:var(--mecx-fs-xxs);letter-spacing:.48px;flex-grow:1}monkey-toast .monkey-toast-action{margin:8px 0 0 -12px}monkey-toast .monkey-toast-action .monkey-toast-btn-action{margin:0!important}monkey-toast .monkey-toast-action .monkey-toast-btn-action .mecx-button{height:24px;color:var(--mecx-color-white)!important;outline-color:var(--mecx-color-white)}monkey-toast .monkey-toast-action .monkey-toast-btn-action .mecx-button .content{padding:12px 8px}monkey-toast .monkey-toast-action .monkey-toast-btn-action .mecx-button:hover{color:var(--mecx-color-white)!important}monkey-toast .monkey-toast-divider{width:1px;height:24px;opacity:.2;background-color:var(--mecx-color-white)}monkey-toast .monkey-toast-close{display:flex;align-items:center;justify-content:center;cursor:pointer}monkey-toast .monkey-toast-close svg *{fill:var(--mecx-color-white)!important}monkey-toast.success{background-color:var(--mecx-color-success-main)}monkey-toast.error{background-color:var(--mecx-color-error-700)}monkey-toast.question{background-color:var(--mecx-color-question-800)}monkey-toast.warning{background-color:var(--mecx-color-warning-main)}monkey-toast.warning .monkey-toast-divider{background-color:var(--mecx-color-gray-900)}monkey-toast.warning .monkey-toast-content{color:var(--mecx-color-gray-900)}monkey-toast.warning .monkey-toast-close svg *{fill:var(--mecx-color-gray-900)!important}monkey-toast.warning .monkey-toast-action .monkey-toast-btn-action .mecx-button{color:var(--mecx-color-gray-900)!important;outline-color:var(--mecx-color-gray-900)}monkey-toast.warning .monkey-toast-action .monkey-toast-btn-action .mecx-button:hover{color:var(--mecx-color-gray-900)!important}@keyframes fade-in{0%{transform:scale(.9);opacity:0}to{transform:scale(1);opacity:1}}@keyframes fade-out{to{transform:scale(.9);opacity:0}}\n"], dependencies: [{ kind: "component", type: MonkeyButtonComponent, selector: "monkey-button", inputs: ["disabled", "color", "size", "type", "loading", "id"] }, { kind: "component", type: UtilIconComponent, selector: "util-icon", inputs: ["name"] }], encapsulation: i0.ViewEncapsulation.None }); }
10759
- }
10760
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyToastComponent, decorators: [{
10761
- type: Component,
10762
- args: [{ selector: 'monkey-toast', imports: [MonkeyButtonComponent, UtilIconComponent], encapsulation: ViewEncapsulation.None, host: {
10763
- 'data-testid': 'monkey-toast',
10764
- '(animationend)': 'onAnimationEnd($event)',
10765
- '[attr.id]': 'id',
10766
- '[id]': 'id'
10767
- }, template: "<div class=\"monkey-toast-content\">\r\n @if (icon) {\r\n <i class=\"mk-i mk-i-{{icon}} lg\"></i>\r\n }\r\n <div>\r\n <div class=\"monkey-toast-message\">\r\n {{ message }}\r\n </div>\r\n @if (actionLabel) {\r\n <div class=\"monkey-toast-action\">\r\n <monkey-button\r\n class=\"monkey-toast-btn-action\"\r\n type=\"tertiary\"\r\n size=\"sm\"\r\n (click)=\"onActionClick.emit(id)\"\r\n >\r\n {{ actionLabel }}\r\n @if (actionIcon) {\r\n <i class=\"mk-i mk-i-{{actionIcon}} xs\" first></i>\r\n }\r\n </monkey-button>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n@if (isClosable) {\r\n <div class=\"monkey-toast-divider\"></div>\r\n <div class=\"monkey-toast-close\" (click)=\"close()\">\r\n <util-icon name=\"clear\" />\r\n </div>\r\n}\r\n", styles: ["monkey-toast{display:flex;align-items:start;min-width:300px;width:100%;gap:var(--mecx-spaces-medium);padding:var(--mecx-spaces-medium);box-shadow:0 8px 16px 0 var(--mecx-color-box-shadow);background-color:var(--mecx-color-gray-900);color:var(--mecx-color-white);border-radius:4px;max-width:450px;box-sizing:border-box;animation:fade-in .3s}monkey-toast.closed{animation:fade-out .1s}monkey-toast .monkey-toast-content{display:flex;gap:var(--mecx-spaces-xs);line-height:var(--mecx-lh-24);font-size:var(--mecx-fs-xxs);letter-spacing:.48px;flex-grow:1}monkey-toast .monkey-toast-action{margin:8px 0 0 -12px}monkey-toast .monkey-toast-action .monkey-toast-btn-action{margin:0!important}monkey-toast .monkey-toast-action .monkey-toast-btn-action .mecx-button{height:24px;color:var(--mecx-color-white)!important;outline-color:var(--mecx-color-white)}monkey-toast .monkey-toast-action .monkey-toast-btn-action .mecx-button .content{padding:12px 8px}monkey-toast .monkey-toast-action .monkey-toast-btn-action .mecx-button:hover{color:var(--mecx-color-white)!important}monkey-toast .monkey-toast-divider{width:1px;height:24px;opacity:.2;background-color:var(--mecx-color-white)}monkey-toast .monkey-toast-close{display:flex;align-items:center;justify-content:center;cursor:pointer}monkey-toast .monkey-toast-close svg *{fill:var(--mecx-color-white)!important}monkey-toast.success{background-color:var(--mecx-color-success-main)}monkey-toast.error{background-color:var(--mecx-color-error-700)}monkey-toast.question{background-color:var(--mecx-color-question-800)}monkey-toast.warning{background-color:var(--mecx-color-warning-main)}monkey-toast.warning .monkey-toast-divider{background-color:var(--mecx-color-gray-900)}monkey-toast.warning .monkey-toast-content{color:var(--mecx-color-gray-900)}monkey-toast.warning .monkey-toast-close svg *{fill:var(--mecx-color-gray-900)!important}monkey-toast.warning .monkey-toast-action .monkey-toast-btn-action .mecx-button{color:var(--mecx-color-gray-900)!important;outline-color:var(--mecx-color-gray-900)}monkey-toast.warning .monkey-toast-action .monkey-toast-btn-action .mecx-button:hover{color:var(--mecx-color-gray-900)!important}@keyframes fade-in{0%{transform:scale(.9);opacity:0}to{transform:scale(1);opacity:1}}@keyframes fade-out{to{transform:scale(.9);opacity:0}}\n"] }]
10768
- }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { message: [{
10769
- type: Input
10770
- }], icon: [{
10771
- type: Input
10772
- }], type: [{
10773
- type: Input
10774
- }], isClosable: [{
10775
- type: Input,
10776
- args: [{ transform: booleanAttribute }]
10777
- }], actionLabel: [{
10778
- type: Input
10779
- }], actionIcon: [{
10780
- type: Input
10781
- }], onActionClick: [{
10782
- type: Output
10783
- }], onClose: [{
10784
- type: Output
10785
- }], id: [{
10786
- type: Input
10787
- }], class: [{
10788
- type: HostBinding,
10789
- args: ['class']
10790
- }] } });
10791
-
10792
- /** ************************
10793
- * Copyright Monkey Exchange. All Rights Reserved
10794
- * This style guide was developed by Monkey Exchange Team
10795
- * MIT Licence
10796
- ************************* */
10797
-
10798
12298
  /** ************************
10799
12299
  * Copyright Monkey Exchange. All Rights Reserved
10800
12300
  * This style guide was developed by Monkey Exchange Team
@@ -11521,5 +13021,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
11521
13021
  * Generated bundle index. Do not edit.
11522
13022
  */
11523
13023
 
11524
- 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, 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 };
13024
+ 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 };
11525
13025
  //# sourceMappingURL=monkey-style-guide.mjs.map