ruflet_core 0.0.21 → 0.0.23

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ruflet/version.rb +1 -1
  3. data/lib/ruflet_ui/ruflet/dsl.rb +76 -0
  4. data/lib/ruflet_ui/ruflet/event.rb +3 -2
  5. data/lib/ruflet_ui/ruflet/events/gesture_events.rb +2 -1
  6. data/lib/ruflet_ui/ruflet/icons/cupertino/cupertino_icons.rb +46 -26
  7. data/lib/ruflet_ui/ruflet/icons/material/material_icons.rb +61 -26
  8. data/lib/ruflet_ui/ruflet/page.rb +242 -4
  9. data/lib/ruflet_ui/ruflet/ui/control_factory.rb +2 -0
  10. data/lib/ruflet_ui/ruflet/ui/control_methods.rb +4 -0
  11. data/lib/ruflet_ui/ruflet/ui/control_registry.rb +20 -1
  12. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactionsheet_control.rb +1 -1
  13. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactionsheetaction_control.rb +1 -1
  14. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactivityindicator_control.rb +1 -1
  15. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoalertdialog_control.rb +1 -1
  16. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoappbar_control.rb +1 -1
  17. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinobottomsheet_control.rb +1 -1
  18. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinobutton_control.rb +1 -1
  19. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocheckbox_control.rb +1 -1
  20. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocontextmenu_control.rb +1 -1
  21. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocontextmenuaction_control.rb +1 -1
  22. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinodatepicker_control.rb +1 -1
  23. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinodialogaction_control.rb +1 -1
  24. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinofilledbutton_control.rb +1 -1
  25. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinolisttile_control.rb +1 -1
  26. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinonavigationbar_control.rb +1 -1
  27. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinopicker_control.rb +1 -1
  28. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoradio_control.rb +1 -1
  29. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinosegmentedbutton_control.rb +1 -1
  30. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoslider_control.rb +1 -1
  31. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoslidingsegmentedbutton_control.rb +1 -1
  32. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoswitch_control.rb +1 -1
  33. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotextfield_control.rb +1 -1
  34. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotimerpicker_control.rb +1 -1
  35. data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotintedbutton_control.rb +1 -1
  36. data/lib/ruflet_ui/ruflet/ui/controls/materials/ad_controls.rb +45 -0
  37. data/lib/ruflet_ui/ruflet/ui/controls/materials/animation_extension_controls.rb +29 -0
  38. data/lib/ruflet_ui/ruflet/ui/controls/materials/chart_controls.rb +56 -279
  39. data/lib/ruflet_ui/ruflet/ui/controls/materials/code_editor_control.rb +42 -0
  40. data/lib/ruflet_ui/ruflet/ui/controls/materials/color_picker_controls.rb +34 -0
  41. data/lib/ruflet_ui/ruflet/ui/controls/materials/datatable2_controls.rb +41 -0
  42. data/lib/ruflet_ui/ruflet/ui/controls/materials/dropdownm2_control.rb +1 -1
  43. data/lib/ruflet_ui/ruflet/ui/controls/materials/map_control.rb +80 -0
  44. data/lib/ruflet_ui/ruflet/ui/controls/materials/ruflet_controls.rb +62 -0
  45. data/lib/ruflet_ui/ruflet/ui/controls/materials/video_control.rb +1 -2
  46. data/lib/ruflet_ui/ruflet/ui/controls/materials/webview_control.rb +5 -30
  47. data/lib/ruflet_ui/ruflet/ui/controls/ruflet_controls.rb +60 -0
  48. data/lib/ruflet_ui/ruflet/ui/controls/shared/browsercontextmenu_control.rb +17 -0
  49. data/lib/ruflet_ui/ruflet/ui/controls/shared/ruflet_app_control.rb +3 -3
  50. data/lib/ruflet_ui/ruflet/ui/controls/shared/serviceregistry_control.rb +5 -1
  51. data/lib/ruflet_ui/ruflet/ui/cupertino_control_methods.rb +2 -0
  52. data/lib/ruflet_ui/ruflet/ui/material_control_methods.rb +110 -6
  53. data/lib/ruflet_ui/ruflet/ui/material_control_registry.rb +23 -8
  54. data/lib/ruflet_ui/ruflet/ui/platform_control_contracts.rb +392 -0
  55. data/lib/ruflet_ui/ruflet/ui/platform_control_methods.rb +35 -0
  56. data/lib/ruflet_ui/ruflet/ui/services/current_service_methods.rb +220 -0
  57. data/lib/ruflet_ui/ruflet/ui/services/ruflet/camera_control.rb +88 -0
  58. data/lib/ruflet_ui/ruflet/ui/services/ruflet_services.rb +4 -0
  59. data/lib/ruflet_ui/ruflet/ui/shared_control_forwarders.rb +75 -0
  60. data/lib/ruflet_ui.rb +6 -9
  61. metadata +9 -1
