hotwire_native_rails 0.4.3 → 0.5.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +14 -11
- data/.gitignore +1 -0
- data/CHANGELOG.md +10 -0
- data/README.md +16 -9
- data/Rakefile +11 -0
- data/bin/smoke +59 -0
- data/hotwire_native_rails.gemspec +4 -0
- data/lib/generators/hotwire_native/hotwire_native_generator.rb +29 -5
- data/lib/generators/hotwire_native/templates/controllers/concerns/device_format.rb +3 -1
- data/lib/generators/hotwire_native/templates/helpers/hotwire_native_helper.rb +46 -18
- data/lib/generators/hotwire_native/templates/javascript/controllers/bridge/menu_controller.js +0 -1
- data/lib/generators/hotwire_native/templates/javascript/controllers/bridge/nav_controller.js +5 -3
- data/lib/generators/hotwire_native/templates/test_unit/hotwire_native_helper_test.rb +39 -8
- data/lib/hotwire_native_rails/version.rb +1 -1
- metadata +20 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b9a2e5493ea7c812bac6c062d58bcd6d2cecf0813e98bbe1c8b04b1d1f19624b
|
|
4
|
+
data.tar.gz: f8d1b8babe84f397588fb343f4941a22d633fc1364c2a32b030547e0b08e2fae
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 214c4723dbfb23fb8f7e056217f19804bcbda9c49bd2afb92b881e481ea6ae9b893007a8ec70b23ef9949314ec86b95b9eb582338335c6c8b36aca212d264eb4
|
|
7
|
+
data.tar.gz: 92d65d6d21760e3334bd109d3d2fb8851b6d84c486f7171ac3b36e91fa79b26076ea503242a4f80bbfb5754bde39b630ef7e391d27d0ef22562ef4c0b3b58cf7
|
data/.github/workflows/main.yml
CHANGED
|
@@ -1,27 +1,30 @@
|
|
|
1
|
-
name:
|
|
1
|
+
name: Smoke test
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
5
|
branches:
|
|
6
|
-
-
|
|
7
|
-
|
|
6
|
+
- main
|
|
8
7
|
pull_request:
|
|
9
8
|
|
|
10
9
|
jobs:
|
|
11
|
-
|
|
10
|
+
smoke:
|
|
12
11
|
runs-on: ubuntu-latest
|
|
13
|
-
name:
|
|
12
|
+
name: ${{ matrix.flavor }}
|
|
14
13
|
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
15
|
matrix:
|
|
16
|
-
|
|
17
|
-
-
|
|
16
|
+
flavor:
|
|
17
|
+
- tailwind4
|
|
18
|
+
- tailwind3
|
|
19
|
+
- css
|
|
18
20
|
|
|
19
21
|
steps:
|
|
20
22
|
- uses: actions/checkout@v4
|
|
21
23
|
- name: Set up Ruby
|
|
22
24
|
uses: ruby/setup-ruby@v1
|
|
23
25
|
with:
|
|
24
|
-
ruby-version:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
ruby-version: '3.4'
|
|
27
|
+
- name: Install Rails
|
|
28
|
+
run: gem install rails --no-document
|
|
29
|
+
- name: Generate an app, run the generator and its tests
|
|
30
|
+
run: bin/smoke ${{ matrix.flavor }}
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.5.0] - 2026-11-14
|
|
4
|
+
|
|
5
|
+
- Generated code uses `hotwire_native_app?` instead of `turbo_native_app?` (#2). Requires `turbo-rails` >= 2.0.11.
|
|
6
|
+
- Fix: Tailwind 3 apps crashed the generator (`add_tailwind_3_css_variants` was undefined).
|
|
7
|
+
- Fix: Tailwind 4 apps did not get the `hotwire-native:` variants, because `@import "tailwindcss";` (double quotes) was not matched.
|
|
8
|
+
- Fix: the `link_to` override now also drops `target` for internal links written with a block, and no longer modifies the options hash passed in (#9).
|
|
9
|
+
- `internal_url?` compares against the request host instead of `root_url`, and treats `mailto:`/`tel:` links as external.
|
|
10
|
+
- README: the request variant is `:native` (`index.html+native.erb`), not `:mobile`.
|
|
11
|
+
- CI runs the generator in fresh Tailwind 4, Tailwind 3 and plain-CSS Rails apps (`bin/smoke`).
|
|
12
|
+
|
|
3
13
|
## [0.1.0] - 2024-11-30
|
|
4
14
|
|
|
5
15
|
- Initial release
|
data/README.md
CHANGED
|
@@ -4,6 +4,8 @@ Power pack to make your Rails app [Hotwire Native](https://native.hotwired.dev)
|
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
+
Requires `turbo-rails` 2.0.11 or newer (for the `hotwire_native_app?` helper).
|
|
8
|
+
|
|
7
9
|
Install the gem:
|
|
8
10
|
|
|
9
11
|
```sh
|
|
@@ -18,13 +20,11 @@ rails g hotwire_native
|
|
|
18
20
|
|
|
19
21
|
## Usage
|
|
20
22
|
|
|
21
|
-
Recommended to use with [my fork of iOS Hotwire Native starter app](https://github.com/yshmarov/hotwire-native-ios/tree/superails-extensions-2/Demo).
|
|
22
|
-
|
|
23
23
|
#### Helpers
|
|
24
24
|
- `viewport_meta_tag` - forbid zooming on mobile/native
|
|
25
25
|
- use `data: { turbo_action: replace_if_native }` to submit authentication forms & forms in modals
|
|
26
|
-
- `:
|
|
27
|
-
- override `link_to`
|
|
26
|
+
- `:native` request variant for Hotwire Native requests: `index.html+native.erb`
|
|
27
|
+
- override `link_to` so internal links open in the app, not the in-app browser (drops `target="_blank"` for your own host; works with and without a block)
|
|
28
28
|
- conditionally override page `<title>` for native apps
|
|
29
29
|
|
|
30
30
|
#### CSS
|
|
@@ -46,17 +46,24 @@ Recommended to use with [my fork of iOS Hotwire Native starter app](https://gith
|
|
|
46
46
|
Run the local version of the gem:
|
|
47
47
|
|
|
48
48
|
```ruby
|
|
49
|
-
gem 'hotwire_native_rails', path: '/Users/
|
|
49
|
+
gem 'hotwire_native_rails', path: '/Users/myusername/Documents/GitHub.nosync/hotwire_native_rails'
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Test the generator in brand-new Rails apps (Tailwind 4, Tailwind 3 and plain CSS). Each run generates an app under `tmp/`, runs `rails g hotwire_native`, checks what it changed and runs the generated tests:
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
bin/smoke tailwind4 # or tailwind3, css
|
|
56
|
+
bundle exec rake # all three
|
|
50
57
|
```
|
|
51
58
|
|
|
52
59
|
Make a release to rubygems:
|
|
53
60
|
|
|
54
61
|
```sh
|
|
55
|
-
# 1. update version in version.rb
|
|
56
|
-
# 2.
|
|
62
|
+
# 1. update version in version.rb and CHANGELOG.md
|
|
63
|
+
# 2. build the gem
|
|
57
64
|
gem build hotwire_native_rails.gemspec
|
|
58
|
-
# 3. push
|
|
59
|
-
gem push hotwire_native_rails-
|
|
65
|
+
# 3. push it to rubygems
|
|
66
|
+
gem push hotwire_native_rails-X.Y.Z.gem
|
|
60
67
|
```
|
|
61
68
|
|
|
62
69
|
- [Github source](https://github.com/yshmarov/hotwire_native_rails)
|
data/Rakefile
CHANGED
|
@@ -1,2 +1,13 @@
|
|
|
1
1
|
require "bundler/gem_tasks"
|
|
2
|
+
|
|
3
|
+
SMOKE_FLAVORS = %w[tailwind4 tailwind3 css].freeze
|
|
4
|
+
|
|
5
|
+
desc "Run the generator in fresh Rails apps (#{SMOKE_FLAVORS.join(", ")}) and run their tests"
|
|
6
|
+
task :test do
|
|
7
|
+
# bin/smoke runs `rails new` and the new app's own bundle, so leave this gem's bundle.
|
|
8
|
+
Bundler.with_unbundled_env do
|
|
9
|
+
SMOKE_FLAVORS.each { |flavor| sh "bin/smoke #{flavor}" }
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
2
13
|
task default: :test
|
data/bin/smoke
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Smoke-tests the generator in a brand-new Rails app, the way a user runs it.
|
|
3
|
+
#
|
|
4
|
+
# bin/smoke tailwind4 rails new --css=tailwind (tailwindcss-rails 4)
|
|
5
|
+
# bin/smoke tailwind3 a config/tailwind.config.js app (Tailwind 3 setup)
|
|
6
|
+
# bin/smoke css plain CSS, no Tailwind
|
|
7
|
+
#
|
|
8
|
+
# It generates the app under tmp/, installs this checkout of the gem, runs
|
|
9
|
+
# `rails g hotwire_native`, checks the files it should have changed, then runs
|
|
10
|
+
# the tests the generator copied into the app.
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
flavor="${1:-tailwind4}"
|
|
14
|
+
root="$(cd "$(dirname "$0")/.." && pwd)"
|
|
15
|
+
app="$root/tmp/smoke-$flavor"
|
|
16
|
+
|
|
17
|
+
rm -rf "$app"
|
|
18
|
+
mkdir -p "$root/tmp"
|
|
19
|
+
|
|
20
|
+
css_flag=()
|
|
21
|
+
if [ "$flavor" = "tailwind4" ]; then css_flag=(--css=tailwind); fi
|
|
22
|
+
|
|
23
|
+
rails new "$app" ${css_flag[@]+"${css_flag[@]}"} --quiet --skip-git --skip-docker --skip-kamal \
|
|
24
|
+
--skip-thruster --skip-solid --skip-action-mailbox --skip-action-text \
|
|
25
|
+
--skip-active-storage --skip-jbuilder --skip-ci --skip-rubocop --skip-brakeman \
|
|
26
|
+
--skip-system-test --skip-bootsnap
|
|
27
|
+
|
|
28
|
+
cd "$app"
|
|
29
|
+
|
|
30
|
+
if [ "$flavor" = "tailwind3" ]; then
|
|
31
|
+
printf 'module.exports = {\n plugins: [\n ]\n}\n' > config/tailwind.config.js
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
bundle add hotwire_native_rails --path "$root"
|
|
35
|
+
|
|
36
|
+
# The generated integration tests request root_path, so give the app a page.
|
|
37
|
+
bin/rails generate controller pages home --skip-routes --no-helper --quiet
|
|
38
|
+
ruby -pi -e 'sub(/^Rails.application.routes.draw do\n/) { "#{$&} root \"pages#home\"\n" }' config/routes.rb
|
|
39
|
+
|
|
40
|
+
bin/rails generate hotwire_native
|
|
41
|
+
|
|
42
|
+
fail() { echo "SMOKE FAIL ($flavor): $*" >&2; exit 1; }
|
|
43
|
+
layout=app/views/layouts/application.html.erb
|
|
44
|
+
grep -q "viewport_meta_tag" "$layout" || fail "viewport_meta_tag not in layout"
|
|
45
|
+
grep -q "platform_identifier" "$layout" || fail "platform_identifier not on <html>"
|
|
46
|
+
grep -q "page_title" "$layout" || fail "page_title not in <title>"
|
|
47
|
+
grep -q "include DeviceFormat" app/controllers/application_controller.rb || fail "DeviceFormat not included"
|
|
48
|
+
grep -q "draw(:hotwire_native)" config/routes.rb || fail "routes not drawn"
|
|
49
|
+
grep -rq "turbo_native_app?" app test && fail "turbo_native_app? still generated"
|
|
50
|
+
|
|
51
|
+
case "$flavor" in
|
|
52
|
+
tailwind4) grep -q "@custom-variant hotwire-native" app/assets/tailwind/application.css || fail "Tailwind 4 variants not added" ;;
|
|
53
|
+
tailwind3) grep -q 'addVariant("hotwire-native"' config/tailwind.config.js || fail "Tailwind 3 variants not added" ;;
|
|
54
|
+
css) grep -q "body.hotwire-native" app/assets/stylesheets/application.css || fail "CSS class not added"
|
|
55
|
+
grep -q "hotwire_native_app?" "$layout" || fail "body class not added" ;;
|
|
56
|
+
esac
|
|
57
|
+
|
|
58
|
+
bin/rails test
|
|
59
|
+
echo "SMOKE OK ($flavor)"
|
|
@@ -11,6 +11,10 @@ Gem::Specification.new do |spec|
|
|
|
11
11
|
spec.summary = "Generate Hotwire Native Rails helpers and bridge components"
|
|
12
12
|
spec.homepage = "https://github.com/yshmarov/hotwire_native_rails"
|
|
13
13
|
spec.license = "MIT"
|
|
14
|
+
spec.required_ruby_version = ">= 3.1"
|
|
15
|
+
|
|
16
|
+
# hotwire_native_app? (used by every generated helper) arrived in turbo-rails 2.0.11.
|
|
17
|
+
spec.add_dependency "turbo-rails", ">= 2.0.11"
|
|
14
18
|
|
|
15
19
|
spec.metadata["homepage_uri"] = spec.homepage
|
|
16
20
|
spec.metadata["source_code_uri"] = spec.homepage
|
|
@@ -2,7 +2,7 @@ class HotwireNativeGenerator < Rails::Generators::Base
|
|
|
2
2
|
source_root File.expand_path("templates", __dir__)
|
|
3
3
|
|
|
4
4
|
def add_gems
|
|
5
|
-
|
|
5
|
+
run "bundle add browser"
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
def copy_files
|
|
@@ -50,11 +50,13 @@ class HotwireNativeGenerator < Rails::Generators::Base
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def add_css_variants
|
|
53
|
-
return
|
|
53
|
+
return add_tailwind_3_css_variants if tailwind3?
|
|
54
|
+
return add_tailwind_4_css_variants if tailwind4?
|
|
54
55
|
|
|
55
56
|
add_hotwire_native_css
|
|
56
57
|
end
|
|
57
58
|
|
|
59
|
+
# todo: set it only if tailwindcss
|
|
58
60
|
def add_platform_identifier
|
|
59
61
|
gsub_file "app/views/layouts/application.html.erb", "<html>", "<html <%= platform_identifier %>>"
|
|
60
62
|
end
|
|
@@ -73,13 +75,17 @@ class HotwireNativeGenerator < Rails::Generators::Base
|
|
|
73
75
|
Rails.root.join("package.json").exist?
|
|
74
76
|
end
|
|
75
77
|
|
|
76
|
-
def
|
|
78
|
+
def tailwind3?
|
|
77
79
|
Rails.root.join("config/tailwind.config.js").exist?
|
|
78
80
|
end
|
|
79
81
|
|
|
82
|
+
def tailwind4?
|
|
83
|
+
Rails.root.join("app/assets/tailwind/application.css").exist?
|
|
84
|
+
end
|
|
85
|
+
|
|
80
86
|
# class="hotwire-native:hidden"
|
|
81
87
|
# class="non-hotwire-native:hidden"
|
|
82
|
-
def
|
|
88
|
+
def add_tailwind_3_css_variants
|
|
83
89
|
prepend_to_file "config/tailwind.config.js", "const plugin = require('tailwindcss/plugin')\n"
|
|
84
90
|
|
|
85
91
|
inject_into_file "config/tailwind.config.js", after: "plugins: [" do
|
|
@@ -93,9 +99,27 @@ class HotwireNativeGenerator < Rails::Generators::Base
|
|
|
93
99
|
end
|
|
94
100
|
end
|
|
95
101
|
|
|
102
|
+
def add_tailwind_4_css_variants
|
|
103
|
+
inject_into_file "app/assets/tailwind/application.css", after: /@import ["']tailwindcss["'];\n/ do
|
|
104
|
+
<<-CSS
|
|
105
|
+
@custom-variant hotwire-native {
|
|
106
|
+
html[data-hotwire-native] & {
|
|
107
|
+
@slot;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@custom-variant non-hotwire-native {
|
|
112
|
+
html:not([data-hotwire-native]) & {
|
|
113
|
+
@slot;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
CSS
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
96
120
|
# class="hotwire-native:hidden"
|
|
97
121
|
def add_hotwire_native_css
|
|
98
|
-
gsub_file "app/views/layouts/application.html.erb", "<body>", "<body class=\"<%= \"hotwire-native\" if
|
|
122
|
+
gsub_file "app/views/layouts/application.html.erb", "<body>", "<body class=\"<%= \"hotwire-native\" if hotwire_native_app? %>\">"
|
|
99
123
|
|
|
100
124
|
append_to_file "app/assets/stylesheets/application.css" do
|
|
101
125
|
<<-CSS
|
|
@@ -8,6 +8,8 @@ module DeviceFormat
|
|
|
8
8
|
private
|
|
9
9
|
|
|
10
10
|
def set_variant
|
|
11
|
-
request.variant = :mobile if
|
|
11
|
+
# request.variant = :mobile if hotwire_native_app? || browser.device.mobile?
|
|
12
|
+
# request.variant = :mobile if browser.device.mobile?
|
|
13
|
+
request.variant = :native if hotwire_native_app?
|
|
12
14
|
end
|
|
13
15
|
end
|
|
@@ -9,41 +9,68 @@ module HotwireNativeHelper
|
|
|
9
9
|
# <% content_for :hotwire_native_title, "Sign in" %>
|
|
10
10
|
# <% content_for :title, "Sign in | My App" %>
|
|
11
11
|
def page_title
|
|
12
|
-
|
|
13
|
-
content_for(:hotwire_native_title)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
title_options = [
|
|
13
|
+
(content_for(:hotwire_native_title) if hotwire_native_app?),
|
|
14
|
+
content_for(:title),
|
|
15
|
+
@page_title,
|
|
16
|
+
Rails.application.class.module_parent.name
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
title_options.compact.first
|
|
17
20
|
end
|
|
18
21
|
|
|
19
22
|
# forbid zooming on mobile devices
|
|
20
23
|
def viewport_meta_tag
|
|
21
24
|
content = ['width=device-width,initial-scale=1']
|
|
22
|
-
content << 'maximum-scale=1, user-scalable=0' if
|
|
25
|
+
content << 'maximum-scale=1, user-scalable=0' if hotwire_native_app? || browser.device.mobile?
|
|
23
26
|
tag.meta(name: 'viewport', content: content.join(','))
|
|
24
27
|
end
|
|
25
28
|
|
|
26
29
|
# set on <html> tag
|
|
27
30
|
def platform_identifier
|
|
28
|
-
'data-hotwire-native' if
|
|
31
|
+
'data-hotwire-native' if hotwire_native_app?
|
|
29
32
|
end
|
|
30
33
|
|
|
31
34
|
# link_to 'Next', next_path, data: { turbo_action: replace_if_native }
|
|
32
35
|
# https://turbo.hotwired.dev/handbook/drive#application-visits
|
|
36
|
+
# caution: if you open a modal on top of the root page, and replace, it will replace the root page.
|
|
37
|
+
# projects#show will replace projects#index => BAD
|
|
33
38
|
def replace_if_native
|
|
34
|
-
return 'replace' if
|
|
39
|
+
return 'replace' if hotwire_native_app?
|
|
35
40
|
|
|
36
41
|
'advance'
|
|
37
42
|
end
|
|
38
43
|
|
|
39
|
-
#
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
# In the native app, drop target="_blank" from links to your own host, so they
|
|
45
|
+
# open in the app instead of the in-app browser. External links keep it.
|
|
46
|
+
# Handles both forms:
|
|
47
|
+
# link_to "Home", root_path, target: "_blank"
|
|
48
|
+
# link_to root_path, target: "_blank" do ... end
|
|
49
|
+
# (with a block, the URL and HTML options arrive one argument earlier).
|
|
50
|
+
# The caller's options hash is copied, never modified.
|
|
51
|
+
def link_to(name = nil, options = nil, html_options = nil, &block)
|
|
52
|
+
if hotwire_native_app?
|
|
53
|
+
url, attributes = block ? [name, options] : [options, html_options]
|
|
54
|
+
|
|
55
|
+
if url && attributes.is_a?(Hash) && internal_url?(url_for(url))
|
|
56
|
+
attributes = attributes.except(:target, 'target')
|
|
57
|
+
if block
|
|
58
|
+
options = attributes
|
|
59
|
+
else
|
|
60
|
+
html_options = attributes
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
super(name, options, html_options, &block)
|
|
43
66
|
end
|
|
44
67
|
|
|
45
68
|
# https://github.com/joemasilotti/daily-log/blob/main/rails/app/helpers/form_helper.rb
|
|
46
69
|
class BridgeFormBuilder < ActionView::Helpers::FormBuilder
|
|
70
|
+
# CAUTION: the submit button has to have a title
|
|
71
|
+
# BAD: f.submit
|
|
72
|
+
# GOOD: f.submit "Save"
|
|
73
|
+
# GOOD: f.submit t('.save')
|
|
47
74
|
def submit(value = nil, options = {})
|
|
48
75
|
options[:data] ||= {}
|
|
49
76
|
options['data-bridge--form-target'] = 'submit'
|
|
@@ -52,10 +79,8 @@ module HotwireNativeHelper
|
|
|
52
79
|
end
|
|
53
80
|
end
|
|
54
81
|
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
# GOOD: f.submit "Save"
|
|
58
|
-
# GOOD: f.submit t('.save')
|
|
82
|
+
# add additional attributes in html options:
|
|
83
|
+
# <%= bridge_form_with(model: project, html: { data: { turbo_action: "advance" } }) do |form| %>
|
|
59
84
|
def bridge_form_with(*, **options, &)
|
|
60
85
|
options[:html] ||= {}
|
|
61
86
|
options[:html][:data] ||= {}
|
|
@@ -75,11 +100,14 @@ module HotwireNativeHelper
|
|
|
75
100
|
}
|
|
76
101
|
end
|
|
77
102
|
|
|
103
|
+
# A relative path, or an http(s) URL on the current host.
|
|
104
|
+
# mailto:, tel: and other schemes are never internal.
|
|
78
105
|
def internal_url?(url)
|
|
79
106
|
uri = URI.parse(url)
|
|
80
|
-
return
|
|
81
|
-
return true if url.include?(root_url)
|
|
107
|
+
return false if uri.scheme.present? && !uri.scheme.match?(/\Ahttps?\z/)
|
|
82
108
|
|
|
109
|
+
uri.host.blank? || uri.host == request.host
|
|
110
|
+
rescue URI::InvalidURIError
|
|
83
111
|
false
|
|
84
112
|
end
|
|
85
113
|
end
|
data/lib/generators/hotwire_native/templates/javascript/controllers/bridge/menu_controller.js
CHANGED
|
@@ -2,7 +2,6 @@ import { BridgeComponent } from "@hotwired/hotwire-native-bridge"
|
|
|
2
2
|
import { BridgeElement } from "@hotwired/hotwire-native-bridge"
|
|
3
3
|
// aka Action Sheet
|
|
4
4
|
// open a menu by clicking an HTML element
|
|
5
|
-
// Question - can I have multiple menus on the same page?
|
|
6
5
|
|
|
7
6
|
// Source:
|
|
8
7
|
// https://github.com/hotwired/hotwire-native-demo/blob/main/public/javascript/controllers/bridge/menu_controller.js
|
data/lib/generators/hotwire_native/templates/javascript/controllers/bridge/nav_controller.js
CHANGED
|
@@ -5,9 +5,11 @@ import { BridgeComponent, BridgeElement } from "@hotwired/hotwire-native-bridge"
|
|
|
5
5
|
// https://blog.corsego.com/hotwire-native-ui-menu-dropdown
|
|
6
6
|
|
|
7
7
|
// Example:
|
|
8
|
-
//
|
|
9
|
-
// <%=
|
|
10
|
-
//
|
|
8
|
+
// <% if user_signed_in? %>
|
|
9
|
+
// <%= tag.div data: { controller: 'bridge--nav', bridge_side: 'left', bridge_image: 'person.circle' } do %>
|
|
10
|
+
// <%= link_to "Edit profile", edit_user_registration_path, data: { bridge__nav_target: 'item', bridge_image: 'person.circle' } %>
|
|
11
|
+
// <%= link_to "Sign out", destroy_user_session_path, data: { bridge__nav_target: 'item', bridge_image: 'power.circle', turbo_method: :delete } %>
|
|
12
|
+
// <% end %>
|
|
11
13
|
// <% end %>
|
|
12
14
|
export default class extends BridgeComponent {
|
|
13
15
|
static component = "nav"
|
|
@@ -7,8 +7,8 @@ class HotwireNativeHelperTest < ActionView::TestCase
|
|
|
7
7
|
end
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
test 'link_to removes target for internal links in
|
|
11
|
-
def
|
|
10
|
+
test 'link_to removes target for internal links in hotwire native app' do
|
|
11
|
+
def hotwire_native_app?
|
|
12
12
|
true
|
|
13
13
|
end
|
|
14
14
|
|
|
@@ -16,8 +16,8 @@ class HotwireNativeHelperTest < ActionView::TestCase
|
|
|
16
16
|
assert_no_match(/target="_blank"/, result)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
test 'link_to keeps target for external links in
|
|
20
|
-
def
|
|
19
|
+
test 'link_to keeps target for external links in hotwire native app' do
|
|
20
|
+
def hotwire_native_app?
|
|
21
21
|
true
|
|
22
22
|
end
|
|
23
23
|
|
|
@@ -25,8 +25,8 @@ class HotwireNativeHelperTest < ActionView::TestCase
|
|
|
25
25
|
assert_match(/target="_blank"/, result)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
test 'link_to keeps target for internal links when not in
|
|
29
|
-
def
|
|
28
|
+
test 'link_to keeps target for internal links when not in hotwire native app' do
|
|
29
|
+
def hotwire_native_app?
|
|
30
30
|
false
|
|
31
31
|
end
|
|
32
32
|
|
|
@@ -34,8 +34,8 @@ class HotwireNativeHelperTest < ActionView::TestCase
|
|
|
34
34
|
assert_match(/target="_blank"/, result)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
test 'link_to keeps target for external links when not in
|
|
38
|
-
def
|
|
37
|
+
test 'link_to keeps target for external links when not in hotwire native app' do
|
|
38
|
+
def hotwire_native_app?
|
|
39
39
|
false
|
|
40
40
|
end
|
|
41
41
|
|
|
@@ -43,11 +43,42 @@ class HotwireNativeHelperTest < ActionView::TestCase
|
|
|
43
43
|
assert_match(/target="_blank"/, result)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
+
test 'link_to with a block removes target for internal links in hotwire native app' do
|
|
47
|
+
def hotwire_native_app?
|
|
48
|
+
true
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
result = link_to('/foo/bar', target: '_blank') { 'Home' }
|
|
52
|
+
assert_no_match(/target=/, result)
|
|
53
|
+
assert_match(%r{href="/foo/bar"}, result)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
test 'link_to with a block keeps target for external links in hotwire native app' do
|
|
57
|
+
def hotwire_native_app?
|
|
58
|
+
true
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
result = link_to('http://external.com', target: '_blank') { 'External' }
|
|
62
|
+
assert_match(/target="_blank"/, result)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
test 'link_to does not modify the html options passed in' do
|
|
66
|
+
def hotwire_native_app?
|
|
67
|
+
true
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
html_options = { target: '_blank' }
|
|
71
|
+
link_to('Home', '/foo/bar', html_options)
|
|
72
|
+
assert_equal({ target: '_blank' }, html_options)
|
|
73
|
+
end
|
|
74
|
+
|
|
46
75
|
test 'internal_url? returns true for internal links' do
|
|
47
76
|
assert internal_url?('http://test.host/some_path')
|
|
77
|
+
assert internal_url?('/some_path')
|
|
48
78
|
end
|
|
49
79
|
|
|
50
80
|
test 'internal_url? returns false for external links' do
|
|
51
81
|
assert_not internal_url?('http://external.com')
|
|
82
|
+
assert_not internal_url?('mailto:hello@test.host')
|
|
52
83
|
end
|
|
53
84
|
end
|
metadata
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hotwire_native_rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yaro Shm
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
12
|
-
dependencies:
|
|
13
|
-
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: turbo-rails
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: 2.0.11
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: 2.0.11
|
|
14
26
|
email:
|
|
15
27
|
- yshmarov@gmail.com
|
|
16
28
|
executables: []
|
|
@@ -26,6 +38,7 @@ files:
|
|
|
26
38
|
- LICENSE.txt
|
|
27
39
|
- README.md
|
|
28
40
|
- Rakefile
|
|
41
|
+
- bin/smoke
|
|
29
42
|
- hotwire_native_rails.gemspec
|
|
30
43
|
- lib/generators/hotwire_native/hotwire_native_generator.rb
|
|
31
44
|
- lib/generators/hotwire_native/templates/controllers/concerns/device_format.rb
|
|
@@ -52,7 +65,6 @@ metadata:
|
|
|
52
65
|
homepage_uri: https://github.com/yshmarov/hotwire_native_rails
|
|
53
66
|
source_code_uri: https://github.com/yshmarov/hotwire_native_rails
|
|
54
67
|
changelog_uri: https://github.com/yshmarov/hotwire_native_rails/blob/main/CHANGELOG.md
|
|
55
|
-
post_install_message:
|
|
56
68
|
rdoc_options: []
|
|
57
69
|
require_paths:
|
|
58
70
|
- lib
|
|
@@ -60,15 +72,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
60
72
|
requirements:
|
|
61
73
|
- - ">="
|
|
62
74
|
- !ruby/object:Gem::Version
|
|
63
|
-
version: '
|
|
75
|
+
version: '3.1'
|
|
64
76
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
65
77
|
requirements:
|
|
66
78
|
- - ">="
|
|
67
79
|
- !ruby/object:Gem::Version
|
|
68
80
|
version: '0'
|
|
69
81
|
requirements: []
|
|
70
|
-
rubygems_version:
|
|
71
|
-
signing_key:
|
|
82
|
+
rubygems_version: 4.0.20
|
|
72
83
|
specification_version: 4
|
|
73
84
|
summary: Generate Hotwire Native Rails helpers and bridge components
|
|
74
85
|
test_files: []
|