scarpe 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/CHANGELOG.md +16 -2
  4. data/Gemfile.lock +7 -3
  5. data/README.md +24 -8
  6. data/Rakefile +1 -1
  7. data/examples/animate.rb +20 -0
  8. data/examples/arrow.rb +10 -0
  9. data/examples/btn_tooltip.rb +7 -0
  10. data/examples/button_style_changed.rb +7 -0
  11. data/examples/button_styles_default.rb +6 -0
  12. data/examples/gen.rb +8 -8
  13. data/examples/highlander.rb +3 -3
  14. data/examples/legacy/README.md +6 -0
  15. data/examples/legacy/not_checked/shoes-contrib/basic/shoes-notes.rb +1 -1
  16. data/examples/legacy/not_checked/simple/anim-shapes.rb +1 -1
  17. data/examples/legacy/not_checked/speedometer_app.rb +55 -0
  18. data/examples/legacy/working/simple/image-icon.rb +3 -0
  19. data/examples/legacy/{not_checked → working}/simple/image.rb +1 -1
  20. data/examples/list_box_choose.rb +17 -0
  21. data/examples/local_assets/local_file_server.rb +82 -0
  22. data/examples/local_assets/sample.gif +0 -0
  23. data/examples/local_assets/sample.mp4 +0 -0
  24. data/examples/local_fonts.rb +2 -2
  25. data/examples/local_images.rb +2 -3
  26. data/examples/para/para_text.rb +14 -0
  27. data/examples/progress.rb +31 -0
  28. data/examples/radio/radio_groups.rb +2 -2
  29. data/examples/rect.rb +4 -0
  30. data/examples/rotate_shapes.rb +17 -0
  31. data/examples/simpler-menu.rb +21 -0
  32. data/exe/scarpe +2 -1
  33. data/lacci/Gemfile +2 -0
  34. data/lacci/Gemfile.lock +8 -1
  35. data/lacci/lacci.gemspec +1 -1
  36. data/lacci/lib/lacci/scarpe_cli.rb +2 -1
  37. data/lacci/lib/lacci/scarpe_core.rb +2 -1
  38. data/lacci/lib/lacci/version.rb +1 -1
  39. data/lacci/lib/scarpe/niente/app.rb +23 -0
  40. data/lacci/lib/scarpe/niente/display_service.rb +62 -0
  41. data/lacci/lib/scarpe/niente/drawable.rb +57 -0
  42. data/lacci/lib/scarpe/niente/logger.rb +29 -0
  43. data/lacci/lib/scarpe/niente/shoes_spec.rb +87 -0
  44. data/lacci/lib/scarpe/niente.rb +20 -0
  45. data/lacci/lib/shoes/app.rb +88 -43
  46. data/lacci/lib/shoes/background.rb +2 -2
  47. data/lacci/lib/shoes/border.rb +2 -2
  48. data/lacci/lib/shoes/builtins.rb +63 -0
  49. data/lacci/lib/shoes/changelog.rb +52 -0
  50. data/lacci/lib/shoes/colors.rb +3 -1
  51. data/lacci/lib/shoes/constants.rb +19 -1
  52. data/lacci/lib/shoes/display_service.rb +39 -16
  53. data/lacci/lib/shoes/download.rb +2 -2
  54. data/lacci/lib/shoes/drawable.rb +380 -0
  55. data/lacci/lib/shoes/drawables/arc.rb +49 -0
  56. data/lacci/lib/shoes/drawables/arrow.rb +41 -0
  57. data/lacci/lib/shoes/drawables/button.rb +73 -0
  58. data/lacci/lib/shoes/{widgets → drawables}/check.rb +5 -4
  59. data/lacci/lib/shoes/{widgets → drawables}/document_root.rb +3 -3
  60. data/lacci/lib/shoes/{widgets → drawables}/edit_box.rb +6 -6
  61. data/lacci/lib/shoes/{widgets → drawables}/edit_line.rb +6 -6
  62. data/lacci/lib/shoes/{widgets → drawables}/flow.rb +6 -6
  63. data/lacci/lib/shoes/{widgets → drawables}/image.rb +6 -6
  64. data/lacci/lib/shoes/{widgets → drawables}/line.rb +7 -5
  65. data/lacci/lib/shoes/drawables/link.rb +34 -0
  66. data/lacci/lib/shoes/drawables/list_box.rb +56 -0
  67. data/lacci/lib/shoes/drawables/para.rb +118 -0
  68. data/lacci/lib/shoes/drawables/progress.rb +14 -0
  69. data/lacci/lib/shoes/drawables/radio.rb +33 -0
  70. data/lacci/lib/shoes/drawables/rect.rb +17 -0
  71. data/lacci/lib/shoes/{widgets → drawables}/shape.rb +6 -7
  72. data/lacci/lib/shoes/{widgets → drawables}/slot.rb +32 -20
  73. data/lacci/lib/shoes/{widgets → drawables}/span.rb +8 -7
  74. data/lacci/lib/shoes/{widgets → drawables}/stack.rb +6 -4
  75. data/lacci/lib/shoes/drawables/star.rb +50 -0
  76. data/lacci/lib/shoes/drawables/subscription_item.rb +93 -0
  77. data/lacci/lib/shoes/drawables/text_drawable.rb +63 -0
  78. data/lacci/lib/shoes/drawables/video.rb +16 -0
  79. data/lacci/lib/shoes/drawables/widget.rb +69 -0
  80. data/lacci/lib/shoes/drawables.rb +31 -0
  81. data/lacci/lib/shoes/errors.rb +28 -0
  82. data/lacci/lib/shoes/log.rb +2 -2
  83. data/lacci/lib/shoes/ruby_extensions.rb +15 -0
  84. data/lacci/lib/shoes/spacing.rb +2 -2
  85. data/lacci/lib/shoes-spec.rb +93 -0
  86. data/lacci/lib/shoes.rb +27 -7
  87. data/lacci/test/test_helper.rb +54 -0
  88. data/lacci/test/test_lacci.rb +12 -3
  89. data/lacci/test/test_shoes_errors.rb +49 -0
  90. data/lib/scarpe/cats_cradle.rb +81 -59
  91. data/lib/scarpe/errors.rb +77 -0
  92. data/lib/scarpe/evented_assertions.rb +50 -17
  93. data/lib/scarpe/shoes_spec.rb +181 -0
  94. data/lib/scarpe/version.rb +2 -2
  95. data/lib/scarpe/wv/app.rb +20 -20
  96. data/lib/scarpe/wv/arc.rb +4 -47
  97. data/lib/scarpe/wv/arrow.rb +9 -0
  98. data/lib/scarpe/wv/button.rb +7 -35
  99. data/lib/scarpe/wv/check.rb +3 -5
  100. data/lib/scarpe/wv/control_interface.rb +18 -20
  101. data/lib/scarpe/wv/document_root.rb +81 -4
  102. data/lib/scarpe/wv/{widget.rb → drawable.rb} +66 -43
  103. data/lib/scarpe/wv/edit_box.rb +4 -17
  104. data/lib/scarpe/wv/edit_line.rb +4 -18
  105. data/lib/scarpe/wv/flow.rb +2 -18
  106. data/lib/scarpe/wv/image.rb +8 -28
  107. data/lib/scarpe/wv/line.rb +3 -25
  108. data/lib/scarpe/wv/link.rb +3 -16
  109. data/lib/scarpe/wv/list_box.rb +6 -29
  110. data/lib/scarpe/wv/para.rb +11 -30
  111. data/lib/scarpe/wv/progress.rb +19 -0
  112. data/lib/scarpe/wv/radio.rb +9 -10
  113. data/lib/scarpe/wv/rect.rb +13 -0
  114. data/lib/scarpe/wv/shape.rb +3 -8
  115. data/lib/scarpe/wv/slot.rb +8 -25
  116. data/lib/scarpe/wv/span.rb +3 -27
  117. data/lib/scarpe/wv/stack.rb +2 -18
  118. data/lib/scarpe/wv/star.rb +3 -53
  119. data/lib/scarpe/wv/subscription_item.rb +38 -4
  120. data/lib/scarpe/wv/text_drawable.rb +32 -0
  121. data/lib/scarpe/wv/video.rb +15 -15
  122. data/lib/scarpe/wv/web_wrangler.rb +299 -329
  123. data/lib/scarpe/wv/webview_local_display.rb +48 -33
  124. data/lib/scarpe/wv/webview_relay_display.rb +12 -12
  125. data/lib/scarpe/wv/webview_relay_util.rb +7 -10
  126. data/lib/scarpe/wv/wv_display_worker.rb +2 -2
  127. data/lib/scarpe/wv.rb +45 -12
  128. data/lib/scarpe/wv_local.rb +1 -1
  129. data/lib/scarpe/wv_relay.rb +1 -1
  130. data/lib/scarpe.rb +1 -0
  131. data/logger/debug_web_wrangler.json +1 -1
  132. data/logger/scarpe_wv_test.json +1 -1
  133. data/scarpe-components/Gemfile.lock +86 -0
  134. data/scarpe-components/lib/scarpe/components/base64.rb +3 -7
  135. data/scarpe-components/lib/scarpe/components/calzini/alert.rb +49 -0
  136. data/scarpe-components/lib/scarpe/components/calzini/art_widgets.rb +203 -0
  137. data/scarpe-components/lib/scarpe/components/calzini/button.rb +39 -0
  138. data/scarpe-components/lib/scarpe/components/calzini/misc.rb +146 -0
  139. data/scarpe-components/lib/scarpe/components/calzini/para.rb +35 -0
  140. data/scarpe-components/lib/scarpe/components/calzini/slots.rb +155 -0
  141. data/scarpe-components/lib/scarpe/components/calzini/text_widgets.rb +65 -0
  142. data/scarpe-components/lib/scarpe/components/calzini.rb +149 -0
  143. data/scarpe-components/lib/scarpe/components/errors.rb +20 -0
  144. data/scarpe-components/lib/scarpe/components/file_helpers.rb +1 -0
  145. data/scarpe-components/lib/scarpe/components/html.rb +131 -0
  146. data/scarpe-components/lib/scarpe/components/minitest_export_reporter.rb +75 -0
  147. data/scarpe-components/lib/scarpe/components/minitest_import_runnable.rb +98 -0
  148. data/scarpe-components/lib/scarpe/components/minitest_result.rb +86 -0
  149. data/scarpe-components/lib/scarpe/components/modular_logger.rb +5 -5
  150. data/scarpe-components/lib/scarpe/components/print_logger.rb +9 -5
  151. data/scarpe-components/lib/scarpe/components/promises.rb +14 -14
  152. data/scarpe-components/lib/scarpe/components/segmented_file_loader.rb +36 -17
  153. data/scarpe-components/lib/scarpe/components/string_helpers.rb +10 -0
  154. data/scarpe-components/lib/scarpe/components/tiranti.rb +225 -0
  155. data/scarpe-components/lib/scarpe/components/unit_test_helpers.rb +45 -5
  156. data/scarpe-components/lib/scarpe/components/version.rb +2 -2
  157. data/scarpe-components/test/calzini/test_calzini_alert.rb +30 -0
  158. data/scarpe-components/test/calzini/test_calzini_art_drawables.rb +105 -0
  159. data/scarpe-components/test/calzini/test_calzini_button.rb +52 -0
  160. data/scarpe-components/test/calzini/test_calzini_misc.rb +115 -0
  161. data/scarpe-components/test/calzini/test_calzini_para.rb +37 -0
  162. data/scarpe-components/test/calzini/test_calzini_slots.rb +130 -0
  163. data/scarpe-components/test/calzini/test_calzini_text_drawables.rb +41 -0
  164. data/scarpe-components/test/mtr_data/exception.json +1 -0
  165. data/scarpe-components/test/mtr_data/fail_with_message.json +1 -0
  166. data/scarpe-components/test/mtr_data/skipped_no_message.json +1 -0
  167. data/scarpe-components/test/mtr_data/skipped_w_msg.json +1 -0
  168. data/scarpe-components/test/mtr_data/succeed_2_asserts.json +1 -0
  169. data/scarpe-components/test/test_dimensions.rb +26 -0
  170. data/scarpe-components/test/test_helper.rb +20 -0
  171. data/scarpe-components/test/test_html.rb +65 -0
  172. data/scarpe-components/test/test_minitest_result.rb +61 -0
  173. data/scarpe-components/test/test_promises.rb +5 -4
  174. data/scarpe-components/test/test_segmented_app_files.rb +8 -6
  175. data/scarpegen.rb +14 -14
  176. data/sig/scarpe.rbs +1 -1
  177. data/templates/basic_class_template.erb +13 -14
  178. data/templates/class_template_with_event_bind.erb +4 -4
  179. data/templates/class_template_with_shapes.erb +8 -17
  180. data/templates/example_template.erb +1 -1
  181. data/templates/module_template.erb +4 -4
  182. data/templates/webview_template.erb +3 -2
  183. metadata +113 -55
  184. data/examples/legacy/not_checked/shoes-contrib/elements/image-icon.rb +0 -3
  185. data/lacci/lib/shoes/widget.rb +0 -218
  186. data/lacci/lib/shoes/widgets/alert.rb +0 -19
  187. data/lacci/lib/shoes/widgets/arc.rb +0 -51
  188. data/lacci/lib/shoes/widgets/button.rb +0 -35
  189. data/lacci/lib/shoes/widgets/font.rb +0 -14
  190. data/lacci/lib/shoes/widgets/link.rb +0 -25
  191. data/lacci/lib/shoes/widgets/list_box.rb +0 -25
  192. data/lacci/lib/shoes/widgets/para.rb +0 -68
  193. data/lacci/lib/shoes/widgets/radio.rb +0 -35
  194. data/lacci/lib/shoes/widgets/star.rb +0 -44
  195. data/lacci/lib/shoes/widgets/subscription_item.rb +0 -60
  196. data/lacci/lib/shoes/widgets/text_widget.rb +0 -51
  197. data/lacci/lib/shoes/widgets/video.rb +0 -15
  198. data/lacci/lib/shoes/widgets.rb +0 -29
  199. data/lib/scarpe/wv/alert.rb +0 -66
  200. data/lib/scarpe/wv/background.rb +0 -27
  201. data/lib/scarpe/wv/border.rb +0 -24
  202. data/lib/scarpe/wv/control_interface_test.rb +0 -238
  203. data/lib/scarpe/wv/dimensions.rb +0 -22
  204. data/lib/scarpe/wv/font.rb +0 -36
  205. data/lib/scarpe/wv/html.rb +0 -108
  206. data/lib/scarpe/wv/spacing.rb +0 -41
  207. data/lib/scarpe/wv/text_widget.rb +0 -30
  208. /data/examples/legacy/not_checked/{expert → shoes-contrib/basic}/definr.rb +0 -0
  209. /data/examples/legacy/not_checked/{expert → shoes-contrib/basic}/funnies.rb +0 -0
  210. /data/examples/legacy/not_checked/shoes-contrib/{elements → basic}/list_box-select-class.rb +0 -0
  211. /data/examples/legacy/{not_checked/shoes-contrib/basic → working/simple}/basic-edit-box.rb +0 -0
  212. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/basic-fps.rb +0 -0
  213. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/border-cat.rb +0 -0
  214. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/check-mate.rb +0 -0
  215. /data/examples/legacy/{not_checked/shoes-contrib/manipulation → working/simple}/clear-slot.rb +0 -0
  216. /data/examples/legacy/{not_checked/shoes-contrib/basic → working/simple}/clock.rb +0 -0
  217. /data/examples/legacy/{not_checked/shoes-contrib/basic → working/simple}/gradient-shoes.rb +0 -0
  218. /data/examples/legacy/{not_checked/shoes-contrib/basic → working/simple}/list_box-shape-report.rb +0 -0
  219. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/list_box.rb +0 -0
  220. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/phat-button.rb +0 -0
  221. /data/examples/legacy/{not_checked/shoes-contrib → working}/simple/simple-calc.rb +0 -0
  222. /data/examples/legacy/{not_checked/shoes-contrib/position → working/simple}/stack-width.rb +0 -0
  223. /data/examples/legacy/{not_checked/shoes-contrib/elements → working/simple}/width-introspec.rb +0 -0
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Scarpe::Components::Calzini
4
+ def arc_element(props, &block)
5
+ dc = props["draw_context"] || {}
6
+ rotate = dc["rotate"]
7
+ HTML.render do |h|
8
+ h.div(id: html_id, style: arc_style(props)) do
9
+ h.svg(width: props["width"], height: props["height"]) do
10
+ h.path(d: arc_path(props), transform: "rotate(#{rotate}, #{props["width"] / 2}, #{props["height"] / 2})")
11
+ end
12
+ block.call(h) if block_given?
13
+ end
14
+ end
15
+ end
16
+
17
+ def rect_element(props)
18
+ dc = props["draw_context"] || {}
19
+ rotate = dc["rotate"]
20
+ HTML.render do |h|
21
+ h.div(id: html_id, style: drawable_style(props)) do
22
+ width = props["width"].to_i
23
+ height = props["height"].to_i
24
+ if props["curve"]
25
+ width += 2 * props["curve"].to_i
26
+ height += 2 * props["curve"].to_i
27
+ end
28
+ h.svg(width:, height:) do
29
+ attrs = { x: props["left"], y: props["top"], width: props["width"], height: props["height"], style: rect_svg_style(props) }
30
+ attrs[:rx] = props["curve"] if props["curve"]
31
+
32
+ h.rect(**attrs, transform: "rotate(#{rotate} #{width / 2} #{height / 2})")
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ def line_element(props)
39
+ HTML.render do |h|
40
+ h.div(id: html_id, style: line_div_style(props)) do
41
+ h.svg(width: props["x2"], height: props["y2"]) do
42
+ h.line(x1: props["left"], y1: props["top"], x2: props["x2"], y2: props["y2"], style: line_svg_style(props))
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def star_element(props, &block)
49
+ dc = props["draw_context"] || {}
50
+ fill = dc["fill"]
51
+ stroke = dc["stroke"]
52
+ fill = "black" if !fill || fill == ""
53
+ stroke = "black" if !stroke || stroke == ""
54
+ HTML.render do |h|
55
+ h.div(id: html_id, style: star_style(props)) do
56
+ h.svg(width: props["outer"], height: props["outer"], style: "fill:#{fill}") do
57
+ h.polygon(points: star_points(props), style: "stroke:#{stroke};stroke-width:2")
58
+ end
59
+ block.call(h) if block_given?
60
+ end
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ def arc_style(props)
67
+ drawable_style(props).merge({
68
+ left: "#{props["left"]}px",
69
+ top: "#{props["top"]}px",
70
+ width: "#{props["width"]}px",
71
+ height: "#{props["height"]}px",
72
+ })
73
+ end
74
+
75
+ def arc_path(props)
76
+ center_x = props["width"] / 2
77
+ center_y = props["height"] / 2
78
+ radius_x = props["width"] / 2
79
+ radius_y = props["height"] / 2
80
+ start_angle_degrees = radians_to_degrees(props["angle1"]) % 360
81
+ end_angle_degrees = radians_to_degrees(props["angle2"]) % 360
82
+ large_arc_flag = (end_angle_degrees - start_angle_degrees) % 360 > 180 ? 1 : 0
83
+
84
+ "M#{center_x} #{center_y} L#{props["width"]} #{center_y} " \
85
+ "A#{radius_x} #{radius_y} 0 #{large_arc_flag} 0 " \
86
+ "#{center_x + radius_x * Math.cos(degrees_to_radians(end_angle_degrees))} " \
87
+ "#{center_y + radius_y * Math.sin(degrees_to_radians(end_angle_degrees))} Z"
88
+ end
89
+
90
+ def line_div_style(props)
91
+ drawable_style(props).merge({
92
+ left: "#{props["left"]}px",
93
+ top: "#{props["top"]}px",
94
+ })
95
+ end
96
+
97
+ def line_svg_style(props)
98
+ stroke = if props["draw_context"] && !props["draw_context"]["stroke"].to_s.empty?
99
+ (props["draw_context"]["stroke"]).to_s
100
+ else
101
+ "black"
102
+ end
103
+ {
104
+
105
+ "stroke": stroke,
106
+ "stroke-width": "4",
107
+ }.compact
108
+ end
109
+
110
+ def rect_svg_style(props)
111
+ {
112
+ stroke: (props["draw_context"] || {})["stroke"],
113
+ #"stroke-width": "1",
114
+ }.compact
115
+ end
116
+
117
+ def star_style(props)
118
+ drawable_style(props).merge({
119
+ width: dimensions_length(props["width"]),
120
+ height: dimensions_length(props["height"]),
121
+ }).compact
122
+ end
123
+
124
+ def star_points(props)
125
+ angle = 2 * Math::PI / props["points"]
126
+ coordinates = []
127
+
128
+ props["points"].times do |i|
129
+ outer_angle = i * angle
130
+ inner_angle = outer_angle + angle / 2
131
+
132
+ coordinates.concat(star_get_coordinates(outer_angle, inner_angle, props))
133
+ end
134
+
135
+ coordinates.join(",")
136
+ end
137
+
138
+ def star_get_coordinates(outer_angle, inner_angle, props)
139
+ outer_x = props["outer"] / 2 + Math.cos(outer_angle) * props["outer"] / 2
140
+ outer_y = props["outer"] / 2 + Math.sin(outer_angle) * props["outer"] / 2
141
+
142
+ inner_x = props["outer"] / 2 + Math.cos(inner_angle) * props["inner"] / 2
143
+ inner_y = props["outer"] / 2 + Math.sin(inner_angle) * props["inner"] / 2
144
+
145
+ [outer_x, outer_y, inner_x, inner_y]
146
+ end
147
+
148
+ def arrow_element(props)
149
+ left = props["left"]
150
+ top = props["top"]
151
+ width = props["width"]
152
+ end_x = left + width
153
+ end_y = top
154
+ stroke_width = width / 2
155
+ dc = props["draw_context"] || {}
156
+ fill = dc["fill"]
157
+ stroke = dc["stroke"]
158
+ rotate = dc["rotate"]
159
+ fill = "black" if !fill || fill == ""
160
+ stroke = "black" if !stroke || stroke == ""
161
+
162
+ stroke_width = width / 4
163
+
164
+ HTML.render do |h|
165
+ h.div(id: html_id, style: arrow_div_style(props)) do
166
+ h.svg do
167
+ h.defs do
168
+ h.marker(
169
+ id: "head",
170
+ viewBox: "0 0 70 70",
171
+ markerWidth: stroke_width.to_s,
172
+ markerHeight: stroke_width.to_s,
173
+ refX: "5",
174
+ refY: "5",
175
+ orient: "auto-start-reverse",
176
+ ) do
177
+ h.path(d: "M 0 0 L 10 5 L 0 10 z", fill: fill.to_s)
178
+ end
179
+ end
180
+
181
+ h.line(
182
+ x2: left.to_s,
183
+ y2: top.to_s,
184
+ x1: end_x.to_s,
185
+ y1: end_y.to_s,
186
+ fill: fill.to_s,
187
+ stroke: stroke.to_s,
188
+ "stroke-width" => stroke_width.to_s,
189
+ "marker-end" => "url(#head)",
190
+ transform: "rotate(#{rotate}, #{left + width / 2}, #{top})",
191
+ )
192
+ end
193
+ end
194
+ end
195
+ end
196
+ def arrow_div_style(props)
197
+ drawable_style(props).merge({
198
+ position: "absolute",
199
+ left: "#{props["left"]}px",
200
+ top: "#{props["top"]}px",
201
+ })
202
+ end
203
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Scarpe::Components::Calzini
4
+ def button_element(props)
5
+ HTML.render do |h|
6
+ h.button(
7
+ id: html_id,
8
+ onclick: handler_js_code("click"),
9
+ onmouseover: handler_js_code("hover"),
10
+ style: button_style(props),
11
+ title: props["tooltip"],
12
+ ) do
13
+ props["text"]
14
+ end
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def button_style(props)
21
+ styles = drawable_style(props)
22
+
23
+ styles[:"background-color"] = props["color"] if props["color"]
24
+ styles[:"padding-top"] = props["padding_top"] if props["padding_top"]
25
+ styles[:"padding-bottom"] = props["padding_bottom"] if props["padding_bottom"]
26
+ styles[:color] = props["text_color"] if props["text_color"]
27
+ styles[:width] = dimensions_length(props["width"]) if props["width"]
28
+ styles[:height] = dimensions_length(props["height"]) if props["height"]
29
+ styles[:"font-size"] = props["font_size"] if props["font_size"]
30
+
31
+ styles[:top] = dimensions_length(props["top"]) if props["top"]
32
+ styles[:left] = dimensions_length(props["left"]) if props["left"]
33
+ styles[:position] = "absolute" if props["top"] || props["left"]
34
+ styles[:"font-size"] = dimensions_length(text_size(props["size"])) if props["size"]
35
+ styles[:"font-family"] = props["font"] if props["font"]
36
+
37
+ styles
38
+ end
39
+ end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Scarpe::Components::Calzini
4
+ def check_element(props)
5
+ HTML.render do |h|
6
+ h.input type: :checkbox,
7
+ id: html_id,
8
+ onclick: handler_js_code("click"),
9
+ value: props["text"],
10
+ checked: props["checked"],
11
+ style: drawable_style(props)
12
+ end
13
+ end
14
+
15
+ def edit_box_element(props)
16
+ oninput = handler_js_code("change", "this.value")
17
+
18
+ HTML.render do |h|
19
+ h.textarea(id: html_id, oninput: oninput, style: edit_box_style(props)) { props["text"] }
20
+ end
21
+ end
22
+
23
+ def edit_line_element(props)
24
+ oninput = handler_js_code("change", "this.value")
25
+
26
+ HTML.render do |h|
27
+ h.input(id: html_id, oninput: oninput, value: props["text"], style: edit_line_style(props))
28
+ end
29
+ end
30
+
31
+ def image_element(props)
32
+ style = image_style(props)
33
+
34
+ if props["click"]
35
+ HTML.render do |h|
36
+ h.a(id: html_id, href: props["click"]) { h.img(id: html_id, src: props["url"], style:) }
37
+ end
38
+ else
39
+ HTML.render do |h|
40
+ h.img(id: html_id, src: props["url"], style:)
41
+ end
42
+ end
43
+ end
44
+
45
+ def list_box_element(props)
46
+ onchange = handler_js_code("change", "this.options[this.selectedIndex].value")
47
+
48
+ # Is this useful at all? Is it overridden below completely?
49
+ option_attrs = { value: nil, selected: false }
50
+
51
+ HTML.render do |h|
52
+ h.select(id: html_id, onchange:, style: list_box_style(props)) do
53
+ (props["items"] || []).each do |item|
54
+ option_attrs = {
55
+ value: item,
56
+ }
57
+ if item == props["choose"]
58
+ option_attrs[:selected] = "true"
59
+ end
60
+ h.option(**option_attrs) do
61
+ item
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ def radio_element(props)
69
+ # This is wrong - need to default to the parent slot -- maybe its linkable ID?
70
+ group_name = props["group"] || "no_group"
71
+
72
+ HTML.render do |h|
73
+ h.input(
74
+ type: :radio,
75
+ id: html_id,
76
+ onclick: handler_js_code("click"),
77
+ name: group_name,
78
+ value: props["text"],
79
+ checked: props["checked"],
80
+ style: drawable_style(props),
81
+ )
82
+ end
83
+ end
84
+
85
+ def video_element(props)
86
+ HTML.render do |h|
87
+ h.video(id: html_id, style: drawable_style(props), controls: true) do
88
+ h.source(src: @url, type: props["format"])
89
+ end
90
+ end
91
+ end
92
+
93
+ def progress_element(props)
94
+ HTML.render do |h|
95
+ h.progress(
96
+ id: html_id,
97
+ style: drawable_style(props),
98
+ role: "progressbar",
99
+ "aria-valuenow": props["fraction"],
100
+ "aria-valuemin": 0.0,
101
+ "aria-valuemax": 1.0,
102
+ max: 1,
103
+ value: props["fraction"],
104
+ )
105
+ end
106
+ end
107
+
108
+ private
109
+
110
+ def edit_box_style(props)
111
+ drawable_style(props).merge({
112
+ height: dimensions_length(props["height"]),
113
+ width: dimensions_length(props["width"]),
114
+ }.compact)
115
+ end
116
+
117
+ def edit_line_style(props)
118
+ styles = drawable_style(props)
119
+
120
+ styles[:width] = dimensions_length(props["width"]) if props["width"]
121
+
122
+ styles
123
+ end
124
+
125
+ def image_style(props)
126
+ styles = drawable_style(props)
127
+
128
+ styles[:width] = dimensions_length(props["width"]) if props["width"]
129
+ styles[:height] = dimensions_length(props["height"]) if props["height"]
130
+
131
+ styles[:top] = dimensions_length(props["top"]) if props["top"]
132
+ styles[:left] = dimensions_length(props["left"]) if props["left"]
133
+ styles[:position] = "absolute" if props["top"] || props["left"]
134
+
135
+ styles
136
+ end
137
+
138
+ def list_box_style(props)
139
+ styles = drawable_style(props)
140
+
141
+ styles[:height] = dimensions_length(props["height"]) if props["height"]
142
+ styles[:width] = dimensions_length(props["width"]) if props["width"]
143
+
144
+ styles
145
+ end
146
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Scarpe::Components::Calzini
4
+ # para_element is a bit of a hard one, since it does not-entirely-trivial
5
+ # mapping between display objects and IDs. But we don't want Calzini
6
+ # messing with the display service or display objects.
7
+ def para_element(props, &block)
8
+ HTML.render do |h|
9
+ h.p(**para_options(props), &block)
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def para_options(props)
16
+ (props["html_attributes"] || {}).merge(id: html_id, style: para_style(props))
17
+ end
18
+
19
+ def para_style(props)
20
+ drawable_style(props).merge({
21
+ color: rgb_to_hex(props["stroke"]),
22
+ "font-size": para_font_size(props),
23
+ "font-family": props["font"],
24
+ }.compact)
25
+ end
26
+
27
+ def para_font_size(props)
28
+ return nil unless props["size"]
29
+
30
+ sz = props["size"].to_s
31
+ font_size = SIZES[sz.to_sym] || sz.to_i
32
+
33
+ dimensions_length(font_size)
34
+ end
35
+ end
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Scarpe::Components::Calzini
4
+ def slot_element(props, &block)
5
+ HTML.render do |h|
6
+ h.div((props["html_attributes"] || {}).merge(id: html_id, style: slot_style(props)), &block)
7
+ end
8
+ end
9
+
10
+ def flow_element(props, &block)
11
+ HTML.render do |h|
12
+ h.div((props["html_attributes"] || {}).merge(id: html_id, style: flow_style(props)), &block)
13
+ end
14
+ end
15
+
16
+ def stack_element(props, &block)
17
+ HTML.render do |h|
18
+ h.div((props["html_attributes"] || {}).merge(id: html_id, style: stack_style(props)), &block)
19
+ end
20
+ end
21
+
22
+ def documentroot_element(props, &block)
23
+ HTML.render do |h|
24
+ # DocumentRoot rendering intentionally uses flow styles.
25
+ h.div((props["html_attributes"] || {}).merge(id: html_id, style: flow_style(props)), &block)
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def slot_style(props)
32
+ styles = drawable_style(props)
33
+ styles = background_style(props, styles)
34
+ styles = border_style(props, styles)
35
+ styles = spacing_styles_for_attr("margin", props, styles)
36
+ styles = spacing_styles_for_attr("padding", props, styles)
37
+
38
+ styles[:width] = dimensions_length(props["width"]) if props["width"]
39
+ styles[:height] = dimensions_length(props["height"]) if props["height"]
40
+
41
+ styles
42
+ end
43
+
44
+ def flow_style(props)
45
+ {
46
+ display: "flex",
47
+ "flex-direction": "row",
48
+ "flex-wrap": "wrap",
49
+ "align-content": "flex-start",
50
+ "justify-content": "flex-start",
51
+ "align-items": "flex-start",
52
+ }.merge(slot_style(props))
53
+ end
54
+
55
+ def stack_style(props)
56
+ {
57
+ display: "flex",
58
+ "flex-direction": "column",
59
+ "align-content": "flex-start",
60
+ "justify-content": "flex-start",
61
+ "align-items": "flex-start",
62
+ overflow: props["scroll"] ? "auto" : nil,
63
+ }.compact.merge(slot_style(props))
64
+ end
65
+
66
+ def border_style(props, styles)
67
+ bc = props["border_color"]
68
+ return styles unless bc
69
+
70
+ opts = props["options"] || {}
71
+
72
+ border_style_hash = case bc
73
+ when Range
74
+ { "border-image": "linear-gradient(45deg, #{bc.first}, #{bc.last})" }
75
+ when Array
76
+ { "border-color": "rgba(#{bc.join(", ")})" }
77
+ else
78
+ { "border-color": bc }
79
+ end
80
+ styles.merge(
81
+ "border-style": "solid",
82
+ "border-width": "#{opts["strokewidth"] || 1}px",
83
+ "border-radius": "#{opts["curve"] || 0}px",
84
+ ).merge(border_style_hash)
85
+ end
86
+
87
+ def background_style(props, styles)
88
+ bc = props["background_color"]
89
+ return styles unless bc
90
+
91
+ color = case bc
92
+ when Array
93
+ "rgba(#{bc.join(", ")})"
94
+ when Range
95
+ "linear-gradient(45deg, #{bc.first}, #{bc.last})"
96
+ when ->(value) { File.exist?(value) }
97
+ "url(data:image/png;base64,#{encode_file_to_base64(bc)})"
98
+ else
99
+ bc
100
+ end
101
+
102
+ styles.merge(background: color)
103
+ end
104
+
105
+ SPACING_DIRECTIONS = [:left, :right, :top, :bottom]
106
+
107
+ # We extract the appropriate margin and padding from the margin and
108
+ # padding properties. If there are no margin or padding properties,
109
+ # we fall back to props["options"] margin or padding, if it exists.
110
+ #
111
+ # Margin or padding (in either props or props["options"]) can be
112
+ # a Hash with directions as keys, or an Array of left/right/top/bottom,
113
+ # or a constant, which means all four are that constant. You can
114
+ # also specify a "margin" plus "margin-top" which is constant but
115
+ # margin-top is overridden, or similar.
116
+ #
117
+ # If any margin or padding property exists in props then we don't
118
+ # check props["options"].
119
+ def spacing_styles_for_attr(attr, props, styles, with_options: true)
120
+ spacing_styles = {}
121
+
122
+ case props[attr]
123
+ when Hash
124
+ props[attr].each do |dir, value|
125
+ spacing_styles[:"#{attr}-#{dir}"] = dimensions_length value
126
+ end
127
+ when Array
128
+ SPACING_DIRECTIONS.zip(props[attr]).to_h.compact.each do |dir, value|
129
+ spacing_styles[:"#{attr}-#{dir}"] = dimensions_length(value)
130
+ end
131
+ when String, Numeric
132
+ spacing_styles[attr.to_sym] = dimensions_length(props[attr])
133
+ end
134
+
135
+ SPACING_DIRECTIONS.each do |dir|
136
+ if props["#{attr}_#{dir}"]
137
+ spacing_styles[:"#{attr}-#{dir}"] = dimensions_length props["#{attr}_#{dir}"]
138
+ end
139
+ end
140
+
141
+ unless spacing_styles.empty?
142
+ return styles.merge(spacing_styles)
143
+ end
144
+
145
+ # We should see if there are spacing properties in props["options"],
146
+ # unless we're currently doing that.
147
+ if with_options && props["options"]
148
+ spacing_styles = spacing_styles_for_attr(attr, props["options"], {}, with_options: false)
149
+ styles.merge spacing_styles
150
+ else
151
+ # No "options" or we already checked it? Return the styles we were given.
152
+ styles
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Scarpe::Components::Calzini
4
+ def link_element(props)
5
+ HTML.render do |h|
6
+ h.a(**link_attributes(props)) do
7
+ props["text"]
8
+ end
9
+ end
10
+ end
11
+
12
+ def span_element(props, &block)
13
+ HTML.render do |h|
14
+ h.span(**span_options(props), &block)
15
+ end
16
+ end
17
+
18
+ def code_element(props, &block)
19
+ HTML.render do |h|
20
+ h.code(&block)
21
+ end
22
+ end
23
+
24
+ def em_element(props, &block)
25
+ HTML.render do |h|
26
+ h.em(&block)
27
+ end
28
+ end
29
+
30
+ def strong_element(props, &block)
31
+ HTML.render do |h|
32
+ h.strong(&block)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def link_attributes(props)
39
+ {
40
+ id: html_id,
41
+ href: props["click"],
42
+ onclick: (handler_js_code("click") if props["has_block"]),
43
+ style: drawable_style(props),
44
+ }.compact
45
+ end
46
+
47
+ def span_style(props)
48
+ {
49
+ color: props["stroke"],
50
+ "font-size": span_font_size(props),
51
+ "font-family": props["font"],
52
+ }.compact
53
+ end
54
+
55
+ def span_options(props)
56
+ (props["html_attributes"] || {}).merge(id: html_id, style: span_style(props))
57
+ end
58
+
59
+ def span_font_size(props)
60
+ sz = props["size"]
61
+ font_size = SIZES.key?(sz.to_s.to_sym) ? SIZES[sz.to_s.to_sym] : sz
62
+
63
+ dimensions_length(font_size)
64
+ end
65
+ end