@govbr-ds/webcomponents 2.0.0-next.61 → 2.0.0-next.62
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/dist/cjs/br-modal.cjs.entry.js +119 -15
- package/dist/cjs/br-modal.entry.cjs.js.map +1 -1
- package/dist/cjs/br-scrim.cjs.entry.js +132 -38
- package/dist/cjs/br-scrim.entry.cjs.js.map +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/webcomponents.cjs.js +1 -1
- package/dist/collection/components/modal/modal.js +152 -37
- package/dist/collection/components/modal/modal.js.map +1 -1
- package/dist/collection/components/scrim/scrim.js +132 -38
- package/dist/collection/components/scrim/scrim.js.map +1 -1
- package/dist/collection/pages/components/modal/index.js +1 -53
- package/dist/components/br-modal.js +123 -26
- package/dist/components/br-modal.js.map +1 -1
- package/dist/components/br-scrim.js +125 -44
- package/dist/components/br-scrim.js.map +1 -1
- package/dist/esm/br-modal.entry.js +119 -15
- package/dist/esm/br-modal.entry.js.map +1 -1
- package/dist/esm/br-scrim.entry.js +132 -38
- package/dist/esm/br-scrim.entry.js.map +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/webcomponents.js +1 -1
- package/dist/hydrate/index.js +252 -55
- package/dist/hydrate/index.mjs +252 -55
- package/dist/types/components/modal/modal.d.ts +46 -4
- package/dist/types/components/scrim/scrim.d.ts +39 -1
- package/dist/types/components.d.ts +11 -11
- package/dist/webcomponents/br-modal.entry.esm.js.map +1 -1
- package/dist/webcomponents/br-scrim.entry.esm.js.map +1 -1
- package/dist/webcomponents/{p-e7b38c63.entry.js → p-216dc111.entry.js} +126 -45
- package/dist/webcomponents/p-216dc111.entry.js.map +1 -0
- package/dist/webcomponents/{p-28dba962.entry.js → p-463b06a4.entry.js} +129 -33
- package/dist/webcomponents/p-463b06a4.entry.js.map +1 -0
- package/dist/webcomponents/webcomponents.esm.js +1 -1
- package/package.json +1 -1
- package/dist/custom-elements.json +0 -18276
- package/dist/webcomponents/p-28dba962.entry.js.map +0 -1
- package/dist/webcomponents/p-e7b38c63.entry.js.map +0 -1
- package/dist/webcomponents.html-custom-data.json +0 -1214
|
@@ -25,32 +25,132 @@ export class Modal {
|
|
|
25
25
|
this.customId = Helpers.generateUniqueId('modal');
|
|
26
26
|
/** Controla a visibilidade do modal. */
|
|
27
27
|
this.show = false;
|
|
28
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Define o comportamento de fechamento do modal.
|
|
30
|
+
*
|
|
31
|
+
* - `true`: O modal fecha automaticamente ao clicar no botão fechar.
|
|
32
|
+
* - `false`: O modal emite `brModalBeforeClose` mas não fecha, permitindo a implementação de lógica customizada (validação, confirmação, etc.) antes do fechamento. O desenvolvedor deve
|
|
33
|
+
* controlar manualmente o fechamento.
|
|
34
|
+
*/
|
|
29
35
|
this.autoClose = false;
|
|
30
36
|
/**
|
|
31
37
|
* Define o tamanho (largura) do modal.
|
|
32
38
|
*/
|
|
33
39
|
this.size = 'medium';
|
|
34
|
-
/** Se `true`, exibe um fundo escurecido (scrim) atrás do modal. */
|
|
35
|
-
this.scrim = false;
|
|
36
40
|
/** Se `true`, habilita a rolagem interna do conteúdo do modal. */
|
|
37
41
|
this.scrollable = false;
|
|
38
42
|
/**
|
|
39
43
|
* Define o alinhamento do conteúdo do rodapé (slot="footer").
|
|
40
44
|
*/
|
|
41
45
|
this.alignFooter = 'center';
|
|
46
|
+
this.isOpeningParentScrim = false;
|
|
47
|
+
/**
|
|
48
|
+
* Handler para evento brScrimOpen do parent scrim
|
|
49
|
+
* Quando scrim abre programaticamente, a modal deve abrir também
|
|
50
|
+
*/
|
|
51
|
+
this.handleParentScrimOpen = () => {
|
|
52
|
+
const parentScrim = this.el.closest('br-scrim');
|
|
53
|
+
if (parentScrim === null)
|
|
54
|
+
return;
|
|
55
|
+
if (!this.show) {
|
|
56
|
+
this.show = true;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Handler para evento brScrimClose do parent scrim
|
|
61
|
+
* Se autoClose=true, fecha a modal junto com o scrim
|
|
62
|
+
* Se autoClose=false, não faz nada (modal permanece aberta)
|
|
63
|
+
*/
|
|
64
|
+
this.handleParentScrimClose = () => {
|
|
65
|
+
const parentScrim = this.el.closest('br-scrim');
|
|
66
|
+
if (parentScrim === null)
|
|
67
|
+
return;
|
|
68
|
+
if (this.autoClose && this.show) {
|
|
69
|
+
this.show = false;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
42
72
|
this.handleClose = () => {
|
|
43
|
-
this.
|
|
73
|
+
this.brModalBeforeClose.emit();
|
|
44
74
|
if (this.autoClose) {
|
|
45
75
|
this.show = false;
|
|
46
|
-
// Se o modal está dentro de um br-scrim, fecha o scrim também
|
|
47
|
-
const parentScrim = this.el.closest('br-scrim');
|
|
48
|
-
if (parentScrim) {
|
|
49
|
-
parentScrim.close();
|
|
50
|
-
}
|
|
51
76
|
}
|
|
52
77
|
};
|
|
53
78
|
}
|
|
79
|
+
handleShowChange(newValue, oldValue) {
|
|
80
|
+
if (newValue) {
|
|
81
|
+
this.brModalOpen.emit();
|
|
82
|
+
this.openParentScrim();
|
|
83
|
+
}
|
|
84
|
+
else if (oldValue === true) {
|
|
85
|
+
this.brModalClose.emit();
|
|
86
|
+
this.closeParentScrim();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
closeParentScrim() {
|
|
90
|
+
const parentScrim = this.el.closest('br-scrim');
|
|
91
|
+
if (parentScrim && typeof parentScrim.close === 'function') {
|
|
92
|
+
parentScrim.close();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
componentWillLoad() {
|
|
96
|
+
if (!this.show) {
|
|
97
|
+
const parentScrim = this.el.closest('br-scrim');
|
|
98
|
+
if (parentScrim !== null && parentScrim.isOpen) {
|
|
99
|
+
this.show = true;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
componentDidLoad() {
|
|
104
|
+
this.listenToParentScrimEvents();
|
|
105
|
+
if (this.show) {
|
|
106
|
+
this.openParentScrim();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
disconnectedCallback() {
|
|
110
|
+
this.isOpeningParentScrim = false;
|
|
111
|
+
this.removeParentScrimEventListeners();
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Adiciona listeners para eventos do parent scrim
|
|
115
|
+
*/
|
|
116
|
+
listenToParentScrimEvents() {
|
|
117
|
+
const parentScrim = this.el.closest('br-scrim');
|
|
118
|
+
if (parentScrim !== null) {
|
|
119
|
+
parentScrim.addEventListener('brScrimOpen', this.handleParentScrimOpen);
|
|
120
|
+
parentScrim.addEventListener('brScrimClose', this.handleParentScrimClose);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Remove listeners de eventos do parent scrim
|
|
125
|
+
*/
|
|
126
|
+
removeParentScrimEventListeners() {
|
|
127
|
+
const parentScrim = this.el.closest('br-scrim');
|
|
128
|
+
if (parentScrim !== null) {
|
|
129
|
+
parentScrim.removeEventListener('brScrimOpen', this.handleParentScrimOpen);
|
|
130
|
+
parentScrim.removeEventListener('brScrimClose', this.handleParentScrimClose);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
openParentScrim() {
|
|
134
|
+
if (this.isOpeningParentScrim)
|
|
135
|
+
return;
|
|
136
|
+
const parentScrim = this.el.closest('br-scrim');
|
|
137
|
+
if (parentScrim && !parentScrim.isOpen) {
|
|
138
|
+
this.isOpeningParentScrim = true;
|
|
139
|
+
Promise.resolve()
|
|
140
|
+
.then(() => {
|
|
141
|
+
try {
|
|
142
|
+
return parentScrim.open();
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
console.warn('br-modal: Erro ao abrir scrim pai:', error);
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
.finally(() => {
|
|
150
|
+
this.isOpeningParentScrim = false;
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
54
154
|
get titleId() {
|
|
55
155
|
return `${this.customId}-title`;
|
|
56
156
|
}
|
|
@@ -70,6 +170,7 @@ export class Modal {
|
|
|
70
170
|
open() {
|
|
71
171
|
return __awaiter(this, void 0, void 0, function* () {
|
|
72
172
|
this.show = true;
|
|
173
|
+
this.openParentScrim();
|
|
73
174
|
});
|
|
74
175
|
}
|
|
75
176
|
/**
|
|
@@ -77,19 +178,17 @@ export class Modal {
|
|
|
77
178
|
*/
|
|
78
179
|
close() {
|
|
79
180
|
return __awaiter(this, void 0, void 0, function* () {
|
|
80
|
-
this.
|
|
81
|
-
|
|
82
|
-
const parentScrim = this.el.closest('br-scrim');
|
|
83
|
-
if (parentScrim) {
|
|
84
|
-
parentScrim.close();
|
|
181
|
+
if (!this.autoClose) {
|
|
182
|
+
return;
|
|
85
183
|
}
|
|
184
|
+
this.show = false;
|
|
86
185
|
});
|
|
87
186
|
}
|
|
88
187
|
render() {
|
|
89
188
|
if (!this.show) {
|
|
90
189
|
return null;
|
|
91
190
|
}
|
|
92
|
-
return (h(Host, null, h("div", { class: this.getCssClassMap(), role: "dialog", "aria-modal": "true", "aria-labelledby": this.titleId, "aria-describedby": this.contentId }, h("div", { class: "br-modal-header" }, h("div", { class: "modal-title", id: this.titleId }, h("slot", { name: "header" }, this.titleText)), h("slot", { name: "close-button" }, h("br-button", { class: "close", shape: "circle", density: "small", "aria-label": "Fechar", onClick: this.handleClose }, h("br-icon", { "icon-name": "fa-solid:times" })))), h("div", { id: this.contentId, class: "br-modal-body" }, h("slot", null)), h("div", { class: `br-modal-footer ${this.alignFooter ? `justify-content-${this.alignFooter}` : ''}` }, h("slot", { name: "footer" })))));
|
|
191
|
+
return (h(Host, null, h("div", { class: this.getCssClassMap(), role: "dialog", "aria-modal": "true", "aria-labelledby": this.titleId, "aria-describedby": this.contentId }, h("div", { class: "br-modal-header" }, h("div", { class: "modal-title", id: this.titleId }, h("slot", { name: "header" }, this.titleText)), h("slot", { name: "close-button" }, h("br-button", { class: "close", shape: "circle", density: "small", "aria-label": "Fechar", onClick: this.handleClose }, h("br-icon", { "icon-name": "fa-solid:times" })))), h("div", { id: this.contentId, class: "br-modal-body" }, h("slot", null)), h("div", { class: `br-modal-footer ${this.alignFooter !== undefined ? `justify-content-${this.alignFooter}` : ''}` }, h("slot", { name: "footer" })))));
|
|
93
192
|
}
|
|
94
193
|
static get is() { return "br-modal"; }
|
|
95
194
|
static get encapsulation() { return "shadow"; }
|
|
@@ -177,7 +276,7 @@ export class Modal {
|
|
|
177
276
|
"optional": false,
|
|
178
277
|
"docs": {
|
|
179
278
|
"tags": [],
|
|
180
|
-
"text": "
|
|
279
|
+
"text": "Define o comportamento de fechamento do modal.\n\n- `true`: O modal fecha automaticamente ao clicar no bot\u00E3o fechar.\n- `false`: O modal emite `brModalBeforeClose` mas n\u00E3o fecha, permitindo a implementa\u00E7\u00E3o de l\u00F3gica customizada (valida\u00E7\u00E3o, confirma\u00E7\u00E3o, etc.) antes do fechamento. O desenvolvedor deve\n controlar manualmente o fechamento."
|
|
181
280
|
},
|
|
182
281
|
"getter": false,
|
|
183
282
|
"setter": false,
|
|
@@ -224,26 +323,6 @@ export class Modal {
|
|
|
224
323
|
"attribute": "size",
|
|
225
324
|
"defaultValue": "'medium'"
|
|
226
325
|
},
|
|
227
|
-
"scrim": {
|
|
228
|
-
"type": "boolean",
|
|
229
|
-
"mutable": false,
|
|
230
|
-
"complexType": {
|
|
231
|
-
"original": "false",
|
|
232
|
-
"resolved": "boolean",
|
|
233
|
-
"references": {}
|
|
234
|
-
},
|
|
235
|
-
"required": false,
|
|
236
|
-
"optional": false,
|
|
237
|
-
"docs": {
|
|
238
|
-
"tags": [],
|
|
239
|
-
"text": "Se `true`, exibe um fundo escurecido (scrim) atr\u00E1s do modal."
|
|
240
|
-
},
|
|
241
|
-
"getter": false,
|
|
242
|
-
"setter": false,
|
|
243
|
-
"reflect": true,
|
|
244
|
-
"attribute": "scrim",
|
|
245
|
-
"defaultValue": "false"
|
|
246
|
-
},
|
|
247
326
|
"scrollable": {
|
|
248
327
|
"type": "boolean",
|
|
249
328
|
"mutable": false,
|
|
@@ -288,6 +367,21 @@ export class Modal {
|
|
|
288
367
|
}
|
|
289
368
|
static get events() {
|
|
290
369
|
return [{
|
|
370
|
+
"method": "brModalOpen",
|
|
371
|
+
"name": "brModalOpen",
|
|
372
|
+
"bubbles": true,
|
|
373
|
+
"cancelable": true,
|
|
374
|
+
"composed": true,
|
|
375
|
+
"docs": {
|
|
376
|
+
"tags": [],
|
|
377
|
+
"text": "Evento emitido quando o modal \u00E9 aberto (quando `show` muda de `false` para `true`)."
|
|
378
|
+
},
|
|
379
|
+
"complexType": {
|
|
380
|
+
"original": "void",
|
|
381
|
+
"resolved": "void",
|
|
382
|
+
"references": {}
|
|
383
|
+
}
|
|
384
|
+
}, {
|
|
291
385
|
"method": "brModalClose",
|
|
292
386
|
"name": "brModalClose",
|
|
293
387
|
"bubbles": true,
|
|
@@ -295,7 +389,22 @@ export class Modal {
|
|
|
295
389
|
"composed": true,
|
|
296
390
|
"docs": {
|
|
297
391
|
"tags": [],
|
|
298
|
-
"text": "Evento emitido
|
|
392
|
+
"text": "Evento emitido ap\u00F3s o modal ser fechado (quando `show` muda de `true` para `false`)."
|
|
393
|
+
},
|
|
394
|
+
"complexType": {
|
|
395
|
+
"original": "void",
|
|
396
|
+
"resolved": "void",
|
|
397
|
+
"references": {}
|
|
398
|
+
}
|
|
399
|
+
}, {
|
|
400
|
+
"method": "brModalBeforeClose",
|
|
401
|
+
"name": "brModalBeforeClose",
|
|
402
|
+
"bubbles": true,
|
|
403
|
+
"cancelable": true,
|
|
404
|
+
"composed": true,
|
|
405
|
+
"docs": {
|
|
406
|
+
"tags": [],
|
|
407
|
+
"text": "Evento emitido antes do fechamento do modal (quando o bot\u00E3o X \u00E9 clicado).\nSe autoClose est\u00E1 desativado, o desenvolvedor deve fechar manualmente o modal ap\u00F3s este evento.\nSe autoClose est\u00E1 ativado, o modal fecha automaticamente ap\u00F3s este evento."
|
|
299
408
|
},
|
|
300
409
|
"complexType": {
|
|
301
410
|
"original": "void",
|
|
@@ -343,6 +452,12 @@ export class Modal {
|
|
|
343
452
|
};
|
|
344
453
|
}
|
|
345
454
|
static get elementRef() { return "el"; }
|
|
455
|
+
static get watchers() {
|
|
456
|
+
return [{
|
|
457
|
+
"propName": "show",
|
|
458
|
+
"methodName": "handleShowChange"
|
|
459
|
+
}];
|
|
460
|
+
}
|
|
346
461
|
static get attachInternalsMemberName() { return "elementInternals"; }
|
|
347
462
|
}
|
|
348
463
|
//# sourceMappingURL=modal.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modal.js","sourceRoot":"","sources":["../../../../../../packages/webcomponents/src/components/modal/modal.tsx"],"names":[],"mappings":"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","sourcesContent":["import { AttachInternals, Component, Element, Event, EventEmitter, h, Host, Method, Prop } from '@stencil/core'\n\nimport Helpers from '../../utils/helpers'\nimport { CssClassMap } from '../../utils/interfaces'\n\n/**\n * ## Design System\n *\n * Para a documentação completa de design, incluindo diretrizes de uso, acessibilidade e exemplos visuais, consulte o [Design System do GovBR](https://www.gov.br/ds/components/modal?tab=designer).\n *\n * @slot header - Cabeçalho do modal. Se não for usado, o `title-text` será exibido.\n * @slot default - Corpo do modal.\n * @slot footer - Rodapé do modal.\n * @slot close-button - Botão de fechar customizado. Se não for usado, o botão padrão será exibido.\n *\n */\n@Component({\n tag: 'br-modal',\n styleUrl: 'modal.scss',\n shadow: true,\n formAssociated: true,\n})\nexport class Modal {\n /** Referência ao elemento host do componente. */\n @Element() el: HTMLBrModalElement\n\n @AttachInternals() elementInternals: ElementInternals\n\n /**\n * Identificador único.\n * Caso não seja fornecido, um ID gerado automaticamente será usado.\n */\n @Prop({ reflect: true }) readonly customId: string = Helpers.generateUniqueId('modal')\n\n /** O texto do título a ser exibido no cabeçalho do modal. Usado quando o slot `header` não é fornecido. */\n @Prop() readonly titleText: string\n\n /** Controla a visibilidade do modal. */\n @Prop({ reflect: true, mutable: true }) show = false\n\n /** Se `true`, o modal se fechará automaticamente ao clicar no botão de fechar ou pressionar a tecla 'Escape'. */\n @Prop({ reflect: true }) autoClose = false\n\n /** Seletor CSS para o elemento que deve receber foco quando o modal é aberto. */\n @Prop() readonly initialFocusSelector: string\n\n /**\n * Define o tamanho (largura) do modal.\n */\n @Prop({ reflect: true }) readonly size: 'xsmall' | 'small' | 'medium' | 'large' | 'auto' = 'medium'\n\n /** Se `true`, exibe um fundo escurecido (scrim) atrás do modal. */\n @Prop({ reflect: true }) readonly scrim = false\n\n /** Se `true`, habilita a rolagem interna do conteúdo do modal. */\n @Prop({ reflect: true }) readonly scrollable = false\n\n /**\n * Define o alinhamento do conteúdo do rodapé (slot=\"footer\").\n */\n @Prop({ reflect: true }) readonly alignFooter: 'start' | 'end' | 'center' = 'center'\n\n /** Evento emitido quando o modal solicita ser fechado (pelo botão 'x', tecla 'Escape' ou clique no scrim). */\n @Event() brModalClose: EventEmitter<void>\n\n private get titleId() {\n return `${this.customId}-title`\n }\n\n private get contentId() {\n return `${this.customId}-content`\n }\n\n private getCssClassMap(): CssClassMap {\n return {\n 'br-modal': true,\n [this.size]: true,\n scrollable: this.scrollable,\n }\n }\n\n private handleClose = () => {\n this.brModalClose.emit()\n if (this.autoClose) {\n this.show = false\n\n // Se o modal está dentro de um br-scrim, fecha o scrim também\n const parentScrim = this.el.closest('br-scrim')\n if (parentScrim) {\n parentScrim.close()\n }\n }\n }\n\n /**\n * Método público para abrir o modal\n */\n @Method()\n async open() {\n this.show = true\n }\n\n /**\n * Método público para fechar o modal\n */\n @Method()\n async close() {\n this.show = false\n\n // Se o modal está dentro de um br-scrim, fecha o scrim também\n const parentScrim = this.el.closest('br-scrim')\n if (parentScrim) {\n parentScrim.close()\n }\n }\n\n render() {\n if (!this.show) {\n return null\n }\n\n return (\n <Host>\n <div\n class={this.getCssClassMap()}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={this.titleId}\n aria-describedby={this.contentId}\n >\n <div class=\"br-modal-header\">\n <div class=\"modal-title\" id={this.titleId}>\n <slot name=\"header\">{this.titleText}</slot>\n </div>\n <slot name=\"close-button\">\n <br-button class=\"close\" shape=\"circle\" density=\"small\" aria-label=\"Fechar\" onClick={this.handleClose}>\n <br-icon icon-name=\"fa-solid:times\"></br-icon>\n </br-button>\n </slot>\n </div>\n <div id={this.contentId} class=\"br-modal-body\">\n <slot></slot>\n </div>\n <div class={`br-modal-footer ${this.alignFooter ? `justify-content-${this.alignFooter}` : ''}`}>\n <slot name=\"footer\"></slot>\n </div>\n </div>\n </Host>\n )\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"modal.js","sourceRoot":"","sources":["../../../../../../packages/webcomponents/src/components/modal/modal.tsx"],"names":[],"mappings":"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","sourcesContent":["import { AttachInternals, Component, Element, Event, EventEmitter, h, Host, Method, Prop, Watch } from '@stencil/core'\n\nimport Helpers from '../../utils/helpers'\nimport { CssClassMap } from '../../utils/interfaces'\n\n/**\n * ## Design System\n *\n * Para a documentação completa de design, incluindo diretrizes de uso, acessibilidade e exemplos visuais, consulte o [Design System do GovBR](https://www.gov.br/ds/components/modal?tab=designer).\n *\n * @slot header - Cabeçalho do modal. Se não for usado, o `title-text` será exibido.\n * @slot default - Corpo do modal.\n * @slot footer - Rodapé do modal.\n * @slot close-button - Botão de fechar customizado. Se não for usado, o botão padrão será exibido.\n *\n */\n@Component({\n tag: 'br-modal',\n styleUrl: 'modal.scss',\n shadow: true,\n formAssociated: true,\n})\nexport class Modal {\n /** Referência ao elemento host do componente. */\n @Element() el: HTMLBrModalElement\n\n @AttachInternals() elementInternals: ElementInternals\n\n /**\n * Identificador único.\n * Caso não seja fornecido, um ID gerado automaticamente será usado.\n */\n @Prop({ reflect: true }) readonly customId: string = Helpers.generateUniqueId('modal')\n\n /** O texto do título a ser exibido no cabeçalho do modal. Usado quando o slot `header` não é fornecido. */\n @Prop() readonly titleText: string\n\n /** Controla a visibilidade do modal. */\n @Prop({ reflect: true, mutable: true }) show = false\n\n /**\n * Define o comportamento de fechamento do modal.\n *\n * - `true`: O modal fecha automaticamente ao clicar no botão fechar.\n * - `false`: O modal emite `brModalBeforeClose` mas não fecha, permitindo a implementação de lógica customizada (validação, confirmação, etc.) antes do fechamento. O desenvolvedor deve\n * controlar manualmente o fechamento.\n */\n @Prop({ reflect: true }) autoClose = false\n\n /** Seletor CSS para o elemento que deve receber foco quando o modal é aberto. */\n @Prop() readonly initialFocusSelector: string\n\n /**\n * Define o tamanho (largura) do modal.\n */\n @Prop({ reflect: true }) readonly size: 'xsmall' | 'small' | 'medium' | 'large' | 'auto' = 'medium'\n\n /** Se `true`, habilita a rolagem interna do conteúdo do modal. */\n @Prop({ reflect: true }) readonly scrollable = false\n\n /**\n * Define o alinhamento do conteúdo do rodapé (slot=\"footer\").\n */\n @Prop({ reflect: true }) readonly alignFooter: 'start' | 'end' | 'center' = 'center'\n\n private isOpeningParentScrim = false\n\n /**\n * Evento emitido quando o modal é aberto (quando `show` muda de `false` para `true`).\n */\n @Event() brModalOpen: EventEmitter<void>\n\n /**\n * Evento emitido após o modal ser fechado (quando `show` muda de `true` para `false`).\n */\n @Event() brModalClose: EventEmitter<void>\n\n /**\n * Evento emitido antes do fechamento do modal (quando o botão X é clicado).\n * Se autoClose está desativado, o desenvolvedor deve fechar manualmente o modal após este evento.\n * Se autoClose está ativado, o modal fecha automaticamente após este evento.\n */\n @Event() brModalBeforeClose: EventEmitter<void>\n\n @Watch('show')\n handleShowChange(newValue: boolean, oldValue: boolean) {\n if (newValue) {\n this.brModalOpen.emit()\n this.openParentScrim()\n } else if (oldValue === true) {\n this.brModalClose.emit()\n this.closeParentScrim()\n }\n }\n\n private closeParentScrim() {\n const parentScrim = this.el.closest('br-scrim')\n if (parentScrim && typeof parentScrim.close === 'function') {\n parentScrim.close()\n }\n }\n\n componentWillLoad() {\n if (!this.show) {\n const parentScrim = this.el.closest('br-scrim')\n if (parentScrim !== null && parentScrim.isOpen) {\n this.show = true\n }\n }\n }\n\n componentDidLoad() {\n this.listenToParentScrimEvents()\n\n if (this.show) {\n this.openParentScrim()\n }\n }\n\n disconnectedCallback() {\n this.isOpeningParentScrim = false\n this.removeParentScrimEventListeners()\n }\n\n /**\n * Adiciona listeners para eventos do parent scrim\n */\n private listenToParentScrimEvents() {\n const parentScrim = this.el.closest('br-scrim')\n if (parentScrim !== null) {\n parentScrim.addEventListener('brScrimOpen', this.handleParentScrimOpen)\n parentScrim.addEventListener('brScrimClose', this.handleParentScrimClose)\n }\n }\n\n /**\n * Remove listeners de eventos do parent scrim\n */\n private removeParentScrimEventListeners() {\n const parentScrim = this.el.closest('br-scrim')\n if (parentScrim !== null) {\n parentScrim.removeEventListener('brScrimOpen', this.handleParentScrimOpen)\n parentScrim.removeEventListener('brScrimClose', this.handleParentScrimClose)\n }\n }\n\n /**\n * Handler para evento brScrimOpen do parent scrim\n * Quando scrim abre programaticamente, a modal deve abrir também\n */\n private handleParentScrimOpen = () => {\n const parentScrim = this.el.closest('br-scrim')\n if (parentScrim === null) return\n\n if (!this.show) {\n this.show = true\n }\n }\n\n /**\n * Handler para evento brScrimClose do parent scrim\n * Se autoClose=true, fecha a modal junto com o scrim\n * Se autoClose=false, não faz nada (modal permanece aberta)\n */\n private handleParentScrimClose = () => {\n const parentScrim = this.el.closest('br-scrim')\n if (parentScrim === null) return\n\n if (this.autoClose && this.show) {\n this.show = false\n }\n }\n\n private openParentScrim() {\n if (this.isOpeningParentScrim) return\n\n const parentScrim = this.el.closest('br-scrim')\n if (parentScrim && !parentScrim.isOpen) {\n this.isOpeningParentScrim = true\n\n Promise.resolve()\n .then(() => {\n try {\n return parentScrim.open()\n } catch (error) {\n console.warn('br-modal: Erro ao abrir scrim pai:', error)\n throw error\n }\n })\n .finally(() => {\n this.isOpeningParentScrim = false\n })\n }\n }\n\n private get titleId() {\n return `${this.customId}-title`\n }\n\n private get contentId() {\n return `${this.customId}-content`\n }\n\n private getCssClassMap(): CssClassMap {\n return {\n 'br-modal': true,\n [this.size]: true,\n scrollable: this.scrollable,\n }\n }\n\n private handleClose = () => {\n this.brModalBeforeClose.emit()\n\n if (this.autoClose) {\n this.show = false\n }\n }\n\n /**\n * Método público para abrir o modal\n */\n @Method()\n async open() {\n this.show = true\n\n this.openParentScrim()\n }\n\n /**\n * Método público para fechar o modal\n */\n @Method()\n async close() {\n if (!this.autoClose) {\n return\n }\n\n this.show = false\n }\n\n render() {\n if (!this.show) {\n return null\n }\n\n return (\n <Host>\n <div\n class={this.getCssClassMap()}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={this.titleId}\n aria-describedby={this.contentId}\n >\n <div class=\"br-modal-header\">\n <div class=\"modal-title\" id={this.titleId}>\n <slot name=\"header\">{this.titleText}</slot>\n </div>\n <slot name=\"close-button\">\n <br-button class=\"close\" shape=\"circle\" density=\"small\" aria-label=\"Fechar\" onClick={this.handleClose}>\n <br-icon icon-name=\"fa-solid:times\"></br-icon>\n </br-button>\n </slot>\n </div>\n <div id={this.contentId} class=\"br-modal-body\">\n <slot></slot>\n </div>\n <div class={`br-modal-footer ${this.alignFooter !== undefined ? `justify-content-${this.alignFooter}` : ''}`}>\n <slot name=\"footer\"></slot>\n </div>\n </div>\n </Host>\n )\n }\n}\n"]}
|
|
@@ -82,6 +82,29 @@ export class Scrim {
|
|
|
82
82
|
this.previouslyFocusedElement = null;
|
|
83
83
|
this.focusTimeoutId = null;
|
|
84
84
|
this.restoreFocusTimeoutId = null;
|
|
85
|
+
// ======================================================================
|
|
86
|
+
// GERENCIAMENTO DE COMPONENTES FILHOS
|
|
87
|
+
// ======================================================================
|
|
88
|
+
/**
|
|
89
|
+
* Handler para evento brModalOpen emitido por modal filha
|
|
90
|
+
*/
|
|
91
|
+
this.handleModalOpen = (event) => {
|
|
92
|
+
const modalElement = event.target;
|
|
93
|
+
if (!this.isDirectChild(modalElement))
|
|
94
|
+
return;
|
|
95
|
+
if (!this.isOpen) {
|
|
96
|
+
this.open();
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Handler para evento brModalClose emitido por modal filha
|
|
101
|
+
*/
|
|
102
|
+
this.handleModalClose = (event) => {
|
|
103
|
+
const modalElement = event.target;
|
|
104
|
+
if (!this.isDirectChild(modalElement))
|
|
105
|
+
return;
|
|
106
|
+
this.close();
|
|
107
|
+
};
|
|
85
108
|
this.handleActivatorClick = () => {
|
|
86
109
|
this.toggle();
|
|
87
110
|
};
|
|
@@ -99,6 +122,10 @@ export class Scrim {
|
|
|
99
122
|
const reference = (_a = this.scrollOrigin) !== null && _a !== void 0 ? _a : this.lastScrollTop;
|
|
100
123
|
if (Math.abs(currentScroll - reference) > this.scrollThreshold) {
|
|
101
124
|
this.scrollOrigin = null;
|
|
125
|
+
// Não fecha se tiver modal filha com autoClose=false ou não definido
|
|
126
|
+
if (this.hasModalWithAutoClose()) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
102
129
|
this.isOpen = false;
|
|
103
130
|
this.handleOpenChange(false);
|
|
104
131
|
return;
|
|
@@ -134,7 +161,9 @@ export class Scrim {
|
|
|
134
161
|
}
|
|
135
162
|
if (event.key === 'Escape' && !this.disableCloseOnClick) {
|
|
136
163
|
event.preventDefault();
|
|
137
|
-
this.
|
|
164
|
+
if (!this.hasModalWithAutoClose()) {
|
|
165
|
+
this.isOpen = false;
|
|
166
|
+
}
|
|
138
167
|
}
|
|
139
168
|
};
|
|
140
169
|
// Intercepta TODOS os eventos de clique globalmente quando scrim está ativo
|
|
@@ -168,11 +197,15 @@ export class Scrim {
|
|
|
168
197
|
}, 0);
|
|
169
198
|
}
|
|
170
199
|
};
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
200
|
+
/**
|
|
201
|
+
* Handler para clique na máscara do scrim
|
|
202
|
+
* Fecha o scrim se disableCloseOnClick for false e não houver modal filha com autoClose=false
|
|
203
|
+
*/
|
|
174
204
|
this.handleMaskClick = (_event) => {
|
|
175
205
|
if (!this.disableCloseOnClick) {
|
|
206
|
+
if (this.hasModalWithAutoClose()) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
176
209
|
this.close();
|
|
177
210
|
}
|
|
178
211
|
};
|
|
@@ -181,37 +214,39 @@ export class Scrim {
|
|
|
181
214
|
// LIFECYCLE HOOKS E WATCHERS
|
|
182
215
|
// ======================================================================
|
|
183
216
|
handleOpenChange(newValue) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
this.
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
this.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
217
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
218
|
+
// Cancelar qualquer timeout anterior
|
|
219
|
+
if (this.focusTimeoutId !== null) {
|
|
220
|
+
clearTimeout(this.focusTimeoutId);
|
|
221
|
+
this.focusTimeoutId = null;
|
|
222
|
+
}
|
|
223
|
+
if (this.restoreFocusTimeoutId !== null) {
|
|
224
|
+
clearTimeout(this.restoreFocusTimeoutId);
|
|
225
|
+
this.restoreFocusTimeoutId = null;
|
|
226
|
+
}
|
|
227
|
+
this.isActive = newValue;
|
|
228
|
+
if (newValue && this.scrollStrategy === 'close') {
|
|
229
|
+
const currentScroll = window.scrollY;
|
|
230
|
+
this.lastScrollTop = currentScroll;
|
|
231
|
+
this.scrollOrigin = currentScroll;
|
|
232
|
+
}
|
|
233
|
+
this.updateStyles();
|
|
234
|
+
if (this.isActive) {
|
|
235
|
+
this.previouslyFocusedElement = document.activeElement;
|
|
236
|
+
this.applyScrollStrategy();
|
|
237
|
+
this.addGlobalEventInterception();
|
|
238
|
+
this.focusTimeoutId = setTimeout(() => {
|
|
239
|
+
this.focusFirstElement();
|
|
240
|
+
}, 100);
|
|
241
|
+
this.brScrimOpen.emit();
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
this.resetScrolling();
|
|
245
|
+
this.removeGlobalEventInterception();
|
|
246
|
+
this.restoreFocus();
|
|
247
|
+
this.brScrimClose.emit();
|
|
248
|
+
}
|
|
249
|
+
});
|
|
215
250
|
}
|
|
216
251
|
updateStyles() {
|
|
217
252
|
if (this.zIndex !== null && this.zIndex !== undefined) {
|
|
@@ -238,6 +273,7 @@ export class Scrim {
|
|
|
238
273
|
this.setupActivator();
|
|
239
274
|
this.setupActivatorSlotClick();
|
|
240
275
|
this.addContentEventListener();
|
|
276
|
+
this.listenToModalEvents();
|
|
241
277
|
if (this.isActive) {
|
|
242
278
|
this.applyScrollStrategy();
|
|
243
279
|
this.addGlobalEventInterception();
|
|
@@ -271,7 +307,6 @@ export class Scrim {
|
|
|
271
307
|
clearTimeout(this.restoreFocusTimeoutId);
|
|
272
308
|
this.restoreFocusTimeoutId = null;
|
|
273
309
|
}
|
|
274
|
-
// Remover event listeners
|
|
275
310
|
window.removeEventListener('scroll', this.handleScrollClose);
|
|
276
311
|
window.removeEventListener('scroll', this.handleBlockScroll);
|
|
277
312
|
if (this.contentRef !== null) {
|
|
@@ -280,6 +315,58 @@ export class Scrim {
|
|
|
280
315
|
this.removeActivatorClickListener();
|
|
281
316
|
this.cleanupActivatorSlotClick();
|
|
282
317
|
this.removeGlobalEventInterception();
|
|
318
|
+
this.removeModalEventListener();
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Verifica se um elemento é filho direto deste scrim (não nested)
|
|
322
|
+
*/
|
|
323
|
+
isDirectChild(element) {
|
|
324
|
+
const children = this.getDirectChildren();
|
|
325
|
+
return children.some((child) => child === element || child.contains(element));
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Adiciona listeners para eventos brModalOpen e brModalClose das modais filhas
|
|
329
|
+
*/
|
|
330
|
+
listenToModalEvents() {
|
|
331
|
+
this.el.addEventListener('brModalOpen', this.handleModalOpen);
|
|
332
|
+
this.el.addEventListener('brModalClose', this.handleModalClose);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Remove listeners dos eventos da modal
|
|
336
|
+
*/
|
|
337
|
+
removeModalEventListener() {
|
|
338
|
+
this.el.removeEventListener('brModalOpen', this.handleModalOpen);
|
|
339
|
+
this.el.removeEventListener('brModalClose', this.handleModalClose);
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Retorna os elementos filhos diretos do scrim via slot padrão
|
|
343
|
+
*/
|
|
344
|
+
getDirectChildren() {
|
|
345
|
+
const shadowRoot = this.el.shadowRoot;
|
|
346
|
+
if (shadowRoot === null)
|
|
347
|
+
return [];
|
|
348
|
+
const slot = shadowRoot.querySelector('slot:not([name])');
|
|
349
|
+
if (slot === null)
|
|
350
|
+
return [];
|
|
351
|
+
return slot.assignedElements();
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Busca uma modal filha direta do scrim
|
|
355
|
+
*/
|
|
356
|
+
findModalChild() {
|
|
357
|
+
var _a;
|
|
358
|
+
const children = this.getDirectChildren();
|
|
359
|
+
const modalElement = children.find((child) => child.tagName === 'BR-MODAL');
|
|
360
|
+
return (_a = modalElement) !== null && _a !== void 0 ? _a : null;
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Verifica se há uma modal filha com autoClose=false (padrão ou explícito)
|
|
364
|
+
* Retorna true se:
|
|
365
|
+
* - Existe modal filha E autoClose não é explicitamente true
|
|
366
|
+
*/
|
|
367
|
+
hasModalWithAutoClose() {
|
|
368
|
+
const modal = this.findModalChild();
|
|
369
|
+
return modal !== null && modal.autoClose !== true;
|
|
283
370
|
}
|
|
284
371
|
// ======================================================================
|
|
285
372
|
// GERENCIAMENTO DO ACTIVATOR (ELEMENTO ACIONADOR)
|
|
@@ -468,7 +555,11 @@ export class Scrim {
|
|
|
468
555
|
return elements.filter((el) => el.offsetWidth > 0 && el.offsetHeight > 0 && getComputedStyle(el).visibility !== 'hidden');
|
|
469
556
|
}
|
|
470
557
|
shouldHandleEscape(event) {
|
|
471
|
-
|
|
558
|
+
if ((event.key === 'Escape' || event.key === 'Esc') && this.isActive && !this.disableCloseOnClick) {
|
|
559
|
+
// Não fecha se tiver modal filha com autoClose=false ou não definido
|
|
560
|
+
return !this.hasModalWithAutoClose();
|
|
561
|
+
}
|
|
562
|
+
return false;
|
|
472
563
|
}
|
|
473
564
|
handleTabNavigation(event) {
|
|
474
565
|
const focusableElements = this.getFocusableElements();
|
|
@@ -530,6 +621,9 @@ export class Scrim {
|
|
|
530
621
|
document.removeEventListener('focus', this.handleGlobalFocus, true);
|
|
531
622
|
document.removeEventListener('focusin', this.handleGlobalFocus, true);
|
|
532
623
|
}
|
|
624
|
+
// ======================================================================
|
|
625
|
+
// UTILITÁRIOS
|
|
626
|
+
// ======================================================================
|
|
533
627
|
getCssClassMap() {
|
|
534
628
|
return {
|
|
535
629
|
'br-scrim': true,
|
|
@@ -580,7 +674,7 @@ export class Scrim {
|
|
|
580
674
|
});
|
|
581
675
|
}
|
|
582
676
|
render() {
|
|
583
|
-
return (h(Host, { key: '
|
|
677
|
+
return (h(Host, { key: '249de7af4056263464615cbe086b419f74b8981b' }, h("slot", { key: '1698faa6b492e1ec594eba8425f20582a2af0e4a', name: "activator" }), h("div", { key: 'adedf3eb84f3d8f79ac9bb19209022301453c019', class: this.getCssClassMap(), id: this.customId, role: "dialog", "aria-modal": "true", "aria-label": this.ariaLabel || 'Conteúdo do diálogo', "data-visible": this.isActive ? 'true' : 'false' }, h("div", { key: 'ef7408a6672fabf4d2f79bc7922f301fd102652e', class: "mask", onClick: this.handleMaskClick }), h("div", { key: '91ffb1a84478f09fc90cefbb97180c5db13dba5c', ref: (el) => (this.contentRef = el), id: `${this.customId}-content`, class: "content", tabIndex: -1, onKeyDown: this.handleKeyDown }, h("slot", { key: '0600ac804980446103154cebf83389ac92e44d9d' })))));
|
|
584
678
|
}
|
|
585
679
|
static get is() { return "br-scrim"; }
|
|
586
680
|
static get encapsulation() { return "shadow"; }
|