turbo_boost-elements 0.0.14 → 0.0.15
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.
- checksums.yaml +4 -4
- data/app/assets/builds/@turbo-boost/commands.metafile.json +1 -0
- data/app/assets/builds/@turbo-boost/elements.js +34 -39
- data/app/assets/builds/@turbo-boost/elements.js.map +4 -4
- data/app/assets/builds/@turbo-boost/elements.metafile.json +1 -0
- data/app/javascript/elements/toggle_elements/target_element/index.js +20 -24
- data/app/javascript/elements/toggle_elements/toggle_element/index.js +10 -10
- data/app/javascript/elements/toggle_elements/trigger_element/focus.js +6 -22
- data/app/javascript/elements/toggle_elements/trigger_element/index.js +102 -66
- data/app/javascript/elements/turbo_boost_element/index.js +7 -10
- data/app/javascript/index.js +1 -1
- data/lib/turbo_boost/elements/version.rb +1 -1
- metadata +5 -11
- data/app/javascript/devtools/dependencies.js +0 -53
- data/app/javascript/devtools/elements/devtool_element.js +0 -75
- data/app/javascript/devtools/elements/supervisor_element.js +0 -136
- data/app/javascript/devtools/elements/tooltip_element.js +0 -121
- data/app/javascript/devtools/index.js +0 -5
- data/app/javascript/devtools/supervisor.js +0 -116
- data/app/javascript/elements/toggle_elements/trigger_element/devtool.js +0 -374
- data/app/javascript/utils/dom.js +0 -70
@@ -1,374 +0,0 @@
|
|
1
|
-
// Icons courtesy of https://feathericons.com/
|
2
|
-
import {
|
3
|
-
appendHTML,
|
4
|
-
addHighlight,
|
5
|
-
attempt,
|
6
|
-
coordinates,
|
7
|
-
removeHighlight
|
8
|
-
} from '../../../utils/dom'
|
9
|
-
import supervisor from '../../../devtools/supervisor'
|
10
|
-
|
11
|
-
let activeToggle
|
12
|
-
|
13
|
-
document.addEventListener('turbo-boost:devtools-start', () =>
|
14
|
-
supervisor.register('toggle', 'toggles')
|
15
|
-
)
|
16
|
-
|
17
|
-
function appendTooltip (title, subtitle, content, options = {}) {
|
18
|
-
let { backgroundColor, color, position } = options
|
19
|
-
color = color || 'white'
|
20
|
-
position = position || 'top'
|
21
|
-
return appendHTML(`
|
22
|
-
<turbo-boost-devtool-tooltip position="${position}" background-color="${backgroundColor}" color="${color}">
|
23
|
-
<div slot='title'>${title}</div>
|
24
|
-
<div slot='subtitle'>${subtitle}</div>
|
25
|
-
${content}
|
26
|
-
</turbo-boost-devtool-tooltip>
|
27
|
-
`)
|
28
|
-
}
|
29
|
-
|
30
|
-
export default class Devtool {
|
31
|
-
constructor (triggerElement) {
|
32
|
-
this.name = 'toggle'
|
33
|
-
this.command = triggerElement.dataset.turboCommand
|
34
|
-
this.triggerElement = triggerElement // SEE: app/javascript/elements/toggle_trigger_element.js
|
35
|
-
this.targetElement = triggerElement.targetElement // SEE: app/javascript/elements/toggle_target_element.js
|
36
|
-
this.morphElement = triggerElement.morphElement
|
37
|
-
|
38
|
-
let hideTimeout
|
39
|
-
const debouncedHide = () => {
|
40
|
-
clearTimeout(hideTimeout)
|
41
|
-
hideTimeout = setTimeout(this.hide({ active: false }), 25)
|
42
|
-
}
|
43
|
-
|
44
|
-
this.eventListeners['turbo-boost:devtool-enable'] = event => {
|
45
|
-
// LeaderLine.positionByWindowResize = false
|
46
|
-
const { name } = event.detail
|
47
|
-
if (name !== this.name) return
|
48
|
-
|
49
|
-
addHighlight(this.triggerElement, {
|
50
|
-
outline: '3px dashed blueviolet',
|
51
|
-
outlineOffset: '2px'
|
52
|
-
})
|
53
|
-
|
54
|
-
this.hide({ active: false })
|
55
|
-
if (this.active) this.show()
|
56
|
-
}
|
57
|
-
|
58
|
-
this.eventListeners['turbo-boost:devtool-disable'] = event => {
|
59
|
-
const { name } = event.detail
|
60
|
-
if (name === this.name) removeHighlight(this.triggerElement)
|
61
|
-
}
|
62
|
-
|
63
|
-
this.eventListeners['click'] = event => {
|
64
|
-
if (event.target.closest('turbo-boost-devtool-tooltip')) return
|
65
|
-
debouncedHide()
|
66
|
-
}
|
67
|
-
|
68
|
-
this.eventListeners['turbo:load'] = debouncedHide
|
69
|
-
this.eventListeners['turbo-frame:load'] = debouncedHide
|
70
|
-
this.eventListeners[TurboBoost.Commands.events.finish] = debouncedHide
|
71
|
-
|
72
|
-
this.registerEventListeners()
|
73
|
-
}
|
74
|
-
|
75
|
-
registerEventListeners () {
|
76
|
-
Object.entries(this.eventListeners).forEach(([type, listener]) => {
|
77
|
-
addEventListener(type, listener)
|
78
|
-
})
|
79
|
-
}
|
80
|
-
|
81
|
-
unregisterEventListeners () {
|
82
|
-
Object.entries(this.eventListeners).forEach(([type, listener]) => {
|
83
|
-
removeEventListener(type, listener)
|
84
|
-
})
|
85
|
-
}
|
86
|
-
|
87
|
-
get eventListeners () {
|
88
|
-
return this._eventListeners || (this._eventListeners = {})
|
89
|
-
}
|
90
|
-
|
91
|
-
get enabled () {
|
92
|
-
return supervisor.enabled(this.name)
|
93
|
-
}
|
94
|
-
|
95
|
-
get active () {
|
96
|
-
return activeToggle === this
|
97
|
-
}
|
98
|
-
|
99
|
-
set active (value) {
|
100
|
-
if (value) activeToggle = this
|
101
|
-
else activeToggle = null
|
102
|
-
}
|
103
|
-
|
104
|
-
show () {
|
105
|
-
if (!this.enabled) return
|
106
|
-
|
107
|
-
if (this.active) return
|
108
|
-
this.active = true
|
109
|
-
|
110
|
-
this.hide({ active: true })
|
111
|
-
|
112
|
-
addHighlight(this.targetElement, {
|
113
|
-
outline: '3px dashed darkcyan',
|
114
|
-
outlineOffset: '-2px'
|
115
|
-
})
|
116
|
-
|
117
|
-
addHighlight(this.triggerElement.morphElement, {
|
118
|
-
outline: '3px dashed chocolate',
|
119
|
-
outlineOffset: '3px'
|
120
|
-
})
|
121
|
-
|
122
|
-
this.renderingTooltip = this.createRenderingTooltip()
|
123
|
-
this.targetTooltip = this.createTargetTooltip()
|
124
|
-
this.triggerTooltip = this.createTriggerTooltip(
|
125
|
-
this.targetTooltip,
|
126
|
-
this.renderingTooltip
|
127
|
-
)
|
128
|
-
|
129
|
-
document
|
130
|
-
.querySelectorAll('.leader-line')
|
131
|
-
.forEach(el => (el.style.zIndex = 100000))
|
132
|
-
|
133
|
-
const data = {
|
134
|
-
morph: {
|
135
|
-
partial: this.triggerElement.renders,
|
136
|
-
id: this.triggerElement.morphs,
|
137
|
-
status: this.morphElement ? 'OK' : 'Not Found'
|
138
|
-
},
|
139
|
-
trigger: { partial: null, id: null, status: 'Not Found' },
|
140
|
-
target: { partial: null, id: null, status: 'Not Found' }
|
141
|
-
}
|
142
|
-
|
143
|
-
if (this.triggerElement) {
|
144
|
-
data.trigger = {
|
145
|
-
partial: this.triggerElement.partial,
|
146
|
-
id: this.triggerElement.id,
|
147
|
-
status: 'OK'
|
148
|
-
}
|
149
|
-
data.target.id = this.triggerElement.controls
|
150
|
-
}
|
151
|
-
|
152
|
-
if (this.targetElement)
|
153
|
-
data.target = {
|
154
|
-
partial: this.targetElement.partial,
|
155
|
-
dom_id: this.targetElement.id,
|
156
|
-
status: 'OK'
|
157
|
-
}
|
158
|
-
|
159
|
-
console.table(data)
|
160
|
-
}
|
161
|
-
|
162
|
-
hide ({ active: active = false }) {
|
163
|
-
document
|
164
|
-
.querySelectorAll('turbo-boost-devtool-tooltip')
|
165
|
-
.forEach(tooltip => {
|
166
|
-
attempt(() => tooltip.line.remove())
|
167
|
-
attempt(() => tooltip.drag.remove())
|
168
|
-
attempt(() => tooltip.lineToRendering.remove())
|
169
|
-
attempt(() => tooltip.lineToTarget.remove())
|
170
|
-
attempt(() => tooltip.remove())
|
171
|
-
})
|
172
|
-
|
173
|
-
document.querySelectorAll('[data-turbo-boost-highlight]').forEach(el => {
|
174
|
-
if (!el.tagName.match(/turbo-boost-toggle-trigger/i)) removeHighlight(el)
|
175
|
-
})
|
176
|
-
|
177
|
-
this.active = active
|
178
|
-
}
|
179
|
-
|
180
|
-
createRenderingTooltip () {
|
181
|
-
if (!this.triggerElement.renders)
|
182
|
-
return console.debug(
|
183
|
-
`Unable to create the rendering tooltip! The trigger element must set the 'renders' attribute.`
|
184
|
-
)
|
185
|
-
|
186
|
-
if (!this.triggerElement.morphs)
|
187
|
-
return console.debug(
|
188
|
-
`Unable to create the rendering tooltip! The trigger element specified the 'morphs' attrbiute but no element matches the DOM id: '${this.triggerElement.morphs}'`
|
189
|
-
)
|
190
|
-
|
191
|
-
const title = `
|
192
|
-
<svg xmlns="http://www.w3.org/2000/svg" style="display:inline-block;" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19l7-7 3 3-7 7-3-3z"></path><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"></path><path d="M2 2l7.586 7.586"></path><circle cx="11" cy="11" r="2"></circle></svg>
|
193
|
-
RENDERING
|
194
|
-
`
|
195
|
-
const subtitle = `
|
196
|
-
<b>partial</b>: ${this.triggerElement.renders || 'unknown'}<br>
|
197
|
-
<b>morphs</b>: ${this.triggerElement.morphs || 'unknown'}<br>
|
198
|
-
`
|
199
|
-
const content = `
|
200
|
-
<div slot="content-top" style="font-size:85%; font-style:italic; font-weight:100;">
|
201
|
-
The <b>TRIGGER</b> toggles the <b>TARGET</b> then renders the partial & morphs the element.<br>
|
202
|
-
</div>
|
203
|
-
`
|
204
|
-
const tooltip = appendTooltip(title, subtitle, content, {
|
205
|
-
backgroundColor: 'lightyellow',
|
206
|
-
color: 'chocolate'
|
207
|
-
})
|
208
|
-
|
209
|
-
const coords = coordinates(this.morphElement)
|
210
|
-
const top = Math.ceil(
|
211
|
-
coords.top + coords.height / 2 - tooltip.offsetHeight / 2
|
212
|
-
)
|
213
|
-
const left = Math.ceil(coords.left + coords.width + 100)
|
214
|
-
tooltip.style.top = `${top}px`
|
215
|
-
tooltip.style.left = `${left}px`
|
216
|
-
|
217
|
-
tooltip.line = new LeaderLine(tooltip, this.morphElement, {
|
218
|
-
...this.leaderLineOptions,
|
219
|
-
color: 'chocolate'
|
220
|
-
})
|
221
|
-
|
222
|
-
tooltip.drag = new PlainDraggable(tooltip)
|
223
|
-
return tooltip
|
224
|
-
}
|
225
|
-
|
226
|
-
createTargetTooltip () {
|
227
|
-
if (!this.targetElement)
|
228
|
-
return console.debug(
|
229
|
-
`Unable to create the target tooltip! No element matches the DOM id: '${this.triggerElement.controls}'`
|
230
|
-
)
|
231
|
-
|
232
|
-
const title = `
|
233
|
-
<svg xmlns="http://www.w3.org/2000/svg" style="display:inline-block;" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><circle cx="12" cy="12" r="6"></circle><circle cx="12" cy="12" r="2"></circle></svg>
|
234
|
-
TARGET
|
235
|
-
`
|
236
|
-
const subtitle = `
|
237
|
-
<b>id</b>: ${this.targetElement.id}<br>
|
238
|
-
<b>aria-labeled-by</b>: ${this.targetElement.labeledBy}<br>
|
239
|
-
`
|
240
|
-
let content = this.targetElement.viewStack
|
241
|
-
.reverse()
|
242
|
-
.map((view, index) => {
|
243
|
-
return this.triggerElement.sharedViews.includes(view)
|
244
|
-
? `<div slot="content">${index + 1}. ${view}</div>`
|
245
|
-
: `<div slot="content-bottom">${index + 1}. ${view}</div>`
|
246
|
-
}, this)
|
247
|
-
.join('')
|
248
|
-
|
249
|
-
content = `
|
250
|
-
<div slot="content-top">
|
251
|
-
<svg xmlns="http://www.w3.org/2000/svg" style="display:inline-block;" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 2 7 12 12 22 7 12 2"></polygon><polyline points="2 17 12 22 22 17"></polyline><polyline points="2 12 12 17 22 12"></polyline></svg>
|
252
|
-
<b>View Stack</b>
|
253
|
-
</div>
|
254
|
-
${content}
|
255
|
-
`
|
256
|
-
|
257
|
-
const tooltip = appendTooltip(title, subtitle, content, {
|
258
|
-
backgroundColor: 'lightcyan',
|
259
|
-
color: 'darkcyan',
|
260
|
-
position: 'bottom'
|
261
|
-
})
|
262
|
-
|
263
|
-
const coords = coordinates(this.targetElement)
|
264
|
-
const top = Math.ceil(coords.top + tooltip.offsetHeight)
|
265
|
-
const left = Math.ceil(coords.left + coords.width + tooltip.offsetWidth / 3)
|
266
|
-
tooltip.style.top = `${top}px`
|
267
|
-
tooltip.style.left = `${left}px`
|
268
|
-
|
269
|
-
tooltip.line = new LeaderLine(tooltip, this.targetElement, {
|
270
|
-
...this.leaderLineOptions,
|
271
|
-
color: 'darkcyan'
|
272
|
-
})
|
273
|
-
|
274
|
-
tooltip.drag = new PlainDraggable(tooltip)
|
275
|
-
return tooltip
|
276
|
-
}
|
277
|
-
|
278
|
-
createTriggerTooltip (targetTooltip, renderingTooltip) {
|
279
|
-
if (!this.triggerElement) return
|
280
|
-
const title = `
|
281
|
-
<svg xmlns="http://www.w3.org/2000/svg" style="display:inline;" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>
|
282
|
-
TRIGGER
|
283
|
-
`
|
284
|
-
const subtitle = `
|
285
|
-
<b>id</b>: ${this.triggerElement.id}<br>
|
286
|
-
<b>aria-controls</b>: ${this.triggerElement.controls}<br>
|
287
|
-
<b>aria-expanded</b>: ${this.triggerElement.expanded}<br>
|
288
|
-
<b>remember</b>: ${this.triggerElement.remember}<br>
|
289
|
-
`
|
290
|
-
let content = this.triggerElement.viewStack
|
291
|
-
.reverse()
|
292
|
-
.map((view, index) => {
|
293
|
-
return this.triggerElement.sharedViews.includes(view)
|
294
|
-
? `<div slot="content">${index + 1}. ${view}</div>`
|
295
|
-
: `<div slot="content-bottom">${index + 1}. ${view}</div>`
|
296
|
-
}, this)
|
297
|
-
.join('')
|
298
|
-
|
299
|
-
content = `
|
300
|
-
<div slot="content-top">
|
301
|
-
<svg xmlns="http://www.w3.org/2000/svg" style="display:inline-block;" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 2 7 12 12 22 7 12 2"></polygon><polyline points="2 17 12 22 22 17"></polyline><polyline points="2 12 12 17 22 12"></polyline></svg>
|
302
|
-
<b>View Stack</b>
|
303
|
-
</div>
|
304
|
-
${content}
|
305
|
-
`
|
306
|
-
|
307
|
-
const tooltip = appendTooltip(title, subtitle, content, {
|
308
|
-
backgroundColor: 'lavender',
|
309
|
-
color: 'blueviolet'
|
310
|
-
})
|
311
|
-
|
312
|
-
const coords = coordinates(this.triggerElement)
|
313
|
-
const top = Math.ceil(coords.top - tooltip.offsetHeight * 2)
|
314
|
-
const left = Math.ceil(coords.left + coords.width + tooltip.offsetWidth / 3)
|
315
|
-
tooltip.style.top = `${top}px`
|
316
|
-
tooltip.style.left = `${left}px`
|
317
|
-
|
318
|
-
tooltip.line = new LeaderLine(this.triggerElement, tooltip, {
|
319
|
-
...this.leaderLineOptions,
|
320
|
-
color: 'blueviolet'
|
321
|
-
})
|
322
|
-
|
323
|
-
if (targetTooltip) {
|
324
|
-
tooltip.lineToTarget = new LeaderLine(tooltip, targetTooltip, {
|
325
|
-
...this.leaderLineOptions,
|
326
|
-
color: 'blueviolet',
|
327
|
-
middleLabel: 'toggles',
|
328
|
-
size: 2.1
|
329
|
-
})
|
330
|
-
|
331
|
-
targetTooltip.drag.onMove = () => {
|
332
|
-
targetTooltip.line.position()
|
333
|
-
tooltip.lineToTarget.position()
|
334
|
-
tooltip.lineToRendering.position()
|
335
|
-
}
|
336
|
-
}
|
337
|
-
|
338
|
-
if (renderingTooltip) {
|
339
|
-
tooltip.lineToRendering = new LeaderLine(tooltip, renderingTooltip, {
|
340
|
-
...this.leaderLineOptions,
|
341
|
-
color: 'blueviolet',
|
342
|
-
middleLabel: 'renders & morphs',
|
343
|
-
size: 2.1
|
344
|
-
})
|
345
|
-
|
346
|
-
renderingTooltip.drag.onMove = () => {
|
347
|
-
renderingTooltip.line.position()
|
348
|
-
if (tooltip.lineToTarget) tooltip.lineToTarget.position()
|
349
|
-
tooltip.lineToRendering.position()
|
350
|
-
}
|
351
|
-
}
|
352
|
-
|
353
|
-
tooltip.drag = new PlainDraggable(tooltip)
|
354
|
-
tooltip.drag.onMove = () => {
|
355
|
-
tooltip.line.position()
|
356
|
-
if (tooltip.lineToTarget) tooltip.lineToTarget.position()
|
357
|
-
if (tooltip.lineToRendering) tooltip.lineToRendering.position()
|
358
|
-
}
|
359
|
-
|
360
|
-
return tooltip
|
361
|
-
}
|
362
|
-
|
363
|
-
get leaderLineOptions () {
|
364
|
-
return {
|
365
|
-
dash: { animation: true },
|
366
|
-
dropShadow: { opacity: 0.3 },
|
367
|
-
endPlug: 'arrow3',
|
368
|
-
endPlugSize: 1.7,
|
369
|
-
size: 3,
|
370
|
-
startPlug: 'disc',
|
371
|
-
startPlugSize: 1
|
372
|
-
}
|
373
|
-
}
|
374
|
-
}
|
data/app/javascript/utils/dom.js
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
export function template (html) {
|
2
|
-
let template = document.createElement('template')
|
3
|
-
template.innerHTML = html
|
4
|
-
return template
|
5
|
-
}
|
6
|
-
|
7
|
-
export function appendHTML (html, parent) {
|
8
|
-
parent = parent || document.body
|
9
|
-
const clone = template(html).content.cloneNode(true)
|
10
|
-
const child = clone.querySelector('*')
|
11
|
-
return parent.appendChild(child)
|
12
|
-
}
|
13
|
-
|
14
|
-
export function addHighlight (element, options = {}) {
|
15
|
-
if (!element) return
|
16
|
-
removeHighlight(element)
|
17
|
-
let { outline, outlineOffset } = options
|
18
|
-
|
19
|
-
outline = outline || 'dashed 3px red'
|
20
|
-
outlineOffset = outlineOffset || '0px'
|
21
|
-
|
22
|
-
element.originalStyles = element.originalStyles || {
|
23
|
-
display: element.style.display,
|
24
|
-
minHeight: element.style.minHeight,
|
25
|
-
minWidth: element.style.minWidth,
|
26
|
-
outline: element.style.outline,
|
27
|
-
outlineOffset: element.style.outlineOffset
|
28
|
-
}
|
29
|
-
|
30
|
-
if (
|
31
|
-
getComputedStyle(element).display.match(/^inline$/i) &&
|
32
|
-
element.offsetWidth === 0 &&
|
33
|
-
element.offsetHeight === 0
|
34
|
-
) {
|
35
|
-
element.style.display = 'inline-block'
|
36
|
-
element.style.minHeight = '2px'
|
37
|
-
element.style.minWidth = '2px'
|
38
|
-
}
|
39
|
-
element.style.outline = outline
|
40
|
-
element.style.outlineOffset = outlineOffset
|
41
|
-
element.dataset.turboBoostHighlight = true
|
42
|
-
}
|
43
|
-
|
44
|
-
export function removeHighlight (element) {
|
45
|
-
if (!element) return
|
46
|
-
if (element.originalStyles) {
|
47
|
-
for (const [key, value] of Object.entries(element.originalStyles))
|
48
|
-
value ? (element.style[key] = value) : (element.style[key] = '')
|
49
|
-
delete element.originalStyles
|
50
|
-
}
|
51
|
-
delete element.dataset.turboBoostHighlight
|
52
|
-
}
|
53
|
-
|
54
|
-
export function coordinates (element) {
|
55
|
-
if (!element) return {}
|
56
|
-
const rect = element.getBoundingClientRect()
|
57
|
-
const width = element.offsetWidth
|
58
|
-
const height = element.offsetHeight
|
59
|
-
const top = rect.top + window.scrollY
|
60
|
-
const left = rect.left + window.scrollX
|
61
|
-
const right = left + width
|
62
|
-
const bottom = top + height
|
63
|
-
return { top, left, right, bottom, width, height }
|
64
|
-
}
|
65
|
-
|
66
|
-
export function attempt (callback) {
|
67
|
-
try {
|
68
|
-
callback()
|
69
|
-
} catch {}
|
70
|
-
}
|