Skip to content

Commit 8be4048

Browse files
authored
feat(ui5-dialog): introduce resizable property (#2301)
Fixes #2082
1 parent cbf2461 commit 8be4048

17 files changed

+250
-7
lines changed

packages/main/src/Dialog.hbs

+8
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,13 @@
1919
<slot name="footer"></slot>
2020
</footer>
2121
{{/if}}
22+
{{#if resizable}}
23+
<ui5-icon
24+
name="resize-corner"
25+
dir="{{effectiveDir}}"
26+
class="ui5-popup-resize-handle"
27+
@mousedown="{{_onResizeMouseDown}}">
28+
</ui5-icon>
29+
{{/if}}
2230
{{/inline}}
2331

packages/main/src/Dialog.js

+145-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { isPhone, isDesktop } from "@ui5/webcomponents-base/dist/Device.js";
22
import Popup from "./Popup.js";
3+
import "@ui5/webcomponents-icons/dist/icons/resize-corner.js";
4+
import Icon from "./Icon.js";
35

46
// Template
57
import DialogTemplate from "./generated/templates/DialogTemplate.lit.js";
@@ -77,6 +79,23 @@ const metadata = {
7779
type: Boolean,
7880
},
7981

82+
/**
83+
* Configures the <code>ui5-dialog</code> to be resizable.
84+
* If this property is set to true, the Dialog will have a resize handle in its bottom right corner in LTR languages.
85+
* In RTL languages, the resize handle will be placed in the bottom left corner.
86+
* <br><br>
87+
* <b>Note:</b> The <code>ui5-dialog</code> can be resizable only in desktop mode.
88+
* <br>
89+
* <b>Note:</b> Upon resizing, externally defined height and width styling will be ignored.
90+
* @type {boolean}
91+
* @defaultvalue false
92+
* @since 1.0.0-rc.10
93+
* @public
94+
*/
95+
resizable: {
96+
type: Boolean,
97+
},
98+
8099
/**
81100
* @private
82101
*/
@@ -137,6 +156,12 @@ class Dialog extends Popup {
137156
return metadata;
138157
}
139158

159+
static get dependencies() {
160+
return [
161+
Icon,
162+
];
163+
}
164+
140165
static get template() {
141166
return DialogTemplate;
142167
}
@@ -168,14 +193,22 @@ class Dialog extends Popup {
168193
};
169194
}
170195

196+
_clamp(val, min, max) {
197+
return Math.min(Math.max(val, min), max);
198+
}
199+
171200
onBeforeRendering() {
201+
this._isRTL = this.effectiveDir === "rtl";
172202
this.onPhone = isPhone();
173203
this.onDesktop = isDesktop();
174204
}
175205

176206
onEnterDOM() {
177207
this._dragMouseMoveHandler = this._onDragMouseMove.bind(this);
178208
this._dragMouseUpHandler = this._onDragMouseUp.bind(this);
209+
210+
this._resizeMouseMoveHandler = this._onResizeMouseMove.bind(this);
211+
this._resizeMouseUpHandler = this._onResizeMouseUp.bind(this);
179212
}
180213

181214
onExitDOM() {
@@ -212,8 +245,8 @@ class Dialog extends Popup {
212245
transform: "none",
213246
top: `${top}px`,
214247
left: `${left}px`,
215-
width: `${Math.round(Number(width) * 100) / 100}px`,
216-
height: `${Math.round(Number(height) * 100) / 100}px`,
248+
width: `${Math.round(Number.parseFloat(width) * 100) / 100}px`,
249+
height: `${Math.round(Number.parseFloat(height) * 100) / 100}px`,
217250
});
218251

219252
this._x = event.clientX;
@@ -232,7 +265,6 @@ class Dialog extends Popup {
232265
top,
233266
} = this.getBoundingClientRect();
234267

235-
236268
Object.assign(this.style, {
237269
left: `${Math.floor(left - calcX)}px`,
238270
top: `${Math.floor(top - calcY)}px`,
@@ -268,6 +300,116 @@ class Dialog extends Popup {
268300
});
269301
this.removeEventListener("ui5-before-close", this._recenter);
270302
}
303+
304+
_onResizeMouseDown(event) {
305+
if (!(this.resizable && this.onDesktop)) {
306+
return;
307+
}
308+
309+
event.preventDefault();
310+
311+
const {
312+
top,
313+
left,
314+
} = this.getBoundingClientRect();
315+
const {
316+
width,
317+
height,
318+
minWidth,
319+
minHeight,
320+
} = window.getComputedStyle(this);
321+
322+
this._initialX = event.clientX;
323+
this._initialY = event.clientY;
324+
this._initialWidth = Number.parseFloat(width);
325+
this._initialHeight = Number.parseFloat(height);
326+
this._initialTop = top;
327+
this._initialLeft = left;
328+
this._minWidth = Number.parseFloat(minWidth);
329+
this._minHeight = Number.parseFloat(minHeight);
330+
331+
Object.assign(this.style, {
332+
transform: "none",
333+
top: `${top}px`,
334+
left: `${left}px`,
335+
});
336+
337+
this._attachResizeHandlers();
338+
}
339+
340+
_onResizeMouseMove(event) {
341+
const { clientX, clientY } = event;
342+
343+
let newWidth;
344+
let newLeft;
345+
346+
if (this._isRTL) {
347+
newWidth = this._clamp(
348+
this._initialWidth - (clientX - this._initialX),
349+
this._minWidth,
350+
this._initialLeft + this._initialWidth
351+
);
352+
353+
newLeft = this._clamp(
354+
this._initialLeft + (clientX - this._initialX),
355+
0,
356+
this._initialX + this._initialWidth - this._minWidth
357+
);
358+
} else {
359+
newWidth = this._clamp(
360+
this._initialWidth + (clientX - this._initialX),
361+
this._minWidth,
362+
window.innerWidth - this._initialLeft
363+
);
364+
}
365+
366+
const newHeight = this._clamp(
367+
this._initialHeight + (clientY - this._initialY),
368+
this._minHeight,
369+
window.innerHeight - this._initialTop
370+
);
371+
372+
Object.assign(this.style, {
373+
height: `${newHeight}px`,
374+
width: `${newWidth}px`,
375+
left: newLeft ? `${newLeft}px` : undefined,
376+
});
377+
}
378+
379+
_onResizeMouseUp() {
380+
this._initialX = null;
381+
this._initialY = null;
382+
this._initialWidth = null;
383+
this._initialHeight = null;
384+
this._initialTop = null;
385+
this._initialLeft = null;
386+
this._minWidth = null;
387+
this._minHeight = null;
388+
389+
this._detachResizeHandlers();
390+
}
391+
392+
_attachResizeHandlers() {
393+
window.addEventListener("mousemove", this._resizeMouseMoveHandler);
394+
window.addEventListener("mouseup", this._resizeMouseUpHandler);
395+
this.addEventListener("ui5-before-close", this._revertSize);
396+
}
397+
398+
_detachResizeHandlers() {
399+
window.removeEventListener("mousemove", this._resizeMouseMoveHandler);
400+
window.removeEventListener("mouseup", this._resizeMouseUpHandler);
401+
}
402+
403+
_revertSize() {
404+
Object.assign(this.style, {
405+
top: "",
406+
left: "",
407+
width: "",
408+
height: "",
409+
transform: "",
410+
});
411+
this.removeEventListener("ui5-before-close", this._revertSize);
412+
}
271413
}
272414

273415
Dialog.define();

packages/main/src/themes/Dialog.css

+16
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
left: 50%;
44
transform: translate(-50%, -50%);
55
min-width: 20rem;
6+
min-height: 6rem;
67
box-shadow: var(--sapContent_Shadow3);
78
}
89