@@ -19,6 +19,28 @@ module Ruflet
19
19
  Array(value).map { |coordinates| map_coordinates(coordinates) }
20
20
  end
21
21
 
22
+ def base_page(**props, &block) = build_widget(:base_page, **props, &block)
23
+ def basepage(**props, &block) = base_page(**props, &block)
24
+ def dialogs(controls = nil, **props)
25
+ mapped = props.dup
26
+ mapped[:controls] = controls unless controls.nil?
27
+ build_widget(:dialogs, **mapped)
28
+ end
29
+ def pagelet(content = nil, **props, &block)
30
+ mapped = props.dup
31
+ mapped[:content] = content unless content.nil?
32
+ build_widget(:pagelet, **mapped, &block)
33
+ end
34
+ def ruflet_app(**props) = build_widget(:ruflet_app, **props)
35
+ def rufletapp(**props) = ruflet_app(**props)
36
+ def service_registry(services = nil, **props)
37
+ mapped = props.dup
38
+ mapped[:services] = services unless services.nil?
39
+ build_widget(:service_registry, **mapped)
40
+ end
41
+ def serviceregistry(services = nil, **props) = service_registry(services, **props)
42
+ def window(**props) = build_widget(:window, **props)
43
+
22
44
  def view(children = nil, **props, &block)
23
45
  mapped = props.dup
24
46
  mapped[:controls] = children unless children.nil?
@@ -77,7 +99,31 @@ module Ruflet
77
99
  Ruflet::Animation.new(duration: duration, **props)
78
100
  end
79
101
  def animation_style(**props) = Ruflet::AnimationStyle.new(**props)
80
- def audio(**props) = build_widget(:audio, **props)
102
+ def accelerometer(**props) = build_service(:accelerometer, **props)
103
+ def audio(**props) = build_service(:audio, **props)
104
+ def audio_recorder(**props) = build_service(:audio_recorder, **props)
105
+ def barometer(**props) = build_service(:barometer, **props)
106
+ def battery(**props) = build_service(:battery, **props)
107
+ def browser_context_menu(**props) = build_service(:browser_context_menu, **props)
108
+ def camera(**props) = build_widget(:camera, **props)
109
+ def connectivity(**props) = build_service(:connectivity, **props)
110
+ def file_picker(**props) = build_service(:file_picker, **props)
111
+ def flashlight(**props) = build_service(:flashlight, **props)
112
+ def geolocator(**props) = build_service(:geolocator, **props)
113
+ def gyroscope(**props) = build_service(:gyroscope, **props)
114
+ def haptic_feedback(**props) = build_service(:haptic_feedback, **props)
115
+ def magnetometer(**props) = build_service(:magnetometer, **props)
116
+ def permission_handler(**props) = build_service(:permission_handler, **props)
117
+ def screen_brightness(**props) = build_service(:screen_brightness, **props)
118
+ def secure_storage(**props) = build_service(:secure_storage, **props)
119
+ def semantics_service(**props) = build_service(:semantics_service, **props)
120
+ def shake_detector(**props) = build_service(:shake_detector, **props)
121
+ def share(**props) = build_service(:share, **props)
122
+ def shared_preferences(**props) = build_service(:shared_preferences, **props)
123
+ def storage_paths(**props) = build_service(:storage_paths, **props)
124
+ def url_launcher(**props) = build_service(:url_launcher, **props)
125
+ def user_accelerometer(**props) = build_service(:user_accelerometer, **props)
126
+ def wakelock(**props) = build_service(:wakelock, **props)
81
127
  def auto_complete(suggestions = nil, **props)
82
128
  mapped = props.dup
83
129
  mapped[:suggestions] = suggestions unless suggestions.nil?
@@ -246,6 +292,26 @@ module Ruflet
246
292
  def polygonmarker(**props) = polygon_marker(**props)
247
293
  def simple_attribution(**props) = build_widget(:simpleattribution, **props)
248
294
  def simpleattribution(**props) = simple_attribution(**props)
295
+ def map_layer(**props) = build_widget(:maplayer, **props)
296
+ def maplayer(**props) = map_layer(**props)
297
+ def rich_attribution(attributions = nil, **props)
298
+ mapped = props.dup
299
+ mapped[:attributions] = attributions unless attributions.nil?
300
+ build_widget(:richattribution, **mapped)
301
+ end
302
+ def richattribution(attributions = nil, **props) = rich_attribution(attributions, **props)
303
+ def image_source_attribution(image = nil, **props)
304
+ mapped = props.dup
305
+ mapped[:image] = image unless image.nil?
306
+ build_widget(:imagesourceattribution, **mapped)
307
+ end
308
+ def imagesourceattribution(image = nil, **props) = image_source_attribution(image, **props)
309
+ def text_source_attribution(text = nil, **props)
310
+ mapped = props.dup
311
+ mapped[:text] = text unless text.nil?
312
+ build_widget(:textsourceattribution, **mapped)
313
+ end
314
+ def textsourceattribution(text = nil, **props) = text_source_attribution(text, **props)
249
315
  def list_view(children = nil, **props)
