shoelace-rails 0.2.0 → 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: 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.