turbo_boost-elements 0.0.8 → 0.0.10

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.
@@ -22,7 +22,6 @@ class TurboBoost::Elements::ToggleCommand < TurboBoost::Elements::ApplicationCom
22
22
  end
23
23
 
24
24
  def toggle
25
- validate_element!
26
25
  element.aria.expanded? ? hide : show
27
26
  end
28
27
 
@@ -84,29 +84,37 @@ export default class TooltipElement extends HTMLElement {
84
84
  display: block;
85
85
  font-size: 0.8rem;
86
86
  font-weight: lighter;
87
- margin-bottom: 8px;
88
- margin-top: 4px;
87
+ margin-bottom: 12px;
88
+ margin-top: 8px;
89
89
  padding-bottom: 4px;
90
90
  padding-top: 4px;
91
91
  width: 100%;
92
92
  }
93
93
 
94
+ slot[name="content-top"],
95
+ slot[name="content"],
96
+ slot[name="content-bottom"] {
97
+ display: block;
98
+ font-weight: normal;
99
+ }
100
+
94
101
  slot[name="content-top"] {
95
102
  color: ${this.color};
96
- font-weight: normal;
103
+ margin-bottom: 8px;
104
+ }
105
+
106
+ slot[name="content"],
107
+ slot[name="content-bottom"] {
97
108
  opacity: 0.7;
109
+ padding-left: 12px;
98
110
  }
99
111
 
100
112
  slot[name="content"] {
101
113
  color: ${this.color};
102
- font-weight: normal;
103
- opacity: 0.7;
104
114
  }
105
115
 
106
116
  slot[name="content-bottom"] {
107
117
  color: red;
108
- font-weight: normal;
109
- opacity: 0.7;
110
118
  }