250
316
  mapped = props.dup
251
317
  mapped[:children] = children unless children.nil?
@@ -313,6 +379,29 @@ module Ruflet
313
379
  build_widget(:datacell, **mapped)
314
380
  end
315
381
  def datacell(content = nil, **props) = data_cell(content, **props)
382
+ def option(key = nil, **props)
383
+ mapped = props.dup
384
+ mapped[:key] = key unless key.nil?
385
+ build_widget(:option, **mapped)
386
+ end
387
+ def data_table2(columns = nil, **props)
388
+ mapped = props.dup
389
+ mapped[:columns] = columns unless columns.nil?
390
+ build_widget(:data_table2, **mapped)
391
+ end
392
+ def datatable2(columns = nil, **props) = data_table2(columns, **props)
393
+ def data_column2(label = nil, **props)
394
+ mapped = props.dup
395
+ mapped[:label] = label unless label.nil?
396
+ build_widget(:data_column2, **mapped)
397
+ end
398
+ def datacolumn2(label = nil, **props) = data_column2(label, **props)
399
+ def data_row2(cells = nil, **props)
400
+ mapped = props.dup
401
+ mapped[:cells] = cells unless cells.nil?
402
+ build_widget(:data_row2, **mapped)
403
+ end
404
+ def datarow2(cells = nil, **props) = data_row2(cells, **props)
316
405
  def expansion_tile(children = nil, **props)
317
406
  mapped = props.dup
318
407
  mapped[:children] = children unless children.nil?
@@ -339,9 +428,7 @@ module Ruflet
339
428
  end
340
429
  def dropdownoption(key = nil, **props) = dropdown_option(key, **props)
341
430
  def dropdown_m2(options = nil, **props)
342
- mapped = props.dup
343
- mapped[:options] = options unless options.nil?
344
- build_widget(:dropdownm2, **mapped)
431
+ dropdown(options, **props)
345
432
  end
346
433
  def dropdownm2(options = nil, **props) = dropdown_m2(options, **props)
347
434
  def progress_bar(**props) = build_widget(:progressbar, **props)
@@ -611,8 +698,7 @@ module Ruflet
611
698
 
612
699
  def app_bar(**props) = build_widget(:appbar, **props)
613
700
  def appbar(**props) = app_bar(**props)
614
- def url_launcher(**props) = build_widget(:url_launcher, **props)
615
- def clipboard(**props) = build_widget(:clipboard, **props)
701
+ def clipboard(**props) = build_service(:clipboard, **props)
616
702
  def floating_action_button(**props) = build_widget(:floatingactionbutton, **props)
617
703
  def floatingactionbutton(**props) = floating_action_button(**props)
618
704
  def tabs(content = nil, **props, &block)
@@ -696,6 +782,24 @@ module Ruflet
696
782
  def web_view(**props) = build_widget(:webview, **props)
697
783
  def webview(**props) = web_view(**props)
698
784
  def video(**props) = build_widget(:video, **props)
785
+ def block_picker(**props) = build_widget(:block_picker, **props)
786
+ def blockpicker(**props) = block_picker(**props)
787
+ def color_picker(**props) = build_widget(:color_picker, **props)
788
+ def colorpicker(**props) = color_picker(**props)
789
+ def hue_ring_picker(**props) = build_widget(:hue_ring_picker, **props)
790
+ def hueringpicker(**props) = hue_ring_picker(**props)
791
+ def material_picker(**props) = build_widget(:material_picker, **props)
792
+ def materialpicker(**props) = material_picker(**props)
793
+ def multiple_choice_block_picker(**props) = build_widget(:multiple_choice_block_picker, **props)
794
+ def multiplechoiceblockpicker(**props) = multiple_choice_block_picker(**props)
795
+ def slide_picker(**props) = build_widget(:slide_picker, **props)
796
+ def slidepicker(**props) = slide_picker(**props)
797
+ def banner_ad(**props) = build_widget(:banner_ad, **props)
798
+ def bannerad(**props) = banner_ad(**props)
799
+ def interstitial_ad(**props) = build_widget(:interstitial_ad, **props)
800
+ def interstitialad(**props) = interstitial_ad(**props)
801
+ def native_ad(**props) = build_widget(:native_ad, **props)
802
+ def nativead(**props) = native_ad(**props)
699
803
  def code_editor(value = nil, **props)
700
804
  mapped = props.dup
701
805
  mapped[:value] = value unless value.nil?
@@ -93,6 +93,12 @@ module Ruflet
93
93
  "url_launcher" => "UrlLauncher",
