@xsmusices/ui 1.44.0 → 1.44.4
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-D5nL8cjS.mjs → xsmusices-ui-xs-modal.xsstory-DJxKOKsQ.mjs} +8 -2
- package/fesm2022/{xsmusices-ui-xs-modal.xsstory-D5nL8cjS.mjs.map → xsmusices-ui-xs-modal.xsstory-DJxKOKsQ.mjs.map} +1 -1
- package/fesm2022/xsmusices-ui.mjs +6 -24
- package/fesm2022/xsmusices-ui.mjs.map +1 -1
- package/index.d.ts +15 -14
- package/package.json +1 -1
|
@@ -194,7 +194,13 @@ const story = {
|
|
|
194
194
|
usage: ['admin', 'app', 'monitor'],
|
|
195
195
|
updated: '2026-05-30T12:00:00.000Z',
|
|
196
196
|
created: '2025-07-29T15:06:52.383Z',
|
|
197
|
-
description: 'Componente Modal con diferentes tipos predefinidos y soporte multi-idioma automático con traducciones expandidas.'
|
|
197
|
+
description: 'Componente Modal con diferentes tipos predefinidos y soporte multi-idioma automático con traducciones expandidas. ' +
|
|
198
|
+
'Contrato de footer reactivo: el componente inyectado puede exponer footerButtons() (XSButtonI[]) y submit(action). ' +
|
|
199
|
+
'El modal sincroniza los botones ante cada cambio (etiqueta, variante, disabled, loading) y enruta cancel→cierre, ' +
|
|
200
|
+
'accept/save/delete/load→submit(action) si existe (si no, cierra con {action}) y cualquier otra acción→cierre con null. ' +
|
|
201
|
+
'Aviso: una acción personalizada sin submit cierra el modal con null. ' +
|
|
202
|
+
'El footer es persistente por construcción (flex, fuera del área de scroll con safe-area inferior) y es opcional: ' +
|
|
203
|
+
'pasar buttons o exponer footerButtons() lo activa; omitirlos conserva el modal sin footer, sin cambios para los usos existentes.',
|
|
198
204
|
component: ModalExampleComponent,
|
|
199
205
|
selector: 'xs-modal',
|
|
200
206
|
multilanguage: true,
|
|
@@ -275,4 +281,4 @@ const story = {
|
|
|
275
281
|
};
|
|
276
282
|
|
|
277
283
|
export { story };
|
|
278
|
-
//# sourceMappingURL=xsmusices-ui-xs-modal.xsstory-
|
|
284
|
+
//# sourceMappingURL=xsmusices-ui-xs-modal.xsstory-DJxKOKsQ.mjs.map
|
|
@@ -1 +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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"}
|
|
1
|
+
{"version":3,"file":"xsmusices-ui-xs-modal.xsstory-DJxKOKsQ.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 'Contrato de footer reactivo: el componente inyectado puede exponer footerButtons() (XSButtonI[]) y submit(action). ' +\n 'El modal sincroniza los botones ante cada cambio (etiqueta, variante, disabled, loading) y enruta cancel→cierre, ' +\n 'accept/save/delete/load→submit(action) si existe (si no, cierra con {action}) y cualquier otra acción→cierre con null. ' +\n 'Aviso: una acción personalizada sin submit cierra el modal con null. ' +\n 'El footer es persistente por construcción (flex, fuera del área de scroll con safe-area inferior) y es opcional: ' +\n 'pasar buttons o exponer footerButtons() lo activa; omitirlos conserva el modal sin footer, sin cambios para los usos existentes.',\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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"}
|
|
@@ -7565,7 +7565,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImpo
|
|
|
7565
7565
|
ReactiveFormsModule,
|
|
7566
7566
|
CountryFlagPipe,
|
|
7567
7567
|
XSImageComponent,
|
|
7568
|
-
XSIconComponent,
|
|
7569
7568
|
XSFormlyLabelComponent,
|
|
7570
7569
|
], host: {
|
|
7571
7570
|
'(document:click)': 'onDocumentClick($event)',
|
|
@@ -8070,14 +8069,14 @@ class XSModalComponent {
|
|
|
8070
8069
|
return this.translateService.translate(key);
|
|
8071
8070
|
}
|
|
8072
8071
|
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 '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
|
|
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 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=\"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))}.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
8073
|
}
|
|
8075
8074
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: XSModalComponent, decorators: [{
|
|
8076
8075
|
type: Component,
|
|
8077
8076
|
args: [{ selector: 'xs-modal', imports: [CommonModule, XSButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
8078
8077
|
'xs-modal-host': '',
|
|
8079
8078
|
'(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 '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
|
|
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 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=\"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))}.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
8080
|
}], ctorParameters: () => [], propDecorators: { dynamicContentPlaceholder: [{ type: i0.ViewChild, args: ['dynamicContentPlaceholder', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
|
|
8082
8081
|
|
|
8083
8082
|
class XSModalConfirmComponent {
|
|
@@ -9381,7 +9380,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImpo
|
|
|
9381
9380
|
}] }] });
|
|
9382
9381
|
|
|
9383
9382
|
class XSFormlyEntityPickerComponent extends XSFormlyBaseComponent {
|
|
9384
|
-
elementRef = inject(ElementRef);
|
|
9385
9383
|
modalService = inject(XSModalService);
|
|
9386
9384
|
searchSubject = new Subject();
|
|
9387
9385
|
valueChangesSub = new Subscription();
|
|
@@ -9394,9 +9392,6 @@ class XSFormlyEntityPickerComponent extends XSFormlyBaseComponent {
|
|
|
9394
9392
|
searching = signal(false, ...(ngDevMode ? [{ debugName: "searching" }] : []));
|
|
9395
9393
|
showDropdown = signal(false, ...(ngDevMode ? [{ debugName: "showDropdown" }] : []));
|
|
9396
9394
|
selectedItems = signal([], ...(ngDevMode ? [{ debugName: "selectedItems" }] : []));
|
|
9397
|
-
dropdownTop = 0;
|
|
9398
|
-
dropdownLeft = 0;
|
|
9399
|
-
dropdownWidth = 0;
|
|
9400
9395
|
get pickerProps() {
|
|
9401
9396
|
return this.props;
|
|
9402
9397
|
}
|
|
@@ -9446,21 +9441,10 @@ class XSFormlyEntityPickerComponent extends XSFormlyBaseComponent {
|
|
|
9446
9441
|
this.showDropdown.set(false);
|
|
9447
9442
|
return;
|
|
9448
9443
|
}
|
|
9449
|
-
this.calculateDropdownPosition();
|
|
9450
9444
|
this.showDropdown.set(true);
|
|
9451
9445
|
this.searching.set(true);
|
|
9452
9446
|
this.searchSubject.next(query);
|
|
9453
9447
|
}
|
|
9454
|
-
calculateDropdownPosition() {
|
|
9455
|
-
const host = this.elementRef.nativeElement;
|
|
9456
|
-
const input = host.querySelector('input');
|
|
9457
|
-
if (!input)
|
|
9458
|
-
return;
|
|
9459
|
-
const rect = input.getBoundingClientRect();
|
|
9460
|
-
this.dropdownTop = rect.bottom + 4;
|
|
9461
|
-
this.dropdownLeft = rect.left;
|
|
9462
|
-
this.dropdownWidth = rect.width;
|
|
9463
|
-
}
|
|
9464
9448
|
async doSearch(query) {
|
|
9465
9449
|
const onSearch = this.pickerProps.onSearch;
|
|
9466
9450
|
if (!onSearch)
|
|
@@ -9620,12 +9604,11 @@ class XSFormlyEntityPickerComponent extends XSFormlyBaseComponent {
|
|
|
9620
9604
|
onSearchFocus() {
|
|
9621
9605
|
if (this.searchQuery().trim() &&
|
|
9622
9606
|
this.searchResults().length > 0) {
|
|
9623
|
-
this.calculateDropdownPosition();
|
|
9624
9607
|
this.showDropdown.set(true);
|
|
9625
9608
|
}
|
|
9626
9609
|
}
|
|
9627
9610
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: XSFormlyEntityPickerComponent, deps: [{ token: XSTranslateService }], target: i0.ɵɵFactoryTarget.Component });
|
|
9628
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.33", type: XSFormlyEntityPickerComponent, isStandalone: true, selector: "xs-formly-entity-picker", usesInheritance: true, ngImport: i0, template: "<div [id]=\"'xs-formly-entity-picker-' + id\" [class]=\"wrapperClass\">\n @if (pickerProps.label) {\n <label class=\"formly-label\">\n {{ translateLabel(pickerProps.label) }}\n @if (infoText) {\n <xs-popover-info [text]=\"infoText\" />\n }\n </label>\n }\n\n <div class=\"flex flex-col gap-4\">\n <div class=\"relative\">\n <input\n type=\"text\"\n [ngModel]=\"searchQuery()\"\n (ngModelChange)=\"onSearchChange($event)\"\n (focus)=\"onSearchFocus()\"\n (blur)=\"onSearchBlur()\"\n [placeholder]=\"searchPlaceholder\"\n class=\"input !pr-11 !py-4 rounded-xl\"\n />\n <xs-icon\n icon=\"magnifying-glass\"\n class=\"absolute right-4 top-1/2 -translate-y-1/2 text-zinc-500 text-sm\"\n ></xs-icon>\n
|
|
9611
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.33", type: XSFormlyEntityPickerComponent, isStandalone: true, selector: "xs-formly-entity-picker", usesInheritance: true, ngImport: i0, template: "<div [id]=\"'xs-formly-entity-picker-' + id\" [class]=\"wrapperClass\">\n @if (pickerProps.label) {\n <label class=\"formly-label\">\n {{ translateLabel(pickerProps.label) }}\n @if (infoText) {\n <xs-popover-info [text]=\"infoText\" />\n }\n </label>\n }\n\n <div class=\"flex flex-col gap-4\">\n <div class=\"relative\">\n <input\n type=\"text\"\n [ngModel]=\"searchQuery()\"\n (ngModelChange)=\"onSearchChange($event)\"\n (focus)=\"onSearchFocus()\"\n (blur)=\"onSearchBlur()\"\n [placeholder]=\"searchPlaceholder\"\n class=\"input !pr-11 !py-4 rounded-xl\"\n />\n <xs-icon\n icon=\"magnifying-glass\"\n class=\"absolute right-4 top-1/2 -translate-y-1/2 text-zinc-500 text-sm\"\n ></xs-icon>\n\n @if (showDropdown()) {\n <div\n class=\"absolute left-0 right-0 top-full mt-1 z-[10002] rounded-xl bg-black shadow-xl max-h-48 overflow-y-auto\"\n >\n @if (searching()) {\n <div class=\"flex items-center justify-center py-6 bg-zinc-900/50 rounded-xl\">\n <div class=\"animate-spin size-5 border-2 border-zinc-600 border-t-white rounded-full\"></div>\n </div>\n } @else if (searchResults().length === 0) {\n <xs-empty-state\n [config]=\"getNoResultsConfig()\"\n />\n } @else {\n <div class=\"bg-zinc-900/50 rounded-xl\">\n <div class=\"flex flex-col\">\n @for (item of searchResults(); track item._id) {\n <button\n type=\"button\"\n class=\"flex items-center gap-3 w-full p-3 hover:bg-zinc-800/60 transition text-left\"\n (click)=\"selectResult(item)\"\n >\n <div class=\"size-9 shrink-0 rounded-lg bg-zinc-800 flex items-center justify-center overflow-hidden\">\n @if (item['image']) {\n <xs-image\n [item]=\"item\"\n [typeItem]=\"typeItem\"\n imageType=\"small\"\n size=\"sm\"\n customClass=\"size-9 object-cover\"\n ></xs-image>\n } @else {\n <xs-icon [icon]=\"iconFallback\" class=\"text-zinc-500 text-xs\"></xs-icon>\n }\n </div>\n <div class=\"flex-1 min-w-0\">\n <p class=\"text-sm font-medium text-zinc-200 truncate\">{{ item.name }}</p>\n @if (getSecondaryText(item)) {\n <p class=\"text-xs text-zinc-400 truncate\">{{ getSecondaryText(item) }}</p>\n }\n </div>\n <xs-icon icon=\"plus\" class=\"text-zinc-400 text-xs shrink-0\"></xs-icon>\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n @if (selectedItems().length > 0) {\n <div class=\"flex flex-col gap-2\">\n <p class=\"formly-label pt-1\">\n {{ t('FORM.ENTITY_PICKER.ITEM_COUNT') }} ({{ selectedItems().length }})\n </p>\n @for (item of selectedItems(); track item._id; let i = $index) {\n <div class=\"flex items-center gap-4 px-4 py-3.5 rounded-xl bg-zinc-900/50\">\n <div class=\"size-9 shrink-0 rounded-lg bg-zinc-800 flex items-center justify-center overflow-hidden\">\n @if (item['image']) {\n <xs-image\n [item]=\"item\"\n [typeItem]=\"typeItem\"\n imageType=\"small\"\n size=\"sm\"\n customClass=\"size-9 object-cover\"\n ></xs-image>\n } @else {\n <xs-icon [icon]=\"iconFallback\" class=\"text-zinc-500 text-xs\"></xs-icon>\n }\n </div>\n\n <div class=\"flex-1 min-w-0\">\n <p class=\"text-sm font-semibold text-zinc-200 truncate\">{{ item.name }}</p>\n @if (getSecondaryText(item)) {\n <p class=\"text-xs text-zinc-400 truncate\">{{ getSecondaryText(item) }}</p>\n }\n </div>\n\n <div class=\"flex items-center gap-1 shrink-0\">\n @if (showReorder) {\n <xs-button\n icon=\"chevron-up\"\n layout=\"iconOnlyMini\"\n variant=\"primary\"\n [title]=\"t('FORM.ENTITY_PICKER.MOVE_UP')\"\n [disabled]=\"i === 0\"\n (onClick)=\"moveItem(i, -1)\"\n />\n <xs-button\n icon=\"chevron-down\"\n layout=\"iconOnlyMini\"\n variant=\"primary\"\n [title]=\"t('FORM.ENTITY_PICKER.MOVE_DOWN')\"\n [disabled]=\"i === selectedItems().length - 1\"\n (onClick)=\"moveItem(i, 1)\"\n />\n }\n <button\n type=\"button\"\n class=\"flex items-center justify-center w-8 h-8 rounded-lg bg-red-600 text-white hover:opacity-70 transition shrink-0\"\n (click)=\"removeItem(i)\"\n [attr.aria-label]=\"t('FORM.ENTITY_PICKER.DELETE')\"\n >\n <xs-icon icon=\"trash\" class=\"text-xs\"></xs-icon>\n </button>\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n @if (errorMessage) {\n <p class=\"text-xs text-red-500 mt-2\">{{ errorMessage }}</p>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.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$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: XSIconComponent, selector: "xs-icon", inputs: ["icon", "size", "class"] }, { kind: "component", type: XSImageComponent, selector: "xs-image", inputs: ["config", "viewTransitionName", "src", "alt", "width", "height", "size", "rounded", "objectFit", "clickable", "item", "typeItem", "imageType", "fallbackSrc", "loading", "priority", "customClass", "generateAvatar"], outputs: ["onClick", "onLoad", "onError"] }, { 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"] }, { kind: "component", type: XSEmptyStateComponent, selector: "xs-empty-state", inputs: ["config", "regionAriaLabel"], outputs: ["actionClick"] }, { kind: "component", type: XSPopoverInfoComponent, selector: "xs-popover-info", inputs: ["text"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9629
9612
|
}
|
|
9630
9613
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: XSFormlyEntityPickerComponent, decorators: [{
|
|
9631
9614
|
type: Component,
|
|
@@ -9637,7 +9620,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImpo
|
|
|
9637
9620
|
XSButtonComponent,
|
|
9638
9621
|
XSEmptyStateComponent,
|
|
9639
9622
|
XSPopoverInfoComponent,
|
|
9640
|
-
], template: "<div [id]=\"'xs-formly-entity-picker-' + id\" [class]=\"wrapperClass\">\n @if (pickerProps.label) {\n <label class=\"formly-label\">\n {{ translateLabel(pickerProps.label) }}\n @if (infoText) {\n <xs-popover-info [text]=\"infoText\" />\n }\n </label>\n }\n\n <div class=\"flex flex-col gap-4\">\n <div class=\"relative\">\n <input\n type=\"text\"\n [ngModel]=\"searchQuery()\"\n (ngModelChange)=\"onSearchChange($event)\"\n (focus)=\"onSearchFocus()\"\n (blur)=\"onSearchBlur()\"\n [placeholder]=\"searchPlaceholder\"\n class=\"input !pr-11 !py-4 rounded-xl\"\n />\n <xs-icon\n icon=\"magnifying-glass\"\n class=\"absolute right-4 top-1/2 -translate-y-1/2 text-zinc-500 text-sm\"\n ></xs-icon>\n
|
|
9623
|
+
], template: "<div [id]=\"'xs-formly-entity-picker-' + id\" [class]=\"wrapperClass\">\n @if (pickerProps.label) {\n <label class=\"formly-label\">\n {{ translateLabel(pickerProps.label) }}\n @if (infoText) {\n <xs-popover-info [text]=\"infoText\" />\n }\n </label>\n }\n\n <div class=\"flex flex-col gap-4\">\n <div class=\"relative\">\n <input\n type=\"text\"\n [ngModel]=\"searchQuery()\"\n (ngModelChange)=\"onSearchChange($event)\"\n (focus)=\"onSearchFocus()\"\n (blur)=\"onSearchBlur()\"\n [placeholder]=\"searchPlaceholder\"\n class=\"input !pr-11 !py-4 rounded-xl\"\n />\n <xs-icon\n icon=\"magnifying-glass\"\n class=\"absolute right-4 top-1/2 -translate-y-1/2 text-zinc-500 text-sm\"\n ></xs-icon>\n\n @if (showDropdown()) {\n <div\n class=\"absolute left-0 right-0 top-full mt-1 z-[10002] rounded-xl bg-black shadow-xl max-h-48 overflow-y-auto\"\n >\n @if (searching()) {\n <div class=\"flex items-center justify-center py-6 bg-zinc-900/50 rounded-xl\">\n <div class=\"animate-spin size-5 border-2 border-zinc-600 border-t-white rounded-full\"></div>\n </div>\n } @else if (searchResults().length === 0) {\n <xs-empty-state\n [config]=\"getNoResultsConfig()\"\n />\n } @else {\n <div class=\"bg-zinc-900/50 rounded-xl\">\n <div class=\"flex flex-col\">\n @for (item of searchResults(); track item._id) {\n <button\n type=\"button\"\n class=\"flex items-center gap-3 w-full p-3 hover:bg-zinc-800/60 transition text-left\"\n (click)=\"selectResult(item)\"\n >\n <div class=\"size-9 shrink-0 rounded-lg bg-zinc-800 flex items-center justify-center overflow-hidden\">\n @if (item['image']) {\n <xs-image\n [item]=\"item\"\n [typeItem]=\"typeItem\"\n imageType=\"small\"\n size=\"sm\"\n customClass=\"size-9 object-cover\"\n ></xs-image>\n } @else {\n <xs-icon [icon]=\"iconFallback\" class=\"text-zinc-500 text-xs\"></xs-icon>\n }\n </div>\n <div class=\"flex-1 min-w-0\">\n <p class=\"text-sm font-medium text-zinc-200 truncate\">{{ item.name }}</p>\n @if (getSecondaryText(item)) {\n <p class=\"text-xs text-zinc-400 truncate\">{{ getSecondaryText(item) }}</p>\n }\n </div>\n <xs-icon icon=\"plus\" class=\"text-zinc-400 text-xs shrink-0\"></xs-icon>\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n @if (selectedItems().length > 0) {\n <div class=\"flex flex-col gap-2\">\n <p class=\"formly-label pt-1\">\n {{ t('FORM.ENTITY_PICKER.ITEM_COUNT') }} ({{ selectedItems().length }})\n </p>\n @for (item of selectedItems(); track item._id; let i = $index) {\n <div class=\"flex items-center gap-4 px-4 py-3.5 rounded-xl bg-zinc-900/50\">\n <div class=\"size-9 shrink-0 rounded-lg bg-zinc-800 flex items-center justify-center overflow-hidden\">\n @if (item['image']) {\n <xs-image\n [item]=\"item\"\n [typeItem]=\"typeItem\"\n imageType=\"small\"\n size=\"sm\"\n customClass=\"size-9 object-cover\"\n ></xs-image>\n } @else {\n <xs-icon [icon]=\"iconFallback\" class=\"text-zinc-500 text-xs\"></xs-icon>\n }\n </div>\n\n <div class=\"flex-1 min-w-0\">\n <p class=\"text-sm font-semibold text-zinc-200 truncate\">{{ item.name }}</p>\n @if (getSecondaryText(item)) {\n <p class=\"text-xs text-zinc-400 truncate\">{{ getSecondaryText(item) }}</p>\n }\n </div>\n\n <div class=\"flex items-center gap-1 shrink-0\">\n @if (showReorder) {\n <xs-button\n icon=\"chevron-up\"\n layout=\"iconOnlyMini\"\n variant=\"primary\"\n [title]=\"t('FORM.ENTITY_PICKER.MOVE_UP')\"\n [disabled]=\"i === 0\"\n (onClick)=\"moveItem(i, -1)\"\n />\n <xs-button\n icon=\"chevron-down\"\n layout=\"iconOnlyMini\"\n variant=\"primary\"\n [title]=\"t('FORM.ENTITY_PICKER.MOVE_DOWN')\"\n [disabled]=\"i === selectedItems().length - 1\"\n (onClick)=\"moveItem(i, 1)\"\n />\n }\n <button\n type=\"button\"\n class=\"flex items-center justify-center w-8 h-8 rounded-lg bg-red-600 text-white hover:opacity-70 transition shrink-0\"\n (click)=\"removeItem(i)\"\n [attr.aria-label]=\"t('FORM.ENTITY_PICKER.DELETE')\"\n >\n <xs-icon icon=\"trash\" class=\"text-xs\"></xs-icon>\n </button>\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n @if (errorMessage) {\n <p class=\"text-xs text-red-500 mt-2\">{{ errorMessage }}</p>\n }\n</div>\n" }]
|
|
9641
9624
|
}], ctorParameters: () => [{ type: XSTranslateService }] });
|
|
9642
9625
|
|
|
9643
9626
|
const iconNameForType = (name) => {
|
|
@@ -14457,7 +14440,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImpo
|
|
|
14457
14440
|
XSButtonComponent,
|
|
14458
14441
|
XSIconComponent,
|
|
14459
14442
|
XSFormlyComponent,
|
|
14460
|
-
XSSpinnerComponent,
|
|
14461
14443
|
XSEmptyStateComponent,
|
|
14462
14444
|
XSTabsComponent,
|
|
14463
14445
|
XSImportMediaCardComponent,
|
|
@@ -16409,7 +16391,7 @@ class XSSelectComponent {
|
|
|
16409
16391
|
}
|
|
16410
16392
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: XSSelectComponent, decorators: [{
|
|
16411
16393
|
type: Component,
|
|
16412
|
-
args: [{ selector: 'xs-select', standalone: true, imports: [CommonModule
|
|
16394
|
+
args: [{ selector: 'xs-select', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
16413
16395
|
'(document:click)': 'onDocumentClick($event)',
|
|
16414
16396
|
}, template: "<div class=\"relative\">\n <input\n type=\"text\"\n [value]=\"displayText()\"\n readonly\n (click)=\"toggle()\"\n (keydown)=\"onTriggerKeydown($event)\"\n [class]=\"inputClass()\"\n [class.text-zinc-400]=\"!selectedOption()\"\n [attr.placeholder]=\"placeholder()\"\n role=\"combobox\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'listbox'\"\n tabindex=\"0\"\n />\n\n <div\n class=\"pointer-events-none absolute inset-y-0 right-0 flex items-center\"\n [class.pr-4]=\"size() === 'md'\"\n [class.pr-3]=\"size() === 'sm'\"\n >\n <svg\n class=\"text-white transition-transform duration-200\"\n [class.w-4.h-4]=\"size() === 'md'\"\n [class.w-3.h-3]=\"size() === 'sm'\"\n [class.rotate-180]=\"isOpen()\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M19 9l-7 7-7-7\"\n />\n </svg>\n </div>\n\n @if (isOpen()) {\n <div\n class=\"fixed z-[10002] rounded-xl shadow-lg min-h-[100px] bg-black overflow-hidden\"\n [style.top.px]=\"dropdownTop\"\n [style.left.px]=\"dropdownLeft\"\n [style.width.px]=\"dropdownWidth\"\n >\n <div class=\"bg-zinc-900/50 rounded-xl\">\n <ul class=\"max-h-48 overflow-y-auto overscroll-contain\" role=\"listbox\">\n @for (option of options(); track option.id) {\n <li\n role=\"option\"\n [attr.aria-selected]=\"option.id === value()\"\n (click)=\"selectOption(option)\"\n (keydown)=\"onOptionKeydown($event, option)\"\n tabindex=\"0\"\n [class]=\"optionClass()\"\n [class.bg-white/5]=\"option.id === value()\"\n >\n <span class=\"flex-1 min-w-0 truncate text-white\">{{ option.name }}</span>\n @if (option.id === value()) {\n <svg\n class=\"text-white shrink-0\"\n [class.w-4.h-4]=\"size() === 'md'\"\n [class.w-3.h-3]=\"size() === 'sm'\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M5 13l4 4L19 7\"\n />\n </svg>\n }\n </li>\n }\n </ul>\n </div>\n </div>\n }\n</div>\n" }]
|
|
16415
16397
|
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
@@ -23142,7 +23124,7 @@ const LIB_STORIES = [
|
|
|
23142
23124
|
() => import('./xsmusices-ui-xs-empty-state.xsstory-CCOJ4b9_.mjs').then((m) => m.story),
|
|
23143
23125
|
() => import('./xsmusices-ui-xs-icon.xsstory-asFaHy5H.mjs').then((m) => m.story),
|
|
23144
23126
|
() => import('./xsmusices-ui-xs-image.xsstory-BaeUg3Zp.mjs').then((m) => m.story),
|
|
23145
|
-
() => import('./xsmusices-ui-xs-modal.xsstory-
|
|
23127
|
+
() => import('./xsmusices-ui-xs-modal.xsstory-DJxKOKsQ.mjs').then((m) => m.story),
|
|
23146
23128
|
() => import('./xsmusices-ui-xs-navbar.xsstory-BDW0nLAH.mjs').then((m) => m.story),
|
|
23147
23129
|
() => import('./xsmusices-ui-xs-navbar-sidebar.xsstory-DHmPSARx.mjs').then((m) => m.story),
|
|
23148
23130
|
() => import('./xsmusices-ui-stats-card.xsstory-PWTUDysc.mjs').then((m) => m.story),
|