Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move hydration mechanics to the lower level commands lib #21

Merged
merged 17 commits into from
Jan 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
</h1>
<p align="center">
<a href="http://blog.codinghorror.com/the-best-code-is-no-code-at-all/">
<img alt="Lines of Code" src="https://img.shields.io/badge/loc-1131-47d299.svg" />
<img alt="Lines of Code" src="https://img.shields.io/badge/loc-1114-47d299.svg" />
</a>
<a href="https://codeclimate.com/github/hopsoft/turbo_boost-elements/maintainability">
<img src="https://api.codeclimate.com/v1/badges/7aac6daed3e4032e292e/maintainability" />
Expand Down Expand Up @@ -181,21 +181,18 @@ This example will re-render the `post` partial and toggle the `form` section.
If a named keyword argument is shared by both the `trigger` and `target`,
the trigger value will take precendence because multiple triggers might control the same target.

#### DevTools

#### DevTools Helpers
To make your development easier, Reflex Behaviors comes with a browser DevTools helper.
You can enable the helper from your javascript console or your application's javascript file
TurboBoost ships with client/browser based devtools designed to improve the developer experience.
You can enable the devtools with JavaScript like so.

```js
ReflexBehaviors.devtools.start()
TurboBoost.devtools.start()
```


## Introductory Video
[![Watch the introduction on YouTube](https://img.youtube.com/vi/WERDPzOz1sA/maxresdefault.jpg)](https://youtu.be/WERDPzOz1sA "Watch the introduction on YouTube")



## Releasing

1. Run `yarn` and `bundle` to pick up the latest
Expand Down
20 changes: 10 additions & 10 deletions app/assets/builds/@turbo-boost/elements.js

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions app/assets/builds/@turbo-boost/elements.js.map

Large diffs are not rendered by default.

30 changes: 0 additions & 30 deletions app/commands/turbo_boost/elements/application_command.rb
Original file line number Diff line number Diff line change
@@ -1,34 +1,4 @@
# frozen_string_literal: true

class TurboBoost::Elements::ApplicationCommand < TurboBoost::Commands::Command
protected

def render_payload
return {} if element.renders.blank?
@render_payload ||= {partial: idomatic_partial_path(element.renders)}.tap do |payload|
if element.assigns.present?
payload[:assigns] = JSON.parse(element.assigns)
payload[:assigns].each { |key, value| payload[:assigns][key] = hydrate_value(value) }
end
if element.locals.present?
payload[:locals] = JSON.parse(element.locals)
payload[:locals].each { |key, value| payload[:locals][key] = hydrate_value(value) }
end
end.deep_symbolize_keys
end

private

def hydrate_value(value)
hydrated = begin
GlobalID::Locator.locate_signed(value)
rescue
value
end
hydrated.blank? ? nil : hydrated
end

def idomatic_partial_path(partial_path)
partial_path.to_s.gsub("/_", "/").split(".").first
end
end
36 changes: 33 additions & 3 deletions app/commands/turbo_boost/elements/toggle_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,51 @@ class TurboBoost::Elements::ToggleCommand < TurboBoost::Elements::ApplicationCom
prevent_controller_action

def show
if element.remember == "true"
validate_element!

if element.remember?
state[element.aria.controls] = true
else
state.now[element.aria.controls] = true
end

morph "##{element.morphs}", render(render_payload)
morph id: element.morphs, html: render(element.render_options)
end

def hide
validate_element!
state[element.aria.controls] = false
morph "##{element.morphs}", render(render_payload)
morph id: element.morphs, html: render(element.render_options)
end

def toggle
validate_element!
element.aria.expanded? ? hide : show
end

private

def validate_element!
validate_element_attributes! && validate_element_aria_attributes!
end

def validate_element_attributes!
case element
in {renders: _, morphs: _} then return true
in {renders: _} then raise TurboBoost::Commands::InvalidElementError, "The trigger element is missing the `morphs` attribute!"
in {morphs: _} then raise TurboBoost::Commands::InvalidElementError, "The trigger element is missing the `renders` attribute!"
else raise TurboBoost::Commands::InvalidCommandError, "The trigger element is missing the `renders` and `moprhs` attributes!"
end
false
end

def validate_element_aria_attributes!
case element.aria
in {controls: _, expanded: _} then return true
in {controls: _} then raise TurboBoost::Commands::InvalidElementError, "The trigger element is missing the `aria-expanded` attribute!"
in {expanded: _} then raise TurboBoost::Commands::InvalidElementError, "The trigger element is missing the `aria-controls` attribute!"
else raise TurboBoost::Commands::InvalidElementError, "The trigger element is missing the `aria-controls` and `aria-expanded` attributes!"
end
false
end
end
13 changes: 3 additions & 10 deletions app/helpers/turbo_boost/elements/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,10 @@
require_relative "../../../../lib/turbo_boost/elements/tag_builders"

module TurboBoost::Elements::ApplicationHelper
# Returns an idiomatic path for the currently rendering template
# i.e. How you'd pass the path to a `render partial: ...` call
def current_partial_path
path = nil
prefix = "app/views/"
start = 1
while path.nil? && start < 100
location = caller_locations(start, 1).first
path = location.path if location.path.include?(prefix)
start += 1
end
return "unknown" if path.nil?
path[(path.index(prefix) + prefix.length), path.rindex("/")]
@virtual_path.to_s.gsub("/_", "/")
end

def method_missing(name, ...)
Expand Down
1 change: 0 additions & 1 deletion app/javascript/devtools/toggle.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,6 @@ export default class ToggleDevtool {

tooltip.drag = new PlainDraggable(tooltip)
tooltip.drag.onMove = () => {
console.log('nate', tooltip.line)
tooltip.line.position()
if (tooltip.lineToTarget) tooltip.lineToTarget.position()
if (tooltip.lineToRendering) tooltip.lineToRendering.position()
Expand Down
2 changes: 1 addition & 1 deletion bin/standardize
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

bundle exec magic_frozen_string_literal
bundle exec standardrb --fix
yarn run prettier-standard "app/javascript/**/*.js"
yarn run prettier-standard package.json app/javascript/**/*.js
5 changes: 3 additions & 2 deletions lib/turbo_boost/elements/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ def self.config
class Engine < ::Rails::Engine
config.turbo_boost_elements = ActiveSupport::OrderedOptions.new

ActiveSupport.on_load(:action_controller) do
try :helper, TurboBoost::Elements::ApplicationHelper
ActiveSupport.on_load(:action_controller_base) do
# `self` is ActionController::Base
helper TurboBoost::Elements::ApplicationHelper
end
end
end
15 changes: 0 additions & 15 deletions lib/turbo_boost/elements/tag_builders/base_tag_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,4 @@ def view_stack
memo << location.path[(location.path.index(prefix) + prefix.length)..]
end
end

protected

def dehydrate_value(value)
return value.to_s unless value.respond_to?(:to_sgid_param)
value.try(:persisted?) ? value.to_sgid_param : nil
end

def dehydrate_hash(hash)
hash
.with_indifferent_access
.each_with_object({}.with_indifferent_access) do |(key, val), memo|
memo[key] = dehydrate_value(val)
end
end
end
12 changes: 5 additions & 7 deletions lib/turbo_boost/elements/tag_builders/toggle_tags_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ def trigger_tag(
renders:, # REQUIRED, the partial path to render
morphs:, # REQUIRED, `dom_id` of the partial's outermost containing element
controls:, # REQUIRED, `dom_id` of the toggle target
assigns: {}, # `assigns` required to render the partial (i.e. instance variables)
locals: {}, # `local_assigns` required to render the parital
collapse_selector: nil, # CSS selector for other matching targets to collapse when the target is expanded
focus_selector: nil, # CSS selector for the element to focus when the target is expanded
method: :toggle, # method to inovke (:show, :hide, :toggle)
Expand All @@ -24,18 +22,16 @@ def trigger_tag(
kwargs[:data] ||= {}
kwargs[:data][:turbo_command] = "TurboBoost::Elements::ToggleCommand##{method}" unless disabled

# target / aria
# aria
kwargs[:aria] ||= {}
kwargs[:aria][:controls] = controls
kwargs[:aria][:controls] = controls # toggle target
kwargs[:aria][:expanded] = target_expanded?(controls)
kwargs[:aria][:atomic] ||= true
kwargs[:aria][:relevant] ||= "all"

# rendering
kwargs[:renders] = renders
kwargs[:morphs] = morphs
kwargs[:assigns] = dehydrate_hash(assigns).compact.to_json if assigns.present?
kwargs[:locals] = dehydrate_hash(locals).compact.to_json if locals.present?
kwargs[:view_stack] = view_stack.to_json if Rails.env.development?

# misc
Expand All @@ -44,7 +40,9 @@ def trigger_tag(
kwargs[:remember] = !!remember

args = kwargs.select { |_, value| value.present? }
content_tag("turbo-boost-toggle-trigger", nil, args.transform_keys(&:dasherize), &block)
args = args.transform_keys(&:dasherize)

content_tag("turbo-boost-toggle-trigger", nil, args, &block)
end

def target_tag(
Expand Down
18 changes: 15 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,24 @@
"name": "@turbo-boost/elements",
"version": "0.0.1",
"description": "Pre-built easy to use reactive TurboBoost elements for Rails/Hotwire apps.",
"main": "app/javascript/index.js",
"keywords": [
"hotwire",
"hotwired",
"rails",
"turbo",
"turbo-boost",
"web-components"
],
"type": "module",
"main": "app/assets/builds/@turbo-boost/elements.js",
"files": [
"app/assets/builds"
],
"repository": "https://github.com/hopsoft/turbo_boost-elements",
"author": "Nate Hopkins (hopsoft) <natehop@gmail.com>",
"license": "MIT",
"dependencies": {
"@turbo-boost/commands": ">= 0.0.1"
"@turbo-boost/commands": ">= 0.0.4"
},
"peerDependencies": {
"@hotwired/turbo-rails": ">= 7.2"
Expand All @@ -18,6 +30,6 @@
"prettier-standard": "^16.4.1"
},
"scripts": {
"build": "esbuild app/javascript/index.js --bundle --minify --sourcemap --format=esm --outfile=app/assets/builds/@turbo-boost/elements.js"
"build": "esbuild app/javascript/index.js --bundle --minify --sourcemap --format=esm --target=es2020,chrome58,firefox57,safari11 --analyze --outfile=app/assets/builds/@turbo-boost/elements.js"
}
}
2 changes: 1 addition & 1 deletion turbo_boost-elements.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Gem::Specification.new do |s|

s.add_dependency "rails", ">= 6.1"
s.add_dependency "turbo-rails", ">= 1.1"
s.add_dependency "turbo_boost-commands", ">= 0.0.2"
s.add_dependency "turbo_boost-commands", ">= 0.0.4"

s.add_development_dependency "magic_frozen_string_literal"
s.add_development_dependency "minitest-reporters"
Expand Down
Loading