@xsmusices/ui 1.44.4 → 1.44.7
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.
- package/fesm2022/xsmusices-ui.mjs +127 -25
- package/fesm2022/xsmusices-ui.mjs.map +1 -1
- package/index.d.ts +52 -13
- package/package.json +1 -1
|
@@ -5223,36 +5223,82 @@ class XSBodyOverflowService {
|
|
|
5223
5223
|
platformId;
|
|
5224
5224
|
documentService;
|
|
5225
5225
|
count = 0;
|
|
5226
|
+
locked = [];
|
|
5226
5227
|
constructor(platformId, documentService) {
|
|
5227
5228
|
this.platformId = platformId;
|
|
5228
5229
|
this.documentService = documentService;
|
|
5229
5230
|
}
|
|
5230
|
-
|
|
5231
|
+
/**
|
|
5232
|
+
* Bloquea el scroll. Sin selector bloquea body (histórico).
|
|
5233
|
+
* Con selector CSS bloquea ese elemento ADEMÁS de body, restaurando
|
|
5234
|
+
* el valor previo exacto al desbloquear. Si el selector no existe,
|
|
5235
|
+
* solo se bloquea body. Contador para aperturas repetidas.
|
|
5236
|
+
*/
|
|
5237
|
+
lock(selector) {
|
|
5231
5238
|
this.count++;
|
|
5232
|
-
if (isPlatformBrowser(this.platformId)
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5239
|
+
if (!isPlatformBrowser(this.platformId))
|
|
5240
|
+
return;
|
|
5241
|
+
if (this.count !== 1)
|
|
5242
|
+
return;
|
|
5243
|
+
const doc = this.documentService.document;
|
|
5244
|
+
if (!doc)
|
|
5245
|
+
return;
|
|
5246
|
+
this.lockEl(doc.body);
|
|
5247
|
+
if (selector) {
|
|
5248
|
+
try {
|
|
5249
|
+
const target = doc.querySelector(selector);
|
|
5250
|
+
if (target instanceof HTMLElement &&
|
|
5251
|
+
target !== doc.body) {
|
|
5252
|
+
this.lockEl(target);
|
|
5253
|
+
}
|
|
5254
|
+
}
|
|
5255
|
+
catch {
|
|
5256
|
+
// Selector inválido: se mantiene solo el bloqueo de body.
|
|
5236
5257
|
}
|
|
5237
5258
|
}
|
|
5238
5259
|
}
|
|
5260
|
+
lockEl(el) {
|
|
5261
|
+
this.locked.push({ el, prevOverflow: el.style.overflow });
|
|
5262
|
+
el.style.overflow = 'hidden';
|
|
5263
|
+
}
|
|
5239
5264
|
unlock() {
|
|
5240
5265
|
this.count = Math.max(0, this.count - 1);
|
|
5241
|
-
if (isPlatformBrowser(this.platformId)
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5266
|
+
if (!isPlatformBrowser(this.platformId))
|
|
5267
|
+
return;
|
|
5268
|
+
if (this.count !== 0)
|
|
5269
|
+
return;
|
|
5270
|
+
const doc = this.documentService.document;
|
|
5271
|
+
if (!doc) {
|
|
5272
|
+
this.locked = [];
|
|
5273
|
+
return;
|
|
5274
|
+
}
|
|
5275
|
+
for (const { el, prevOverflow } of this.locked) {
|
|
5276
|
+
if (el.isConnected) {
|
|
5277
|
+
el.style.overflow = prevOverflow;
|
|
5245
5278
|
}
|
|
5246
5279
|
}
|
|
5280
|
+
this.locked = [];
|
|
5247
5281
|
}
|
|
5248
5282
|
reset() {
|
|
5249
5283
|
this.count = 0;
|
|
5250
|
-
if (isPlatformBrowser(this.platformId)) {
|
|
5251
|
-
|
|
5252
|
-
|
|
5284
|
+
if (!isPlatformBrowser(this.platformId)) {
|
|
5285
|
+
this.locked = [];
|
|
5286
|
+
return;
|
|
5287
|
+
}
|
|
5288
|
+
const doc = this.documentService.document;
|
|
5289
|
+
if (doc) {
|
|
5290
|
+
for (const { el, prevOverflow } of this.locked) {
|
|
5291
|
+
if (el.isConnected) {
|
|
5292
|
+
el.style.overflow = prevOverflow;
|
|
5293
|
+
}
|
|
5294
|
+
}
|
|
5295
|
+
// Compatibilidad: por si algún consumidor antiguo mutó body
|
|
5296
|
+
// directamente fuera del registro.
|
|
5297
|
+
if (doc.body.style.overflow === 'hidden') {
|
|
5253
5298
|
doc.body.style.overflow = '';
|
|
5254
5299
|
}
|
|
5255
5300
|
}
|
|
5301
|
+
this.locked = [];
|
|
5256
5302
|
}
|
|
5257
5303
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: XSBodyOverflowService, deps: [{ token: PLATFORM_ID }, { token: XSDocumentService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
5258
5304
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: XSBodyOverflowService, providedIn: 'root' });
|
|
@@ -7884,6 +7930,7 @@ class XSModalComponent {
|
|
|
7884
7930
|
injector = inject(Injector);
|
|
7885
7931
|
dynamicContentPlaceholder = viewChild.required('dynamicContentPlaceholder', { read: ViewContainerRef });
|
|
7886
7932
|
destroyRef = inject(DestroyRef);
|
|
7933
|
+
hostRef = inject(ElementRef);
|
|
7887
7934
|
translateService = inject(XSTranslateService);
|
|
7888
7935
|
langVersion = signal(0, ...(ngDevMode ? [{ debugName: "langVersion" }] : []));
|
|
7889
7936
|
platformId = inject(PLATFORM_ID);
|
|
@@ -7901,6 +7948,10 @@ class XSModalComponent {
|
|
|
7901
7948
|
buttons = signal([], ...(ngDevMode ? [{ debugName: "buttons" }] : []));
|
|
7902
7949
|
hasOverflow = true;
|
|
7903
7950
|
closeOnBackdropClick = signal(true, ...(ngDevMode ? [{ debugName: "closeOnBackdropClick" }] : []));
|
|
7951
|
+
showCloseButton = signal(false, ...(ngDevMode ? [{ debugName: "showCloseButton" }] : []));
|
|
7952
|
+
closeLabel = signal('', ...(ngDevMode ? [{ debugName: "closeLabel" }] : []));
|
|
7953
|
+
contentPadding = signal('default', ...(ngDevMode ? [{ debugName: "contentPadding" }] : []));
|
|
7954
|
+
panelSize = signal('xl', ...(ngDevMode ? [{ debugName: "panelSize" }] : []));
|
|
7904
7955
|
// unknown es necesario porque la acción que emite el modal es genérica y la define el componente inyectado
|
|
7905
7956
|
onAction = new Subject();
|
|
7906
7957
|
constructor() {
|
|
@@ -7932,7 +7983,7 @@ class XSModalComponent {
|
|
|
7932
7983
|
// unknown es necesario porque el modal acepta cualquier tipo de componente a inyectar
|
|
7933
7984
|
componentType,
|
|
7934
7985
|
// unknown es necesario porque el dato es genérico y lo define el componente inyectado
|
|
7935
|
-
data, type, title, subTitle, buttons, _hasOverflow, _closeOnBackdropClick) {
|
|
7986
|
+
data, type, title, subTitle, buttons, _hasOverflow, _closeOnBackdropClick, _showCloseButton, _closeLabel, _contentPadding, _panelSize) {
|
|
7936
7987
|
const placeholder = this.dynamicContentPlaceholder();
|
|
7937
7988
|
placeholder?.clear();
|
|
7938
7989
|
this.injectedComponentRef = placeholder.createComponent(componentType, {
|
|
@@ -7954,8 +8005,13 @@ class XSModalComponent {
|
|
|
7954
8005
|
}
|
|
7955
8006
|
this.closeRequested = false;
|
|
7956
8007
|
this.isVisible.set(true);
|
|
7957
|
-
this.
|
|
7958
|
-
|
|
8008
|
+
if (isPlatformBrowser(this.platformId)) {
|
|
8009
|
+
this.previousActiveElement =
|
|
8010
|
+
document.activeElement;
|
|
8011
|
+
}
|
|
8012
|
+
else {
|
|
8013
|
+
this.previousActiveElement = null;
|
|
8014
|
+
}
|
|
7959
8015
|
if (title !== undefined)
|
|
7960
8016
|
this.modalTitle.set(title);
|
|
7961
8017
|
if (subTitle !== undefined)
|
|
@@ -7966,6 +8022,17 @@ class XSModalComponent {
|
|
|
7966
8022
|
this.hasOverflow = _hasOverflow;
|
|
7967
8023
|
if (_closeOnBackdropClick !== undefined)
|
|
7968
8024
|
this.closeOnBackdropClick.set(_closeOnBackdropClick);
|
|
8025
|
+
if (_showCloseButton !== undefined)
|
|
8026
|
+
this.showCloseButton.set(_showCloseButton);
|
|
8027
|
+
if (_closeLabel !== undefined)
|
|
8028
|
+
this.closeLabel.set(_closeLabel);
|
|
8029
|
+
if (_contentPadding !== undefined)
|
|
8030
|
+
this.contentPadding.set(_contentPadding);
|
|
8031
|
+
if (_panelSize !== undefined)
|
|
8032
|
+
this.panelSize.set(_panelSize);
|
|
8033
|
+
if (isPlatformBrowser(this.platformId)) {
|
|
8034
|
+
setTimeout(() => this.focusInitial(), 0);
|
|
8035
|
+
}
|
|
7969
8036
|
const fbInstance = this.injectedComponentRef?.instance?.footerButtons;
|
|
7970
8037
|
if (fbInstance) {
|
|
7971
8038
|
this.footerSyncEffect?.destroy();
|
|
@@ -8000,6 +8067,11 @@ class XSModalComponent {
|
|
|
8000
8067
|
onTabKey(event) {
|
|
8001
8068
|
if (!this.isVisible())
|
|
8002
8069
|
return;
|
|
8070
|
+
if (!isPlatformBrowser(this.platformId))
|
|
8071
|
+
return;
|
|
8072
|
+
const active = document.activeElement;
|
|
8073
|
+
if (!active || !this.hostRef.nativeElement.contains(active))
|
|
8074
|
+
return;
|
|
8003
8075
|
const focusable = this.getFocusableElements();
|
|
8004
8076
|
if (focusable.length === 0) {
|
|
8005
8077
|
event.preventDefault();
|
|
@@ -8018,19 +8090,37 @@ class XSModalComponent {
|
|
|
8018
8090
|
}
|
|
8019
8091
|
}
|
|
8020
8092
|
getFocusableElements() {
|
|
8021
|
-
const hostEl =
|
|
8093
|
+
const hostEl = this.hostRef.nativeElement;
|
|
8022
8094
|
if (!hostEl)
|
|
8023
8095
|
return [];
|
|
8024
8096
|
return Array.from(hostEl.querySelectorAll('a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'));
|
|
8025
8097
|
}
|
|
8098
|
+
/** Lleva el foco al panel o a su primer elemento enfocable. */
|
|
8099
|
+
focusInitial() {
|
|
8100
|
+
if (!this.isVisible())
|
|
8101
|
+
return;
|
|
8102
|
+
const focusable = this.getFocusableElements();
|
|
8103
|
+
if (focusable.length > 0) {
|
|
8104
|
+
focusable[0].focus();
|
|
8105
|
+
return;
|
|
8106
|
+
}
|
|
8107
|
+
const panel = this.hostRef.nativeElement.querySelector('[data-xs-modal-panel]');
|
|
8108
|
+
panel?.focus();
|
|
8109
|
+
}
|
|
8026
8110
|
close(result) {
|
|
8027
8111
|
if (this.closeRequested)
|
|
8028
8112
|
return;
|
|
8029
8113
|
this.modalResult.next(result !== undefined ? result : null);
|
|
8030
8114
|
this.closeRequested = true;
|
|
8031
8115
|
this.isVisible.set(false);
|
|
8032
|
-
this.previousActiveElement
|
|
8116
|
+
const prev = this.previousActiveElement;
|
|
8033
8117
|
this.previousActiveElement = null;
|
|
8118
|
+
if (isPlatformBrowser(this.platformId) &&
|
|
8119
|
+
prev &&
|
|
8120
|
+
prev.isConnected &&
|
|
8121
|
+
typeof prev.focus === 'function') {
|
|
8122
|
+
prev.focus();
|
|
8123
|
+
}
|
|
8034
8124
|
}
|
|
8035
8125
|
onBackdropMouseDown(event) {
|
|
8036
8126
|
if (event.target === event.currentTarget &&
|
|
@@ -8069,14 +8159,14 @@ class XSModalComponent {
|
|
|
8069
8159
|
return this.translateService.translate(key);
|
|
8070
8160
|
}
|
|
8071
8161
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: XSModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8072
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.33", type: XSModalComponent, isStandalone: true, selector: "xs-modal", host: { attributes: { "xs-modal-host": "" }, listeners: { "document:keydown.escape": "onEscapeKey($event)" } }, viewQueries: [{ propertyName: "dynamicContentPlaceholder", first: true, predicate: ["dynamicContentPlaceholder"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<div\n class=\"modal-overlay\"\n role=\"dialog\"\n [attr.aria-modal]=\"true\"\n [attr.aria-label]=\"modalTitle() || translate('MODAL.DIALOG_LABEL')\"\n [ngClass]=\"{\n 'bottom-sheet': currentModalType() === 'bottom-sheet',\n centered: currentModalType() === 'centered',\n 'side-panel': currentModalType() === 'side-panel',\n }\"\n (mousedown)=\"onBackdropMouseDown($event)\"\n>\n <div\n class=\"relative
|
|
8162
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.33", type: XSModalComponent, isStandalone: true, selector: "xs-modal", host: { attributes: { "xs-modal-host": "" }, listeners: { "document:keydown.escape": "onEscapeKey($event)" } }, viewQueries: [{ propertyName: "dynamicContentPlaceholder", first: true, predicate: ["dynamicContentPlaceholder"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<div\n class=\"modal-overlay\"\n role=\"dialog\"\n [attr.aria-modal]=\"true\"\n [attr.aria-label]=\"modalTitle() || translate('MODAL.DIALOG_LABEL')\"\n [ngClass]=\"{\n 'bottom-sheet': currentModalType() === 'bottom-sheet',\n centered: currentModalType() === 'centered',\n 'side-panel': currentModalType() === 'side-panel',\n }\"\n (mousedown)=\"onBackdropMouseDown($event)\"\n>\n <div\n data-xs-modal-panel\n tabindex=\"-1\"\n class=\"relative bg-black shadow-lg max-h-[80vh] flex flex-col\"\n [class.p-4]=\"contentPadding() === 'default'\"\n [class.p-0]=\"contentPadding() === 'none'\"\n [ngClass]=\"{\n 'modal-bottom-sheet': currentModalType() === 'bottom-sheet',\n 'modal-centered': currentModalType() === 'centered',\n 'modal-side-panel': currentModalType() === 'side-panel',\n 'modal-side-panel-sm': currentModalType() === 'side-panel' && panelSize() === 'sm',\n 'modal-side-panel-md': currentModalType() === 'side-panel' && panelSize() === 'md',\n 'modal-side-panel-lg': currentModalType() === 'side-panel' && panelSize() === 'lg',\n 'animate-slide-up':\n isVisible() && currentModalType() === 'bottom-sheet',\n 'animate-slide-down':\n !isVisible() && currentModalType() === 'bottom-sheet',\n 'animate-zoom-in':\n isVisible() && currentModalType() === 'centered',\n 'animate-slide-in-right':\n isVisible() && currentModalType() === 'side-panel',\n 'animate-slide-out-right':\n !isVisible() && currentModalType() === 'side-panel',\n }\"\n role=\"document\"\n (mousedown)=\"$event.stopPropagation()\"\n (mouseup)=\"$event.stopPropagation()\"\n (animationend)=\"onAnimationEnd()\"\n >\n @if (currentModalType() === 'bottom-sheet') {\n <div\n class=\"flex justify-center p-2\"\n (mousedown)=\"$event.stopPropagation()\"\n (mouseup)=\"$event.stopPropagation()\"\n >\n <div class=\"w-10 h-1 bg-gray-300 rounded-full\"></div>\n </div>\n }\n @if (modalTitle()) {\n <div\n class=\"modal-header px-4 pb-2 text-center\"\n (mousedown)=\"$event.stopPropagation()\"\n (mouseup)=\"$event.stopPropagation()\"\n >\n <h2 class=\"text-xl font-bold text-white\">\n {{ modalTitle() }}\n </h2>\n @if (modalSubTitle()) {\n <p class=\"text-sm text-gray-300\">\n {{ modalSubTitle() }}\n </p>\n }\n </div>\n }\n @if (showCloseButton()) {\n <button\n type=\"button\"\n class=\"modal-close-btn\"\n (click)=\"close()\"\n [attr.aria-label]=\"closeLabel() || translate('MODAL.CLOSE')\"\n >\n <span aria-hidden=\"true\">\u00D7</span>\n </button>\n }\n\n <div class=\"flex-1 px-2 overflow-y-auto overflow-x-hidden\">\n <ng-template #dynamicContentPlaceholder></ng-template>\n </div>\n\n @if (buttons() && buttons().length > 0) {\n <div\n class=\"modal-footer grid grid-cols-12 gap-2 pt-4 mt-2 bg-black border-t border-zinc-800/30\"\n >\n @for (button of buttons(); track button.id ?? $index) {\n <xs-button\n [id]=\"\n button.id\n ? button.id\n : buttons().indexOf(button).toString()\n \"\n (click)=\"handleButtonAction(button.action!)\"\n [variant]=\"\n button.variant ? button.variant : 'primary'\n \"\n [layout]=\"button.layout ? button.layout : 'between'\"\n [isFull]=\"true\"\n [disabled]=\"button.disabled ?? false\"\n [loading]=\"button.loading ?? false\"\n [icon]=\"button.icon\"\n [label]=\"button.label\"\n [ngClass]=\"getButtonClass(button)\"\n >\n </xs-button>\n }\n </div>\n }\n </div>\n</div>\n", styles: [".modal-overlay{position:fixed;inset:0;z-index:10000;display:flex;justify-content:center;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1));--tw-bg-opacity: .5}.modal-bottom-sheet{z-index:10001;width:100%;max-width:28rem;border-top-left-radius:1rem;border-top-right-radius:1rem}.modal-overlay.bottom-sheet{align-items:flex-end}.modal-centered{z-index:10001;margin:1rem;width:100%;max-width:32rem;border-radius:.75rem}.modal-overlay.centered{align-items:center}.modal-footer{padding-bottom:max(1rem,env(safe-area-inset-bottom,0px));padding-left:max(1rem,env(safe-area-inset-left,0px));padding-right:max(1rem,env(safe-area-inset-right,0px))}.modal-overlay.side-panel .modal-header{padding-top:max(.5rem,env(safe-area-inset-top,0px))}.modal-close-btn{position:absolute;top:.75rem;right:.75rem;z-index:10;display:flex;height:2.25rem;width:2.25rem;align-items:center;justify-content:center;border-radius:9999px;font-size:1.5rem;line-height:2rem;line-height:1;--tw-text-opacity: 1;color:rgb(161 161 170 / var(--tw-text-opacity, 1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.modal-close-btn:hover{background-color:#27272a99;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.modal-close-btn:focus-visible{outline-width:2px;outline-color:#fff}.modal-overlay.side-panel .modal-close-btn{top:max(.75rem,env(safe-area-inset-top,0px));right:max(.75rem,env(safe-area-inset-right,0px))}.modal-side-panel{z-index:10001;margin:0;height:100vh;max-height:100vh;width:100%;border-radius:0;border-left-width:1px;--tw-border-opacity: 1;border-color:rgb(39 39 42 / var(--tw-border-opacity, 1));height:100dvh;max-height:100dvh}.modal-side-panel,.modal-side-panel-sm,.modal-side-panel-md,.modal-side-panel-lg{width:100%}@media(min-width:640px){.modal-side-panel-sm{max-width:28rem}.modal-side-panel-md{max-width:32rem}.modal-side-panel-lg,.modal-side-panel{max-width:36rem}}@media(min-width:1024px){.modal-side-panel{max-width:42rem}}.modal-overlay.side-panel{align-items:stretch;justify-content:flex-end;padding:0}@keyframes slideUp{0%{transform:translateY(100%)}to{transform:translateY(0)}}@keyframes slideDown{0%{transform:translateY(0)}to{transform:translateY(100%)}}@keyframes zoomIn{0%{transform:scale(.9);opacity:0}to{transform:scale(1);opacity:1}}@keyframes slideInRight{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes slideOutRight{0%{transform:translate(0)}to{transform:translate(100%)}}.animate-slide-in-right{animation:slideInRight .3s ease-out forwards}.animate-slide-out-right{animation:slideOutRight .3s ease-in forwards}.animate-zoom-in{animation:zoomIn .3s ease-out forwards}.animate-slide-up{animation:slideUp .3s ease-out forwards}.animate-slide-down{animation:slideDown .3s ease-in forwards}:host h2{text-transform:uppercase}:host-context(xs-button) button{text-transform:uppercase}.close-button{position:absolute;top:.75rem;right:.75rem;cursor:pointer;font-size:1.5rem;line-height:2rem;font-weight:700;--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.close-button:hover{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.modal-open{overflow:hidden}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: XSButtonComponent, selector: "xs-button", inputs: ["id", "label", "type", "icon", "action", "customClass", "variant", "layout", "badgeCount", "isFull", "disabled", "loading", "title", "ariaLabel", "borderRadius", "isGrouped", "groupPosition"], outputs: ["isGroupedChange", "groupPositionChange", "click", "onClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
8073
8163
|
}
|
|
8074
8164
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: XSModalComponent, decorators: [{
|
|
8075
8165
|
type: Component,
|
|
8076
8166
|
args: [{ selector: 'xs-modal', imports: [CommonModule, XSButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
8077
8167
|
'xs-modal-host': '',
|
|
8078
8168
|
'(document:keydown.escape)': 'onEscapeKey($event)',
|
|
8079
|
-
}, template: "<div\n class=\"modal-overlay\"\n role=\"dialog\"\n [attr.aria-modal]=\"true\"\n [attr.aria-label]=\"modalTitle() || translate('MODAL.DIALOG_LABEL')\"\n [ngClass]=\"{\n 'bottom-sheet': currentModalType() === 'bottom-sheet',\n centered: currentModalType() === 'centered',\n 'side-panel': currentModalType() === 'side-panel',\n }\"\n (mousedown)=\"onBackdropMouseDown($event)\"\n>\n <div\n class=\"relative
|
|
8169
|
+
}, template: "<div\n class=\"modal-overlay\"\n role=\"dialog\"\n [attr.aria-modal]=\"true\"\n [attr.aria-label]=\"modalTitle() || translate('MODAL.DIALOG_LABEL')\"\n [ngClass]=\"{\n 'bottom-sheet': currentModalType() === 'bottom-sheet',\n centered: currentModalType() === 'centered',\n 'side-panel': currentModalType() === 'side-panel',\n }\"\n (mousedown)=\"onBackdropMouseDown($event)\"\n>\n <div\n data-xs-modal-panel\n tabindex=\"-1\"\n class=\"relative bg-black shadow-lg max-h-[80vh] flex flex-col\"\n [class.p-4]=\"contentPadding() === 'default'\"\n [class.p-0]=\"contentPadding() === 'none'\"\n [ngClass]=\"{\n 'modal-bottom-sheet': currentModalType() === 'bottom-sheet',\n 'modal-centered': currentModalType() === 'centered',\n 'modal-side-panel': currentModalType() === 'side-panel',\n 'modal-side-panel-sm': currentModalType() === 'side-panel' && panelSize() === 'sm',\n 'modal-side-panel-md': currentModalType() === 'side-panel' && panelSize() === 'md',\n 'modal-side-panel-lg': currentModalType() === 'side-panel' && panelSize() === 'lg',\n 'animate-slide-up':\n isVisible() && currentModalType() === 'bottom-sheet',\n 'animate-slide-down':\n !isVisible() && currentModalType() === 'bottom-sheet',\n 'animate-zoom-in':\n isVisible() && currentModalType() === 'centered',\n 'animate-slide-in-right':\n isVisible() && currentModalType() === 'side-panel',\n 'animate-slide-out-right':\n !isVisible() && currentModalType() === 'side-panel',\n }\"\n role=\"document\"\n (mousedown)=\"$event.stopPropagation()\"\n (mouseup)=\"$event.stopPropagation()\"\n (animationend)=\"onAnimationEnd()\"\n >\n @if (currentModalType() === 'bottom-sheet') {\n <div\n class=\"flex justify-center p-2\"\n (mousedown)=\"$event.stopPropagation()\"\n (mouseup)=\"$event.stopPropagation()\"\n >\n <div class=\"w-10 h-1 bg-gray-300 rounded-full\"></div>\n </div>\n }\n @if (modalTitle()) {\n <div\n class=\"modal-header px-4 pb-2 text-center\"\n (mousedown)=\"$event.stopPropagation()\"\n (mouseup)=\"$event.stopPropagation()\"\n >\n <h2 class=\"text-xl font-bold text-white\">\n {{ modalTitle() }}\n </h2>\n @if (modalSubTitle()) {\n <p class=\"text-sm text-gray-300\">\n {{ modalSubTitle() }}\n </p>\n }\n </div>\n }\n @if (showCloseButton()) {\n <button\n type=\"button\"\n class=\"modal-close-btn\"\n (click)=\"close()\"\n [attr.aria-label]=\"closeLabel() || translate('MODAL.CLOSE')\"\n >\n <span aria-hidden=\"true\">\u00D7</span>\n </button>\n }\n\n <div class=\"flex-1 px-2 overflow-y-auto overflow-x-hidden\">\n <ng-template #dynamicContentPlaceholder></ng-template>\n </div>\n\n @if (buttons() && buttons().length > 0) {\n <div\n class=\"modal-footer grid grid-cols-12 gap-2 pt-4 mt-2 bg-black border-t border-zinc-800/30\"\n >\n @for (button of buttons(); track button.id ?? $index) {\n <xs-button\n [id]=\"\n button.id\n ? button.id\n : buttons().indexOf(button).toString()\n \"\n (click)=\"handleButtonAction(button.action!)\"\n [variant]=\"\n button.variant ? button.variant : 'primary'\n \"\n [layout]=\"button.layout ? button.layout : 'between'\"\n [isFull]=\"true\"\n [disabled]=\"button.disabled ?? false\"\n [loading]=\"button.loading ?? false\"\n [icon]=\"button.icon\"\n [label]=\"button.label\"\n [ngClass]=\"getButtonClass(button)\"\n >\n </xs-button>\n }\n </div>\n }\n </div>\n</div>\n", styles: [".modal-overlay{position:fixed;inset:0;z-index:10000;display:flex;justify-content:center;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1));--tw-bg-opacity: .5}.modal-bottom-sheet{z-index:10001;width:100%;max-width:28rem;border-top-left-radius:1rem;border-top-right-radius:1rem}.modal-overlay.bottom-sheet{align-items:flex-end}.modal-centered{z-index:10001;margin:1rem;width:100%;max-width:32rem;border-radius:.75rem}.modal-overlay.centered{align-items:center}.modal-footer{padding-bottom:max(1rem,env(safe-area-inset-bottom,0px));padding-left:max(1rem,env(safe-area-inset-left,0px));padding-right:max(1rem,env(safe-area-inset-right,0px))}.modal-overlay.side-panel .modal-header{padding-top:max(.5rem,env(safe-area-inset-top,0px))}.modal-close-btn{position:absolute;top:.75rem;right:.75rem;z-index:10;display:flex;height:2.25rem;width:2.25rem;align-items:center;justify-content:center;border-radius:9999px;font-size:1.5rem;line-height:2rem;line-height:1;--tw-text-opacity: 1;color:rgb(161 161 170 / var(--tw-text-opacity, 1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.modal-close-btn:hover{background-color:#27272a99;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.modal-close-btn:focus-visible{outline-width:2px;outline-color:#fff}.modal-overlay.side-panel .modal-close-btn{top:max(.75rem,env(safe-area-inset-top,0px));right:max(.75rem,env(safe-area-inset-right,0px))}.modal-side-panel{z-index:10001;margin:0;height:100vh;max-height:100vh;width:100%;border-radius:0;border-left-width:1px;--tw-border-opacity: 1;border-color:rgb(39 39 42 / var(--tw-border-opacity, 1));height:100dvh;max-height:100dvh}.modal-side-panel,.modal-side-panel-sm,.modal-side-panel-md,.modal-side-panel-lg{width:100%}@media(min-width:640px){.modal-side-panel-sm{max-width:28rem}.modal-side-panel-md{max-width:32rem}.modal-side-panel-lg,.modal-side-panel{max-width:36rem}}@media(min-width:1024px){.modal-side-panel{max-width:42rem}}.modal-overlay.side-panel{align-items:stretch;justify-content:flex-end;padding:0}@keyframes slideUp{0%{transform:translateY(100%)}to{transform:translateY(0)}}@keyframes slideDown{0%{transform:translateY(0)}to{transform:translateY(100%)}}@keyframes zoomIn{0%{transform:scale(.9);opacity:0}to{transform:scale(1);opacity:1}}@keyframes slideInRight{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes slideOutRight{0%{transform:translate(0)}to{transform:translate(100%)}}.animate-slide-in-right{animation:slideInRight .3s ease-out forwards}.animate-slide-out-right{animation:slideOutRight .3s ease-in forwards}.animate-zoom-in{animation:zoomIn .3s ease-out forwards}.animate-slide-up{animation:slideUp .3s ease-out forwards}.animate-slide-down{animation:slideDown .3s ease-in forwards}:host h2{text-transform:uppercase}:host-context(xs-button) button{text-transform:uppercase}.close-button{position:absolute;top:.75rem;right:.75rem;cursor:pointer;font-size:1.5rem;line-height:2rem;font-weight:700;--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.close-button:hover{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.modal-open{overflow:hidden}\n"] }]
|
|
8080
8170
|
}], ctorParameters: () => [], propDecorators: { dynamicContentPlaceholder: [{ type: i0.ViewChild, args: ['dynamicContentPlaceholder', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
|
|
8081
8171
|
|
|
8082
8172
|
class XSModalConfirmComponent {
|
|
@@ -9125,7 +9215,7 @@ class XSModalService {
|
|
|
9125
9215
|
if (this.modalComponentRef) {
|
|
9126
9216
|
this.doCloseModal();
|
|
9127
9217
|
}
|
|
9128
|
-
this.bodyOverflow.lock();
|
|
9218
|
+
this.bodyOverflow.lock(options.scrollLockSelector);
|
|
9129
9219
|
this.modalComponentRef = createComponent(XSModalComponent, {
|
|
9130
9220
|
environmentInjector: this.appRef.injector,
|
|
9131
9221
|
elementInjector: this.injector,
|
|
@@ -9139,7 +9229,7 @@ class XSModalService {
|
|
|
9139
9229
|
this.currentModalResult$ = modalResult$;
|
|
9140
9230
|
const result$ = modalResult$.asObservable();
|
|
9141
9231
|
if (this.modalComponentRef) {
|
|
9142
|
-
this.modalComponentRef.instance.injectComponent(componentType, options.data, options.type, options.title, options.subTitle, options.buttons, options.hasOverflow, options.closeOnBackdropClick);
|
|
9232
|
+
this.modalComponentRef.instance.injectComponent(componentType, options.data, options.type, options.title, options.subTitle, options.buttons, options.hasOverflow, options.closeOnBackdropClick, options.showCloseButton, options.closeLabel, options.contentPadding, options.panelSize);
|
|
9143
9233
|
result$.onAction =
|
|
9144
9234
|
this.modalComponentRef.instance.onAction.asObservable();
|
|
9145
9235
|
this.modalComponentRef.instance.onClose
|
|
@@ -9412,17 +9502,23 @@ class XSFormlyEntityPickerComponent extends XSFormlyBaseComponent {
|
|
|
9412
9502
|
ngOnDestroy() {
|
|
9413
9503
|
super.ngOnDestroy();
|
|
9414
9504
|
this.valueChangesSub.unsubscribe();
|
|
9505
|
+
this.searchSubject.complete();
|
|
9415
9506
|
}
|
|
9416
9507
|
syncSelectedItems() {
|
|
9417
9508
|
const value = this.control.value;
|
|
9418
9509
|
const items = Array.isArray(value)
|
|
9419
|
-
? [...value].sort((a, b) => a['position']
|
|
9420
|
-
|
|
9510
|
+
? [...value].sort((a, b) => (typeof a['position'] === 'number'
|
|
9511
|
+
? a['position']
|
|
9512
|
+
: 0) -
|
|
9513
|
+
(typeof b['position'] === 'number'
|
|
9514
|
+
? b['position']
|
|
9515
|
+
: 0))
|
|
9421
9516
|
: [];
|
|
9422
9517
|
this.selectedItems.set(items);
|
|
9423
9518
|
}
|
|
9424
9519
|
updateControl(items) {
|
|
9425
|
-
const sorted = [...items].sort((a, b) => a['position']
|
|
9520
|
+
const sorted = [...items].sort((a, b) => (typeof a['position'] === 'number' ? a['position'] : 0) -
|
|
9521
|
+
(typeof b['position'] === 'number' ? b['position'] : 0));
|
|
9426
9522
|
this.selectedItems.set(sorted);
|
|
9427
9523
|
this.control.setValue(sorted);
|
|
9428
9524
|
this.control.markAsDirty();
|
|
@@ -9489,7 +9585,13 @@ class XSFormlyEntityPickerComponent extends XSFormlyBaseComponent {
|
|
|
9489
9585
|
return;
|
|
9490
9586
|
const onConfirm = this.pickerProps.onConfirmRemove;
|
|
9491
9587
|
if (onConfirm) {
|
|
9492
|
-
|
|
9588
|
+
let allow = false;
|
|
9589
|
+
try {
|
|
9590
|
+
allow = await onConfirm(item);
|
|
9591
|
+
}
|
|
9592
|
+
catch {
|
|
9593
|
+
allow = false;
|
|
9594
|
+
}
|
|
9493
9595
|
if (!allow)
|
|
9494
9596
|
return;
|
|
9495
9597
|
}
|