shoelace-rails 0.2.0 → 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: 43863053db02a41a1fd24e9a2b82f72a10ed5ef99e90bedc142b7cb9a3d94696
4
- data.tar.gz: 6615e13ecde994ab1e5c029c84cd3e1bdc5be11a5262fe5b887d0b18b86115e1
3
+ metadata.gz: 6bf02de3fbe6ef35ad4c464e666bd7ace7bf0c2e673b0767afea4d6b87522749
4
+ data.tar.gz: 73abb906c86ffc3f4a945f73f3a97e3cd335c1cb4245b82362cf53c3587619d5
5
5
  SHA512:
6
- metadata.gz: 5fadffcefc1ac4a5be597e5b6274ea8f5463ee375dd535c6b42f4fb34c02fd8ef0c80dfe4fe7bb889c1096968c83d82b6e7ba5c1641dad7c8cf3761b4723447d
7
- data.tar.gz: 56398431cd8865bacaae5daf55a4076b0ab2c5857878a89994c13209fae098273c0fe4d2032b890473b71147074884f476a1dd09f86129e58fcab0810e6e4722
6
+ metadata.gz: 1e7a5bca7b14951f97b54c9de1be69698ceebb63a421be912cc8f692ebec8ed075ebdf58a4fbc9d9200c296e3150ae63f41f6a6a40f62fc368c1a54044905a9b
7
+ data.tar.gz: 5d09b9294065025cb30762a152c3b037739790a8b16ff5e2178bcb98afc0592756447ba0273967450783e11fbfd9863be5e11027a61074ed622e35d380a95dc5
@@ -9,22 +9,24 @@ jobs:
9
9
  strategy:
10
10
  matrix:
11
11
  ruby_version:
12
+ - '3.2'
12
13
  - '3.1'
13
14
  - '3.0'
14
15
  - '2.7'
15
- - 'jruby-9.3.3.0'
16
+ - 'jruby-9.3'
17
+ - 'jruby-9.4'
16
18
  gemfile:
17
19
  - gemfiles/rails_70.gemfile
18
20
  - gemfiles/rails_61.gemfile
19
21
  - gemfiles/rails_60.gemfile
20
22
  exclude:
21
- - ruby_version: 'jruby-9.3.3.0'
23
+ - ruby_version: 'jruby-9.3'
22
24
  gemfile: gemfiles/rails_70.gemfile
23
- runs-on: ubuntu-18.04
25
+ runs-on: ubuntu-22.04
24
26
  env:
25
27
  BUNDLE_GEMFILE: ${{ matrix.gemfile }}
26
28
  steps:
27
- - uses: actions/checkout@v2
29
+ - uses: actions/checkout@v3
28
30
  - name: Set up Ruby
29
31
  uses: ruby/setup-ruby@v1
30
32
  with:
@@ -34,13 +36,13 @@ jobs:
34
36
 
35
37
  system:
36
38
  needs: unit
37
- runs-on: ubuntu-18.04
39
+ runs-on: ubuntu-22.04
38
40
  steps:
39
- - uses: actions/checkout@v2
41
+ - uses: actions/checkout@v3
40
42
  - name: Set up Ruby
41
43
  uses: ruby/setup-ruby@v1
42
44
  with:
43
- ruby-version: 3.1.0
45
+ ruby-version: 3.2.0
44
46
  bundler-cache: true
45
47
  - name: Install dependencies
46
48
  run: |
@@ -53,11 +55,11 @@ jobs:
53
55
 
54
56
  rails_edge:
55
57
  needs: system
56
- runs-on: ubuntu-18.04
58
+ runs-on: ubuntu-22.04
57
59
  env:
58
60
  BUNDLE_GEMFILE: gemfiles/rails_edge.gemfile
59
61
  steps:
60
- - uses: actions/checkout@v2
62
+ - uses: actions/checkout@v3
61
63
  - name: Set up Ruby
62
64
  uses: ruby/setup-ruby@v1
63
65
  with:
@@ -72,11 +74,11 @@ jobs:
72
74
  gemfile:
73
75
  - gemfiles/rails_edge.gemfile
74
76
  - gemfiles/rails_70.gemfile
75
- runs-on: ubuntu-18.04
77
+ runs-on: ubuntu-22.04
76
78
  env:
77
79
  BUNDLE_GEMFILE: ${{ matrix.gemfile }}
78
80
  steps:
79
- - uses: actions/checkout@v2
81
+ - uses: actions/checkout@v3
80
82
  - name: Set up Ruby
81
83
  uses: ruby/setup-ruby@v1
82
84
  with:
@@ -85,13 +87,13 @@ jobs:
85
87
  - run: bundle exec rake || echo "Ruby edge test is done."
86
88
 
87
89
  # browser_tests:
88
- # runs-on: ubuntu-18.04
90
+ # runs-on: ubuntu-22.04
89
91
  # steps:
90
- # - uses: actions/checkout@v2
92
+ # - uses: actions/checkout@v3
91
93
  # - name: Set up Ruby
92
94
  # uses: ruby/setup-ruby@v1
93
95
  # with:
94
- # ruby-version: 3.1.0
96
+ # ruby-version: 3.2.0
95
97
  # bundler-cache: true
96
98
  # - name: Install dependencies
97
99
  # run: |
data/Appraisals CHANGED
@@ -1,5 +1,5 @@
1
1
  appraise "rails_edge" do
2
- git "https://github.com/rails/rails.git" do
2
+ git "https://github.com/rails/rails.git", branch: "main" do
3
3
  gem "rails"
4
4
  gem "railties"
5
5
  gem "activesupport"
