@vaadin/dialog 22.0.0-alpha10

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.
@@ -0,0 +1,250 @@
1
+ import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js';
2
+ import { getMouseOrFirstTouchEvent, eventInWindow } from './vaadin-dialog-utils.js';
3
+
4
+ registerStyles(
5
+ 'vaadin-dialog-overlay',
6
+ css`
7
+ [part='overlay'] {
8
+ position: relative;
9
+ overflow: visible;
10
+ max-height: 100%;
11
+ display: flex;
12
+ }
13
+
14
+ [part='content'] {
15
+ box-sizing: border-box;
16
+ height: 100%;
17
+ }
18
+
19
+ .resizer-container {
20
+ overflow: auto;
21
+ flex-grow: 1;
22
+ }
23
+
24
+ [part='overlay'][style] .resizer-container {
25
+ min-height: 100%;
26
+ width: 100%;
27
+ }
28
+
29
+ :host(:not([resizable])) .resizer {
30
+ display: none;
31
+ }
32
+
33
+ .resizer {
34
+ position: absolute;
35
+ height: 16px;
36
+ width: 16px;
37
+ }
38
+
39
+ .resizer.edge {
40
+ height: 8px;
41
+ width: 8px;
42
+ top: -4px;
43
+ right: -4px;
44
+ bottom: -4px;
45
+ left: -4px;
46
+ }
47
+
48
+ .resizer.edge.n {
49
+ width: auto;
50
+ bottom: auto;
51
+ cursor: ns-resize;
52
+ }
53
+
54
+ .resizer.ne {
55
+ top: -4px;
56
+ right: -4px;
57
+ cursor: nesw-resize;
58
+ }
59
+
60
+ .resizer.edge.e {
61
+ height: auto;
62
+ left: auto;
63
+ cursor: ew-resize;
64
+ }
65
+
66
+ .resizer.se {
67
+ bottom: -4px;
68
+ right: -4px;
69
+ cursor: nwse-resize;
70
+ }
71
+
72
+ .resizer.edge.s {
73
+ width: auto;
74
+ top: auto;
75
+ cursor: ns-resize;
76
+ }
77
+
78
+ .resizer.sw {
79
+ bottom: -4px;
80
+ left: -4px;
81
+ cursor: nesw-resize;
82
+ }
83
+
84
+ .resizer.edge.w {
85
+ height: auto;
86
+ right: auto;
87
+ cursor: ew-resize;
88
+ }
89
+
90
+ .resizer.nw {
91
+ top: -4px;
92
+ left: -4px;
93
+ cursor: nwse-resize;
94
+ }
95
+ `,
96
+ { moduleId: 'vaadin-dialog-resizable-overlay-styles' }
97
+ );
98
+
99
+ /**
100
+ * @polymerMixin
101
+ */
102
+ export const DialogResizableMixin = (superClass) =>
103
+ class VaadinDialogResizableMixin extends superClass {
104
+ static get properties() {
105
+ return {
106
+ /**
107
+ * Set to true to enable resizing the dialog by dragging the corners and edges.
108
+ * @type {boolean}
109
+ */
110
+ resizable: {
111
+ type: Boolean,
112
+ value: false,
113
+ reflectToAttribute: true
114
+ }
115
+ };
116
+ }
117
+
118
+ /** @protected */
119
+ ready() {
120
+ super.ready();
121
+ this._originalBounds = {};
122
+ this._originalMouseCoords = {};
123
+ this._resizeListeners = { start: {}, resize: {}, stop: {} };
124
+ this._addResizeListeners();
125
+ }
126
+
127
+ /** @private */
128
+ _addResizeListeners() {
129
+ // Note: edge controls added before corners
130
+ ['n', 'e', 's', 'w', 'nw', 'ne', 'se', 'sw'].forEach((direction) => {
131
+ const resizer = document.createElement('div');
132
+ this._resizeListeners.start[direction] = (e) => this._startResize(e, direction);
133
+ this._resizeListeners.resize[direction] = (e) => this._resize(e, direction);
134
+ this._resizeListeners.stop[direction] = () => this._stopResize(direction);
135
+ if (direction.length === 1) {
136
+ resizer.classList.add('edge');
137
+ }
138
+ resizer.classList.add('resizer');
139
+ resizer.classList.add(direction);
140
+ resizer.addEventListener('mousedown', this._resizeListeners.start[direction]);
141
+ resizer.addEventListener('touchstart', this._resizeListeners.start[direction]);
142
+ this.$.overlay.$.resizerContainer.appendChild(resizer);
143
+ });
144
+ }
145
+
146
+ /**
147
+ * @param {!MouseEvent | !TouchEvent} e
148
+ * @param {!DialogResizableDirection} direction
149
+ * @protected
150
+ */
151
+ _startResize(e, direction) {
152
+ // Don't initiate when there's more than 1 touch (pinch zoom)
153
+ if (e.type === 'touchstart' && e.touches.length > 1) {
154
+ return;
155
+ }
156
+
157
+ if (e.button === 0 || e.touches) {
158
+ e.preventDefault();
159
+
160
+ this._originalBounds = this.$.overlay.getBounds();
161
+ const event = getMouseOrFirstTouchEvent(e);
162
+ this._originalMouseCoords = { top: event.pageY, left: event.pageX };
163
+ window.addEventListener('mousemove', this._resizeListeners.resize[direction]);
164
+ window.addEventListener('touchmove', this._resizeListeners.resize[direction]);
165
+ window.addEventListener('mouseup', this._resizeListeners.stop[direction]);
166
+ window.addEventListener('touchend', this._resizeListeners.stop[direction]);
167
+ if (this.$.overlay.$.overlay.style.position !== 'absolute') {
168
+ this.$.overlay.setBounds(this._originalBounds);
169
+ }
170
+ }
171
+ }
172
+
173
+ /**
174
+ * @param {!MouseEvent | !TouchEvent} e
175
+ * @param {!DialogResizableDirection} resizer
176
+ * @protected
177
+ */
178
+ _resize(e, resizer) {
179
+ const event = getMouseOrFirstTouchEvent(e);
180
+ if (eventInWindow(event)) {
181
+ const minimumSize = 40;
182
+ resizer.split('').forEach((direction) => {
183
+ switch (direction) {
184
+ case 'n': {
185
+ const height = this._originalBounds.height - (event.pageY - this._originalMouseCoords.top);
186
+ const top = this._originalBounds.top + (event.pageY - this._originalMouseCoords.top);
187
+ if (height > minimumSize) {
188
+ this.$.overlay.setBounds({ top, height });
189
+ }
190
+ break;
191
+ }
192
+ case 'e': {
193
+ const width = this._originalBounds.width + (event.pageX - this._originalMouseCoords.left);
194
+ if (width > minimumSize) {
195
+ this.$.overlay.setBounds({ width });
196
+ }
197
+ break;
198
+ }
199
+ case 's': {
200
+ const height = this._originalBounds.height + (event.pageY - this._originalMouseCoords.top);
201
+ if (height > minimumSize) {
202
+ this.$.overlay.setBounds({ height });
203
+ }
204
+ break;
205
+ }
206
+ case 'w': {
207
+ const width = this._originalBounds.width - (event.pageX - this._originalMouseCoords.left);
208
+ const left = this._originalBounds.left + (event.pageX - this._originalMouseCoords.left);
209
+ if (width > minimumSize) {
210
+ this.$.overlay.setBounds({ left, width });
211
+ }
212
+ break;
213
+ }
214
+ }
215
+ });
216
+
217
+ this.$.overlay.notifyResize();
218
+ }
219
+ }
220
+
221
+ /**
222
+ * @param {!DialogResizableDirection} direction
223
+ * @protected
224
+ */
225
+ _stopResize(direction) {
226
+ window.removeEventListener('mousemove', this._resizeListeners.resize[direction]);
227
+ window.removeEventListener('touchmove', this._resizeListeners.resize[direction]);
228
+ window.removeEventListener('mouseup', this._resizeListeners.stop[direction]);
229
+ window.removeEventListener('touchend', this._resizeListeners.stop[direction]);
230
+ this.dispatchEvent(new CustomEvent('resize', { detail: this._getResizeDimensions() }));
231
+ }
232
+
233
+ /**
234
+ * @return {!DialogResizeDimensions}
235
+ * @protected
236
+ */
237
+ _getResizeDimensions() {
238
+ const scrollPosition = this.$.overlay.$.resizerContainer.scrollTop;
239
+ const { width, height } = getComputedStyle(this.$.overlay.$.overlay);
240
+ const content = this.$.overlay.$.content;
241
+ content.setAttribute(
242
+ 'style',
243
+ 'position: absolute; top: 0; right: 0; bottom: 0; left: 0; box-sizing: content-box; height: auto;'
244
+ );
245
+ const { width: contentWidth, height: contentHeight } = getComputedStyle(content);
246
+ content.removeAttribute('style');
247
+ this.$.overlay.$.resizerContainer.scrollTop = scrollPosition;
248
+ return { width, height, contentWidth, contentHeight };
249
+ }
250
+ };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2021 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+
7
+ /**
8
+ * Checks if the argument is a touch event and if so, returns a first touch.
9
+ * Otherwise, if the mouse event was passed, returns it as is.
10
+ */
11
+ declare function getMouseOrFirstTouchEvent(e: MouseEvent | TouchEvent): MouseEvent | Touch;
12
+
13
+ export { getMouseOrFirstTouchEvent };
14
+
15
+ /**
16
+ * Checks whether a mouse or touch event is in window.
17
+ */
18
+ declare function eventInWindow(e: MouseEvent | TouchEvent): boolean;
19
+
20
+ export { eventInWindow };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Checks if the argument is a touch event and if so, returns a first touch.
3
+ * Otherwise, if the mouse event was passed, returns it as is.
4
+ * @param {!MouseEvent | !TouchEvent} e
5
+ * @return {!MouseEvent | !Touch}
6
+ * @protected
7
+ */
8
+ export function getMouseOrFirstTouchEvent(e) {
9
+ return e.touches ? e.touches[0] : e;
10
+ }
11
+
12
+ /**
13
+ * Checks whether a mouse or touch event is in window.
14
+ * @param {!MouseEvent | !TouchEvent} e
15
+ * @return {boolean}
16
+ * @protected
17
+ */
18
+ export function eventInWindow(e) {
19
+ return e.clientX >= 0 && e.clientX <= window.innerWidth && e.clientY >= 0 && e.clientY <= window.innerHeight;
20
+ }
@@ -0,0 +1,165 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2021 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
7
+ import { ThemePropertyMixin } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
8
+ import { DialogDraggableMixin } from './vaadin-dialog-draggable-mixin.js';
9
+ import { DialogResizableMixin } from './vaadin-dialog-resizable-mixin.js';
10
+
11
+ export type DialogRenderer = (root: HTMLElement, dialog?: Dialog) => void;
12
+
13
+ export type DialogResizableDirection = 'n' | 'e' | 's' | 'w' | 'nw' | 'ne' | 'se' | 'sw';
14
+
15
+ export type DialogResizeDimensions = {
16
+ width: string;
17
+ height: string;
18
+ contentWidth: string;
19
+ contentHeight: string;
20
+ };
21
+
22
+ export type DialogOverlayBounds = {
23
+ top: number;
24
+ left: number;
25
+ width: number;
26
+ height: number;
27
+ };
28
+
29
+ export type DialogOverlayBoundsParam =
30
+ | DialogOverlayBounds
31
+ | {
32
+ top?: string | number;
33
+ left?: string | number;
34
+ width?: string | number;
35
+ height?: string | number;
36
+ };
37
+
38
+ /**
39
+ * Fired when the `opened` property changes.
40
+ */
41
+ export type DialogOpenedChangedEvent = CustomEvent<{ value: boolean }>;
42
+
43
+ /**
44
+ * Fired when the dialog resize is finished.
45
+ */
46
+ export type DialogResizeEvent = CustomEvent<DialogResizeDimensions>;
47
+
48
+ export interface DialogCustomEventMap {
49
+ 'opened-changed': DialogOpenedChangedEvent;
50
+
51
+ resize: DialogResizeEvent;
52
+ }
53
+
54
+ export type DialogEventMap = HTMLElementEventMap & DialogCustomEventMap;
55
+
56
+ /**
57
+ * `<vaadin-dialog>` is a Web Component for creating customized modal dialogs.
58
+ *
59
+ * ### Rendering
60
+ *
61
+ * The content of the dialog can be populated by using the renderer callback function.
62
+ *
63
+ * The renderer function provides `root`, `dialog` arguments.
64
+ * Generate DOM content, append it to the `root` element and control the state
65
+ * of the host element by accessing `dialog`. Before generating new content,
66
+ * users are able to check if there is already content in `root` for reusing it.
67
+ *
68
+ * ```html
69
+ * <vaadin-dialog id="dialog"></vaadin-dialog>
70
+ * ```
71
+ * ```js
72
+ * const dialog = document.querySelector('#dialog');
73
+ * dialog.renderer = function(root, dialog) {
74
+ * root.textContent = "Sample dialog";
75
+ * };
76
+ * ```
77
+ *
78
+ * Renderer is called on the opening of the dialog.
79
+ * DOM generated during the renderer call can be reused
80
+ * in the next renderer call and will be provided with the `root` argument.
81
+ * On first call it will be empty.
82
+ *
83
+ * ### Styling
84
+ *
85
+ * `<vaadin-dialog>` uses `<vaadin-dialog-overlay>` internal
86
+ * themable component as the actual visible dialog overlay.
87
+ *
88
+ * See [`<vaadin-overlay>`](#/elements/vaadin-overlay) documentation.
89
+ * for `<vaadin-dialog-overlay>` parts.
90
+ *
91
+ * Note: the `theme` attribute value set on `<vaadin-dialog>` is
92
+ * propagated to the internal `<vaadin-dialog-overlay>` component.
93
+ *
94
+ * See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
95
+ *
96
+ * @fires {CustomEvent} resize - Fired when the dialog resize is finished.
97
+ * @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
98
+ */
99
+ declare class Dialog extends ThemePropertyMixin(ElementMixin(DialogDraggableMixin(DialogResizableMixin(HTMLElement)))) {
100
+ /**
101
+ * True if the overlay is currently displayed.
102
+ */
103
+ opened: boolean;
104
+
105
+ /**
106
+ * Set to true to disable closing dialog on outside click
107
+ * @attr {boolean} no-close-on-outside-click
108
+ */
109
+ noCloseOnOutsideClick: boolean;
110
+
111
+ /**
112
+ * Set to true to disable closing dialog on Escape press
113
+ * @attr {boolean} no-close-on-esc
114
+ */
115
+ noCloseOnEsc: boolean;
116
+
117
+ /**
118
+ * Set the `aria-label` attribute for assistive technologies like
119
+ * screen readers. An empty string value for this property (the
120
+ * default) means that the `aria-label` attribute is not present.
121
+ */
122
+ ariaLabel: string;
123
+
124
+ /**
125
+ * Custom function for rendering the content of the dialog.
126
+ * Receives two arguments:
127
+ *
128
+ * - `root` The root container DOM element. Append your content to it.
129
+ * - `dialog` The reference to the `<vaadin-dialog>` element.
130
+ */
131
+ renderer: DialogRenderer | null | undefined;
132
+
133
+ /**
134
+ * Set to true to remove backdrop and allow click events on background elements.
135
+ */
136
+ modeless: boolean;
137
+
138
+ /**
139
+ * Requests an update for the content of the dialog.
140
+ * While performing the update, it invokes the renderer passed in the `renderer` property.
141
+ *
142
+ * It is not guaranteed that the update happens immediately (synchronously) after it is requested.
143
+ */
144
+ requestContentUpdate(): void;
145
+
146
+ addEventListener<K extends keyof DialogEventMap>(
147
+ type: K,
148
+ listener: (this: Dialog, ev: DialogEventMap[K]) => void,
149
+ options?: boolean | AddEventListenerOptions
150
+ ): void;
151
+
152
+ removeEventListener<K extends keyof DialogEventMap>(
153
+ type: K,
154
+ listener: (this: Dialog, ev: DialogEventMap[K]) => void,
155
+ options?: boolean | EventListenerOptions
156
+ ): void;
157
+ }
158
+
159
+ declare global {
160
+ interface HTMLElementTagNameMap {
161
+ 'vaadin-dialog': Dialog;
162
+ }
163
+ }
164
+
165
+ export { Dialog };