glimmer-dsl-web 0.0.8 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,223 @@
1
+ # Copyright (c) 2023-2024 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer-dsl-web'
23
+
24
+ Address = Struct.new(:full_name, :street, :street2, :city, :state, :zip_code, keyword_init: true) do
25
+ STATES = {
26
+ "AK"=>"Alaska",
27
+ "AL"=>"Alabama",
28
+ "AR"=>"Arkansas",
29
+ "AS"=>"American Samoa",
30
+ "AZ"=>"Arizona",
31
+ "CA"=>"California",
32
+ "CO"=>"Colorado",
33
+ "CT"=>"Connecticut",
34
+ "DC"=>"District of Columbia",
35
+ "DE"=>"Delaware",
36
+ "FL"=>"Florida",
37
+ "GA"=>"Georgia",
38
+ "GU"=>"Guam",
39
+ "HI"=>"Hawaii",
40
+ "IA"=>"Iowa",
41
+ "ID"=>"Idaho",
42
+ "IL"=>"Illinois",
43
+ "IN"=>"Indiana",
44
+ "KS"=>"Kansas",
45
+ "KY"=>"Kentucky",
46
+ "LA"=>"Louisiana",
47
+ "MA"=>"Massachusetts",
48
+ "MD"=>"Maryland",
49
+ "ME"=>"Maine",
50
+ "MI"=>"Michigan",
51
+ "MN"=>"Minnesota",
52
+ "MO"=>"Missouri",
53
+ "MS"=>"Mississippi",
54
+ "MT"=>"Montana",
55
+ "NC"=>"North Carolina",
56
+ "ND"=>"North Dakota",
57
+ "NE"=>"Nebraska",
58
+ "NH"=>"New Hampshire",
59
+ "NJ"=>"New Jersey",
60
+ "NM"=>"New Mexico",
61
+ "NV"=>"Nevada",
62
+ "NY"=>"New York",
63
+ "OH"=>"Ohio",
64
+ "OK"=>"Oklahoma",
65
+ "OR"=>"Oregon",
66
+ "PA"=>"Pennsylvania",
67
+ "PR"=>"Puerto Rico",
68
+ "RI"=>"Rhode Island",
69
+ "SC"=>"South Carolina",
70
+ "SD"=>"South Dakota",
71
+ "TN"=>"Tennessee",
72
+ "TX"=>"Texas",
73
+ "UT"=>"Utah",
74
+ "VA"=>"Virginia",
75
+ "VI"=>"Virgin Islands",
76
+ "VT"=>"Vermont",
77
+ "WA"=>"Washington",
78
+ "WI"=>"Wisconsin",
79
+ "WV"=>"West Virginia",
80
+ "WY"=>"Wyoming"
81
+ }
82
+
83
+ def state_code
84
+ STATES.invert[state]
85
+ end
86
+
87
+ def state_code=(value)
88
+ self.state = STATES[value]
89
+ end
90
+
91
+ def summary
92
+ to_h.values.map(&:to_s).reject(&:empty?).join(', ')
93
+ end
94
+ end
95
+
96
+ # AddressForm Glimmer Web Component (View component)
97
+ #
98
+ # Including Glimmer::Web::Component makes this class a View component and automatically
99
+ # generates a new Glimmer GUI DSL keyword that matches the lowercase underscored version
100
+ # of the name of the class. AddressForm generates address_form keyword, which can be used
101
+ # elsewhere in Glimmer GUI DSL code as done inside AddressPage below.
102
+ class AddressForm
103
+ include Glimmer::Web::Component
104
+
105
+ option :address
106
+
107
+ # Optionally, you can execute code before rendering markup.
108
+ # This is useful for pre-setup of variables (e.g. Models) that you would use in the markup.
109
+ #
110
+ # before_render do
111
+ # end
112
+
113
+ # Optionally, you can execute code after rendering markup.
114
+ # This is useful for post-setup of extra Model listeners that would interact with the
115
+ # markup elements and expect them to be rendered already.
116
+ #
117
+ # after_render do
118
+ # end
119
+
120
+ # markup block provides the content of the
121
+ markup {
122
+ div {
123
+ div(style: 'display: grid; grid-auto-columns: 80px 260px;') { |address_div|
124
+ label('Full Name: ', for: 'full-name-field')
125
+ input(id: 'full-name-field') {
126
+ value <=> [address, :full_name]
127
+ }
128
+
129
+ @somelabel = label('Street: ', for: 'street-field')
130
+ input(id: 'street-field') {
131
+ value <=> [address, :street]
132
+ }
133
+
134
+ label('Street 2: ', for: 'street2-field')
135
+ textarea(id: 'street2-field') {
136
+ value <=> [address, :street2]
137
+ }
138
+
139
+ label('City: ', for: 'city-field')
140
+ input(id: 'city-field') {
141
+ value <=> [address, :city]
142
+ }
143
+
144
+ label('State: ', for: 'state-field')
145
+ select(id: 'state-field') {
146
+ Address::STATES.each do |state_code, state|
147
+ option(value: state_code) { state }
148
+ end
149
+
150
+ value <=> [address, :state_code]
151
+ }
152
+
153
+ label('Zip Code: ', for: 'zip-code-field')
154
+ input(id: 'zip-code-field', type: 'number', min: '0', max: '99999') {
155
+ value <=> [address, :zip_code,
156
+ on_write: :to_s,
157
+ ]
158
+ }
159
+
160
+ style {
161
+ <<~CSS
162
+ #{address_div.selector} * {
163
+ margin: 5px;
164
+ }
165
+ #{address_div.selector} input, #{address_div.selector} select {
166
+ grid-column: 2;
167
+ }
168
+ CSS
169
+ }
170
+ }
171
+
172
+ div(style: 'margin: 5px') {
173
+ inner_text <= [address, :summary,
174
+ computed_by: address.members + ['state_code'],
175
+ ]
176
+ }
177
+ }
178
+ }
179
+ end
180
+
181
+ # AddressPage Glimmer Web Component (View component)
182
+ #
183
+ # This View component represents the main page being rendered,
184
+ # as done by its `render` class method below
185
+ class AddressPage
186
+ include Glimmer::Web::Component
187
+
188
+ before_render do
189
+ @shipping_address = Address.new(
190
+ full_name: 'Johnny Doe',
191
+ street: '3922 Park Ave',
192
+ street2: 'PO BOX 8382',
193
+ city: 'San Diego',
194
+ state: 'California',
195
+ zip_code: '91913',
196
+ )
197
+ @billing_address = Address.new(
198
+ full_name: 'John C Doe',
199
+ street: '123 Main St',
200
+ street2: 'Apartment 3C',
201
+ city: 'San Diego',
202
+ state: 'California',
203
+ zip_code: '91911',
204
+ )
205
+ end
206
+
207
+ markup {
208
+ div {
209
+ h1('Shipping Address')
210
+
211
+ address_form(address: @shipping_address)
212
+
213
+ h1('Billing Address')
214
+
215
+ address_form(address: @billing_address)
216
+ }
217
+ }
218
+ end
219
+
220
+ Document.ready? do
221
+ # renders a top-level (root) AddressPage component
222
+ AddressPage.render
223
+ end
@@ -87,51 +87,55 @@ end
87
87
 