data/CHANGELOG.md CHANGED
@@ -1,4 +1,32 @@
1
- ## v0.2.0
1
+ ## v0.3.0
2
+
3
+ _<sup>released at 2023-01-05 08:47:12 UTC</sup>_
4
+
5
+ #### Features
6
+
7
+ - No longer requires the `sl-form` component (`4fdbfa15`)
8
+ - The `#text_area` method now accepts a block (`5092dc1c`)
9
+ - Allow overriding the value attribute for `<sl-select>` (`1f38be73`)
10
+ - Auto-display labels whenever possible (`c1e3a950`)
11
+ - `<sl-select>` now always has a label by default (`f9fb5f0c`)
12
+ - Support Ruby 3.2 (`b286cbc1`)
13
+ - Add `#sl_button_to` (`e1bdedba`)
14
+ - Add `#sl_icon_tag` (`8a2187a2`)
15
+ - Add `#sl_avatar_tag` (`77dccdb2`)
16
+ - Allow using the `Shoelace::FormBuilder` in a cleaner way (`43dea330`)
17
+
18
+ #### Bug Fixes
19
+
20
+ - Fixes a bug where the gem rake tasks are not loaded (`115bfb3d`)
21
+ - Fixes a bug where values are not properly passed in to `<sl-textarea>` (`3d163845`)
22
+ - Make sure yarn install is always executed before copying shoelace assets (`98018a27`)
23
+ - Fixes a bug where the `@object` needs to respond to `#errors` (`bb981ed0`)
24
+ - Fixes a bug where the `size` attr is ignored by the `#text_area` method (`8bc4c378`)
25
+ - Fixes a bug where unchecked checkbox values are not captured (`dc658bea`)
26
+
27
+ ## [v0.2.0](https://github.com/yuki24/shoelace-rails/tree/v0.2.0)
28
+
29
+ _<sup>released at 2022-06-24 05:14:01 UTC</sup>_
2
30
 
3
31
  #### Features
4
32
 
