ruby_native 0.0.5 → 0.1.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/README.md +80 -8
- data/app/assets/stylesheets/ruby_native.css +11 -0
- data/app/javascript/ruby_native/back.js +3 -0
- data/app/javascript/ruby_native/bridge/button_controller.js +30 -0
- data/app/javascript/ruby_native/bridge/form_controller.js +27 -0
- data/app/javascript/ruby_native/bridge/index.js +14 -0
- data/app/javascript/ruby_native/bridge/menu_controller.js +22 -0
- data/app/javascript/ruby_native/bridge/push_controller.js +10 -0
- data/app/javascript/ruby_native/bridge/search_controller.js +16 -0
- data/app/javascript/ruby_native/bridge/tabs_controller.js +11 -0
- data/config/importmap.rb +2 -0
- data/lib/generators/ruby_native/install_generator.rb +1 -1
- data/lib/generators/ruby_native/templates/CLAUDE.md +6 -8
- data/lib/ruby_native/cli/preview.rb +4 -4
- data/lib/ruby_native/engine.rb +10 -1
- data/lib/ruby_native/helper.rb +66 -3
- data/lib/ruby_native/version.rb +1 -1
- metadata +10 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d6157407a95aecdb39c9f05de070e3268e6d0910162fcd3b50e54b75f52f4093
|
|
4
|
+
data.tar.gz: 66c9cc2caa92638cbb52f56cae855c16ffd956de4ad1e8db843e990a7197cc90
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1a510f3343561161004f5a4104a28c79846f224e4d30335fcd33617d18f57c35179aedced255e9876fdb704c6cdd7e5b26727614dbda9bb0e5c95470fbd029a5
|
|
7
|
+
data.tar.gz: 0a177fca9a18e66d623c18a97412e4ccc923ca3f97c750f90c246f6f7eb4c7124bd279a41fa6a91f3c3e627deabf7b83584ad74f5fc731a0703311c5042b8451
|
data/README.md
CHANGED
|
@@ -23,7 +23,7 @@ This creates `config/ruby_native.yml` with sensible defaults. If you have a `.cl
|
|
|
23
23
|
1. Edit the config with your app name, colors, and tabs
|
|
24
24
|
2. Add `<%= stylesheet_link_tag :ruby_native %>` to your layout `<head>`
|
|
25
25
|
3. Add `<%= native_tabs_tag %>` to your layout `<body>`
|
|
26
|
-
4. Run `ruby_native preview` to see it on your phone
|
|
26
|
+
4. Run `bundle exec ruby_native preview` to see it on your phone
|
|
27
27
|
|
|
28
28
|
Using Claude Code? Open it in your project and ask "what do I need to do next?" for guided setup.
|
|
29
29
|
|
|
@@ -32,8 +32,6 @@ Using Claude Code? Open it in your project and ask "what do I need to do next?"
|
|
|
32
32
|
Edit `config/ruby_native.yml`:
|
|
33
33
|
|
|
34
34
|
```yaml
|
|
35
|
-
app:
|
|
36
|
-
name: My App
|
|
37
35
|
appearance:
|
|
38
36
|
tint_color: "#4F46E5"
|
|
39
37
|
background_color: "#FFFFFF"
|
|
@@ -60,7 +58,7 @@ background_color:
|
|
|
60
58
|
Preview your app on a real device without deploying. This starts a Cloudflare tunnel and displays a QR code for the companion app to scan.
|
|
61
59
|
|
|
62
60
|
```bash
|
|
63
|
-
ruby_native preview
|
|
61
|
+
bundle exec ruby_native preview
|
|
64
62
|
```
|
|
65
63
|
|
|
66
64
|
Options:
|
|
@@ -80,14 +78,88 @@ The companion app persists the scanned URL across launches. Long-press the app i
|
|
|
80
78
|
- `GET /native/config` - returns the YAML config as JSON
|
|
81
79
|
- `POST /native/push/devices` - registers a push notification token (requires `current_user` from host app)
|
|
82
80
|
|
|
81
|
+
## Standard and Advanced Modes
|
|
82
|
+
|
|
83
|
+
Standard Mode works with any frontend framework and requires no JavaScript. You get tabs, form page marking, push notifications, and history management.
|
|
84
|
+
|
|
85
|
+
Advanced Mode adds native navigation bar buttons, submit buttons, action menus, and search bars. It requires Stimulus and a small JavaScript setup step (see [Advanced Mode setup](#advanced-mode-setup) below). Migration is additive. Start with Standard and add Advanced helpers one page at a time.
|
|
86
|
+
|
|
83
87
|
## View helpers
|
|
84
88
|
|
|
89
|
+
Place helpers in the `<body>`, not the `<head>`.
|
|
90
|
+
|
|
91
|
+
### Any mode
|
|
92
|
+
|
|
85
93
|
- `native_app?` - true when the request comes from a Ruby Native app (checks user agent)
|
|
86
|
-
- `native_tabs_tag` -
|
|
87
|
-
- `
|
|
88
|
-
- `
|
|
94
|
+
- `native_tabs_tag(enabled: true)` - shows the native tab bar.
|
|
95
|
+
- `native_push_tag` - requests push notification permission.
|
|
96
|
+
- `native_back_button_tag(text = nil, **options)` - renders a back button for Standard Mode. Hidden by default, shown when the native app sets `body.can-go-back`. Not needed in [Advanced Mode](https://rubynative.dev/docs/advanced-mode) where the system provides a native back button.
|
|
97
|
+
|
|
98
|
+
### Standard Mode
|
|
99
|
+
|
|
100
|
+
- `native_form_tag` - marks the page as a form. The app skips form pages when navigating back.
|
|
101
|
+
|
|
102
|
+
### Advanced Mode
|
|
103
|
+
|
|
104
|
+
These require the JavaScript setup described in [Advanced Mode setup](#advanced-mode-setup).
|
|
105
|
+
|
|
106
|
+
- `native_form_data` - returns the data hash for the native form submit button. Pass to `form_with`'s `data:` option.
|
|
107
|
+
- `native_submit_data` - returns the data hash for the native submit target. Pass to `form.submit`'s `data:` option.
|
|
108
|
+
- `native_button_tag(title, url, ios_image:, side: :right, **options)` - adds a native navigation bar button.
|
|
109
|
+
- `native_menu_tag(title:, side: :right, &block)` - displays a native action sheet menu.
|
|
110
|
+
- `native_search_tag` - adds a native search bar.
|
|
111
|
+
|
|
112
|
+
## Advanced Mode setup
|
|
113
|
+
|
|
114
|
+
1. Install the JavaScript dependency:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
yarn add @hotwired/hotwire-native-bridge
|
|
118
|
+
# or
|
|
119
|
+
bin/importmap pin @hotwired/hotwire-native-bridge
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
2. Import the controllers in your JavaScript entrypoint:
|
|
123
|
+
|
|
124
|
+
```js
|
|
125
|
+
import "ruby_native/bridge"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### `native_form_data` / `native_submit_data`
|
|
129
|
+
|
|
130
|
+
```erb
|
|
131
|
+
<%= form_with model: @link, data: native_form_data do |f| %>
|
|
132
|
+
<%= f.text_field :url %>
|
|
133
|
+
<%= f.submit "Save", data: native_submit_data %>
|
|
134
|
+
<% end %>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### `native_button_tag`
|
|
138
|
+
|
|
139
|
+
```erb
|
|
140
|
+
<%= native_button_tag "Add a link", new_link_path, ios_image: "plus", class: "btn btn-primary" %>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Options:
|
|
144
|
+
- `ios_image:` - SF Symbol icon name (falls back to the title text)
|
|
145
|
+
- `side:` - `:left` or `:right` (default). Left supplements the back button.
|
|
146
|
+
|
|
147
|
+
### `native_menu_tag`
|
|
148
|
+
|
|
149
|
+
```erb
|
|
150
|
+
<%= native_menu_tag(title: "Actions") do |menu| %>
|
|
151
|
+
<%= menu.item "Edit", edit_link_path(@link) %>
|
|
152
|
+
<%= menu.item "Delete", link_path(@link), method: :delete, destructive: true %>
|
|
153
|
+
<% end %>
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Options on `native_menu_tag`:
|
|
157
|
+
- `title:` - action sheet title
|
|
158
|
+
- `side:` - `:left` or `:right` (default)
|
|
89
159
|
|
|
90
|
-
|
|
160
|
+
Options on `menu.item`:
|
|
161
|
+
- `method:` - Turbo method (e.g., `:delete`)
|
|
162
|
+
- `destructive: true` - red styling
|
|
91
163
|
|
|
92
164
|
## Stylesheet
|
|
93
165
|
|
|
@@ -5,3 +5,14 @@
|
|
|
5
5
|
body.can-go-back .native-back-button {
|
|
6
6
|
display: inline;
|
|
7
7
|
}
|
|
8
|
+
|
|
9
|
+
[data-bridge-components~="form"]
|
|
10
|
+
[data-controller~="bridge--form"]
|
|
11
|
+
[type="submit"] {
|
|
12
|
+
display: none;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
[data-bridge-components~="button"]
|
|
16
|
+
[data-controller~="bridge--button"] {
|
|
17
|
+
display: none;
|
|
18
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { BridgeComponent } from "@hotwired/hotwire-native-bridge"
|
|
2
|
+
|
|
3
|
+
export default class extends BridgeComponent {
|
|
4
|
+
static component = "button"
|
|
5
|
+
|
|
6
|
+
connect() {
|
|
7
|
+
super.connect()
|
|
8
|
+
this.#addButton()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
disconnect() {
|
|
12
|
+
super.disconnect()
|
|
13
|
+
this.#removeButton()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
#addButton() {
|
|
17
|
+
const element = this.bridgeElement
|
|
18
|
+
const side = element.bridgeAttribute("side") || "right"
|
|
19
|
+
const image = element.bridgeAttribute("ios-image")
|
|
20
|
+
const data = { title: element.title, image }
|
|
21
|
+
|
|
22
|
+
this.send(side, data, () => {
|
|
23
|
+
this.element.click()
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
#removeButton() {
|
|
28
|
+
this.send("disconnect")
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { BridgeComponent, BridgeElement } from "@hotwired/hotwire-native-bridge"
|
|
2
|
+
|
|
3
|
+
export default class extends BridgeComponent {
|
|
4
|
+
static component = "form"
|
|
5
|
+
static targets = ["submit"]
|
|
6
|
+
|
|
7
|
+
connect() {
|
|
8
|
+
super.connect()
|
|
9
|
+
|
|
10
|
+
const title = new BridgeElement(this.submitTarget).title
|
|
11
|
+
this.send("connect", { submitTitle: title.trim() }, () => {
|
|
12
|
+
this.submitTarget.click()
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
this.element.addEventListener("turbo:submit-start", this.submitStarted)
|
|
16
|
+
this.element.addEventListener("turbo:submit-end", this.submitEnded)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
disconnect() {
|
|
20
|
+
super.disconnect()
|
|
21
|
+
this.element.removeEventListener("turbo:submit-start", this.submitStarted)
|
|
22
|
+
this.element.removeEventListener("turbo:submit-end", this.submitEnded)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
submitStarted = () => this.send("submitDisabled")
|
|
26
|
+
submitEnded = () => this.send("submitEnabled")
|
|
27
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { application } from "controllers/application"
|
|
2
|
+
import TabsController from "ruby_native/bridge/tabs_controller"
|
|
3
|
+
import FormController from "ruby_native/bridge/form_controller"
|
|
4
|
+
import PushController from "ruby_native/bridge/push_controller"
|
|
5
|
+
import MenuController from "ruby_native/bridge/menu_controller"
|
|
6
|
+
import SearchController from "ruby_native/bridge/search_controller"
|
|
7
|
+
import ButtonController from "ruby_native/bridge/button_controller"
|
|
8
|
+
|
|
9
|
+
application.register("bridge--tabs", TabsController)
|
|
10
|
+
application.register("bridge--form", FormController)
|
|
11
|
+
application.register("bridge--push", PushController)
|
|
12
|
+
application.register("bridge--menu", MenuController)
|
|
13
|
+
application.register("bridge--search", SearchController)
|
|
14
|
+
application.register("bridge--button", ButtonController)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BridgeComponent, BridgeElement } from "@hotwired/hotwire-native-bridge"
|
|
2
|
+
|
|
3
|
+
export default class extends BridgeComponent {
|
|
4
|
+
static component = "menu"
|
|
5
|
+
static targets = ["item"]
|
|
6
|
+
static values = { title: String, side: { type: String, default: "right" } }
|
|
7
|
+
|
|
8
|
+
connect() {
|
|
9
|
+
super.connect()
|
|
10
|
+
|
|
11
|
+
const items = this.itemTargets.map((el, index) => ({
|
|
12
|
+
title: new BridgeElement(el).title,
|
|
13
|
+
index,
|
|
14
|
+
destructive: el.hasAttribute("data-destructive")
|
|
15
|
+
}))
|
|
16
|
+
|
|
17
|
+
this.send("connect", { title: this.titleValue, items, side: this.sideValue }, (message) => {
|
|
18
|
+
const { selectedIndex } = message.data
|
|
19
|
+
this.itemTargets[selectedIndex]?.click()
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BridgeComponent } from "@hotwired/hotwire-native-bridge"
|
|
2
|
+
|
|
3
|
+
export default class extends BridgeComponent {
|
|
4
|
+
static component = "search"
|
|
5
|
+
|
|
6
|
+
connect() {
|
|
7
|
+
super.connect()
|
|
8
|
+
|
|
9
|
+
this.send("connect", {}, (message) => {
|
|
10
|
+
const query = message.data.query
|
|
11
|
+
const detail = {query}
|
|
12
|
+
|
|
13
|
+
this.dispatch("queried", {detail})
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BridgeComponent } from "@hotwired/hotwire-native-bridge"
|
|
2
|
+
|
|
3
|
+
export default class extends BridgeComponent {
|
|
4
|
+
static component = "tabs"
|
|
5
|
+
static values = { enabled: Boolean }
|
|
6
|
+
|
|
7
|
+
connect() {
|
|
8
|
+
super.connect()
|
|
9
|
+
this.send("connect", { enabled: this.enabledValue })
|
|
10
|
+
}
|
|
11
|
+
}
|
data/config/importmap.rb
ADDED
|
@@ -35,7 +35,7 @@ module RubyNative
|
|
|
35
35
|
say " 3. Add to your layout <body>:"
|
|
36
36
|
say " <%= native_tabs_tag %>"
|
|
37
37
|
say " 4. Preview on your device:"
|
|
38
|
-
say " ruby_native preview"
|
|
38
|
+
say " bundle exec ruby_native preview"
|
|
39
39
|
say ""
|
|
40
40
|
if File.directory?(File.join(destination_root, ".claude"))
|
|
41
41
|
say " Tip: .claude/ruby_native.md was added with setup instructions."
|
|
@@ -33,7 +33,7 @@ rails generate ruby_native:install
|
|
|
33
33
|
6. Preview on your phone:
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
|
-
ruby_native preview
|
|
36
|
+
bundle exec ruby_native preview
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
Scan the QR code with the Ruby Native Preview app from the App Store.
|
|
@@ -100,7 +100,7 @@ Signal elements are hidden `<div>` tags. Place them in the `<body>`, not the `<h
|
|
|
100
100
|
|
|
101
101
|
## Preview
|
|
102
102
|
|
|
103
|
-
`ruby_native preview` starts a Cloudflare tunnel and displays a QR code. Requires `cloudflared`:
|
|
103
|
+
`bundle exec ruby_native preview` starts a Cloudflare tunnel and displays a QR code. Requires `cloudflared`:
|
|
104
104
|
|
|
105
105
|
```bash
|
|
106
106
|
brew install cloudflare/cloudflare/cloudflared
|
|
@@ -122,7 +122,7 @@ The Preview app remembers the scanned URL. Long-press the app icon and tap "Swit
|
|
|
122
122
|
|
|
123
123
|
The gem auto-mounts at `/native`. No route configuration needed.
|
|
124
124
|
|
|
125
|
-
- `GET /native/config
|
|
125
|
+
- `GET /native/config` returns the YAML config as JSON
|
|
126
126
|
- `POST /native/push/devices` registers a push notification device token
|
|
127
127
|
|
|
128
128
|
## Common tasks
|
|
@@ -139,16 +139,14 @@ The gem auto-mounts at `/native`. No route configuration needed.
|
|
|
139
139
|
<%= native_tabs_tag if user_signed_in? %>
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
-
### Add a native back button
|
|
142
|
+
### Add a native back button (Standard Mode only)
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
Use the `native_back_button_tag` helper. The gem's stylesheet handles showing it only when there's history to go back to. Not needed in Advanced Mode where the system provides a native back button.
|
|
145
145
|
|
|
146
146
|
```erb
|
|
147
147
|
<%= stylesheet_link_tag :ruby_native %>
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
```erb
|
|
151
|
-
|
|
152
|
-
Back
|
|
153
|
-
</button>
|
|
151
|
+
<%= native_back_button_tag %>
|
|
154
152
|
```
|
|
@@ -5,10 +5,10 @@ module RubyNative
|
|
|
5
5
|
class Preview
|
|
6
6
|
TUNNEL_URL_PATTERN = %r{https://[a-z0-9-]+\.trycloudflare\.com}
|
|
7
7
|
|
|
8
|
-
BLACK_BG = "\033[
|
|
9
|
-
WHITE_BG = "\033[
|
|
10
|
-
BLACK_FG = "\033[
|
|
11
|
-
WHITE_FG = "\033[
|
|
8
|
+
BLACK_BG = "\033[40m"
|
|
9
|
+
WHITE_BG = "\033[107m"
|
|
10
|
+
BLACK_FG = "\033[30m"
|
|
11
|
+
WHITE_FG = "\033[97m"
|
|
12
12
|
RESET = "\033[0m"
|
|
13
13
|
|
|
14
14
|
def initialize(argv)
|
data/lib/ruby_native/engine.rb
CHANGED
|
@@ -10,7 +10,16 @@ module RubyNative
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
initializer "ruby_native.assets" do |app|
|
|
13
|
-
|
|
13
|
+
if app.config.respond_to?(:assets)
|
|
14
|
+
app.config.assets.paths << root.join("app/assets/stylesheets")
|
|
15
|
+
app.config.assets.paths << root.join("app/javascript")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
initializer "ruby_native.importmap", before: "importmap" do |app|
|
|
20
|
+
if app.config.respond_to?(:importmap)
|
|
21
|
+
app.config.importmap.paths << root.join("config/importmap.rb")
|
|
22
|
+
end
|
|
14
23
|
end
|
|
15
24
|
|
|
16
25
|
initializer "ruby_native.config" do
|
data/lib/ruby_native/helper.rb
CHANGED
|
@@ -4,16 +4,79 @@ module RubyNative
|
|
|
4
4
|
request.user_agent.to_s.include?("Ruby Native")
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
-
def native_tabs_tag
|
|
8
|
-
|
|
7
|
+
def native_tabs_tag(enabled: true)
|
|
8
|
+
safe_join([
|
|
9
|
+
(tag.div(data: { native_tabs: true }, hidden: true) if enabled),
|
|
10
|
+
tag.div(data: { controller: "bridge--tabs", bridge__tabs_enabled_value: enabled })
|
|
11
|
+
].compact)
|
|
9
12
|
end
|
|
10
13
|
|
|
11
14
|
def native_form_tag
|
|
12
15
|
tag.div(data: { native_form: true }, hidden: true)
|
|
13
16
|
end
|
|
14
17
|
|
|
18
|
+
def native_form_data
|
|
19
|
+
{ controller: "bridge--form" }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def native_submit_data
|
|
23
|
+
{ bridge__form_target: "submit" }
|
|
24
|
+
end
|
|
25
|
+
|
|
15
26
|
def native_push_tag
|
|
16
|
-
|
|
27
|
+
safe_join([
|
|
28
|
+
tag.div(data: { native_push: true }, hidden: true),
|
|
29
|
+
tag.div(data: { controller: "bridge--push" })
|
|
30
|
+
])
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def native_back_button_tag(text = nil, **options)
|
|
34
|
+
options[:class] = [options[:class], "native-back-button"].compact.join(" ")
|
|
35
|
+
tag.button(text || "Back", onclick: "webkit.messageHandlers.rubyNative.postMessage({action: 'back'})", **options)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def native_search_tag
|
|
39
|
+
tag.div(data: { controller: "bridge--search" })
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def native_button_tag(title, url, ios_image: nil, side: :right, **options)
|
|
43
|
+
data = options.delete(:data) || {}
|
|
44
|
+
data[:controller] = "bridge--button"
|
|
45
|
+
data[:bridge_side] = side.to_s
|
|
46
|
+
data[:bridge_ios_image] = ios_image if ios_image
|
|
47
|
+
|
|
48
|
+
link_to title, url, **options, data: data
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def native_menu_tag(title:, side: :right, &block)
|
|
52
|
+
builder = MenuBuilder.new(self)
|
|
53
|
+
capture(builder, &block)
|
|
54
|
+
|
|
55
|
+
tag.div(style: "display:none", data: {
|
|
56
|
+
controller: "bridge--menu",
|
|
57
|
+
bridge__menu_title_value: title,
|
|
58
|
+
bridge__menu_side_value: side.to_s
|
|
59
|
+
}) { builder.to_html }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class MenuBuilder
|
|
63
|
+
def initialize(context)
|
|
64
|
+
@context = context
|
|
65
|
+
@items = []
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def item(title, url, method: nil, destructive: false, **options)
|
|
69
|
+
data = options.delete(:data) || {}
|
|
70
|
+
data[:bridge__menu_target] = "item"
|
|
71
|
+
data[:turbo_method] = method if method
|
|
72
|
+
data[:destructive] = "" if destructive
|
|
73
|
+
|
|
74
|
+
@items << @context.link_to(title, url, **options, data: data, hidden: true)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def to_html
|
|
78
|
+
@context.safe_join(@items)
|
|
79
|
+
end
|
|
17
80
|
end
|
|
18
81
|
end
|
|
19
82
|
end
|
data/lib/ruby_native/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby_native
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joe Masilotti
|
|
@@ -51,6 +51,15 @@ files:
|
|
|
51
51
|
- app/assets/stylesheets/ruby_native.css
|
|
52
52
|
- app/controllers/ruby_native/config_controller.rb
|
|
53
53
|
- app/controllers/ruby_native/push/devices_controller.rb
|
|
54
|
+
- app/javascript/ruby_native/back.js
|
|
55
|
+
- app/javascript/ruby_native/bridge/button_controller.js
|
|
56
|
+
- app/javascript/ruby_native/bridge/form_controller.js
|
|
57
|
+
- app/javascript/ruby_native/bridge/index.js
|
|
58
|
+
- app/javascript/ruby_native/bridge/menu_controller.js
|
|
59
|
+
- app/javascript/ruby_native/bridge/push_controller.js
|
|
60
|
+
- app/javascript/ruby_native/bridge/search_controller.js
|
|
61
|
+
- app/javascript/ruby_native/bridge/tabs_controller.js
|
|
62
|
+
- config/importmap.rb
|
|
54
63
|
- config/routes.rb
|
|
55
64
|
- exe/ruby_native
|
|
56
65
|
- lib/generators/ruby_native/install_generator.rb
|