reflex_behaviors 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -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