111
119
  `
112
120
  }
@@ -81,6 +81,7 @@ addEventListener('turbo:load', autoRestart)
81
81
  addEventListener('turbo-frame:load', autoRestart)
82
82
  addEventListener(TurboBoost.Commands.events.success, autoRestart)
83
83
  addEventListener(TurboBoost.Commands.events.finish, autoRestart)
84
+ addEventListener('turbo-boost:devtools-connect', autoRestart)
84
85
  addEventListener('turbo-boost:devtools-close', stop)
85
86
 
86
87
  function register (name, label) {
@@ -1,5 +1,9 @@
1
- import ToggleTargetElement from './toggle_target_element'
2
- import ToggleTriggerElement from './toggle_trigger_element'
1
+ import TurboBoostElement from './turbo_boost_element'
2
+ import ToggleTargetElement from './toggle_elements/target_element'
3
+ import ToggleTriggerElement from './toggle_elements/trigger_element'
3
4
 
5
+ // Valid custom element names: https://html.spec.whatwg.org/#valid-custom-element-name
6
+
7
+ customElements.define('turbo-boost', TurboBoostElement)
4
8
  customElements.define('turbo-boost-toggle-target', ToggleTargetElement)
5
9
  customElements.define('turbo-boost-toggle-trigger', ToggleTriggerElement)
@@ -0,0 +1,138 @@
1
+ import ToggleElement from '../toggle_element'
2
+ import './focus'
3
+
4
+ export default class ToggleTargetElement extends ToggleElement {
5
+ connectedCallback () {
6
+ super.connectedCallback()
7
+
8
+ this.mouseenterHandler = this.onMouseenter.bind(this)
9
+ this.addEventListener('mouseenter', this.mouseenterHandler)
10
+
11
+ this.collapseHandler = this.collapse.bind(this)
12
+ this.collapseNowHandler = this.collapseNow.bind(this)
13
+
14
+ this.collapseOn.forEach(entry => {
15
+ const parts = entry.split('@')
16
+ const name = parts[0]
17
+
18
+ if (parts.length > 1) {
19
+ const target = parts[1].match(/^self|window$/) ? self : self[parts[1]]
20
+ target.addEventListener(name, this.collapseNowHandler)
21
+ } else {
22
+ this.addEventListener(name, this.collapseHandler)
23
+ }
24
+ })
25
+ }
26
+
27
+ disconnectedCallback () {
28
+ this.removeEventListener('mouseenter', this.mouseenterHandler)
29
+
30
+ this.collapseOn.forEach(entry => {
31
+ const parts = entry.split('@')
32
+ const name = parts[0]
33
+
34
+ if (parts.length > 1) {
35
+ const target = parts[1].match(/^self|window$/) ? self : self[parts[1]]
36
+ target.removeEventListener(name, this.collapseNowHandler)
37
+ } else {
38
+ this.removeEventListener(name, this.collapseHandler)
39
+ }
40
+ })
41
+ }
42
+
43
+ // TODO: get cached content working properly
44
+ // perhaps use a mechanic other than morph
45
+
46
+ // TODO: implement cache (similar to Turbo Drive restoration visit)
47
+ cacheHTML () {
48
+ // this.cachedHTML = this.innerHTML
49
+ }
50
+
51
+ // TODO: implement cache (similar to Turbo Drive restoration visit)
52
+ renderCachedHTML () {
53
+ // if (!this.cachedHTML) return
54
+ // this.innerHTML = this.cachedHTML
55
+ }
56
+
57
+ onMouseenter () {
58
+ clearTimeout(this.collapseTimeout)
59
+ }
60
+
61
+ collapse (delay = 250) {
62
+ clearTimeout(this.collapseTimeout)
63
+ if (typeof delay !== 'number') delay = 250
64
+
65
+ if (delay > 0)
66
+ return (this.collapseTimeout = setTimeout(() => this.collapse(0), delay))
67
+
68
+ this.innerHTML = ''
69
+ try {
70
+ this.expanded = false
71
+ this.triggerElement.hideDevtool()
72
+ } catch {}
73
+ }
74
+
75
+ collapseNow (event) {
76
+ if (event.target.closest('turbo-boost-devtool-tooltip')) return
77
+ this.collapse(0)
78
+ }
79
+
80
+ collapseMatches () {
81
+ document.querySelectorAll(this.collapseSelector).forEach(el => {
82
+ if (el === this) return
83
+ if (el.collapse) el.collapse(0)
84
+ })
85
+ }
86
+
87
+ get collapseSelector () {
88
+ return (
89
+ this.triggerElement.collapseSelector ||
90
+ this.getAttribute('collapse-selector')
91
+ )
92
+ }
93
+
94
+ focus () {
95
+ clearTimeout(this.focusTimeout)
96
+ this.focusTimeout = setTimeout(() => {
97
+ if (this.focusElement) this.focusElement.focus()
98
+ }, 50)
99
+ }
100
+
101
+ get focusSelector () {
102
+ let value = this.getAttribute('focus-selector')
103
+ if (this.triggerElement)
104
+ value = this.triggerElement.getAttribute('focus-selector') || value
105
+ return value
106
+ }
107
+
108
+ get focusElement () {
109
+ return this.querySelector(this.focusSelector)
110
+ }
111
+
112
+ get triggerElement () {
113
+ return (
114
+ document.getElementById(this.labeledBy) ||
115
+ document.querySelector(
116
+ `turbo-boost-toggle-trigger[aria-controls="${this.id}"]`
117
+ )
118
+ )
119
+ }
120
+
121
+ get labeledBy () {
122
+ return this.getAttribute('aria-labeledby')
123
+ }
124
+
125
+ get collapseOn () {
126
+ const value = this.getAttribute('collapse-on')
127
+ if (!value) return []
128
+ return JSON.parse(value)
129
+ }
130
+
131
+ get expanded () {
132
+ return this.triggerElement.expanded
133
+ }
134
+
135
+ set expanded (value) {
136
+ return (this.triggerElement.expanded = value)
137
+ }
138
+ }
@@ -0,0 +1,83 @@
1
+ import TurboBoostElement from '../../turbo_boost_element'
2
+
3
+ const html = `
4
+ <turbo-boost>
5
+ <slot name="busy" hidden></slot>
6
+ <slot></slot>
7
+ </turbo-boost>
8
+ `
9
+
10
+ export const busyDelay = 100 // milliseconds - time to wait before showing busy element
11
+ export const busyDuration = 400 // milliseconds - minimum time that busy element is shown
12
+
13
+ export default class ToggleElement extends TurboBoostElement {
14
+ constructor () {
15
+ super(html)
16
+ }
17
+
18
+ // TODO: Should we timeout after a theoretical max wait time?
19
+ // The idea being that a server error occurred and the toggle failed.
20
+ showBusyElement () {
21
+ clearTimeout(this.showBusyElementTimeout)
22
+ clearTimeout(this.hideBusyElementTimeout)
23
+
24
+ if (!this.busyElement) return
25
+
26
+ this.busyStartedAt = Date.now() + busyDelay
27
+ this.showBusyElementTimeout = setTimeout(() => {
28
+ this.busySlotElement.hidden = false
29
+ this.defaultSlotElement.hidden = true
30
+ }, busyDelay)
31
+ }
32
+
33
+ hideBusyElement () {
34
+ clearTimeout(this.showBusyElementTimeout)
35
+ clearTimeout(this.hideBusyElementTimeout)
36
+
37
+ if (!this.busyElement) return
38
+
39
+ let delay = busyDuration - (Date.now() - this.busyStartedAt)
40
+ if (delay < 0) delay = 0
41
+
42
+ delete this.busyStartedAt
43
+ this.hideBusyElementTimeout = setTimeout(() => {
44
+ this.busySlotElement.hidden = true
45
+ this.defaultSlotElement.hidden = false
46
+ }, delay)
47
+ }
48
+
49
+ get busyElement () {
50
+ return this.querySelector(':scope > [slot="busy"]')
51
+ }
52
+
53
+ get busySlotElement () {
54
+ return this.shadowRoot.querySelector('slot[name="busy"]')
55
+ }
56
+
57
+ get defaultSlotElement () {
58
+ return this.shadowRoot.querySelector('slot:not([name])')
59
+ }
60
+
61
+ // indicates if an rpc call is active/busy
62
+ get busy () {
63
+ return this.getAttribute('busy') === 'true'
64
+ }
65
+
66
+ // indicates if an rpc call is active/busy
67
+ set busy (value) {
68
+ value = !!value
69
+ if (this.busy === value) return
70
+ this.setAttribute('busy', value)
71
+ if (value) this.showBusyElement()
72
+ else this.hideBusyElement()
73
+ }
74
+
75
+ get busyStartedAt () {
76
+ if (!this.dataset.busyStartedAt) return 0
77
+ return Number(this.dataset.busyStartedAt)
78
+ }
79
+
80
+ set busyStartedAt (value) {
81
+ this.dataset.busyStartedAt = value
82
+ }
83
+ }
@@ -1,15 +1,17 @@
1
+ // Icons courtesy of https://feathericons.com/
1
2
  import {
2
3
  appendHTML,
3
4
  addHighlight,
5
+ attempt,
4
6
  coordinates,
5
7
  removeHighlight
6
- } from '../utils/dom'
7
- import supervisor from './supervisor'
8
+ } from '../../../utils/dom'
9
+ import supervisor from '../../../devtools/supervisor'
8
10
 
9
11
  let activeToggle
10
12
 
11
13
  document.addEventListener('turbo-boost:devtools-start', () =>
12
- supervisor.register('toggle', 'toggles<small>(trigger/target)</small>')
14
+ supervisor.register('toggle', 'toggles')
13
15
  )
14
16
 
15
17
  function appendTooltip (title, subtitle, content, options = {}) {
@@ -25,7 +27,7 @@ function appendTooltip (title, subtitle, content, options = {}) {
25
27
  `)
