glimmer-dsl-web 0.0.8 → 0.0.10

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.
@@ -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