@vaadin/dialog 24.9.11 → 24.10.0-alpha2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/dialog",
3
- "version": "24.9.11",
3
+ "version": "24.10.0-alpha2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -39,18 +39,18 @@
39
39
  "dependencies": {
40
40
  "@open-wc/dedupe-mixin": "^1.3.0",
41
41
  "@polymer/polymer": "^3.0.0",
42
- "@vaadin/component-base": "~24.9.11",
43
- "@vaadin/lit-renderer": "~24.9.11",
44
- "@vaadin/overlay": "~24.9.11",
45
- "@vaadin/vaadin-lumo-styles": "~24.9.11",
46
- "@vaadin/vaadin-material-styles": "~24.9.11",
47
- "@vaadin/vaadin-themable-mixin": "~24.9.11",
42
+ "@vaadin/component-base": "24.10.0-alpha2",
43
+ "@vaadin/lit-renderer": "24.10.0-alpha2",
44
+ "@vaadin/overlay": "24.10.0-alpha2",
45
+ "@vaadin/vaadin-lumo-styles": "24.10.0-alpha2",
46
+ "@vaadin/vaadin-material-styles": "24.10.0-alpha2",
47
+ "@vaadin/vaadin-themable-mixin": "24.10.0-alpha2",
48
48
  "lit": "^3.0.0"
49
49
  },
50
50
  "devDependencies": {
51
- "@vaadin/a11y-base": "~24.9.11",
52
- "@vaadin/chai-plugins": "~24.9.11",
53
- "@vaadin/test-runner-commands": "~24.9.11",
51
+ "@vaadin/a11y-base": "24.10.0-alpha2",
52
+ "@vaadin/chai-plugins": "24.10.0-alpha2",
53
+ "@vaadin/test-runner-commands": "24.10.0-alpha2",
54
54
  "@vaadin/testing-helpers": "^1.1.0",
55
55
  "sinon": "^18.0.0"
56
56
  },
@@ -58,5 +58,5 @@
58
58
  "web-types.json",
59
59
  "web-types.lit.json"
60
60
  ],
61
- "gitHead": "235991ba683038cc6556b3551c7763d8b538120f"
61
+ "gitHead": "43abf4293381464fe47f5339b0ee64caf8867cfa"
62
62
  }
@@ -70,4 +70,14 @@ export declare class DialogBaseMixinClass {
70
70
  * If a unitless number is provided, pixels are assumed.
71
71
  */
72
72
  height: string;
73
+
74
+ /**
75
+ * Set to true to prevent the dialog from moving outside the viewport bounds.
76
+ * When enabled, all four edges of the dialog will remain visible, for example
77
+ * when dragging the dialog or when the viewport is resized. Note that the
78
+ * dialog will also adjust any programmatically configured size and position
79
+ * so that it stays within the viewport.
80
+ * @attr {boolean} keep-in-viewport
81
+ */
82
+ keepInViewport: boolean;
73
83
  }
@@ -100,6 +100,21 @@ export const DialogBaseMixin = (superClass) =>
100
100
  type: String,
101
101
  value: 'dialog',
102
102
  },
103
+
104
+ /**
105
+ * Set to true to prevent the dialog from moving outside the viewport bounds.
106
+ * When enabled, all four edges of the dialog will remain visible, for example
107
+ * when dragging the dialog or when the viewport is resized. Note that the
108
+ * dialog will also adjust any programmatically configured size and position
109
+ * so that it stays within the viewport.
110
+ * @attr {boolean} keep-in-viewport
111
+ * @type {boolean}
112
+ */
113
+ keepInViewport: {
114
+ type: Boolean,
115
+ value: false,
116
+ reflectToAttribute: true,
117
+ },
103
118
  };
104
119
  }
105
120
 