88
88
  @user = User.new
89
89
 
90
- div {
90
+ include Glimmer
91
+
92
+ Document.ready? do
91
93
  div {
92
- label('Number of addresses: ', for: 'address-count-field')
93
- input(id: 'address-count-field', type: 'number', min: 1, max: 3) {
94
- value <=> [@user, :address_count]
94
+ div {
95
+ label('Number of addresses: ', for: 'address-count-field')
96
+ input(id: 'address-count-field', type: 'number', min: 1, max: 3) {
97
+ value <=> [@user, :address_count]
98
+ }
95
99
  }
96
- }
97
-
98
- div {
99
- # Content Data-Binding is used to dynamically (re)generate content of div
100
- # based on changes to @user.addresses, replacing older content on every change
101
- content(@user, :addresses) do
102
- @user.addresses.each do |address|
103
- div {
104
- div(style: 'display: grid; grid-auto-columns: 80px 280px;') { |address_div|
105
- [:name, :street, :city, :state, :zip].each do |attribute|
106
- label(attribute.to_s.capitalize, for: "#{attribute}-field")
107
- input(id: "#{attribute}-field", type: 'text') {
108
- value <=> [address, attribute]
109
- }
110
- end
111
-
112
- div(style: 'grid-column: 1 / span 2;') {
113
- inner_text <= [address, :text]
114
- }
115
-
116
- style {
117
- <<~CSS
118
- #{address_div.selector} {
119
- margin: 10px 0;
120
- }
121
- #{address_div.selector} * {
122
- margin: 5px;
123
- }
124
- #{address_div.selector} label {
125
- grid-column: 1;
100
+
101
+ div {
102
+ # Content Data-Binding is used to dynamically (re)generate content of div
103
+ # based on changes to @user.addresses, replacing older content on every change
104
+ content(@user, :addresses) do
105
+ @user.addresses.each do |address|
106
+ div {
107
+ div(style: 'display: grid; grid-auto-columns: 80px 280px;') { |address_div|
108
+ [:name, :street, :city, :state, :zip].each do |attribute|
109
+ label(attribute.to_s.capitalize, for: "#{attribute}-field")
110
+ input(id: "#{attribute}-field", type: 'text') {
111
+ value <=> [address, attribute]
126
112
  }
127
- #{address_div.selector} input, #{address_div.selector} select {
128
- grid-column: 2;
129
- }
130
- CSS
113
+ end
114
+
115
+ div(style: 'grid-column: 1 / span 2;') {
116
+ inner_text <= [address, :text]
117
+ }
118
+
119
+ style {
120
+ <<~CSS
121
+ #{address_div.selector} {
122
+ margin: 10px 0;
123
+ }
124
+ #{address_div.selector} * {
125
+ margin: 5px;
126
+ }
127
+ #{address_div.selector} label {
128
+ grid-column: 1;
129
+ }
130
+ #{address_div.selector} input, #{address_div.selector} select {
131
+ grid-column: 2;
132
+ }
133
+ CSS
134
+ }
131
135
  }
132
136
  }
