@descope/web-components-ui 3.14.10 → 3.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,6 +23,10 @@ const customMixin = (superclass) =>
23
23
  return this.getAttribute('opened') === 'true';
24
24
  }
25
25
 
26
+ get closeOnOutsideClick() {
27
+ return this.getAttribute('close-on-outside-click') === 'true';
28
+ }
29
+
26
30
  handleOpened() {
27
31
  if (this.opened) {
28
32
  this.style.display = '';
@@ -88,6 +92,28 @@ const customMixin = (superclass) =>
88
92
  overlay._enterModalState = () => {};
89
93
 
90
94
  overlay.close = () => false;
95
+
96
+ // close the modal when the user clicks/taps the backdrop (outside the modal
97
+ // box). Vaadin's own outside-click does not fire here because we keep the
98
+ // overlay in the shadow DOM (see _attachOverlay above), which leaves it out
99
+ // of Vaadin's overlay stack, so we detect the backdrop click ourselves.
100
+ // the listener is always attached and reads `closeOnOutsideClick` at click
101
+ // time, so toggling the attribute after init is respected.
102
+ overlay.addEventListener('click', (event) => {
103
+ if (!this.closeOnOutsideClick || !this.opened) return;
104
+
105
+ // the visible modal box; clicks inside it (content + its padding) keep
106
+ // the modal open, only clicks on the dimmed backdrop close it. if we
107
+ // can't find the box, don't close - safer than closing on an inside click
108
+ const overlayPart = overlay.shadowRoot?.querySelector('[part="overlay"]');
109
+ if (!overlayPart || event.composedPath().includes(overlayPart)) {
110
+ return;
111
+ }
112
+
113
+ // just close ourselves; consumers that need to react (e.g. ModalDriver
114
+ // resetting the content) observe the `opened` attribute
115
+ this.removeAttribute('opened');
116
+ });
91
117
  }
92
118
  };
93
119
 
@@ -13,7 +13,7 @@ const template = `
13
13
  </descope-container>
14
14
  </descope-container>`;
15
15
 
16
- const Template = ({ opened }) => {
16
+ const Template = ({ opened, closeOnOutsideClick }) => {
17
17
  const loader = `
18
18
  <descope-container direction="column" st-align-items="center" st-horizontal-padding="1.25rem" st-vertical-padding="1.25rem" st-gap="0.75rem" st-background-color="transparent">
19
19
  <descope-loader-radial size="sm" mode="primary"></descope-loader-radial>
@@ -21,7 +21,7 @@ const Template = ({ opened }) => {
21
21
  `;
22
22
 
23
23
  return `
24
- <descope-modal opened="${opened}">
24
+ <descope-modal opened="${opened}" close-on-outside-click="${closeOnOutsideClick}">
25
25
  ${loader}
26
26
  </descope-modal>
27
27
  `;
@@ -30,6 +30,16 @@ const Template = ({ opened }) => {
30
30
  export default {
31
31
  component: componentName,
32
32
  title: 'descope-modal',
33
+ argTypes: {
34
+ opened: {
35
+ name: 'Opened',
36
+ control: { type: 'boolean' },
37
+ },
38
+ closeOnOutsideClick: {
39
+ name: 'Close on outside click',
40
+ control: { type: 'boolean' },
41
+ },
42
+ },
33
43
  decorators: [
34
44
  (render) => {
35
45
  setTimeout(() => {
@@ -45,4 +55,5 @@ export const Default = Template.bind({});
45
55
 
46
56
  Default.args = {
47
57
  opened: true,
58
+ closeOnOutsideClick: true,
48
59
  };