94
94
  "clipboard" => "Clipboard",
95
95
  "audio" => "Audio",
96
+ "bannerad" => "BannerAd",
97
+ "banner_ad" => "BannerAd",
98
+ "interstitialad" => "InterstitialAd",
99
+ "interstitial_ad" => "InterstitialAd",
100
+ "nativead" => "NativeAd",
101
+ "native_ad" => "NativeAd",
96
102
  "video" => "Video",
97
103
  "map" => "Map",
98
104
  "tilelayer" => "TileLayer",
@@ -114,19 +120,28 @@ module Ruflet
114
120
  "polygon_marker" => "PolygonMarker",
115
121
  "simpleattribution" => "SimpleAttribution",
116
122
  "simple_attribution" => "SimpleAttribution",
123
+ "maplayer" => "MapLayer",
124
+ "map_layer" => "MapLayer",
125
+ "richattribution" => "RichAttribution",
126
+ "rich_attribution" => "RichAttribution",
127
+ "imagesourceattribution" => "ImageSourceAttribution",
128
+ "image_source_attribution" => "ImageSourceAttribution",
129
+ "textsourceattribution" => "TextSourceAttribution",
130
+ "text_source_attribution" => "TextSourceAttribution",
117
131
  "codeeditor" => "CodeEditor",
118
132
  "code_editor" => "CodeEditor",
119
133
  "lottie" => "Lottie",
134
+ "rive" => "Rive",
120
135
  "flashlight" => "Flashlight",
121
136
  "barchart" => "BarChart",
122
- "barchartgroup" => "group",
123
- "barchartrod" => "rod",
124
- "barchartrodstackitem" => "stack_item",
137
+ "barchartgroup" => "BarChartGroup",
138
+ "barchartrod" => "BarChartRod",
139
+ "barchartrodstackitem" => "BarChartRodStackItem",
125
140
  "linechart" => "LineChart",
126
- "linechartdata" => "data",
127
- "linechartdatapoint" => "p",
141
+ "linechartdata" => "LineChartData",
142
+ "linechartdatapoint" => "LineChartDataPoint",
128
143
  "piechart" => "PieChart",
129
- "piechartsection" => "section",
144
+ "piechartsection" => "PieChartSection",
130
145
  "candlestickchart" => "CandlestickChart",
131
146
  "candlestickchartspot" => "CandlestickChartSpot",
132
147
  "radarchart" => "RadarChart",
@@ -135,8 +150,8 @@ module Ruflet
135
150
  "radardatasetentry" => "RadarDataSetEntry",
136
151
  "scatterchart" => "ScatterChart",
137
152
  "scatterchartspot" => "ScatterChartSpot",
138
- "chartaxis" => "axis",
139
- "chartaxislabel" => "l",
153
+ "chartaxis" => "ChartAxis",
154
+ "chartaxislabel" => "ChartAxisLabel",
140
155
  "datacell" => "c",
141
156
  "datacolumn" => "c",
142
157
  "datarow" => "r",
