@ewc-lib/ewc-popovers 2.0.4-beta → 2.1.0-alpha

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.
@@ -3,7 +3,9 @@
3
3
  "main": "src/main.js",
4
4
  "license": "EUPL v.1.1",
5
5
  "peerDependencies": {
6
- "@ewc-lib/ewc-css-common": "0.1.0",
7
- "@ewc-lib/ewc-dialogs": "5.0.8-beta"
6
+ "@ewc-lib/ewc-css-common": "0.1.0"
7
+ },
8
+ "optionalDependencies": {
9
+ "@ewc-lib/ewc-dialogs": "5.0.10"
8
10
  }
9
11
  }
@@ -27,6 +27,7 @@ ewc-popover must have 2 children:
27
27
 
28
28
  - an HTML element to open/close the popover (**slot="toggle"**)
29
29
  - the position of the popover is relative to this element
30
+ - Note: eventListeners (click and keyboard) are being attached to the element ("toggleElement" in element.js)
30
31
  - the content of the popover (**slot="content"**)
31
32
  - this element is expected to have "display:inline" style
32
33
 
@@ -61,3 +62,13 @@ An element within the content can be specified to close the popover.
61
62
  This is done by setting the attribute "**data-ewc-popover-close**" on it.
62
63
  Just existence is checked, value doesn't matter.
63
64
  Use case: a close button inside the popover.
65
+
66
+ ## Suppressing tooltips
67
+
68
+ On a child with slot="toggle" attribute, the attribute "tooltip-suppressed" is set to "true" when popover opens and set to "false" when the popover closes.
69
+
70
+ This can be seen as an optional interface.
71
+
72
+ If the child implements that interface, the popover expects the child to not show any tooltip. If the child does not inplement that interface, nothing happens - ⚠️ as long as the child doesn't expose any other functionality via the attribute "tooltip-suppressed".
73
+
74
+ Note: ewc-icon-button (a WebComponent intended to be used together with this popover) implements this interface.
@@ -1,4 +1,4 @@
1
- import * as POPOVER from "./popover.js"
1
+ import Popover from "./popover.js"
2
2
  import MARKUP from "./markup.js" // keep this file markup free
3
3
  import CSS from "./css.js"
4
4
 
