@schukai/monster 3.75.0 → 3.76.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.
- package/CHANGELOG.md +21 -8
- package/package.json +1 -1
- package/source/components/layout/collapse.mjs +361 -395
- package/source/components/layout/details.mjs +10 -40
- package/source/components/layout/iframe.mjs +358 -0
- package/source/components/layout/panel.mjs +10 -25
- package/source/components/layout/slider.mjs +11 -11
- package/source/components/layout/split-panel.mjs +7 -39
- package/source/components/layout/style/iframe.pcss +39 -0
- package/source/components/layout/style/panel.pcss +10 -3
- package/source/components/layout/style/split-panel.pcss +2 -0
- package/source/components/layout/stylesheet/iframe.mjs +38 -0
- package/source/components/layout/stylesheet/panel.mjs +1 -1
- package/source/components/layout/tabs.mjs +6 -35
- package/source/components/layout/width-toggle.mjs +10 -31
- package/source/components/tree-menu/tree-menu.mjs +16 -12
- package/source/math/random.mjs +2 -3
- package/source/monster.mjs +2 -1
- package/test/cases/components/form/button.mjs +2 -1
- package/test/cases/components/form/confirm-button.mjs +1 -1
- package/test/cases/components/form/form.mjs +1 -1
- package/test/cases/components/form/reload.mjs +1 -1
- package/test/cases/components/form/select.mjs +1 -1
- package/test/cases/components/form/state-button.mjs +1 -1
- package/test/cases/components/form/template.mjs +1 -1
- package/test/cases/components/form/toggle-switch.mjs +1 -1
- package/test/cases/components/form/tree-select.mjs +1 -1
- package/test/cases/components/host/details.mjs +1 -1
- package/test/cases/components/host/host.mjs +1 -1
- package/test/cases/components/host/overlay.mjs +1 -1
- package/test/cases/components/layout/panel.mjs +1 -1
- package/test/cases/components/layout/slit-panel.mjs +1 -1
- package/test/cases/components/layout/tabs.mjs +1 -1
- package/test/cases/components/notify/message.mjs +1 -1
- package/test/cases/components/notify/notify.mjs +1 -1
- package/test/cases/dom/customcontrol.mjs +1 -1
- package/test/cases/dom/customelement-initfromscripthost.mjs +1 -1
- package/test/cases/dom/customelement.mjs +1 -1
- package/test/cases/dom/resource/data.mjs +1 -1
- package/test/cases/dom/resource/link/stylesheet.mjs +1 -1
- package/test/cases/dom/resource/link.mjs +1 -1
- package/test/cases/dom/resource/script.mjs +1 -1
- package/test/cases/dom/updater.mjs +1 -1
|
@@ -38,49 +38,15 @@ const buttonElementSymbol = Symbol("buttonElement");
|
|
|
38
38
|
const buttonEventHandlerSymbol = Symbol("buttonEventHandler");
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
*
|
|
41
|
+
* A Details component
|
|
42
42
|
*
|
|
43
|
-
*
|
|
43
|
+
* @fragments /fragments/components/layout/details/
|
|
44
44
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* You can create this control either by specifying the HTML tag <monster-details />` directly in the HTML or using
|
|
48
|
-
* Javascript via the `document.createElement('monster-details');` method.
|
|
49
|
-
*
|
|
50
|
-
* ```html
|
|
51
|
-
* <monster-details></monster-details>
|
|
52
|
-
* ```
|
|
53
|
-
*
|
|
54
|
-
* Or you can create this CustomControl directly in Javascript:
|
|
55
|
-
*
|
|
56
|
-
* ```js
|
|
57
|
-
* import '@schukai/component-state/source/details.mjs';
|
|
58
|
-
* document.createElement('monster-details');
|
|
59
|
-
* ```
|
|
60
|
-
*
|
|
61
|
-
* The Body should have a class "hidden" to ensure that the styles are applied correctly.
|
|
62
|
-
*
|
|
63
|
-
* ```css
|
|
64
|
-
* body.hidden {
|
|
65
|
-
* visibility: hidden;
|
|
66
|
-
* }
|
|
67
|
-
* ```
|
|
68
|
-
*
|
|
69
|
-
* @startuml details.png
|
|
70
|
-
* skinparam monochrome true
|
|
71
|
-
* skinparam shadowing false
|
|
72
|
-
* HTMLElement <|-- CustomElement
|
|
73
|
-
* CustomElement <|-- Collapse
|
|
74
|
-
* Collapse <|-- Details
|
|
75
|
-
* @enduml
|
|
45
|
+
* @example /examples/components/layout/details-simple
|
|
76
46
|
*
|
|
47
|
+
* @since 3.74.0
|
|
77
48
|
* @copyright schukai GmbH
|
|
78
|
-
* @
|
|
79
|
-
* @summary A simple details component
|
|
80
|
-
* @fires Monster.Components.Layout.Details.event:monster-details-before-open
|
|
81
|
-
* @fires Monster.Components.Layout.Details.event:monster-details-open
|
|
82
|
-
* @fires Monster.Components.Layout.Details.event:monster-details-before-close
|
|
83
|
-
* @fires Monster.Components.Layout.Details.event:monster-details-closed
|
|
49
|
+
* @summary A simple but cool Details component
|
|
84
50
|
*/
|
|
85
51
|
class Details extends Collapse {
|
|
86
52
|
/**
|
|
@@ -215,13 +181,17 @@ function initButtonLabel() {
|
|
|
215
181
|
if (this.hasAttribute(ATTRIBUTE_BUTTON_LABEL)) {
|
|
216
182
|
label = this.getAttribute(ATTRIBUTE_BUTTON_LABEL);
|
|
217
183
|
} else {
|
|
218
|
-
label = this.
|
|
184
|
+
label = this.getOption("labels.button", "Details");
|
|
219
185
|
}
|
|
220
186
|
|
|
221
187
|
if (!isString(label)) {
|
|
222
188
|
label = "";
|
|
223
189
|
}
|
|
224
190
|
|
|
191
|
+
if (label==="") {
|
|
192
|
+
label = this.innerText;
|
|
193
|
+
}
|
|
194
|
+
|
|
225
195
|
label = label.trim();
|
|
226
196
|
|
|
227
197
|
if (label === "") {
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved.
|
|
3
|
+
* Node module: @schukai/monster
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
|
|
6
|
+
* The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
|
|
7
|
+
*
|
|
8
|
+
* For those who do not wish to adhere to the AGPLv3, a commercial license is available.
|
|
9
|
+
* Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
|
|
10
|
+
* For more information about purchasing a commercial license, please contact schukai GmbH.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { instanceSymbol } from "../../constants.mjs";
|
|
14
|
+
import { addAttributeToken } from "../../dom/attributes.mjs";
|
|
15
|
+
import {
|
|
16
|
+
ATTRIBUTE_ERRORMESSAGE,
|
|
17
|
+
ATTRIBUTE_ROLE,
|
|
18
|
+
} from "../../dom/constants.mjs";
|
|
19
|
+
import { CustomControl } from "../../dom/customcontrol.mjs";
|
|
20
|
+
import { CustomElement } from "../../dom/customelement.mjs";
|
|
21
|
+
import {
|
|
22
|
+
assembleMethodSymbol,
|
|
23
|
+
registerCustomElement,
|
|
24
|
+
} from "../../dom/customelement.mjs";
|
|
25
|
+
import { findTargetElementFromEvent } from "../../dom/events.mjs";
|
|
26
|
+
import { isFunction } from "../../types/is.mjs";
|
|
27
|
+
import { DeadMansSwitch } from "../../util/deadmansswitch.mjs";
|
|
28
|
+
import { IframeStyleSheet } from "./stylesheet/iframe.mjs";
|
|
29
|
+
import { fireCustomEvent } from "../../dom/events.mjs";
|
|
30
|
+
|
|
31
|
+
export { Iframe };
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @private
|
|
35
|
+
* @type {symbol}
|
|
36
|
+
*/
|
|
37
|
+
export const iframeElementSymbol = Symbol("iframeElement");
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @private
|
|
41
|
+
* @type {symbol}
|
|
42
|
+
*/
|
|
43
|
+
const PanelElementSymbol = Symbol("PanelElement");
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* local symbol
|
|
47
|
+
* @private
|
|
48
|
+
* @type {symbol}
|
|
49
|
+
*/
|
|
50
|
+
const resizeObserverSymbol = Symbol("resizeObserver");
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @private
|
|
54
|
+
* @type {symbol}
|
|
55
|
+
*/
|
|
56
|
+
const timerCallbackSymbol = Symbol("timerCallback");
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* A Iframe Control
|
|
60
|
+
*
|
|
61
|
+
* @fragments /fragments/components/layout/iframe/
|
|
62
|
+
*
|
|
63
|
+
* @example /examples/components/layout/iframe-simple
|
|
64
|
+
*
|
|
65
|
+
* @since 3.76.0
|
|
66
|
+
* @copyright schukai GmbH
|
|
67
|
+
* @summary A cool and fancy Iframe that can make your life easier and also looks good.
|
|
68
|
+
*/
|
|
69
|
+
class Iframe extends CustomElement {
|
|
70
|
+
/**
|
|
71
|
+
* This method is called by the `instanceof` operator.
|
|
72
|
+
* @returns {symbol}
|
|
73
|
+
*/
|
|
74
|
+
static get [instanceSymbol]() {
|
|
75
|
+
return Symbol.for("@schukai/monster/components/layout/iframe@@instance");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
*
|
|
80
|
+
* @return {Components.Layout.Iframe
|
|
81
|
+
*/
|
|
82
|
+
[assembleMethodSymbol]() {
|
|
83
|
+
super[assembleMethodSymbol]();
|
|
84
|
+
initControlReferences.call(this);
|
|
85
|
+
initEventHandler.call(this);
|
|
86
|
+
calcHeight.call(this);
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* This method is called by the dom and should not be called directly.
|
|
92
|
+
*
|
|
93
|
+
* @return {void}
|
|
94
|
+
*/
|
|
95
|
+
connectedCallback() {
|
|
96
|
+
super.connectedCallback();
|
|
97
|
+
attachResizeObserver.call(this);
|
|
98
|
+
|
|
99
|
+
// disable scrolling in parent node
|
|
100
|
+
if (this.parentNode && this.parentNode instanceof HTMLElement) {
|
|
101
|
+
this.parentNode.style.overflow = "hidden";
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* This method is called by the dom and should not be called directly.
|
|
107
|
+
*
|
|
108
|
+
* @return {void}
|
|
109
|
+
*/
|
|
110
|
+
disconnectedCallback() {
|
|
111
|
+
super.disconnectedCallback();
|
|
112
|
+
disconnectResizeObserver.call(this);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* To set the options via the HTML Tag the attribute `data-monster-options` must be used.
|
|
117
|
+
* @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
|
|
118
|
+
*
|
|
119
|
+
* The individual configuration values can be found in the table.
|
|
120
|
+
*
|
|
121
|
+
* @property {Object} templates Template definitions
|
|
122
|
+
* @property {string} templates.main Main template
|
|
123
|
+
* @property {Object} labels Label definitions
|
|
124
|
+
* @property {Object} actions Callbacks
|
|
125
|
+
* @property {string} actions.click="throw Error" Callback when clicked
|
|
126
|
+
* @property {Object} features Features
|
|
127
|
+
* @property {Object} classes CSS classes
|
|
128
|
+
* @property {boolean} disabled=false Disabled state
|
|
129
|
+
*/
|
|
130
|
+
get defaults() {
|
|
131
|
+
return Object.assign({}, super.defaults, {
|
|
132
|
+
templates: {
|
|
133
|
+
main: getTemplate(),
|
|
134
|
+
},
|
|
135
|
+
src: null,
|
|
136
|
+
|
|
137
|
+
/* "allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-top-navigation"*/
|
|
138
|
+
sandbox: null,
|
|
139
|
+
|
|
140
|
+
labels: {},
|
|
141
|
+
classes: {},
|
|
142
|
+
|
|
143
|
+
name: "",
|
|
144
|
+
|
|
145
|
+
referrerpolicy: "no-referrer",
|
|
146
|
+
|
|
147
|
+
disabled: false,
|
|
148
|
+
features: {
|
|
149
|
+
allowfullscreen: true,
|
|
150
|
+
allowpaymentrequest: true,
|
|
151
|
+
loading: "egager",
|
|
152
|
+
},
|
|
153
|
+
actions: {
|
|
154
|
+
click: () => {
|
|
155
|
+
throw new Error("the click action is not defined");
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* @return {string}
|
|
163
|
+
*/
|
|
164
|
+
static getTag() {
|
|
165
|
+
return "monster-iframe";
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* @return {CSSStyleSheet[]}
|
|
170
|
+
*/
|
|
171
|
+
static getCSSStyleSheet() {
|
|
172
|
+
return [IframeStyleSheet];
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @private
|
|
178
|
+
*/
|
|
179
|
+
function calcHeight() {
|
|
180
|
+
this.style.boxSizing = "border-box";
|
|
181
|
+
|
|
182
|
+
const height = calculateMaximumHeight.call(this, this.parentNode);
|
|
183
|
+
console.log("height", height);
|
|
184
|
+
if (height < 0 || isNaN(height)) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
this[iframeElementSymbol].style.height = `${height}px`;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Calculate the maximum height of an element based on the window's inner height
|
|
193
|
+
* @param element
|
|
194
|
+
* @returns {*}
|
|
195
|
+
*/
|
|
196
|
+
function calculateMaximumHeight(element) {
|
|
197
|
+
let totalBottomBorder = 0;
|
|
198
|
+
let totalBottomPadding = 0;
|
|
199
|
+
let totalBottomMargin = 0;
|
|
200
|
+
let totalOutlineHeight = 0;
|
|
201
|
+
let totalBoxShadowHeight = 0;
|
|
202
|
+
let currentElement = element;
|
|
203
|
+
|
|
204
|
+
while (currentElement && currentElement !== document.body) {
|
|
205
|
+
const style = window.getComputedStyle(currentElement);
|
|
206
|
+
const boxSizing = style.boxSizing;
|
|
207
|
+
|
|
208
|
+
const elementHeight = currentElement.getBoundingClientRect().height;
|
|
209
|
+
|
|
210
|
+
const borderBottomWidth = parseFloat(style.borderBottomWidth);
|
|
211
|
+
const paddingBottom = parseFloat(style.paddingBottom);
|
|
212
|
+
const marginBottom = parseFloat(style.marginBottom);
|
|
213
|
+
|
|
214
|
+
const outlineHeight = parseFloat(style.outlineWidth);
|
|
215
|
+
|
|
216
|
+
totalBottomBorder += isNaN(borderBottomWidth) ? 0 : borderBottomWidth;
|
|
217
|
+
totalBottomPadding +=
|
|
218
|
+
isNaN(paddingBottom) || boxSizing === "border-box" ? 0 : paddingBottom;
|
|
219
|
+
totalBottomMargin += isNaN(marginBottom) ? 0 : marginBottom;
|
|
220
|
+
totalOutlineHeight += isNaN(outlineHeight) ? 0 : outlineHeight;
|
|
221
|
+
|
|
222
|
+
const boxShadow = style.boxShadow;
|
|
223
|
+
let boxShadowVerticalTotal = 0;
|
|
224
|
+
|
|
225
|
+
if (boxShadow !== "none") {
|
|
226
|
+
const boxShadowValues = boxShadow.split(" ");
|
|
227
|
+
const verticalOffset = parseFloat(boxShadowValues[3]);
|
|
228
|
+
const blurRadius = parseFloat(boxShadowValues[4]);
|
|
229
|
+
const spreadRadius = parseFloat(boxShadowValues[5]);
|
|
230
|
+
|
|
231
|
+
boxShadowVerticalTotal = verticalOffset + blurRadius + spreadRadius;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
totalBoxShadowHeight += isNaN(boxShadowVerticalTotal)
|
|
235
|
+
? 0
|
|
236
|
+
: boxShadowVerticalTotal;
|
|
237
|
+
|
|
238
|
+
if (elementHeight > 200) {
|
|
239
|
+
return (
|
|
240
|
+
elementHeight -
|
|
241
|
+
totalBottomBorder -
|
|
242
|
+
totalBottomPadding -
|
|
243
|
+
totalBottomMargin -
|
|
244
|
+
totalOutlineHeight -
|
|
245
|
+
totalBoxShadowHeight
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
currentElement = currentElement.parentNode || currentElement.host;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* @private
|
|
255
|
+
*/
|
|
256
|
+
function attachResizeObserver() {
|
|
257
|
+
// against flickering
|
|
258
|
+
this[resizeObserverSymbol] = new ResizeObserver(() => {
|
|
259
|
+
if (this[timerCallbackSymbol] instanceof DeadMansSwitch) {
|
|
260
|
+
try {
|
|
261
|
+
this[timerCallbackSymbol].touch();
|
|
262
|
+
return;
|
|
263
|
+
} catch (e) {
|
|
264
|
+
delete this[timerCallbackSymbol];
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
this[timerCallbackSymbol] = new DeadMansSwitch(200, () => {
|
|
269
|
+
calcHeight.call(this);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
this[resizeObserverSymbol].observe(this.ownerDocument.body);
|
|
274
|
+
this[resizeObserverSymbol].observe(document.scrollingElement);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function disconnectResizeObserver() {
|
|
278
|
+
if (this[resizeObserverSymbol] instanceof ResizeObserver) {
|
|
279
|
+
this[resizeObserverSymbol].disconnect();
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* @private
|
|
285
|
+
* @return {initEventHandler}
|
|
286
|
+
* @fires monster-iframe-clicked
|
|
287
|
+
*/
|
|
288
|
+
function initEventHandler() {
|
|
289
|
+
const self = this;
|
|
290
|
+
const element = this[iframeElementSymbol];
|
|
291
|
+
|
|
292
|
+
const type = "click";
|
|
293
|
+
|
|
294
|
+
element.addEventListener(type, function (event) {
|
|
295
|
+
const callback = self.getOption("actions.click");
|
|
296
|
+
|
|
297
|
+
fireCustomEvent(self, "monster-iframe-clicked", {
|
|
298
|
+
element: self,
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
if (!isFunction(callback)) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const element = findTargetElementFromEvent(
|
|
306
|
+
event,
|
|
307
|
+
ATTRIBUTE_ROLE,
|
|
308
|
+
"control",
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
if (!(element instanceof Node && self.hasNode(element))) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
callback.call(self, event);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
return this;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* @private
|
|
323
|
+
* @return {void}
|
|
324
|
+
*/
|
|
325
|
+
function initControlReferences() {
|
|
326
|
+
if (!this.shadowRoot) {
|
|
327
|
+
throw new Error("no shadow-root is defined");
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
this[PanelElementSymbol] = this.shadowRoot.querySelector(
|
|
331
|
+
"[data-monster-role=control]",
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
this[iframeElementSymbol] = this.shadowRoot.querySelector(
|
|
335
|
+
`[${ATTRIBUTE_ROLE}="control"] iframe`,
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* @private
|
|
341
|
+
* @return {string}
|
|
342
|
+
*/
|
|
343
|
+
function getTemplate() {
|
|
344
|
+
// language=HTML
|
|
345
|
+
return `
|
|
346
|
+
<div data-monster-role="control" part="control">
|
|
347
|
+
<iframe data-monster-role="iframe"
|
|
348
|
+
data-monster-attributes="sandbox path:sandbox,
|
|
349
|
+
name path:name,
|
|
350
|
+
referrerpolicy path:referrerpolicy,
|
|
351
|
+
loading path:features.loading,
|
|
352
|
+
allowpaymentrequest path:features.allowpaymentrequest,
|
|
353
|
+
allowfullscreen path:features.allowfullscreen,
|
|
354
|
+
src path:src"
|
|
355
|
+
></iframe></div>`;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
registerCustomElement(Iframe);
|
|
@@ -44,35 +44,15 @@ const resizeObserverSymbol = Symbol("resizeObserver");
|
|
|
44
44
|
const timerCallbackSymbol = Symbol("timerCallback");
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
47
|
+
* A Slider
|
|
48
48
|
*
|
|
49
|
-
*
|
|
49
|
+
* @fragments /fragments/components/layout/panel/
|
|
50
50
|
*
|
|
51
|
-
*
|
|
52
|
-
* Javascript via the `document.createElement('monster-panel');` method.
|
|
53
|
-
*
|
|
54
|
-
* ```html
|
|
55
|
-
* <monster-panel></monster-panel>
|
|
56
|
-
* ```
|
|
57
|
-
*
|
|
58
|
-
* Or you can create this CustomControl directly in Javascript:
|
|
59
|
-
*
|
|
60
|
-
* ```js
|
|
61
|
-
* import '@schukai/monster/components/layout/panel.mjs';
|
|
62
|
-
* document.createElement('monster-panel');
|
|
63
|
-
* ```
|
|
64
|
-
*
|
|
65
|
-
* @startuml panel.png
|
|
66
|
-
* skinparam monochrome true
|
|
67
|
-
* skinparam shadowing false
|
|
68
|
-
* HTMLElement <|-- CustomElement
|
|
69
|
-
* CustomElement <|-- CustomControl
|
|
70
|
-
* CustomControl <|-- Panel
|
|
71
|
-
* @enduml
|
|
51
|
+
* @example /examples/components/layout/panel-simple
|
|
72
52
|
*
|
|
53
|
+
* @since 3.54.0
|
|
73
54
|
* @copyright schukai GmbH
|
|
74
|
-
* @
|
|
75
|
-
* @summary A simple panel component
|
|
55
|
+
* @summary The Panel component is used to display a panel, isn't that cool?
|
|
76
56
|
*/
|
|
77
57
|
class Panel extends CustomElement {
|
|
78
58
|
/**
|
|
@@ -169,6 +149,11 @@ function calcHeight() {
|
|
|
169
149
|
this.style.height = `${height}px`;
|
|
170
150
|
}
|
|
171
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Calculate the maximum height of an element based on the window's inner height
|
|
154
|
+
* @param element
|
|
155
|
+
* @returns {*}
|
|
156
|
+
*/
|
|
172
157
|
function calculateMaximumHeight(element) {
|
|
173
158
|
let totalBottomBorder = 0;
|
|
174
159
|
let totalBottomPadding = 0;
|
|
@@ -58,14 +58,14 @@ const configSymbol = Symbol("config");
|
|
|
58
58
|
* @private
|
|
59
59
|
* @type {string}
|
|
60
60
|
*/
|
|
61
|
-
const
|
|
61
|
+
const ATTRIBUTE_CLONE_FROM = ATTRIBUTE_PREFIX + "clone-from";
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
64
|
* A Slider
|
|
65
65
|
*
|
|
66
|
-
* @fragments /fragments/components/
|
|
66
|
+
* @fragments /fragments/components/layout/slider/
|
|
67
67
|
*
|
|
68
|
-
* @example /examples/components/
|
|
68
|
+
* @example /examples/components/layout/slider-simple
|
|
69
69
|
*
|
|
70
70
|
* @since 3.74.0
|
|
71
71
|
* @copyright schukai GmbH
|
|
@@ -120,7 +120,7 @@ class Slider extends CustomElement {
|
|
|
120
120
|
* @property {Object} autoPlay Auto play configuration
|
|
121
121
|
* @property {number} autoPlay.delay=1500 Delay between slides
|
|
122
122
|
* @property {number} autoPlay.startDelay=1000 Start delay
|
|
123
|
-
* @property {string} autoPlay.direction="next" Direction of the
|
|
123
|
+
* @property {string} autoPlay.direction="next" Direction of the autoplay
|
|
124
124
|
* @property {boolean} autoPlay.mouseOverPause=true Pause on mouse over
|
|
125
125
|
* @property {boolean} autoPlay.touchPause=true Pause on touch
|
|
126
126
|
* @property {Object} classes CSS classes
|
|
@@ -352,10 +352,10 @@ function initCarousel() {
|
|
|
352
352
|
const { slides, totalSlides } = getSlidesAndTotal.call(this);
|
|
353
353
|
if (this.getOption("features.carousel") && totalSlides > 2) {
|
|
354
354
|
const firstElement = slides[0].cloneNode(true);
|
|
355
|
-
firstElement.setAttribute(
|
|
355
|
+
firstElement.setAttribute(ATTRIBUTE_CLONE_FROM, 1);
|
|
356
356
|
|
|
357
357
|
const lastElement = slides[totalSlides - 1].cloneNode(true);
|
|
358
|
-
lastElement.setAttribute(
|
|
358
|
+
lastElement.setAttribute(ATTRIBUTE_CLONE_FROM, totalSlides);
|
|
359
359
|
slides[totalSlides - 1].insertAdjacentElement("afterend", firstElement);
|
|
360
360
|
|
|
361
361
|
slides[0].insertAdjacentElement("beforebegin", lastElement);
|
|
@@ -462,8 +462,8 @@ function moveTo(index) {
|
|
|
462
462
|
if (this.getOption("features.carousel")) {
|
|
463
463
|
slideIndex = index - 1;
|
|
464
464
|
|
|
465
|
-
if (slides[index].hasAttribute(
|
|
466
|
-
const from = parseInt(slides[index].getAttribute(
|
|
465
|
+
if (slides[index].hasAttribute(ATTRIBUTE_CLONE_FROM)) {
|
|
466
|
+
const from = parseInt(slides[index].getAttribute(ATTRIBUTE_CLONE_FROM));
|
|
467
467
|
|
|
468
468
|
getWindow().requestAnimationFrame(() => {
|
|
469
469
|
getWindow().requestAnimationFrame(() => {
|
|
@@ -633,14 +633,14 @@ function getTemplate() {
|
|
|
633
633
|
// language=HTML
|
|
634
634
|
return `
|
|
635
635
|
<div data-monster-role="control" part="control">
|
|
636
|
-
<div class="prev" data-monster-role="prev" part="prev">
|
|
636
|
+
<div class="prev" data-monster-role="prev" part="prev" part="prev">
|
|
637
637
|
<slot name="prev"></slot>
|
|
638
638
|
</div>
|
|
639
|
-
<div data-monster-role="slider">
|
|
639
|
+
<div data-monster-role="slider" part="slides">
|
|
640
640
|
<slot></slot>
|
|
641
641
|
</div>
|
|
642
642
|
<div data-monster-role="thumbnails"></div>
|
|
643
|
-
<div class="next" data-monster-role="next" part="next">
|
|
643
|
+
<div class="next" data-monster-role="next" part="next" part="next">
|
|
644
644
|
<slot name="next"></slot>
|
|
645
645
|
</div>
|
|
646
646
|
</div>`;
|
|
@@ -65,49 +65,17 @@ const TYPE_VERTICAL = "vertical";
|
|
|
65
65
|
const TYPE_HORIZONTAL = "horizontal";
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
|
-
*
|
|
69
|
-
* into two parts. The split can be either vertical or horizontal. The control provides a
|
|
70
|
-
* draggable handle that allows you to adjust the size of the two panels.
|
|
71
|
-
*
|
|
72
|
-
* <img src="./images/split-panel.png">
|
|
73
|
-
*
|
|
74
|
-
* You can create this control either by specifying the HTML tag <monster-split-panel />`
|
|
75
|
-
* directly in the HTML or using Javascript via the `document.createElement('monster-split-panel');`
|
|
76
|
-
* method.
|
|
77
|
-
*
|
|
78
|
-
* ```html
|
|
79
|
-
* <monster-split-panel></monster-split-panel>
|
|
80
|
-
* ```
|
|
81
|
-
*
|
|
82
|
-
* Or you can create this CustomControl directly in Javascript:
|
|
68
|
+
* A SplitPanel Control
|
|
83
69
|
*
|
|
84
|
-
*
|
|
85
|
-
* import '@schukai/monster/components/layout/split-panel.mjs';
|
|
86
|
-
* document.createElement('monster-split-panel');
|
|
87
|
-
* ```
|
|
70
|
+
* @fragments /fragments/components/layout/split-panel/
|
|
88
71
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* ```css
|
|
92
|
-
* <style>
|
|
93
|
-
* *:not(:defined) {
|
|
94
|
-
* visibility: hidden;
|
|
95
|
-
* }
|
|
96
|
-
* </style>
|
|
97
|
-
* ```
|
|
98
|
-
*
|
|
99
|
-
* @startuml split-panel.png
|
|
100
|
-
* skinparam monochrome true
|
|
101
|
-
* skinparam shadowing false
|
|
102
|
-
* HTMLElement <|-- CustomElement
|
|
103
|
-
* CustomElement <|-- CustomControl
|
|
104
|
-
* CustomControl <|-- SplitPanel
|
|
105
|
-
* @enduml
|
|
72
|
+
* @example /examples/components/layout/split-panel-simple
|
|
106
73
|
*
|
|
74
|
+
* @since 3.54.0
|
|
107
75
|
* @copyright schukai GmbH
|
|
108
|
-
* @
|
|
109
|
-
*
|
|
110
|
-
*
|
|
76
|
+
* @summary The SplitPanel control is a simple layout control that allows you to split the screen
|
|
77
|
+
* into two parts. The split can be either vertical or horizontal. The control provides a
|
|
78
|
+
* draggable handle that allows you to adjust the size of the two panels.
|
|
111
79
|
*/
|
|
112
80
|
class SplitPanel extends CustomElement {
|
|
113
81
|
/**
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
|
|
2
|
+
:host {
|
|
3
|
+
display: block;
|
|
4
|
+
border: none;
|
|
5
|
+
box-sizing: border-box;
|
|
6
|
+
padding: 0;
|
|
7
|
+
margin: 0;
|
|
8
|
+
height: fill-available;
|
|
9
|
+
height: -moz-available;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
iframe {
|
|
14
|
+
display: block;
|
|
15
|
+
border: none;
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
|
|
18
|
+
padding: 0;
|
|
19
|
+
margin: 0;
|
|
20
|
+
|
|
21
|
+
height: fill-available;
|
|
22
|
+
height: stretch;
|
|
23
|
+
width: 100%;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
[data-monster-role="control"] {
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
align-items: center;
|
|
31
|
+
justify-content: center;
|
|
32
|
+
width: 100%;
|
|
33
|
+
border: none;
|
|
34
|
+
box-sizing: border-box;
|
|
35
|
+
padding: 0;
|
|
36
|
+
margin: 0;
|
|
37
|
+
height: fill-available;
|
|
38
|
+
height: stretch;
|
|
39
|
+
}
|
|
@@ -14,7 +14,11 @@
|
|
|
14
14
|
width: 100%;
|
|
15
15
|
box-sizing: border-box;
|
|
16
16
|
overflow: auto;
|
|
17
|
-
|
|
17
|
+
|
|
18
|
+
height: fill-available;
|
|
19
|
+
height: -moz-available;
|
|
20
|
+
height: stretch;
|
|
21
|
+
|
|
18
22
|
}
|
|
19
23
|
|
|
20
24
|
[data-monster-role="control"] {
|
|
@@ -26,8 +30,11 @@
|
|
|
26
30
|
overflow: auto;
|
|
27
31
|
scrollbar-width: thin;
|
|
28
32
|
scrollbar-color: var(--monster-color-primary-1) var(--monster-bg-color-primary-1);
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
|
|
34
|
+
height: fill-available;
|
|
35
|
+
height: -moz-available;
|
|
36
|
+
height: stretch;
|
|
37
|
+
|
|
31
38
|
//position: fixed;
|
|
32
39
|
//top: 0;
|
|
33
40
|
//left: 0;
|