scarpe-components 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b7067a7b6f0e71d041289334dccf5c0edaae3db689a710450c1d8f585888f74d
4
- data.tar.gz: c73105b84ae8468779ca93c216e7f618213a79086e2c0d7a7470bdece885c2b9
3
+ metadata.gz: 553966daf7d03ffd9c9b0262ea65c8ae0ac2de161b94eeb5d468c0ac5f38a51f
4
+ data.tar.gz: fa7b2161160b5e49bf2bf15f73b5e991ad463a5bbed129cc4efa16d95ced77f6
5
5
  SHA512:
6
- metadata.gz: 8d0be001e64c94d3e82dcfc7dca65cbfe373edfd219905716075cfcb3655b0da9a9fec76cf2323cec7d151b83581b3762d7b7c81d51ba2b34dcc10451b33c4db
7
- data.tar.gz: 78a734af216bf4c7275483258d20508a985782442a1b6700632905d26b6dfccf0a66ca3c752202b41f32893094450681fdfae7e0d832ee08ba43812b300b8427
6
+ metadata.gz: cfe8b66b552128271fea15b7df830b680b12ce833e79725198804bd224394b6fd00dcada10dcd03ecb4f6d9c67b6cb87d8ede6e71d6277b8d181f5d2b985e9ef
7
+ data.tar.gz: b531fe0af1d193f73a7e201afbde322152d659987bad14f51c8af65b65c823ebe330ffc1848f272dca169814dc10105672e3d0bfb617c723a9eb723ef556d44b
data/Gemfile.lock ADDED
@@ -0,0 +1,86 @@
1
+ PATH
2
+ remote: ../lacci
3
+ specs:
4
+ lacci (0.3.0)
5
+ scarpe-components
6
+
7
+ PATH
8
+ remote: .
9
+ specs:
10
+ scarpe-components (0.3.0)
11
+
12
+ GEM
13
+ remote: https://rubygems.org/
14
+ specs:
15
+ ansi (1.5.0)
16
+ ast (2.4.2)
17
+ base64 (0.1.1)
18
+ builder (3.2.4)
19
+ debug (1.8.0)
20
+ irb (>= 1.5.0)
21
+ reline (>= 0.3.1)
22
+ io-console (0.6.0)
23
+ irb (1.8.0)
24
+ rdoc (~> 6.5)
25
+ reline (>= 0.3.6)
26
+ json (2.6.3)
27
+ language_server-protocol (3.17.0.3)
28
+ minitest (5.19.0)
29
+ minitest-reporters (1.6.1)
30
+ ansi
31
+ builder
32
+ minitest (>= 5.0)
33
+ ruby-progressbar
34
+ nokogiri (1.15.4-x86_64-darwin)
35
+ racc (~> 1.4)
36
+ parallel (1.23.0)
37
+ parser (3.2.2.3)
38
+ ast (~> 2.4.1)
39
+ racc
40
+ psych (5.1.0)
41
+ stringio
42
+ racc (1.7.1)
43
+ rainbow (3.1.1)
44
+ rake (13.0.6)
45
+ rdoc (6.5.0)
46
+ psych (>= 4.0.0)
47
+ regexp_parser (2.8.1)
48
+ reline (0.3.8)
49
+ io-console (~> 0.5)
50
+ rexml (3.2.6)
51
+ rubocop (1.56.2)
52
+ base64 (~> 0.1.1)
53
+ json (~> 2.3)
54
+ language_server-protocol (>= 3.17.0)
55
+ parallel (~> 1.10)
56
+ parser (>= 3.2.2.3)
57
+ rainbow (>= 2.2.2, < 4.0)
58
+ regexp_parser (>= 1.8, < 3.0)
59
+ rexml (>= 3.2.5, < 4.0)
60
+ rubocop-ast (>= 1.28.1, < 2.0)
61
+ ruby-progressbar (~> 1.7)
62
+ unicode-display_width (>= 2.4.0, < 3.0)
63
+ rubocop-ast (1.29.0)
64
+ parser (>= 3.2.1.0)
65
+ rubocop-shopify (2.14.0)
66
+ rubocop (~> 1.51)
67
+ ruby-progressbar (1.13.0)
68
+ stringio (3.0.8)
69
+ unicode-display_width (2.4.2)
70
+
71
+ PLATFORMS
72
+ x86_64-darwin-22
73
+
74
+ DEPENDENCIES
75
+ debug
76
+ lacci!
77
+ minitest (~> 5.0)
78
+ minitest-reporters
79
+ nokogiri
80
+ rake (~> 13.0)
81
+ rubocop (~> 1.21)
82
+ rubocop-shopify
83
+ scarpe-components!
84
+
85
+ BUNDLED WITH
86
+ 2.4.14
@@ -3,9 +3,9 @@
3
3
  require "base64"
4
4
  require "uri"
5
5
 
6
- class Scarpe; end
6
+ module Scarpe; end
7
7
  module Scarpe::Components; end
8
- class Scarpe
8
+ module Scarpe
9
9
  module Components::Base64
10
10
  def valid_url?(string)
11
11
  uri = URI.parse(string)
@@ -14,11 +14,7 @@ class Scarpe
14
14
  false
15
15
  end
16
16
 
17
- def encode_file_to_base64(image_filename)
18
- directory_path = File.dirname(__FILE__, 5)
19
-
20
- image_path = File.join(directory_path, image_filename)
21
-
17
+ def encode_file_to_base64(image_path)
22
18
  image_data = File.binread(image_path)
23
19
 
24
20
  encoded_data = ::Base64.strict_encode64(image_data)
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Scarpe::Components::Calzini
4
+ def alert_element(props)
5
+ event = props["event_name"] || "click"
6
+ onclick = handler_js_code(event)
7
+
8
+ HTML.render do |h|
9
+ h.div(id: html_id, style: alert_overlay_style(props)) do
10
+ h.div(style: alert_modal_style) do
11
+ h.div(style: {}) { props["text"] }
12
+ h.button(style: {}, onclick: onclick) { "OK" }
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ # If the whole drawable is hidden, the parent style adds display:none
21
+ def alert_overlay_style(props)
22
+ {
23
+ position: "fixed",
24
+ top: "0",
25
+ left: "0",
26
+ width: "100%",
27
+ height: "100%",
28
+ overflow: "auto",
29
+ "z-index": "1",
30
+ background: "rgba(0,0,0,0.4)",
31
+ display: "flex",
32
+ "align-items": "center",
33
+ "justify-content": "center",
34
+ }.merge(drawable_style(props))
35
+ end
36
+
37
+ def alert_modal_style
38
+ {
39
+ "min-width": "200px",
40
+ "min-height": "50px",
41
+ padding: "10px",
42
+ display: "flex",
43
+ background: "#fefefe",
44
+ "flex-direction": "column",
45
+ "justify-content": "space-between",
46
+ "border-radius": "9px",
47
+ }
48
+ end
49
+ end
@@ -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