@@ -6,15 +6,18 @@ import CSS from "./css.js"
6
6
  export default class Element extends HTMLElement {
7
7
 
8
8
  #isInitialized=false
9
- #popover
9
+ #popover = null
10
+ #toggleElement = null
10
11
 
11
12
  constructor() {
12
- super()
13
+ super()
14
+ this.toggleVisibility = this.toggleVisibility.bind(this)
15
+ this.handleClickGlobal = this.handleClickGlobal.bind(this)
13
16
  }
14
17
 
15
18
  connectedCallback(ignoreCheck) {
16
19
  if(this.#isInitialized) { return } else { this.#isInitialized=true }
17
- this.setAttribute("ewc-version", "2.0.4-beta") // please always keep in sync with version in package.json
20
+ this.setAttribute("ewc-version", "2.1.0-alpha") // please always keep in sync with version in package.json
18
21
  if(ignoreCheck || this.childElementCount===2) {
19
22
  // please see also comment in html.js
20
23
 
@@ -24,13 +27,25 @@ export default class Element extends HTMLElement {
24
27
  this.shadowRoot.appendChild( MARKUP().cloneNode(true) )
25
28
 
26
29
  const rootElement = this.shadowRoot.querySelector(".main_container")
27
- const toggleElement = this.shadowRoot.querySelector("slot[name=toggle]").assignedElements()[0]
30
+ this.#toggleElement = this.shadowRoot.querySelector("slot[name=toggle]").assignedElements()[0]
28
31
  const p = {
29
- toggleElement : toggleElement,
32
+ toggleElement : this.#toggleElement,
30
33
  positioninghint : this.hasAttribute("positioninghint") ? this.getAttribute("positioninghint").toLowerCase() : false
31
34
  }
32
- this.#popover = new POPOVER.Popover( rootElement, p).init()
33
-
35
+ this.#popover = new Popover(rootElement, p).init()
36
+
37
+ if (this.#toggleElement) {
38
+ this.#toggleElement.addEventListener('click', this.toggleVisibility);
39
+ }
40
+
41
+ if (this.#toggleElement) {
42
+ this.#toggleElement.addEventListener('keydown', e=>{
43
+ if(e.key==="Enter" || e.key===" " || e.key==="ArrowDown") {this.toggleVisibility(e)}
44
+ })
45
+ }
46
+
47
+ document.addEventListener('click', this.handleClickGlobal);
48
+
34
49
  } else {
35
50
  console.error("popover: Must have 2 children: the toggle-element and the content.")
36
51
  }
@@ -41,19 +56,61 @@ export default class Element extends HTMLElement {
41
56
 
42
57
  set visibility(val) {
43
58
  if(val==true) {
59
+ this.#toggleElement.setAttribute("tooltip-suppressed", "true")
44
60
  this.#popover.openPopover()
61
+ this.#popover.positionPopover()
45
62
  } else {
63
+ this.#toggleElement.setAttribute("tooltip-suppressed", "false")
46
64
  this.#popover.closePopover()
47
65
  }
48
66
  }
49
67
 
50
- toggleVisibility() {
68
+ toggleVisibility(e) {
69
+ if(e) {e.preventDefault()}
70
+
51
71
  if(this.#popover.isOpen()) {
52
- this.#popover.closePopover()
72
+ this.visibility = false
53
73
  } else {
54
- this.#popover.openPopover()
74
+ this.visibility = true
55
75
  }
56
76
  }
57
77
 
58
78
  setFocusToToggleElement() {this.#popover.setFocusToToggleElement()}
79
+
80
+ /**
81
+ * Handles global click events, triggered outside of the popover.
82
+ * It's tediously complicated :-(
83
+ */
84
+ handleClickGlobal(e) {
85
+ if (this.#popover.isOpen()) {
86
+
87
+ const rootElement = this.shadowRoot.querySelector(".main_container")
88
+
89
+ // this is the whole popover area
90
+ // we're in shadow DOM. test if element containing content is in also in shadow or in light DOM
91
+ const content = rootElement.querySelector("slot[name=content]")
92
+ const cond1 = content ? content.assignedElements()[0].contains(e.target) : rootElement.querySelector(".ewc-popover__content").contains(e.target)
93
+
94
+ // this is the designated element to toggle the popover
95
+ const cond2 = e.target === this.#toggleElement || e.target === this.#toggleElement.firstElementChild
96
+
97
+ // this is the custom property itself
98
+ // also include derived classes
99
+ const cond3 = e.target.nodeName.slice(0, 11)==="EWC-POPOVER"
100
+
101
+ // this is the element inside the content area with which it should be closed
102
+ // close when such an element was clicked
103
+ const cond4 = e.target.hasAttribute("data-ewc-popover-close")
104
+
105
+ //console.log(!cond2,!cond3,!cond1,cond4)
106
+
107
+ // close if anything other than the popover was clicked
108
+ if(!cond2 && !cond3 && (!cond1 || cond4)) {
109
+ e.preventDefault()
110
+ e.stopImmediatePropagation()
111
+ this.visibility=false
112
+ }
113
+ }
114
+ }
115
+
59
116
  }
@@ -16,7 +16,7 @@ See also comment in html.js
16
16
  * @param {Boolean} options.attachClickListener
17
17
  * @param {Boolean} options.attachKeyListener
18
18
  */
19
- export class Popover {
19
+ export default class Popover {
20
20
 
21
21
  constructor(
22
22
  element,
@@ -53,9 +53,7 @@ export class Popover {
53
53
  this.openPopover = this.openPopover.bind(this);
54
54
  this.closePopover = this.closePopover.bind(this);
55
55
  this.positionPopover = this.positionPopover.bind(this);
56
- this.handleClickOnToggle = this.handleClickOnToggle.bind(this);
57
56
  this.handleKeyboardGlobal = this.handleKeyboardGlobal.bind(this);
58
- this.handleClickGlobal = this.handleClickGlobal.bind(this);
59
57
  this.checkPosition = this.checkPosition.bind(this);
60
58
  this.resetStyles = this.resetStyles.bind(this);
61
59
 
@@ -79,23 +77,10 @@ export class Popover {
79
77
  if (this.attachKeyListener) {
80
78
  document.addEventListener('keyup', this.handleKeyboardGlobal);
81
79
  }
82
- if (this.attachClickListener) {
83
- document.addEventListener('click', this.handleClickGlobal);
84
- }
85
80
 
86
81
  window.addEventListener('resize', this.checkPosition);
87
82
  document.addEventListener('scroll', this.checkPosition);
88
83
 
89
- if (this.attachClickListener && this.toggle) {
90
- this.toggle.addEventListener('click', this.handleClickOnToggle);
91
- }
92
-
93
- if (this.attachKeyListener && this.toggle) {
94
- this.toggle.addEventListener('keydown', e=>{
95
- if(e.key==="Enter" || e.key===" " || e.key==="ArrowDown") {this.handleClickOnToggle(e)}
96
- })
97
- }
98
-
99
84
  return this
100
85
  }
101
86
 
@@ -109,35 +94,16 @@ export class Popover {
109
94
  if (this.attachKeyListener) {
110
95
  document.removeEventListener('keyup', this.handleKeyboardGlobal);
111
96
  }
112
- if (this.attachClickListener) {
113
- document.removeEventListener('click', this.handleClickGlobal);
114
- }
115
97
 
116
98
  if (this.toggle.getAttribute('aria-expanded') === 'true') {
117
99
  this.closePopover();
118
100
  }
119
101
  }
120
102
 
121
- #isOpen() {
103
+ isOpen() {
122
104
  return this.container.style.display!=="none" && this.container.style.display!==""
123
105
  }
124
106
 
125
- /**
126
- * Toggles between collapsed/expanded states.
127
- *
128
- * @param {Event} e
129
- */
130
- handleClickOnToggle(e) {
131
- e.preventDefault();
132
- // Toggle the popover
133
- if (this.#isOpen()) {
134
- this.closePopover();
135
- return;
136
- }
137
- this.openPopover();
138
- this.positionPopover();
139
- }
140
-
141
107
  openPopover() {
142
108
  this.toggle.setAttribute('aria-expanded', 'true');
143
109
  this.container.style.display="block"
@@ -348,7 +314,7 @@ export class Popover {
348
314
  checkPosition() {
349
315
  clearTimeout(this.resizeTimer);
350
316
  this.resizeTimer = setTimeout(() => {
351
- if(this.#isOpen()) {
317
+ if(this.isOpen()) {
352
318
  this.positionPopover();
353
319
  }
354
320
  }, 200);
@@ -363,7 +329,7 @@ export class Popover {
363
329
  if (!this.container) return;
364
330
 
365
331
  // assume there's maximally only 1 open
366
- if(this.#isOpen()) {
332
+ if(this.isOpen()) {
367
333
  if (e.key === 'Escape' || e.key === 'Esc') {
368
334
  this.closePopover();
369
335
  this.setFocusToToggleElement()
@@ -372,42 +338,7 @@ export class Popover {
372
338
  }
373
339
 
374
340
  setFocusToToggleElement() {
375
- this.element.firstElementChild.assignedElements()[0].focus()
341
+ this.toggle.focus()
376
342
  }
377
343
 
378
- /**
379
- * Handles global click events, triggered outside of the popover.
380
- * It's tediously complicated :-(
381
- */
382
- handleClickGlobal(e) {
383
- if (!this.container) return;
384
-
385
- if (this.#isOpen()) {
386
-
387
- // this is the whole popover area
388
- // we're in shadow DOM. test if element containing content is in also in shadow or in light DOM
389
- const content = this.container.querySelector("slot[name=content]")
390
- const cond1 = content ? content.assignedElements()[0].contains(e.target) : this.container.querySelector(".ewc-popover__content").contains(e.target)
391
-
392
- // this is the designated element to toggle the popover
393
- const cond2 = e.target === this.toggle || e.target === this.toggle.firstElementChild
394
-
395
- // this is the custom property itself
396
- // also include derived classes
397
- const cond3 = e.target.nodeName.slice(0, 11)==="EWC-POPOVER"
398
-
399
- // this is the element inside the content area with which it should be closed
400
- // close when such an element was clicked
401
- const cond4 = e.target.hasAttribute("data-ewc-popover-close")
402
-
403
- //console.log(!cond2,cond3,cond1,cond4)
404
-
405
- // close if anything other than the popover was clicked
406
- if(!cond2 && !cond3 && (!cond1 || cond4)) {
407
- e.preventDefault()
408
- e.stopImmediatePropagation()
409
- this.closePopover();
410
- }
411
- }
412
- }
413
344
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@ewc-lib/ewc-popovers",
3
3
  "description": "Monorepo for EWCL popover WebComponents",
4
4
  "//": "please always keep version in sync with version info in the sourcecode",
5
- "version": "2.0.4-beta",
5
+ "version": "2.1.0-alpha",
6
6
  "workspaces": [
7
7
  "ewc-popover",
8
8
  "ewc-popover-sharing"
package/readme.md CHANGED
@@ -118,3 +118,12 @@ Before the 2 popover components were grouped together into this monorepo, they e
118
118
 
119
119
  - 2.0.4-beta
120
120
  - fix opener bug for X
121
+
122
+ - 2.0.4
123
+ - drop beta
124
+
125
+ - 2.0.5-alpha
126
+ - consolidation of development workflow
127
+
128
+ - 2.1.0-alpha
129
+ - use a child's optional "tooltip-suppressed" functionality