@csedl/hotwire-svelte-helpers 0.1.1 → 1.0.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/index.js +2 -2
- package/package.json +6 -8
- package/src/lib/config.js +11 -0
- package/src/lib/floating-ui-functions.js +3 -2
- package/src/lib/type-validators.js +34 -0
- package/src/lib/utils.js +111 -60
- package/src/stimulus/dropdown-controller.js +8 -35
- package/src/stimulus/tooltip-controller.js +2 -2
package/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
|
|
2
2
|
import HotwireSvelteHelpers from "./src/lib/config.js";
|
|
3
3
|
import { cleanMount, unmountAllDetached } from './src/svelte/cleanMount';
|
|
4
|
-
import {initializeDropdown,
|
|
4
|
+
import {initializeDropdown, openDropdownPanel, getOrSetPanelId, debugLog} from './src/lib/utils.js'
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
export {
|
|
9
9
|
HotwireSvelteHelpers,
|
|
10
10
|
cleanMount, unmountAllDetached,
|
|
11
|
-
initializeDropdown,
|
|
11
|
+
initializeDropdown, openDropdownPanel, getOrSetPanelId, debugLog
|
|
12
12
|
}
|
package/package.json
CHANGED
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@csedl/hotwire-svelte-helpers",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Hotwire + Svelte helpers for Rails: Stimulus floating dropdowns/toolips + Svelte global panels/modals +
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Hotwire + Svelte helpers for Rails: Stimulus floating dropdowns/toolips + Svelte global panels/modals + RTurbo-friendly utilities. Build together with the rubygem svelte-on-rails and its npm-package.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
8
|
},
|
|
9
9
|
"exports": {
|
|
10
|
-
".":
|
|
11
|
-
"./index.js",
|
|
12
|
-
"./src/utils.js"
|
|
13
|
-
]
|
|
10
|
+
".": "./index.js"
|
|
14
11
|
},
|
|
15
12
|
"repository": {
|
|
16
13
|
"type": "git",
|
|
17
14
|
"url": "git+https://gitlab.com/sedl/csedl-hotwire-svelte-helpers"
|
|
18
15
|
},
|
|
19
16
|
"keywords": [
|
|
20
|
-
"
|
|
17
|
+
"Hotwire",
|
|
21
18
|
"Dropdown",
|
|
22
|
-
"Rails"
|
|
19
|
+
"Rails",
|
|
20
|
+
"Svelte"
|
|
23
21
|
],
|
|
24
22
|
"author": "Christian Sedlmair",
|
|
25
23
|
"license": "MIT",
|
package/src/lib/config.js
CHANGED
|
@@ -3,6 +3,7 @@ import { Application } from "@hotwired/stimulus"
|
|
|
3
3
|
import dc from '../stimulus/dropdown-controller'
|
|
4
4
|
import ttc from '../stimulus/tooltip-controller'
|
|
5
5
|
import ppc from '../stimulus/move-panels-controller'
|
|
6
|
+
import { validateOptions } from "./type-validators";
|
|
6
7
|
|
|
7
8
|
// DEFAULTS
|
|
8
9
|
let _debug = false;
|
|
@@ -34,6 +35,16 @@ const HotwireSvelteHelpers = {
|
|
|
34
35
|
},
|
|
35
36
|
|
|
36
37
|
initializeOverlays(options = {}) {
|
|
38
|
+
|
|
39
|
+
validateOptions(options, {
|
|
40
|
+
closeButtonSelector: 'string',
|
|
41
|
+
dropdownContentSelector: 'string',
|
|
42
|
+
tooltipContentSelector: 'string',
|
|
43
|
+
addArrow: 'boolean',
|
|
44
|
+
persistTooltipOnClick: 'boolean',
|
|
45
|
+
closeOnClickOutsideListenerAdded: 'boolean',
|
|
46
|
+
})
|
|
47
|
+
|
|
37
48
|
const overlays = this.overlays;
|
|
38
49
|
|
|
39
50
|
if (options.closeButtonSelector !== undefined) {
|
|
@@ -42,6 +42,7 @@ export function positionAllPanels(elements) {
|
|
|
42
42
|
|
|
43
43
|
// Positions a single panel relative to its button
|
|
44
44
|
export function positionPanel(button, panel) {
|
|
45
|
+
|
|
45
46
|
let arrowElement = panel.querySelector('#arrow')
|
|
46
47
|
panel.style.removeProperty('height')
|
|
47
48
|
panel.style.removeProperty('left')
|
|
@@ -75,9 +76,9 @@ export function positionPanel(button, panel) {
|
|
|
75
76
|
bottom: '',
|
|
76
77
|
[staticSide]: '-4px',
|
|
77
78
|
});
|
|
78
|
-
debugLog(`panel + arrow positioned`)
|
|
79
|
+
debugLog(`panel + arrow positioned: ${Math.round(x)}/${Math.round(y)}`)
|
|
79
80
|
} else {
|
|
80
|
-
debugLog(`panel positioned`)
|
|
81
|
+
debugLog(`panel positioned: ${Math.round(x)}/${Math.round(y)}`)
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
adjustToWindowBounds(button, panel)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates that all options in `givenOptions` are valid keys
|
|
3
|
+
* and have the correct runtime type as defined in `validations`.
|
|
4
|
+
*
|
|
5
|
+
* @param {Object} givenOptions - The options object to validate
|
|
6
|
+
* @param {Object} validations - Map of option name → expected typeof string
|
|
7
|
+
* e.g. { timeout: 'number', debug: 'boolean' }
|
|
8
|
+
* @throws {Error} If an invalid option is found or type doesn't match
|
|
9
|
+
*/
|
|
10
|
+
export function validateOptions(givenOptions, validations) {
|
|
11
|
+
const validKeys = Object.keys(validations);
|
|
12
|
+
|
|
13
|
+
for (const option of Object.keys(givenOptions)) {
|
|
14
|
+
// Check if the option is allowed
|
|
15
|
+
if (!validKeys.includes(option)) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
`Invalid option: "${option}". ` +
|
|
18
|
+
`Available options are:\n • ${validKeys.map(k => `"${k}"`).join("\n • ")}`
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Check the type
|
|
23
|
+
const expectedType = validations[option];
|
|
24
|
+
const actualType = typeof givenOptions[option];
|
|
25
|
+
|
|
26
|
+
if (actualType !== expectedType) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`Option «${option}»: expected type «${expectedType}», ` +
|
|
29
|
+
`but received «${actualType}» ` +
|
|
30
|
+
`(value: ${JSON.stringify(givenOptions[option])})`
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/lib/utils.js
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
import {positionPanelSelf, positionPanelByButton} from "./floating-ui-functions.js";
|
|
1
|
+
import {positionPanelSelf, positionPanelByButton, positionPanel} from "./floating-ui-functions.js";
|
|
2
|
+
import {validateOptions} from "./type-validators";
|
|
2
3
|
|
|
3
4
|
// Fetch content from server based on panel's data-src attribute and update content
|
|
4
|
-
export function
|
|
5
|
+
export function openDropdownPanel(buttonElement, panelElement, options = {}) {
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
if (buttonElement.classList.contains('has-open-panel')) {return}
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
//validateOptions(options, {clickedElement: 'object'})
|
|
10
|
+
//const clickedElement = options.clickedElement || buttonElement;
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
|
|
13
|
+
// link button and panel, initialize
|
|
14
|
+
panelElement.id = getOrSetPanelId(buttonElement);
|
|
15
|
+
initializeDropdown(buttonElement)
|
|
16
|
+
debugLog(`opening panel ${panelElement.id.split('-').pop()}`)
|
|
17
|
+
panelElement.style.display = 'block';
|
|
11
18
|
|
|
12
19
|
// add arrow
|
|
13
20
|
if (window.HotwireSvelteHelpers.overlays.addArrow) {
|
|
14
|
-
if (!
|
|
21
|
+
if (!panelElement.querySelector(':scope > #arrow')) {
|
|
15
22
|
const arrowTag = document.createElement('div');
|
|
16
23
|
arrowTag.id = 'arrow';
|
|
17
|
-
|
|
24
|
+
panelElement.appendChild(arrowTag)
|
|
18
25
|
}
|
|
19
26
|
}
|
|
20
27
|
|
|
21
|
-
|
|
28
|
+
positionPanel(buttonElement, panelElement);
|
|
22
29
|
|
|
23
30
|
// Set focus to input element
|
|
24
|
-
if (
|
|
25
|
-
let dataFocus =
|
|
26
|
-
let focusElement =
|
|
31
|
+
if (panelElement.hasAttribute('data-set-focus')) {
|
|
32
|
+
let dataFocus = panelElement.getAttribute('data-set-focus');
|
|
33
|
+
let focusElement = panelElement.querySelector(dataFocus);
|
|
27
34
|
focusElement.focus();
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
// Set status attribute
|
|
31
|
-
|
|
32
|
-
|
|
38
|
+
panelElement.setAttribute('data-hsh-panel-status', 'open');
|
|
39
|
+
buttonElement.classList.add('has-open-panel');
|
|
33
40
|
|
|
34
41
|
// Dispatch events
|
|
35
42
|
const panelOpenEvent = new CustomEvent('before-open');
|
|
36
|
-
|
|
43
|
+
panelElement.dispatchEvent(panelOpenEvent);
|
|
37
44
|
|
|
38
45
|
const buttonOpenEvent = new CustomEvent('before-open-panel');
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
// Add listener for closing on outside click
|
|
42
|
-
if (!window.HotwireSvelteHelpers.overlays.closeOnClickOutsideListenerAdded) {
|
|
43
|
-
window.HotwireSvelteHelpers.overlays.closeOnClickOutsideListenerAdded = true;
|
|
44
|
-
window.addEventListener('click', closeOnOutsideClick);
|
|
45
|
-
debugLog('Listener for close panels on click outside added');
|
|
46
|
-
}
|
|
46
|
+
buttonElement.dispatchEvent(buttonOpenEvent);
|
|
47
47
|
|
|
48
48
|
// fetch content from server
|
|
49
|
-
const src =
|
|
49
|
+
const src = panelElement.getAttribute('data-src');
|
|
50
50
|
if (src) {
|
|
51
51
|
let xhr = new XMLHttpRequest();
|
|
52
52
|
debugLog(`Panel / data-src: «${src}»`);
|
|
@@ -56,46 +56,48 @@ export function onPanelOpen(event, button) {
|
|
|
56
56
|
if (xhr.status !== 200) {
|
|
57
57
|
alert(`Dropdown Controller, GET «${src}», Error ${xhr.status}: ${xhr.statusText}`);
|
|
58
58
|
} else {
|
|
59
|
-
const
|
|
60
|
-
const ctrl =
|
|
59
|
+
const buttonElement = document.querySelector(`[data-panel-id="${panelElement.id}"]`);
|
|
60
|
+
const ctrl = buttonElement.getAttribute('data-controller');
|
|
61
61
|
const config = window.HotwireSvelteHelpers.overlays;
|
|
62
62
|
const contentSelector = config.dropdownContentSelector;
|
|
63
63
|
|
|
64
64
|
if (ctrl === 'csedl-dropdown' && contentSelector) {
|
|
65
65
|
debugLog(`dropdown / contentSelector: «${contentSelector}»`);
|
|
66
|
-
const wrapper =
|
|
66
|
+
const wrapper = panelElement.querySelector(contentSelector);
|
|
67
67
|
wrapper.innerHTML = xhr.response;
|
|
68
68
|
} else if (ctrl === 'csedl-tooltip' && contentSelector) {
|
|
69
69
|
debugLog(`tooltip / contentSelector: «${contentSelector}»`);
|
|
70
|
-
const wrapper =
|
|
70
|
+
const wrapper = panelElement.querySelector(config.tooltipContentSelector);
|
|
71
71
|
wrapper.innerHTML = xhr.response;
|
|
72
72
|
} else {
|
|
73
73
|
debugLog(`? / contentSelector: «${contentSelector}»`);
|
|
74
|
-
|
|
74
|
+
panelElement.innerHTML = xhr.response;
|
|
75
75
|
console.error('fallback to replace whole panel');
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
positionPanelByButton(
|
|
78
|
+
positionPanelByButton(buttonElement, `after http-request "${ctrl}"`);
|
|
79
79
|
}
|
|
80
80
|
};
|
|
81
81
|
} else {
|
|
82
82
|
debugLog('no data-src attribute provided on panel');
|
|
83
83
|
}
|
|
84
|
+
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
// Handle panel closing
|
|
87
|
-
export function
|
|
88
|
+
export function closePanel(button) {
|
|
88
89
|
|
|
89
|
-
const panel =
|
|
90
|
+
const panel = findPanelOrThrow(button);
|
|
90
91
|
|
|
91
|
-
debugLog('
|
|
92
|
+
debugLog(`closing panel ${panel.id.split('-').pop()}`)
|
|
92
93
|
|
|
93
94
|
// Update status attributes
|
|
94
95
|
button.classList.remove('has-open-panel');
|
|
95
|
-
panel.setAttribute('data-
|
|
96
|
+
panel.setAttribute('data-hsh-panel-status', 'closed');
|
|
97
|
+
panel.style.display = 'none';
|
|
96
98
|
|
|
97
99
|
// Remove outside click listener if no panels are open
|
|
98
|
-
const openPanels = document.querySelectorAll("[data-
|
|
100
|
+
const openPanels = document.querySelectorAll("[data-hsh-panel-status='open']");
|
|
99
101
|
debugLog(`panel closed, still open: ${openPanels.length}`);
|
|
100
102
|
if (window.HotwireSvelteHelpers.closeOnClickOutsideListenerAdded && openPanels.length === 0) {
|
|
101
103
|
window.HotwireSvelteHelpers.closeOnClickOutsideListenerAdded = false;
|
|
@@ -109,12 +111,27 @@ export function onPanelClose(button) {
|
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
// Close panels when clicking outside
|
|
112
|
-
export function closeOnOutsideClick(
|
|
114
|
+
export function closeOnOutsideClick(clickedElement) {
|
|
115
|
+
|
|
116
|
+
// set button
|
|
117
|
+
let btn
|
|
118
|
+
if (clickedElement instanceof HTMLElement) {
|
|
119
|
+
btn = clickedElement;
|
|
120
|
+
} else if (clickedElement instanceof Event) {
|
|
121
|
+
btn = clickedElement.target;
|
|
122
|
+
} else {
|
|
123
|
+
console.error('closeOnOutsideClick: invalid argument', clickedElement);
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// do nothing if clicked within button or panel
|
|
128
|
+
const in_btn = btn.closest(".dropdown-button");
|
|
129
|
+
const in_panel = btn.closest(".dropdown-panel");
|
|
130
|
+
if (in_btn || in_panel) return;
|
|
113
131
|
|
|
114
|
-
let btn = ev.target;
|
|
115
132
|
let parentPanelIds = [];
|
|
116
133
|
|
|
117
|
-
const persistElement =
|
|
134
|
+
const persistElement = btn.closest('[data-overlay-persist]');
|
|
118
135
|
if (persistElement) {
|
|
119
136
|
if (persistElement.getAttribute('data-overlay-persist') !== 'false') {
|
|
120
137
|
debugLog('closing panel prevented because the target element has attribute "data-overlay-persist"');
|
|
@@ -122,10 +139,10 @@ export function closeOnOutsideClick(ev) {
|
|
|
122
139
|
}
|
|
123
140
|
}
|
|
124
141
|
|
|
125
|
-
debugLog('closeOnOutsideClick called,
|
|
142
|
+
debugLog('closeOnOutsideClick called, clicked on:', btn);
|
|
126
143
|
|
|
127
144
|
while (true) {
|
|
128
|
-
const parentPanel = btn.closest("[data-
|
|
145
|
+
const parentPanel = btn.closest("[data-hsh-panel-status='open']");
|
|
129
146
|
if (parentPanel) {
|
|
130
147
|
parentPanelIds.push(parentPanel.id);
|
|
131
148
|
btn = document.querySelector(`[data-panel-id="${parentPanel.id}"]`);
|
|
@@ -134,11 +151,14 @@ export function closeOnOutsideClick(ev) {
|
|
|
134
151
|
}
|
|
135
152
|
}
|
|
136
153
|
|
|
137
|
-
const openPanels = document.querySelectorAll("[data-
|
|
154
|
+
const openPanels = document.querySelectorAll("[data-hsh-panel-status='open']");
|
|
138
155
|
for (const panel of openPanels) {
|
|
139
156
|
if (!parentPanelIds.includes(panel.id)) {
|
|
157
|
+
debugLog(`closeOnOutsideClick: dispatching close event for panel ${panel.id.split('-').pop()}`);
|
|
140
158
|
const ev = new Event('close');
|
|
141
159
|
panel.dispatchEvent(ev);
|
|
160
|
+
} else {
|
|
161
|
+
debugLog('closeOnOutsideClick: panel is still open:', panel);
|
|
142
162
|
}
|
|
143
163
|
}
|
|
144
164
|
}
|
|
@@ -156,22 +176,58 @@ export function initializeDropdown(button) {
|
|
|
156
176
|
throw new Error(`panel element not found by ID: «${panel_id}»`);
|
|
157
177
|
}
|
|
158
178
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
179
|
+
let msg = []
|
|
180
|
+
|
|
181
|
+
// initialize panel
|
|
182
|
+
if (!panel.hasAttribute('data-hsh-initialized')) {
|
|
183
|
+
panel.setAttribute('data-hsh-initialized', 'true');
|
|
184
|
+
|
|
185
|
+
// Add close button functionality
|
|
186
|
+
const selector = window.HotwireSvelteHelpers.overlays.closeButtonSelector;
|
|
187
|
+
const closeButtons = panel.querySelectorAll(selector);
|
|
188
|
+
for (const btn of closeButtons) {
|
|
189
|
+
btn.addEventListener('click', () => {
|
|
190
|
+
const ev = new Event('close');
|
|
191
|
+
panel.dispatchEvent(ev);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
// Add event listeners to panel
|
|
195
|
+
panel.addEventListener('place-me', () => positionPanelSelf(panel));
|
|
196
|
+
panel.addEventListener('close', () => closePanel(button))
|
|
197
|
+
msg.push('panel')
|
|
198
|
+
} else {
|
|
199
|
+
debugLog('initializeDropdown: panel already initialized:', panel.id.split('-').pop())
|
|
167
200
|
}
|
|
168
201
|
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
202
|
+
// initialize the button
|
|
203
|
+
if (!button.hasAttribute('data-hsh-initialized')) {
|
|
204
|
+
button.setAttribute('data-hsh-initialized', 'true');
|
|
205
|
+
button.addEventListener('place-panel', () => positionPanelByButton(button))
|
|
206
|
+
msg.push('button')
|
|
207
|
+
}
|
|
173
208
|
|
|
174
|
-
|
|
209
|
+
// Add listener for closing on outside click
|
|
210
|
+
let overlays = window.HotwireSvelteHelpers.overlays
|
|
211
|
+
if (!overlays.closeOnClickOutsideListenerAdded) {
|
|
212
|
+
overlays.closeOnClickOutsideListenerAdded = true;
|
|
213
|
+
setTimeout(() => {
|
|
214
|
+
window.addEventListener('click', closeOnOutsideClick)
|
|
215
|
+
}, 100)
|
|
216
|
+
msg.push('close-on-outside-click')
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
if (msg.length > 0) {
|
|
221
|
+
debugLog(`Initialized «${panel_id}»: ${msg.join(' + ')}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function findPanelOrThrow(button) {
|
|
226
|
+
const panel = document.getElementById(button.getAttribute('data-panel-id'))
|
|
227
|
+
if (!panel) {
|
|
228
|
+
throw new Error(`dropdown button not found by attribute data-panel-id: «${button.getAttribute('data-panel-id')}»`)
|
|
229
|
+
}
|
|
230
|
+
return (panel)
|
|
175
231
|
}
|
|
176
232
|
|
|
177
233
|
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
@@ -217,10 +273,5 @@ function generateRandomHex(n) {
|
|
|
217
273
|
).join('');
|
|
218
274
|
}
|
|
219
275
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if (!panel) {
|
|
223
|
-
throw new Error(`dropdown button not found by attribute data-panel-id: «${button.getAttribute('data-panel-id')}»`)
|
|
224
|
-
}
|
|
225
|
-
return(panel)
|
|
226
|
-
}
|
|
276
|
+
|
|
277
|
+
|
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
import {Controller} from "@hotwired/stimulus"
|
|
2
|
-
import {
|
|
3
|
-
import {debugLog} from "../lib/utils.js";
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
import { openDropdownPanel, closePanel, findPanelOrThrow } from "../lib/utils.js";
|
|
3
|
+
import { debugLog } from "../lib/utils.js";
|
|
4
4
|
|
|
5
5
|
export default class extends Controller {
|
|
6
6
|
|
|
7
7
|
connect() {
|
|
8
8
|
|
|
9
|
-
initializeDropdown(this.element)
|
|
10
|
-
|
|
11
9
|
this.element.addEventListener('click', (e) => this.toggle(e))
|
|
12
10
|
|
|
13
|
-
debugLog('dropdown connected')
|
|
14
|
-
|
|
15
11
|
}
|
|
16
12
|
|
|
17
13
|
|
|
@@ -21,38 +17,15 @@ export default class extends Controller {
|
|
|
21
17
|
}
|
|
22
18
|
e.stopPropagation()
|
|
23
19
|
debugLog('toggle panel', e)
|
|
24
|
-
|
|
25
|
-
const panel =
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
} else if (panel.style.display === 'block') {
|
|
29
|
-
this.close(panel)
|
|
20
|
+
|
|
21
|
+
const panel = findPanelOrThrow(this.element)
|
|
22
|
+
if (panel.style.display === 'block') {
|
|
23
|
+
closePanel(this.element)
|
|
30
24
|
} else {
|
|
31
|
-
this.
|
|
25
|
+
openDropdownPanel(this.element, panel)
|
|
32
26
|
}
|
|
33
27
|
}
|
|
34
28
|
|
|
35
|
-
open(e, panel) {
|
|
36
|
-
|
|
37
|
-
// open the panel
|
|
38
|
-
|
|
39
|
-
panel.style.display = 'block';
|
|
40
|
-
debugLog('opened panel:', panel)
|
|
41
|
-
|
|
42
|
-
onPanelOpen(e, this.element)
|
|
43
|
-
|
|
44
|
-
panel.addEventListener('close', () => this.close(panel))
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
close(panel) {
|
|
49
|
-
|
|
50
|
-
// Close actions
|
|
51
|
-
|
|
52
|
-
panel.style.display = 'none';
|
|
53
|
-
debugLog('panel closed:', panel)
|
|
54
|
-
|
|
55
|
-
}
|
|
56
29
|
|
|
57
30
|
|
|
58
31
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {Controller} from "@hotwired/stimulus"
|
|
2
2
|
import {positionPanelByButton} from "../lib/floating-ui-functions.js";
|
|
3
|
-
import {debugLog,
|
|
3
|
+
import {debugLog, findPanelOrThrow, openDropdownPanel} from "../lib/utils.js";
|
|
4
4
|
|
|
5
5
|
export default class extends Controller {
|
|
6
6
|
|
|
@@ -42,7 +42,7 @@ export default class extends Controller {
|
|
|
42
42
|
|
|
43
43
|
open(e, panel_id) {
|
|
44
44
|
this.element.classList.add('tooltip-is-visible')
|
|
45
|
-
|
|
45
|
+
openDropdownPanel(this.element, findPanelOrThrow(this.element))
|
|
46
46
|
this.opening_timer_id = null
|
|
47
47
|
let panel = document.getElementById(panel_id)
|
|
48
48
|
panel.style.display = 'block';
|