shoelace-rails 0.1.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: 1c7cf138c772d734257018fa691d7082b04caf56da45e2d5243041d9a90e345b
4
- data.tar.gz: 1902dd8b4ee4d41e57dd3ede4bfe4c71f21a1fc7607d02524e052667a3481330
3
+ metadata.gz: 6bf02de3fbe6ef35ad4c464e666bd7ace7bf0c2e673b0767afea4d6b87522749
4
+ data.tar.gz: 73abb906c86ffc3f4a945f73f3a97e3cd335c1cb4245b82362cf53c3587619d5
5
5
  SHA512:
6
- metadata.gz: e6fb93a87eabac57355bd4a2a7d567d1e94680c0b59d0dc40731d46b76b3eb4ca74cce56f6c720b7bd63f4845de37a93a735a8013ea21e3d1d7a3c8b5aa22722
7
- data.tar.gz: de7ddf7f75dee4a26b71eb95cf1ae3d29e9884080a25abe8f575352b0068a3c5d5e459852947ce8d286999cec6ca218efd77f9587f32ba9c44efd56ceac8fc6f
6
+ metadata.gz: 1e7a5bca7b14951f97b54c9de1be69698ceebb63a421be912cc8f692ebec8ed075ebdf58a4fbc9d9200c296e3150ae63f41f6a6a40f62fc368c1a54044905a9b
7
+ data.tar.gz: 5d09b9294065025cb30762a152c3b037739790a8b16ff5e2178bcb98afc0592756447ba0273967450783e11fbfd9863be5e11027a61074ed622e35d380a95dc5
@@ -9,21 +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
- runs-on: ubuntu-18.04
22
+ exclude:
23
+ - ruby_version: 'jruby-9.3'
24
+ gemfile: gemfiles/rails_70.gemfile
25
+ runs-on: ubuntu-22.04
21
26
  env:
22
27
  BUNDLE_GEMFILE: ${{ matrix.gemfile }}
23
28
  steps:
24
- - uses: actions/checkout@v2
25
- - name: Install curl
26
- run: sudo apt-get install curl libcurl4-openssl-dev
29
+ - uses: actions/checkout@v3
27
30
  - name: Set up Ruby
28
31
  uses: ruby/setup-ruby@v1
29
32
  with:
@@ -32,13 +35,14 @@ jobs:
32
35
  - run: bundle exec rake test
33
36
 
34
37
  system:
35
- runs-on: ubuntu-18.04
38
+ needs: unit
39
+ runs-on: ubuntu-22.04
36
40
  steps:
37
- - uses: actions/checkout@v2
41
+ - uses: actions/checkout@v3
38
42
  - name: Set up Ruby
39
43
  uses: ruby/setup-ruby@v1
40
44
  with:
41
- ruby-version: 3.1.0
45
+ ruby-version: 3.2.0
42
46
  bundler-cache: true
43
47
  - name: Install dependencies
44
48
  run: |
@@ -49,14 +53,47 @@ jobs:
49
53
  - name: Run the system test in the dummy app
50
54
  run: rake test:system
51
55
 
56
+ rails_edge:
57
+ needs: system
58
+ runs-on: ubuntu-22.04
59
+ env:
60
+ BUNDLE_GEMFILE: gemfiles/rails_edge.gemfile
61
+ steps:
62
+ - uses: actions/checkout@v3
63
+ - name: Set up Ruby
64
+ uses: ruby/setup-ruby@v1
65
+ with:
66
+ ruby-version: 3.1
67
+ bundler-cache: true
68
+ - run: bundle exec rake test || echo "Rails edge test is done."
69
+
70
+ ruby_edge:
71
+ needs: system
72
+ strategy:
73
+ matrix:
74
+ gemfile:
75
+ - gemfiles/rails_edge.gemfile
76
+ - gemfiles/rails_70.gemfile
77
+ runs-on: ubuntu-22.04
78
+ env:
79
+ BUNDLE_GEMFILE: ${{ matrix.gemfile }}
80
+ steps:
81
+ - uses: actions/checkout@v3
82
+ - name: Set up Ruby
83
+ uses: ruby/setup-ruby@v1
84
+ with:
85
+ ruby-version: 'ruby-head'
86
+ bundler-cache: true
87
+ - run: bundle exec rake || echo "Ruby edge test is done."
88
+
52
89
  # browser_tests:
53
- # runs-on: ubuntu-18.04
90
+ # runs-on: ubuntu-22.04
54
91
  # steps:
55
- # - uses: actions/checkout@v2
92
+ # - uses: actions/checkout@v3
56
93
  # - name: Set up Ruby
57
94
  # uses: ruby/setup-ruby@v1
58
95
  # with:
59
- # ruby-version: 3.1.0
96
+ # ruby-version: 3.2.0
60
97
  # bundler-cache: true
61
98
  # - name: Install dependencies
62
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"
@@ -7,9 +7,9 @@ appraise "rails_edge" do
7
7
  end
8
8
 
9
9
  appraise "rails_70" do
10
- gem "rails", "~> 6.1.0"
11
- gem "railties", "~> 6.1.0"
12
- gem "activesupport", "~> 6.1.0"
10
+ gem "rails", "~> 7.0.0"
11
+ gem "railties", "~> 7.0.0"
12
+ gem "activesupport", "~> 7.0.0"
13
13
  end
14
14
 
15
15
  appraise "rails_61" do
data/CHANGELOG.md CHANGED
@@ -1,3 +1,40 @@
1
- ## [0.1.0] - 2022-02-17
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>_
30
+
31
+ #### Features
32
+
33
+ - Do not require the `copy-webpack-plugin` to set up Shoelace so the gem works with any js bundler.
34
+
35
+ ## [v0.1.0](https://github.com/yuki24/shoelace-rails/tree/v0.1.0)
36
+
37
+ _<sup>released at 2022-02-17 13:17:09 UTC</sup>_
38
+
39
+ First release!
2
40
 
3
- - First release!
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
@@ -23,7 +19,7 @@ $ bundle install
23
19
  Additionally, you need to add the following npm packages:
24
20
 
25
21
  ```sh
26
- $ yarn add @shoelace-style/shoelace copy-webpack-plugin
22
+ $ yarn add @shoelace-style/shoelace
27
23
  ```
28
24
 
29
25
  ## Set up CSS
@@ -50,66 +46,31 @@ import "@shoelace-style/shoelace/dist/themes/dark.css" // Optional dark mode
50
46
 
51
47
  ## Set up Javascript
52
48
 
53
- In order to use Shoelace the icons need to be copied to the `public/assets` directory so they will show pu properly.
54
-
55
- If you are using the `jsbundling-rails` gem and have `webpack.config.js` in the top level directory of your project, Add th
56
- e configuration for the `CopyPlugin`:
49
+ In this README, it is assumed that you are using a JS bundler such as `webpack` or `esbuild`. In order to define all
50
+ the custome elements, import the shoelace dependency in the entrypoint file:
57
51
 
58
52
  ```js
59
- // webpack.config.js
60
- const CopyPlugin = require("copy-webpack-plugin")
61
- const path = require('path')
62
-
63
- module.exports = {
64
- ...,
65
- plugins: [
66
- new CopyPlugin({
67
- patterns: [
68
- {
69
- from: path.resolve(__dirname, "node_modules/@shoelace-style/shoelace/dist/assets"),
70
- to: path.resolve(__dirname, "public/assets"),
71
- },
72
- ],
73
- }),
74
- ],
75
- }
76
- ```
77
-
78
- If you are using the `webpacker` gem, you could add the same configuration but to `config/webpack/environment.js`:
53
+ import "@shoelace-style/shoelace"
54
+ ```
79
55
 
80
- ```js
81
- // config/webpack/environment.js
82
- const { environment } = require('@rails/webpacker')
83
- const path = require('path')
84
- const CopyPlugin = require('copy-webpack-plugin')
56
+ That's it!
85
57
 
86
- // Add shoelace icons to webpack's build process
87
- environment.plugins.append(
88
- 'CopyPlugin',
89
- new CopyPlugin({
90
- patterns: [
91
- {
92
- from: path.resolve(__dirname, '../../node_modules/@shoelace-style/shoelace/dist/assets'),
93
- to: path.resolve(__dirname, '../../public/packs/js/assets')
94
- }
95
- ]
96
- })
97
- )
58
+ ### Shoelace Icons
98
59
 