@@ -106,8 +106,20 @@ export const DialogDraggableMixin = (superClass) =>
106
106
  _drag(e) {
107
107
  const event = getMouseOrFirstTouchEvent(e);
108
108
  if (eventInWindow(event)) {
109
- const top = this._originalBounds.top + (event.pageY - this._originalMouseCoords.top);
110
- const left = this._originalBounds.left + (event.pageX - this._originalMouseCoords.left);
109
+ let top = this._originalBounds.top + (event.pageY - this._originalMouseCoords.top);
110
+ let left = this._originalBounds.left + (event.pageX - this._originalMouseCoords.left);
111
+
112
+ if (this.keepInViewport) {
113
+ // Constrain the dialog position so that it stays within the overlay host bounds,
114
+ // respecting the `--vaadin-overlay-viewport-inset` (offset from the viewport edges).
115
+ const { width, height } = this._originalBounds;
116
+ const overlayHostBounds = this.$.overlay.getBoundingClientRect();
117
+ const maxLeft = overlayHostBounds.right - overlayHostBounds.left - width;
118
+ const maxTop = overlayHostBounds.bottom - overlayHostBounds.top - height;
119
+ left = Math.max(0, Math.min(left, maxLeft));
120
+ top = Math.max(0, Math.min(top, maxTop));
121
+ }
122
+
111
123
  this.top = top;
112
124
  this.left = left;
113
125
  }
@@ -34,6 +34,11 @@ export declare class DialogOverlayMixinClass {
34
34
  */
35
35
  headerTitle: string;
36
36
 
37
+ /**
38
+ * Whether to keep the overlay within the viewport.
39
+ */
40
+ keepInViewport: boolean;
41
+
37
42
  /**
38
43
  * Custom function for rendering the dialog header.
39
44
  */
@@ -33,6 +33,14 @@ export const DialogOverlayMixin = (superClass) =>
33
33
  footerRenderer: {
34
34
  type: Object,
35
35
  },
36
+
37
+ /**
38
+ * Whether to keep the overlay within the viewport.
39
+ */
40
+ keepInViewport: {
41
+ type: Boolean,
42
+ reflectToAttribute: true,
43
+ },
36
44
  };
37
45
  }
38
46
 
@@ -40,6 +48,7 @@ export const DialogOverlayMixin = (superClass) =>
40
48
  return [
41
49
  '_headerFooterRendererChange(headerRenderer, footerRenderer, opened)',
42
50
  '_headerTitleChanged(headerTitle, opened)',
51
+ '__keepInViewportChanged(keepInViewport, opened)',
43
52
  ];
44
53
  }
45
54
 
@@ -50,6 +59,7 @@ export const DialogOverlayMixin = (superClass) =>
50
59
  // Update overflow attribute on resize
51
60
  this.__resizeObserver = new ResizeObserver(() => {
52
61
  this.__updateOverflow();
62
+ this.__adjustPosition();
53
63
  });
54
64
  this.__resizeObserver.observe(this.$.resizerContainer);
55
65
 
@@ -57,6 +67,8 @@ export const DialogOverlayMixin = (superClass) =>
57
67
  this.$.content.addEventListener('scroll', () => {
58
68
  this.__updateOverflow();
59
69
  });
70
+
71
+ this.__handleWindowResize = this.__handleWindowResize.bind(this);
60
72
  }
61
73
 
62
74
  /** @private */
@@ -214,6 +226,8 @@ export const DialogOverlayMixin = (superClass) =>
214
226
  });
215
227
 
216
228
  Object.assign(overlay.style, parsedBounds);
229
+
230
+ this.__adjustPosition();
217
231
  }
218
232
 
219
233
  /**
@@ -255,4 +269,54 @@ export const DialogOverlayMixin = (superClass) =>
255
269
  this.removeAttribute('overflow');
256
270
  }
257
271
  }
272
+
273
+ /** @private */
274
+ __keepInViewportChanged(keepInViewport, opened) {
275
+ if (opened && keepInViewport) {
276
+ window.addEventListener('resize', this.__handleWindowResize);
277
+ } else {
278
+ window.removeEventListener('resize', this.__handleWindowResize);
279
+ }
280
+ }
281
+
282
+ /** @private */
283
+ __handleWindowResize() {
284
+ this.__adjustPosition();
285
+ }
286
+
287
+ /**
288
+ * Adjusts the position of the overlay to keep it within the viewport if `keepInViewport` is true.
289
+ * @private
290
+ */
291
+ __adjustPosition() {
292
+ if (!this.opened || !this.keepInViewport) {
293
+ return;
294
+ }
295
+
296
+ // Centered dialogs do not use absolute positioning and automatically adjust their position / size to fit the viewport
297
+ const style = getComputedStyle(this.$.overlay);
298
+ if (style.position !== 'absolute') {
299
+ return;
300
+ }
301
+
302
+ const overlayHostBounds = this.getBoundingClientRect();
303
+ const bounds = this.getBounds();
304
+ // Prefer dimensions from getComputedStyle, as bounding rect is affected
305
+ // by scale transform applied by opening animation in Lumo
306
+ const width = parseFloat(style.width) || bounds.width;
307
+ const height = parseFloat(style.height) || bounds.height;
308
+
309
+ const maxLeft = overlayHostBounds.right - overlayHostBounds.left - width;
310
+ const maxTop = overlayHostBounds.bottom - overlayHostBounds.top - height;
311
+
312
+ if (bounds.left > maxLeft || bounds.top > maxTop) {
313
+ const left = Math.max(0, Math.min(bounds.left, maxLeft));
314
+ const top = Math.max(0, Math.min(bounds.top, maxTop));
315
+
316
+ Object.assign(this.$.overlay.style, {
317
+ left: `${left}px`,
318
+ top: `${top}px`,
319
+ });
320
+ }
321
+ }
258
322
  };
