ruflet_core 0.0.18 → 0.0.19

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c28a07c8c32f3e0eca58c3d1400f06453275690b4e9f75d3a868a4507e78c74a
4
- data.tar.gz: 71f044a3c2f0464571e4d16f779e1f751c42f4e16ea3aeeecb3036b596269022
3
+ metadata.gz: 412cca0911d7e0d196902336dff3da369a776e146713f511b4571fe3e693f99e
4
+ data.tar.gz: 9f07083cd60681b95aec47ec0a269c9c0ef42365ee23f8f627f2ea6795e82a66
5
5
  SHA512:
6
- metadata.gz: 38de8d3745bbdf5b217e91de9a6dab2a194757964fa39f7a78bb89c83586fb4f0acee955ae7457221b12a15c4ab7fd18465e2a74af58627c8da25d6c75b62463
7
- data.tar.gz: 476528dec0a5b55ca3e2a3622d4cf2691162434794a498d544a9da165efb249bca5e612f6ba8f49da52387223441ec34ebe64769f162a78916db0f27bee3dce9
6
+ metadata.gz: 77edfb41b260ca90eaa82cc02fd63d81f5c8212845eba2fec5289d31d8d45d1b6c6cf5b02ebf911fbce91bc070a3f591f60d4c9d6a2906f5c87f7456fed1d83c
7
+ data.tar.gz: 70606ebdd3a54ea6d10924b742a2821f5ce05b6ddf0ae0e8c0c23ed69d6042a40452aca569dd48d43b36fa7f85c99c96f674f22ad2722dc075bbdb5fa55f4d5f
data/README.md CHANGED
@@ -1,3 +1,31 @@
1
- # ruflet
1
+ # ruflet_core
2
2
 
3
- Part of Ruflet monorepo.
3
+ `ruflet_core` provides Ruflet's Ruby UI API: controls, control builders, page
4
+ operations, events, services, and application lifecycle behavior.
5
+
6
+ Applications normally receive this package through a generated Ruflet project
7
+ or through `ruflet_rails`; it is not a standalone application server.
8
+
9
+ ```ruby
10
+ require "ruflet"
11
+
12
+ Ruflet.run do |page|
13
+ page.title = "Hello"
14
+ page.add(
15
+ container(
16
+ bgcolor: :surface_container_high,
17
+ padding: 24,
18
+ content: text("Hello Ruflet", color: "DeepOrange500")
19
+ )
20
+ )
21
+ end
22
+ ```
23
+
24
+ Color properties accept named colors and hex values. Use Ruby-style symbols
25
+ like `:deep_orange_500`, compact strings like `"DeepOrange500"`, spaced names
26
+ like `"Deep Orange 500"`, semantic theme names like `:primary_container`, or
27
+ hex strings like `"#ff6d00"`. Ruflet normalizes named colors before sending
28
+ them to the client.
29
+
30
+ Use `ruflet_server` to run a standalone server-driven application. Use
31
+ `ruflet_rails` when the UI is hosted by Rails.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ruflet
4
- VERSION = "0.0.18" unless const_defined?(:VERSION)
4
+ VERSION = "0.0.19" unless const_defined?(:VERSION)
5
5
  end
@@ -590,11 +590,13 @@ module Ruflet
590
590
  def dialog=(value)
591
591
  @dialog = value
592
592
  refresh_dialogs_container!
593
+ push_dialogs_update! if @dialogs_container_mounted
593
594
  end
594
595
 
595
596
  def snack_bar=(value)
596
597
  @snack_bar = value
597
598
  refresh_dialogs_container!
599
+ push_dialogs_update! if @dialogs_container_mounted
598
600
  end
599
601
 
600
602
  def snack_bar
@@ -608,6 +610,7 @@ module Ruflet
608
610
  def bottom_sheet=(value)
609
611
  @bottom_sheet = value
610
612
  refresh_dialogs_container!
