@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
|
@@ -13,7 +13,9 @@ const modalCss = "*,*::before,*::after{-webkit-box-sizing:border-box;box-sizing:
|
|
|
13
13
|
const Modal = class {
|
|
14
14
|
constructor(hostRef) {
|
|
15
15
|
index.registerInstance(this, hostRef);
|
|
16
|
+
this.brModalOpen = index.createEvent(this, "brModalOpen", 7);
|
|
16
17
|
this.brModalClose = index.createEvent(this, "brModalClose", 7);
|
|
18
|
+
this.brModalBeforeClose = index.createEvent(this, "brModalBeforeClose", 7);
|
|
17
19
|
if (hostRef.$hostElement$["s-ei"]) {
|
|
18
20
|
this.elementInternals = hostRef.$hostElement$["s-ei"];
|
|
19
21
|
}
|
|
@@ -28,32 +30,132 @@ const Modal = class {
|
|
|
28
30
|
this.customId = helpers.Helpers.generateUniqueId('modal');
|
|
29
31
|
/** Controla a visibilidade do modal. */
|
|
30
32
|
this.show = false;
|
|
31
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* Define o comportamento de fechamento do modal.
|
|
35
|
+
*
|
|
36
|
+
* - `true`: O modal fecha automaticamente ao clicar no botão fechar.
|
|
37
|
+
* - `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
|
|
38
|
+
* controlar manualmente o fechamento.
|
|
39
|
+
*/
|
|
32
40
|
this.autoClose = false;
|
|
33
41
|
/**
|
|
34
42
|
* Define o tamanho (largura) do modal.
|
|
35
43
|
*/
|
|
36
44
|
this.size = 'medium';
|
|
37
|
-
/** Se `true`, exibe um fundo escurecido (scrim) atrás do modal. */
|
|
38
|
-
this.scrim = false;
|
|
39
45
|
/** Se `true`, habilita a rolagem interna do conteúdo do modal. */
|
|
40
46
|
this.scrollable = false;
|
|
41
47
|
/**
|
|
42
48
|
* Define o alinhamento do conteúdo do rodapé (slot="footer").
|
|
43
49
|
*/
|
|
44
50
|
this.alignFooter = 'center';
|
|
51
|
+
this.isOpeningParentScrim = false;
|
|
52
|
+
/**
|
|
53
|
+
* Handler para evento brScrimOpen do parent scrim
|
|
54
|
+
* Quando scrim abre programaticamente, a modal deve abrir também
|
|
55
|
+
*/
|
|
56
|
+
this.handleParentScrimOpen = () => {
|
|
57
|
+
const parentScrim = this.el.closest('br-scrim');
|
|
58
|
+
if (parentScrim === null)
|
|
59
|
+
return;
|
|
60
|
+
if (!this.show) {
|
|
61
|
+
this.show = true;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Handler para evento brScrimClose do parent scrim
|
|
66
|
+
* Se autoClose=true, fecha a modal junto com o scrim
|
|
67
|
+
* Se autoClose=false, não faz nada (modal permanece aberta)
|
|
68
|
+
*/
|
|
69
|
+
this.handleParentScrimClose = () => {
|
|
70
|
+
const parentScrim = this.el.closest('br-scrim');
|
|
71
|
+
if (parentScrim === null)
|
|
72
|
+
return;
|
|
73
|
+
if (this.autoClose && this.show) {
|
|
74
|
+
this.show = false;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
45
77
|
this.handleClose = () => {
|
|
46
|
-
this.
|
|
78
|
+
this.brModalBeforeClose.emit();
|
|
47
79
|
if (this.autoClose) {
|
|
48
80
|
this.show = false;
|
|
49
|
-
// Se o modal está dentro de um br-scrim, fecha o scrim também
|
|
50
|
-
const parentScrim = this.el.closest('br-scrim');
|
|
51
|
-
if (parentScrim) {
|
|
52
|
-
parentScrim.close();
|
|
53
|
-
}
|
|
54
81
|
}
|
|
55
82
|
};
|
|
56
83
|
}
|
|
84
|
+
handleShowChange(newValue, oldValue) {
|
|
85
|
+
if (newValue) {
|
|
86
|
+
this.brModalOpen.emit();
|
|
87
|
+
this.openParentScrim();
|
|
88
|
+
}
|
|
89
|
+
else if (oldValue === true) {
|
|
90
|
+
this.brModalClose.emit();
|
|
91
|
+
this.closeParentScrim();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
closeParentScrim() {
|
|
95
|
+
const parentScrim = this.el.closest('br-scrim');
|
|
96
|
+
if (parentScrim && typeof parentScrim.close === 'function') {
|
|
97
|
+
parentScrim.close();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
componentWillLoad() {
|
|
101
|
+
if (!this.show) {
|
|
102
|
+
const parentScrim = this.el.closest('br-scrim');
|
|
103
|
+
if (parentScrim !== null && parentScrim.isOpen) {
|
|
104
|
+
this.show = true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
componentDidLoad() {
|
|
109
|
+
this.listenToParentScrimEvents();
|
|
110
|
+
if (this.show) {
|
|
111
|
+
this.openParentScrim();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
disconnectedCallback() {
|
|
115
|
+
this.isOpeningParentScrim = false;
|
|
116
|
+
this.removeParentScrimEventListeners();
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Adiciona listeners para eventos do parent scrim
|
|
120
|
+
*/
|
|
121
|
+
listenToParentScrimEvents() {
|
|
122
|
+
const parentScrim = this.el.closest('br-scrim');
|
|
123
|
+
if (parentScrim !== null) {
|
|
124
|
+
parentScrim.addEventListener('brScrimOpen', this.handleParentScrimOpen);
|
|
125
|
+
parentScrim.addEventListener('brScrimClose', this.handleParentScrimClose);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Remove listeners de eventos do parent scrim
|
|
130
|
+
*/
|
|
131
|
+
removeParentScrimEventListeners() {
|
|
132
|
+
const parentScrim = this.el.closest('br-scrim');
|
|
133
|
+
if (parentScrim !== null) {
|
|
134
|
+
parentScrim.removeEventListener('brScrimOpen', this.handleParentScrimOpen);
|
|
135
|
+
parentScrim.removeEventListener('brScrimClose', this.handleParentScrimClose);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
openParentScrim() {
|
|
139
|
+
if (this.isOpeningParentScrim)
|
|
140
|
+
return;
|
|
141
|
+
const parentScrim = this.el.closest('br-scrim');
|
|
142
|
+
if (parentScrim && !parentScrim.isOpen) {
|
|
143
|
+
this.isOpeningParentScrim = true;
|
|
144
|
+
Promise.resolve()
|
|
145
|
+
.then(() => {
|
|
146
|
+
try {
|
|
147
|
+
return parentScrim.open();
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
console.warn('br-modal: Erro ao abrir scrim pai:', error);
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
.finally(() => {
|
|
155
|
+
this.isOpeningParentScrim = false;
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
57
159
|
get titleId() {
|
|
58
160
|
return `${this.customId}-title`;
|
|
59
161
|
}
|
|
@@ -73,6 +175,7 @@ const Modal = class {
|
|
|
73
175
|
open() {
|
|
74
176
|
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
75
177
|
this.show = true;
|
|
178
|
+
this.openParentScrim();
|
|
76
179
|
});
|
|
77
180
|
}
|
|
78
181
|
/**
|
|
@@ -80,22 +183,23 @@ const Modal = class {
|
|
|
80
183
|
*/
|
|
81
184
|
close() {
|
|
82
185
|
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
83
|
-
this.
|
|
84
|
-
|
|
85
|
-
const parentScrim = this.el.closest('br-scrim');
|
|
86
|
-
if (parentScrim) {
|
|
87
|
-
parentScrim.close();
|
|
186
|
+
if (!this.autoClose) {
|
|
187
|
+
return;
|
|
88
188
|
}
|
|
189
|
+
this.show = false;
|
|
89
190
|
});
|
|
90
191
|
}
|
|
91
192
|
render() {
|
|
92
193
|
if (!this.show) {
|
|
93
194
|
return null;
|
|
94
195
|
}
|
|
95
|
-
return (index.h(index.Host, null, index.h("div", { class: this.getCssClassMap(), role: "dialog", "aria-modal": "true", "aria-labelledby": this.titleId, "aria-describedby": this.contentId }, index.h("div", { class: "br-modal-header" }, index.h("div", { class: "modal-title", id: this.titleId }, index.h("slot", { name: "header" }, this.titleText)), index.h("slot", { name: "close-button" }, index.h("br-button", { class: "close", shape: "circle", density: "small", "aria-label": "Fechar", onClick: this.handleClose }, index.h("br-icon", { "icon-name": "fa-solid:times" })))), index.h("div", { id: this.contentId, class: "br-modal-body" }, index.h("slot", null)), index.h("div", { class: `br-modal-footer ${this.alignFooter ? `justify-content-${this.alignFooter}` : ''}` }, index.h("slot", { name: "footer" })))));
|
|
196
|
+
return (index.h(index.Host, null, index.h("div", { class: this.getCssClassMap(), role: "dialog", "aria-modal": "true", "aria-labelledby": this.titleId, "aria-describedby": this.contentId }, index.h("div", { class: "br-modal-header" }, index.h("div", { class: "modal-title", id: this.titleId }, index.h("slot", { name: "header" }, this.titleText)), index.h("slot", { name: "close-button" }, index.h("br-button", { class: "close", shape: "circle", density: "small", "aria-label": "Fechar", onClick: this.handleClose }, index.h("br-icon", { "icon-name": "fa-solid:times" })))), index.h("div", { id: this.contentId, class: "br-modal-body" }, index.h("slot", null)), index.h("div", { class: `br-modal-footer ${this.alignFooter !== undefined ? `justify-content-${this.alignFooter}` : ''}` }, index.h("slot", { name: "footer" })))));
|
|
96
197
|
}
|
|
97
198
|
static get formAssociated() { return true; }
|
|
98
199
|
get el() { return index.getElement(this); }
|
|
200
|
+
static get watchers() { return {
|
|
201
|
+
"show": ["handleShowChange"]
|
|
202
|
+
}; }
|
|
99
203
|
};
|
|
100
204
|
Modal.style = modalCss;
|
|
101
205
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"br-modal.entry.cjs.js","sources":["../../packages/webcomponents/src/components/modal/modal.scss?tag=br-modal&encapsulation=shadow","../../packages/webcomponents/src/components/modal/modal.tsx"],"sourcesContent":["@import \"~@govbr-ds/core/src/components/modal/modal\";\n\n.br-modal.scrollable {\n max-height: 400px;\n}\n\n.br-modal-footer.justify-content-end {\n justify-content: flex-end;\n}\n","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"],"names":["Helpers","h","Host"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"br-modal.entry.cjs.js","sources":["../../packages/webcomponents/src/components/modal/modal.scss?tag=br-modal&encapsulation=shadow","../../packages/webcomponents/src/components/modal/modal.tsx"],"sourcesContent":["@import \"~@govbr-ds/core/src/components/modal/modal\";\n\n.br-modal.scrollable {\n max-height: 400px;\n}\n\n.br-modal-footer.justify-content-end {\n justify-content: flex-end;\n}\n","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"],"names":["Helpers","h","Host"],"mappings":"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"}
|
|
@@ -89,6 +89,29 @@ const Scrim = class {
|
|
|
89
89
|
this.previouslyFocusedElement = null;
|
|
90
90
|
this.focusTimeoutId = null;
|
|
91
91
|
this.restoreFocusTimeoutId = null;
|
|
92
|
+
// ======================================================================
|
|
93
|
+
// GERENCIAMENTO DE COMPONENTES FILHOS
|
|
94
|
+
// ======================================================================
|
|
95
|
+
/**
|
|
96
|
+
* Handler para evento brModalOpen emitido por modal filha
|
|
97
|
+
*/
|
|
98
|
+
this.handleModalOpen = (event) => {
|
|
99
|
+
const modalElement = event.target;
|
|
100
|
+
if (!this.isDirectChild(modalElement))
|
|
101
|
+
return;
|
|
102
|
+
if (!this.isOpen) {
|
|
103
|
+
this.open();
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Handler para evento brModalClose emitido por modal filha
|
|
108
|
+
*/
|
|
109
|
+
this.handleModalClose = (event) => {
|
|
110
|
+
const modalElement = event.target;
|
|
111
|
+
if (!this.isDirectChild(modalElement))
|
|
112
|
+
return;
|
|
113
|
+
this.close();
|
|
114
|
+
};
|
|
92
115
|
this.handleActivatorClick = () => {
|
|
93
116
|
this.toggle();
|
|
94
117
|
};
|
|
@@ -106,6 +129,10 @@ const Scrim = class {
|
|
|
106
129
|
const reference = (_a = this.scrollOrigin) !== null && _a !== void 0 ? _a : this.lastScrollTop;
|
|
107
130
|
if (Math.abs(currentScroll - reference) > this.scrollThreshold) {
|
|
108
131
|
this.scrollOrigin = null;
|
|
132
|
+
// Não fecha se tiver modal filha com autoClose=false ou não definido
|
|
133
|
+
if (this.hasModalWithAutoClose()) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
109
136
|
this.isOpen = false;
|
|
110
137
|
this.handleOpenChange(false);
|
|
111
138
|
return;
|
|
@@ -141,7 +168,9 @@ const Scrim = class {
|
|
|
141
168
|
}
|
|
142
169
|
if (event.key === 'Escape' && !this.disableCloseOnClick) {
|
|
143
170
|
event.preventDefault();
|
|
144
|
-
this.
|
|
171
|
+
if (!this.hasModalWithAutoClose()) {
|
|
172
|
+
this.isOpen = false;
|
|
173
|
+
}
|
|
145
174
|
}
|
|
146
175
|
};
|
|
147
176
|
// Intercepta TODOS os eventos de clique globalmente quando scrim está ativo
|
|
@@ -175,11 +204,15 @@ const Scrim = class {
|
|
|
175
204
|
}, 0);
|
|
176
205
|
}
|
|
177
206
|
};
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
207
|
+
/**
|
|
208
|
+
* Handler para clique na máscara do scrim
|
|
209
|
+
* Fecha o scrim se disableCloseOnClick for false e não houver modal filha com autoClose=false
|
|
210
|
+
*/
|
|
181
211
|
this.handleMaskClick = (_event) => {
|
|
182
212
|
if (!this.disableCloseOnClick) {
|
|
213
|
+
if (this.hasModalWithAutoClose()) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
183
216
|
this.close();
|
|
184
217
|
}
|
|
185
218
|
};
|
|
@@ -188,37 +221,39 @@ const Scrim = class {
|
|
|
188
221
|
// LIFECYCLE HOOKS E WATCHERS
|
|
189
222
|
// ======================================================================
|
|
190
223
|
handleOpenChange(newValue) {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
this.
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
this.
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
224
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
225
|
+
// Cancelar qualquer timeout anterior
|
|
226
|
+
if (this.focusTimeoutId !== null) {
|
|
227
|
+
clearTimeout(this.focusTimeoutId);
|
|
228
|
+
this.focusTimeoutId = null;
|
|
229
|
+
}
|
|
230
|
+
if (this.restoreFocusTimeoutId !== null) {
|
|
231
|
+
clearTimeout(this.restoreFocusTimeoutId);
|
|
232
|
+
this.restoreFocusTimeoutId = null;
|
|
233
|
+
}
|
|
234
|
+
this.isActive = newValue;
|
|
235
|
+
if (newValue && this.scrollStrategy === 'close') {
|
|
236
|
+
const currentScroll = window.scrollY;
|
|
237
|
+
this.lastScrollTop = currentScroll;
|
|
238
|
+
this.scrollOrigin = currentScroll;
|
|
239
|
+
}
|
|
240
|
+
this.updateStyles();
|
|
241
|
+
if (this.isActive) {
|
|
242
|
+
this.previouslyFocusedElement = document.activeElement;
|
|
243
|
+
this.applyScrollStrategy();
|
|
244
|
+
this.addGlobalEventInterception();
|
|
245
|
+
this.focusTimeoutId = setTimeout(() => {
|
|
246
|
+
this.focusFirstElement();
|
|
247
|
+
}, 100);
|
|
248
|
+
this.brScrimOpen.emit();
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
this.resetScrolling();
|
|
252
|
+
this.removeGlobalEventInterception();
|
|
253
|
+
this.restoreFocus();
|
|
254
|
+
this.brScrimClose.emit();
|
|
255
|
+
}
|
|
256
|
+
});
|
|
222
257
|
}
|
|
223
258
|
updateStyles() {
|
|
224
259
|
if (this.zIndex !== null && this.zIndex !== undefined) {
|
|
@@ -245,6 +280,7 @@ const Scrim = class {
|
|
|
245
280
|
this.setupActivator();
|
|
246
281
|
this.setupActivatorSlotClick();
|
|
247
282
|
this.addContentEventListener();
|
|
283
|
+
this.listenToModalEvents();
|
|
248
284
|
if (this.isActive) {
|
|
249
285
|
this.applyScrollStrategy();
|
|
250
286
|
this.addGlobalEventInterception();
|
|
@@ -278,7 +314,6 @@ const Scrim = class {
|
|
|
278
314
|
clearTimeout(this.restoreFocusTimeoutId);
|
|
279
315
|
this.restoreFocusTimeoutId = null;
|
|
280
316
|
}
|
|
281
|
-
// Remover event listeners
|
|
282
317
|
window.removeEventListener('scroll', this.handleScrollClose);
|
|
283
318
|
window.removeEventListener('scroll', this.handleBlockScroll);
|
|
284
319
|
if (this.contentRef !== null) {
|
|
@@ -287,6 +322,58 @@ const Scrim = class {
|
|
|
287
322
|
this.removeActivatorClickListener();
|
|
288
323
|
this.cleanupActivatorSlotClick();
|
|
289
324
|
this.removeGlobalEventInterception();
|
|
325
|
+
this.removeModalEventListener();
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Verifica se um elemento é filho direto deste scrim (não nested)
|
|
329
|
+
*/
|
|
330
|
+
isDirectChild(element) {
|
|
331
|
+
const children = this.getDirectChildren();
|
|
332
|
+
return children.some((child) => child === element || child.contains(element));
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Adiciona listeners para eventos brModalOpen e brModalClose das modais filhas
|
|
336
|
+
*/
|
|
337
|
+
listenToModalEvents() {
|
|
338
|
+
this.el.addEventListener('brModalOpen', this.handleModalOpen);
|
|
339
|
+
this.el.addEventListener('brModalClose', this.handleModalClose);
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Remove listeners dos eventos da modal
|
|
343
|
+
*/
|
|
344
|
+
removeModalEventListener() {
|
|
345
|
+
this.el.removeEventListener('brModalOpen', this.handleModalOpen);
|
|
346
|
+
this.el.removeEventListener('brModalClose', this.handleModalClose);
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Retorna os elementos filhos diretos do scrim via slot padrão
|
|
350
|
+
*/
|
|
351
|
+
getDirectChildren() {
|
|
352
|
+
const shadowRoot = this.el.shadowRoot;
|
|
353
|
+
if (shadowRoot === null)
|
|
354
|
+
return [];
|
|
355
|
+
const slot = shadowRoot.querySelector('slot:not([name])');
|
|
356
|
+
if (slot === null)
|
|
357
|
+
return [];
|
|
358
|
+
return slot.assignedElements();
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Busca uma modal filha direta do scrim
|
|
362
|
+
*/
|
|
363
|
+
findModalChild() {
|
|
364
|
+
var _a;
|
|
365
|
+
const children = this.getDirectChildren();
|
|
366
|
+
const modalElement = children.find((child) => child.tagName === 'BR-MODAL');
|
|
367
|
+
return (_a = modalElement) !== null && _a !== void 0 ? _a : null;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Verifica se há uma modal filha com autoClose=false (padrão ou explícito)
|
|
371
|
+
* Retorna true se:
|
|
372
|
+
* - Existe modal filha E autoClose não é explicitamente true
|
|
373
|
+
*/
|
|
374
|
+
hasModalWithAutoClose() {
|
|
375
|
+
const modal = this.findModalChild();
|
|
376
|
+
return modal !== null && modal.autoClose !== true;
|
|
290
377
|
}
|
|
291
378
|
// ======================================================================
|
|
292
379
|
// GERENCIAMENTO DO ACTIVATOR (ELEMENTO ACIONADOR)
|
|
@@ -475,7 +562,11 @@ const Scrim = class {
|
|
|
475
562
|
return elements.filter((el) => el.offsetWidth > 0 && el.offsetHeight > 0 && getComputedStyle(el).visibility !== 'hidden');
|
|
476
563
|
}
|
|
477
564
|
shouldHandleEscape(event) {
|
|
478
|
-
|
|
565
|
+
if ((event.key === 'Escape' || event.key === 'Esc') && this.isActive && !this.disableCloseOnClick) {
|
|
566
|
+
// Não fecha se tiver modal filha com autoClose=false ou não definido
|
|
567
|
+
return !this.hasModalWithAutoClose();
|
|
568
|
+
}
|
|
569
|
+
return false;
|
|
479
570
|
}
|
|
480
571
|
handleTabNavigation(event) {
|
|
481
572
|
const focusableElements = this.getFocusableElements();
|
|
@@ -536,6 +627,9 @@ const Scrim = class {
|
|
|
536
627
|
document.removeEventListener('focus', this.handleGlobalFocus, true);
|
|
537
628
|
document.removeEventListener('focusin', this.handleGlobalFocus, true);
|
|
538
629
|
}
|
|
630
|
+
// ======================================================================
|
|
631
|
+
// UTILITÁRIOS
|
|
632
|
+
// ======================================================================
|
|
539
633
|
getCssClassMap() {
|
|
540
634
|
return {
|
|
541
635
|
'br-scrim': true,
|
|
@@ -586,7 +680,7 @@ const Scrim = class {
|
|
|
586
680
|
});
|
|
587
681
|
}
|
|
588
682
|
render() {
|
|
589
|
-
return (index.h(index.Host, { key: '
|
|
683
|
+
return (index.h(index.Host, { key: '249de7af4056263464615cbe086b419f74b8981b' }, index.h("slot", { key: '1698faa6b492e1ec594eba8425f20582a2af0e4a', name: "activator" }), index.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' }, index.h("div", { key: 'ef7408a6672fabf4d2f79bc7922f301fd102652e', class: "mask", onClick: this.handleMaskClick }), index.h("div", { key: '91ffb1a84478f09fc90cefbb97180c5db13dba5c', ref: (el) => (this.contentRef = el), id: `${this.customId}-content`, class: "content", tabIndex: -1, onKeyDown: this.handleKeyDown }, index.h("slot", { key: '0600ac804980446103154cebf83389ac92e44d9d' })))));
|
|
590
684
|
}
|
|
591
685
|
static get formAssociated() { return true; }
|
|
592
686
|
get el() { return index.getElement(this); }
|