@@ -74,7 +74,7 @@ export const dialogOverlay = css`
74
74
  min-width: 12em; /* matches the default <vaadin-text-field> width */
75
75
  }
76
76
 
77
- :host([has-bounds-set]) [part='overlay'] {
77
+ :host([has-bounds-set]:not([keep-in-viewport])) [part='overlay'] {
78
78
  max-width: none;
79
79
  }
80
80
 
@@ -115,6 +115,7 @@ class Dialog extends DialogDraggableMixin(
115
115
  with-backdrop="[[!modeless]]"
116
116
  resizable$="[[resizable]]"
117
117
  draggable$="[[draggable]]"
118
+ keep-in-viewport="[[keepInViewport]]"
118
119
  restore-focus-on-close
119
120
  focus-trap
120
121
  ></vaadin-dialog-overlay>
package/web-types.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/dialog",
4
- "version": "24.9.11",
4
+ "version": "24.10.0-alpha2",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
8
8
  "elements": [
9
9
  {
10
10
  "name": "vaadin-dialog",
11
- "description": "`<vaadin-dialog>` is a Web Component for creating customized modal dialogs.\n\n### Rendering\n\nThe content of the dialog can be populated by using the renderer callback function.\n\nThe renderer function provides `root`, `dialog` arguments.\nGenerate DOM content, append it to the `root` element and control the state\nof the host element by accessing `dialog`. Before generating new content,\nusers are able to check if there is already content in `root` for reusing it.\n\n```html\n<vaadin-dialog id=\"dialog\"></vaadin-dialog>\n```\n```js\nconst dialog = document.querySelector('#dialog');\ndialog.renderer = function(root, dialog) {\n root.textContent = \"Sample dialog\";\n};\n```\n\nRenderer is called on the opening of the dialog.\nDOM generated during the renderer call can be reused\nin the next renderer call and will be provided with the `root` argument.\nOn first call it will be empty.\n\n### Styling\n\n`<vaadin-dialog>` uses `<vaadin-dialog-overlay>` internal\nthemable component as the actual visible dialog overlay.\n\nSee [`<vaadin-overlay>`](https://cdn.vaadin.com/vaadin-web-components/24.9.11/#/elements/vaadin-overlay) documentation.\nfor `<vaadin-dialog-overlay>` parts.\n\nIn addition to `<vaadin-overlay>` parts, the following parts are available for styling:\n\nPart name | Description\n-----------------|-------------------------------------------\n`header` | Element wrapping title and header content\n`header-content` | Element wrapping the header content slot\n`title` | Element wrapping the title slot\n`footer` | Element wrapping the footer slot\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n-----------------|--------------------------------------------\n`has-title` | Set when the element has a title\n`has-header` | Set when the element has header renderer\n`has-footer` | Set when the element has footer renderer\n`overflow` | Set to `top`, `bottom`, none or both\n\nNote: the `theme` attribute value set on `<vaadin-dialog>` is\npropagated to the internal `<vaadin-dialog-overlay>` component.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
11
+ "description": "`<vaadin-dialog>` is a Web Component for creating customized modal dialogs.\n\n### Rendering\n\nThe content of the dialog can be populated by using the renderer callback function.\n\nThe renderer function provides `root`, `dialog` arguments.\nGenerate DOM content, append it to the `root` element and control the state\nof the host element by accessing `dialog`. Before generating new content,\nusers are able to check if there is already content in `root` for reusing it.\n\n```html\n<vaadin-dialog id=\"dialog\"></vaadin-dialog>\n```\n```js\nconst dialog = document.querySelector('#dialog');\ndialog.renderer = function(root, dialog) {\n root.textContent = \"Sample dialog\";\n};\n```\n\nRenderer is called on the opening of the dialog.\nDOM generated during the renderer call can be reused\nin the next renderer call and will be provided with the `root` argument.\nOn first call it will be empty.\n\n### Styling\n\n`<vaadin-dialog>` uses `<vaadin-dialog-overlay>` internal\nthemable component as the actual visible dialog overlay.\n\nSee [`<vaadin-overlay>`](https://cdn.vaadin.com/vaadin-web-components/24.10.0-alpha2/#/elements/vaadin-overlay) documentation.\nfor `<vaadin-dialog-overlay>` parts.\n\nIn addition to `<vaadin-overlay>` parts, the following parts are available for styling:\n\nPart name | Description\n-----------------|-------------------------------------------\n`header` | Element wrapping title and header content\n`header-content` | Element wrapping the header content slot\n`title` | Element wrapping the title slot\n`footer` | Element wrapping the footer slot\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n-----------------|--------------------------------------------\n`has-title` | Set when the element has a title\n`has-header` | Set when the element has header renderer\n`has-footer` | Set when the element has footer renderer\n`overflow` | Set to `top`, `bottom`, none or both\n\nNote: the `theme` attribute value set on `<vaadin-dialog>` is\npropagated to the internal `<vaadin-dialog-overlay>` component.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
12
12
  "attributes": [
13
13
  {
14
14
  "name": "opened",
@@ -101,6 +101,15 @@
101
101
  ]
102
102
  }