99
- module.exports = environment
100
- ```
60
+ Shoelace icons are automatically set up to load properly, so you don't need to add any extra code. More specifically,
101
61
 
102
- Finally, import the shoelace dependency in the entrypoint file:
62
+ * In development, the icons are served by the `ActionDispatch::Static` middleware, directly from the
63
+ `node_modules/@shoelace-style/shoelace/dist/assets/icons` directory.
64
+ * In production, the icon files are automatically copied into the `public/assets` directory as part of the
65
+ `assets:precompile` rake task.
103
66
 
104
- ```js
105
- import "@shoelace-style/shoelace"
106
- ```
67
+ ## View Helpers
107
68
 
108
- That's it!
69
+ As explained above, this gem provides drop-in replacements to Rails view helpers.
109
70
 
110
- ## View Helpers
71
+ ### Form Helpers
111
72
 
112
- As explained above, this gem provides drop-in replacements to. Here is a short example of how the form helper works:
73
+ The `sl_form_with` or `sl_form_for` method could be used to generate a form with the Shoelace components:
113
74
 
114
75
  ```erb
115
76
  <%= sl_form_for @user do |form| %>
@@ -133,7 +94,7 @@ As explained above, this gem provides drop-in replacements to. Here is a short e
133
94
  And this code will produce:
134
95
 
