@nys-cui/cui-section 0.2.19 → 0.2.20

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/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "main": "./dist/js/section.js",
8
8
  "type": "module",
9
- "version": "0.2.19",
9
+ "version": "0.2.20",
10
10
  "scripts": {
11
11
  "clean": "rm -rf ./dist",
12
12
  "build": "npm run clean && cui --dep",
package/src/section.js CHANGED
@@ -35,6 +35,12 @@ export default class CUI_SECTION extends HTMLElement {
35
35
  "label": "sTitle",
36
36
  "instructions": "oInstructions"
37
37
  }
38
+
39
+ this.bSectionMenuDisplayed = false;
40
+ this.dSectionMenu = null;
41
+ this.bMobile = false;
42
+ this.dSectionMenuDialog = null;
43
+ this.fGlobalBodyClick = this.globalBodyClick.bind(this);
38
44
  }
39
45
 
40
46
  get style() {
@@ -74,6 +80,7 @@ export default class CUI_SECTION extends HTMLElement {
74
80
  }
75
81
 
76
82
  sTemplate += `</header><div class="container" id="container" part="container">
83
+ <slot name="section-menu"></slot>
77
84
  <slot name="section-text"></slot>
78
85
  <slot name="section-messages"></slot>
79
86
  <slot name="section-contents"></slot>
@@ -212,6 +219,12 @@ export default class CUI_SECTION extends HTMLElement {
212
219
  oInstructions: this.state.oInstructions || null
213
220
  }
214
221
 
222
+ let match = window.matchMedia || window.msMatchMedia;
223
+ if(match) {
224
+ let mq = match("(pointer:coarse)");
225
+ this.bMobile = mq.matches;
226
+ }
227
+
215
228
  this.sIconBasePath = this.getAttribute('iconbase') || null;
216
229
 
217
230
  let dMessageList = this.querySelector(`[slot="section-messages"]`);
@@ -230,9 +243,11 @@ export default class CUI_SECTION extends HTMLElement {
230
243
  this.sdSectionTitle = this.shadowRoot.querySelector(`#section-title`);
231
244
  this.sdContentsContainer = this.shadowRoot.querySelector(`#container`);
232
245
 
233
- this.sdSectionTitle.appendChild(document.createTextNode(this.state.sTitle));
246
+ if(!this.state.bHideHeader) {
247
+ this.sdSectionTitle.appendChild(document.createTextNode(this.state.sTitle));
248
+ }
234
249
 
235
- if (!this.state.bHideControls) {
250
+ if (!this.state.bHideControls && !this.state.bHideHeader) {
236
251
 
237
252
  this.sdSectionCollapseControl = this.shadowRoot.querySelector(`#collapse-control`);
238
253
 
@@ -304,6 +319,136 @@ export default class CUI_SECTION extends HTMLElement {
304
319
  this.appendChild(dSectionInstructions);
305
320
  }
306
321
 
322
+ let dSectionMenuSlot = this.querySelector('[slot="section-menu"]');
323
+ if(dSectionMenuSlot && dSectionMenuSlot.hasChildNodes()) {
324
+ this.generateSectionMenuButton(dSectionMenuSlot);
325
+ }
326
+ }
327
+
328
+ generateSectionMenuButton(dSectionMenuSlot) {
329
+ let dMenuItems = dSectionMenuSlot.querySelectorAll('cui-item');
330
+
331
+ if(dMenuItems) {
332
+ let dHeaderControls = this.shadowRoot.querySelector('.header-controls');
333
+ let dCollapseControl = dHeaderControls.querySelector('#collapse-control');
334
+
335
+ let dMenuButton = document.createElement('button');
336
+ dMenuButton.classList.add('section-menu-btn');
337
+ dMenuButton.setAttribute('part', 'section-menu-btn');
338
+ dMenuButton.setAttribute('id', 'section-menu-btn');
339
+ dMenuButton.addEventListener('click', this.sectionMenuClick.bind(this, dMenuItems));
340
+
341
+ let dMenuIcon = document.createElement('cui-icon');
342
+ dMenuIcon.setAttribute('src', 'ellipsis-vertical');
343
+ dMenuIcon.setAttribute('part', 'section-menu-icon');
344
+
345
+ dMenuButton.appendChild(dMenuIcon);
346
+ dCollapseControl.before(dMenuButton);
347
+ }
348
+ }
349
+
350
+ sectionMenuClick(dMenuItems, evt) {
351
+ evt.stopImmediatePropagation();
352
+ let dActiveBody = this.closest('body, dialog, modal');
353
+ if(this.bSectionMenuDisplayed) {
354
+ this.hideSectionMenu();
355
+ dActiveBody.removeEventListener('click', this.fGlobalBodyClick, false);
356
+ dActiveBody.removeEventListener('screenUnloadComplete', this.fGlobalBodyClick, false);
357
+ }
358
+ else {
359
+ this.displaySectionMenu(dMenuItems, dActiveBody);
360
+ dActiveBody.addEventListener('click', this.fGlobalBodyClick, false);
361
+ dActiveBody.addEventListener('screenUnloadComplete', this.fGlobalBodyClick, false);
362
+ }
363
+ }
364
+
365
+ displaySectionMenu(dMenuItems) {
366
+ if(this.dSectionMenu) {
367
+ if(this.bMobile) {
368
+ this.dSectionMenuDialog.showModal();
369
+ }
370
+ else {
371
+ this.shadowRoot.appendChild(this.dSectionMenu);
372
+ }
373
+ }
374
+ else {
375
+ let dMenu = document.createElement('div');
376
+ dMenu.classList.add('section-menu-popover');
377
+ dMenu.setAttribute('part', 'section-menu-popover');
378
+ let bFirstMenuItem = true;
379
+ for(let dMenuItem of dMenuItems) {
380
+ let dMenuOption = document.createElement('button');
381
+ dMenuOption.innerHTML = dMenuItem.getAttribute('text');
382
+ if(bFirstMenuItem) {
383
+ dMenuOption.classList.add('section-menu-item');
384
+ dMenuOption.setAttribute('part', 'section-menu-item');
385
+ bFirstMenuItem = false;
386
+ }
387
+ else {
388
+ dMenuOption.classList.add(['section-menu-item', 'not-first']);
389
+ dMenuOption.setAttribute('part', 'section-menu-item not-first');
390
+ }
391
+ dMenuOption.addEventListener('click', this.emitActionEvent.bind(this, dMenuItem.getAttribute('action')));
392
+ dMenu.appendChild(dMenuOption);
393
+ }
394
+ this.dSectionMenu = dMenu;
395
+ if(this.bMobile) {
396
+ let dMenuDialog = document.createElement('dialog');
397
+ dMenuDialog.setAttribute('id', 'section-menu-dialog');
398
+ dMenuDialog.classList.add('section-menu-dialog');
399
+ dMenuDialog.setAttribute('part', 'section-menu-dialog');
400
+ dMenuDialog.setAttribute('closedby', 'any');
401
+
402
+ dMenu.classList.add('dialog');
403
+ dMenu.setAttribute('part', dMenu.getAttribute('part') + ' dialog');
404
+
405
+ dMenuDialog.appendChild(dMenu);
406
+ this.shadowRoot.appendChild(dMenuDialog);
407
+ dMenuDialog.showModal();
408
+ this.dSectionMenuDialog = dMenuDialog;
409
+ }
410
+ else {
411
+ this.shadowRoot.appendChild(dMenu);
412
+ }
413
+ }
414
+ this.bSectionMenuDisplayed = true;
415
+ }
416
+
417
+ emitActionEvent(sAction) {
418
+ const E_CONTROL_EVENT = new CustomEvent("eventAction", {
419
+ bubbles: true,
420
+ composed: true,
421
+ detail: {
422
+ target: this,
423
+ name: sAction
424
+ }
425
+ });
426
+
427
+ this.dispatchEvent(E_CONTROL_EVENT);
428
+ this.hideSectionMenu();
429
+ }
430
+
431
+ hideSectionMenu() {
432
+ if(this.bSectionMenuDisplayed === false) {
433
+ return;
434
+ }
435
+
436
+ if(this.bMobile) {
437
+ this.dSectionMenuDialog.close();
438
+ }
439
+ else {
440
+ this.shadowRoot.removeChild(this.dSectionMenu);
441
+ }
442
+
443
+ this.bSectionMenuDisplayed = false;
444
+ }
445
+
446
+ globalBodyClick(evt) {
447
+ if(this.bSectionMenuDisplayed && !this.dSectionMenu.contains(evt.target)) {
448
+ this.hideSectionMenu();
449
+ evt.currentTarget.removeEventListener('click', this.fGlobalBodyClick, false);
450
+ evt.currentTarget.removeEventListener('screenUnloadComplete', this.fGlobalBodyClick, false);
451
+ }
307
452
  }
308
453
 
309
454
  get messages() {
package/src/section.scss CHANGED
@@ -33,16 +33,16 @@
33
33
  }
34
34
 
35
35
  .header-controls {
36
- flex: 0 1 0;
36
+ flex: 0 1 auto;
37
37
  margin: 10px 0 3px;
38
38
 
39
- button {
39
+ button#collapse-control,
40
+ button#section-menu-btn {
40
41
  background: transparent;
41
42
  border: 0;
42
43
  border-radius: 32px;
43
44
  cursor: pointer;
44
45
  height: 32px;
45
- margin-left: 0.5em;
46
46
  margin-top: -7px;
47
47
  transform: rotate(180deg);
48
48
  width: 32px;
@@ -66,6 +66,14 @@
66
66
  transform: rotate(0);
67
67
  }
68
68
  }
69
+
70
+ button#collapse-control {
71
+ margin-left: 0.5em;
72
+ }
73
+
74
+ button#section-menu-btn {
75
+ anchor-name: --section-menu;
76
+ }
69
77
  }
70
78
 
71
79
  &.headless {
@@ -96,6 +104,19 @@
96
104
  }
97
105
  }
98
106
 
107
+ .section-menu-popover {
108
+ display: flex;
109
+ flex-direction: column;
110
+ align-items: flex-end;
111
+
112
+ &:not(.dialog) {
113
+ position: fixed;
114
+ position-anchor: --section-menu;
115
+ top: anchor(bottom);
116
+ right: anchor(right);
117
+ }
118
+ }
119
+
99
120
  }
100
121
 
101
122
  :host([subsection]) {