133
- }
137
+ end
134
138
  end
135
- end
136
- }
137
- }.render
139
+ }
140
+ }.render
141
+ end
@@ -0,0 +1,156 @@
1
+ require 'glimmer-dsl-web'
2
+
3
+ class AddressForm
4
+ Address = Struct.new(:full_name, :street, :street2, :city, :state, :zip_code, keyword_init: true) do
5
+ def state_code
6
+ STATES.invert[state]
7
+ end
8
+
9
+ def state_code=(value)
10
+ self.state = STATES[value]
11
+ end
12
+
13
+ def summary
14
+ to_h.values.map(&:to_s).reject(&:empty?).join(', ')
15
+ end
16
+ end
17
+
18
+ STATES = {
19
+ "AK"=>"Alaska",
20
+ "AL"=>"Alabama",
21
+ "AR"=>"Arkansas",
22
+ "AS"=>"American Samoa",
23
+ "AZ"=>"Arizona",
24
+ "CA"=>"California",
25
+ "CO"=>"Colorado",
26
+ "CT"=>"Connecticut",
27
+ "DC"=>"District of Columbia",
28
+ "DE"=>"Delaware",
29
+ "FL"=>"Florida",
30
+ "GA"=>"Georgia",
31
+ "GU"=>"Guam",
32
+ "HI"=>"Hawaii",
33
+ "IA"=>"Iowa",
34
+ "ID"=>"Idaho",
35
+ "IL"=>"Illinois",
36
+ "IN"=>"Indiana",
37
+ "KS"=>"Kansas",
38
+ "KY"=>"Kentucky",
39
+ "LA"=>"Louisiana",
40
+ "MA"=>"Massachusetts",
41
+ "MD"=>"Maryland",
42
+ "ME"=>"Maine",
43
+ "MI"=>"Michigan",
44
+ "MN"=>"Minnesota",
45
+ "MO"=>"Missouri",
46
+ "MS"=>"Mississippi",
47
+ "MT"=>"Montana",
48
+ "NC"=>"North Carolina",
49
+ "ND"=>"North Dakota",
50
+ "NE"=>"Nebraska",
51
+ "NH"=>"New Hampshire",
52
+ "NJ"=>"New Jersey",
53
+ "NM"=>"New Mexico",
54
+ "NV"=>"Nevada",
55
+ "NY"=>"New York",
56
+ "OH"=>"Ohio",
57
+ "OK"=>"Oklahoma",
58
+ "OR"=>"Oregon",
59
+ "PA"=>"Pennsylvania",
60
+ "PR"=>"Puerto Rico",
61
+ "RI"=>"Rhode Island",
62
+ "SC"=>"South Carolina",
63
+ "SD"=>"South Dakota",
64
+ "TN"=>"Tennessee",
65
+ "TX"=>"Texas",
66
+ "UT"=>"Utah",
67
+ "VA"=>"Virginia",
68
+ "VI"=>"Virgin Islands",
69
+ "VT"=>"Vermont",
70
+ "WA"=>"Washington",
71
+ "WI"=>"Wisconsin",
72
+ "WV"=>"West Virginia",
73
+ "WY"=>"Wyoming"
74
+ }
75
+
76
+ include Glimmer::Web::Component
77
+
78
+ option :full_name
79
+ option :street
80
+ option :street2
81
+ option :city
82
+ option :state
83
+ option :zip_code
84
+
85
+ attr_reader :address
86
+
87
+ before_render do
88
+ @address = Address.new(
89
+ full_name: full_name,
90
+ street: street,
91
+ street2: street2,
92
+ city: city,
93
+ state: state,
94
+ zip_code: zip_code,
95
+ )
96
+ end
97
+
98
+ markup {
99
+ div {
100
+ div(style: 'display: grid; grid-auto-columns: 80px 260px;') { |address_div|
101
+ label('Full Name: ', for: 'full-name-field')
102
+ input(id: 'full-name-field') {
103
+ value <=> [address, :full_name]
104
+ }
105
+
106
+ @somelabel = label('Street: ', for: 'street-field')
107
+ input(id: 'street-field') {
108
+ value <=> [address, :street]
109
+ }
110
+
111
+ label('Street 2: ', for: 'street2-field')
112
+ textarea(id: 'street2-field') {
113
+ value <=> [address, :street2]
114
+ }
115
+
116
+ label('City: ', for: 'city-field')
117
+ input(id: 'city-field') {
118
+ value <=> [address, :city]
119
+ }
120
+
121
+ label('State: ', for: 'state-field')
122
+ select(id: 'state-field') {
123
+ STATES.each do |state_code, state|
124
+ option(value: state_code) { state }
125
+ end
126
+
127
+ value <=> [address, :state_code]
128
+ }
129
+
130
+ label('Zip Code: ', for: 'zip-code-field')
131
+ input(id: 'zip-code-field', type: 'number', min: '0', max: '99999') {
132
+ value <=> [address, :zip_code,
133
+ on_write: :to_s,
134
+ ]
135
+ }
136
+
137
+ style {
138
+ <<~CSS
139
+ #{address_div.selector} * {
140
+ margin: 5px;
141
+ }
142
+ #{address_div.selector} input, #{address_div.selector} select {
143
+ grid-column: 2;
144
+ }
145
+ CSS
146
+ }
147
+ }
148
+
149
+ div(style: 'margin: 5px') {
150
+ inner_text <= [address, :summary,
151
+ computed_by: address.members + ['state_code'],
152
+ ]
153
+ }
154
+ }
155
+ }
156
+ end
@@ -30,6 +30,7 @@ if RUBY_ENGINE != 'opal'
30
30
  require 'opal-rails'
