monkey-style-guide 21.2.8 → 21.2.9
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,
|
|
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
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
this.
|
|
6580
|
-
this.
|
|
6581
|
-
|
|
6582
|
-
this.
|
|
6583
|
-
|
|
6584
|
-
this.
|
|
6585
|
-
|
|
6586
|
-
this.
|
|
6587
|
-
|
|
6588
|
-
this.
|
|
6589
|
-
this.
|
|
6590
|
-
this.
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
|
|
6602
|
-
|
|
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-
|
|
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.
|
|
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(
|
|
8862
|
-
this.onChange.emit(this.
|
|
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:
|
|
8866
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type:
|
|
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"
|
|
10513
|
+
<div class="pin-input">
|
|
10514
|
+
{{ selected[input] }}
|
|
10515
|
+
</div>
|
|
8870
10516
|
}
|
|
8871
10517
|
</div>
|
|
8872
10518
|
<div class="grid">
|
|
8873
|
-
@for (pin of
|
|
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
|
|
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"] }
|
|
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:
|
|
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-
|
|
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"
|
|
10554
|
+
<div class="pin-input">
|
|
10555
|
+
{{ selected[input] }}
|
|
10556
|
+
</div>
|
|
8901
10557
|
}
|
|
8902
10558
|
</div>
|
|
8903
10559
|
<div class="grid">
|
|
8904
|
-
@for (pin of
|
|
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
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
9084
|
-
|
|
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
|
-
|
|
9096
|
-
|
|
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
|
-
|
|
9116
|
-
|
|
9117
|
-
return;
|
|
9118
|
-
this.drag = null;
|
|
9119
|
-
event.target.releasePointerCapture?.(event.pointerId);
|
|
10614
|
+
get isDisabledClear() {
|
|
10615
|
+
return this.selected?.length === 0;
|
|
9120
10616
|
}
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
|
|
9124
|
-
|
|
9125
|
-
|
|
9126
|
-
|
|
9127
|
-
|
|
9128
|
-
|
|
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
|
-
|
|
9142
|
-
|
|
9143
|
-
|
|
9144
|
-
|
|
9145
|
-
|
|
9146
|
-
|
|
9147
|
-
|
|
9148
|
-
|
|
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
|
-
|
|
9151
|
-
|
|
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:
|
|
10692
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MonkeyPassSecretNumberComponent, decorators: [{
|
|
9154
10693
|
type: Component,
|
|
9155
|
-
args: [{ selector: 'monkey-
|
|
9156
|
-
|
|
9157
|
-
|
|
9158
|
-
|
|
9159
|
-
|
|
9160
|
-
|
|
9161
|
-
|
|
9162
|
-
|
|
9163
|
-
|
|
9164
|
-
|
|
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 =
|
|
11452
|
+
const VIRTUAL_MIN_ROWS = 22;
|
|
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 {
|
|
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
|