@@ -37,5 +38,20 @@
3738
}
3839

3940
.ui5-popup-content {
41+
min-height: var(--_ui5_dialog_content_min_height);
4042
flex: 1 1 auto;
43+
}
44+
45+
.ui5-popup-resize-handle {
46+
position: absolute;
47+
bottom: -0.0625rem;
48+
right: -0.25rem;
49+
cursor: se-resize;
50+
color: var(--_ui5_dialog_resize_handle_color);
51+
}
52+
53+
.ui5-popup-resize-handle[dir=rtl] {
54+
left: -0.25rem;
55+
right: unset;
56+
cursor: sw-resize;
4157
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:root {
2+
--_ui5_dialog_resize_handle_color: var(--sapButton_Lite_TextColor);
3+
}

packages/main/src/themes/base/sizes-parameters.css

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
--_ui5_datetime_timeview_phonemode_width: 19.5rem;
1818
--_ui5_datetime_timeview_padding: 1rem;
1919

20+
/* Dialog */
21+
--_ui5_dialog_content_min_height: 2.75rem;
22+
2023
--_ui5_input_inner_padding: 0 0.625rem;
2124
--_ui5_input_inner_padding_with_icon: 0 0.25rem 0 0.625rem;
2225
--_ui5_input_value_state_icon_padding: var(--_ui5-input-icon-padding);
@@ -116,6 +119,9 @@
116119
--_ui5_datetime_timeview_phonemode_width: 18.5rem;
117120
--_ui5_datetime_timeview_padding: 0.5rem;
118121

122+
/* Dialog */
123+
--_ui5_dialog_content_min_height: 2.5rem;
124+
119125
/* Input */
120126
--_ui5_input_height: var(--_ui5_input_compact_height);
121127
--_ui5_input_inner_padding: 0 0.5rem;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@import "../base/Dialog-parameters.css";
2+
3+
:root {
4+
--_ui5_dialog_resize_handle_color: var(--sapButton_Emphasized_Background);
5+
}

packages/main/src/themes/sap_belize/parameters-bundle.css

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
@import "./Button-parameters.css";
55
@import "../base/DatePicker-parameters.css";
66
@import "../base/DayPicker-parameters.css";
7+
@import "./Dialog-parameters.css";
78
@import "../base/CalendarHeader-parameters.css";
89
@import "./Carousel-parameters.css";
910
@import "../base/Card-parameters.css";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@import "../base/Dialog-parameters.css";
2+
3+
:root {
4+
--_ui5_dialog_resize_handle_color: var(--sapContent_IconColor);
5+
}

packages/main/src/themes/sap_belize_hcb/parameters-bundle.css

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
@import "./CheckBox-parameters.css";
99
@import "./DatePicker-parameters.css";
1010
@import "./DayPicker-parameters.css";
11+
@import "./Dialog-parameters.css";
1112
@import "../base/GroupHeaderListItem-parameters.css";
1213
@import "./Input-parameters.css";
1314
@import "./InputIcon-parameters.css";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@import "../base/Dialog-parameters.css";
2+
3+
:root {
4+
--_ui5_dialog_resize_handle_color: var(--sapContent_IconColor);
5+
}

packages/main/src/themes/sap_belize_hcw/parameters-bundle.css

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
@import "./CheckBox-parameters.css";
99
@import "./DatePicker-parameters.css";
1010
@import "./DayPicker-parameters.css";
11+
@import "./Dialog-parameters.css";
1112
@import "../base/GroupHeaderListItem-parameters.css";
1213
@import "./Input-parameters.css";
1314
@import "./InputIcon-parameters.css";

packages/main/src/themes/sap_fiori_3/parameters-bundle.css

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
@import "./CheckBox-parameters.css";
88
@import "../base/DatePicker-parameters.css";
99
@import "./DayPicker-parameters.css";
10+
@import "../base/Dialog-parameters.css";
1011
@import "../base/GroupHeaderListItem-parameters.css";
1112
@import "./Input-parameters.css";
1213
@import "../base/InputIcon-parameters.css";

packages/main/src/themes/sap_fiori_3_dark/parameters-bundle.css

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
@import "./CheckBox-parameters.css";
88
@import "../base/DatePicker-parameters.css";
99
@import "./DayPicker-parameters.css";
10+
@import "../base/Dialog-parameters.css";
1011
@import "../base/GroupHeaderListItem-parameters.css";
1112
@import "./Input-parameters.css";
1213
@import "../base/InputIcon-parameters.css";

packages/main/src/themes/sap_fiori_3_hcb/parameters-bundle.css

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
@import "./CheckBox-parameters.css";
99
@import "./DatePicker-parameters.css";
1010
@import "./DayPicker-parameters.css";
11+
@import "../base/Dialog-parameters.css";
1112
@import "../base/GroupHeaderListItem-parameters.css";
1213
@import "./Input-parameters.css";
1314
@import "./InputIcon-parameters.css";

packages/main/src/themes/sap_fiori_3_hcw/parameters-bundle.css

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
@import "./CheckBox-parameters.css";
99
@import "./DatePicker-parameters.css";
1010
@import "./DayPicker-parameters.css";
11+
@import "../base/Dialog-parameters.css";
1112
@import "../base/GroupHeaderListItem-parameters.css";
1213
@import "./Input-parameters.css";
1314
@import "./InputIcon-parameters.css";

packages/main/test/pages/Dialog.html

+15-2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@
4747
<br>
4848
<br>
4949
<ui5-button id="draggable-open">Open draggable dialog</ui5-button>
50+
<br>
51+
<br>
52+
<ui5-button id="resizable-open">Open resizable dialog</ui5-button>
5053

5154
<ui5-block-layer></ui5-block-layer>
5255

@@ -200,6 +203,15 @@
200203
</div>
201204
</ui5-dialog>
202205

206+
<ui5-dialog id="resizable-dialog" header-text="Resizable dialog" resizable>
207+
<p>Resize this dialog by dragging it by its resize handle.</p>
208+
<p>This feature available only on Desktop.</p>
209+
210+
<div slot="footer" style="display: flex; justify-content: flex-end; width: 100%; padding: .25rem 1rem;">
211+
<ui5-button id="resizable-close" design="Emphasized">OK</ui5-button>
212+
</div>
213+
</ui5-dialog>
214+
203215
<ui5-popover header-text="My Heading" id="pop" style="width: 300px" placement-type="Top">
204216
<!-- <div slot="header">
205217
Hello World
@@ -316,8 +328,9 @@
316328
window["wide-open2"].addEventListener("click", function () { window["wide-dialog2"].open(); });
317329
window["draggable-open"].addEventListener("click", function () { window["draggable-dialog"].open(); });
318330
window["draggable-close"].addEventListener("click", function () { window["draggable-dialog"].close(); });
319-
331+
window["resizable-open"].addEventListener("click", function () { window["resizable-dialog"].open(); });
332+
window["resizable-close"].addEventListener("click", function () { window["resizable-dialog"].close(); });
320333
</script>
321334
</body>
322335

323-
</html>
336+
</html>

0 commit comments

Comments
 (0)