ruflet_core 0.0.9
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 +7 -0
- data/README.md +3 -0
- data/lib/ruflet/version.rb +5 -0
- data/lib/ruflet.rb +3 -0
- data/lib/ruflet_core.rb +40 -0
- data/lib/ruflet_protocol/ruflet/protocol.rb +62 -0
- data/lib/ruflet_protocol.rb +4 -0
- data/lib/ruflet_ui/ruflet/app.rb +27 -0
- data/lib/ruflet_ui/ruflet/colors.rb +234 -0
- data/lib/ruflet_ui/ruflet/control.rb +281 -0
- data/lib/ruflet_ui/ruflet/dsl.rb +291 -0
- data/lib/ruflet_ui/ruflet/event.rb +42 -0
- data/lib/ruflet_ui/ruflet/events/gesture_events.rb +552 -0
- data/lib/ruflet_ui/ruflet/icon_data.rb +62 -0
- data/lib/ruflet_ui/ruflet/icons/cupertino/cupertino_icons.rb +54 -0
- data/lib/ruflet_ui/ruflet/icons/cupertino_icon_lookup.rb +70 -0
- data/lib/ruflet_ui/ruflet/icons/material/material_icons.rb +55 -0
- data/lib/ruflet_ui/ruflet/icons/material_icon_lookup.rb +70 -0
- data/lib/ruflet_ui/ruflet/page.rb +1222 -0
- data/lib/ruflet_ui/ruflet/types/geometry.rb +65 -0
- data/lib/ruflet_ui/ruflet/types/text_style.rb +191 -0
- data/lib/ruflet_ui/ruflet/ui/control_factory.rb +53 -0
- data/lib/ruflet_ui/ruflet/ui/control_methods.rb +17 -0
- data/lib/ruflet_ui/ruflet/ui/control_registry.rb +33 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactionsheet_control.rb +57 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactionsheetaction_control.rb +58 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactivityindicator_control.rb +57 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoalertdialog_control.rb +39 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoappbar_control.rb +44 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinobottomsheet_control.rb +38 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinobutton_control.rb +73 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocheckbox_control.rb +70 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocontextmenu_control.rb +34 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocontextmenuaction_control.rb +36 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinodatepicker_control.rb +67 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinodialogaction_control.rb +35 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinofilledbutton_control.rb +73 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinolisttile_control.rb +67 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinonavigationbar_control.rb +61 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinopicker_control.rb +66 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoradio_control.rb +66 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinosegmentedbutton_control.rb +63 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoslider_control.rb +64 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoslidingsegmentedbutton_control.rb +60 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoswitch_control.rb +73 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotextfield_control.rb +159 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotimerpicker_control.rb +61 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotintedbutton_control.rb +73 -0
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/ruflet_controls.rb +89 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/alertdialog_control.rb +58 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/appbar_control.rb +53 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/audio_control.rb +36 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/autocomplete_control.rb +58 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/badge_control.rb +31 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/banner_control.rb +47 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/bottomappbar_control.rb +62 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/bottomsheet_control.rb +48 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/button_control.rb +69 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/card_control.rb +63 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/chart_controls.rb +321 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/checkbox_control.rb +76 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/chip_control.rb +88 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/circleavatar_control.rb +62 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/container_control.rb +81 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/contextmenu_control.rb +63 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datacell_control.rb +38 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datacolumn_control.rb +34 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datarow_control.rb +35 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datatable_control.rb +78 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datepicker_control.rb +55 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/daterangepicker_control.rb +57 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/divider_control.rb +36 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/dropdown_control.rb +99 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/dropdownm2_control.rb +119 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/dropdownoption_control.rb +35 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/expansionpanel_control.rb +61 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/expansionpanellist_control.rb +60 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/expansiontile_control.rb +82 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/filledbutton_control.rb +69 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/fillediconbutton_control.rb +81 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/filledtonalbutton_control.rb +69 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/filledtonaliconbutton_control.rb +81 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/floatingactionbutton_control.rb +73 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/iconbutton_control.rb +81 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/listtile_control.rb +87 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/menubar_control.rb +33 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/menuitembutton_control.rb +67 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationbar_control.rb +67 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationbardestination_control.rb +35 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationdrawer_control.rb +41 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationdrawerdestination_control.rb +34 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationrail_control.rb +70 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationraildestination_control.rb +36 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/option_control.rb +35 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/outlinedbutton_control.rb +66 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/outlinediconbutton_control.rb +81 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/popupmenubutton_control.rb +74 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/popupmenuitem_control.rb +38 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/progressbar_control.rb +64 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/progressring_control.rb +65 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/radio_control.rb +70 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/radiogroup_control.rb +33 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/rangeslider_control.rb +67 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/reorderablelistview_control.rb +80 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/ruflet_controls.rb +252 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/searchbar_control.rb +94 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/segment_control.rb +33 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/segmentedbutton_control.rb +63 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/selectionarea_control.rb +32 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/slider_control.rb +76 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/snackbar_control.rb +51 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/submenubutton_control.rb +66 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/switch_control.rb +77 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/tab_control.rb +35 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/tabbar_control.rb +77 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/tabbarview_control.rb +57 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/tabs_control.rb +59 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/textbutton_control.rb +66 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/textfield_control.rb +148 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/timepicker_control.rb +50 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/verticaldivider_control.rb +36 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/video_control.rb +39 -0
- data/lib/ruflet_ui/ruflet/ui/controls/materials/webview_control.rb +35 -0
- data/lib/ruflet_ui/ruflet/ui/controls/ruflet_controls.rb +447 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/animatedswitcher_control.rb +59 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/arc_control.rb +29 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/autofillgroup_control.rb +32 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/basepage_control.rb +44 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/browsercontextmenu_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/canvas_control.rb +57 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/circle_control.rb +25 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/color_control.rb +23 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/column_control.rb +67 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/dialogs_control.rb +22 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/dismissible_control.rb +66 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/draggable_control.rb +39 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/dragtarget_control.rb +36 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/fill_control.rb +22 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/fletapp_control.rb +62 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/gesturedetector_control.rb +129 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/gridview_control.rb +71 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/hero_control.rb +56 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/icon_control.rb +64 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/image_control.rb +27 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/interactiveviewer_control.rb +69 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/keyboardlistener_control.rb +36 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/line_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/listview_control.rb +71 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/markdown_control.rb +70 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/mergesemantics_control.rb +31 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/oval_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/overlay_control.rb +22 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/page_control.rb +74 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/pagelet_control.rb +64 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/pageview_control.rb +64 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/path_control.rb +23 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/placeholder_control.rb +58 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/points_control.rb +24 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/rect_control.rb +27 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/reorderabledraghandle_control.rb +56 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/responsiverow_control.rb +61 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/row_control.rb +67 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/ruflet_controls.rb +140 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/safearea_control.rb +61 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/semantics_control.rb +79 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/serviceregistry_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/shadermask_control.rb +57 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/shadow_control.rb +25 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/shimmer_control.rb +60 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/stack_control.rb +58 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/text_control.rb +32 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/textspan_control.rb +39 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/transparentpointer_control.rb +54 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/view_control.rb +77 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/window_control.rb +56 -0
- data/lib/ruflet_ui/ruflet/ui/controls/shared/windowdragarea_control.rb +58 -0
- data/lib/ruflet_ui/ruflet/ui/cupertino_control_factory.rb +13 -0
- data/lib/ruflet_ui/ruflet/ui/cupertino_control_methods.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/cupertino_control_registry.rb +49 -0
- data/lib/ruflet_ui/ruflet/ui/material_control_factory.rb +13 -0
- data/lib/ruflet_ui/ruflet/ui/material_control_methods.rb +170 -0
- data/lib/ruflet_ui/ruflet/ui/material_control_registry.rb +168 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/accelerometer_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/barometer_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/battery_control.rb +22 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/camera_control.rb +58 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/clipboard_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/connectivity_control.rb +22 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/filepicker_control.rb +23 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/flashlight_control.rb +22 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/gyroscope_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/hapticfeedback_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/magnetometer_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/screenbrightness_control.rb +23 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/screenshot_control.rb +31 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/semanticsservice_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/shakedetector_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/share_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/sharedpreferences_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/storagepaths_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/urllauncher_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/useraccelerometer_control.rb +26 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/wakelock_control.rb +21 -0
- data/lib/ruflet_ui/ruflet/ui/services/ruflet_services.rb +66 -0
- data/lib/ruflet_ui/ruflet/ui/shared_control_forwarders.rb +129 -0
- data/lib/ruflet_ui/ruflet/ui/widget_builder.rb +64 -0
- data/lib/ruflet_ui.rb +160 -0
- metadata +245 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 261081fe6de16011831ffa9ccce2ce123ea5c0b078177b9450800df70780cc62
|
|
4
|
+
data.tar.gz: 76d310dd1e0464545ce6172c2ddf8529c24543e1a34b346f02161542e56cb48f
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 705e39c75cd934fde6e282ebbf6f8ca26c93f0f96f85dcdae6f227c1343af92a78435b725c6c9d32930a815348875ccf228377cccda569cb96a24f218e9e38f7
|
|
7
|
+
data.tar.gz: 4c24b89490f9cb4a18f198163796b9a156ac9a24dec897c0267c52e6812ab072b0c8889cc5fb4018c2c77ec40d8ed0f7bd79b638050bd76ad1706d3a33885916
|
data/README.md
ADDED
data/lib/ruflet.rb
ADDED
data/lib/ruflet_core.rb
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "thread"
|
|
4
|
+
require "ruflet_protocol"
|
|
5
|
+
require "ruflet_ui"
|
|
6
|
+
|
|
7
|
+
module Ruflet
|
|
8
|
+
@run_interceptors = []
|
|
9
|
+
@run_interceptors_mutex = Mutex.new
|
|
10
|
+
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def run(entrypoint = nil, host: "0.0.0.0", port: 8550, &block)
|
|
14
|
+
callback = entrypoint || block
|
|
15
|
+
raise ArgumentError, "Ruflet.run requires a callable entrypoint or block" unless callback.respond_to?(:call)
|
|
16
|
+
|
|
17
|
+
interceptor = @run_interceptors_mutex.synchronize { @run_interceptors.last }
|
|
18
|
+
if interceptor
|
|
19
|
+
result = interceptor.call(entrypoint: callback, host: host, port: port)
|
|
20
|
+
return result unless result == :pass
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
begin
|
|
24
|
+
require "ruflet_server"
|
|
25
|
+
rescue LoadError => e
|
|
26
|
+
raise LoadError, "Ruflet.run requires the 'ruflet_server' gem unless a run interceptor handles execution.", e.backtrace
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
Server.new(host: host, port: port) do |page|
|
|
30
|
+
callback.call(page)
|
|
31
|
+
end.start
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def with_run_interceptor(interceptor)
|
|
35
|
+
@run_interceptors_mutex.synchronize { @run_interceptors << interceptor }
|
|
36
|
+
yield
|
|
37
|
+
ensure
|
|
38
|
+
@run_interceptors_mutex.synchronize { @run_interceptors.delete(interceptor) }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ruflet
|
|
4
|
+
module Protocol
|
|
5
|
+
ACTIONS = {
|
|
6
|
+
register_client: 1,
|
|
7
|
+
patch_control: 2,
|
|
8
|
+
control_event: 3,
|
|
9
|
+
update_control: 4,
|
|
10
|
+
invoke_control_method: 5,
|
|
11
|
+
session_crashed: 6,
|
|
12
|
+
|
|
13
|
+
# Legacy JSON protocol aliases kept for compatibility.
|
|
14
|
+
register_web_client: "registerWebClient",
|
|
15
|
+
page_event_from_web: "pageEventFromWeb",
|
|
16
|
+
update_control_props: "updateControlProps"
|
|
17
|
+
}.freeze
|
|
18
|
+
|
|
19
|
+
module_function
|
|
20
|
+
|
|
21
|
+
def pack_message(action:, payload:)
|
|
22
|
+
[action, payload]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def normalize_register_payload(payload)
|
|
26
|
+
page = payload["page"] || {}
|
|
27
|
+
{
|
|
28
|
+
"session_id" => payload["session_id"],
|
|
29
|
+
"page_name" => payload["page_name"] || "",
|
|
30
|
+
"route" => page["route"] || "/",
|
|
31
|
+
"width" => page["width"],
|
|
32
|
+
"height" => page["height"],
|
|
33
|
+
"platform" => page["platform"],
|
|
34
|
+
"platform_brightness" => page["platform_brightness"],
|
|
35
|
+
"media" => page["media"] || {}
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def normalize_control_event_payload(payload)
|
|
40
|
+
{
|
|
41
|
+
"target" => payload["target"] || payload["eventTarget"],
|
|
42
|
+
"name" => payload["name"] || payload["eventName"],
|
|
43
|
+
"data" => payload["data"] || payload["eventData"]
|
|
44
|
+
}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def normalize_update_control_payload(payload)
|
|
48
|
+
{
|
|
49
|
+
"id" => payload["id"] || payload["target"] || payload["eventTarget"],
|
|
50
|
+
"props" => payload["props"].is_a?(Hash) ? payload["props"] : {}
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def register_response(session_id:)
|
|
55
|
+
{
|
|
56
|
+
"session_id" => session_id,
|
|
57
|
+
"page_patch" => {},
|
|
58
|
+
"error" => nil
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ruflet
|
|
4
|
+
class App
|
|
5
|
+
def initialize(host: nil, port: nil)
|
|
6
|
+
@host = (host || ENV["RUFLET_HOST"] || "0.0.0.0")
|
|
7
|
+
@port = normalize_port(port || ENV["RUFLET_PORT"] || 8550)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def run
|
|
11
|
+
Ruflet.run(host: @host, port: @port) do |page|
|
|
12
|
+
view(page)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def view(_page)
|
|
17
|
+
raise NotImplementedError, "#{self.class} must implement #view(page)"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def normalize_port(value)
|
|
23
|
+
port = value.to_i
|
|
24
|
+
port > 0 ? port : 8550
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ruflet
|
|
4
|
+
module Colors
|
|
5
|
+
SEMANTIC_COLORS = {
|
|
6
|
+
PRIMARY: "primary",
|
|
7
|
+
ON_PRIMARY: "onprimary",
|
|
8
|
+
PRIMARY_CONTAINER: "primarycontainer",
|
|
9
|
+
ON_PRIMARY_CONTAINER: "onprimarycontainer",
|
|
10
|
+
PRIMARY_FIXED: "primaryfixed",
|
|
11
|
+
PRIMARY_FIXED_DIM: "primaryfixeddim",
|
|
12
|
+
ON_PRIMARY_FIXED: "onprimaryfixed",
|
|
13
|
+
ON_PRIMARY_FIXED_VARIANT: "onprimaryfixedvariant",
|
|
14
|
+
SECONDARY: "secondary",
|
|
15
|
+
ON_SECONDARY: "onsecondary",
|
|
16
|
+
SECONDARY_CONTAINER: "secondarycontainer",
|
|
17
|
+
ON_SECONDARY_CONTAINER: "onsecondarycontainer",
|
|
18
|
+
SECONDARY_FIXED: "secondaryfixed",
|
|
19
|
+
SECONDARY_FIXED_DIM: "secondaryfixeddim",
|
|
20
|
+
ON_SECONDARY_FIXED: "onsecondaryfixed",
|
|
21
|
+
ON_SECONDARY_FIXED_VARIANT: "onsecondaryfixedvariant",
|
|
22
|
+
TERTIARY: "tertiary",
|
|
23
|
+
ON_TERTIARY: "ontertiary",
|
|
24
|
+
TERTIARY_CONTAINER: "tertiarycontainer",
|
|
25
|
+
ON_TERTIARY_CONTAINER: "ontertiarycontainer",
|
|
26
|
+
TERTIARY_FIXED: "tertiaryfixed",
|
|
27
|
+
TERTIARY_FIXED_DIM: "tertiaryfixeddim",
|
|
28
|
+
ON_TERTIARY_FIXED: "ontertiaryfixed",
|
|
29
|
+
ON_TERTIARY_FIXED_VARIANT: "ontertiaryfixedvariant",
|
|
30
|
+
ERROR: "error",
|
|
31
|
+
ON_ERROR: "onerror",
|
|
32
|
+
ERROR_CONTAINER: "errorcontainer",
|
|
33
|
+
ON_ERROR_CONTAINER: "onerrorcontainer",
|
|
34
|
+
SURFACE: "surface",
|
|
35
|
+
ON_SURFACE: "onsurface",
|
|
36
|
+
ON_SURFACE_VARIANT: "onsurfacevariant",
|
|
37
|
+
SURFACE_TINT: "surfacetint",
|
|
38
|
+
SURFACE_DIM: "surfacedim",
|
|
39
|
+
SURFACE_BRIGHT: "surfacebright",
|
|
40
|
+
SURFACE_CONTAINER: "surfacecontainer",
|
|
41
|
+
SURFACE_CONTAINER_LOW: "surfacecontainerlow",
|
|
42
|
+
SURFACE_CONTAINER_LOWEST: "surfacecontainerlowest",
|
|
43
|
+
SURFACE_CONTAINER_HIGH: "surfacecontainerhigh",
|
|
44
|
+
SURFACE_CONTAINER_HIGHEST: "surfacecontainerhighest",
|
|
45
|
+
OUTLINE: "outline",
|
|
46
|
+
OUTLINE_VARIANT: "outlinevariant",
|
|
47
|
+
SHADOW: "shadow",
|
|
48
|
+
SCRIM: "scrim",
|
|
49
|
+
INVERSE_SURFACE: "inversesurface",
|
|
50
|
+
ON_INVERSE_SURFACE: "oninversesurface",
|
|
51
|
+
INVERSE_PRIMARY: "inverseprimary"
|
|
52
|
+
}.freeze
|
|
53
|
+
|
|
54
|
+
BASE_PRIMARY = %w[
|
|
55
|
+
amber blue bluegrey brown cyan deeporange deeppurple green grey indigo lightblue
|
|
56
|
+
lightgreen lime orange pink purple red teal yellow
|
|
57
|
+
].freeze
|
|
58
|
+
BASE_ACCENT = %w[
|
|
59
|
+
amber blue cyan deeporange deeppurple green indigo lightblue lightgreen lime
|
|
60
|
+
orange pink purple red teal yellow
|
|
61
|
+
].freeze
|
|
62
|
+
PRIMARY_SHADES = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900].freeze
|
|
63
|
+
ACCENT_SHADES = [100, 200, 400, 700].freeze
|
|
64
|
+
|
|
65
|
+
FIXED_COLORS = {
|
|
66
|
+
BLACK: "black",
|
|
67
|
+
BLACK_12: "black12",
|
|
68
|
+
BLACK_26: "black26",
|
|
69
|
+
BLACK_38: "black38",
|
|
70
|
+
BLACK_45: "black45",
|
|
71
|
+
BLACK_54: "black54",
|
|
72
|
+
BLACK_87: "black87",
|
|
73
|
+
WHITE: "white",
|
|
74
|
+
WHITE_10: "white10",
|
|
75
|
+
WHITE_12: "white12",
|
|
76
|
+
WHITE_24: "white24",
|
|
77
|
+
WHITE_30: "white30",
|
|
78
|
+
WHITE_38: "white38",
|
|
79
|
+
WHITE_54: "white54",
|
|
80
|
+
WHITE_60: "white60",
|
|
81
|
+
WHITE_70: "white70",
|
|
82
|
+
TRANSPARENT: "transparent"
|
|
83
|
+
}.freeze
|
|
84
|
+
|
|
85
|
+
DEPRECATED_ALIASES = {
|
|
86
|
+
BLACK12: :BLACK_12,
|
|
87
|
+
BLACK26: :BLACK_26,
|
|
88
|
+
BLACK38: :BLACK_38,
|
|
89
|
+
BLACK45: :BLACK_45,
|
|
90
|
+
BLACK54: :BLACK_54,
|
|
91
|
+
BLACK87: :BLACK_87,
|
|
92
|
+
WHITE10: :WHITE_10,
|
|
93
|
+
WHITE12: :WHITE_12,
|
|
94
|
+
WHITE24: :WHITE_24,
|
|
95
|
+
WHITE30: :WHITE_30,
|
|
96
|
+
WHITE38: :WHITE_38,
|
|
97
|
+
WHITE54: :WHITE_54,
|
|
98
|
+
WHITE60: :WHITE_60,
|
|
99
|
+
WHITE70: :WHITE_70
|
|
100
|
+
}.freeze
|
|
101
|
+
|
|
102
|
+
def with_opacity(opacity, color)
|
|
103
|
+
value = Float(opacity)
|
|
104
|
+
raise ArgumentError, "opacity must be between 0.0 and 1.0 inclusive, got #{opacity}" unless value.between?(0.0, 1.0)
|
|
105
|
+
|
|
106
|
+
"#{normalize_color(color)},#{value}"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def random(exclude: nil, weights: nil)
|
|
110
|
+
choices = all_values.dup
|
|
111
|
+
excluded = Array(exclude).map { |c| normalize_color(c) }
|
|
112
|
+
choices.reject! { |c| excluded.include?(c) }
|
|
113
|
+
return nil if choices.empty?
|
|
114
|
+
|
|
115
|
+
if weights && !weights.empty?
|
|
116
|
+
expanded = choices.flat_map do |color|
|
|
117
|
+
weight = weights.fetch(color, weights.fetch(color.to_sym, 1)).to_i rescue 1
|
|
118
|
+
weight = 1 if weight <= 0
|
|
119
|
+
[color] * weight
|
|
120
|
+
end
|
|
121
|
+
return expanded.sample
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
choices.sample
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def all_values
|
|
128
|
+
return @all_values if @all_values
|
|
129
|
+
|
|
130
|
+
values = []
|
|
131
|
+
SEMANTIC_COLORS.each_value { |v| values << v }
|
|
132
|
+
FIXED_COLORS.each_value { |v| values << v }
|
|
133
|
+
|
|
134
|
+
BASE_PRIMARY.each do |base|
|
|
135
|
+
values << base
|
|
136
|
+
PRIMARY_SHADES.each do |shade|
|
|
137
|
+
values << "#{base}#{shade}"
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
BASE_ACCENT.each do |base|
|
|
142
|
+
values << "#{base}accent"
|
|
143
|
+
ACCENT_SHADES.each do |shade|
|
|
144
|
+
values << "#{base}accent#{shade}"
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
uniq_map = {}
|
|
149
|
+
values.each { |v| uniq_map[v] = true }
|
|
150
|
+
@all_values = uniq_map.keys.freeze
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def self.normalize_color(color)
|
|
154
|
+
return color.to_s if color.is_a?(Symbol)
|
|
155
|
+
return color if color.is_a?(String)
|
|
156
|
+
return color.to_s unless color.respond_to?(:to_s)
|
|
157
|
+
|
|
158
|
+
color.to_s
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
BASE_PREFIX = {
|
|
162
|
+
"amber" => "AMBER",
|
|
163
|
+
"blue" => "BLUE",
|
|
164
|
+
"bluegrey" => "BLUE_GREY",
|
|
165
|
+
"brown" => "BROWN",
|
|
166
|
+
"cyan" => "CYAN",
|
|
167
|
+
"deeporange" => "DEEP_ORANGE",
|
|
168
|
+
"deeppurple" => "DEEP_PURPLE",
|
|
169
|
+
"green" => "GREEN",
|
|
170
|
+
"grey" => "GREY",
|
|
171
|
+
"indigo" => "INDIGO",
|
|
172
|
+
"lightblue" => "LIGHT_BLUE",
|
|
173
|
+
"lightgreen" => "LIGHT_GREEN",
|
|
174
|
+
"lime" => "LIME",
|
|
175
|
+
"orange" => "ORANGE",
|
|
176
|
+
"pink" => "PINK",
|
|
177
|
+
"purple" => "PURPLE",
|
|
178
|
+
"red" => "RED",
|
|
179
|
+
"teal" => "TEAL",
|
|
180
|
+
"yellow" => "YELLOW"
|
|
181
|
+
}.freeze
|
|
182
|
+
|
|
183
|
+
def self.constant_prefix_for(base_name)
|
|
184
|
+
key = base_name.to_s
|
|
185
|
+
return BASE_PREFIX[key] if BASE_PREFIX.key?(key)
|
|
186
|
+
key.upcase
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
SEMANTIC_COLORS.each { |k, v| const_set(k, v) }
|
|
190
|
+
FIXED_COLORS.each { |k, v| const_set(k, v) }
|
|
191
|
+
|
|
192
|
+
BASE_PRIMARY.each do |base|
|
|
193
|
+
prefix = self.constant_prefix_for(base)
|
|
194
|
+
const_set(prefix, base)
|
|
195
|
+
PRIMARY_SHADES.each do |shade|
|
|
196
|
+
const_set("#{prefix}_#{shade}", "#{base}#{shade}")
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
BASE_ACCENT.each do |base|
|
|
201
|
+
prefix = "#{self.constant_prefix_for(base)}_ACCENT"
|
|
202
|
+
const_set(prefix, "#{base}accent")
|
|
203
|
+
ACCENT_SHADES.each do |shade|
|
|
204
|
+
const_set("#{prefix}_#{shade}", "#{base}accent#{shade}")
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
DEPRECATED_ALIASES.each do |alias_name, target|
|
|
209
|
+
const_set(alias_name, const_get(target))
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
constant_names = []
|
|
213
|
+
SEMANTIC_COLORS.each_key { |k| constant_names << k }
|
|
214
|
+
FIXED_COLORS.each_key { |k| constant_names << k }
|
|
215
|
+
BASE_PRIMARY.each do |base|
|
|
216
|
+
constant_names << constant_prefix_for(base).to_sym
|
|
217
|
+
PRIMARY_SHADES.each { |shade| constant_names << "#{constant_prefix_for(base)}_#{shade}".to_sym }
|
|
218
|
+
end
|
|
219
|
+
BASE_ACCENT.each do |base|
|
|
220
|
+
constant_names << "#{constant_prefix_for(base)}_ACCENT".to_sym
|
|
221
|
+
ACCENT_SHADES.each { |shade| constant_names << "#{constant_prefix_for(base)}_ACCENT_#{shade}".to_sym }
|
|
222
|
+
end
|
|
223
|
+
DEPRECATED_ALIASES.each_key { |k| constant_names << k }
|
|
224
|
+
|
|
225
|
+
uniq_constants = {}
|
|
226
|
+
constant_names.each { |n| uniq_constants[n] = true }
|
|
227
|
+
if respond_to?(:define_singleton_method)
|
|
228
|
+
uniq_constants.keys.each do |name|
|
|
229
|
+
next if respond_to?(name)
|
|
230
|
+
define_singleton_method(name) { const_get(name) }
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require "securerandom"
|
|
5
|
+
rescue LoadError
|
|
6
|
+
nil
|
|
7
|
+
end
|
|
8
|
+
require_relative "icon_data"
|
|
9
|
+
require_relative "icons/material_icon_lookup"
|
|
10
|
+
require_relative "icons/cupertino_icon_lookup"
|
|
11
|
+
require "set"
|
|
12
|
+
|
|
13
|
+
module Ruflet
|
|
14
|
+
class Control
|
|
15
|
+
HOST_EXPANDED_TYPES = %w[view row column].freeze
|
|
16
|
+
|
|
17
|
+
attr_reader :type, :id, :props, :children
|
|
18
|
+
attr_accessor :wire_id, :runtime_page
|
|
19
|
+
|
|
20
|
+
def initialize(type:, id: nil, **props)
|
|
21
|
+
@type = type.to_s.downcase
|
|
22
|
+
@id = (id || props.delete(:id) || "ctrl_#{self.class.generate_id}").to_s
|
|
23
|
+
@children = []
|
|
24
|
+
@handlers = {}
|
|
25
|
+
@wire_id = nil
|
|
26
|
+
@props = normalize_props(extract_handlers(preprocess_props(props)))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def on(event_name, &block)
|
|
30
|
+
name = normalized_event_name(event_name)
|
|
31
|
+
validate_event_name!(name)
|
|
32
|
+
@handlers[name] = block
|
|
33
|
+
@props["on_#{name}"] = true
|
|
34
|
+
runtime_page&.update(self, "on_#{name}": true) if wire_id
|
|
35
|
+
self
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def emit(event_name, event)
|
|
39
|
+
handler = @handlers[normalized_event_name(event_name)]
|
|
40
|
+
return false unless handler
|
|
41
|
+
|
|
42
|
+
handler.call(event)
|
|
43
|
+
true
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def has_handler?(event_name)
|
|
47
|
+
@handlers.key?(normalized_event_name(event_name))
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def to_patch
|
|
51
|
+
wire_type = schema_wire_type_for_class
|
|
52
|
+
if wire_type.nil?
|
|
53
|
+
compact_type_key = type.delete("_")
|
|
54
|
+
wire_type = type_map[type] || type_map[compact_type_key]
|
|
55
|
+
end
|
|
56
|
+
raise ArgumentError, "Unknown control type: #{type}" unless wire_type
|
|
57
|
+
patch = {
|
|
58
|
+
"_c" => wire_type,
|
|
59
|
+
"_i" => wire_id
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
internals = {}
|
|
63
|
+
internals["host_positioned"] = true if type == "stack"
|
|
64
|
+
internals["host_expanded"] = true if HOST_EXPANDED_TYPES.include?(type)
|
|
65
|
+
patch["_internals"] = internals unless internals.empty?
|
|
66
|
+
|
|
67
|
+
props.each { |k, v| patch[k] = serialize_value(v) }
|
|
68
|
+
patch["controls"] = children.map(&:to_patch) unless children.empty?
|
|
69
|
+
patch
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
class << self
|
|
75
|
+
def generate_id
|
|
76
|
+
if defined?(SecureRandom) && SecureRandom.respond_to?(:hex)
|
|
77
|
+
SecureRandom.hex(4)
|
|
78
|
+
else
|
|
79
|
+
format("%08x", rand(0..0xffff_ffff))
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def serialize_value(value)
|
|
85
|
+
case value
|
|
86
|
+
when Control
|
|
87
|
+
value.to_patch
|
|
88
|
+
when Ruflet::IconData
|
|
89
|
+
value.value
|
|
90
|
+
when Array
|
|
91
|
+
value.map { |v| serialize_value(v) }
|
|
92
|
+
when Hash
|
|
93
|
+
value.transform_values { |v| serialize_value(v) }
|
|
94
|
+
else
|
|
95
|
+
value.respond_to?(:to_h) ? serialize_value(value.to_h) : value
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def extract_handlers(input)
|
|
100
|
+
output = input.dup
|
|
101
|
+
allowed_events = event_names
|
|
102
|
+
allowed_events_set = allowed_events.to_set
|
|
103
|
+
|
|
104
|
+
output.keys.each do |key|
|
|
105
|
+
key_string = key.to_s
|
|
106
|
+
next unless key_string.start_with?("on_")
|
|
107
|
+
|
|
108
|
+
event_name = normalized_event_name(key_string)
|
|
109
|
+
if allowed_events.any? && !allowed_events_set.include?(event_name)
|
|
110
|
+
raise ArgumentError, "Unknown event `#{key_string}` for control type `#{type}`"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
handler = output.delete(key)
|
|
114
|
+
@handlers[event_name] = handler if handler.respond_to?(:call)
|
|
115
|
+
output["on_#{event_name}"] = true
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
event_props.each do |prop, event_name|
|
|
119
|
+
string_prop = prop.to_s
|
|
120
|
+
next unless output.key?(prop) || output.key?(string_prop)
|
|
121
|
+
next if allowed_events.any? && !allowed_events_set.include?(event_name)
|
|
122
|
+
|
|
123
|
+
handler = output.key?(prop) ? output.delete(prop) : output.delete(string_prop)
|
|
124
|
+
@handlers[event_name] = handler if handler.respond_to?(:call)
|
|
125
|
+
output["on_#{event_name}"] = true
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
output
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def normalize_props(hash)
|
|
132
|
+
allowed_props = property_names
|
|
133
|
+
normalized_allowed = allowed_props.to_set
|
|
134
|
+
|
|
135
|
+
hash.each_with_object({}) do |(k, v), result|
|
|
136
|
+
key = k.to_s
|
|
137
|
+
mapped_key = key
|
|
138
|
+
if strict_schema_enforced?(allowed_props) &&
|
|
139
|
+
!mapped_key.start_with?("_") &&
|
|
140
|
+
!mapped_key.start_with?("on_") &&
|
|
141
|
+
!normalized_allowed.include?(mapped_key)
|
|
142
|
+
raise ArgumentError, "Unknown attribute `#{mapped_key}` for control type `#{type}`"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
value =
|
|
146
|
+
if v.is_a?(Symbol)
|
|
147
|
+
v.to_s
|
|
148
|
+
elsif v.is_a?(Ruflet::IconData)
|
|
149
|
+
v.value
|
|
150
|
+
else
|
|
151
|
+
v
|
|
152
|
+
end
|
|
153
|
+
value = normalize_icon_prop(mapped_key, value)
|
|
154
|
+
value = normalize_color_prop(mapped_key, value)
|
|
155
|
+
|
|
156
|
+
result[mapped_key] = value
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def preprocess_props(props)
|
|
161
|
+
props
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def normalize_color_prop(key, value)
|
|
165
|
+
return value unless value.is_a?(String)
|
|
166
|
+
return value.downcase if color_prop_key?(key)
|
|
167
|
+
|
|
168
|
+
value
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def color_prop_key?(key)
|
|
172
|
+
key == "color" || key == "bgcolor" || key.end_with?("_color")
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def normalize_icon_prop(key, value)
|
|
176
|
+
return value unless icon_prop_key?(key)
|
|
177
|
+
codepoint = resolve_icon_codepoint(value)
|
|
178
|
+
codepoint.nil? ? value : codepoint
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def icon_prop_key?(key)
|
|
182
|
+
key == "icon" || key.end_with?("_icon")
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def resolve_icon_codepoint(value)
|
|
186
|
+
return nil unless value.is_a?(Integer) || value.is_a?(Symbol) || value.is_a?(String)
|
|
187
|
+
|
|
188
|
+
codepoint = Ruflet::MaterialIconLookup.codepoint_for(value)
|
|
189
|
+
if codepoint.nil? || (value.is_a?(Integer) && codepoint == value)
|
|
190
|
+
cupertino = Ruflet::CupertinoIconLookup.codepoint_for(value)
|
|
191
|
+
codepoint = cupertino unless cupertino.nil?
|
|
192
|
+
end
|
|
193
|
+
codepoint
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def normalized_event_name(event_name)
|
|
197
|
+
event_name.to_s.sub(/\Aon_/, "")
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def validate_event_name!(event_name)
|
|
201
|
+
events = event_names
|
|
202
|
+
return if events.empty? || events.include?(event_name)
|
|
203
|
+
|
|
204
|
+
raise ArgumentError, "Unknown event `on_#{event_name}` for control type `#{type}`"
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def strict_schema_enforced?(allowed_props)
|
|
208
|
+
!allowed_props.empty?
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def property_names
|
|
212
|
+
constructor_keywords_for_schema_class
|
|
213
|
+
.reject { |name| name.to_s.start_with?("on_") }
|
|
214
|
+
.map(&:to_s)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def event_names
|
|
218
|
+
constructor_keywords_for_schema_class
|
|
219
|
+
.select { |name| name.to_s.start_with?("on_") }
|
|
220
|
+
.map { |name| name.to_s.sub(/\Aon_/, "") }
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def schema_wire_type_for_class
|
|
224
|
+
return nil unless self.class.const_defined?(:WIRE)
|
|
225
|
+
|
|
226
|
+
self.class::WIRE.to_s
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def schema_class_for_validation
|
|
230
|
+
if self.class != Ruflet::Control && has_explicit_initialize_keywords?(self.class)
|
|
231
|
+
return self.class
|
|
232
|
+
end
|
|
233
|
+
begin
|
|
234
|
+
require_relative "ui/control_factory"
|
|
235
|
+
mapped = UI::ControlFactory::CLASS_MAP[type]
|
|
236
|
+
return mapped if mapped && has_explicit_initialize_keywords?(mapped)
|
|
237
|
+
rescue LoadError
|
|
238
|
+
nil
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
begin
|
|
242
|
+
require_relative "ui/controls/ruflet_controls"
|
|
243
|
+
mapped = UI::Controls::RufletControls::CLASS_MAP[type]
|
|
244
|
+
return mapped if mapped && has_explicit_initialize_keywords?(mapped)
|
|
245
|
+
rescue LoadError
|
|
246
|
+
nil
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
nil
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def constructor_keywords_for_schema_class
|
|
253
|
+
schema_class = schema_class_for_validation
|
|
254
|
+
return [] unless schema_class
|
|
255
|
+
|
|
256
|
+
schema_class.instance_method(:initialize).parameters
|
|
257
|
+
.select { |kind, _| kind == :key || kind == :keyreq }
|
|
258
|
+
.map { |_, name| name }
|
|
259
|
+
.reject { |name| name == :id }
|
|
260
|
+
rescue StandardError
|
|
261
|
+
[]
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def has_explicit_initialize_keywords?(klass)
|
|
265
|
+
params = klass.instance_method(:initialize).parameters
|
|
266
|
+
params.any? { |kind, _| kind == :key || kind == :keyreq }
|
|
267
|
+
rescue StandardError
|
|
268
|
+
false
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def type_map
|
|
272
|
+
require_relative "ui/control_registry"
|
|
273
|
+
UI::ControlRegistry::TYPE_MAP
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def event_props
|
|
277
|
+
require_relative "ui/control_registry"
|
|
278
|
+
UI::ControlRegistry::EVENT_PROPS
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|