Skip to content

Commit

Permalink
Implement inertia_ui_modal_renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
skryukov committed Oct 30, 2024
1 parent a575b85 commit 1aa792b
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning].

## [Unreleased]

Added:

- [InertiaUI Modal](https://github.com/inertiaui/modal) support ([@skryukov])

## [0.3.0] - 2024-10-25

Added:
Expand Down
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ bin/rails generate inertia:install
```

This command will:

- Check for Vite Rails and install it if not present
- Ask if you want to use TypeScript
- Ask you to choose your preferred frontend framework (React, Vue, Svelte 4, or Svelte 5)
Expand Down Expand Up @@ -149,6 +150,37 @@ $ bin/rails generate inertia:scaffold Post title:string body:text
- `inertia_templates` - default
- `inertia_tw_templates` - Tailwind CSS
## InertiaUI Modal Support
`InertiaRailsContrib` provides support for [InertiaUI Modal](https://github.com/inertiaui/modal) in the Rails application.
With InertiaUI Modal, you can easily open any route in a Modal or Slideover without having to change anything about your existing routes or controllers.
By default, InertiaUI Modal doesn't require anything from the Inertia Server Adapters, since it just opens modals without changing the URL.
However, InertiaUI Modal also supports updating the URL when opening a modal (see the docs on why you might want that: https://inertiaui.com/inertia-modal/docs/base-route-url).

### Setup

1. Follow the NPM installation instructions from the [InertiaUI Modal documentation](https://inertiaui.com/inertia-modal/docs/installation).

2. Enable InertiaUI Modal, turn on the `enable_inertia_ui_modal` option in the `inertia_rails_contrib.rb` initializer:

```ruby
InertiaRailsContrib.configure do |config|
config.enable_inertia_ui_modal = true
end
```

This will add a new render method `inertia_modal` that can be used in the controller actions:

```ruby
class PostsController < ApplicationController
def new
render inertia_modal: 'Post/New', props: { post: Post.new }, base_url: posts_path
end
end
```
## Development
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
Expand Down
15 changes: 14 additions & 1 deletion lib/inertia_rails_contrib.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
# frozen_string_literal: true

require "inertia_rails" if defined?(Rails)
if defined?(Rails)
require "inertia_rails"
require_relative "inertia_rails_contrib/engine"
end

require_relative "inertia_rails_contrib/version"
require_relative "inertia_rails_contrib/configuration"

module InertiaRailsContrib
class << self
def configuration
@configuration ||= Configuration.new
end

def configure
yield(configuration)
end
end
end
10 changes: 10 additions & 0 deletions lib/inertia_rails_contrib/configuration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# lib/inertia_rails_contrib/engine.rb
module InertiaRailsContrib
class Configuration
attr_accessor :enable_inertia_ui_modal

def initialize
@enable_inertia_ui_modal = false
end
end
end
9 changes: 9 additions & 0 deletions lib/inertia_rails_contrib/engine.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module InertiaRailsContrib
class Engine < ::Rails::Engine
initializer "inertia_rails_contrib.inertia_ui_modal" do
require_relative "inertia_ui_modal" if InertiaRailsContrib.configuration.enable_inertia_ui_modal
end
end
end
27 changes: 27 additions & 0 deletions lib/inertia_rails_contrib/inertia_ui_modal.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

require_relative "inertia_ui_modal/renderer"
require_relative "inertia_ui_modal/redirect"
require_relative "inertia_ui_modal/inertia_rails_patch"

module InertiaRailsContrib
module InertiaUIModal
HEADER_BASE_URL = "X-InertiaUI-Modal-Base-Url"
HEADER_USE_ROUTER = "X-InertiaUI-Modal-Use-Router"
end
end

ActionController::Renderers.add :inertia_modal do |component, options|
InertiaRailsContrib::InertiaUIModal::Renderer.new(
component,
self,
request,
response,
method(:render),
**options
).render
end

ActiveSupport.on_load(:action_controller_base) do
prepend ::InertiaRailsContrib::InertiaUIModal::Redirect
end
20 changes: 20 additions & 0 deletions lib/inertia_rails_contrib/inertia_ui_modal/inertia_rails_patch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

require "inertia_rails/renderer"

module InertiaRailsContrib
module InertiaUIModal
module RendererPatch
def page
super.tap do |modal|
if @request.env[:_inertiaui_modal]
modal[:props][:_inertiaui_modal] = @request.env[:_inertiaui_modal]
modal[:url] = modal[:props][:_inertiaui_modal][:url]
end
end
end
end
end
end

InertiaRails::Renderer.prepend(InertiaRailsContrib::InertiaUIModal::RendererPatch)
16 changes: 16 additions & 0 deletions lib/inertia_rails_contrib/inertia_ui_modal/redirect.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

module InertiaRailsContrib
module InertiaUIModal
module Redirect
def redirect_back_or_to(fallback_location, allow_other_host: _allow_other_host, **options)
inertia_modal_referer = request.headers[HEADER_BASE_URL]
if inertia_modal_referer && (allow_other_host || _url_host_allowed?(inertia_modal_referer))
redirect_to inertia_modal_referer, allow_other_host: allow_other_host, **options
else
super
end
end
end
end
end
48 changes: 48 additions & 0 deletions lib/inertia_rails_contrib/inertia_ui_modal/renderer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# frozen_string_literal: true

module InertiaRailsContrib
module InertiaUIModal
class Renderer
def initialize(component, controller, request, response, render_method, base_url: nil, **options)
@request = request
@response = response
@base_url = base_url
@inertia_renderer = InertiaRails::Renderer.new(component, controller, request, response, render_method, **options)
end

def render
if @request.headers[HEADER_USE_ROUTER] == "0" || base_url.blank?
return @inertia_renderer.render
end

@request.env[:_inertiaui_modal] = @inertia_renderer.page.merge(baseUrl: base_url)

render_base_url
end

def base_url
@request.headers[HEADER_BASE_URL] || @base_url
end

def render_base_url
original_env = Rack::MockRequest.env_for(
base_url,
method: @request.method,
params: @request.params
)
@request.each_header do |k, v|
original_env[k] ||= v
end

original_request = ActionDispatch::Request.new(original_env)

path = ActionDispatch::Journey::Router::Utils.normalize_path(original_request.path_info)
Rails.application.routes.recognize_path_with_request(original_request, path, {})
controller = original_request.controller_class.new
controller.request = @request
controller.response = @response
controller.process(original_request.path_parameters[:action])
end
end
end
end

0 comments on commit 1aa792b

Please sign in to comment.