@schukai/monster 3.64.1 → 3.65.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/example/components/form/button.mjs +1 -1
  3. package/example/components/form/field-set.mjs +4 -0
  4. package/example/components/form/select.mjs +1 -1
  5. package/package.json +2 -1
  6. package/source/components/datatable/datatable/header.mjs +228 -221
  7. package/source/components/datatable/style/dataset.pcss +1 -0
  8. package/source/components/datatable/style/datatable.pcss +1 -0
  9. package/source/components/datatable/stylesheet/dataset.mjs +1 -1
  10. package/source/components/datatable/stylesheet/datatable.mjs +1 -1
  11. package/source/components/form/button.mjs +263 -281
  12. package/source/components/form/field-set.mjs +300 -0
  13. package/source/components/form/popper.mjs +13 -480
  14. package/source/components/form/style/field-set.pcss +13 -0
  15. package/source/components/form/stylesheet/button-bar.mjs +1 -1
  16. package/source/components/form/stylesheet/confirm-button.mjs +1 -1
  17. package/source/components/form/stylesheet/field-set.mjs +31 -0
  18. package/source/components/form/stylesheet/form.mjs +1 -1
  19. package/source/components/host/collapse.mjs +14 -516
  20. package/source/components/host/config-manager.mjs +9 -2
  21. package/source/components/host/constants.mjs +9 -4
  22. package/source/components/host/details.mjs +14 -253
  23. package/source/components/host/stylesheet/host.mjs +1 -1
  24. package/source/components/host/stylesheet/overlay.mjs +1 -1
  25. package/source/components/layout/collapse.mjs +542 -0
  26. package/source/components/layout/details.mjs +271 -0
  27. package/source/components/layout/popper.mjs +476 -0
  28. package/source/components/layout/tabs.mjs +3 -3
  29. package/source/components/layout/width-toggle.mjs +3 -3
  30. package/source/components/navigation/style/table-of-content.pcss +84 -0
  31. package/source/components/navigation/stylesheet/table-of-content.mjs +31 -0
  32. package/source/components/navigation/table-of-content.mjs +418 -0
  33. package/source/components/state/stylesheet/state.mjs +1 -1
  34. package/source/components/style/link.pcss +0 -1
  35. package/source/components/style/mixin/typography.pcss +7 -7
  36. package/source/components/style/typography.pcss +1 -1
  37. package/source/components/stylesheet/typography.mjs +1 -1
  38. package/source/dom/ready.mjs +10 -4
  39. package/source/monster.mjs +5 -84
  40. package/source/types/proxyobserver.mjs +4 -2
  41. package/source/types/version.mjs +1 -1
  42. package/test/cases/monster.mjs +1 -1
  43. package/test/web/tests.js +4 -4
  44. package/source/components/form/form-field.mjs +0 -341
  45. package/source/components/form/style/form-field.pcss +0 -4
  46. package/source/components/form/stylesheet/form-field.mjs +0 -31
  47. /package/source/components/{host → layout}/style/collapse.pcss +0 -0
  48. /package/source/components/{host → layout}/style/details.pcss +0 -0
  49. /package/source/components/{form → layout}/style/popper.pcss +0 -0
  50. /package/source/components/{host → layout}/stylesheet/collapse.mjs +0 -0
  51. /package/source/components/{host → layout}/stylesheet/details.mjs +0 -0
  52. /package/source/components/{form → layout}/stylesheet/popper.mjs +0 -0