26
28
  }
27
29
 
28
- export default class ToggleDevtool {
30
+ export default class Devtool {
29
31
  constructor (triggerElement) {
30
32
  this.name = 'toggle'
31
33
  this.command = triggerElement.dataset.turboCommand
@@ -33,47 +35,79 @@ export default class ToggleDevtool {
33
35
  this.targetElement = triggerElement.targetElement // SEE: app/javascript/elements/toggle_target_element.js
34
36
  this.morphElement = triggerElement.morphElement
35
37
 
36
- document.addEventListener('turbo-boost:devtool-enable', event => {
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
37
46
  const { name } = event.detail
38
- if (name === this.name) {
39
- addHighlight(this.triggerElement, {
40
- outline: '3px dashed blueviolet',
41
- outlineOffset: '2px'
42
- })
43
- }
44
- })
47
+ if (name !== this.name) return
48
+
49
+ addHighlight(this.triggerElement, {
50
+ outline: '3px dashed blueviolet',
51
+ outlineOffset: '2px'
52
+ })
45
53
 
46
- document.addEventListener('turbo-boost:devtool-disable', event => {
54
+ this.hide({ active: false })
55
+ if (this.active) this.show()
56
+ }
57
+
58
+ this.eventListeners['turbo-boost:devtool-disable'] = event => {
47
59
  const { name } = event.detail
48
60
  if (name === this.name) removeHighlight(this.triggerElement)
49
- })
50
-
51
- let hideTimeout
52
- const debouncedHide = () => {
53
- clearTimeout(hideTimeout)
54
- hideTimeout = setTimeout(this.hide(true), 25)
55
61
  }
56
62
 
57
- addEventListener('click', event => {
63
+ this.eventListeners['click'] = event => {
58
64
  if (event.target.closest('turbo-boost-devtool-tooltip')) return
59
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)
60
84
  })
85
+ }
61
86
 
62
- addEventListener('turbo:load', debouncedHide)
63
- addEventListener('turbo-frame:load', debouncedHide)
64
- addEventListener(TurboBoost.Commands.events.success, debouncedHide)
65
- addEventListener(TurboBoost.Commands.events.finish, debouncedHide)
87
+ get eventListeners () {
88
+ return this._eventListeners || (this._eventListeners = {})
66
89
  }
67
90
 
68
91
  get enabled () {
69
92
  return supervisor.enabled(this.name)
70
93
  }
71
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
+
72
104
  show () {
73
105
  if (!this.enabled) return
74
- if (activeToggle === this) return
75
- activeToggle = this
76
- this.hide()
106
+
107
+ if (this.active) return
108
+ this.active = true
109
+
110
+ this.hide({ active: true })
77
111
 
78
112
  addHighlight(this.targetElement, {
79
113
  outline: '3px dashed darkcyan',
@@ -85,9 +119,12 @@ export default class ToggleDevtool {
85
119
  outlineOffset: '3px'
86
120
  })
87
121
 
88
- const morphTooltip = this.createMorphTooltip()
89
- const targetTooltip = this.createTargetTooltip()
90
- this.createTriggerTooltip(targetTooltip, morphTooltip)
122
+ this.renderingTooltip = this.createRenderingTooltip()
123
+ this.targetTooltip = this.createTargetTooltip()
124
+ this.triggerTooltip = this.createTriggerTooltip(
125
+ this.targetTooltip,
126
+ this.renderingTooltip
127
+ )
91
128
 
92
129
  document
93
130
  .querySelectorAll('.leader-line')
@@ -115,38 +152,55 @@ export default class ToggleDevtool {
115
152
  if (this.targetElement)
116
153
  data.target = {
117
154
  partial: this.targetElement.partial,
118
- id: this.targetElement.id,
155
+ dom_id: this.targetElement.id,
119
156
  status: 'OK'
120
157
  }
121
158
 
122
159
  console.table(data)
123
160
  }
124
161
 
125
- hide (clearActiveToggle) {
126
- document.querySelectorAll('.leader-line').forEach(el => el.remove())
162
+ hide ({ active: active = false }) {
127
163
  document
128
164
  .querySelectorAll('turbo-boost-devtool-tooltip')
129
- .forEach(el => el.remove())
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
+ })
130
172
 
131
173
  document.querySelectorAll('[data-turbo-boost-highlight]').forEach(el => {
132
174
  if (!el.tagName.match(/turbo-boost-toggle-trigger/i)) removeHighlight(el)
133
175
  })
134
176
 
135
- if (clearActiveToggle) activeToggle = null
177
+ this.active = active
136
178
  }
137
179
 
138
- createMorphTooltip () {
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
+
139
186
  if (!this.triggerElement.morphs)
140
187
  return console.debug(
141
- `Unable to create the morph tooltip! No element matches the DOM id: '${this.triggerElement.morphs}'`
188
+ `Unable to create the rendering tooltip! The trigger element specified the 'morphs' attrbiute but no element matches the DOM id: '${this.triggerElement.morphs}'`
142
189
  )
143
190
 
144
- const title = 'PARTIAL'
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
+ `
145
195
  const subtitle = `
146
- id: ${this.triggerElement.morphs || 'unknown'}<br>
147
- partial: ${this.triggerElement.renders || 'unknown'}
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 &amp; morphs the element.<br>
202
+ </div>
148
203
  `
149
- const content = '<div slot="content"></div>'
150
204
  const tooltip = appendTooltip(title, subtitle, content, {
151
205
  backgroundColor: 'lightyellow',
152
206
  color: 'chocolate'
@@ -175,20 +229,31 @@ export default class ToggleDevtool {
175
229
  `Unable to create the target tooltip! No element matches the DOM id: '${this.triggerElement.controls}'`
176
230
  )
177
231
 
178
- const title = 'TARGET'
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
+ `
179
236
  const subtitle = `
180
- id: ${this.targetElement.id}<br>
181
- labeled by: ${this.targetElement.labeledBy}
237
+ <b>id</b>: ${this.targetElement.id}<br>
238
+ <b>aria-labeled-by</b>: ${this.targetElement.labeledBy}<br>
182
239
  `
183
- const content = this.targetElement.viewStack
240
+ let content = this.targetElement.viewStack
184
241
  .reverse()
185
242
  .map((view, index) => {
186
243
  return this.triggerElement.sharedViews.includes(view)
187
- ? `<div slot="content-top">${index + 1}. ${view}</div>`
244
+ ? `<div slot="content">${index + 1}. ${view}</div>`
188
245
  : `<div slot="content-bottom">${index + 1}. ${view}</div>`
189
246
  }, this)
190
247
  .join('')
191
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
+
192
257
  const tooltip = appendTooltip(title, subtitle, content, {
193
258
  backgroundColor: 'lightcyan',
194
259
  color: 'darkcyan',
@@ -210,22 +275,35 @@ export default class ToggleDevtool {
210
275
  return tooltip
211
276
  }
212
277
 
213
- createTriggerTooltip (targetTooltip, morphTooltip) {
278
+ createTriggerTooltip (targetTooltip, renderingTooltip) {
214
279
  if (!this.triggerElement) return
215
- const title = 'TRIGGER'
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
+ `
216
284
  const subtitle = `
217
- id: ${this.triggerElement.id}<br>
218
- controls: ${this.triggerElement.controls}
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>
219
289
  `
220
- const content = this.triggerElement.viewStack
290
+ let content = this.triggerElement.viewStack
221
291
  .reverse()
222
292
  .map((view, index) => {
223
293
  return this.triggerElement.sharedViews.includes(view)
224
- ? `<div slot="content-top">${index + 1}. ${view}</div>`
294
+ ? `<div slot="content">${index + 1}. ${view}</div>`
225
295
  : `<div slot="content-bottom">${index + 1}. ${view}</div>`
226
296
  }, this)
227
297
  .join('')
228
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
+
229
307
  const tooltip = appendTooltip(title, subtitle, content, {
230
308
  backgroundColor: 'lavender',
231
309
  color: 'blueviolet'
@@ -257,16 +335,16 @@ export default class ToggleDevtool {
257
335
  }
258
336
  }
259
337
 
260
- if (morphTooltip) {
261
- tooltip.lineToRendering = new LeaderLine(tooltip, morphTooltip, {
338
+ if (renderingTooltip) {
339
+ tooltip.lineToRendering = new LeaderLine(tooltip, renderingTooltip, {
262
340
  ...this.leaderLineOptions,
263
341
  color: 'blueviolet',
264
- middleLabel: 'renders and morphs',
342
+ middleLabel: 'renders & morphs',
265
343
  size: 2.1
266
344
  })
267
345
 
268
- morphTooltip.drag.onMove = () => {
269
- morphTooltip.line.position()
346
+ renderingTooltip.drag.onMove = () => {
347
+ renderingTooltip.line.position()
270
348
  if (tooltip.lineToTarget) tooltip.lineToTarget.position()
271
349
  tooltip.lineToRendering.position()
272
350
  }