reflex_behaviors 0.0.4 → 0.0.5

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,13 +22,15 @@ export function addHighlight (element, options = {}) {
22
22
  }
23
23
  element.style.outline = `dotted ${width} ${color}`
24
24
  element.style.outlineOffset = offset
25
+ element.dataset.reflexBehaviorsHighlight = true
25
26
  }
26
27
 
27
28
  export function removeHighlight (element) {
28
- if (element && element.originalStyles) {
29
- for (const [key, value] of Object.entries(element.originalStyles)) {
29
+ if (!element) return
30
+ if (element.originalStyles) {
31
+ for (const [key, value] of Object.entries(element.originalStyles))
30
32
  value ? (element.style[key] = value) : (element.style[key] = '')
31
- }
32
33
  delete element.originalStyles
33
34
  }
35
+ delete element.dataset.reflexBehaviorsHighlight
34
36
  }
@@ -54,8 +54,22 @@ export default class DevtoolElement extends HTMLElement {
54
54
 
55
55
  get stylesheet () {
56
56
  return `
57
+ :host, :host * {
58
+ cursor: pointer;
59
+ }
60
+
57
61
  div {
58
62
  display: flex;
63
+ position: relative;
64
+ top: -1px;
65
+ }
66
+
67
+ input:checked + label{
68
+ font-weight: bold;
69
+ }
70
+
71
+ label {
72
+ color: indigo;
59
73
  }
60
74
  `
61
75
  }
@@ -7,7 +7,7 @@ export default class SupervisorElement extends HTMLElement {
7
7
  this.attachShadow({ mode: 'open' })
8
8
  this.shadowRoot.innerHTML = this.html
9
9
  this.shadowRoot
10
- .querySelector('button[data-role="closer"]')
10
+ .querySelector('button')
11
11
  .addEventListener('click', () => this.close())
12
12
 
13
13
  this.addEventListener('change', event => {
@@ -51,16 +51,16 @@ export default class SupervisorElement extends HTMLElement {
51
51
  }
52
52
 
53
53
  get closeElement () {
54
- return this.querySelector('button[data-role="closer"]')
54
+ return this.querySelector('button')
55
55
  }
56
56
 
57
57
  get html () {
58
58
  return `
59
59
  <style>${this.stylesheet}</style>
60
- <div data-role="container">
61
- <strong>ReflexBehaviors</strong>
60
+ <div>
61
+ <label>ReflexBehaviors</label>
62
62
  <slot name="devtool"></slot>
63
- <button data-role='closer'>X</button>
63
+ <button>X</button>
64
64
  </div>
65
65
  `
66
66
  }
@@ -68,46 +68,62 @@ export default class SupervisorElement extends HTMLElement {
68
68
  get stylesheet () {
69
69
  return `
70
70
  :host {
71
- background-color: ghostwhite;
72
- border-radius: 10px;
73
- outline: solid 1px gainsboro;
71
+ background-color: lavender;
72
+ border-radius: 15px;
74
73
  bottom: 20px;
75
74
  display: block;
76
- filter: drop-shadow(0 4px 3px rgba(0,0,0,.07));
75
+ filter: drop-shadow(3px 3px 3px rgba(0,0,0,0.3));
77
76
  left: 50%;
77
+ outline-offset: 1px;
78
+ outline: solid 3px indigo;
78
79
  padding: 5px 10px;
79
80
  position: fixed;
80
81
  transform: translateX(-50%);
81
- z-index: 10000;
82
+ z-index: 100000;
82
83
  }
83
84
 
84
85
  :host, :host * {
85
86
  -webkit-user-select: none;
87
+ font-family: helvetica, sans-serif;
86
88
  user-select: none;
87
89
  }
88
90
 
89
- strong {
90
- color: silver;
91
- font-weight: 600;
91
+ :host:has( input) {
92
+ outline-color: red;
93
+ outline-width: 2px;
92
94
  }
93
95
 
94
- div[data-role="container"] {
96
+ label {
97
+ color: indigo;
98
+ opacity: 0.5;
99
+ }
100
+
101
+ div {
95
102
  display: flex;
96
103
  gap: 0 5px;
104
+ position: relative;
97
105
  }
98
106
 
99
- button[data-role="closer"] {
100
- border: none;
101
- background-color: gainsboro;
107
+ button {
108
+ background-color: thistle;
102
109
  border-radius: 50%;
103
- color: white;
104
- font-size: 12px;
110
+ border: none;
111
+ color: indigo;
112
+ cursor: pointer;
113
+ font-size: 10px;
105
114
  height: 18px;
106
115
  line-height: 18px;
107
116
  margin: 0 -5px 0 10px;
108
- padding: 0 3px;
117
+ outline: solid 1px indigo;
118
+ padding: 0 2px;
119
+ position: relative;
120
+ top: 1px;
109
121
  width: 18px;
110
122
  }
123
+
124
+ button:hover {
125
+ outline-width: 2px;
126
+ }
111
127
  `
112
128
  }
113
129
  }
@@ -56,14 +56,15 @@ export default class TooltipElement extends HTMLElement {
56
56
 
57
57
  [role="tooltip"] {
58
58
  background-color: ${this.backgroundColor};
59
- border-radius: 5px;
59
+ border-radius: 15px;
60
60
  filter: drop-shadow(3px 3px 3px rgba(0,0,0,0.3));
61
61
  font-family: monospace;
62
62
  left: 50px;
63
63
  min-height: 30px;
64
64
  min-width: 100px;
65
65
  opacity: 0.9;
66
- outline: solid 2px ${this.emphasisColor};
66
+ outline-offset: 1px;
67
+ outline: solid 3px ${this.emphasisColor};
67
68
  padding: 8px 12px 8px 12px;
68
69
  white-space: nowrap;
69
70
  }
@@ -71,11 +72,11 @@ export default class TooltipElement extends HTMLElement {
71
72
  [role="tooltip"]::after {
72
73
  border-color: ${this.cssArrow};
73
74
  border-style: solid;
74
- border-width: 5px;
75
+ border-width: 10px;
75
76
  content: "";
76
- margin-left: -5px;
77
+ margin-left: -7px;
77
78
  position: absolute;
78
- top: ${this.position === 'bottom' ? '-10px' : '100%'};
79
+ top: ${this.position === 'bottom' ? '-21px' : 'calc(100% + 1px)'};
79
80
  }
80
81
 
81
82
  slot[name="title"] {
@@ -10,7 +10,7 @@ customElements.define('reflex-behaviors-devools-tooltip', TooltipElement)
10
10
  let supervisorElement
11
11
 
12
12
  function stop () {
13
- if (!supervisorElement) return
13
+ if (stopped()) return
14
14
  supervisorElement.close()
15
15
  supervisorElement.dispatchEvent(
16
16
  new CustomEvent('reflex-behaviors:devtools-stop', {
@@ -21,6 +21,7 @@ function stop () {
21
21
  }
22
22
 
23
23
  function start () {
24
+ if (started()) return
24
25
  appendHTML(
25
26
  '<reflex-behaviors-devtool-supervisor></reflex-behaviors-devtool-supervisor>'
26
27
  )
@@ -47,15 +48,28 @@ function restart () {
47
48
  })
48
49
  }
49
50
 
51
+ function started () {
52
+ return !!supervisorElement
53
+ }
54
+
55
+ function stopped () {
56
+ return !started()
57
+ }
58
+
50
59
  let restartTimeout
51
60
  function debouncedRestart () {
52
61
  clearTimeout(restartTimeout)
53
62
  restartTimeout = setTimeout(restart, 25)
54
63
  }
55
- addEventListener('turbo:load', debouncedRestart)
56
- addEventListener('turbo-frame:load', debouncedRestart)
57
- addEventListener('turbo-reflex:success', debouncedRestart)
58
- addEventListener('turbo-reflex:finish', debouncedRestart)
64
+
65
+ function autoRestart () {
66
+ if (started()) debouncedRestart()
67
+ }
68
+
69
+ addEventListener('turbo:load', autoRestart)
70
+ addEventListener('turbo-frame:load', autoRestart)
71
+ addEventListener('turbo-reflex:success', autoRestart)
72
+ addEventListener('turbo-reflex:finish', autoRestart)
59
73
 
60
74
  function register (name, label) {
61
75
  if (!supervisorElement) return
@@ -77,7 +91,13 @@ function enabled (name) {
77
91
  export default {
78
92
  enabled,
79
93
  register,
80
- restart: debouncedRestart,
81
94
  start,
82
- stop
95
+ stop,
96
+ restart: debouncedRestart,
97
+ get started () {
98
+ return started()
99
+ },
100
+ get stopped () {
101
+ return stopped()
102
+ }
83
103
  }
@@ -8,16 +8,6 @@ document.addEventListener('reflex-behaviors:devtools-start', () =>
8
8
  const triggerTooltipId = 'toggle-trigger-tooltip'
9
9
  const targetTooltipId = 'toggle-target-tooltip'
10
10
 
11
- addEventListener('click', () => setTimeout(removeTooltips))
12
-
13
- function removeTooltips () {
14
- const ids = [triggerTooltipId, targetTooltipId]
15
- ids.forEach(id => {
16
- const el = document.getElementById(id)
17
- if (el) el.remove()
18
- })
19
- }
20
-
21
11
  function appendTooltip (id, title, content, options = {}) {
22
12
  let { backgroundColor, color, emphaisColor, position } = options
23
13
  color = color || 'white'
@@ -38,11 +28,6 @@ export default class ToggleDevtool {
38
28
  this.reflex = trigger.dataset.turboReflex
39
29
  this.trigger = trigger
40
30
  this.target = trigger.target
41
- this.renderingPartial = trigger.renderingPartial
42
- this.renderingElement = trigger.renderingElement
43
- this.renderingElementId = this.renderingElement
44
- ? this.renderingElement.id
45
- : null
46
31
 
47
32
  document.addEventListener('reflex-behaviors:devtool-enable', event => {
48
33
  const { name } = event.detail
@@ -54,6 +39,11 @@ export default class ToggleDevtool {
54
39
  const { name } = event.detail
55
40
  if (name === this.name) removeHighlight(this.trigger)
56
41
  })
42
+
43
+ document.addEventListener('click', event => {
44
+ if (event.target.closest('reflex-behaviors-devools-tooltip')) return
45
+ this.hide()
46
+ })
57
47
  }
58
48
 
59
49
  get enabled () {
@@ -66,30 +56,67 @@ export default class ToggleDevtool {
66
56
  this.createTriggerTooltip()
67
57
  this.createTargetTooltip()
68
58
  addHighlight(this.target, { color: 'blue', offset: '-2px' })
69
- addHighlight(this.renderingElement, {
59
+
60
+ let renderingPartial = this.trigger ? this.trigger.renderingPartial : null
61
+ renderingPartial =
62
+ renderingPartial || (this.target ? this.target.renderingPartial : null)
63
+
64
+ let renderingElement = this.trigger ? this.trigger.renderingElement : null
65
+ renderingElement =
66
+ renderingElement || (this.target ? this.target.renderingElement : null)
67
+
68
+ addHighlight(renderingElement, {
70
69
  color: 'turquoise',
71
70
  offset: '4px',
72
71
  width: '4px'
73
72
  })
74
73
 
75
- console.table({
76
- trigger: { id: this.trigger.id, partial: this.trigger.partial },
77
- target: { id: this.target.id, partial: this.target.partial },
78
- [this.reflex]: {
79
- id: this.renderingElementId,
80
- partial: this.renderingPartial
81
- }
82
- })
74
+ const data = {
75
+ rendering: { partial: null, id: null },
76
+ trigger: { partial: null, id: null },
77
+ target: { partial: null, id: null }
78
+ }
79
+
80
+ if (renderingPartial) data.rendering.partial = renderingPartial
81
+ if (renderingElement) data.rendering.id = renderingElement.id
82
+
83
+ if (this.trigger)
84
+ data.trigger = { partial: this.trigger.partial, id: this.trigger.id }
85
+
86
+ if (this.target)
87
+ data.target = { partial: this.target.partial, id: this.target.id }
88
+ else if (this.trigger)
89
+ data.target.id = `No element matches the targeted DOM id: ${this.trigger.controls}`
90
+
91
+ console.table(data)
83
92
  }
84
93
 
85
94
  hide () {
95
+ let renderingElement = this.trigger ? this.trigger.renderingElement : null
96
+ renderingElement =
97
+ renderingElement || (this.target ? this.target.renderingElement : null)
98
+
86
99
  this.destroyTriggerTooltip()
87
100
  this.destroyTargetTooltip()
88
101
  removeHighlight(this.target)
89
- removeHighlight(this.renderingElement)
102
+ removeHighlight(renderingElement)
103
+ this.cleanup()
104
+ }
105
+
106
+ cleanup () {
107
+ document
108
+ .querySelectorAll('reflex-behaviors-devools-tooltip')
109
+ .forEach(el => el.remove())
110
+
111
+ document
112
+ .querySelectorAll('[data-reflex-behaviors-highlight]')
113
+ .forEach(el => {
114
+ if (!el.tagName.match(/toggle-trigger/i)) removeHighlight(el)
115
+ })
90
116
  }
91
117
 
92
118
  createTriggerTooltip () {
119
+ if (!this.trigger) return
93
120
  const title = `TRIGGER (targets: ${this.trigger.controls})`
94
121
  const content = this.trigger.viewStack
95
122
  .map(view => {
@@ -105,8 +132,8 @@ export default class ToggleDevtool {
105
132
  })
106
133
 
107
134
  const coords = this.trigger.coordinates
108
- const top = Math.ceil(coords.top - this.triggerTooltip.offsetHeight - 5)
109
- const left = Math.ceil(coords.left)
135
+ const top = Math.ceil(coords.top - this.triggerTooltip.offsetHeight - 14)
136
+ const left = Math.ceil(coords.left - 15)
110
137
  this.triggerTooltip.style.top = `${top}px`
111
138
  this.triggerTooltip.style.left = `${left}px`
112
139
  }
@@ -119,6 +146,7 @@ export default class ToggleDevtool {
119
146
 
120
147
  createTargetTooltip () {
121
148
  if (!this.target) return
149
+ if (!this.target.viewStack) return
122
150
 
123
151
  const title = `TARGET (id: ${this.target.id})`
124
152
  const content = this.target.viewStack
@@ -136,8 +164,8 @@ export default class ToggleDevtool {
136
164
  })
137
165
 
138
166
  const coords = this.target.coordinates
139
- const top = Math.ceil(coords.top + coords.height + 4)
140
- const left = Math.ceil(coords.left)
167
+ const top = Math.ceil(coords.top + coords.height + 12)
168
+ const left = Math.ceil(coords.left - 15)
141
169
  this.targetTooltip.style.top = `${top}px`
142
170
  this.targetTooltip.style.left = `${left}px`
143
171
  }
@@ -5,23 +5,19 @@ import ToggleDevtool from '../devtools/toggle'
5
5
  export default class ToggleTriggerElement extends ReflexElement {
6
6
  connectedCallback () {
7
7
  super.connectedCallback()
8
-
9
8
  const mouseenter = () => this.devtool.show()
10
- const mouseleave = () => this.devtool.hide()
11
9
 
12
10
  document.addEventListener('reflex-behaviors:devtools-start', () => {
13
11
  this.devtool = new ToggleDevtool(this)
14
12
  this.addEventListener('mouseenter', mouseenter)
15
- this.addEventListener('mouseleave', mouseleave)
16
13
  })
17
14
 
18
15
  document.addEventListener('reflex-behaviors:devtools-stop', () => {
19
16
  this.removeEventListener('mouseenter', mouseenter)
20
- this.removeEventListener('mouseleave', mouseleave)
21
17
  delete this.devtool
22
18
  })
23
19
 
24
- DevtoolSupervisor.restart()
20
+ if (DevtoolSupervisor.started) DevtoolSupervisor.restart()
25
21
  }
26
22
 
27
23
  collapse () {
@@ -35,6 +31,7 @@ export default class ToggleTriggerElement extends ReflexElement {
35
31
 
36
32
  get sharedViews () {
37
33
  if (!this.target) return []
34
+ if (!this.target.viewStack) return []
38
35
  const reducer = (memo, view) => {
39
36
  if (this.target.viewStack.includes(view)) memo.push(view)
40
37
  return memo
@@ -34,8 +34,11 @@ class ReflexBehaviors::ApplicationReflex < TurboReflex::Base
34
34
  private
35
35
 
36
36
  def hydrated_value(value)
37
- GlobalID::Locator.locate_signed(value)
38
- rescue
39
- value
37
+ hydrated = begin
38
+ GlobalID::Locator.locate_signed(value)
39
+ rescue
40
+ value
41
+ end
42
+ hydrated.blank? ? nil : hydrated
40
43
  end
41
44
  end
@@ -4,25 +4,6 @@ require_relative "base_tag_builder"
4
4
 
5
5
  module ReflexBehaviors::TagBuilders
6
6
  class ToggleTagsBuilder < BaseTagBuilder
7
- def target_tag(id, expanded: false, **kwargs, &block)
8
- kwargs = kwargs.with_indifferent_access
9
- kwargs[:id] = id
10
- kwargs[:role] = "region"
11
-
12
- kwargs[:aria] ||= {}
13
- kwargs[:aria][:label] ||= "Dynamic Content Region"
14
- kwargs[:aria][:live] ||= "polite"
15
-
16
- kwargs[:data] ||= {}
17
- kwargs[:data][:view_stack] = view_stack.to_json if Rails.env.development?
18
-
19
- if expanded || target_expanded?(id)
20
- content_tag("toggle-target", nil, kwargs, &block)
21
- else
22
- content_tag("toggle-target", nil, kwargs)
23
- end
24
- end
25
-
26
7
  def trigger_tag(target:, render:, action: :toggle, disabled: false, **kwargs, &block)
27
8
  kwargs = kwargs.with_indifferent_access
28
9
  kwargs[:id] ||= "#{target}-toggle-trigger"
@@ -42,6 +23,25 @@ module ReflexBehaviors::TagBuilders
42
23
  content_tag("toggle-trigger", nil, kwargs, &block)
43
24
  end
44
25
 
26
+ def target_tag(id, expanded: false, **kwargs, &block)
27
+ kwargs = kwargs.with_indifferent_access
28
+ kwargs[:id] = id
29
+ kwargs[:role] = "region"
30
+
31
+ kwargs[:aria] ||= {}
32
+ kwargs[:aria][:label] ||= "Dynamic Content Region"
33
+ kwargs[:aria][:live] ||= "polite"
34
+
35
+ kwargs[:data] ||= {}
36
+ kwargs[:data][:view_stack] = view_stack.to_json if Rails.env.development?
37
+
38
+ if expanded || target_expanded?(id)
39
+ content_tag("toggle-target", nil, kwargs, &block)
40
+ else
41
+ content_tag("toggle-target", nil, kwargs)
42
+ end
43
+ end
44
+
45
45
  def target_expanded?(target)
46
46
  !!turbo_reflex.state[target]
47
47
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReflexBehaviors
4
- VERSION = "0.0.4"
4
+ VERSION = "0.0.5"
5
5
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reflex_behaviors",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "Pre-built easy to use reactive TurboReflex behaviors for Rails/Hotwire apps.",
5
5
  "main": "app/javascript/index.js",
6
6
  "repository": "https://github.com/hopsoft/reflex_behaviors",
data/tags CHANGED
@@ -213706,7 +213706,7 @@ VDash node_modules/parse-srcset/tests/he.js /^ var decodeMap = {'Aacute':'\\xC1'
213706
213706
  VDash node_modules/simple-html-tokenizer/dist/es6/index.js /^ Aacute: "Á", aacute: "á", Abreve: "Ă", abreve: "ă", ac: "∾", acd: "∿", acE: "∾̳",/;" p variable:namedCharRefs
213707
213707
  VDash node_modules/simple-html-tokenizer/dist/simple-html-tokenizer.js /^ Aacute: "Á", aacute: "á", Abreve: "Ă", abreve: "ă", ac: "∾", acd: "∿", acE: "∾/;" p variable:anonymousFunction3825d8d70300.namedCharRefs
213708
213708
  VDash node_modules/simple-html-tokenizer/dist/types/generated/html5-named-char-refs.d.ts /^ VDash: string;$/;" C
213709
- VERSION lib/reflex_behaviors/version.rb /^ VERSION = "0.0.4"$/;" C module:ReflexBehaviors
213709
+ VERSION lib/reflex_behaviors/version.rb /^ VERSION = "0.0.5"$/;" C module:ReflexBehaviors
213710
213710
  VERSION node_modules/@angular/compiler/esm2015/src/output/source_map.js /^const VERSION = 3;$/;" C
213711
213711
  VERSION node_modules/@angular/compiler/esm2015/src/version.js /^export const VERSION = new Version('8.2.14');$/;" C
213712
213712
  VERSION node_modules/@angular/compiler/esm5/src/output/source_map.js /^var VERSION = 3;$/;" v
@@ -473774,7 +473774,7 @@ version node_modules/yaml/dist/index.js /^ version: '1.2'$/;" p variable:defaul
473774
473774
  version node_modules/yaml/dist/test-events.js /^ version: '1.2'$/;" p variable:testEvents.anonymousObjecta2b129440205
473775
473775
  version node_modules/yaml/package.json /^ "version": "1.8.3",$/;" s
473776
473776
  version node_modules/yocto-queue/package.json /^ "version": "0.1.0",$/;" s
473777
- version package.json /^ "version": "0.0.3",$/;" s
473777
+ version package.json /^ "version": "0.0.4",$/;" s
473778
473778
  versionIncluded node_modules/prettier-standard/src/vendor/node_modules/resolve/lib/core.js /^function versionIncluded(specifierValue) {$/;" f
473779
473779
  versionIncluded node_modules/resolve/lib/core.js /^function versionIncluded(specifierValue) {$/;" f
473780
473780
  versionInfo node_modules/graphql/version.d.ts /^export const versionInfo: {$/;" C
data/yarn.lock CHANGED
@@ -165,9 +165,9 @@
165
165
  integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==
166
166
 
167
167
  "@types/node@*":
168
- version "18.11.10"
169
- resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.10.tgz#4c64759f3c2343b7e6c4b9caf761c7a3a05cee34"
170
- integrity sha512-juG3RWMBOqcOuXC643OAdSA525V44cVgGV6dUDuiFtss+8Fk5x1hI93Rsld43VeJVIeqlP9I7Fn9/qaVqoEAuQ==
168
+ version "18.11.11"
169
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.11.tgz#1d455ac0211549a8409d3cdb371cd55cc971e8dc"
170
+ integrity sha512-KJ021B1nlQUBLopzZmPBVuGU9un7WJd/W4ya7Ih02B4Uwky5Nja0yGYav2EfYIk0RR2Q9oVhf60S2XR1BCWJ2g==
171
171
 
172
172
  "@types/unist@^2.0.0", "@types/unist@^2.0.2":
173
173
  version "2.0.6"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reflex_behaviors
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
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: 2022-12-05 00:00:00.000000000 Z
11
+ date: 2022-12-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails