turbo_boost-elements 0.0.11 → 0.0.13

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,4 @@
1
1
  import ToggleElement from '../toggle_element'
2
- import './focus'
3
2
 
4
3
  export default class ToggleTargetElement extends ToggleElement {
5
4
  connectedCallback () {
@@ -91,19 +90,8 @@ export default class ToggleTargetElement extends ToggleElement {
91
90
  )
92
91
  }
93
92
 
94
- applyFocus () {
95
- if (this.focusElement) this.focusElement.focus()
96
- }
97
-
98
93
  get focusSelector () {
99
- let value = this.getAttribute('focus-selector')
100
- if (this.triggerElement)
101
- value = this.triggerElement.getAttribute('focus-selector') || value
102
- return value
103
- }
104
-
105
- get focusElement () {
106
- return this.querySelector(this.focusSelector)
94
+ return this.getAttribute('focus-selector')
107
95
  }
108
96
 
109
97
  get triggerElement () {
@@ -114,6 +102,10 @@ export default class ToggleTargetElement extends ToggleElement {
114
102
  return this.getAttribute('aria-labeledby')
115
103
  }
116
104
 
105
+ set labeledBy (value) {
106
+ return this.setAttribute('aria-labeledby', value)
107
+ }
108
+
117
109
  get collapseOn () {
118
110
  const value = this.getAttribute('collapse-on')
119
111
  if (!value) return []
@@ -1,3 +1,5 @@
1
+ let focusTimeout
2
+
1
3
  function deactivateTrixAttributes (editor) {
2
4
  const attributes = [
3
5
  'bold',
@@ -43,35 +45,26 @@ function focusTrixEditorElement (element) {
43
45
  ])
44
46
  }
45
47
 
46
- function shouldEnhanceFocus (element) {
47
- if (!element.tagName.match(/^input|textarea|trix-editor$/i)) return false
48
- const toggleTargetElement = element.closest('turbo-boost-toggle-target')
49
- return toggleTargetElement && toggleTargetElement.focusSelector
50
- }
48
+ function debouncedFocus (element) {
49
+ clearTimeout(focusTimeout)
51
50
 
52
- function enhanceFocus (element) {
53
- const trixEditorElement = element.closest('trix-editor')
51
+ focusTimeout = setTimeout(() => {
52
+ if (!element) return
54
53
 
55
- try {
56
- if (trixEditorElement) {
57
- focusTrixEditorElement(trixEditorElement)
58
- } else {
59
- element.selectionStart = element.selectionEnd = element.value.length
54
+ element.focus()
55
+ const trixEditorElement = element.closest('trix-editor')
56
+
57
+ try {
58
+ if (trixEditorElement) {
59
+ focusTrixEditorElement(trixEditorElement)
60
+ } else {
61
+ element.selectionStart = element.selectionEnd = element.value.length
62
+ }
63
+ } catch (_) {
64
+ } finally {
65
+ element.scrollIntoView({ block: 'center', behavior: 'smooth' })
60
66
  }
61
- } catch (_) {
62
- } finally {
63
- setTimeout(
64
- () => element.scrollIntoView({ block: 'center', behavior: 'smooth' }),
65
- 100
66
- )
67
- }
67
+ }, 100)
68
68
  }
69
69
 
70
- addEventListener(
71
- 'focus',
72
- event => {
73
- if (shouldEnhanceFocus(document.activeElement))
74
- enhanceFocus(document.activeElement)
75
- },
76
- true
77
- )
70
+ export default element => debouncedFocus(element)
@@ -1,13 +1,13 @@
1
1
  import ToggleElement, { busyDuration } from '../toggle_element'
2
2
  import Devtool from './devtool'
3
+ import focus from './focus'
4
+
5
+ let currentFocusSelector
3
6
 
4
7
  export default class ToggleTriggerElement extends ToggleElement {
5
8
  connectedCallback () {
6
9
  super.connectedCallback()
7
10
 
8
- if (this.targetElement)
9
- this.targetElement.setAttribute('aria-labeledby', this.id)
10
-
11
11
  const { start: commandStartEvent } = TurboBoost.Commands.events
12
12
  this.commandStartHandler = this.onCommandStart.bind(this)
13
13
  this.addEventListener(commandStartEvent, this.commandStartHandler)
@@ -25,15 +25,19 @@ export default class ToggleTriggerElement extends ToggleElement {
25
25
  }
26
26
 
27
27
  disconnectedCallback () {
28
- const { start: commandStartEvent } = TurboBoost.Commands.events
29
- this.removeEventListener(commandStartEvent, this.commandStartHandler)
28
+ // delay cleanup because the trigger may have been morphed out of the DOM,
29
+ // but it's needed to apply behavior like focus etc...
30
+ setTimeout(() => {
31
+ const { start: commandStartEvent } = TurboBoost.Commands.events
32
+ this.removeEventListener(commandStartEvent, this.commandStartHandler)
30
33
 
31
- const { before: beforeInvokeEvent } = TurboBoost.Streams.invokeEvents
32
- removeEventListener(beforeInvokeEvent, this.beforeInvokeHandler)
34
+ const { before: beforeInvokeEvent } = TurboBoost.Streams.invokeEvents
35
+ removeEventListener(beforeInvokeEvent, this.beforeInvokeHandler)
33
36
 
34
- this.devtool.hide({ active: false })
35
- this.devtool.unregisterEventListeners()
36
- delete this.devtool
37
+ this.devtool.hide({ active: false })
38
+ this.devtool.unregisterEventListeners()
39
+ delete this.devtool
40
+ }, 1000)
37
41
  }
38
42
 
39
43
  initializeDevtool () {
@@ -61,16 +65,21 @@ export default class ToggleTriggerElement extends ToggleElement {
61
65
  }
62
66
 
63
67
  onCommandStart (event) {
64
- this.targetElement.setAttribute('aria-labeledby', this.id)
68
+ currentFocusSelector = this.focusSelector
69
+ this.targetElement.labeledBy = this.id
65
70
  this.targetElement.collapseMatches()
66
71
  this.targetElement.busy = true
67
72
  this.busy = true
68
73
  // TODO: implement cache - this.targetElement.renderCachedHTML()
69
74
  }
70
75
 
76
+ // runs before an invoke turbo stream is executed
71
77
  onBeforeInvoke (event) {
78
+ // return early if we're not the element responsible for this invoke
72
79
  if (event.detail.method !== 'morph') return
73
80
  if (event.target.id !== this.morphs) return
81
+ const selector = `turbo-boost-toggle-target[aria-labeledby="${this.id}"]`
82
+ if (!event.target.querySelector(selector)) return
74
83
 
75
84
  // ensure the busy element is shown long enough for a good user experience
76
85
  // we accomplish this by modifying the event.detail with invoke instructions i.e. { delay }
@@ -88,10 +97,10 @@ export default class ToggleTriggerElement extends ToggleElement {
88
97
  }, delay - 10)
89
98
 
90
99
  // runs after the morph is executed
91
- setTimeout(() => {
92
- this.targetElement.setAttribute('aria-labeledby', this.id)
93
- this.targetElement.applyFocus()
94
- }, delay + 100)
100
+ setTimeout(
101
+ () => focus(this.targetElement.querySelector(currentFocusSelector)),
102
+ delay + 100
103
+ )
95
104
  }
96
105
 
97
106
  // a list of views shared between the trigger and target
@@ -147,8 +156,7 @@ export default class ToggleTriggerElement extends ToggleElement {
147
156
 
148
157
  get focusSelector () {
149
158
  return (
150
- this.getAttribute('focus-selector') ||
151
- this.targetElement.getAttribute('focus-selector')
159
+ this.getAttribute('focus-selector') || this.targetElement.focusSelector
152
160
  )
153
161
  }
154
162
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module TurboBoost
4
4
  module Elements
5
- VERSION = "0.0.11"
5
+ VERSION = "0.0.13"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turbo_boost-elements
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.11
4
+ version: 0.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nate Hopkins (hopsoft)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-07 00:00:00.000000000 Z
11
+ date: 2023-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -144,10 +144,10 @@ files:
144
144
  - app/javascript/devtools/index.js
145
145
  - app/javascript/devtools/supervisor.js
146
146
  - app/javascript/elements/index.js
147
- - app/javascript/elements/toggle_elements/target_element/focus.js
148
147
  - app/javascript/elements/toggle_elements/target_element/index.js
149
148
  - app/javascript/elements/toggle_elements/toggle_element/index.js
150
149
  - app/javascript/elements/toggle_elements/trigger_element/devtool.js
150
+ - app/javascript/elements/toggle_elements/trigger_element/focus.js
151
151
  - app/javascript/elements/toggle_elements/trigger_element/index.js
152
152
  - app/javascript/elements/turbo_boost_element/index.js
153
153
  - app/javascript/index.js