613
+ push_dialogs_update! if @dialogs_container_mounted
611
614
  end
612
615
 
613
616
  def bottom_sheet
@@ -656,6 +659,9 @@ module Ruflet
656
659
  return nil unless target
657
660
 
658
661
  target.props["open"] = false
662
+ @dialog = nil if @dialog.equal?(target)
663
+ @snack_bar = nil if @snack_bar.equal?(target)
664
+ @bottom_sheet = nil if @bottom_sheet.equal?(target)
659
665
  refresh_dialogs_container!
660
666
  push_dialogs_update!
661
667
  target
@@ -1192,6 +1198,8 @@ module Ruflet
1192
1198
  patch["content"] = patch.delete("text")
1193
1199
  end
1194
1200
 
1201
+ patch.each { |key, value| control.props[key] = value }
1202
+
1195
1203
  # Keep runtime control tree aligned with incremental patches.
1196
1204
  if patch.key?("controls")
1197
1205
  control.children.clear
@@ -15,8 +15,8 @@ module Ruflet
15
15
  .freeze
16
16
  CONSTRUCTOR_KEYWORDS_CACHE = {}
17
17
 
18
- PYTHON_COMMON_ATTRIBUTES = %i[flip ref transform].freeze
19
- PYTHON_ATTRIBUTE_OVERRIDES = {
18
+ COMMON_ATTRIBUTES = %i[flip ref transform].freeze
19
+ ATTRIBUTE_OVERRIDES = {
20
20
  "expansionpanellist" => %i[auto_scroll on_scroll scroll scroll_interval],
21
21
  "fletapp" => %i[assets_dir on_python_output],
22
22
  "image" => %i[
@@ -64,7 +64,7 @@ module Ruflet
64
64
 
65
65
  def normalize_constructor_props(klass, type, props)
66
66
  keywords = constructor_keywords(klass)
67
- return [props, {}] if keywords.empty? && PYTHON_ATTRIBUTE_OVERRIDES[type].nil?
67
+ return [props, {}] if keywords.empty? && ATTRIBUTE_OVERRIDES[type].nil?
68
68
 
69
69
  allowed = keywords.map(&:to_s)
70
70
  mapped = props.each_with_object({}) { |(k, v), out| out[k.to_sym] = v }
@@ -74,7 +74,7 @@ module Ruflet
74
74
  if mapped.key?(:value) && !allowed.include?("value") && allowed.include?("text") && !mapped.key?(:text)
75
75
  mapped[:text] = mapped.delete(:value)
76
76
  end
77
- supplemental_names = PYTHON_COMMON_ATTRIBUTES + PYTHON_ATTRIBUTE_OVERRIDES.fetch(type, [])
77
+ supplemental_names = COMMON_ATTRIBUTES + ATTRIBUTE_OVERRIDES.fetch(type, [])
78
78
  supplemental = mapped.slice(*supplemental_names)
79
79
  [mapped.reject { |key, _| supplemental_names.include?(key) }, supplemental]
80
80
  end
@@ -4,11 +4,32 @@ module Ruflet
4
4
  module UI
5
5
  module Controls
6
6
  module RufletComponents
7
+ # WebView control — parity with Flet's WebView
8
+ # (https://flet.dev/docs/controls/webview/).
9
+ #
10
+ # Properties: url, bgcolor, prevent_links, plus the usual layout props.
11
+ # Events: on_page_started, on_page_ended, on_web_resource_error,
12
+ # on_progress, on_url_change, on_scroll, on_console_message,
13
+ # on_javascript_alert_dialog.
14
+ # Methods (invoked over the wire on a mounted control): reload, go_back,
15
+ # go_forward, can_go_back, can_go_forward, run_javascript, load_html,
16
+ # load_request, load_file, scroll_to, scroll_by, clear_cache,
17
+ # clear_local_storage, enable_zoom, disable_zoom, set_javascript_mode,
18
+ # get_current_url, get_title, get_user_agent.
19
+ #
20
+ # Platform note: the native webview runs on iOS, Android, macOS, Windows,
21
+ # and Linux. Linux distributions must provide WebKitGTK 4.1. On web it
22
+ # uses an iframe, so browser cross-origin restrictions still apply.
7
23
  class WebViewControl < Ruflet::Control
8
24
  TYPE = "WebView".freeze
9
25
  WIRE = "WebView".freeze
10
26
 
11
- def initialize(id: nil, bgcolor: nil, data: nil, enable_javascript: nil, expand: nil, height: nil, key: nil, method: nil, opacity: nil, rtl: nil, tooltip: nil, url: nil, visible: nil, width: nil, on_page_ended: nil, on_page_started: nil, on_web_resource_error: nil)
27
+ def initialize(id: nil, bgcolor: nil, data: nil, enable_javascript: nil, expand: nil,
28
+ height: nil, key: nil, method: nil, opacity: nil, prevent_links: nil,
29
+ rtl: nil, tooltip: nil, url: nil, visible: nil, width: nil,
30
+ on_page_ended: nil, on_page_started: nil, on_web_resource_error: nil,
31
+ on_progress: nil, on_url_change: nil, on_scroll: nil,
32
+ on_console_message: nil, on_javascript_alert_dialog: nil)
12
33
  props = {}
13
34
  props[:bgcolor] = bgcolor unless bgcolor.nil?
14
35
  props[:data] = data unless data.nil?
@@ -18,6 +39,7 @@ module Ruflet
18
39
  props[:key] = key unless key.nil?
19
40
  props[:method] = method unless method.nil?
20
41
  props[:opacity] = opacity unless opacity.nil?
42
+ props[:prevent_links] = prevent_links unless prevent_links.nil?
21
43
  props[:rtl] = rtl unless rtl.nil?
22
44
  props[:tooltip] = tooltip unless tooltip.nil?
23
45
  props[:url] = url unless url.nil?
@@ -26,8 +48,98 @@ module Ruflet
26
48
  props[:on_page_ended] = on_page_ended unless on_page_ended.nil?
27
49
  props[:on_page_started] = on_page_started unless on_page_started.nil?
28
50
  props[:on_web_resource_error] = on_web_resource_error unless on_web_resource_error.nil?
51
+ props[:on_progress] = on_progress unless on_progress.nil?
52
+ props[:on_url_change] = on_url_change unless on_url_change.nil?
53
+ props[:on_scroll] = on_scroll unless on_scroll.nil?
54
+ props[:on_console_message] = on_console_message unless on_console_message.nil?
55
+ props[:on_javascript_alert_dialog] = on_javascript_alert_dialog unless on_javascript_alert_dialog.nil?
29
56
  super(type: TYPE, id: id, **props)
30
57
  end
58
+
59
+ # --- Navigation --------------------------------------------------
60
+
61
+ def reload = invoke_webview_method("reload")
62
+ def go_back = invoke_webview_method("go_back")
63
+ def go_forward = invoke_webview_method("go_forward")
64
+
65
+ def can_go_back(timeout: 10, &on_result)
66
+ invoke_webview_method("can_go_back", timeout: timeout, on_result: on_result)
67
+ end
68
+
69
+ def can_go_forward(timeout: 10, &on_result)
70
+ invoke_webview_method("can_go_forward", timeout: timeout, on_result: on_result)
71
+ end
72
+
73
+ # --- Loading content ---------------------------------------------
74
+
75
+ def load_request(url, method: "get")
76
+ invoke_webview_method("load_request", { "url" => url.to_s, "method" => method.to_s })
77
+ end
78
+
79
+ def load_html(value, base_url: nil)
80
+ args = { "value" => value.to_s }
81
+ args["base_url"] = base_url.to_s unless base_url.nil?
82
+ invoke_webview_method("load_html", args)
83
+ end
84
+
85
+ def load_file(path)
86
+ invoke_webview_method("load_file", { "path" => path.to_s })
87
+ end
88
+
89
+ # --- JavaScript injection ---------------------------------------
90
+
91
+ # Run arbitrary JS inside the page — e.g. hide a node so a native
92
+ # control can take its place:
93
+ # webview.run_javascript("document.getElementById('banner').remove()")
94
+ def run_javascript(value)
95
+ invoke_webview_method("run_javascript", { "value" => value.to_s })
96
+ end
97
+
98
+ def set_javascript_mode(mode)
99
+ invoke_webview_method("set_javascript_mode", { "mode" => mode.to_s })
100
+ end
101
+
102
+ # --- Scrolling ---------------------------------------------------
103
+
104
+ def scroll_to(x, y)
105
+ invoke_webview_method("scroll_to", { "x" => x.to_i, "y" => y.to_i })
106
+ end
107
+
108
+ def scroll_by(x, y)
109
+ invoke_webview_method("scroll_by", { "x" => x.to_i, "y" => y.to_i })
110
+ end
111
+
112
+ # --- Storage / zoom ----------------------------------------------
113
+
114
+ def clear_cache = invoke_webview_method("clear_cache")
115
+ def clear_local_storage = invoke_webview_method("clear_local_storage")
116
+ def enable_zoom = invoke_webview_method("enable_zoom")
117
+ def disable_zoom = invoke_webview_method("disable_zoom")
118
+
119
+ # --- Introspection (result delivered to the block) ---------------
120
+
121
+ def get_current_url(timeout: 10, &on_result)
122
+ invoke_webview_method("get_current_url", timeout: timeout, on_result: on_result)
123
+ end
124
+
125
+ def get_title(timeout: 10, &on_result)
126
+ invoke_webview_method("get_title", timeout: timeout, on_result: on_result)
127
+ end
128
+
129
+ def get_user_agent(timeout: 10, &on_result)
130
+ invoke_webview_method("get_user_agent", timeout: timeout, on_result: on_result)
131
+ end
132
+
133
+ private
134
+
135
+ def invoke_webview_method(name, args = nil, timeout: 10, on_result: nil)
136
+ page = runtime_page
137
+ unless page && wire_id
138
+ raise "WebView ##{id} is not mounted yet — add it to the page before calling #{name}."
139
+ end
140
+
141
+ page.invoke(self, name, args: args, timeout: timeout, on_result: on_result)
142
+ end
31
143
  end
32
144
  end
33
145
  end
@@ -21,7 +21,7 @@ module Ruflet
21
21
 
22
22
  def view(children = nil, **props, &block)
23
23
  mapped = props.dup
24
- mapped[:children] = children unless children.nil?
24
+ mapped[:controls] = children unless children.nil?
25
25
  build_widget(:view, **mapped, &block)
26
26
  end
27
27
  def column(children = nil, **props, &block)
@@ -6,7 +6,11 @@ module Ruflet
6
6
  def control(type, **props, &block) = control_delegate.control(type, **props, &block)
7
7
  def widget(type, **props, &block) = control_delegate.widget(type, **props, &block)
8
8
  def service(type, **props, &block) = control_delegate.service(type, **props, &block)
9
- def view(children = nil, **props, &block) = control_delegate.view(children, **props, &block)
9
+ def view(children = nil, **props, &block)
10
+ mapped = props.dup
11
+ mapped[:controls] = children unless children.nil?
12
+ control_delegate.control(:view, **mapped, &block)
13
+ end
10
14
  def column(children = nil, **props, &block) = control_delegate.column(children, **props, &block)
11
15
  def center(**props, &block) = control_delegate.center(**props, &block)
12
16
  def row(children = nil, **props, &block) = control_delegate.row(children, **props, &block)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruflet_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.18
4
+ version: 0.0.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - AdamMusa