103
103
  },
104
+ {
105
+ "name": "keep-in-viewport",
106
+ "description": "Set to true to prevent the dialog from moving outside the viewport bounds.\nWhen enabled, all four edges of the dialog will remain visible, for example\nwhen dragging the dialog or when the viewport is resized. Note that the\ndialog will also adjust any programmatically configured size and position\nso that it stays within the viewport.",
107
+ "value": {
108
+ "type": [
109
+ "boolean"
110
+ ]
111
+ }
112
+ },
104
113
  {
105
114
  "name": "draggable",
106
115
  "description": "Set to true to enable repositioning the dialog by clicking and dragging.\n\nBy default, only the overlay area can be used to drag the element. But,\na child element can be marked as a draggable area by adding a\n\"`draggable`\" class to it, this will by default make all of its children draggable also.\nIf you want a child element to be draggable\nbut still have its children non-draggable (by default), mark it with\n\"`draggable-leaf-only`\" class name.",
@@ -257,6 +266,15 @@
257
266
  ]
258
267
  }
259
268
  },
269
+ {
270
+ "name": "keepInViewport",
271
+ "description": "Set to true to prevent the dialog from moving outside the viewport bounds.\nWhen enabled, all four edges of the dialog will remain visible, for example\nwhen dragging the dialog or when the viewport is resized. Note that the\ndialog will also adjust any programmatically configured size and position\nso that it stays within the viewport.",
272
+ "value": {
273
+ "type": [
274
+ "boolean"
275
+ ]
276
+ }
277
+ },
260
278
  {
261
279
  "name": "draggable",
262
280
  "description": "Set to true to enable repositioning the dialog by clicking and dragging.\n\nBy default, only the overlay area can be used to drag the element. But,\na child element can be marked as a draggable area by adding a\n\"`draggable`\" class to it, this will by default make all of its children draggable also.\nIf you want a child element to be draggable\nbut still have its children non-draggable (by default), mark it with\n\"`draggable-leaf-only`\" class name.",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/dialog",
4
- "version": "24.9.11",
4
+ "version": "24.10.0-alpha2",
5
5
  "description-markup": "markdown",
6
6
  "framework": "lit",
7
7
  "framework-config": {
@@ -16,7 +16,7 @@
16
16
  "elements": [
17
17
  {
18
18
  "name": "vaadin-dialog",
19
- "description": "`<vaadin-dialog>` is a Web Component for creating customized modal dialogs.\n\n### Rendering\n\nThe content of the dialog can be populated by using the renderer callback function.\n\nThe renderer function provides `root`, `dialog` arguments.\nGenerate DOM content, append it to the `root` element and control the state\nof the host element by accessing `dialog`. Before generating new content,\nusers are able to check if there is already content in `root` for reusing it.\n\n```html\n<vaadin-dialog id=\"dialog\"></vaadin-dialog>\n```\n```js\nconst dialog = document.querySelector('#dialog');\ndialog.renderer = function(root, dialog) {\n root.textContent = \"Sample dialog\";\n};\n```\n\nRenderer is called on the opening of the dialog.\nDOM generated during the renderer call can be reused\nin the next renderer call and will be provided with the `root` argument.\nOn first call it will be empty.\n\n### Styling\n\n`<vaadin-dialog>` uses `<vaadin-dialog-overlay>` internal\nthemable component as the actual visible dialog overlay.\n\nSee [`<vaadin-overlay>`](https://cdn.vaadin.com/vaadin-web-components/24.9.11/#/elements/vaadin-overlay) documentation.\nfor `<vaadin-dialog-overlay>` parts.\n\nIn addition to `<vaadin-overlay>` parts, the following parts are available for styling:\n\nPart name | Description\n-----------------|-------------------------------------------\n`header` | Element wrapping title and header content\n`header-content` | Element wrapping the header content slot\n`title` | Element wrapping the title slot\n`footer` | Element wrapping the footer slot\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n-----------------|--------------------------------------------\n`has-title` | Set when the element has a title\n`has-header` | Set when the element has header renderer\n`has-footer` | Set when the element has footer renderer\n`overflow` | Set to `top`, `bottom`, none or both\n\nNote: the `theme` attribute value set on `<vaadin-dialog>` is\npropagated to the internal `<vaadin-dialog-overlay>` component.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
19
+ "description": "`<vaadin-dialog>` is a Web Component for creating customized modal dialogs.\n\n### Rendering\n\nThe content of the dialog can be populated by using the renderer callback function.\n\nThe renderer function provides `root`, `dialog` arguments.\nGenerate DOM content, append it to the `root` element and control the state\nof the host element by accessing `dialog`. Before generating new content,\nusers are able to check if there is already content in `root` for reusing it.\n\n```html\n<vaadin-dialog id=\"dialog\"></vaadin-dialog>\n```\n```js\nconst dialog = document.querySelector('#dialog');\ndialog.renderer = function(root, dialog) {\n root.textContent = \"Sample dialog\";\n};\n```\n\nRenderer is called on the opening of the dialog.\nDOM generated during the renderer call can be reused\nin the next renderer call and will be provided with the `root` argument.\nOn first call it will be empty.\n\n### Styling\n\n`<vaadin-dialog>` uses `<vaadin-dialog-overlay>` internal\nthemable component as the actual visible dialog overlay.\n\nSee [`<vaadin-overlay>`](https://cdn.vaadin.com/vaadin-web-components/24.10.0-alpha2/#/elements/vaadin-overlay) documentation.\nfor `<vaadin-dialog-overlay>` parts.\n\nIn addition to `<vaadin-overlay>` parts, the following parts are available for styling:\n\nPart name | Description\n-----------------|-------------------------------------------\n`header` | Element wrapping title and header content\n`header-content` | Element wrapping the header content slot\n`title` | Element wrapping the title slot\n`footer` | Element wrapping the footer slot\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n-----------------|--------------------------------------------\n`has-title` | Set when the element has a title\n`has-header` | Set when the element has header renderer\n`has-footer` | Set when the element has footer renderer\n`overflow` | Set to `top`, `bottom`, none or both\n\nNote: the `theme` attribute value set on `<vaadin-dialog>` is\npropagated to the internal `<vaadin-dialog-overlay>` component.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
20
20
  "extension": true,
21
21
  "attributes": [
22
22
  {
@@ -47,6 +47,13 @@
47
47
  "kind": "expression"
48
48
  }
49
49
  },
50
+ {
51
+ "name": "?keepInViewport",
52
+ "description": "Set to true to prevent the dialog from moving outside the viewport bounds.\nWhen enabled, all four edges of the dialog will remain visible, for example\nwhen dragging the dialog or when the viewport is resized. Note that the\ndialog will also adjust any programmatically configured size and position\nso that it stays within the viewport.",
53
+ "value": {
54
+ "kind": "expression"
55
+ }
56
+ },
50
57
  {
51
58
  "name": "?draggable",
52
59
  "description": "Set to true to enable repositioning the dialog by clicking and dragging.\n\nBy default, only the overlay area can be used to drag the element. But,\na child element can be marked as a draggable area by adding a\n\"`draggable`\" class to it, this will by default make all of its children draggable also.\nIf you want a child element to be draggable\nbut still have its children non-draggable (by default), mark it with\n\"`draggable-leaf-only`\" class name.",