@@ -0,0 +1,542 @@
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 {
14
+ assembleMethodSymbol,
15
+ CustomElement,
16
+ getSlottedElements,
17
+ registerCustomElement,
18
+ } from "../../dom/customelement.mjs";
19
+ import { CollapseStyleSheet } from "./stylesheet/collapse.mjs";
20
+ import { fireCustomEvent } from "../../dom/events.mjs";
21
+ import { getDocument } from "../../dom/util.mjs";
22
+ import { addAttributeToken } from "../../dom/attributes.mjs";
23
+ import { ATTRIBUTE_ERRORMESSAGE } from "../../dom/constants.mjs";
24
+ import { Host } from "../host/host.mjs";
25
+ import { generateUniqueConfigKey } from "../host/util.mjs";
26
+ import { DeadMansSwitch } from "../../util/deadmansswitch.mjs";
27
+ import { instanceSymbol } from "../../constants.mjs";
28
+
29
+ export { Collapse, nameSymbol };
30
+
31
+ /**
32
+ * @private
33
+ * @type {symbol}
34
+ */
35
+ const timerCallbackSymbol = Symbol("timerCallback");
36
+
37
+ /**
38
+ * @private
39
+ * @type {symbol}
40
+ */
41
+ const detailsElementSymbol = Symbol("detailsElement");
42
+
43
+ /**
44
+ * @private
45
+ * @type {symbol}
46
+ */
47
+ const controlElementSymbol = Symbol("controlElement");
48
+
49
+ /**
50
+ * local symbol
51
+ * @private
52
+ * @type {symbol}
53
+ */
54
+ const resizeObserverSymbol = Symbol("resizeObserver");
55
+
56
+ /**
57
+ * @private
58
+ * @type {symbol}
59
+ */
60
+ const detailsSlotElementSymbol = Symbol("detailsSlotElement");
61
+
62
+ /**
63
+ * @private
64
+ * @type {symbol}
65
+ */
66
+ const detailsContainerElementSymbol = Symbol("detailsContainerElement");
67
+ /**
68
+
69
+ * @private
70
+ * @type {symbol}
71
+ */
72
+ const detailsDecoElementSymbol = Symbol("detailsDecoElement");
73
+
74
+ /**
75
+ * @private
76
+ * @type {symbol}
77
+ */
78
+ const nameSymbol = Symbol("name");
79
+
80
+ /**
81
+ * The Collapse component is used to show a details.
82
+ *
83
+ * <img src="./images/collapse.png">
84
+ *
85
+ * Dependencies: the system uses functions of the [monsterjs](https://monsterjs.org/) library
86
+ *
87
+ * You can create this control either by specifying the HTML tag <monster-collapse />` directly in the HTML or using
88
+ * Javascript via the `document.createElement('monster-collapse');` method.
89
+ *
90
+ * ```html
91
+ * <monster-collapse></monster-collapse>
92
+ * ```
93
+ *
94
+ * Or you can create this CustomControl directly in Javascript:
95
+ *
96
+ * ```js
97
+ * import '@schukai/monster/source/components/host/collapse.mjs';
98
+ * document.createElement('monster-collapse');
99
+ * ```
100
+ *
101
+ * The Body should have a class "hidden" to ensure that the styles are applied correctly.
102
+ *
103
+ * ```css
104
+ * body.hidden {
105
+ * visibility: hidden;
106
+ * }
107
+ * ```
108
+ *
109
+ * @startuml collapse.png
110
+ * skinparam monochrome true
111
+ * skinparam shadowing false
112
+ * HTMLElement <|-- CustomElement
113
+ * CustomElement <|-- Collapse
114
+ * @enduml
115
+ *
116
+ * @copyright schukai GmbH
117
+ * @memberOf Monster.Components.Host
118
+ * @summary A simple collapse component
119
+ * @fires Monster.Components.Host.Collapse.event:monster-collapse-before-open
120
+ * @fires Monster.Components.Host.Collapse.event:monster-collapse-open
121
+ * @fires Monster.Components.Host.Collapse.event:monster-collapse-before-close
122
+ * @fires Monster.Components.Host.Collapse.event:monster-collapse-closed
123
+ * @fires Monster.Components.Host.Collapse.event:monster-collapse-adjust-height
124
+ */
125
+ class Collapse extends CustomElement {
126
+ /**
127
+ * This method is called by the `instanceof` operator.
128
+ * @returns {symbol}
129
+ */
130
+ static get [instanceSymbol]() {
131
+ return Symbol.for("@schukai/monster/components/layout/collapse@@instance");
132
+ }
133
+
134
+ /**
135
+ *
136
+ */
137
+ constructor() {
138
+ super();
139
+ // the name is only used for the host config and the event name
140
+ this[nameSymbol] = "collapse";
141
+ }
142
+
143
+ /**
144
+ * To set the options via the html tag the attribute `data-monster-options` must be used.
145
+ * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
146
+ *
147
+ * The individual configuration values can be found in the table.
148
+ *
149
+ * @property {Object} templates Template definitions
150
+ * @property {string} templates.main Main template
151
+ * @property {Object} classes CSS classes
152
+ * @property {string} classes.container CSS class for the container
153
+ * @property {Object} features Feature configuration
154
+ * @property {boolean} features.accordion Enable accordion mode
155
+ * @property {boolean} features.persistState Enable persist state (Host and Config-Manager required)
156
+ * @property {boolean} features.useScrollValues Use scroll values (scrollHeight) instead of clientHeight for the height calculation
157
+ * @property {boolean} openByDefault Open the details by default
158
+ */
159
+ get defaults() {
160
+ return Object.assign({}, super.defaults, {
161
+ templates: {
162
+ main: getTemplate(),
163
+ },
164
+ classes: {
165
+ container: "padding",
166
+ },
167
+ features: {
168
+ accordion: true,
169
+ persistState: true,
170
+ useScrollValues: false,
171
+ },
172
+ openByDefault: false,
173
+ });
174
+ }
175
+
176
+ /**
177
+ *
178
+ * @returns {Monster.Components.Host.Collapse}
179
+ */
180
+ [assembleMethodSymbol]() {
181
+ super[assembleMethodSymbol]();
182
+ initControlReferences.call(this);
183
+ initStateFromHostConfig.call(this);
184
+ initResizeObserver.call(this);
185
+ initEventHandler.call(this);
186
+
187
+ if (this.getOption("openByDefault")) {
188
+ this.open();
189
+ }
190
+
191
+ }
192
+
193
+ /**
194
+ *
195
+ */
196
+ connectedCallback() {
197
+ super.connectedCallback();
198
+ updateResizeObserverObservation.call(this);
199
+ // this[resizeObserverSymbol].observe(getDocument().body);
200
+ }
201
+
202
+ /**
203
+ *
204
+ */
205
+ disconnectedCallback() {
206
+ super.disconnectedCallback();
207
+ //this[resizeObserverSymbol].disconnect();
208
+ }
209
+
210
+ /**
211
+ *
212
+ * @returns {Monster.Components.Host.Collapse}
213
+ */
214
+ toggle() {
215
+ if (this[detailsElementSymbol].classList.contains("active")) {
216
+ this.close();
217
+ } else {
218
+ this.open();
219
+ }
220
+ return this;
221
+ }
222
+
223
+ /**
224
+ *
225
+ * @returns {boolean}
226
+ */
227
+ isClosed() {
228
+ return !this[detailsElementSymbol].classList.contains("active");
229
+ }
230
+
231
+ /**
232
+ *
233
+ * @returns {boolean}
234
+ */
235
+ isOpen() {
236
+ return !this.isClosed();
237
+ }
238
+
239
+ /**
240
+ *
241
+ * @returns {Monster.Components.Host.Collapse}
242
+ * @fires Monster.Components.Host.Collapse.event:monster-collapse-before-open
243
+ * @fires Monster.Components.Host.Collapse.event:monster-collapse-open
244
+ */
245
+ open() {
246
+ let node;
247
+ if (this[detailsElementSymbol].classList.contains("active")) {
248
+ return this;
249
+ }
250
+
251
+ fireCustomEvent(this, "monster-" + this[nameSymbol] + "-before-open", {});
252
+
253
+ adjustHeight.call(this);
254
+ this[detailsElementSymbol].classList.add("active");
255
+
256
+ if (this.getOption("features.accordion") === true) {
257
+ node = this;
258
+ while (node.nextElementSibling instanceof Collapse) {
259
+ node = node.nextElementSibling;
260
+ node.close();
261
+ }
262
+
263
+ node = this;
264
+ while (node.previousElementSibling instanceof Collapse) {
265
+ node = node.previousElementSibling;
266
+ node.close();
267
+ }
268
+ }
269
+
270
+ setTimeout(() => {
271
+ setTimeout(() => {
272
+ updateStateConfig.call(this);
273
+ fireCustomEvent(this, "monster-" + this[nameSymbol] + "-open", {});
274
+ setTimeout(() => {
275
+ this[controlElementSymbol].classList.remove("overflow-hidden");
276
+ }, 500);
277
+ }, 0);
278
+ }, 0);
279
+
280
+ return this;
281
+ }
282
+
283
+ /**
284
+ *
285
+ * @returns {Monster.Components.Host.Collapse}
286
+ * @fires Monster.Components.Host.Collapse.event:monster-collapse-before-close
287
+ * @fires Monster.Components.Host.Collapse.event:monster-collapse-closed
288
+ */
289
+ close() {
290
+ if (!this[detailsElementSymbol].classList.contains("active")) {
291
+ return this;
292
+ }
293
+
294
+ fireCustomEvent(this, "monster-" + this[nameSymbol] + "-before-close", {});
295
+ this[controlElementSymbol].classList.add("overflow-hidden");
296
+
297
+ setTimeout(() => {
298
+ this[detailsElementSymbol].classList.remove("active");
299
+ setTimeout(() => {
300
+ updateStateConfig.call(this);
301
+ fireCustomEvent(this, "monster-" + this[nameSymbol] + "-closed", {});
302
+ }, 0);
303
+ }, 0);
304
+
305
+ return this;
306
+ }
307
+
308
+ /**
309
+ *
310
+ * @return {string}
311
+ */
312
+ static getTag() {
313
+ return "monster-collapse";
314
+ }
315
+
316
+ /**
317
+ * @return {Array<CSSStyleSheet>}
318
+ */
319
+ static getCSSStyleSheet() {
320
+ return [CollapseStyleSheet];
321
+ }
322
+
323
+ /**
324
+ * This method is called when the element is inserted into a document, including into a shadow tree.
325
+ * @return {Monster.Components.Host.Collapse}
326
+ * @fires Monster.Components.Host.Collapse.event:monster-collapse-adjust-height
327
+ */
328
+ adjustHeight() {
329
+ adjustHeight.call(this);
330
+ return this;
331
+ }
332
+ }
333
+
334
+ function adjustHeight() {
335
+ let height = 0;
336
+
337
+ if (this[detailsContainerElementSymbol]) {
338
+ if (this.getOption("features.useScrollValues")) {
339
+ height += this[detailsContainerElementSymbol].scrollHeight;
340
+ } else {
341
+ height += this[detailsContainerElementSymbol].clientHeight;
342
+ }
343
+ }
344
+
345
+ if (this[detailsDecoElementSymbol]) {
346
+ if (this.getOption("features.useScrollValues")) {
347
+ height += this[detailsDecoElementSymbol].scrollHeight;
348
+ } else {
349
+ height += this[detailsDecoElementSymbol].clientHeight + 1;
350
+ }
351
+ }
352
+
353
+ if (height === 0) {
354
+ if (this.getOption("features.useScrollValues")) {
355
+ height = this[detailsElementSymbol].scrollHeight;
356
+ } else {
357
+ height = this[detailsElementSymbol].clientHeight;
358
+ }
359
+
360
+ if (height === 0) {
361
+ height = "auto";
362
+ }
363
+ } else {
364
+ height += "px";
365
+ }
366
+
367
+ this[detailsElementSymbol].style.setProperty(
368
+ "--monster-height",
369
+ height,
370
+ "important",
371
+ );
372
+ fireCustomEvent(this, "monster-" + this[nameSymbol] + "-adjust-height", {});
373
+ }
374
+
375
+ function updateResizeObserverObservation() {
376
+ this[resizeObserverSymbol].disconnect();
377
+
378
+ const slottedNodes = getSlottedElements.call(this);
379
+ slottedNodes.forEach((node) => {
380
+ this[resizeObserverSymbol].observe(node);
381
+ });
382
+
383
+ if (this[detailsContainerElementSymbol]) {
384
+ this[resizeObserverSymbol].observe(this[detailsContainerElementSymbol]);
385
+ }
386
+
387
+ this.adjustHeight();
388
+ }
389
+
390
+ /**
391
+ * @private
392
+ */
393
+ function initEventHandler() {
394
+ if (!this.shadowRoot) {
395
+ throw new Error("no shadow-root is defined");
396
+ }
397
+
398
+ initSlotChangedHandler.call(this);
399
+ return this;
400
+ }
401
+
402
+ function initSlotChangedHandler() {
403
+ this[detailsSlotElementSymbol].addEventListener("slotchange", () => {
404
+ updateResizeObserverObservation.call(this);
405
+ });
406
+ }
407
+
408
+ /**
409
+ * @private
410
+ * @return {Select}
411
+ * @throws {Error} no shadow-root is defined
412
+ */
413
+ function initControlReferences() {
414
+ if (!this.shadowRoot) {
415
+ throw new Error("no shadow-root is defined");
416
+ }
417
+
418
+ this[controlElementSymbol] = this.shadowRoot.querySelector(
419
+ "[data-monster-role=control]",
420
+ );
421
+ this[detailsElementSymbol] = this.shadowRoot.querySelector(
422
+ "[data-monster-role=detail]",
423
+ );
424
+ this[detailsSlotElementSymbol] = this.shadowRoot.querySelector("slot");
425
+ this[detailsContainerElementSymbol] = this.shadowRoot.querySelector(
426
+ "[data-monster-role=container]",
427
+ );
428
+ this[detailsDecoElementSymbol] = this.shadowRoot.querySelector(
429
+ "[data-monster-role=deco]",
430
+ );
431
+ }
432
+
433
+ /**
434
+ * @private
435
+ * @returns {string}
436
+ */
437
+ function getConfigKey() {
438
+ return generateUniqueConfigKey(this[nameSymbol], this.id, "state");
439
+ }
440
+
441
+ /**
442
+ * @private
443
+ */
444
+ function updateStateConfig() {
445
+ if (!this.getOption("features.persistState")) {
446
+ return;
447
+ }
448
+
449
+ if (!this[detailsElementSymbol]) {
450
+ return;
451
+ }
452
+
453
+ const document = getDocument();
454
+ const host = document.querySelector("monster-host");
455
+ if (!(host && this.id)) {
456
+ return;
457
+ }
458
+
459
+ const configKey = getConfigKey.call(this);
460
+
461
+ try {
462
+ host.setConfig(configKey, this.isOpen());
463
+ } catch (error) {
464
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error));
465
+ }
466
+ }
467
+
468
+ /**
469
+ * @private
470
+ * @returns {Promise}
471
+ */
472
+ function initStateFromHostConfig() {
473
+ if (!this.getOption("features.persistState")) {
474
+ return Promise.resolve({});
475
+ }
476
+
477
+ const document = getDocument();
478
+ const host = document.querySelector("monster-host");
479
+
480
+ if (!(host && this.id)) {
481
+ return Promise.resolve({});
482
+ }
483
+
484
+ const configKey = getConfigKey.call(this);
485
+ return host
486
+ .getConfig(configKey)
487
+ .then((state) => {
488
+ if (state === true) {
489
+ this.open();
490
+ } else {
491
+ this.close();
492
+ }
493
+ })
494
+ .catch((error) => {
495
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error.toString());
496
+ });
497
+ }
498
+
499
+ /**
500
+ * @private
501
+ */
502
+ function initResizeObserver() {
503
+ // against flickering
504
+ this[resizeObserverSymbol] = new ResizeObserver((entries) => {
505
+ if (this[timerCallbackSymbol] instanceof DeadMansSwitch) {
506
+ try {
507
+ this[timerCallbackSymbol].touch();
508
+ return;
509
+ } catch (e) {
510
+ delete this[timerCallbackSymbol];
511
+ }
512
+ }
513
+
514
+ this[timerCallbackSymbol] = new DeadMansSwitch(200, () => {
515
+ checkAndRearrangeContent.call(this);
516
+ });
517
+ });
518
+ }
519
+
520
+ function checkAndRearrangeContent() {
521
+ this.adjustHeight();
522
+ }
523
+
524
+ /**
525
+ * @private
526
+ * @return {string}
527
+ */
528
+ function getTemplate() {
529
+ // language=HTML
530
+ return `
531
+ <div data-monster-role="control" part="control" class="overflow-hidden">
532
+ <div data-monster-role="detail">
533
+ <div data-monster-attributes="class path:classes.container" part="container"
534
+ data-monster-role="container">
535
+ <slot></slot>
536
+ </div>
537
+ <div class="deco-line" data-monster-role="deco" part="deco"></div>
538
+ </div>
539
+ </div>`;
540
+ }
541
+
542
+ registerCustomElement(Collapse);