@@ -0,0 +1,392 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "controls/ruflet_controls"
4
+
5
+ module Ruflet
6
+ module UI
7
+ # One Ruby protocol contract for controls whose visual implementation is
8
+ # selected by the Flet client. These schemas deliberately accept the union
9
+ # of the Material and Cupertino properties: Ruby describes intent and the
10
+ # platform renderer decides how that intent looks.
11
+ module PlatformControlContracts
12
+ module Components
13
+ class PlatformControl < Ruflet::Control
14
+ def initialize(id: nil, **props)
15
+ props = platform_defaults.merge(props)
16
+ validate_platform_props!(props)
17
+ compact = {}
18
+ props.each do |key, value|
19
+ raise ArgumentError, "unknown keyword: :#{key}" unless self.class::KEYWORDS.include?(key)
20
+
21
+ value = normalize_platform_prop(key, value)
22
+ compact[key] = value unless value.nil?
23
+ end
24
+ super(type: self.class::TYPE, id: id, **compact)
25
+ end
26
+
27
+ private
28
+
29
+ def platform_defaults = {}
30
+ def validate_platform_props!(_props); end
31
+ def normalize_platform_prop(_key, value) = value
32
+
33
+ def require_control_prop!(props, name)
34
+ value = props[name]
35
+ raise ArgumentError, "#{self.class::TYPE} requires #{name}" if value.nil?
36
+ end
37
+ end
38
+
39
+ class ButtonControl < PlatformControl
40
+ TYPE = "button".freeze
41
+ WIRE = "Button".freeze
42
+ KEYWORDS = (
43
+ Controls::RufletComponents::ButtonControl::KEYWORDS +
44
+ Controls::RufletComponents::CupertinoButtonControl::KEYWORDS +
45
+ %i[default destructive]
46
+ ).uniq.freeze
47
+
48
+ end
49
+
50
+ class FilledButtonControl < PlatformControl
51
+ TYPE = "filledbutton".freeze
52
+ WIRE = "FilledButton".freeze
53
+ KEYWORDS = (
54
+ Controls::RufletComponents::FilledButtonControl::KEYWORDS +
55
+ Controls::RufletComponents::CupertinoFilledButtonControl::KEYWORDS
56
+ ).uniq.freeze
57
+
58
+ private
59
+
60
+ def platform_defaults = { autofocus: false, clip_behavior: "none" }
61
+ end
62
+
63
+ class FilledTonalButtonControl < PlatformControl
64
+ TYPE = "filledtonalbutton".freeze
65
+ WIRE = "FilledTonalButton".freeze
66
+ KEYWORDS = (
67
+ Controls::RufletComponents::FilledTonalButtonControl::KEYWORDS +
68
+ Controls::RufletComponents::CupertinoTintedButtonControl::KEYWORDS
69
+ ).uniq.freeze
70
+
71
+ private
72
+
73
+ def platform_defaults = { autofocus: false, clip_behavior: "none" }
74
+ end
75
+
76
+ class OutlinedButtonControl < PlatformControl
77
+ TYPE = "outlinedbutton".freeze
78
+ WIRE = "OutlinedButton".freeze
79
+ KEYWORDS = (
80
+ Controls::RufletComponents::OutlinedButtonControl::KEYWORDS +
81
+ Controls::RufletComponents::CupertinoButtonControl::KEYWORDS
82
+ ).uniq.freeze
83
+
84
+ private
85
+
86
+ def platform_defaults = { autofocus: false, clip_behavior: "none" }
87
+ end
88
+
89
+ class TextButtonControl < PlatformControl
90
+ TYPE = "textbutton".freeze
91
+ WIRE = "TextButton".freeze
92
+ KEYWORDS = (
93
+ Controls::RufletComponents::TextButtonControl::KEYWORDS +
94
+ Controls::RufletComponents::CupertinoButtonControl::KEYWORDS
95
+ ).uniq.freeze
96
+
97
+ private
98
+
99
+ def platform_defaults = { autofocus: false, clip_behavior: "none" }
100
+ end
101
+
102
+ class TextFieldControl < PlatformControl
103
+ TYPE = "textfield".freeze
104
+ WIRE = "TextField".freeze
105
+ KEYWORDS = (
106
+ Controls::RufletComponents::TextFieldControl::KEYWORDS +
107
+ Controls::RufletComponents::CupertinoTextFieldControl::KEYWORDS
108
+ ).uniq.freeze
109
+ end
110
+
111
+ class CheckboxControl < PlatformControl
112
+ TYPE = "checkbox".freeze
113
+ WIRE = "Checkbox".freeze
114
+ KEYWORDS = (
115
+ Controls::RufletComponents::CheckboxControl::KEYWORDS +
116
+ Controls::RufletComponents::CupertinoCheckboxControl::KEYWORDS
117
+ ).uniq.freeze
118
+ end
119
+
120
+ class RadioControl < PlatformControl
121
+ TYPE = "radio".freeze
122
+ WIRE = "Radio".freeze
123
+ KEYWORDS = (
124
+ Controls::RufletComponents::RadioControl::KEYWORDS +
125
+ Controls::RufletComponents::CupertinoRadioControl::KEYWORDS
126
+ ).uniq.freeze
127
+ end
128
+
129
+ class SliderControl < PlatformControl
130
+ TYPE = "slider".freeze
131
+ WIRE = "Slider".freeze
132
+ KEYWORDS = (
133
+ Controls::RufletComponents::SliderControl::KEYWORDS +
134
+ Controls::RufletComponents::CupertinoSliderControl::KEYWORDS
135
+ ).uniq.freeze
136
+ end
137
+
138
+ class SwitchControl < PlatformControl
139
+ TYPE = "switch".freeze
140
+ WIRE = "Switch".freeze
141
+ KEYWORDS = (
142
+ Controls::RufletComponents::SwitchControl::KEYWORDS +
143
+ Controls::RufletComponents::CupertinoSwitchControl::KEYWORDS
144
+ ).uniq.freeze
145
+ end
146
+
147
+ class AlertDialogControl < PlatformControl
148
+ TYPE = "alertdialog".freeze
149
+ WIRE = "AlertDialog".freeze
150
+ KEYWORDS = (
151
+ Controls::RufletComponents::AlertDialogControl::KEYWORDS +
152
+ %i[inset_animation]
153
+ ).uniq.freeze
154
+ end
155
+
156
+ class BottomSheetControl < PlatformControl
157
+ TYPE = "bottomsheet".freeze
158
+ WIRE = "BottomSheet".freeze
159
+ KEYWORDS = %i[
160
+ adaptive animation_style badge barrier_color bgcolor clip_behavior col content data
161
+ disabled dismissible draggable elevation expand expand_loose fullscreen height key
162
+ maintain_bottom_view_insets_padding modal opacity open padding rtl scrollable shape
163
+ show_drag_handle size_constraints tooltip use_safe_area visible on_dismiss
164
+ ].freeze
165
+
166
+ private
167
+
168
+ def validate_platform_props!(props) = require_control_prop!(props, :content)
169
+ end
170
+
171
+ class AppBarControl < PlatformControl
172
+ TYPE = "appbar".freeze
173
+ WIRE = "AppBar".freeze
174
+ KEYWORDS = (
175
+ Controls::RufletComponents::AppBarControl::KEYWORDS + %i[
176
+ automatic_background_visibility automatically_imply_title border brightness
177
+ enable_background_filter_blur large padding previous_page_title trailing
178
+ transition_between_routes
179
+ ]
180
+ ).uniq.freeze
181
+ end
182
+
183
+ class ListTileControl < PlatformControl
184
+ TYPE = "listtile".freeze
185
+ WIRE = "ListTile".freeze
186
+ KEYWORDS = (
187
+ Controls::RufletComponents::ListTileControl::KEYWORDS +
188
+ Controls::RufletComponents::CupertinoListTileControl::KEYWORDS
189
+ ).uniq.freeze
190
+
191
+ private
192
+
193
+ def validate_platform_props!(props) = require_control_prop!(props, :title)
194
+ end
195
+
196
+ class NavigationBarControl < PlatformControl
197
+ TYPE = "navigationbar".freeze
198
+ WIRE = "NavigationBar".freeze
199
+ KEYWORDS = (
200
+ Controls::RufletComponents::NavigationBarControl::KEYWORDS +
201
+ Controls::RufletComponents::CupertinoNavigationBarControl::KEYWORDS
202
+ ).uniq.freeze
203
+ end
204
+
205
+ class ProgressRingControl < PlatformControl
206
+ TYPE = "progressring".freeze
207
+ WIRE = "ProgressRing".freeze
208
+ KEYWORDS = (
209
+ Controls::RufletComponents::ProgressRingControl::KEYWORDS +
210
+ Controls::RufletComponents::CupertinoActivityIndicatorControl::KEYWORDS
211
+ ).uniq.freeze
212
+ end
213
+
214
+ class SegmentedButtonControl < PlatformControl
215
+ TYPE = "segmentedbutton".freeze
216
+ WIRE = "SegmentedButton".freeze
217
+ KEYWORDS = (
218
+ Controls::RufletComponents::SegmentedButtonControl::KEYWORDS +
219
+ Controls::RufletComponents::CupertinoSegmentedButtonControl::KEYWORDS +
220
+ Controls::RufletComponents::CupertinoSlidingSegmentedButtonControl::KEYWORDS
221
+ ).uniq.freeze
222
+ end
223
+
224
+ class ContextMenuControl < PlatformControl
225
+ TYPE = "contextmenu".freeze
226
+ WIRE = "ContextMenu".freeze
227
+ KEYWORDS = (
228
+ Controls::RufletComponents::ContextMenuControl::KEYWORDS +
229
+ %i[actions adaptive enable_haptic_feedback]
230
+ ).uniq.freeze
231
+
232
+ def open(position: nil, timeout: 10, on_result: nil)
233
+ args = {}
234
+ args["position"] = stringify_hash_keys(position) unless position.nil?
235
+ runtime_page&.invoke(self, "open", args: args, timeout: timeout, on_result: on_result)
236
+ end
237
+
238
+ private
239
+
240
+ def validate_platform_props!(props) = require_control_prop!(props, :content)
241
+
242
+ def stringify_hash_keys(value)
243
+ return value.map { |item| stringify_hash_keys(item) } if value.is_a?(Array)
244
+ if value.is_a?(Hash)
245
+ return value.each_with_object({}) do |(key, child), result|
246
+ result[key.to_s] = stringify_hash_keys(child)
247
+ end
248
+ end
249
+
250
+ value
251
+ end
252
+ end
253
+
254
+ class ContextMenuActionControl < PlatformControl
255
+ TYPE = "contextmenuaction".freeze
256
+ WIRE = "ContextMenuAction".freeze
257
+ KEYWORDS = %i[
258
+ adaptive align animate_align animate_margin animate_offset animate_opacity
259
+ animate_position animate_rotation animate_scale animate_size aspect_ratio badge bottom
260
+ checked col content data default destructive disabled expand expand_loose height icon key
261
+ left margin mouse_cursor offset opacity right rotate rtl scale size_change_interval
262
+ tooltip top trailing_icon value visible width on_animation_end on_click on_size_change
263
+ ].freeze
264
+
265
+ private
266
+
267
+ def validate_platform_props!(props) = require_control_prop!(props, :content)
268
+ end
269
+
270
+ class ActionSheetControl < PlatformControl
271
+ TYPE = "actionsheet".freeze
272
+ WIRE = "ActionSheet".freeze
273
+ KEYWORDS = Controls::RufletComponents::CupertinoActionSheetControl::KEYWORDS
274
+ end
275
+
276
+ class ActionSheetActionControl < PlatformControl
277
+ TYPE = "actionsheetaction".freeze
278
+ WIRE = "ActionSheetAction".freeze
279
+ KEYWORDS = Controls::RufletComponents::CupertinoActionSheetActionControl::KEYWORDS
280
+
281
+ private
282
+
283
+ def validate_platform_props!(props) = require_control_prop!(props, :content)
284
+ end
285
+
286
+ class DatePickerControl < PlatformControl
287
+ TYPE = "datepicker".freeze
288
+ WIRE = "DatePicker".freeze
289
+ KEYWORDS = (
290
+ Controls::RufletComponents::DatePickerControl::KEYWORDS +
291
+ Controls::RufletComponents::CupertinoDatePickerControl::KEYWORDS
292
+ ).uniq.freeze
293
+
294
+ private
295
+
296
+ def normalize_platform_prop(key, value)
297
+ return value unless %i[value first_date last_date current_date].include?(key)
298
+
299
+ Ruflet::Protocol.date_time(value)
300
+ end
301
+ end
302
+
303
+ class PickerControl < PlatformControl
304
+ TYPE = "picker".freeze
305
+ WIRE = "Picker".freeze
306
+ KEYWORDS = Controls::RufletComponents::CupertinoPickerControl::KEYWORDS
307
+ end
308
+
309
+ class TimerPickerControl < PlatformControl
310
+ TYPE = "timerpicker".freeze
311
+ WIRE = "TimerPicker".freeze
312
+ KEYWORDS = Controls::RufletComponents::CupertinoTimerPickerControl::KEYWORDS
313
+ end
314
+
315
+ class DropdownControl < PlatformControl
316
+ TYPE = "dropdown".freeze
317
+ WIRE = "Dropdown".freeze
318
+ KEYWORDS = (
319
+ Controls::RufletComponents::DropdownControl::KEYWORDS +
320
+ Controls::RufletComponents::Dropdown2Control::KEYWORDS
321
+ ).uniq.freeze
322
+ end
323
+ end
324
+
325
+ CANONICAL_CLASS_MAP = {
326
+ %w[button elevated_button elevatedbutton] => Components::ButtonControl,
327
+ %w[filled_button filledbutton] => Components::FilledButtonControl,
328
+ %w[filled_tonal_button filledtonalbutton] => Components::FilledTonalButtonControl,
329
+ %w[outlined_button outlinedbutton] => Components::OutlinedButtonControl,
330
+ %w[text_button textbutton] => Components::TextButtonControl,
331
+ %w[text_field textfield] => Components::TextFieldControl,
332
+ %w[checkbox] => Components::CheckboxControl,
333
+ %w[radio] => Components::RadioControl,
334
+ %w[slider] => Components::SliderControl,
335
+ %w[switch] => Components::SwitchControl,
336
+ %w[alert_dialog alertdialog] => Components::AlertDialogControl,
337
+ %w[bottom_sheet bottomsheet] => Components::BottomSheetControl,
338
+ %w[app_bar appbar] => Components::AppBarControl,
339
+ %w[list_tile listtile] => Components::ListTileControl,
340
+ %w[navigation_bar navigationbar] => Components::NavigationBarControl,
341
+ %w[progress_ring progressring] => Components::ProgressRingControl,
342
+ %w[segmented_button segmentedbutton] => Components::SegmentedButtonControl,
343
+ %w[context_menu contextmenu] => Components::ContextMenuControl,
344
+ %w[context_menu_action contextmenuaction] => Components::ContextMenuActionControl,
345
+ %w[action_sheet actionsheet] => Components::ActionSheetControl,
346
+ %w[action_sheet_action actionsheetaction] => Components::ActionSheetActionControl,
347
+ %w[date_picker datepicker] => Components::DatePickerControl,
348
+ %w[picker] => Components::PickerControl,
349
+ %w[timer_picker timerpicker] => Components::TimerPickerControl,
350
+ %w[dropdown dropdown_m2 dropdownm2] => Components::DropdownControl,
351
+ }.each_with_object({}) do |(names, klass), map|
352
+ names.each { |name| map[name] = klass }
353
+ end.freeze
354
+
355
+ LEGACY_CLASS_MAP = {
356
+ %w[cupertino_button cupertinobutton] => Controls::RufletComponents::CupertinoButtonControl,
357
+ %w[cupertino_filled_button cupertinofilledbutton] => Controls::RufletComponents::CupertinoFilledButtonControl,
358
+ %w[cupertino_tinted_button cupertinotintedbutton] => Controls::RufletComponents::CupertinoTintedButtonControl,
359
+ %w[cupertino_text_field cupertinotextfield] => Controls::RufletComponents::CupertinoTextFieldControl,
360
+ %w[cupertino_checkbox cupertinocheckbox] => Controls::RufletComponents::CupertinoCheckboxControl,
361
+ %w[cupertino_radio cupertinoradio] => Controls::RufletComponents::CupertinoRadioControl,
362
+ %w[cupertino_slider cupertinoslider] => Controls::RufletComponents::CupertinoSliderControl,
363
+ %w[cupertino_switch cupertinoswitch] => Controls::RufletComponents::CupertinoSwitchControl,
364
+ %w[cupertino_alert_dialog cupertinoalertdialog] => Controls::RufletComponents::CupertinoAlertDialogControl,
365
+ %w[cupertino_bottom_sheet cupertinobottomsheet] => Controls::RufletComponents::CupertinoBottomSheetControl,
366
+ %w[cupertino_app_bar cupertinoappbar] => Controls::RufletComponents::CupertinoAppBarControl,
367
+ %w[cupertino_list_tile cupertinolisttile] => Controls::RufletComponents::CupertinoListTileControl,
368
+ %w[cupertino_navigation_bar cupertinonavigationbar] => Controls::RufletComponents::CupertinoNavigationBarControl,
369
+ %w[cupertino_activity_indicator cupertinoactivityindicator] => Controls::RufletComponents::CupertinoActivityIndicatorControl,
370
+ %w[cupertino_segmented_button cupertinosegmentedbutton] => Controls::RufletComponents::CupertinoSegmentedButtonControl,
371
+ %w[cupertino_sliding_segmented_button cupertinoslidingsegmentedbutton] => Controls::RufletComponents::CupertinoSlidingSegmentedButtonControl,
372
+ %w[cupertino_context_menu cupertinocontextmenu] => Controls::RufletComponents::CupertinoContextMenuControl,
373
+ %w[cupertino_context_menu_action cupertinocontextmenuaction] => Controls::RufletComponents::CupertinoContextMenuActionControl,
374
+ %w[cupertino_action_sheet cupertinoactionsheet] => Controls::RufletComponents::CupertinoActionSheetControl,
375
+ %w[cupertino_action_sheet_action cupertinoactionsheetaction] => Controls::RufletComponents::CupertinoActionSheetActionControl,
376
+ %w[cupertino_date_picker cupertinodatepicker] => Controls::RufletComponents::CupertinoDatePickerControl,
377
+ %w[cupertino_picker cupertinopicker] => Controls::RufletComponents::CupertinoPickerControl,
378
+ %w[cupertino_timer_picker cupertinotimerpicker] => Controls::RufletComponents::CupertinoTimerPickerControl,
379
+ %w[cupertino_dialog_action cupertinodialogaction] => Controls::RufletComponents::CupertinoDialogActionControl,
380
+ %w[popup_menu_item popupmenuitem] => Controls::RufletComponents::PopupMenuItemControl
381
+ }.each_with_object({}) do |(names, klass), map|
382
+ names.each { |name| map[name] = klass }
383
+ end.freeze
384
+
385
+ CLASS_MAP = CANONICAL_CLASS_MAP.merge(LEGACY_CLASS_MAP).freeze
386
+
387
+ TYPE_MAP = CLASS_MAP.each_with_object({}) do |(name, klass), map|
388
+ map[name] = klass::WIRE
389
+ end.freeze
390
+ end
391
+ end
392
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ruflet
4
+ module UI
5
+ # Canonical DSL entry points for controls whose renderer is selected by
6
+ # the Flet client. There is no design-system choice in this API.
7
+ module PlatformControlMethods
8
+ def context_menu_action(content = nil, **props)
9
+ mapped = props.dup
10
+ mapped[:content] = content unless content.nil?
11
+ build_widget(:contextmenuaction, **mapped)
12
+ end
13
+ def contextmenuaction(content = nil, **props) = context_menu_action(content, **props)
14
+
15
+ def action_sheet(**props) = build_widget(:actionsheet, **props)
16
+ def actionsheet(**props) = action_sheet(**props)
17
+
18
+ def action_sheet_action(content = nil, **props)
19
+ mapped = props.dup
20
+ mapped[:content] = content unless content.nil?
21
+ build_widget(:actionsheetaction, **mapped)
22
+ end
23
+ def actionsheetaction(content = nil, **props) = action_sheet_action(content, **props)
24
+
25
+ def picker(children = nil, **props)
26
+ mapped = props.dup
27
+ mapped[:controls] = children unless children.nil?
28
+ build_widget(:picker, **mapped)
29
+ end
30
+
31
+ def timer_picker(**props) = build_widget(:timerpicker, **props)
32
+ def timerpicker(**props) = timer_picker(**props)
33
+ end
34
+ end
35
+ end