@xsmusices/ui 1.43.1 → 1.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/{xsmusices-ui-xs-modal.xsstory-B96CYHF0.mjs → xsmusices-ui-xs-modal.xsstory-D5nL8cjS.mjs} +83 -4
- package/fesm2022/xsmusices-ui-xs-modal.xsstory-D5nL8cjS.mjs.map +1 -0
- package/fesm2022/xsmusices-ui.mjs +3 -3
- package/fesm2022/xsmusices-ui.mjs.map +1 -1
- package/index.d.ts +22 -22
- package/package.json +1 -1
- package/fesm2022/xsmusices-ui-xs-modal.xsstory-B96CYHF0.mjs.map +0 -1
|
@@ -1,6 +1,64 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input,
|
|
2
|
+
import { input, output, signal, ChangeDetectionStrategy, Component, inject } from '@angular/core';
|
|
3
3
|
import { XSModalService, XSModalImageSearchComponent, XSButtonComponent } from './xsmusices-ui.mjs';
|
|
4
|
+
import * as i1 from '@angular/forms';
|
|
5
|
+
import { FormsModule } from '@angular/forms';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Contenido de ejemplo para el modo side-panel de xs-modal.
|
|
9
|
+
* Formulario largo con textarea para validar scroll interno,
|
|
10
|
+
* responsive (pantalla completa en móvil) y acciones de guardar/cancelar.
|
|
11
|
+
*/
|
|
12
|
+
class ModalSidePanelExampleComponent {
|
|
13
|
+
modalData = input(...(ngDevMode ? [undefined, { debugName: "modalData" }] : []));
|
|
14
|
+
modalResult = output();
|
|
15
|
+
artistName = signal('', ...(ngDevMode ? [{ debugName: "artistName" }] : []));
|
|
16
|
+
infoEn = signal('', ...(ngDevMode ? [{ debugName: "infoEn" }] : []));
|
|
17
|
+
genre = signal('', ...(ngDevMode ? [{ debugName: "genre" }] : []));
|
|
18
|
+
savedResult = signal(null, ...(ngDevMode ? [{ debugName: "savedResult" }] : []));
|
|
19
|
+
constructor() {
|
|
20
|
+
const data = this.modalData();
|
|
21
|
+
if (data?.artistName)
|
|
22
|
+
this.artistName.set(data.artistName);
|
|
23
|
+
if (data?.infoEn)
|
|
24
|
+
this.infoEn.set(data.infoEn);
|
|
25
|
+
}
|
|
26
|
+
footerButtons() {
|
|
27
|
+
return [
|
|
28
|
+
{
|
|
29
|
+
id: 'sidePanelCancel',
|
|
30
|
+
label: 'Cancelar',
|
|
31
|
+
icon: { name: 'cancel' },
|
|
32
|
+
action: 'cancel',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 'sidePanelSave',
|
|
36
|
+
label: 'Guardar',
|
|
37
|
+
icon: { name: 'check' },
|
|
38
|
+
action: 'save',
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
submit(action) {
|
|
43
|
+
if (action === 'save') {
|
|
44
|
+
const data = {
|
|
45
|
+
artistName: this.artistName(),
|
|
46
|
+
infoEn: this.infoEn(),
|
|
47
|
+
};
|
|
48
|
+
this.savedResult.set(`Guardado: ${data.artistName ?? '(sin nombre)'}`);
|
|
49
|
+
this.modalResult.emit({ action: 'save', data });
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
this.modalResult.emit(null);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: ModalSidePanelExampleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
56
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.33", type: ModalSidePanelExampleComponent, isStandalone: true, selector: "modal-side-panel-example", inputs: { modalData: { classPropertyName: "modalData", publicName: "modalData", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { modalResult: "modalResult" }, host: { attributes: { "modal-side-panel-example-host": "" } }, ngImport: i0, template: "<div class=\"flex flex-col gap-4 p-1\">\n <p class=\"text-sm text-zinc-400\">\n Ejemplo de panel lateral con formulario extenso. El contenido\n debe desplazarse internamente cuando sea largo y el panel debe\n ocupar toda la pantalla en m\u00F3vil.\n </p>\n\n <label class=\"flex flex-col gap-1 text-sm text-zinc-300\">\n Nombre del artista\n <input\n class=\"rounded-lg border border-zinc-700 bg-zinc-900 px-3 py-2 text-white outline-none focus:border-zinc-500\"\n type=\"text\"\n placeholder=\"Ej. Aphex Twin\"\n [ngModel]=\"artistName()\"\n (ngModelChange)=\"artistName.set($event)\"\n />\n </label>\n\n <label class=\"flex flex-col gap-1 text-sm text-zinc-300\">\n G\u00E9nero\n <input\n class=\"rounded-lg border border-zinc-700 bg-zinc-900 px-3 py-2 text-white outline-none focus:border-zinc-500\"\n type=\"text\"\n placeholder=\"Ej. Electronic\"\n [ngModel]=\"genre()\"\n (ngModelChange)=\"genre.set($event)\"\n />\n </label>\n\n <label class=\"flex flex-col gap-1 text-sm text-zinc-300\">\n Biograf\u00EDa (infoEn)\n <textarea\n class=\"min-h-40 rounded-lg border border-zinc-700 bg-zinc-900 px-3 py-2 text-white outline-none focus:border-zinc-500\"\n rows=\"8\"\n placeholder=\"Pega aqu\u00ED una biograf\u00EDa larga para probar el scroll y el teclado virtual\u2026\"\n [ngModel]=\"infoEn()\"\n (ngModelChange)=\"infoEn.set($event)\"\n ></textarea>\n </label>\n\n @for (\n block of [\n 'Bloque de relleno 1: contenido largo para forzar el scroll interno del panel.',\n 'Bloque de relleno 2: verifica que la cabecera y las acciones sigan accesibles.',\n 'Bloque de relleno 3: en m\u00F3vil no debe haber scroll horizontal ni contenido cortado.',\n 'Bloque de relleno 4: al cerrar se restaura el scroll de la p\u00E1gina original.',\n ];\n track $index\n ) {\n <p class=\"rounded-lg bg-zinc-900 p-3 text-sm text-zinc-400\">\n {{ block }}\n </p>\n }\n\n @if (savedResult()) {\n <p class=\"rounded-lg bg-zinc-800 p-3 text-sm text-emerald-400\">\n {{ savedResult() }}\n </p>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
57
|
+
}
|
|
58
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: ModalSidePanelExampleComponent, decorators: [{
|
|
59
|
+
type: Component,
|
|
60
|
+
args: [{ selector: 'modal-side-panel-example', host: { 'modal-side-panel-example-host': '' }, changeDetection: ChangeDetectionStrategy.OnPush, imports: [FormsModule], template: "<div class=\"flex flex-col gap-4 p-1\">\n <p class=\"text-sm text-zinc-400\">\n Ejemplo de panel lateral con formulario extenso. El contenido\n debe desplazarse internamente cuando sea largo y el panel debe\n ocupar toda la pantalla en m\u00F3vil.\n </p>\n\n <label class=\"flex flex-col gap-1 text-sm text-zinc-300\">\n Nombre del artista\n <input\n class=\"rounded-lg border border-zinc-700 bg-zinc-900 px-3 py-2 text-white outline-none focus:border-zinc-500\"\n type=\"text\"\n placeholder=\"Ej. Aphex Twin\"\n [ngModel]=\"artistName()\"\n (ngModelChange)=\"artistName.set($event)\"\n />\n </label>\n\n <label class=\"flex flex-col gap-1 text-sm text-zinc-300\">\n G\u00E9nero\n <input\n class=\"rounded-lg border border-zinc-700 bg-zinc-900 px-3 py-2 text-white outline-none focus:border-zinc-500\"\n type=\"text\"\n placeholder=\"Ej. Electronic\"\n [ngModel]=\"genre()\"\n (ngModelChange)=\"genre.set($event)\"\n />\n </label>\n\n <label class=\"flex flex-col gap-1 text-sm text-zinc-300\">\n Biograf\u00EDa (infoEn)\n <textarea\n class=\"min-h-40 rounded-lg border border-zinc-700 bg-zinc-900 px-3 py-2 text-white outline-none focus:border-zinc-500\"\n rows=\"8\"\n placeholder=\"Pega aqu\u00ED una biograf\u00EDa larga para probar el scroll y el teclado virtual\u2026\"\n [ngModel]=\"infoEn()\"\n (ngModelChange)=\"infoEn.set($event)\"\n ></textarea>\n </label>\n\n @for (\n block of [\n 'Bloque de relleno 1: contenido largo para forzar el scroll interno del panel.',\n 'Bloque de relleno 2: verifica que la cabecera y las acciones sigan accesibles.',\n 'Bloque de relleno 3: en m\u00F3vil no debe haber scroll horizontal ni contenido cortado.',\n 'Bloque de relleno 4: al cerrar se restaura el scroll de la p\u00E1gina original.',\n ];\n track $index\n ) {\n <p class=\"rounded-lg bg-zinc-900 p-3 text-sm text-zinc-400\">\n {{ block }}\n </p>\n }\n\n @if (savedResult()) {\n <p class=\"rounded-lg bg-zinc-800 p-3 text-sm text-emerald-400\">\n {{ savedResult() }}\n </p>\n }\n</div>\n" }]
|
|
61
|
+
}], ctorParameters: () => [], propDecorators: { modalData: [{ type: i0.Input, args: [{ isSignal: true, alias: "modalData", required: false }] }], modalResult: [{ type: i0.Output, args: ["modalResult"] }] } });
|
|
4
62
|
|
|
5
63
|
class ModalExampleComponent {
|
|
6
64
|
activeModal = input(...(ngDevMode ? [undefined, { debugName: "activeModal" }] : []));
|
|
@@ -106,12 +164,25 @@ class ModalExampleComponent {
|
|
|
106
164
|
})
|
|
107
165
|
.subscribe((_result) => { });
|
|
108
166
|
}
|
|
167
|
+
openSidePanel() {
|
|
168
|
+
this.modalService
|
|
169
|
+
.open(ModalSidePanelExampleComponent, {
|
|
170
|
+
type: 'side-panel',
|
|
171
|
+
title: 'Editar artista',
|
|
172
|
+
subTitle: 'Panel lateral (pantalla completa en móvil)',
|
|
173
|
+
data: {
|
|
174
|
+
artistName: 'Aphex Twin',
|
|
175
|
+
infoEn: 'Richard David James, known as Aphex Twin, is a British electronic musician.',
|
|
176
|
+
},
|
|
177
|
+
})
|
|
178
|
+
.subscribe((_result) => { });
|
|
179
|
+
}
|
|
109
180
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: ModalExampleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
110
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.33", type: ModalExampleComponent, isStandalone: true, selector: "modal-example", inputs: { activeModal: { classPropertyName: "activeModal", publicName: "activeModal", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "modal-example-host": "" } }, ngImport: i0, template: " <div class=\"p-4\">\n <div class=\"grid grid-cols-1 gap-4\">\n @if (activeModal() === 'confirm' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Confirmaci\u00F3n'\"\n (onClick)=\"openConfirm()\"\n ></xs-button>\n }\n @if (activeModal() === 'info' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Informaci\u00F3n'\"\n (onClick)=\"openInfo()\"\n ></xs-button>\n }\n @if (activeModal() === 'input' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Input'\"\n (onClick)=\"openInput()\"\n ></xs-button>\n }\n @if (activeModal() === 'claim' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Reclamo'\"\n (onClick)=\"openClaim()\"\n ></xs-button>\n }\n @if (\n activeModal() === 'imageSearch' || !activeModal()\n ) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de B\u00FAsqueda de Im\u00E1genes'\"\n (onClick)=\"openImageSearch()\"\n class=\"mb-2\"\n ></xs-button>\n }\n @if (\n activeModal() === 'imageSearchSources' ||\n !activeModal()\n ) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir con Google + SoundCloud'\"\n (onClick)=\"openImageSearchWithSources()\"\n ></xs-button>\n }\n </div>\n </div>\n", dependencies: [{ 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 });
|
|
181
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.33", type: ModalExampleComponent, isStandalone: true, selector: "modal-example", inputs: { activeModal: { classPropertyName: "activeModal", publicName: "activeModal", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "modal-example-host": "" } }, ngImport: i0, template: " <div class=\"p-4\">\n <div class=\"grid grid-cols-1 gap-4\">\n @if (activeModal() === 'confirm' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Confirmaci\u00F3n'\"\n (onClick)=\"openConfirm()\"\n ></xs-button>\n }\n @if (activeModal() === 'info' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Informaci\u00F3n'\"\n (onClick)=\"openInfo()\"\n ></xs-button>\n }\n @if (activeModal() === 'input' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Input'\"\n (onClick)=\"openInput()\"\n ></xs-button>\n }\n @if (activeModal() === 'claim' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Reclamo'\"\n (onClick)=\"openClaim()\"\n ></xs-button>\n }\n @if (\n activeModal() === 'imageSearch' || !activeModal()\n ) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de B\u00FAsqueda de Im\u00E1genes'\"\n (onClick)=\"openImageSearch()\"\n class=\"mb-2\"\n ></xs-button>\n }\n @if (\n activeModal() === 'imageSearchSources' ||\n !activeModal()\n ) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir con Google + SoundCloud'\"\n (onClick)=\"openImageSearchWithSources()\"\n ></xs-button>\n }\n @if (activeModal() === 'sidePanel' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Panel Lateral'\"\n (onClick)=\"openSidePanel()\"\n ></xs-button>\n }\n </div>\n </div>\n", dependencies: [{ 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 });
|
|
111
182
|
}
|
|
112
183
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: ModalExampleComponent, decorators: [{
|
|
113
184
|
type: Component,
|
|
114
|
-
args: [{ selector: 'modal-example', host: { 'modal-example-host': '' }, changeDetection: ChangeDetectionStrategy.OnPush, imports: [XSButtonComponent], template: " <div class=\"p-4\">\n <div class=\"grid grid-cols-1 gap-4\">\n @if (activeModal() === 'confirm' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Confirmaci\u00F3n'\"\n (onClick)=\"openConfirm()\"\n ></xs-button>\n }\n @if (activeModal() === 'info' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Informaci\u00F3n'\"\n (onClick)=\"openInfo()\"\n ></xs-button>\n }\n @if (activeModal() === 'input' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Input'\"\n (onClick)=\"openInput()\"\n ></xs-button>\n }\n @if (activeModal() === 'claim' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Reclamo'\"\n (onClick)=\"openClaim()\"\n ></xs-button>\n }\n @if (\n activeModal() === 'imageSearch' || !activeModal()\n ) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de B\u00FAsqueda de Im\u00E1genes'\"\n (onClick)=\"openImageSearch()\"\n class=\"mb-2\"\n ></xs-button>\n }\n @if (\n activeModal() === 'imageSearchSources' ||\n !activeModal()\n ) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir con Google + SoundCloud'\"\n (onClick)=\"openImageSearchWithSources()\"\n ></xs-button>\n }\n </div>\n </div>\n" }]
|
|
185
|
+
args: [{ selector: 'modal-example', host: { 'modal-example-host': '' }, changeDetection: ChangeDetectionStrategy.OnPush, imports: [XSButtonComponent], template: " <div class=\"p-4\">\n <div class=\"grid grid-cols-1 gap-4\">\n @if (activeModal() === 'confirm' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Confirmaci\u00F3n'\"\n (onClick)=\"openConfirm()\"\n ></xs-button>\n }\n @if (activeModal() === 'info' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Informaci\u00F3n'\"\n (onClick)=\"openInfo()\"\n ></xs-button>\n }\n @if (activeModal() === 'input' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Input'\"\n (onClick)=\"openInput()\"\n ></xs-button>\n }\n @if (activeModal() === 'claim' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Reclamo'\"\n (onClick)=\"openClaim()\"\n ></xs-button>\n }\n @if (\n activeModal() === 'imageSearch' || !activeModal()\n ) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de B\u00FAsqueda de Im\u00E1genes'\"\n (onClick)=\"openImageSearch()\"\n class=\"mb-2\"\n ></xs-button>\n }\n @if (\n activeModal() === 'imageSearchSources' ||\n !activeModal()\n ) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir con Google + SoundCloud'\"\n (onClick)=\"openImageSearchWithSources()\"\n ></xs-button>\n }\n @if (activeModal() === 'sidePanel' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Panel Lateral'\"\n (onClick)=\"openSidePanel()\"\n ></xs-button>\n }\n </div>\n </div>\n" }]
|
|
115
186
|
}], propDecorators: { activeModal: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeModal", required: false }] }] } });
|
|
116
187
|
|
|
117
188
|
const story = {
|
|
@@ -139,6 +210,7 @@ const story = {
|
|
|
139
210
|
'claim',
|
|
140
211
|
'imageSearch',
|
|
141
212
|
'imageSearchSources',
|
|
213
|
+
'sidePanel',
|
|
142
214
|
],
|
|
143
215
|
default: null,
|
|
144
216
|
},
|
|
@@ -186,6 +258,13 @@ const story = {
|
|
|
186
258
|
activeModal: 'imageSearchSources',
|
|
187
259
|
},
|
|
188
260
|
},
|
|
261
|
+
{
|
|
262
|
+
name: 'Side Panel',
|
|
263
|
+
description: 'Panel lateral derecho (pantalla completa en móvil) con formulario largo, textarea y scroll interno',
|
|
264
|
+
inputs: {
|
|
265
|
+
activeModal: 'sidePanel',
|
|
266
|
+
},
|
|
267
|
+
},
|
|
189
268
|
],
|
|
190
269
|
coverage: {
|
|
191
270
|
statements: 38,
|
|
@@ -196,4 +275,4 @@ const story = {
|
|
|
196
275
|
};
|
|
197
276
|
|
|
198
277
|
export { story };
|
|
199
|
-
//# sourceMappingURL=xsmusices-ui-xs-modal.xsstory-
|
|
278
|
+
//# sourceMappingURL=xsmusices-ui-xs-modal.xsstory-D5nL8cjS.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xsmusices-ui-xs-modal.xsstory-D5nL8cjS.mjs","sources":["../../../projects/xs-ui/src/lib/components/base/modal/modal-side-panel-example.component.ts","../../../projects/xs-ui/src/lib/components/base/modal/modal-side-panel-example.component.html","../../../projects/xs-ui/src/lib/components/base/modal/modal-example.component.ts","../../../projects/xs-ui/src/lib/components/base/modal/modal-example.component.html","../../../projects/xs-ui/src/lib/components/base/modal/xs-modal.xsstory.ts"],"sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n signal,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { XSButtonI } from '../button/xs-button.interface';\n\nexport interface ModalSidePanelData {\n artistName?: string;\n infoEn?: string;\n}\n\nexport interface ModalSidePanelResult {\n action: string;\n data: ModalSidePanelData;\n}\n\n/**\n * Contenido de ejemplo para el modo side-panel de xs-modal.\n * Formulario largo con textarea para validar scroll interno,\n * responsive (pantalla completa en móvil) y acciones de guardar/cancelar.\n */\n@Component({\n selector: 'modal-side-panel-example',\n host: { 'modal-side-panel-example-host': '' },\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [FormsModule],\n templateUrl: './modal-side-panel-example.component.html',\n})\nexport class ModalSidePanelExampleComponent {\n modalData = input<ModalSidePanelData>();\n modalResult = output<ModalSidePanelResult | null>();\n\n artistName = signal('');\n infoEn = signal('');\n genre = signal('');\n savedResult = signal<string | null>(null);\n\n constructor() {\n const data = this.modalData();\n if (data?.artistName) this.artistName.set(data.artistName);\n if (data?.infoEn) this.infoEn.set(data.infoEn);\n }\n\n footerButtons(): XSButtonI[] {\n return [\n {\n id: 'sidePanelCancel',\n label: 'Cancelar',\n icon: { name: 'cancel' },\n action: 'cancel',\n },\n {\n id: 'sidePanelSave',\n label: 'Guardar',\n icon: { name: 'check' },\n action: 'save',\n },\n ];\n }\n\n submit(action: string): void {\n if (action === 'save') {\n const data: ModalSidePanelData = {\n artistName: this.artistName(),\n infoEn: this.infoEn(),\n };\n this.savedResult.set(\n `Guardado: ${data.artistName ?? '(sin nombre)'}`,\n );\n this.modalResult.emit({ action: 'save', data });\n } else {\n this.modalResult.emit(null);\n }\n }\n}\n","<div class=\"flex flex-col gap-4 p-1\">\n <p class=\"text-sm text-zinc-400\">\n Ejemplo de panel lateral con formulario extenso. El contenido\n debe desplazarse internamente cuando sea largo y el panel debe\n ocupar toda la pantalla en móvil.\n </p>\n\n <label class=\"flex flex-col gap-1 text-sm text-zinc-300\">\n Nombre del artista\n <input\n class=\"rounded-lg border border-zinc-700 bg-zinc-900 px-3 py-2 text-white outline-none focus:border-zinc-500\"\n type=\"text\"\n placeholder=\"Ej. Aphex Twin\"\n [ngModel]=\"artistName()\"\n (ngModelChange)=\"artistName.set($event)\"\n />\n </label>\n\n <label class=\"flex flex-col gap-1 text-sm text-zinc-300\">\n Género\n <input\n class=\"rounded-lg border border-zinc-700 bg-zinc-900 px-3 py-2 text-white outline-none focus:border-zinc-500\"\n type=\"text\"\n placeholder=\"Ej. Electronic\"\n [ngModel]=\"genre()\"\n (ngModelChange)=\"genre.set($event)\"\n />\n </label>\n\n <label class=\"flex flex-col gap-1 text-sm text-zinc-300\">\n Biografía (infoEn)\n <textarea\n class=\"min-h-40 rounded-lg border border-zinc-700 bg-zinc-900 px-3 py-2 text-white outline-none focus:border-zinc-500\"\n rows=\"8\"\n placeholder=\"Pega aquí una biografía larga para probar el scroll y el teclado virtual…\"\n [ngModel]=\"infoEn()\"\n (ngModelChange)=\"infoEn.set($event)\"\n ></textarea>\n </label>\n\n @for (\n block of [\n 'Bloque de relleno 1: contenido largo para forzar el scroll interno del panel.',\n 'Bloque de relleno 2: verifica que la cabecera y las acciones sigan accesibles.',\n 'Bloque de relleno 3: en móvil no debe haber scroll horizontal ni contenido cortado.',\n 'Bloque de relleno 4: al cerrar se restaura el scroll de la página original.',\n ];\n track $index\n ) {\n <p class=\"rounded-lg bg-zinc-900 p-3 text-sm text-zinc-400\">\n {{ block }}\n </p>\n }\n\n @if (savedResult()) {\n <p class=\"rounded-lg bg-zinc-800 p-3 text-sm text-emerald-400\">\n {{ savedResult() }}\n </p>\n }\n</div>\n","import {\n Component,\n input,\n inject,\n ChangeDetectionStrategy,\n} from '@angular/core';\nimport { XSModalService } from './xs-modal.service';\nimport { XSButtonComponent } from '../button/xs-button.component';\nimport { XSModalImageSearchComponent } from './types/image-search/xs-modal-image-search.component';\nimport { ModalSidePanelExampleComponent } from './modal-side-panel-example.component';\n\n@Component({\n selector: 'modal-example',\n host: { 'modal-example-host': '' },\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [XSButtonComponent],\n templateUrl: './modal-example.component.html',\n})\nexport class ModalExampleComponent {\n activeModal = input<\n | 'confirm'\n | 'info'\n | 'input'\n | 'claim'\n | 'imageSearch'\n | 'imageSearchSources'\n | 'sidePanel'\n | null\n >();\n\n private modalService = inject(XSModalService);\n\n openConfirm(): void {\n this.modalService\n .openConfirm({\n title: 'Confirmar eliminación',\n subTitle:\n '¿Estás seguro de que quieres eliminar este elemento?',\n labelAccept: 'Sí, eliminar',\n labelCancel: 'Cancelar',\n type: 'centered',\n })\n .subscribe((_result) => {});\n }\n\n openInfo(): void {\n this.modalService\n .openInfo({\n title: 'Información importante',\n info: '<p>Este es un mensaje <strong>importante</strong> que el usuario debe leer.</p><p>Contiene información crítica sobre el sistema.</p>',\n labelClose: 'Entendido',\n type: 'centered',\n })\n .subscribe(() => {});\n }\n\n openInput(): void {\n this.modalService\n .openInput({\n title: 'Ingrese su nombre',\n subTitle: 'Necesitamos su nombre para continuar',\n placeholder: 'Escriba su nombre aquí...',\n minLength: 2,\n maxLength: 50,\n labelAccept: 'Guardar',\n labelCancel: 'Cancelar',\n type: 'centered',\n })\n .subscribe((_result) => {});\n }\n\n openClaim(): void {\n this.modalService\n .openClaim({\n title: 'Reclamar elemento',\n subTitle: 'Esta acción requiere justificación',\n warningMsg:\n '¿Estás seguro de que quieres reclamar este elemento?',\n enterReason:\n 'Por favor explica el motivo de la reclamación',\n labelAccept: 'Reclamar',\n labelCancel: 'Cancelar',\n type: 'centered',\n })\n .subscribe((_result) => {});\n }\n\n openImageSearch(): void {\n this.modalService\n .open(XSModalImageSearchComponent, {\n type: 'bottom-sheet',\n title: 'Scraping de imágenes',\n subTitle: 'Busca y selecciona una imagen',\n data: {\n q: 'music',\n searchImages: async (query: string, limit: number) => {\n const images = Array.from(\n { length: limit },\n (_, i) =>\n `https://picsum.photos/seed/${encodeURIComponent(query)}${i}/300/300`,\n );\n return { images };\n },\n },\n })\n .subscribe((_result) => {});\n }\n\n openImageSearchWithSources(): void {\n const mockSoundcloudSearch = async (query: string) => {\n return {\n images: [\n `https://picsum.photos/seed/soundcloud-${encodeURIComponent(query)}/300/300`,\n ],\n };\n };\n\n const mockGoogleSearch = async (\n query: string,\n limit: number,\n start?: number,\n ) => {\n const totalResults = 15;\n const offset = start ?? 1;\n const images = Array.from(\n { length: Math.min(limit, totalResults - offset + 1) },\n (_, i) =>\n `https://picsum.photos/seed/${encodeURIComponent(query)}-g-${offset + i}/300/300`,\n );\n return { images, totalResults };\n };\n\n this.modalService\n .open(XSModalImageSearchComponent, {\n type: 'bottom-sheet',\n title: 'Scraping de imágenes',\n subTitle: 'Busca en Google Images y SoundCloud',\n data: {\n q: 'music',\n sources: [\n {\n id: 'google',\n label: 'Google Images',\n searchImages: mockGoogleSearch,\n },\n {\n id: 'soundcloud',\n label: 'SoundCloud',\n searchImages: mockSoundcloudSearch,\n },\n ],\n },\n })\n .subscribe((_result) => {});\n }\n\n openSidePanel(): void {\n this.modalService\n .open(ModalSidePanelExampleComponent, {\n type: 'side-panel',\n title: 'Editar artista',\n subTitle: 'Panel lateral (pantalla completa en móvil)',\n data: {\n artistName: 'Aphex Twin',\n infoEn:\n 'Richard David James, known as Aphex Twin, is a British electronic musician.',\n },\n })\n .subscribe((_result) => {});\n }\n}\n"," <div class=\"p-4\">\n <div class=\"grid grid-cols-1 gap-4\">\n @if (activeModal() === 'confirm' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Confirmación'\"\n (onClick)=\"openConfirm()\"\n ></xs-button>\n }\n @if (activeModal() === 'info' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Información'\"\n (onClick)=\"openInfo()\"\n ></xs-button>\n }\n @if (activeModal() === 'input' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Input'\"\n (onClick)=\"openInput()\"\n ></xs-button>\n }\n @if (activeModal() === 'claim' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Reclamo'\"\n (onClick)=\"openClaim()\"\n ></xs-button>\n }\n @if (\n activeModal() === 'imageSearch' || !activeModal()\n ) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Modal de Búsqueda de Imágenes'\"\n (onClick)=\"openImageSearch()\"\n class=\"mb-2\"\n ></xs-button>\n }\n @if (\n activeModal() === 'imageSearchSources' ||\n !activeModal()\n ) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir con Google + SoundCloud'\"\n (onClick)=\"openImageSearchWithSources()\"\n ></xs-button>\n }\n @if (activeModal() === 'sidePanel' || !activeModal()) {\n <xs-button\n variant=\"primary\"\n [label]=\"'Abrir Panel Lateral'\"\n (onClick)=\"openSidePanel()\"\n ></xs-button>\n }\n </div>\n </div>\n","import { StoryMeta } from '../../../story.types';\nimport { ModalExampleComponent } from './modal-example.component';\n\nexport const story: StoryMeta = {\n id: 'modal',\n name: 'Modal',\n type: 'component',\n subtype: 'Base',\n status: 'active',\n usage: ['admin', 'app', 'monitor'],\n updated: '2026-05-30T12:00:00.000Z',\n created: '2025-07-29T15:06:52.383Z',\n description:\n 'Componente Modal con diferentes tipos predefinidos y soporte multi-idioma automático con traducciones expandidas.',\n component: ModalExampleComponent,\n selector: 'xs-modal',\n multilanguage: true,\n inputs: [\n {\n key: 'activeModal',\n label: 'Modal activo',\n type: 'select',\n options: [\n 'confirm',\n 'info',\n 'input',\n 'claim',\n 'imageSearch',\n 'imageSearchSources',\n 'sidePanel',\n ],\n default: null,\n },\n ],\n examples: [\n {\n name: 'Confirm Modal',\n description:\n 'Modal de confirmación para acciones del usuario',\n inputs: {\n activeModal: 'confirm',\n },\n },\n {\n name: 'Info Modal',\n description:\n 'Modal de información para mostrar mensajes al usuario',\n inputs: {\n activeModal: 'info',\n },\n },\n {\n name: 'Input Modal',\n description:\n 'Modal para solicitar entrada de datos del usuario',\n inputs: {\n activeModal: 'input',\n },\n },\n {\n name: 'Claim Modal',\n description:\n 'Modal de reclamación con campo de justificación',\n inputs: {\n activeModal: 'claim',\n },\n },\n {\n name: 'Image Search Modal',\n description:\n 'Modal de búsqueda de imágenes con input y resultados en grid',\n inputs: {\n activeModal: 'imageSearch',\n },\n },\n {\n name: 'Image Search con Google + SoundCloud',\n description:\n 'Modal de búsqueda de imágenes con múltiples fuentes: Google Images y SoundCloud',\n inputs: {\n activeModal: 'imageSearchSources',\n },\n },\n {\n name: 'Side Panel',\n description:\n 'Panel lateral derecho (pantalla completa en móvil) con formulario largo, textarea y scroll interno',\n inputs: {\n activeModal: 'sidePanel',\n },\n },\n ],\n coverage: {\n statements: 38,\n branches: 11,\n functions: 45,\n lines: 38,\n },\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -8070,14 +8070,14 @@ class XSModalComponent {
|
|
|
8070
8070
|
return this.translateService.translate(key);
|
|
8071
8071
|
}
|
|
8072
8072
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: XSModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8073
|
-
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 }\"\n (mousedown)=\"onBackdropMouseDown($event)\"\n>\n <div\n class=\"relative p-4 bg-black shadow-lg max-h-[80vh] flex flex-col\"\n [ngClass]=\"{\n 'modal-bottom-sheet': currentModalType() === 'bottom-sheet',\n 'modal-centered': currentModalType() === 'centered',\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 }\"\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=\"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\n <div class=\"flex-1 px-2 overflow-y-auto\">\n <ng-template #dynamicContentPlaceholder></ng-template>\n </div>\n\n @if (buttons() && buttons().length > 0) {\n <div\n class=\"grid grid-cols-12 gap-2 py-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 [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}@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}}.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
|
+
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 p-4 bg-black shadow-lg max-h-[80vh] flex flex-col\"\n [ngClass]=\"{\n 'modal-bottom-sheet': currentModalType() === 'bottom-sheet',\n 'modal-centered': currentModalType() === 'centered',\n 'modal-side-panel': currentModalType() === 'side-panel',\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=\"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\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=\"grid grid-cols-12 gap-2 py-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 [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-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))}@media(min-width:640px){.modal-side-panel{max-width:36rem}}@media(min-width:1024px){.modal-side-panel{max-width:42rem}}.modal-side-panel{height:100dvh;max-height:100dvh}.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 });
|
|
8074
8074
|
}
|
|
8075
8075
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: XSModalComponent, decorators: [{
|
|
8076
8076
|
type: Component,
|
|
8077
8077
|
args: [{ selector: 'xs-modal', imports: [CommonModule, XSButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
8078
8078
|
'xs-modal-host': '',
|
|
8079
8079
|
'(document:keydown.escape)': 'onEscapeKey($event)',
|
|
8080
|
-
}, 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 }\"\n (mousedown)=\"onBackdropMouseDown($event)\"\n>\n <div\n class=\"relative p-4 bg-black shadow-lg max-h-[80vh] flex flex-col\"\n [ngClass]=\"{\n 'modal-bottom-sheet': currentModalType() === 'bottom-sheet',\n 'modal-centered': currentModalType() === 'centered',\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 }\"\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=\"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\n <div class=\"flex-1 px-2 overflow-y-auto\">\n <ng-template #dynamicContentPlaceholder></ng-template>\n </div>\n\n @if (buttons() && buttons().length > 0) {\n <div\n class=\"grid grid-cols-12 gap-2 py-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 [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}@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}}.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
|
+
}, 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 p-4 bg-black shadow-lg max-h-[80vh] flex flex-col\"\n [ngClass]=\"{\n 'modal-bottom-sheet': currentModalType() === 'bottom-sheet',\n 'modal-centered': currentModalType() === 'centered',\n 'modal-side-panel': currentModalType() === 'side-panel',\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=\"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\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=\"grid grid-cols-12 gap-2 py-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 [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-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))}@media(min-width:640px){.modal-side-panel{max-width:36rem}}@media(min-width:1024px){.modal-side-panel{max-width:42rem}}.modal-side-panel{height:100dvh;max-height:100dvh}.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"] }]
|
|
8081
8081
|
}], ctorParameters: () => [], propDecorators: { dynamicContentPlaceholder: [{ type: i0.ViewChild, args: ['dynamicContentPlaceholder', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
|
|
8082
8082
|
|
|
8083
8083
|
class XSModalConfirmComponent {
|
|
@@ -23142,7 +23142,7 @@ const LIB_STORIES = [
|
|
|
23142
23142
|
() => import('./xsmusices-ui-xs-empty-state.xsstory-CCOJ4b9_.mjs').then((m) => m.story),
|
|
23143
23143
|
() => import('./xsmusices-ui-xs-icon.xsstory-asFaHy5H.mjs').then((m) => m.story),
|
|
23144
23144
|
() => import('./xsmusices-ui-xs-image.xsstory-BaeUg3Zp.mjs').then((m) => m.story),
|
|
23145
|
-
() => import('./xsmusices-ui-xs-modal.xsstory-
|
|
23145
|
+
() => import('./xsmusices-ui-xs-modal.xsstory-D5nL8cjS.mjs').then((m) => m.story),
|
|
23146
23146
|
() => import('./xsmusices-ui-xs-navbar.xsstory-BDW0nLAH.mjs').then((m) => m.story),
|
|
23147
23147
|
() => import('./xsmusices-ui-xs-navbar-sidebar.xsstory-DHmPSARx.mjs').then((m) => m.story),
|
|
23148
23148
|
() => import('./xsmusices-ui-stats-card.xsstory-PWTUDysc.mjs').then((m) => m.story),
|