ruflet_rails 0.0.12 → 0.0.14
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 +170 -60
- data/lib/generators/ruflet/install/install_generator.rb +3 -3
- data/lib/ruflet/rails/configuration.rb +13 -7
- data/lib/ruflet/rails/install_support.rb +19 -637
- data/lib/ruflet/rails/native_app/actions.rb +167 -0
- data/lib/ruflet/rails/native_app/customization.rb +118 -0
- data/lib/ruflet/rails/native_app/html_adapter.rb +248 -0
- data/lib/ruflet/rails/native_app/navigation.rb +645 -0
- data/lib/ruflet/rails/native_app/overlays.rb +222 -0
- data/lib/ruflet/rails/native_app/shell.rb +390 -0
- data/lib/ruflet/rails/native_app.rb +26 -222
- data/lib/ruflet/rails/protocol/web_app.rb +1 -1
- data/lib/ruflet/rails/railtie.rb +3 -15
- data/lib/ruflet/rails/view_helpers.rb +205 -0
- data/lib/ruflet/rails.rb +22 -55
- data/lib/ruflet/version.rb +1 -1
- data/lib/ruflet_rails.rb +0 -4
- metadata +16 -15
- data/lib/generators/ruflet/form/form_generator.rb +0 -55
- data/lib/generators/ruflet/scaffold/scaffold_generator.rb +0 -54
- data/lib/ruflet/rails/form_helpers.rb +0 -161
- data/lib/ruflet/rails/resource_component.rb +0 -371
- data/lib/ruflet/rails/route_stack.rb +0 -90
- data/lib/ruflet/rails/webview_app.rb +0 -54
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '097cfb74aac7af1e15b8bcb49135851595cbd7a1856eef1b4df39672c95ebab8'
|
|
4
|
+
data.tar.gz: 27d2e764c20535ebc41befd5672741500cb78387ee74f56ea284a60de9d8d721
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ad4c0ab96a6741c9ff4339590e854abf2e72648a0b10c85bdf371ff7aaaee005e394f5063eecf9395756e1d9260d021a4d6c54737a8ad6326e811e63dca9d75a
|
|
7
|
+
data.tar.gz: c5aa7b3df32bedad4122d379739e05f770b8caa359e3ac01b114a29ee9c89bc7c5a3ecd175857dc79eaccb737b33bcd007d977086061b9ad25c9187872a2f994
|
data/README.md
CHANGED
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
`ruflet_rails` is the Rails-first integration package for Ruflet.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
It mounts Ruby-driven Ruflet interfaces in a Rails application, makes Rails
|
|
6
|
+
views able to opt into native WebView chrome, and connects web, mobile, and
|
|
7
|
+
desktop clients to the same application entrypoint.
|
|
7
8
|
|
|
8
|
-
##
|
|
9
|
+
## Add The Gem
|
|
9
10
|
|
|
10
11
|
```ruby
|
|
11
12
|
# Gemfile
|
|
12
|
-
gem "ruflet_rails"
|
|
13
|
+
gem "ruflet_rails"
|
|
13
14
|
```
|
|
14
15
|
|
|
15
|
-
## Install
|
|
16
|
+
## Install Into Rails
|
|
16
17
|
|
|
17
18
|
```bash
|
|
18
19
|
bin/rails generate ruflet:install
|
|
@@ -23,27 +24,29 @@ bin/rails generate ruflet:install --web --desktop
|
|
|
23
24
|
|
|
24
25
|
This generator will:
|
|
25
26
|
- create `app/views/ruflet/main.rb`
|
|
26
|
-
- create `ruflet.
|
|
27
|
+
- create `config/initializers/ruflet.rb`
|
|
27
28
|
- add the Ruflet WebSocket route to `config/routes.rb`
|
|
28
29
|
- add a `/ruflet` web mount when `--web` is used
|
|
29
30
|
- download prebuilt clients from GitHub releases when `--web`, `--desktop`, or
|
|
30
31
|
`--client=web|desktop|all` is used
|
|
31
32
|
|
|
32
|
-
Generated `ruflet.
|
|
33
|
+
Generated `config/initializers/ruflet.rb`:
|
|
33
34
|
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
backend_url
|
|
35
|
+
```ruby
|
|
36
|
+
Ruflet::Rails.configure do |config|
|
|
37
|
+
config.app_name = "My App"
|
|
38
|
+
config.backend_url = ENV.fetch("RUFLET_BACKEND_URL", "http://localhost:3000")
|
|
38
39
|
|
|
39
|
-
services
|
|
40
|
+
config.services = []
|
|
40
41
|
|
|
41
|
-
assets
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
config.splash_screen = Rails.root.join("app/assets/images/splash.png")
|
|
43
|
+
config.icon_launcher = Rails.root.join("app/assets/images/icon.png")
|
|
44
|
+
end
|
|
44
45
|
```
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
At build time `ruflet_rails` serializes this Rails config into the Ruflet CLI
|
|
48
|
+
config shape, so the initializer remains the source of truth for app name,
|
|
49
|
+
backend URL, services, assets, and build colors.
|
|
47
50
|
|
|
48
51
|
## Web client
|
|
49
52
|
|
|
@@ -85,7 +88,7 @@ bundle exec rake ruflet:build[desktop]
|
|
|
85
88
|
```
|
|
86
89
|
|
|
87
90
|
Rails desktop builds are server-driven. The built desktop app connects back to the
|
|
88
|
-
Rails backend configured in `ruflet.
|
|
91
|
+
Rails backend configured in `config/initializers/ruflet.rb`; it does not package a self-contained
|
|
89
92
|
Ruby runtime.
|
|
90
93
|
|
|
91
94
|
Plain Rails dev server commands do not launch the desktop app. Request a desktop
|
|
@@ -117,76 +120,183 @@ bundle exec rake ruflet:install
|
|
|
117
120
|
bundle exec rake ruflet:install[DEVICE_ID]
|
|
118
121
|
```
|
|
119
122
|
|
|
120
|
-
##
|
|
123
|
+
## Native WebView shell
|
|
121
124
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
Beyond the server-driven UI, Ruflet can wrap an existing Rails HTML app in a
|
|
126
|
+
managed native WebView. This is an opt-in shell: calling
|
|
127
|
+
`Ruflet::Rails.native_app` wraps web pages in a native Ruflet shell whose body is
|
|
128
|
+
a WebView. Plain `Ruflet.run { |page| ... }` remains a normal Ruflet app with no
|
|
129
|
+
WebView wrapper or HTML adapter.
|
|
127
130
|
|
|
128
|
-
|
|
131
|
+
Native behavior is explicit from Rails views: ordinary links and Turbo visits
|
|
132
|
+
stay inside the WebView, while links annotated with `data-ruflet-*` can push
|
|
133
|
+
native screens, replace/root the stack, open a sheet, show a dialog, toast, or
|
|
134
|
+
promote page chrome.
|
|
129
135
|
|
|
130
136
|
```ruby
|
|
131
|
-
# app/views/ruflet/
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
137
|
+
# app/views/ruflet/main.rb
|
|
138
|
+
Ruflet.run do |page|
|
|
139
|
+
Ruflet::Rails.native_app(
|
|
140
|
+
page,
|
|
141
|
+
start_url: "https://myapp.com",
|
|
142
|
+
title: "My App", # opt into a native AppBar (tracks <title>)
|
|
143
|
+
loading: :shimmer # default; can be "Loading..." or false
|
|
144
|
+
)
|
|
136
145
|
end
|
|
137
146
|
```
|
|
138
147
|
|
|
139
|
-
|
|
148
|
+
### Crossing web and native from HTML
|
|
140
149
|
|
|
141
|
-
|
|
142
|
-
|
|
150
|
+
A tiny HTML adapter reads `data-ruflet-*` attributes from the rendered page and
|
|
151
|
+
sends those payloads back to Ruby. Ruby then builds the native AppBar, drawer,
|
|
152
|
+
tabs, dialogs, sheets, services, and navigation with normal Ruflet controls. The
|
|
153
|
+
page stays a normal page in a plain browser; the attributes only activate inside
|
|
154
|
+
the native shell. Keep using normal Rails helpers like `link_to`; add Ruflet data
|
|
155
|
+
attributes only where the native app should augment the web behavior.
|
|
156
|
+
|
|
157
|
+
**Navigation** — `action` is `push` (default), `root` (reset to a root screen,
|
|
158
|
+
tab-style), `replace`, `sheet`, or `back`:
|
|
159
|
+
|
|
160
|
+
```erb
|
|
161
|
+
<%= link_to "Messages", messages_path,
|
|
162
|
+
data: { ruflet_screen: { action: "push", title: "Messages" }.to_json } %>
|
|
163
|
+
|
|
164
|
+
<%= link_to "Sign in", new_session_path,
|
|
165
|
+
data: { ruflet_screen: { action: "push", title: "Sign in",
|
|
166
|
+
leading: { icon: "close", action: "back" } }.to_json } %>
|
|
167
|
+
|
|
168
|
+
<%= link_to "Sign in", new_session_path,
|
|
169
|
+
data: { ruflet_screen: { action: "sheet" }.to_json } %>
|
|
170
|
+
|
|
171
|
+
<a href="/dashboard" data-ruflet-screen='{"action":"root","title":"Dashboard"}'>Dashboard</a>
|
|
143
172
|
```
|
|
144
173
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
174
|
+
**Promote HTML chrome to native** — hide HTML header/nav elements and render
|
|
175
|
+
native AppBar, NavigationBar, NavigationDrawer, or desktop NavigationRail:
|
|
176
|
+
|
|
177
|
+
```erb
|
|
178
|
+
<%= tag.div hidden: true,
|
|
179
|
+
data: { ruflet_appbar: { title: "Sign in",
|
|
180
|
+
leading: { icon: "close", action: "back" } }.to_json } %>
|
|
181
|
+
|
|
182
|
+
<%= ruflet_appbar "Inbox", leading: { icon: "menu", action: "drawer" } do %>
|
|
183
|
+
<%= ruflet_appbar_action "search", search_path %>
|
|
184
|
+
<% end %>
|
|
185
|
+
|
|
186
|
+
<%= ruflet_drawer do %>
|
|
187
|
+
<%= ruflet_drawer_item "Home", root_path, icon: "home", selected: true %>
|
|
188
|
+
<%= ruflet_drawer_item "Settings", settings_path, icon: "settings", nav: :push %>
|
|
189
|
+
<% end %>
|
|
190
|
+
|
|
191
|
+
<%= ruflet_bottom_nav do %>
|
|
192
|
+
<%= ruflet_nav_item "Home", root_path, icon: "house", selected: true %>
|
|
193
|
+
<%= ruflet_nav_item "Profile", profile_path, icon: "person" %>
|
|
194
|
+
<% end %>
|
|
195
|
+
|
|
196
|
+
<%= ruflet_navigation_rail extended: true, breakpoint: 720 do %>
|
|
197
|
+
<%= ruflet_rail_item "Home", root_path, icon: "home", selected: true %>
|
|
198
|
+
<%= ruflet_rail_item "Inbox", inbox_path, icon: "mail" %>
|
|
199
|
+
<%= ruflet_rail_item "Settings", settings_path, icon: "settings", nav: :push %>
|
|
200
|
+
<% end %>
|
|
201
|
+
```
|
|
149
202
|
|
|
150
|
-
|
|
203
|
+
**Native dialogs and toasts** — from annotated Rails links and buttons.
|
|
204
|
+
Dialogs, bottom sheets, and snackbars are adaptive by default, so the native shell
|
|
205
|
+
can use platform-appropriate presentation instead of forcing the same Material
|
|
206
|
+
look everywhere:
|
|
151
207
|
|
|
152
|
-
|
|
208
|
+
```erb
|
|
209
|
+
<%= link_to "Delete", item_path(item),
|
|
210
|
+
data: { ruflet_action: { component: "dialog", title: "Delete?",
|
|
211
|
+
content: "This cannot be undone.", confirm: "Delete", action: "replace" }.to_json } %>
|
|
153
212
|
|
|
154
|
-
|
|
155
|
-
|
|
213
|
+
<%= button_tag "Copy link",
|
|
214
|
+
data: { ruflet_action: { component: "toast", message: "Copied to clipboard" }.to_json } %>
|
|
156
215
|
```
|
|
157
216
|
|
|
158
|
-
|
|
159
|
-
|
|
217
|
+
**Native menus and bottom sheets** — menus are regular Ruflet bottom sheets
|
|
218
|
+
driven by Rails payload data. Item taps close the native sheet first, wait for
|
|
219
|
+
the native dismiss event, then run the item callback or navigation. This keeps
|
|
220
|
+
the overlay lifecycle stable on mobile and desktop.
|
|
221
|
+
|
|
222
|
+
```erb
|
|
223
|
+
<%= ruflet_appbar "T4U",
|
|
224
|
+
actions: [
|
|
225
|
+
{
|
|
226
|
+
icon: "language",
|
|
227
|
+
action: "menu",
|
|
228
|
+
title: "Language",
|
|
229
|
+
items: [
|
|
230
|
+
{ label: "FR", icon: "check", url: url_for(locale: :fr), action: "root", selected: I18n.locale == :fr },
|
|
231
|
+
{ label: "EN", icon: "translate", url: url_for(locale: :en), action: "root" },
|
|
232
|
+
{ label: "AR", icon: "translate", url: url_for(locale: :ar), action: "root" }
|
|
233
|
+
]
|
|
234
|
+
}
|
|
235
|
+
] %>
|
|
236
|
+
```
|
|
160
237
|
|
|
161
|
-
|
|
162
|
-
|
|
238
|
+
Items close the sheet by default. Pass `close: false` only for an item that
|
|
239
|
+
should run without dismissing the sheet:
|
|
240
|
+
|
|
241
|
+
```erb
|
|
242
|
+
<%= ruflet_appbar "Filters",
|
|
243
|
+
actions: [
|
|
244
|
+
{
|
|
245
|
+
icon: "tune",
|
|
246
|
+
action: "menu",
|
|
247
|
+
title: "Filters",
|
|
248
|
+
items: [
|
|
249
|
+
{ label: "Toggle remote only", icon: "check", close: false }
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
] %>
|
|
163
253
|
```
|
|
164
254
|
|
|
165
|
-
|
|
166
|
-
|
|
255
|
+
Use `action: "sheet"` to present a Rails URL inside a native bottom sheet whose
|
|
256
|
+
body is still a WebView:
|
|
167
257
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
258
|
+
```erb
|
|
259
|
+
<%= link_to "Choose language", languages_path,
|
|
260
|
+
data: { ruflet_action: { component: "sheet", url: languages_path }.to_json } %>
|
|
261
|
+
```
|
|
171
262
|
|
|
172
|
-
|
|
263
|
+
Inside a WebView sheet, plain Rails links are promoted to native actions so the
|
|
264
|
+
sheet closes before navigation:
|
|
173
265
|
|
|
174
|
-
|
|
175
|
-
|
|
266
|
+
```erb
|
|
267
|
+
<!-- app/views/languages/index.html.erb, rendered inside the sheet -->
|
|
268
|
+
<%= link_to "Français", url_for(locale: :fr) %>
|
|
269
|
+
<%= link_to "English", url_for(locale: :en) %>
|
|
270
|
+
<%= link_to "العربية", url_for(locale: :ar) %>
|
|
271
|
+
```
|
|
176
272
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
text(value, size: desktop? || web? ? 28 : 24, weight: "bold")
|
|
182
|
-
end
|
|
183
|
-
end
|
|
273
|
+
Add `data-ruflet-close="false"` when a sheet link should not dismiss:
|
|
274
|
+
|
|
275
|
+
```erb
|
|
276
|
+
<%= link_to "Preview", preview_path, data: { ruflet_close: "false" } %>
|
|
184
277
|
```
|
|
185
278
|
|
|
279
|
+
**Native services** — ERB can trigger safe platform services through the same
|
|
280
|
+
`data-ruflet-action` channel:
|
|
281
|
+
|
|
282
|
+
```erb
|
|
283
|
+
<%= ruflet_share_link "Share", "#",
|
|
284
|
+
text: "Look at this", title: "My App" %>
|
|
285
|
+
|
|
286
|
+
<%= ruflet_copy_button "Copy invite", text: invite_url(@invite) %>
|
|
287
|
+
|
|
288
|
+
<%= ruflet_launch_link "Open docs", "https://flutteronrails.com" %>
|
|
289
|
+
|
|
290
|
+
<%= ruflet_haptic_button "Tap", style: "light" %>
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
For a Fizzy-style web app, keep `Ruflet::Rails.native_app` simple and opt in from
|
|
294
|
+
the views that need native treatment:
|
|
295
|
+
|
|
186
296
|
```ruby
|
|
187
297
|
# app/views/ruflet/main.rb
|
|
188
298
|
Ruflet.run do |page|
|
|
189
|
-
|
|
299
|
+
Ruflet::Rails.native_app(page, start_url: "#{Ruflet::Rails.backend_url}/")
|
|
190
300
|
end
|
|
191
301
|
```
|
|
192
302
|
|
|
@@ -19,11 +19,11 @@ module Ruflet
|
|
|
19
19
|
create_file target, Ruflet::Rails::InstallSupport.default_app_template(app_title: app_name)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def
|
|
23
|
-
target = File.join(destination_root, "ruflet.
|
|
22
|
+
def create_ruflet_initializer
|
|
23
|
+
target = File.join(destination_root, "config", "initializers", "ruflet.rb")
|
|
24
24
|
return if File.exist?(target)
|
|
25
25
|
|
|
26
|
-
create_file target, Ruflet::Rails::InstallSupport.
|
|
26
|
+
create_file target, Ruflet::Rails::InstallSupport.default_initializer(app_name: app_name)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
# Mount the native WebSocket endpoint explicitly in config/routes.rb.
|
|
@@ -4,9 +4,9 @@ module Ruflet
|
|
|
4
4
|
module Rails
|
|
5
5
|
# Central configuration for ruflet_rails.
|
|
6
6
|
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
7
|
+
# Rails apps keep Ruflet build metadata in config/initializers/ruflet.rb.
|
|
8
|
+
# The build task serializes this object to the ruflet.yaml structure the
|
|
9
|
+
# Ruflet CLI consumes, so Rails remains the source of truth:
|
|
10
10
|
#
|
|
11
11
|
# Ruflet::Rails.configure do |config|
|
|
12
12
|
# # Runtime / server
|
|
@@ -15,8 +15,9 @@ module Ruflet
|
|
|
15
15
|
# # App metadata (ruflet.yaml → app:)
|
|
16
16
|
# config.app_name = "My App"
|
|
17
17
|
#
|
|
18
|
-
# # Services (ruflet.yaml → services:)
|
|
18
|
+
# # Services / extensions (ruflet.yaml → services: / extensions:)
|
|
19
19
|
# config.services = []
|
|
20
|
+
# config.extensions = %w[webview]
|
|
20
21
|
#
|
|
21
22
|
# # Assets (ruflet.yaml → assets:)
|
|
22
23
|
# config.splash_screen = Rails.root.join("app/assets/images/splash.png")
|
|
@@ -38,16 +39,17 @@ module Ruflet
|
|
|
38
39
|
# --- Runtime / server ---
|
|
39
40
|
|
|
40
41
|
# Backend base URL. Used as --dart-define=RUFLET_URL at build time
|
|
41
|
-
# and by the desktop launcher.
|
|
42
|
+
# and by the desktop launcher.
|
|
42
43
|
attr_accessor :backend_url
|
|
43
44
|
|
|
44
45
|
# --- App metadata (ruflet.yaml → app:) ---
|
|
45
46
|
|
|
46
47
|
attr_accessor :app_name
|
|
47
48
|
|
|
48
|
-
# --- Services (ruflet.yaml → services:) ---
|
|
49
|
+
# --- Services / extensions (ruflet.yaml → services: / extensions:) ---
|
|
49
50
|
|
|
50
51
|
attr_accessor :services
|
|
52
|
+
attr_accessor :extensions
|
|
51
53
|
|
|
52
54
|
# --- Assets (ruflet.yaml → assets:) ---
|
|
53
55
|
|
|
@@ -71,6 +73,7 @@ module Ruflet
|
|
|
71
73
|
@backend_url = nil
|
|
72
74
|
@app_name = nil
|
|
73
75
|
@services = []
|
|
76
|
+
@extensions = []
|
|
74
77
|
end
|
|
75
78
|
|
|
76
79
|
# Serialises config to the ruflet.yaml hash structure so the CLI can
|
|
@@ -84,7 +87,10 @@ module Ruflet
|
|
|
84
87
|
app["backend_url"] = @backend_url if @backend_url
|
|
85
88
|
hash["app"] = app unless app.empty?
|
|
86
89
|
|
|
87
|
-
|
|
90
|
+
services = Array(@services)
|
|
91
|
+
extensions = Array(@extensions)
|
|
92
|
+
hash["services"] = services unless services.empty?
|
|
93
|
+
hash["extensions"] = extensions unless extensions.empty?
|
|
88
94
|
|
|
89
95
|
assets = {}
|
|
90
96
|
assets["splash_screen"] = @splash_screen.to_s if @splash_screen
|