data/README.md CHANGED
@@ -4,10 +4,6 @@ The `shoelace-rails` gem adds useful helper methods for [Shoelace.style](https:/
4
4
 
5
5
  ## Installation
6
6
 
7
- This document assumes that you use the [`webpacker`](https://github.com/rails/webpacker) or
8
- the [`jsbundling-rails`](https://github.com/rails/jsbundling-rails) gem. You may have to tweak the examples here if
9
- you do not use it. However, the principle here should be the same regardless of the JS bundler you use.
10
-
11
7
  Add this line to your application's Gemfile:
12
8
 
13
9
  ```ruby
@@ -70,7 +66,11 @@ Shoelace icons are automatically set up to load properly, so you don't need to a
70
66
 
71
67
  ## View Helpers
72
68
 
73
- As explained above, this gem provides drop-in replacements to. Here is a short example of how the form helper works:
69
+ As explained above, this gem provides drop-in replacements to Rails view helpers.
70
+
71
+ ### Form Helpers
72
+
73
+ The `sl_form_with` or `sl_form_for` method could be used to generate a form with the Shoelace components:
74
74
 
75
75
  ```erb
76
76
  <%= sl_form_for @user do |form| %>
@@ -115,6 +115,81 @@ And this code will produce:
115
115
  </form>
116
116
  ```
117
117
 
118
+ #### Using The `sl-select` component with `multiple`
119
+
120
+ TDB
121
+
122
+ #### Using the Shoelace FormBuilder with other gems
123
+
124
+ Sometimes you want to use the Shoelace FormBuilder with other gems, such as [ransack](https://github.com/activerecord-hackery/ransack).
125
+ In this case, you can not use the `sl_form_for` or `sl_form_with` methods in tandem with `ransack`, but you can use
126
+ the `Shoelace::FormBuilder` with e.g. [the `search_form_for` method](https://activerecord-hackery.github.io/ransack/getting-started/simple-mode/#form-helper):
127
+
128
+ ```erb
129
+ <%= search_form_for @q, builder: Shoelace::FormBuilder do |form| %>
130
+ ...
131
+ <% end %>
132
+ ```
133
+
134
+ ### Tag Helpers
135
+
136
+ #### `#sl_avatar_tag`
137
+
138
+ The `@sl_avatar_tag` method behaves just like the `image_tag` method.
139
+
140
+ ```erb
141
+ <%= sl_avatar_tag "/path/to/image.jpg" %>
142
+ ```
143
+
144
+ Will produce:
145
+
146
+ ```html
147
+ <sl-avatar image="/path/to/image.jpg"></sl-avatar>
148
+ ```
149
+
150
+ #### `#sl_button_to`
151
+
152
+ The `sl_button_to` method behaves just like the `link_to` method. Note that this is slightly different from the
153
+ built-in `button_to` method.
154
+
155
+ Without a block:
156
+
157
+ ```erb
158
+ <%= sl_button_to "Next Page", "/components?page=2" %>
159
+ ```
160
+
161
+ ```html
162
+ <sl-button href="/components?page=2">
163
+ Next Page
164
+ </sl-button>
165
+ ```
166
+
167
+ With a block:
168
+
169
+ ```erb
170
+ <%= sl_button_to "/components?page=2" do %>
171
+ Next Page
172
+ <% end %>
173
+ ```
174
+
175
+ ```html
176
+ <sl-button href="/components?page=2">
177
+ Next Page
178
+ </sl-button>
179
+ ```
180
+
181
+ #### `#sl_icon_tag`
182
+
183
+ The `sl_icon_tag` method takes the `name` attribute value as the first argument:
184
+
185
+ ```erb
186
+ <%= sl_icon_tag "apple" %>
187
+ ```
188
+
189
+ ```html
190
+ <sl-icon name="apple"></sl-icon>
191
+ ```
192
+
118
193
  ## Development
119
194
 
120
195
  1. Run `bundle install`
@@ -2,11 +2,8 @@
2
2
 
3
3
  module Shoelace
4
4
  module FormHelper
5
- mattr_accessor :use_sl_form_tag
6
- self.use_sl_form_tag = false
7
-
8
- mattr_accessor :remote_form
9
- self.remote_form = false
5
+ mattr_accessor :invalid_input_class_name
6
+ self.invalid_input_class_name = nil
10
7
 
11
8
  class ShoelaceInputField < ActionView::Helpers::Tags::TextField #:nodoc:
12
9
  attr_reader :field_type
@@ -24,7 +21,8 @@ module Shoelace
24
21
 
25
22
  options["size"] = options["maxlength"] unless options.key?("size")
26
23
  options["type"] ||= field_type
27
- options["invalid"] = options.fetch("invalid") { @object.errors[@method_name].presence }
24
+ options["class"] ||= [options["class"], Shoelace::FormHelper.invalid_input_class_name].compact.join(" ") if @object.respond_to?(:errors) && @object.errors[@method_name].present?
25
+
28
26
  add_default_name_and_id(options)
29
27
 
30
28
  @template_object.content_tag('sl-input', '', options, &block)
@@ -68,10 +66,12 @@ module Shoelace
68
66
  end
69
67
 
70
68
  class ShoelaceTextArea < ActionView::Helpers::Tags::TextArea #:nodoc:
71
- def content_tag(tag_name, content, options)
72
- options[:value] = content if content.present?
69
+ def render(&block)
70
+ options = @options.stringify_keys
71
+ options["value"] = options.fetch("value") { value_before_type_cast }
72
+ add_default_name_and_id(options)
73
73
 
74
- tag_name.to_s == 'textarea' ? super('sl-textarea', '', options) : super
74
+ @template_object.content_tag("sl-textarea", '', options, &block)
75
75
  end
76
76
  end
77
77
 
@@ -86,7 +86,7 @@ module Shoelace
86
86
 
87
87
  def select_content_tag(option_tags, _options, html_options)
88
88
  html_options = html_options.stringify_keys
89
- html_options['value']= value
89
+ html_options['value'] ||= value
90
90
  add_default_name_and_id(html_options)
91
91
 
92
92
  @template_object.content_tag("sl-select", option_tags, html_options)
@@ -100,7 +100,7 @@ module Shoelace
100
100
 
101
101
  def select_content_tag(option_tags, _options, html_options)
102
102
  html_options = html_options.stringify_keys
103
- html_options['value']= value
103
+ html_options['value'] ||= value
104
104
  add_default_name_and_id(html_options)
105
105
 
106
106
  @template_object.content_tag("sl-select", option_tags, html_options)
@@ -120,10 +120,18 @@ module Shoelace
120
120
  add_default_name_and_id(options)
121
121
  end
122
122
 
123
- if block_given?
124
- @template_object.content_tag('sl-checkbox', '', options, &block)
123
+ include_hidden = options.delete("include_hidden") { true }
124
+
125
+ sl_checkbox_tag = if block_given?
126
+ @template_object.content_tag('sl-checkbox', '', options, &block)
127
+ else
128
+ @template_object.content_tag('sl-checkbox', @method_name.to_s.humanize, options)
129
+ end
130
+
131
+ if include_hidden
132
+ hidden_field_for_checkbox(options) + sl_checkbox_tag
125
133
  else
126
- @template_object.content_tag('sl-checkbox', @method_name.to_s.humanize, options)
134
+ sl_checkbox_tag
127
135
  end
128
136
  end
129
137
  end
@@ -198,7 +206,7 @@ module Shoelace
198
206
  alias color_picker color_field
199
207
 
200
208
  def range_field(method, **options)
201
- ShoelaceRange.new(object_name, method, @template, options.with_defaults(object: @object)).render
209
+ ShoelaceRange.new(object_name, method, @template, options.with_defaults(object: @object, label: method.to_s.humanize)).render
202
210
  end
203
211
  alias range range_field
204
212
 
@@ -207,8 +215,8 @@ module Shoelace
207
215
  end
208
216
  alias switch switch_field
209
217
 
210
- def text_area(method, **options)
211
- ShoelaceTextArea.new(object_name, method, @template, options.with_defaults(object: @object, resize: 'auto')).render
218
+ def text_area(method, **options, &block)
219
+ ShoelaceTextArea.new(object_name, method, @template, options.with_defaults(object: @object, label: method.to_s.humanize, resize: 'auto')).render(&block)
212
220
  end
213
221
 
214
222
  def check_box(method, options = {}, checked_value = "1", unchecked_value = "0", &block)
@@ -216,11 +224,11 @@ module Shoelace
216
224
  end
217
225
 
218
226
  def select(method, choices = nil, options = {}, html_options = {}, &block)
219
- ShoelaceSelect.new(object_name, method, @template, choices, options.with_defaults(object: @object), html_options, &block).render
227
+ ShoelaceSelect.new(object_name, method, @template, choices, options.with_defaults(object: @object), html_options.with_defaults(label: method.to_s.humanize), &block).render
220
228
  end
221
229
 
222
230
  def collection_select(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
223
- ShoelaceCollectionSelect.new(object_name, method, @template, collection, value_method, text_method, options.with_defaults(object: @object), html_options, &block).render
231
+ ShoelaceCollectionSelect.new(object_name, method, @template, collection, value_method, text_method, options.with_defaults(object: @object), html_options.with_defaults(label: method.to_s.humanize), &block).render
224
232
  end
225
233
 
226
234
  def collection_radio_buttons(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
@@ -234,118 +242,19 @@ module Shoelace
234
242
  end
235
243
  end
236
244
 
237
- DEFAULT_FORM_PARAMETERS = {
238
- builder: ShoelaceFormBuilder,
239
- data: {
240
- remote: true,
241
- }
242
- }
243
-
244
- DEFAULT_TURBO_FORM_PARAMETERS = {
245
- builder: ShoelaceFormBuilder,
246
- }
247
-
245
+ DEFAULT_FORM_PARAMETERS = { builder: ShoelaceFormBuilder }
248
246
  DIVIDER_TAG = "<sl-divider></sl-divider>".html_safe
249
- OPENING_SL_FORM_TAG = '<sl-form'.html_safe
250
- CLOSING_SL_FORM_TAG = '</sl-form>'.html_safe
251
- OPENING_SL_TURBO_FORM_TAG = '<sl-turbo-form'.html_safe
252
- CLOSING_SL_TURBO_FORM_TAG = '</sl-turbo-form>'.html_safe
253
247
 
254
- private_constant :DEFAULT_FORM_PARAMETERS, :DIVIDER_TAG, :OPENING_SL_FORM_TAG, :CLOSING_SL_FORM_TAG, :OPENING_SL_TURBO_FORM_TAG, :CLOSING_SL_TURBO_FORM_TAG
248
+ private_constant :DEFAULT_FORM_PARAMETERS, :DIVIDER_TAG
255
249
 
256
250
  def sl_form_for(*args, **options, &block)
257
- form_params = if ::Shoelace::FormHelper.remote_form
258
- DEFAULT_FORM_PARAMETERS.deep_merge(options)
259
- else
260
- DEFAULT_FORM_PARAMETERS.without(:data).merge(options)
261
- end
262
-
263
- content = form_for(*args, **form_params, &block)
264
-
265
- if ::Shoelace::FormHelper.use_sl_form_tag
266
- content[0, 5] = OPENING_SL_FORM_TAG
267
- content[-7, 7] = CLOSING_SL_FORM_TAG
268
- end
269
-
270
- content
251
+ form_for(*args, **DEFAULT_FORM_PARAMETERS, **options, &block)
271
252
  end
272
253
 
273
254
  def sl_form_with(**args, &block)
274
- content = form_with(**args, **DEFAULT_FORM_PARAMETERS.except(:data), &block)
275
-
276
- if ::Shoelace::FormHelper.use_sl_form_tag
277
- content[0, 5] = OPENING_SL_FORM_TAG
278
- content[-7, 7] = CLOSING_SL_FORM_TAG
279
- end
280
-
281
- content
255
+ form_with(**args, **DEFAULT_FORM_PARAMETERS, &block)
282
256
  end
283
257
 
284
- def sl_form_tag(url_for_options = {}, options = {}, &block)
285
- content = form_tag(url_for_options, options.with_defaults(DEFAULT_FORM_PARAMETERS.except(:builder)), &block)
286
-
287
- if ::Shoelace::FormHelper.use_sl_form_tag
288
- content[0, 5] = OPENING_SL_FORM_TAG
289
- content[-7, 7] = CLOSING_SL_FORM_TAG
290
- end
291
-
292
- content
293
- end
294
-
295
- def sl_turbo_form_for(*args, **options, &block)
296
- content = form_for(*args, **DEFAULT_TURBO_FORM_PARAMETERS.merge(options), &block)
297
-
298
- if ::Shoelace::FormHelper.use_sl_form_tag
299
- content[0, 5] = OPENING_SL_TURBO_FORM_TAG
300
- content[-7, 7] = CLOSING_SL_TURBO_FORM_TAG
301
- end
302
-
303
- content
304
- end
305
-
306
- def sl_turbo_form_with(**args, &block)
307
- content = form_with(**args, **DEFAULT_TURBO_FORM_PARAMETERS, &block)
308
-
309
- if ::Shoelace::FormHelper.use_sl_form_tag
310
- content[0, 5] = OPENING_SL_TURBO_FORM_TAG
311
- content[-7, 7] = CLOSING_SL_TURBO_FORM_TAG
312
- end
313
-
314
- content
315
- end
316
-
317
- def sl_turbo_form_tag(url_for_options = {}, options = {}, &block)
318
- content = form_tag(url_for_options, options.with_defaults(DEFAULT_TURBO_FORM_PARAMETERS.except(:builder)), &block)
319
-
320
- if ::Shoelace::FormHelper.use_sl_form_tag
321
- content[0, 5] = OPENING_SL_TURBO_FORM_TAG
322
- content[-7, 7] = CLOSING_SL_TURBO_FORM_TAG
323
- end
324
-
325
- content
326
- end
327
-
328
- # Creates a generic +<sl-button>+ element.
329
- def sl_button_tag(**attrs, &block)
330
- content_tag("sl-button", **attrs, &block)
331
- end
332
-
333
- # Not providing this helper for now due to potentially untraceable HTML. E.g.
334
- #
335
- # <a href="...">
336
- # <sl-button>...</sl-button>
337
- # </a>
338
- #
339
- # may be trackable and traceable by search bots and scrapers, but:
340
- #
341
- # <sl-button href="...">...</sl-button>
342
- #
343
- # may not be. In the mean time, it is advisable to wrap a <sl-button> tag with an <a> tag.
344
- #
345
- # def sl_button_to(href, **attrs, &block)
346
- # sl_button_tag(href: href, **attrs, &block)
347
- # end
348
-
349
258
  # Creates a submit button with the text value as the caption, with the +submit+ attribute.
350
259
  def sl_submit_tag(value = 'Save changes', **options)
351
260
  options = options.deep_stringify_keys
@@ -448,4 +357,6 @@ module Shoelace
448
357
  RUBY
449
358
  end
450
359
  end
360
+
361
+ FormBuilder = FormHelper::ShoelaceFormBuilder
451
362
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shoelace
4
+ module TagHelper
5
+ # Creates a generic +<sl-button>+ element.
6
+ def sl_button_tag(**attrs, &block)
7
+ content_tag("sl-button", **attrs, &block)
8
+ end
9
+
10
+ # Creates an <sl-button> tag with the href value as the caption.
11
+ def sl_button_to(body, href = nil, **attrs, &block)
12
+ if block_given?
13
+ sl_button_tag(href: body, **(href || {}), **attrs, &block)
14
+ else
15
+ sl_button_tag(href: href, **attrs) { body }
16
+ end
17
+ end
18
+
19
+ def sl_icon_tag(name, **attrs)
20
+ tag.sl_icon(name: name, **attrs)
21
+ end
22
+
23
+ def sl_avatar_tag(source, **attrs, &block)
24
+ tag.sl_avatar(image: source, **attrs, &block)
25
+ end
26
+ end
27
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- git "https://github.com/rails/rails.git" do
5
+ git "https://github.com/rails/rails.git", branch: "main" do
6
6
  gem "rails"
7
7
  gem "railties"
8
8
  gem "activesupport"
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Shoelace
4
4
  module Rails
5
- VERSION = "0.2.0"
5
+ VERSION = "0.3.0"
6
6
  end
7
7
  end
@@ -23,18 +23,32 @@ module Shoelace
23
23
 
24
24
  class Railtie < ::Rails::Railtie #:nodoc:
25
25
  config.shoelace = ActiveSupport::OrderedOptions.new
26
- config.shoelace.use_sl_form_tag = false
27
- config.shoelace.dist_path = "node_modules/@shoelace-style/shoelace/dist"
26
+
27
+ # Path to the shoelace assets.
28
+ config.shoelace.dist_path = "node_modules/@shoelace-style/shoelace/dist"
29
+
30
+ # Class name that is added to a form input when the corresponding attribute has an `ActiveModel` error.
31
+ config.shoelace.invalid_input_class_name = nil
28
32
 
29
33
  initializer "shoelace.use_rack_middleware" do |app|
30
34
  icon_dir = File.join(app.paths["public"].first, "assets/icons")
31
35
 
32
36
  if !Dir.exist?(icon_dir)
33
- path = app.root.join(config.shoelace.dist_path).to_s
37
+ path = app.root.join(app.config.shoelace.dist_path).to_s
34
38
  headers = app.config.public_file_server.headers || {}
35
39
 
36
40
  app.config.middleware.insert_after ActionDispatch::Static, Shoelace::AssetProvider, path, index: "index.html", headers: headers
37
41
  end
38
42
  end
43
+
44
+ initializer "shoelace.form_helper" do |app|
45
+ ActiveSupport.on_load :action_view do
46
+ Shoelace::FormHelper.invalid_input_class_name = app.config.shoelace.invalid_input_class_name
47
+ end
48
+ end
49
+
50
+ rake_tasks do
51
+ load "tasks/shoelace.rake"
52
+ end
39
53
  end
40
54
  end
@@ -12,6 +12,9 @@ namespace :shoelace do
12
12
  end
13
13
  end
14
14
 
15
+ # Make sure `yarn install` is run before running `shoelace:icons:copy`.
16
+ Rake::Task["shoelace:icons:copy"].enhance(["javascript:build"])
17
+
15
18
  if Rake::Task.task_defined?("assets:precompile")
16
19
  Rake::Task["assets:precompile"].enhance(["shoelace:icons:copy"])
17
20
  end
@@ -1,5 +1,5 @@
1
1
  <% locations = { tokyo: "Tokyo", new_york: "New York", london: "London" } %>
2
- <%= sl_turbo_form_for(@user, url: hotwire_forms_path) do |form| %>
2
+ <%= sl_form_for(@user, url: hotwire_forms_path) do |form| %>
3
3
  <div>
4
4
  <%= form.text_field :name do %>
5
5
  <span slot="help-text" style="color: rgb(var(--sl-color-danger-600));">
@@ -21,8 +21,8 @@
21
21
  }
22
22
  </style>
23
23
 
24
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.0.0-beta.65/dist/themes/light.css">
25
- <script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.0.0-beta.65/dist/shoelace.js"></script>
24
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.0.0-beta.87/dist/themes/light.css">
25
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.0.0-beta.87/dist/shoelace.js"></script>
26
26
 
27
27
  <% if request.path.include?("hotwire") %>
28
28
  <%= javascript_pack_tag 'hotwire' %>
@@ -22,7 +22,6 @@ class HotwireFormTest < ApplicationSystemTestCase
22
22
  assert_current_path hotwire_form_path(1)
23
23
  assert_text "Name: Yuki Nishijima"
24
24
  assert_text "Description: I am a human."
25
- assert_text "Color: #ffffff"
26
25
  assert_text "Score: 50"
27
26
  # assert_text "Current City:"
28
27
  assert_text "Previous City: tokyo"
@@ -48,7 +47,6 @@ class HotwireFormTest < ApplicationSystemTestCase
48
47
  assert_current_path hotwire_form_path(1)
49
48
  assert_text "Name: Yuki Nishijima"
50
49
  assert_text "Description: I am a human."
51
- assert_text "Color: #ffffff"
52
50
  assert_text "Score: 50"
53
51
  # assert_text "Current City:"
54
52
  assert_text "Previous City: tokyo"
@@ -22,7 +22,6 @@ class TurbolinksFormTest < ApplicationSystemTestCase
22
22
  assert_current_path turbolinks_forms_path
23
23
  assert_text "Name: Yuki Nishijima"
24
24
  assert_text "Description: I am a human."
25
- assert_text "Color: #ffffff"
26
25
  assert_text "Score: 50"
27
26
  # assert_text "Current City:"
28
27
  assert_text "Previous City: tokyo"
@@ -44,26 +44,12 @@ class FormHelperTest < ActionView::TestCase
44
44
  HTML
45
45
  end
46
46
 
47
- test "#sl_button_tag" do
48
- assert_dom_equal(<<~HTML, sl_button_tag { "Submit" })
49
- <sl-button>Submit</sl-button>
50
- HTML
51
- end
52
-
53
47
  test "#sl_radio_button" do
54
48
  assert_dom_equal(<<~HTML, sl_radio_button(:user, :name, 'userid-314', checked: true) { "Yuki Nishijima" })
55
49
  <sl-radio value="userid-314" checked="checked" name="user[name]" id="user_name_userid-314">Yuki Nishijima</sl-radio>
56
50
  HTML
57
51
  end
58
52
 
59
- test "#sl_form_tag" do
60
- assert_dom_equal(<<~HTML, sl_form_tag("/posts") { })
61
- <form data-remote="true" action="/posts" accept-charset="UTF-8" method="post">
62
- <input name="utf8" type="hidden" value="&#x2713;" #{AUTOCOMPLETE_ATTRIBUTE} />
63
- </sl-form>
64
- HTML
65
- end
66
-
67
53
  test "#sl_form_with" do
68
54
  assert_dom_equal(<<~HTML, sl_form_with(url: "/") {})
69
55
  <form action="/" accept-charset="UTF-8" data-remote="true" method="post">
@@ -80,30 +66,6 @@ class FormHelperTest < ActionView::TestCase
80
66
  HTML
81
67
  end
82
68
 
83
- test "#sl_turbo_form_tag" do
84
- assert_dom_equal(<<~HTML, sl_turbo_form_tag("/posts") { })
85
- <form action="/posts" accept-charset="UTF-8" method="post">
86
- <input name="utf8" type="hidden" value="&#x2713;" #{AUTOCOMPLETE_ATTRIBUTE} />
87
- </form>
88
- HTML
89
- end
90
-
91
- test "#sl_turbo_form_with" do
92
- assert_dom_equal(<<~HTML, sl_turbo_form_with(url: "/") {})
93
- <form action="/" accept-charset="UTF-8" data-remote="true" method="post">
94
- <input name="utf8" type="hidden" value="&#x2713;" #{AUTOCOMPLETE_ATTRIBUTE} />
95
- </form>
96
- HTML
97
- end
98
-
99
- test "#sl_turbo_form_for" do
100
- assert_dom_equal(<<~HTML, sl_turbo_form_for(User.new, url: "/") { })
101
- <form class="new_user" id="new_user" action="/" accept-charset="UTF-8" method="post">
102
- <input name="utf8" type="hidden" value="&#x2713;" #{AUTOCOMPLETE_ATTRIBUTE} />
103
- </form>
104
- HTML
105
- end
106
-
107
69
  test "#text_field" do
108
70
  sl_form_for(User.new, url: "/") do |form|
109
71
  assert_dom_equal <<~HTML, form.text_field(:name)
@@ -195,6 +157,14 @@ class FormHelperTest < ActionView::TestCase
195
157
  test "#range_field" do
196
158
  sl_form_for(User.new, url: "/") do |form|
197
159
  assert_dom_equal <<~HTML, form.range_field(:name)
160
+ <sl-range label="Name" name="user[name]" id="user_name"></sl-range>
161
+ HTML
162
+ end
163
+ end
164
+
165
+ test "#range_field without a label" do
166
+ sl_form_for(User.new, url: "/") do |form|
167
+ assert_dom_equal <<~HTML, form.range_field(:name, label: nil)
198
168
  <sl-range name="user[name]" id="user_name"></sl-range>
199
169
  HTML
200
170
  end
@@ -211,22 +181,92 @@ class FormHelperTest < ActionView::TestCase
211
181
  test "#text_area" do
212
182
  sl_form_for(User.new, url: "/") do |form|
213
183
  assert_dom_equal <<~HTML, form.text_area(:name)
184
+ <sl-textarea label="Name" resize="auto" name="user[name]" id="user_name"></sl-textarea>
185
+ HTML
186
+ end
187
+ end
188
+
189
+ test "#text_area with a value" do
190
+ sl_form_for(User.new(name: "Yuki Nishijima"), url: "/") do |form|
191
+ assert_dom_equal <<~HTML, form.text_area(:name)
192
+ <sl-textarea label="Name" resize="auto" value="Yuki Nishijima" name="user[name]" id="user_name"></sl-textarea>
193
+ HTML
194
+ end
195
+ end
196
+
197
+ test "#text_area with an one-off value" do
198
+ sl_form_for(User.new(name: "Yuki Nishijima"), url: "/") do |form|
199
+ assert_dom_equal <<~HTML, form.text_area(:name, value: "Yuki")
200
+ <sl-textarea label="Name" resize="auto" value="Yuki" name="user[name]" id="user_name"></sl-textarea>
201
+ HTML
202
+ end
203
+ end
204
+
205
+ test "#text_area without a label" do
206
+ sl_form_for(User.new, url: "/") do |form|
207
+ assert_dom_equal <<~HTML, form.text_area(:name, label: nil)
214
208
  <sl-textarea resize="auto" name="user[name]" id="user_name"></sl-textarea>
215
209
  HTML
216
210
  end
217
211
  end
218
212
 
219
- test "#check_box" do
213
+ test "#text_area with a size" do
214
+ sl_form_for(User.new, url: "/") do |form|
215
+ assert_dom_equal <<~HTML, form.text_area(:name, size: "small")
216
+ <sl-textarea label="Name" resize="auto" size="small" name="user[name]" id="user_name"></sl-textarea>
217
+ HTML
218
+ end
219
+ end
220
+
221
+ test "#text_area with a block" do
220
222
  sl_form_for(User.new, url: "/") do |form|
221
- assert_dom_equal <<~HTML, form.check_box(:name)
222
- <sl-checkbox value="1" name="user[name]" id="user_name">Name</sl-checkbox>
223
+ expected = <<~HTML
224
+ <sl-textarea label="Name" resize="auto" name="user[name]" id="user_name">
225
+ <div slot="help-text">Name can not be blank.</div>
226
+ </sl-textarea>
223
227
  HTML
228
+
229
+ assert_dom_equal(expected, form.text_area(:name) {
230
+ content_tag(:div, "Name can not be blank.", slot: "help-text")
231
+ })
232
+ end
233
+ end
234
+
235
+ test "#check_box" do
236
+ sl_form_for(User.new, url: "/") do |form|
237
+ if ActionView::VERSION::STRING >= '6.1.0'
238
+ assert_dom_equal <<~HTML, form.check_box(:name)
239
+ <input name="user[name]" type="hidden" value="0" autocomplete="off" />
240
+ <sl-checkbox value="1" name="user[name]" id="user_name">Name</sl-checkbox>
241
+ HTML
242
+ else
243
+ assert_dom_equal <<~HTML, form.check_box(:name)
244
+ <input name="user[name]" type="hidden" value="0" />
245
+ <sl-checkbox value="1" name="user[name]" id="user_name">Name</sl-checkbox>
246
+ HTML
247
+ end
224
248
  end
225
249
  end
226
250
 
227
251
  test "#check_box with a block" do
228
252
  sl_form_for(User.new, url: "/") do |form|
229
- assert_dom_equal <<~HTML, form.check_box(:name) { "Maintainer Name" }
253
+ if ActionView::VERSION::STRING >= '6.1.0'
254
+ assert_dom_equal <<~HTML, form.check_box(:name) { "Maintainer Name" }
255
+ <input name="user[name]" type="hidden" value="0" autocomplete="off" />
256
+ <sl-checkbox value="1" name="user[name]" id="user_name">Maintainer Name</sl-checkbox>
257
+ HTML
258
+ else
259
+ assert_dom_equal <<~HTML, form.check_box(:name) { "Maintainer Name" }
260
+ <input name="user[name]" type="hidden" value="0" />
261
+ <sl-checkbox value="1" name="user[name]" id="user_name">Maintainer Name</sl-checkbox>
262
+ HTML
263
+ end
264
+ end
265
+ end
266
+
267
+ test "#check_box without a hidden input" do
268
+ sl_form_for(User.new, url: "/") do |form|
269
+ assert_dom_equal <<~HTML, form.check_box(:name, include_hidden: false) { "Maintainer Name" }
230
270
  <sl-checkbox value="1" name="user[name]" id="user_name">Maintainer Name</sl-checkbox>
231
271
  HTML
232
272
  end
@@ -241,7 +281,7 @@ class FormHelperTest < ActionView::TestCase
241
281
 
242
282
  sl_form_for(User.new, url: "/") do |form|
243
283
  assert_dom_equal <<~HTML, form.select(:name, users)
244
- <sl-select name="user[name]" id="user_name">
284
+ <sl-select label="Name" name="user[name]" id="user_name">
245
285
  <sl-menu-item value="1">Yuki Nishijima</sl-menu-item>
246
286
  <sl-menu-item value="2">Matz</sl-menu-item>
247
287
  <sl-menu-item value="3">Koichi Sasada</sl-menu-item>
@@ -250,6 +290,42 @@ class FormHelperTest < ActionView::TestCase
250
290
  end
251
291
  end
252
292
 
293
+ test "#select with a custom value" do
294
+ users = {
295
+ "Yuki Nishijima" => 1,
296
+ "Matz" => 2,
297
+ "Koichi Sasada" => 3
298
+ }
299
+
300
+ sl_form_for(User.new, url: "/") do |form|
301
+ assert_dom_equal <<~HTML, form.select(:name, users, {}, { value: 3 })
302
+ <sl-select label="Name" value="3" name="user[name]" id="user_name">
303
+ <sl-menu-item value="1">Yuki Nishijima</sl-menu-item>
304
+ <sl-menu-item value="2">Matz</sl-menu-item>
305
+ <sl-menu-item value="3">Koichi Sasada</sl-menu-item>
306
+ </sl-select>
307
+ HTML
308
+ end
309
+ end
310
+
311
+ test "#select with custom selected and disabled values" do
312
+ users = {
313
+ "Yuki Nishijima" => 1,
314
+ "Matz" => 2,
315
+ "Koichi Sasada" => 3
316
+ }
317
+
318
+ sl_form_for(User.new, url: "/") do |form|
319
+ assert_dom_equal <<~HTML, form.select(:name, users, selected: 3, disabled: 1)
320
+ <sl-select label="Name" name="user[name]" id="user_name">
321
+ <sl-menu-item value="1" disabled="disabled">Yuki Nishijima</sl-menu-item>
322
+ <sl-menu-item value="2">Matz</sl-menu-item>
323
+ <sl-menu-item value="3" checked="checked">Koichi Sasada</sl-menu-item>
324
+ </sl-select>
325
+ HTML
326
+ end
327
+ end
328
+
253
329
  test "#select with multiple" do
254
330
  users = {
255
331
  "Yuki Nishijima" => 1,
@@ -259,7 +335,7 @@ class FormHelperTest < ActionView::TestCase
259
335
 
260
336
  sl_form_for(User.new, url: "/") do |form|
261
337
  assert_dom_equal <<~HTML, form.select(:name, users, {}, { multiple: true })
262
- <sl-select name="user[name][]" id="user_name" multiple="multiple">
338
+ <sl-select label="Name" name="user[name][]" id="user_name" multiple="multiple">
263
339
  <sl-menu-item value="1">Yuki Nishijima</sl-menu-item>
264
340
  <sl-menu-item value="2">Matz</sl-menu-item>
265
341
  <sl-menu-item value="3">Koichi Sasada</sl-menu-item>
@@ -281,7 +357,7 @@ class FormHelperTest < ActionView::TestCase
281
357
 
282
358
  sl_form_for(User.new, url: "/") do |form|
283
359
  assert_dom_equal <<~HTML, form.select(:name, users)
284
- <sl-select name="user[name]" id="user_name">
360
+ <sl-select label="Name" name="user[name]" id="user_name">
285
361
  <sl-menu-label>Main maintainers</sl-menu-label>
286
362
  <sl-menu-item value="2">Matz</sl-menu-item>
287
363
  <sl-menu-item value="3">Koichi Sasada</sl-menu-item>
@@ -304,9 +380,9 @@ class FormHelperTest < ActionView::TestCase
304
380
  ]
305
381
  }
306
382
 
307
- sl_form_for(User.new(name: "2"), url: "/") do |form|
383
+ sl_form_for(User.new(name: 2), url: "/") do |form|
308
384
  assert_dom_equal <<~HTML, form.select(:name, users)
309
- <sl-select name="user[name]" id="user_name" value="2">
385
+ <sl-select label="Name" name="user[name]" id="user_name" value="2">
310
386
  <sl-menu-label>Main maintainers</sl-menu-label>
311
387
  <sl-menu-item value="2" checked="checked">Matz</sl-menu-item>
312
388
  <sl-menu-item value="3">Koichi Sasada</sl-menu-item>
@@ -327,7 +403,7 @@ class FormHelperTest < ActionView::TestCase
327
403
 
328
404
  sl_form_for(User.new, url: "/") do |form|
329
405
  assert_dom_equal <<~HTML, form.collection_select(:name, users, :first, :last)
330
- <sl-select name="user[name]" id="user_name">
406
+ <sl-select label="Name" name="user[name]" id="user_name">
331
407
  <sl-menu-item value="1">Yuki Nishijima</sl-menu-item>
332
408
  <sl-menu-item value="2">Matz</sl-menu-item>
333
409
  <sl-menu-item value="3">Koichi Sasada</sl-menu-item>
@@ -345,7 +421,7 @@ class FormHelperTest < ActionView::TestCase
345
421
 
346
422
  sl_form_for(User.new(name: "2"), url: "/") do |form|
347
423
  assert_dom_equal <<~HTML, form.collection_select(:name, users, :first, :last)
348
- <sl-select name="user[name]" id="user_name" value="2">
424
+ <sl-select label="Name" name="user[name]" id="user_name" value="2">
349
425
  <sl-menu-item value="1">Yuki Nishijima</sl-menu-item>
350
426
  <sl-menu-item value="2" checked="checked">Matz</sl-menu-item>
351
427
  <sl-menu-item value="3">Koichi Sasada</sl-menu-item>
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+ require 'test_helper'
3
+
4
+ require_relative '../../app/helpers/shoelace/tag_helper'
5
+
6
+ class TagHelperTest < ActionView::TestCase
7
+ include Shoelace::TagHelper
8
+
9
+ test "#sl_button_tag" do
10
+ assert_dom_equal(<<~HTML, sl_button_tag { "Submit" })
11
+ <sl-button>Submit</sl-button>
12
+ HTML
13
+ end
14
+
15
+ test "#sl_button_to" do
16
+ assert_dom_equal <<~HTML, sl_button_to("Next", "/next")
17
+ <sl-button href="/next">Next</sl-button>
18
+ HTML
19
+
20
+ assert_dom_equal <<~HTML, sl_button_to("Next", "/next", class: "mt-1")
21
+ <sl-button href="/next" class="mt-1">Next</sl-button>
22
+ HTML
23
+
24
+ assert_dom_equal(<<~HTML, sl_button_to("/next") { "Next" })
25
+ <sl-button href="/next">Next</sl-button>
26
+ HTML
27
+
28
+ assert_dom_equal(<<~HTML, sl_button_to("/next", class: "mt-1") { "Next" })
29
+ <sl-button href="/next" class="mt-1">Next</sl-button>
30
+ HTML
31
+
32
+ assert_dom_equal <<~HTML, sl_button_to("Next")
33
+ <sl-button>Next</sl-button>
34
+ HTML
35
+ end
36
+
37
+ test "#sl_icon_tag"do
38
+ assert_dom_equal <<~HTML, sl_icon_tag("0-circle-fill")
39
+ <sl-icon name="0-circle-fill"></sl-icon>
40
+ HTML
41
+
42
+ assert_dom_equal <<~HTML, sl_icon_tag("0-circle-fill", slot: "icon")
43
+ <sl-icon name="0-circle-fill" slot="icon"></sl-icon>
44
+ HTML
45
+ end
46
+
47
+ test "#sl_avatar_tag"do
48
+ assert_dom_equal <<~HTML, sl_avatar_tag("/path/to/image.jpg")
49
+ <sl-avatar image="/path/to/image.jpg"></sl-avatar>
50
+ HTML
51
+
52
+ assert_dom_equal(<<~HTML, sl_avatar_tag("/path/to/image.jpg", slot: "trigger") { "Body" })
53
+ <sl-avatar image="/path/to/image.jpg" slot="trigger">
54
+ Body
55
+ </sl-avatar>
56
+ HTML
57
+ end
58
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shoelace-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuki Nishijima
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-06-24 00:00:00.000000000 Z
11
+ date: 2023-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionview
@@ -98,6 +98,7 @@ files:
98
98
  - README.md
99
99
  - Rakefile
100
100
  - app/helpers/shoelace/form_helper.rb
101
+ - app/helpers/shoelace/tag_helper.rb
101
102
  - bin/console
102
103
  - bin/setup
103
104
  - dist/.keep
@@ -114,7 +115,7 @@ files:
114
115
  - lib/shoelace/rails/version.rb
115
116
  - lib/shoelace/railtie.rb
116
117
  - lib/shoelace/testing.rb
117
- - lib/tasks/assets.rake
118
+ - lib/tasks/shoelace.rake
118
119
  - package.json
119
120
  - rollup.config.js
120
121
  - shoelace-rails.gemspec
@@ -166,6 +167,7 @@ files:
166
167
  - test/dummy_app/test/system/turbolinks_form_test.rb
167
168
  - test/dummy_app/test/test_helper.rb
168
169
  - test/helpers/form_helper_test.rb
170
+ - test/helpers/tag_helper_test.rb
169
171
  - test/test_helper.rb
170
172
  - tsconfig.json
171
173
  - yarn.lock
@@ -191,7 +193,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
191
193
  - !ruby/object:Gem::Version
192
194
  version: '0'
193
195
  requirements: []
194
- rubygems_version: 3.3.7
196
+ rubygems_version: 3.4.1
195
197
  signing_key:
196
198
  specification_version: 4
197
199
  summary: Rails view helpers Shoelace.style, the design system.