@schukai/monster 3.58.4 → 3.59.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -106,7 +106,7 @@ class Overlay extends CustomElement {
106
106
  * @returns {symbol}
107
107
  */
108
108
  static get [instanceSymbol]() {
109
- return Symbol.for("@schukai/component-host/overlay@@instance");
109
+ return Symbol.for("@schukai/monster/components/host/overlay@@instance");
110
110
  }
111
111
 
112
112
  /**
@@ -39,18 +39,10 @@ const viewerElementSymbol = Symbol("viewerElement");
39
39
  * Or you can create this CustomControl directly in Javascript:
40
40
  *
41
41
  * ```js
42
- * import '@schukai/component-state/source/viewer.mjs';
42
+ * import '@schukai/monster/components/host/viewer.mjs';
43
43
  * document.createElement('monster-viewer');
44
44
  * ```
45
45
  *
46
- * The Body should have a class "hidden" to ensure that the styles are applied correctly.
47
- *
48
- * ```css
49
- * body.hidden {
50
- * visibility: hidden;
51
- * }
52
- * ```
53
- *
54
46
  * @startuml viewer.png
55
47
  * skinparam monochrome true
56
48
  * skinparam shadowing false
@@ -62,10 +54,6 @@ const viewerElementSymbol = Symbol("viewerElement");
62
54
  * @copyright schukai GmbH
63
55
  * @memberOf Monster.Components.Host
64
56
  * @summary A simple viewer component
65
- * @fires Monster.Components.Host.Viewer.event:monster-viewer-before-open
66
- * @fires Monster.Components.Host.Viewer.event:monster-viewer-open
67
- * @fires Monster.Components.Host.Viewer.event:monster-viewer-before-close
68
- * @fires Monster.Components.Host.Viewer.event:monster-viewer-closed
69
57
  */
70
58
  class Viewer extends CustomElement {
71
59
  /**
@@ -73,7 +61,7 @@ class Viewer extends CustomElement {
73
61
  * @returns {symbol}
74
62
  */
75
63
  static get [instanceSymbol]() {
76
- return Symbol.for("@schukai/component-host/viewer@@instance");
64
+ return Symbol.for("@schukai/monster/components/host/viewer@@instance");
77
65
  }
78
66
 
79
67
  /**
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Copyright 2023 schukai GmbH
3
+ * SPDX-License-Identifier: AGPL-3.0
4
+ */
5
+
6
+ /**
7
+ * Namespace for all layout related functions.
8
+ *
9
+ * @namespace Monster.Components.Layout
10
+ * @memberOf Monster
11
+ * @author schukai GmbH
12
+ */
13
+ const ns = {};
@@ -0,0 +1,341 @@
1
+ /**
2
+ * Copyright 2023 schukai GmbH
3
+ * SPDX-License-Identifier: AGPL-3.0
4
+ */
5
+
6
+ import {
7
+ assembleMethodSymbol,
8
+ CustomElement,
9
+ registerCustomElement,
10
+ } from "../../dom/customelement.mjs";
11
+ import "../notify/notify.mjs";
12
+ import {Observer} from "../../types/observer.mjs";
13
+ import {SplitScreenStyleSheet} from "./stylesheet/split-screen.mjs";
14
+ import {instanceSymbol} from "../../constants.mjs";
15
+ import {internalSymbol} from "../../constants.mjs";
16
+
17
+ export {SplitScreen, TYPE_VERTICAL, TYPE_HORIZONTAL};
18
+
19
+ /**
20
+ * @private
21
+ * @type {symbol}
22
+ */
23
+ const splitScreenElementSymbol = Symbol("splitScreenElement");
24
+
25
+ /**
26
+ * @private
27
+ * @type {symbol}
28
+ */
29
+ const draggerElementSymbol = Symbol("draggerElement");
30
+ /**
31
+ * @private
32
+ * @type {symbol}
33
+ */
34
+ const startPanelElementSymbol = Symbol("startPanelElement");
35
+ /**
36
+ * @private
37
+ * @type {symbol}
38
+ */
39
+ const endPanelElementSymbol = Symbol("endPanelElement");
40
+ /**
41
+ * @private
42
+ * @type {symbol}
43
+ */
44
+ const handleElementSymbol = Symbol("handleElement");
45
+
46
+ /**
47
+ *
48
+ * @type {string}
49
+ */
50
+ const TYPE_VERTICAL = "vertical";
51
+ /**
52
+ *
53
+ * @type {string}
54
+ */
55
+ const TYPE_HORIZONTAL = "horizontal";
56
+
57
+
58
+ /**
59
+ * The Viewer component is used to show a PDF, HTML or Image.
60
+ *
61
+ * <img src="./images/splitscreen.png">
62
+ *
63
+ * You can create this control either by specifying the HTML tag <monster-splitscreen />` directly in the HTML or using
64
+ * Javascript via the `document.createElement('monster-split-screen');` method.
65
+ *
66
+ * ```html
67
+ * <monster-split-screen></monster-split-screen>
68
+ * ```
69
+ *
70
+ * Or you can create this CustomControl directly in Javascript:
71
+ *
72
+ * ```js
73
+ * import '@schukai/monster/components/layout/split-screen.mjs';
74
+ * document.createElement('monster-split-screen');
75
+ * ```
76
+ *
77
+ * @startuml splitscreen.png
78
+ * skinparam monochrome true
79
+ * skinparam shadowing false
80
+ * HTMLElement <|-- CustomElement
81
+ * CustomElement <|-- CustomControl
82
+ * CustomControl <|-- SplitScreen
83
+ * @enduml
84
+ *
85
+ * @copyright schukai GmbH
86
+ * @memberOf Monster.Components.Layout
87
+ * @summary A simple split screen layout
88
+ */
89
+ class SplitScreen extends CustomElement {
90
+
91
+ /**
92
+ * This method is called by the `instanceof` operator.
93
+ * @returns {symbol}
94
+ */
95
+ static get [instanceSymbol]() {
96
+ return Symbol.for("@schukai/monster/components/layout/splitscreen");
97
+ }
98
+
99
+ /**
100
+ * To set the options via the html tag the attribute `data-monster-options` must be used.
101
+ * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
102
+ *
103
+ * The individual configuration values can be found in the table.
104
+ *
105
+ * @property {Object} templates Template definitions
106
+ * @property {string} templates.main Main template
107
+ * @property {Object} classes Css classes
108
+ * @property {Object} features Feature definitions
109
+ */
110
+ get defaults() {
111
+ return Object.assign({}, super.defaults, {
112
+ templates: {
113
+ main: getTemplate(),
114
+ },
115
+ splitType: TYPE_VERTICAL,
116
+ dimension: "20%",
117
+ classes: {},
118
+ features: {},
119
+ });
120
+ }
121
+
122
+ setContent(html) {
123
+ this.setOption("content", html);
124
+ return this;
125
+ }
126
+
127
+ /**
128
+ *
129
+ * @returns {Monster.Components.Host.Viewer}
130
+ */
131
+ [assembleMethodSymbol]() {
132
+ super[assembleMethodSymbol]();
133
+
134
+ initControlReferences.call(this);
135
+ initEventHandler.call(this);
136
+ applyPanelDimensions.call(this);
137
+ }
138
+
139
+ setDimension(dimension) {
140
+ // check if percent and greater than100
141
+ if (dimension.includes("%")) {
142
+ if (parseInt(dimension) > 100) {
143
+ throw new Error("dimension must be less than 100%");
144
+ } else if (parseInt(dimension) < 0) {
145
+ throw new Error("dimension must be greater than 0%");
146
+ }
147
+ }
148
+
149
+ this.setOption("dimension", dimension);
150
+ return this;
151
+ }
152
+
153
+
154
+ /**
155
+ *
156
+ * @return {string}
157
+ */
158
+ static getTag() {
159
+ return "monster-split-screen";
160
+ }
161
+
162
+ /**
163
+ * @return {CSSStyleSheet[]}
164
+ */
165
+ static getCSSStyleSheet() {
166
+ return [SplitScreenStyleSheet];
167
+ }
168
+ }
169
+
170
+
171
+ /**
172
+ * Set the dimensions of the panel based on the split type.
173
+ */
174
+ function applyPanelDimensions() {
175
+
176
+ const splitType = this.getOption("splitType");
177
+ const dimension = this.getOption("dimension");
178
+
179
+ if (splitType === TYPE_VERTICAL) {
180
+ this[startPanelElementSymbol].style.width = dimension;
181
+ this[endPanelElementSymbol].style.width = `calc(100% - ${dimension} - 5px)`;
182
+ this[draggerElementSymbol].style.cursor = "ew-resize";
183
+ this[splitScreenElementSymbol].classList.add("vertical");
184
+ this[splitScreenElementSymbol].classList.remove("horizontal");
185
+
186
+ } else {
187
+ this[startPanelElementSymbol].style.height = dimension;
188
+ this[endPanelElementSymbol].style.height = `calc(100% - ${dimension} - 5px)`;
189
+ this[draggerElementSymbol].style.cursor = "ns-resize";
190
+ this[splitScreenElementSymbol].classList.add("horizontal");
191
+ this[splitScreenElementSymbol].classList.remove("vertical");
192
+
193
+ }
194
+ }
195
+
196
+
197
+ /**
198
+ * @private
199
+ * @return {Select}
200
+ * @throws {Error} no shadow-root is defined
201
+ */
202
+ function initControlReferences() {
203
+ if (!this.shadowRoot) {
204
+ throw new Error("no shadow-root is defined");
205
+ }
206
+
207
+ this[splitScreenElementSymbol] = this.shadowRoot.querySelector("[data-monster-role=split-screen]");
208
+ this[draggerElementSymbol] = this.shadowRoot.querySelector("[data-monster-role=dragger]");
209
+ this[handleElementSymbol] = this.shadowRoot.querySelector("[data-monster-role=handle]");
210
+
211
+ this[startPanelElementSymbol] = this.shadowRoot.querySelector("[data-monster-role=startPanel]");
212
+ this[endPanelElementSymbol] = this.shadowRoot.querySelector("[data-monster-role=endPanel]");
213
+
214
+ }
215
+
216
+ /**
217
+ * @private
218
+ */
219
+ function initEventHandler() {
220
+ const self = this;
221
+
222
+ this[internalSymbol].getSubject().isDragging = false;
223
+
224
+ this[draggerElementSymbol].addEventListener('dblclick', () => {
225
+ self[internalSymbol].getSubject().isDragging = false;
226
+ applyPanelDimensions.call(this);
227
+ });
228
+
229
+ const resizeObserver = new ResizeObserver((entries) => {
230
+ for (let entry of entries) {
231
+ console.log(entry.contentRect.width);
232
+ }
233
+ });
234
+
235
+ resizeObserver.observe(this[splitScreenElementSymbol]);
236
+
237
+
238
+ this[draggerElementSymbol].addEventListener('mousedown', () => {
239
+ self[internalSymbol].getSubject().isDragging = true;
240
+
241
+ document.addEventListener('mousemove', (e) => {
242
+ e.preventDefault();
243
+ if (!self[internalSymbol].getSubject().isDragging) {
244
+ return;
245
+ }
246
+
247
+ if (self.getOption("splitType") === TYPE_HORIZONTAL) {
248
+ const containerOffsetTop = self[splitScreenElementSymbol].offsetTop;
249
+ const topPanel = self[startPanelElementSymbol];
250
+ const bottomPanel = self[endPanelElementSymbol];
251
+ const newTopHeight = e.clientY - containerOffsetTop;
252
+ topPanel.style.height = `${newTopHeight}px`;
253
+ bottomPanel.style.height = `calc(100% - ${newTopHeight}px - 5px)`; // 5px is dragger height
254
+
255
+
256
+ } else {
257
+
258
+ const containerOffsetLeft = self[splitScreenElementSymbol].offsetLeft;
259
+ const leftPanel = self[startPanelElementSymbol];
260
+ const rightPanel = self[endPanelElementSymbol];
261
+ const newLeftWidth = e.clientX - containerOffsetLeft;
262
+ leftPanel.style.width = `${newLeftWidth}px`;
263
+ rightPanel.style.width = `calc(100% - ${newLeftWidth}px - 5px)`; // 5px is dragger width
264
+ }
265
+
266
+ });
267
+
268
+ document.addEventListener('mouseup', (e) => {
269
+ self[internalSymbol].getSubject().isDragging = false;
270
+ document.removeEventListener('mousemove', (e) => {
271
+ if (!self[internalSymbol].getSubject().isDragging) {
272
+ return;
273
+ }
274
+
275
+ if (self.getOption("splitType") === TYPE_VERTICAL) {
276
+ const containerOffsetTop = self[splitScreenElementSymbol].offsetTop;
277
+ const topPanel = self[startPanelElementSymbol];
278
+ const bottomPanel = self[endPanelElementSymbol];
279
+ const newTopHeight = e.clientY - containerOffsetTop;
280
+ topPanel.style.height = `${newTopHeight}px`;
281
+ bottomPanel.style.height = `calc(100% - ${newTopHeight}px - 5px)`; // 5px is dragger height
282
+
283
+ } else {
284
+ const containerOffsetLeft = self[splitScreenElementSymbol].offsetLeft;
285
+ const newLeftWidth = e.clientX - containerOffsetLeft;
286
+ const leftPanel = self[startPanelElementSymbol];
287
+ const rightPanel = self[endPanelElementSymbol];
288
+ leftPanel.style.width = `${newLeftWidth}px`;
289
+ rightPanel.style.width = `calc(100% - ${newLeftWidth}px - 5px)`; // 5px is dragger width
290
+ }
291
+ });
292
+ document.removeEventListener('mouseup', (e) => {
293
+ self[internalSymbol].getSubject().isDragging = false;
294
+ });
295
+ });
296
+ });
297
+
298
+ let lastDimension = this.getOption("dimension");
299
+ let lastType = this.getOption("splitType");
300
+ this[internalSymbol].attachObserver(
301
+ new Observer(() => {
302
+ if (lastDimension !== this.getOption("dimension")) {
303
+ lastDimension = this.getOption("dimension");
304
+ applyPanelDimensions.call(this);
305
+ }
306
+
307
+ if (lastType !== this.getOption("splitType")) {
308
+ lastType = this.getOption("splitType");
309
+ applyPanelDimensions.call(this);
310
+ }
311
+
312
+ }));
313
+
314
+
315
+ return this;
316
+
317
+ }
318
+
319
+ /**
320
+ * @private
321
+ * @return {string}
322
+ */
323
+ function getTemplate() {
324
+ // language=HTML
325
+ return `
326
+ <div data-monster-role="split-screen" part="container">
327
+ <div data-monster-role="startPanel" class="panel" part="startPanel">
328
+ <slot name="start"></slot>
329
+ </div>
330
+ <div data-monster-role="dragger" part="dragger">
331
+ <div data-monster-role="handle"></div>
332
+ </div>
333
+ <div data-monster-role="endPanel" class="panel" part="endPanel">
334
+ <slot name="end"></slot>
335
+ </div>
336
+
337
+
338
+ </div>`;
339
+ }
340
+
341
+ registerCustomElement(SplitScreen);
@@ -0,0 +1,59 @@
1
+
2
+
3
+ [data-monster-role="split-screen"] {
4
+
5
+ box-sizing: border-box;
6
+ display: flex;
7
+ width: 100%;
8
+ height: auto;
9
+ flex-direction: row;
10
+ margin: 0;
11
+ padding: 0;
12
+
13
+ & .panel {
14
+ flex-grow: 1;
15
+ overflow: auto;
16
+ }
17
+
18
+ [data-monster-role="dragger"] {
19
+ background-color: var(--monster-bg-color-primary-4);
20
+ color: var(--monster-color-primary-4);
21
+ width: var(--monster-border-width);
22
+ height: auto;
23
+
24
+ position: relative;
25
+
26
+ & [data-monster-role=handle] {
27
+ position: absolute;
28
+ top: 50%;
29
+ left: 50%;
30
+ transform: translate(-50%, -50%);
31
+ cursor: pointer;
32
+ width: 5px;
33
+ height: 120px;
34
+ background-color: var(--monster-bg-color-primary-3);
35
+ color: var(--monster-color-primary-3);
36
+ z-index: var(--monster-z-index-outline);
37
+ }
38
+ }
39
+
40
+ &.horizontal {
41
+ flex-direction: column;
42
+
43
+ [data-monster-role="dragger"] {
44
+ width: 100%;
45
+ height: var(--monster-border-width);
46
+
47
+ & [data-monster-role=handle] {
48
+ width: 120px;
49
+ height: 5px;
50
+ }
51
+
52
+ }
53
+
54
+
55
+ }
56
+
57
+ }
58
+
59
+
@@ -27,9 +27,6 @@ nav[data-monster-role=nav] {
27
27
  border-bottom-style: var(--monster-border-style);
28
28
  box-shadow: var(--monster-box-shadow-1);
29
29
  border-color: var(--monster-bg-color-primary-2);
30
-
31
- flex-wrap: nowrap;
32
-
33
30
  }
34
31
 
35
32
  [data-monster-role=nav] button .remove-tab {
@@ -0,0 +1,27 @@
1
+
2
+ /**
3
+ * Copyright schukai GmbH and contributors 2024. All Rights Reserved.
4
+ * Node module: @schukai/monster
5
+ * This file is licensed under the AGPLv3 License.
6
+ * License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
7
+ */
8
+
9
+ import {addAttributeToken} from "../../../dom/attributes.mjs";
10
+ import {ATTRIBUTE_ERRORMESSAGE} from "../../../dom/constants.mjs";
11
+
12
+ export {SplitScreenStyleSheet}
13
+
14
+ /**
15
+ * @private
16
+ * @type {CSSStyleSheet}
17
+ */
18
+ const SplitScreenStyleSheet = new CSSStyleSheet();
19
+
20
+ try {
21
+ SplitScreenStyleSheet.insertRule(`
22
+ @layer splitscreen {
23
+ [data-monster-role=split-screen]{box-sizing:border-box;display:flex;flex-direction:row;height:auto;margin:0;padding:0;width:100%}[data-monster-role=split-screen] .panel{flex-grow:1;overflow:auto}[data-monster-role=split-screen] [data-monster-role=dragger]{background-color:var(--monster-bg-color-primary-4);color:var(--monster-color-primary-4);height:auto;position:relative;width:var(--monster-border-width)}[data-monster-role=split-screen] [data-monster-role=dragger] [data-monster-role=handle]{background-color:var(--monster-bg-color-primary-3);color:var(--monster-color-primary-3);cursor:pointer;height:120px;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:5px;z-index:var(--monster-z-index-outline)}.horizontal[data-monster-role=split-screen]{flex-direction:column}.horizontal[data-monster-role=split-screen] [data-monster-role=dragger]{height:var(--monster-border-width);width:100%}.horizontal[data-monster-role=split-screen] [data-monster-role=dragger] [data-monster-role=handle]{height:5px;width:120px}
24
+ }`, 0);
25
+ } catch (e) {
26
+ addAttributeToken(document.getRootNode().querySelector('html'), ATTRIBUTE_ERRORMESSAGE, e + "");
27
+ }