scarpe-components 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.
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