135
96
  ```html
136
- <sl-form class="new_user" id="new_user" data-remote="true" action="/" accept-charset="UTF-8" method="post">
97
+ <form class="new_user" id="new_user" data-remote="true" action="/" accept-charset="UTF-8" method="post">
137
98
  <sl-input label="Name" type="text" name="user[name]" id="user_name"></sl-input>
138
99
  <sl-input label="Password" type="password" name="user[password]" id="user_password"></sl-input>
139
100
  <sl-color-picker value="#ffffff" name="user[color]" id="user_color"></sl-color-picker>
@@ -151,7 +112,82 @@ And this code will produce:
151
112
  </sl-select>
152
113
 
153
114
  <sl-button submit="true" type="primary" data-disable-with="Create User">Create User</sl-button>
154
- </sl-form>
115
+ </form>
116
+ ```
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>
155
191
  ```
156
192
 
157
193
  ## Development
@@ -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
@@ -4,8 +4,8 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "rake", "~> 13.0"
6
6
  gem "rails-dom-testing", git: "https://github.com/rails/rails-dom-testing.git", ref: "8f5acdfc"
7
- gem "rails", "~> 6.1.0"
8
- gem "railties", "~> 6.1.0"
9
- gem "activesupport", "~> 6.1.0"
7
+ gem "rails", "~> 7.0.0"
8
+ gem "railties", "~> 7.0.0"
9
+ gem "activesupport", "~> 7.0.0"
10
10
 
11
11
  gemspec path: "../"
@@ -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,7 +2,5 @@
2
2
 
3
3
  module Shoelace
4
4
  class Engine < ::Rails::Engine #:nodoc:
5
- config.shoelace = ActiveSupport::OrderedOptions.new
6
- config.shoelace.use_sl_form_tag = false
7
5
  end
8
6
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Shoelace
4
4
  module Rails
5
- VERSION = "0.1.0"
5
+ VERSION = "0.3.0"
6
6
  end
7
7
  end
@@ -1,7 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "rails/version"
4
- require_relative "engine" if defined?(::Rails::Railtie)
4
+
5
+ if defined?(::Rails::Railtie)
6
+ require_relative "engine"
7
+ require_relative "railtie"
8
+ end
5
9
 
6
10
  module Shoelace
7
11
  module Rails
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'action_dispatch/middleware/static'
4
+
5
+ module Shoelace
6
+ # The only reason this class exists is to clarify that we have a custom static file server after
7
+ # `ActionDispatch::Static`. We could just use `ActionDispatch::Static` directly, but it would make the result of
8
+ # `rake middleware` more difficult to understand, as the output would look like:
9
+ #
10
+ # use ...
11
+ # use ActionDispatch::Static
12
+ # use ActionDispatch::Static # Why do we use the same middleware twice?
13
+ # use ...
14
+ #
15
+ # It is much more straightforward if it looks like:
16
+ #
17
+ # use ...
18
+ # use ActionDispatch::Static
19
+ # use Shoelace::AssetProvider
20
+ # use ...
21
+ #
22
+ class AssetProvider < ActionDispatch::Static; end
23
+
24
+ class Railtie < ::Rails::Railtie #:nodoc:
25
+ config.shoelace = ActiveSupport::OrderedOptions.new
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
32
+
33
+ initializer "shoelace.use_rack_middleware" do |app|
34
+ icon_dir = File.join(app.paths["public"].first, "assets/icons")
35
+
36
+ if !Dir.exist?(icon_dir)
37
+ path = app.root.join(app.config.shoelace.dist_path).to_s
38
+ headers = app.config.public_file_server.headers || {}
39
+
40
+ app.config.middleware.insert_after ActionDispatch::Static, Shoelace::AssetProvider, path, index: "index.html", headers: headers
41
+ end
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
53
+ end
54
+ end
@@ -0,0 +1,20 @@
1
+ namespace :shoelace do
2
+ namespace :icons do
3
+ desc "Copy Shoelace icons to the assets path"
4
+ task copy: :environment do
5
+ cp_r Rails.root.join(Shoelace::Railtie.config.shoelace.dist_path, "assets").to_s, Rails.public_path
6
+ end
7
+
8
+ desc "Remove Shoelace icons"
9
+ task clobber: :environment do
10
+ rm_rf File.join(Rails.public_path, "assets/icons")
11
+ end
12
+ end
13
+ end
14
+
15
+ # Make sure `yarn install` is run before running `shoelace:icons:copy`.
16
+ Rake::Task["shoelace:icons:copy"].enhance(["javascript:build"])
17
+
18
+ if Rake::Task.task_defined?("assets:precompile")
19
+ Rake::Task["assets:precompile"].enhance(["shoelace:icons:copy"])
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"
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'test_helper'
2
3
 
3
4
  require_relative '../../app/helpers/shoelace/form_helper'
@@ -5,6 +6,8 @@ require_relative '../../app/helpers/shoelace/form_helper'
5
6
  class FormHelperTest < ActionView::TestCase
6
7
  include Shoelace::FormHelper
7
8
 
9
+ AUTOCOMPLETE_ATTRIBUTE = ActionView::VERSION::STRING >= '6.1.0' ? 'autocomplete="off"' : ''
10
+
8
11
  test "#sl_text_field_tag with name and value" do
9
12
  assert_dom_equal <<~HTML, sl_text_field_tag('name', 'Your name')
10
13
  <sl-input type="text" name="name" id="name" value="Your name"></sl-input>
@@ -41,30 +44,16 @@ class FormHelperTest < ActionView::TestCase
41
44
  HTML
42
45
  end
43
46
 
44
- test "#sl_button_tag" do
45
- assert_dom_equal(<<~HTML, sl_button_tag { "Submit" })
46
- <sl-button>Submit</sl-button>
47
- HTML
48
- end
49
-
50
47
  test "#sl_radio_button" do
51
48
  assert_dom_equal(<<~HTML, sl_radio_button(:user, :name, 'userid-314', checked: true) { "Yuki Nishijima" })
52
49
  <sl-radio value="userid-314" checked="checked" name="user[name]" id="user_name_userid-314">Yuki Nishijima</sl-radio>
53
50
  HTML
54
51
  end
55
52
 
56
- test "#sl_form_tag" do
57
- assert_dom_equal(<<~HTML, sl_form_tag("/posts") { })
58
- <form data-remote="true" action="/posts" accept-charset="UTF-8" method="post">
59
- <input name="utf8" type="hidden" value="&#x2713;" />
60
- </sl-form>
61
- HTML
62
- end
63
-
64
53
  test "#sl_form_with" do
65
54
  assert_dom_equal(<<~HTML, sl_form_with(url: "/") {})
66
55
  <form action="/" accept-charset="UTF-8" data-remote="true" method="post">
67
- <input name="utf8" type="hidden" value="&#x2713;" />
56
+ <input name="utf8" type="hidden" value="&#x2713;" #{AUTOCOMPLETE_ATTRIBUTE} />
68
57
  </sl-form>
69
58
  HTML
70
59
  end
@@ -72,35 +61,11 @@ class FormHelperTest < ActionView::TestCase
72
61
  test "#sl_form_for" do
73
62
  assert_dom_equal(<<~HTML, sl_form_for(User.new, url: "/") { })
74
63
  <form class="new_user" id="new_user" action="/" accept-charset="UTF-8" method="post">
75
- <input name="utf8" type="hidden" value="&#x2713;" />
64
+ <input name="utf8" type="hidden" value="&#x2713;" #{AUTOCOMPLETE_ATTRIBUTE} />
76
65
  </sl-form>
77
66
  HTML
78
67
  end
79
68
 
80
- test "#sl_turbo_form_tag" do
81
- assert_dom_equal(<<~HTML, sl_turbo_form_tag("/posts") { })
82
- <form action="/posts" accept-charset="UTF-8" method="post">
83
- <input name="utf8" type="hidden" value="&#x2713;" />
84
- </form>
85
- HTML
86
- end
87
-
88
- test "#sl_turbo_form_with" do
89
- assert_dom_equal(<<~HTML, sl_turbo_form_with(url: "/") {})
90
- <form action="/" accept-charset="UTF-8" data-remote="true" method="post">
91
- <input name="utf8" type="hidden" value="&#x2713;" />
92
- </form>
93
- HTML
94
- end
95
-
96
- test "#sl_turbo_form_for" do
97
- assert_dom_equal(<<~HTML, sl_turbo_form_for(User.new, url: "/") { })
98
- <form class="new_user" id="new_user" action="/" accept-charset="UTF-8" method="post">
99
- <input name="utf8" type="hidden" value="&#x2713;" />
100
- </form>
101
- HTML
102
- end
103
-
104
69
  test "#text_field" do
105
70
  sl_form_for(User.new, url: "/") do |form|
106
71
  assert_dom_equal <<~HTML, form.text_field(:name)
@@ -192,6 +157,14 @@ class FormHelperTest < ActionView::TestCase
192
157
  test "#range_field" do
193
158
  sl_form_for(User.new, url: "/") do |form|
194
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)
195
168
  <sl-range name="user[name]" id="user_name"></sl-range>
196
169
  HTML
197
170
  end
@@ -208,22 +181,92 @@ class FormHelperTest < ActionView::TestCase
208
181
  test "#text_area" do
209
182
  sl_form_for(User.new, url: "/") do |form|
210
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)
211
208
  <sl-textarea resize="auto" name="user[name]" id="user_name"></sl-textarea>
212
209
  HTML
213
210
  end
214
211
  end
215
212
 
216
- test "#check_box" do
213
+ test "#text_area with a size" do
217
214
  sl_form_for(User.new, url: "/") do |form|
218
- assert_dom_equal <<~HTML, form.check_box(:name)
219
- <sl-checkbox value="1" name="user[name]" id="user_name">Name</sl-checkbox>
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>
220
217
  HTML
221
218
  end
222
219
  end
223
220
 
221
+ test "#text_area with a block" do
222
+ sl_form_for(User.new, url: "/") do |form|
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>
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
248
+ end
249
+ end
250
+
224
251
  test "#check_box with a block" do
225
252
  sl_form_for(User.new, url: "/") do |form|
226
- 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" }
227
270
  <sl-checkbox value="1" name="user[name]" id="user_name">Maintainer Name</sl-checkbox>
228
271
  HTML
229
272
  end
@@ -238,7 +281,7 @@ class FormHelperTest < ActionView::TestCase
238
281
 
239
282
  sl_form_for(User.new, url: "/") do |form|
240
283
  assert_dom_equal <<~HTML, form.select(:name, users)
241
- <sl-select name="user[name]" id="user_name">
284
+ <sl-select label="Name" name="user[name]" id="user_name">
242
285
  <sl-menu-item value="1">Yuki Nishijima</sl-menu-item>
243
286
  <sl-menu-item value="2">Matz</sl-menu-item>
244
287
  <sl-menu-item value="3">Koichi Sasada</sl-menu-item>
@@ -247,6 +290,42 @@ class FormHelperTest < ActionView::TestCase
247
290
  end
248
291
  end
249
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
+
250
329
  test "#select with multiple" do
251
330
  users = {
252
331
  "Yuki Nishijima" => 1,
@@ -256,7 +335,7 @@ class FormHelperTest < ActionView::TestCase
256
335
 
257
336
  sl_form_for(User.new, url: "/") do |form|
258
337
  assert_dom_equal <<~HTML, form.select(:name, users, {}, { multiple: true })
259
- <sl-select name="user[name][]" id="user_name" multiple="multiple">
338
+ <sl-select label="Name" name="user[name][]" id="user_name" multiple="multiple">
260
339
  <sl-menu-item value="1">Yuki Nishijima</sl-menu-item>
261
340
  <sl-menu-item value="2">Matz</sl-menu-item>
262
341
  <sl-menu-item value="3">Koichi Sasada</sl-menu-item>
@@ -278,7 +357,7 @@ class FormHelperTest < ActionView::TestCase
278
357
 
279
358
  sl_form_for(User.new, url: "/") do |form|
280
359
  assert_dom_equal <<~HTML, form.select(:name, users)
281
- <sl-select name="user[name]" id="user_name">
360
+ <sl-select label="Name" name="user[name]" id="user_name">
282
361
  <sl-menu-label>Main maintainers</sl-menu-label>
283
362
  <sl-menu-item value="2">Matz</sl-menu-item>
284
363
  <sl-menu-item value="3">Koichi Sasada</sl-menu-item>
@@ -301,9 +380,9 @@ class FormHelperTest < ActionView::TestCase
301
380
  ]
302
381
  }
303
382
 
304
- sl_form_for(User.new(name: "2"), url: "/") do |form|
383
+ sl_form_for(User.new(name: 2), url: "/") do |form|
305
384
  assert_dom_equal <<~HTML, form.select(:name, users)
306
- <sl-select name="user[name]" id="user_name" value="2">
385
+ <sl-select label="Name" name="user[name]" id="user_name" value="2">
307
386
  <sl-menu-label>Main maintainers</sl-menu-label>
308
387
  <sl-menu-item value="2" checked="checked">Matz</sl-menu-item>
309
388
  <sl-menu-item value="3">Koichi Sasada</sl-menu-item>
@@ -324,7 +403,7 @@ class FormHelperTest < ActionView::TestCase
324
403
 
325
404
  sl_form_for(User.new, url: "/") do |form|
326
405
  assert_dom_equal <<~HTML, form.collection_select(:name, users, :first, :last)
327
- <sl-select name="user[name]" id="user_name">
406
+ <sl-select label="Name" name="user[name]" id="user_name">
328
407
  <sl-menu-item value="1">Yuki Nishijima</sl-menu-item>
329
408
  <sl-menu-item value="2">Matz</sl-menu-item>
330
409
  <sl-menu-item value="3">Koichi Sasada</sl-menu-item>
@@ -342,7 +421,7 @@ class FormHelperTest < ActionView::TestCase
342
421
 
343
422
  sl_form_for(User.new(name: "2"), url: "/") do |form|
344
423
  assert_dom_equal <<~HTML, form.collection_select(:name, users, :first, :last)
345
- <sl-select name="user[name]" id="user_name" value="2">
424
+ <sl-select label="Name" name="user[name]" id="user_name" value="2">
346
425
  <sl-menu-item value="1">Yuki Nishijima</sl-menu-item>
347
426
  <sl-menu-item value="2" checked="checked">Matz</sl-menu-item>
348
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.1.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-02-17 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
@@ -112,7 +113,9 @@ files:
112
113
  - lib/shoelace/engine.rb
113
114
  - lib/shoelace/rails.rb
114
115
  - lib/shoelace/rails/version.rb
116
+ - lib/shoelace/railtie.rb
115
117
  - lib/shoelace/testing.rb
118
+ - lib/tasks/shoelace.rake
116
119
  - package.json
117
120
  - rollup.config.js
118
121
  - shoelace-rails.gemspec
@@ -164,6 +167,7 @@ files:
164
167
  - test/dummy_app/test/system/turbolinks_form_test.rb
165
168
  - test/dummy_app/test/test_helper.rb
166
169
  - test/helpers/form_helper_test.rb
170
+ - test/helpers/tag_helper_test.rb
167
171
  - test/test_helper.rb
168
172
  - tsconfig.json
169
173
  - yarn.lock
@@ -189,7 +193,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
189
193
  - !ruby/object:Gem::Version
190
194
  version: '0'
191
195
  requirements: []
192
- rubygems_version: 3.3.3
196
+ rubygems_version: 3.4.1
193
197
  signing_key:
194
198
  specification_version: 4
195
199
  summary: Rails view helpers Shoelace.style, the design system.