31
31
  require 'opal-async'
32
32
  require 'opal-jquery'
33
+ require 'glimmer/helpers/glimmer_helper'
33
34
  else
34
35
  # GLIMMER_DSL_OPAL_MISSING = File.join(GLIMMER_DSL_OPAL_ROOT, 'lib', 'glimmer-dsl-opal', 'missing')
35
36
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-web
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Maleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-03 00:00:00.000000000 Z
11
+ date: 2024-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer
@@ -58,28 +58,28 @@ dependencies:
58
58
  requirements:
59
59
  - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: 1.4.1
61
+ version: 1.8.2
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: 1.4.1
68
+ version: 1.8.2
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: opal-rails
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: 2.0.2
75
+ version: 2.0.3
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: 2.0.2
82
+ version: 2.0.3
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: opal-async
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -253,15 +253,18 @@ files:
253
253
  - lib/glimmer-dsl-web/ext/date.rb
254
254
  - lib/glimmer-dsl-web/ext/exception.rb
255
255
  - lib/glimmer-dsl-web/samples/hello/hello_button.rb
256
+ - lib/glimmer-dsl-web/samples/hello/hello_component.rb
256
257
  - lib/glimmer-dsl-web/samples/hello/hello_content_data_binding.rb
257
258
  - lib/glimmer-dsl-web/samples/hello/hello_data_binding.rb
258
259
  - lib/glimmer-dsl-web/samples/hello/hello_form.rb
260
+ - lib/glimmer-dsl-web/samples/hello/hello_glimmer_component_helper/address_form.rb
259
261
  - lib/glimmer-dsl-web/samples/hello/hello_input_date_time.rb
260
262
  - lib/glimmer-dsl-web/samples/hello/hello_world.rb
261
263
  - lib/glimmer-dsl-web/vendor/jquery.js
262
264
  - lib/glimmer/config/opal_logger.rb
263
265
  - lib/glimmer/data_binding/element_binding.rb
264
266
  - lib/glimmer/dsl/web/bind_expression.rb
267
+ - lib/glimmer/dsl/web/component_expression.rb
265
268
  - lib/glimmer/dsl/web/content_data_binding_expression.rb
266
269
  - lib/glimmer/dsl/web/data_binding_expression.rb
267
270
  - lib/glimmer/dsl/web/dsl.rb
@@ -272,8 +275,10 @@ files:
272
275
  - lib/glimmer/dsl/web/property_expression.rb
273
276
  - lib/glimmer/dsl/web/select_expression.rb
274
277
  - lib/glimmer/dsl/web/shine_data_binding_expression.rb
278
+ - lib/glimmer/helpers/glimmer_helper.rb
275
279
  - lib/glimmer/util/proc_tracker.rb
276
280
  - lib/glimmer/web.rb
281
+ - lib/glimmer/web/component.rb
277
282
  - lib/glimmer/web/element_proxy.rb
278
283
  - lib/glimmer/web/event_proxy.rb
279
284
  - lib/glimmer/web/listener_proxy.rb