stimulus_plumbers 0.4.11 → 0.4.12
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 +4 -4
- data/CHANGELOG.md +7 -0
- data/docs/architecture.md +1 -1
- data/docs/component/form.md +36 -15
- data/docs/guide.md +2 -1
- data/lib/stimulus_plumbers/components/button/icon_layout.rb +34 -0
- data/lib/stimulus_plumbers/components/button.rb +2 -23
- data/lib/stimulus_plumbers/components/combobox/builder.rb +52 -14
- data/lib/stimulus_plumbers/components/combobox/date.rb +35 -9
- data/lib/stimulus_plumbers/components/combobox/dropdown.rb +22 -6
- data/lib/stimulus_plumbers/components/combobox/time.rb +18 -5
- data/lib/stimulus_plumbers/components/combobox/typeahead.rb +22 -7
- data/lib/stimulus_plumbers/components/icon.rb +4 -2
- data/lib/stimulus_plumbers/components/indicator.rb +3 -1
- data/lib/stimulus_plumbers/components/popover.rb +7 -3
- data/lib/stimulus_plumbers/components/progress_bar.rb +3 -1
- data/lib/stimulus_plumbers/components/progress_meter.rb +3 -1
- data/lib/stimulus_plumbers/components/progress_ring.rb +3 -1
- data/lib/stimulus_plumbers/components/timeline/event.rb +4 -2
- data/lib/stimulus_plumbers/form/field.rb +4 -2
- data/lib/stimulus_plumbers/form/fields/inputs/code.rb +93 -32
- data/lib/stimulus_plumbers/form/fields/inputs/credit_card.rb +61 -33
- data/lib/stimulus_plumbers/form/fields/inputs/password.rb +5 -2
- data/lib/stimulus_plumbers/form/fields/inputs/submit.rb +52 -7
- data/lib/stimulus_plumbers/generators/css_entrypoint.rb +10 -0
- data/lib/stimulus_plumbers/plumber/dispatcher.rb +14 -12
- data/lib/stimulus_plumbers/plumber/slots.rb +8 -8
- data/lib/stimulus_plumbers/themes/schema.rb +4 -0
- data/lib/stimulus_plumbers/version.rb +1 -1
- data/lib/stimulus_plumbers.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: daf604780fb07315e9c562c6a3c9d4ea0cb054c03236c0947e1a58ed0d100ba0
|
|
4
|
+
data.tar.gz: abbb7e4dbe89695cd04a6c1951d1c693ac3c24bcc45d3ccace964c62b1fec6ac
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a99f6ebfbbb8e7aa0bfb273926f6828a82fb463b19407ef84f9d145d5e7f59aa14486f0388fc1aad96c6a76cd1508edae469f42bf3e2274915037e5faf2875d3
|
|
7
|
+
data.tar.gz: 33a5f7f61e581f30604a9f6a49c55d2b244f52aa0d52283c0c114e57e45adca7dee6013bdc7072a9c511d42edd96cbd1ec01d18ac476bbfd1a5dd4d675e3748e
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
---
|
|
6
|
+
## [0.4.11](https://github.com/ryancyq/stimulus-plumbers/compare/stimulus-plumbers-rails/v0.4.10..stimulus-plumbers-rails/v0.4.11) - 2026-07-19
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- tailwind source being committed with machine path. migrate to generated source file which should be gitignored + import the generated file in css entry point file instead. ([#180](https://github.com/ryancyq/stimulus-plumbers/issues/180)) - ([347e6ed](https://github.com/ryancyq/stimulus-plumbers/commit/347e6edeee92571f4f2fe7e509b5eed8fd0f2893)) - Ryan Chang
|
|
11
|
+
|
|
5
12
|
---
|
|
6
13
|
## [0.4.10](https://github.com/ryancyq/stimulus-plumbers/compare/stimulus-plumbers-rails/v0.4.9..stimulus-plumbers-rails/v0.4.10) - 2026-07-19
|
|
7
14
|
|
data/docs/architecture.md
CHANGED
|
@@ -26,6 +26,6 @@ Validation ranges for theme schema params live under `lib/stimulus_plumbers/them
|
|
|
26
26
|
|
|
27
27
|
`Button#build_button` and `Link#build_content` always wrap non-nil text/block content in `<span>`. When content is nil and no block is given (icon-only), no `<span>` is rendered.
|
|
28
28
|
|
|
29
|
-
The active theme uses `:has(> span)` / `:not(:has(> span))` CSS to distinguish icon-only from text buttons without any Ruby flag.
|
|
29
|
+
The active theme uses `:has(> span)` / `:not(:has(> span))` CSS to distinguish icon-only from text buttons without any Ruby flag. Submit buttons with visually hidden text additionally use `:has(> span[data-sp-label-hidden])` so they retain the icon-only square layout while keeping an accessible name.
|
|
30
30
|
|
|
31
31
|
**Do not change this contract** without updating `stimulus-plumbers-tailwind`'s `Button::LAYOUT` and `Link::BUTTON` constants accordingly. See [tailwind architecture doc](../../stimulus-plumbers-tailwind/docs/architecture.md#icon-only-square-pattern).
|
data/docs/component/form.md
CHANGED
|
@@ -55,6 +55,25 @@ Special options on native helpers:
|
|
|
55
55
|
| `password_field` | `revealable: true` | Wraps input in an `input-formatter` reveal controller |
|
|
56
56
|
| `search_field` | `clearable: true` | Wraps input in an `input-clearable` controller with a clear button |
|
|
57
57
|
|
|
58
|
+
### f.submit
|
|
59
|
+
|
|
60
|
+
`f.submit` renders a themed `<button type="submit">` without a field wrapper.
|
|
61
|
+
|
|
62
|
+
```erb
|
|
63
|
+
<%= f.submit "Save" %>
|
|
64
|
+
<%= f.submit "Save", icon_leading: "save" %>
|
|
65
|
+
<%= f.submit "Continue", icon_trailing: "arrow-right" %>
|
|
66
|
+
<%= f.submit "Save", icon_leading: "save", hide_label: true %>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
| Option | Description |
|
|
70
|
+
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
71
|
+
| `type:` / `variant:` | Button theme type and variant. |
|
|
72
|
+
| `icon_leading:` / `icon_trailing:` | Decorative icon name placed before or after the submit text. |
|
|
73
|
+
| `hide_label: true` | Visually hides the button's own text span while keeping it available to screen readers. This differs from `Form::Field#hide_label`, which hides an associated `<label>` element. |
|
|
74
|
+
|
|
75
|
+
Submit buttons need an accessible name: pass non-blank text, or an `aria` label such as `aria: { label: "Save changes" }`.
|
|
76
|
+
|
|
58
77
|
---
|
|
59
78
|
|
|
60
79
|
## Level 2 — Full-field helpers
|
|
@@ -151,21 +170,23 @@ Use `f.password_field` for a plain `<input type="password">` (also accepts `reve
|
|
|
151
170
|
|
|
152
171
|
**Code** (`as: :code`) — character-cell entry backed by `input-formatter` and the `character-cells` plumber. The native input remains the accessible control; cells are decorative.
|
|
153
172
|
|
|
154
|
-
| Option | Values | Default | Description
|
|
155
|
-
| -------------- | ---------------------------------------- | ---------------------- |
|
|
156
|
-
| `length` | positive Integer | required | Number of cells and input maximum length
|
|
157
|
-
| `charset` | `:digits` / `:letters` / `:alphanumeric` | `:digits` | Allowed code characters
|
|
158
|
-
| `groups` | Array of positive Integers | `[]` | Visual cell groups; must add up to `length`
|
|
159
|
-
| `
|
|
160
|
-
| `
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
|
166
|
-
|
|
|
167
|
-
| `
|
|
168
|
-
| `
|
|
173
|
+
| Option | Values | Default | Description |
|
|
174
|
+
| -------------- | ---------------------------------------- | ---------------------- | -------------------------------------------------------- |
|
|
175
|
+
| `length` | positive Integer | required | Number of cells and input maximum length |
|
|
176
|
+
| `charset` | `:digits` / `:letters` / `:alphanumeric` | `:digits` | Allowed code characters |
|
|
177
|
+
| `groups` | Array of positive Integers | `[]` | Visual cell groups; must add up to `length` |
|
|
178
|
+
| `separator` | String / `nil` | `nil` | Character between groups; `nil` shows the break as a gap |
|
|
179
|
+
| `autocomplete` | String | `"one-time-code"` | Native autocomplete value |
|
|
180
|
+
| `inputmode` | String | `"numeric"` for digits | Native input mode |
|
|
181
|
+
|
|
182
|
+
**Credit card** (`as: :credit_card`) — grouped card-number entry backed by `input-formatter` and the `character-cells` plumber (grouped mode). Renders one cell per group; their sum sets `maxlength`.
|
|
183
|
+
|
|
184
|
+
| Option | Values | Default | Description |
|
|
185
|
+
| -------------- | -------------------------- | -------------- | ------------------------------------------------------------ |
|
|
186
|
+
| `groups` | Array of positive Integers | `[4, 4, 4, 4]` | Cell groups — one cell per group; their sum sets `maxlength` |
|
|
187
|
+
| `separator` | String / `nil` | `nil` | Character between cells; `nil` renders none |
|
|
188
|
+
| `autocomplete` | String | `"cc-number"` | Native autocomplete value |
|
|
189
|
+
| `inputmode` | String | `"numeric"` | Native input mode |
|
|
169
190
|
|
|
170
191
|
Character-cell fields do not support `floating:` labels.
|
|
171
192
|
|
data/docs/guide.md
CHANGED
|
@@ -12,7 +12,8 @@ Use `StimulusPlumbers::Form::Builder` (set `config.action_view.default_form_buil
|
|
|
12
12
|
- **Level 1.** Native helper overrides (`f.text_field`, `f.select`, `f.check_box`, ...) render
|
|
13
13
|
only the themed input element — use when you control the surrounding markup.
|
|
14
14
|
|
|
15
|
-
Submit with `f.submit` (themed button
|
|
15
|
+
Submit with `f.submit` (themed button; supports `icon_leading:`/`icon_trailing:` and
|
|
16
|
+
`hide_label:` for an icon-only button — see [docs/component/form.md](component/form.md)).
|
|
16
17
|
|
|
17
18
|
## Building views
|
|
18
19
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Components
|
|
5
|
+
class Button < Plumber::Base
|
|
6
|
+
module IconLayout
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def build_layout(slots, &block)
|
|
10
|
+
@template.safe_join(
|
|
11
|
+
[
|
|
12
|
+
render_icon_slot(slots, :icon_leading),
|
|
13
|
+
@template.capture(&block),
|
|
14
|
+
render_icon_slot(slots, :icon_trailing)
|
|
15
|
+
]
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def render_icon_slot(slots, name)
|
|
20
|
+
slots.resolve(name) do |value|
|
|
21
|
+
next value unless Components::Icon.icon_name?(value)
|
|
22
|
+
|
|
23
|
+
Components::Icon.new(@template).render(
|
|
24
|
+
name: value,
|
|
25
|
+
size: :sm,
|
|
26
|
+
classes: theme.resolve(:button_icon).fetch(:classes, ""),
|
|
27
|
+
aria: { hidden: "true" }
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
module StimulusPlumbers
|
|
4
4
|
module Components
|
|
5
5
|
class Button < Plumber::Base
|
|
6
|
+
include IconLayout
|
|
7
|
+
|
|
6
8
|
def render(content = nil, icon_leading: nil, icon_trailing: nil, **kwargs, &block)
|
|
7
9
|
slots = Button::Slots.new(template)
|
|
8
10
|
slots.with_icon_leading(icon_leading) if icon_leading
|
|
@@ -34,29 +36,6 @@ module StimulusPlumbers
|
|
|
34
36
|
template.content_tag(:span, content)
|
|
35
37
|
end
|
|
36
38
|
end
|
|
37
|
-
|
|
38
|
-
def build_layout(slots, &block)
|
|
39
|
-
template.safe_join(
|
|
40
|
-
[
|
|
41
|
-
render_icon_slot(slots, :icon_leading),
|
|
42
|
-
template.capture(&block),
|
|
43
|
-
render_icon_slot(slots, :icon_trailing)
|
|
44
|
-
]
|
|
45
|
-
)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def render_icon_slot(slots, name)
|
|
49
|
-
slots.resolve(name) do |value|
|
|
50
|
-
next value unless Components::Icon.icon_name?(value)
|
|
51
|
-
|
|
52
|
-
Components::Icon.new(template).render(
|
|
53
|
-
name: value,
|
|
54
|
-
size: :sm,
|
|
55
|
-
classes: theme.resolve(:button_icon).fetch(:classes, ""),
|
|
56
|
-
aria: { hidden: "true" }
|
|
57
|
-
)
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
39
|
end
|
|
61
40
|
end
|
|
62
41
|
end
|
|
@@ -6,15 +6,37 @@ module StimulusPlumbers
|
|
|
6
6
|
# Yielded to `Combobox#render`: selects a variant renderer, then exposes its
|
|
7
7
|
# `metadata` (trigger/wrapper wiring) and renders its panel body.
|
|
8
8
|
class Builder < Plumber::Slots
|
|
9
|
-
def dropdown(**options)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
def dropdown(**options)
|
|
10
|
+
select(Dropdown, options)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def typeahead(**options)
|
|
14
|
+
select(Typeahead, options)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def date(**options)
|
|
18
|
+
select(Date, options)
|
|
19
|
+
end
|
|
13
20
|
|
|
14
|
-
def
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
21
|
+
def time(**options)
|
|
22
|
+
select(Time, options)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def selected?
|
|
26
|
+
@slots.key?(:variant)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def renderer
|
|
30
|
+
selection&.fetch(:renderer)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def options
|
|
34
|
+
selection ? selection[:options] : {}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def metadata
|
|
38
|
+
renderer ? renderer::Metadata : DefaultMetadata
|
|
39
|
+
end
|
|
18
40
|
|
|
19
41
|
def render_panel(template, panel_attrs:)
|
|
20
42
|
renderer&.new(template)&.render(panel_attrs: panel_attrs, **options)
|
|
@@ -24,11 +46,25 @@ module StimulusPlumbers
|
|
|
24
46
|
module DefaultMetadata
|
|
25
47
|
module_function
|
|
26
48
|
|
|
27
|
-
def haspopup
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def
|
|
49
|
+
def haspopup
|
|
50
|
+
"dialog"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def popup_id_for(panel_id)
|
|
54
|
+
panel_id
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def trigger_icon
|
|
58
|
+
nil
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def trigger_options
|
|
62
|
+
{}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def stimulus_data(_panel_id, _options)
|
|
66
|
+
{}
|
|
67
|
+
end
|
|
32
68
|
end
|
|
33
69
|
|
|
34
70
|
private
|
|
@@ -38,7 +74,9 @@ module StimulusPlumbers
|
|
|
38
74
|
nil
|
|
39
75
|
end
|
|
40
76
|
|
|
41
|
-
def selection
|
|
77
|
+
def selection
|
|
78
|
+
resolve(:variant)
|
|
79
|
+
end
|
|
42
80
|
end
|
|
43
81
|
end
|
|
44
82
|
end
|
|
@@ -16,21 +16,47 @@ module StimulusPlumbers
|
|
|
16
16
|
"#{STIMULUS_CONTROLLER}:selected->#{Components::Popover::STIMULUS_CONTROLLER}#closeOnSelect"
|
|
17
17
|
].join(" ").freeze
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
class << self
|
|
20
|
+
def month_id_for(panel_id)
|
|
21
|
+
[panel_id, "calendar_month"].compact.join("_")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def year_id_for(panel_id)
|
|
25
|
+
[panel_id, "calendar_year"].compact.join("_")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def decade_id_for(panel_id)
|
|
29
|
+
[panel_id, "calendar_decade"].compact.join("_")
|
|
30
|
+
end
|
|
31
|
+
end
|
|
22
32
|
|
|
23
33
|
module Metadata
|
|
24
34
|
module_function
|
|
25
35
|
|
|
26
|
-
def haspopup
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def
|
|
36
|
+
def haspopup
|
|
37
|
+
"dialog"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def popup_id_for(panel_id)
|
|
41
|
+
panel_id
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def trigger_icon
|
|
45
|
+
"calendar"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def trigger_options
|
|
49
|
+
{}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def stimulus_data(_panel_id, _options)
|
|
53
|
+
{ input_formatter_format_value: "date" }
|
|
54
|
+
end
|
|
31
55
|
end
|
|
32
56
|
|
|
33
|
-
def render(...)
|
|
57
|
+
def render(...)
|
|
58
|
+
render_date(...)
|
|
59
|
+
end
|
|
34
60
|
|
|
35
61
|
private
|
|
36
62
|
|
|
@@ -15,14 +15,30 @@ module StimulusPlumbers
|
|
|
15
15
|
module Metadata
|
|
16
16
|
module_function
|
|
17
17
|
|
|
18
|
-
def haspopup
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def
|
|
18
|
+
def haspopup
|
|
19
|
+
"listbox"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def popup_id_for(panel_id)
|
|
23
|
+
panel_id
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def trigger_icon
|
|
27
|
+
"chevron-down"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def trigger_options
|
|
31
|
+
{}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def stimulus_data(_panel_id, _options)
|
|
35
|
+
{}
|
|
36
|
+
end
|
|
23
37
|
end
|
|
24
38
|
|
|
25
|
-
def render(...)
|
|
39
|
+
def render(...)
|
|
40
|
+
render_dropdown(...)
|
|
41
|
+
end
|
|
26
42
|
|
|
27
43
|
private
|
|
28
44
|
|
|
@@ -13,10 +13,21 @@ module StimulusPlumbers
|
|
|
13
13
|
module Metadata
|
|
14
14
|
module_function
|
|
15
15
|
|
|
16
|
-
def haspopup
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
def haspopup
|
|
17
|
+
"dialog"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def popup_id_for(panel_id)
|
|
21
|
+
panel_id
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def trigger_icon
|
|
25
|
+
"clock"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def trigger_options
|
|
29
|
+
{}
|
|
30
|
+
end
|
|
20
31
|
|
|
21
32
|
def stimulus_data(_panel_id, options)
|
|
22
33
|
{
|
|
@@ -26,7 +37,9 @@ module StimulusPlumbers
|
|
|
26
37
|
end
|
|
27
38
|
end
|
|
28
39
|
|
|
29
|
-
def render(...)
|
|
40
|
+
def render(...)
|
|
41
|
+
render_time(...)
|
|
42
|
+
end
|
|
30
43
|
|
|
31
44
|
private
|
|
32
45
|
|
|
@@ -4,17 +4,30 @@ module StimulusPlumbers
|
|
|
4
4
|
module Components
|
|
5
5
|
class Combobox
|
|
6
6
|
class Typeahead < Plumber::Base
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
class << self
|
|
8
|
+
def listbox_id_for(panel_id)
|
|
9
|
+
[panel_id, "listbox"].compact.join("_")
|
|
10
|
+
end
|
|
9
11
|
end
|
|
10
12
|
|
|
11
13
|
module Metadata
|
|
12
14
|
module_function
|
|
13
15
|
|
|
14
|
-
def haspopup
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
def haspopup
|
|
17
|
+
"listbox"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def popup_id_for(panel_id)
|
|
21
|
+
Typeahead.listbox_id_for(panel_id)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def trigger_icon
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def trigger_options
|
|
29
|
+
{ readonly: false, aria: { autocomplete: "list" } }
|
|
30
|
+
end
|
|
18
31
|
|
|
19
32
|
def stimulus_data(panel_id, _options)
|
|
20
33
|
{
|
|
@@ -24,7 +37,9 @@ module StimulusPlumbers
|
|
|
24
37
|
end
|
|
25
38
|
end
|
|
26
39
|
|
|
27
|
-
def render(...)
|
|
40
|
+
def render(...)
|
|
41
|
+
render_typeahead(...)
|
|
42
|
+
end
|
|
28
43
|
|
|
29
44
|
private
|
|
30
45
|
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
module StimulusPlumbers
|
|
4
4
|
module Components
|
|
5
5
|
class Icon < Plumber::Base
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
class << self
|
|
7
|
+
def icon_name?(value)
|
|
8
|
+
value.is_a?(Symbol) || (value.is_a?(String) && !value.html_safe?)
|
|
9
|
+
end
|
|
8
10
|
end
|
|
9
11
|
|
|
10
12
|
def render(name:, size: :lg, **kwargs)
|
|
@@ -5,11 +5,15 @@ module StimulusPlumbers
|
|
|
5
5
|
class Popover < Plumber::Base
|
|
6
6
|
STIMULUS_CONTROLLER = "popover"
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
class << self
|
|
9
|
+
def panel_id_for(trigger_id)
|
|
10
|
+
[trigger_id, "popover"].compact.join("_")
|
|
11
|
+
end
|
|
10
12
|
end
|
|
11
13
|
|
|
12
|
-
def render(...)
|
|
14
|
+
def render(...)
|
|
15
|
+
render_popover(...)
|
|
16
|
+
end
|
|
13
17
|
|
|
14
18
|
def build(panel_id: nil, &block)
|
|
15
19
|
@panel_id = panel_id || self.class.panel_id_for(template.sp_dom_id)
|
|
@@ -6,8 +6,10 @@ module StimulusPlumbers
|
|
|
6
6
|
class Event < Plumber::Base
|
|
7
7
|
attr_reader :interactive
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
class << self
|
|
10
|
+
def detail_id_for(event_id)
|
|
11
|
+
[event_id, "detail"].compact.join("_")
|
|
12
|
+
end
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
def render(datetime: nil, id: nil, interactive: false, orientation: :vertical, **kwargs, &block)
|
|
@@ -15,8 +15,10 @@ module StimulusPlumbers
|
|
|
15
15
|
|
|
16
16
|
attr_reader :hide_label
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
class << self
|
|
19
|
+
def label_id(input_id)
|
|
20
|
+
[input_id, "label"].compact.join("_")
|
|
21
|
+
end
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def initialize(template, hide_label: false, **kwargs)
|
|
@@ -5,64 +5,124 @@ module StimulusPlumbers
|
|
|
5
5
|
module Fields
|
|
6
6
|
module Inputs
|
|
7
7
|
module Code
|
|
8
|
+
STIMULUS_CONTROLLER = "input-formatter"
|
|
9
|
+
STIMULUS_ACTION = [
|
|
10
|
+
"input->#{STIMULUS_CONTROLLER}#onInput",
|
|
11
|
+
"focus->#{STIMULUS_CONTROLLER}#onFocus",
|
|
12
|
+
"blur->#{STIMULUS_CONTROLLER}#onBlur"
|
|
13
|
+
].join(" ").freeze
|
|
14
|
+
DEFAULT_CHARSET = :digits
|
|
15
|
+
DEFAULT_AUTOCOMPLETE = "one-time-code"
|
|
16
|
+
DEFAULT_SEPARATOR = nil
|
|
17
|
+
|
|
8
18
|
private
|
|
9
19
|
|
|
10
|
-
def render_code_input(
|
|
11
|
-
|
|
20
|
+
def render_code_input(
|
|
21
|
+
attribute,
|
|
22
|
+
html_opts,
|
|
23
|
+
opts,
|
|
24
|
+
error,
|
|
25
|
+
length: nil,
|
|
26
|
+
charset: DEFAULT_CHARSET,
|
|
27
|
+
groups: [],
|
|
28
|
+
separator: DEFAULT_SEPARATOR,
|
|
29
|
+
floating: nil,
|
|
30
|
+
**kwargs
|
|
31
|
+
)
|
|
12
32
|
raise ArgumentError, "floating labels are not supported for code fields" if floating.present?
|
|
13
33
|
|
|
14
34
|
validate_code_options!(length, groups)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
35
|
+
config = {
|
|
36
|
+
error: error,
|
|
37
|
+
length: length,
|
|
38
|
+
charset: charset,
|
|
39
|
+
groups: groups,
|
|
40
|
+
separator: separator,
|
|
41
|
+
autocomplete: kwargs.delete(:autocomplete) || DEFAULT_AUTOCOMPLETE,
|
|
42
|
+
inputmode: kwargs.delete(:inputmode) || (charset.to_sym == DEFAULT_CHARSET ? "numeric" : nil),
|
|
43
|
+
kwargs: kwargs
|
|
44
|
+
}
|
|
20
45
|
render_code_field(attribute, html_opts, opts, config)
|
|
21
46
|
end
|
|
22
47
|
|
|
23
48
|
def render_code_field(attribute, html_opts, opts, config)
|
|
24
|
-
|
|
49
|
+
overlay_options = merge_html_options(
|
|
50
|
+
theme.resolve(:form_field_input_code_overlay, error: config[:error]),
|
|
51
|
+
opts,
|
|
52
|
+
html_opts
|
|
53
|
+
)
|
|
54
|
+
wrapper_options = merge_html_options(
|
|
55
|
+
theme.resolve(:form_field_input_code, error: config[:error]),
|
|
56
|
+
code_options(config)
|
|
57
|
+
)
|
|
58
|
+
@template.content_tag(:div, **wrapper_options) do
|
|
25
59
|
@template.safe_join(
|
|
26
|
-
[render_code_cells(config), code_input(attribute,
|
|
60
|
+
[render_code_cells(config), code_input(attribute, overlay_options, config)]
|
|
27
61
|
)
|
|
28
62
|
end
|
|
29
63
|
end
|
|
30
64
|
|
|
31
|
-
def
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
controller: "input-formatter",
|
|
65
|
+
def code_options(config)
|
|
66
|
+
{
|
|
67
|
+
data: {
|
|
68
|
+
controller: STIMULUS_CONTROLLER,
|
|
36
69
|
input_formatter_format_value: "code",
|
|
37
|
-
input_formatter_options_value: { charset: config[:charset].to_s, length: config[:length] }
|
|
38
|
-
input_formatter_groups_value: config
|
|
70
|
+
input_formatter_options_value: { charset: config[:charset].to_s, length: config[:length] },
|
|
71
|
+
input_formatter_groups_value: code_groups_value(config)
|
|
39
72
|
}
|
|
40
|
-
}
|
|
41
|
-
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Server-rendered separators already mark the group breaks. Passing groups as well
|
|
77
|
+
# would stamp data-group-end and lay the themed gap on top of the separator.
|
|
78
|
+
def code_groups_value(config)
|
|
79
|
+
return if config[:separator].present?
|
|
80
|
+
|
|
81
|
+
config[:groups].presence
|
|
42
82
|
end
|
|
43
83
|
|
|
44
|
-
def code_input(attribute, html_opts,
|
|
84
|
+
def code_input(attribute, html_opts, config)
|
|
45
85
|
input_options = merge_html_options(
|
|
46
|
-
theme.resolve(:form_field_input_code_overlay, error: config[:error]),
|
|
47
|
-
opts,
|
|
48
86
|
html_opts,
|
|
49
87
|
config[:kwargs],
|
|
50
|
-
{
|
|
51
|
-
|
|
52
|
-
|
|
88
|
+
{
|
|
89
|
+
maxlength: config[:length],
|
|
90
|
+
autocomplete: config[:autocomplete],
|
|
91
|
+
inputmode: config[:inputmode],
|
|
92
|
+
data: { input_formatter_target: "input", action: STIMULUS_ACTION }
|
|
93
|
+
}
|
|
53
94
|
)
|
|
54
95
|
@template.text_field(@object_name, attribute, objectify_options(input_options))
|
|
55
96
|
end
|
|
56
97
|
|
|
57
98
|
def render_code_cells(config)
|
|
58
|
-
|
|
99
|
+
@template.content_tag(:div, **merge_html_options(theme.resolve(:form_field_input_code_cells))) do
|
|
100
|
+
@template.safe_join(code_cells(config))
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def code_cells(config)
|
|
105
|
+
groups = config[:groups].presence || [config[:length]]
|
|
106
|
+
groups.flat_map.with_index do |width, index|
|
|
107
|
+
cells = Array.new(width) { render_code_cell(config) }
|
|
108
|
+
index.zero? || config[:separator].blank? ? cells : [render_code_separator(config), *cells]
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def render_code_cell(config)
|
|
59
113
|
cell_options = merge_html_options(
|
|
60
114
|
theme.resolve(:form_field_input_code_cell, error: config[:error]),
|
|
61
115
|
{ data: { input_formatter_target: "cell" } }
|
|
62
116
|
)
|
|
63
|
-
@template.content_tag(:
|
|
64
|
-
|
|
65
|
-
|
|
117
|
+
@template.content_tag(:span, nil, **cell_options)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def render_code_separator(config)
|
|
121
|
+
separator_options = merge_html_options(
|
|
122
|
+
theme.resolve(:form_field_input_code_separator),
|
|
123
|
+
{ aria: { hidden: true } }
|
|
124
|
+
)
|
|
125
|
+
@template.content_tag(:span, config[:separator], **separator_options)
|
|
66
126
|
end
|
|
67
127
|
|
|
68
128
|
def validate_code_options!(length, groups)
|
|
@@ -73,11 +133,12 @@ module StimulusPlumbers
|
|
|
73
133
|
raise ArgumentError, "groups must add up to length" unless groups.sum == length
|
|
74
134
|
end
|
|
75
135
|
|
|
76
|
-
def valid_groups?(groups)
|
|
77
|
-
|
|
136
|
+
def valid_groups?(groups)
|
|
137
|
+
groups.is_a?(Array) && groups.all? { |group| positive_integer?(group) }
|
|
138
|
+
end
|
|
78
139
|
|
|
79
|
-
def
|
|
80
|
-
|
|
140
|
+
def positive_integer?(value)
|
|
141
|
+
value.is_a?(Integer) && value.positive?
|
|
81
142
|
end
|
|
82
143
|
end
|
|
83
144
|
end
|
|
@@ -5,64 +5,96 @@ module StimulusPlumbers
|
|
|
5
5
|
module Fields
|
|
6
6
|
module Inputs
|
|
7
7
|
module CreditCard
|
|
8
|
-
|
|
8
|
+
STIMULUS_CONTROLLER = "input-formatter"
|
|
9
|
+
STIMULUS_ACTION = [
|
|
10
|
+
"input->#{STIMULUS_CONTROLLER}#onInput",
|
|
11
|
+
"focus->#{STIMULUS_CONTROLLER}#onFocus",
|
|
12
|
+
"blur->#{STIMULUS_CONTROLLER}#onBlur"
|
|
13
|
+
].join(" ").freeze
|
|
14
|
+
DEFAULT_GROUPS = [4, 4, 4, 4].freeze
|
|
15
|
+
DEFAULT_AUTOCOMPLETE = "cc-number"
|
|
16
|
+
DEFAULT_INPUTMODE = "numeric"
|
|
17
|
+
DEFAULT_SEPARATOR = nil
|
|
9
18
|
|
|
10
19
|
private
|
|
11
20
|
|
|
12
|
-
def render_credit_card_input(
|
|
21
|
+
def render_credit_card_input(
|
|
22
|
+
attribute,
|
|
23
|
+
html_opts,
|
|
24
|
+
opts,
|
|
25
|
+
error,
|
|
26
|
+
groups: DEFAULT_GROUPS,
|
|
27
|
+
separator: DEFAULT_SEPARATOR,
|
|
28
|
+
floating: nil,
|
|
29
|
+
**kwargs
|
|
30
|
+
)
|
|
13
31
|
raise ArgumentError, "floating labels are not supported for credit card fields" if floating.present?
|
|
14
32
|
|
|
15
33
|
normalized_groups = groups.presence || DEFAULT_GROUPS
|
|
16
|
-
inputmode = kwargs.delete(:inputmode) || "numeric"
|
|
17
|
-
autocomplete = kwargs.delete(:autocomplete) || "cc-number"
|
|
18
34
|
validate_credit_card_groups!(normalized_groups)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
35
|
+
config = {
|
|
36
|
+
error: error,
|
|
37
|
+
groups: normalized_groups,
|
|
38
|
+
length: normalized_groups.sum,
|
|
39
|
+
separator: separator,
|
|
40
|
+
autocomplete: kwargs.delete(:autocomplete) || DEFAULT_AUTOCOMPLETE,
|
|
41
|
+
inputmode: kwargs.delete(:inputmode) || DEFAULT_INPUTMODE,
|
|
42
|
+
kwargs: kwargs
|
|
43
|
+
}
|
|
23
44
|
render_credit_card_field(attribute, html_opts, opts, config)
|
|
24
45
|
end
|
|
25
46
|
|
|
26
47
|
def render_credit_card_field(attribute, html_opts, opts, config)
|
|
27
|
-
|
|
48
|
+
overlay_options = merge_html_options(
|
|
49
|
+
theme.resolve(:form_field_input_credit_card_overlay, error: config[:error]),
|
|
50
|
+
opts,
|
|
51
|
+
html_opts
|
|
52
|
+
)
|
|
53
|
+
wrapper_options = merge_html_options(
|
|
54
|
+
theme.resolve(:form_field_input_credit_card, error: config[:error]),
|
|
55
|
+
credit_card_options(config)
|
|
56
|
+
)
|
|
57
|
+
@template.content_tag(:div, **wrapper_options) do
|
|
28
58
|
@template.safe_join(
|
|
29
|
-
[render_credit_card_cells(config), credit_card_input(attribute,
|
|
59
|
+
[render_credit_card_cells(config), credit_card_input(attribute, overlay_options, config)]
|
|
30
60
|
)
|
|
31
61
|
end
|
|
32
62
|
end
|
|
33
63
|
|
|
34
|
-
def
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
controller: "input-formatter",
|
|
64
|
+
def credit_card_options(config)
|
|
65
|
+
{
|
|
66
|
+
data: {
|
|
67
|
+
controller: STIMULUS_CONTROLLER,
|
|
39
68
|
input_formatter_format_value: "creditCard",
|
|
40
69
|
input_formatter_groups_value: config[:groups]
|
|
41
70
|
}
|
|
42
|
-
}
|
|
43
|
-
)
|
|
71
|
+
}
|
|
44
72
|
end
|
|
45
73
|
|
|
46
|
-
def credit_card_input(attribute, html_opts,
|
|
74
|
+
def credit_card_input(attribute, html_opts, config)
|
|
47
75
|
input_options = merge_html_options(
|
|
48
|
-
theme.resolve(:form_field_input_credit_card_overlay, error: config[:error]),
|
|
49
|
-
opts,
|
|
50
76
|
html_opts,
|
|
51
77
|
config[:kwargs],
|
|
52
|
-
{
|
|
53
|
-
|
|
54
|
-
|
|
78
|
+
{
|
|
79
|
+
maxlength: config[:length],
|
|
80
|
+
autocomplete: config[:autocomplete],
|
|
81
|
+
inputmode: config[:inputmode],
|
|
82
|
+
data: { input_formatter_target: "input", action: STIMULUS_ACTION }
|
|
83
|
+
}
|
|
55
84
|
)
|
|
56
85
|
@template.text_field(@object_name, attribute, objectify_options(input_options))
|
|
57
86
|
end
|
|
58
87
|
|
|
59
88
|
def render_credit_card_cells(config)
|
|
60
|
-
|
|
61
|
-
|
|
89
|
+
@template.content_tag(:div, **merge_html_options(theme.resolve(:form_field_input_credit_card_cells))) do
|
|
90
|
+
@template.safe_join(credit_card_cells(config))
|
|
62
91
|
end
|
|
92
|
+
end
|
|
63
93
|
|
|
64
|
-
|
|
65
|
-
|
|
94
|
+
def credit_card_cells(config)
|
|
95
|
+
config[:groups].each_index.flat_map do |index|
|
|
96
|
+
cell = render_credit_card_cell(config)
|
|
97
|
+
index.zero? || config[:separator].blank? ? [cell] : [render_credit_card_separator(config), cell]
|
|
66
98
|
end
|
|
67
99
|
end
|
|
68
100
|
|
|
@@ -74,12 +106,12 @@ module StimulusPlumbers
|
|
|
74
106
|
@template.content_tag(:span, nil, **cell_options)
|
|
75
107
|
end
|
|
76
108
|
|
|
77
|
-
def render_credit_card_separator
|
|
109
|
+
def render_credit_card_separator(config)
|
|
78
110
|
separator_options = merge_html_options(
|
|
79
111
|
theme.resolve(:form_field_input_credit_card_separator),
|
|
80
112
|
{ aria: { hidden: true } }
|
|
81
113
|
)
|
|
82
|
-
@template.content_tag(:span,
|
|
114
|
+
@template.content_tag(:span, config[:separator], **separator_options)
|
|
83
115
|
end
|
|
84
116
|
|
|
85
117
|
def validate_credit_card_groups!(groups)
|
|
@@ -87,10 +119,6 @@ module StimulusPlumbers
|
|
|
87
119
|
|
|
88
120
|
raise ArgumentError, "groups must be an array of positive integers"
|
|
89
121
|
end
|
|
90
|
-
|
|
91
|
-
def formatter_actions
|
|
92
|
-
"input->input-formatter#onInput focus->input-formatter#onFocus blur->input-formatter#onBlur"
|
|
93
|
-
end
|
|
94
122
|
end
|
|
95
123
|
end
|
|
96
124
|
end
|
|
@@ -5,6 +5,9 @@ module StimulusPlumbers
|
|
|
5
5
|
module Fields
|
|
6
6
|
module Inputs
|
|
7
7
|
module Password
|
|
8
|
+
STIMULUS_CONTROLLER = "input-formatter"
|
|
9
|
+
STIMULUS_ACTION = "click->#{STIMULUS_CONTROLLER}#toggle".freeze
|
|
10
|
+
|
|
8
11
|
def password_field(attribute, floating: nil, revealable: false, **options)
|
|
9
12
|
html_options = merge_html_options(theme.resolve(:form_field_input, floating: floating), options)
|
|
10
13
|
if revealable
|
|
@@ -42,7 +45,7 @@ module StimulusPlumbers
|
|
|
42
45
|
trailing: method(:reveal_button),
|
|
43
46
|
**merge_html_options(
|
|
44
47
|
theme.resolve(:form_field_input_reveal, error: error),
|
|
45
|
-
{ data: { controller:
|
|
48
|
+
{ data: { controller: STIMULUS_CONTROLLER, input_formatter_format_value: "password" } }
|
|
46
49
|
)
|
|
47
50
|
) { @template.capture(&block) }
|
|
48
51
|
end
|
|
@@ -66,7 +69,7 @@ module StimulusPlumbers
|
|
|
66
69
|
{
|
|
67
70
|
type: "button",
|
|
68
71
|
aria: { label: I18n.t("stimulus_plumbers.form.password.show", default: "Show password"), pressed: "false" },
|
|
69
|
-
data: { input_formatter_target: "toggle", action:
|
|
72
|
+
data: { input_formatter_target: "toggle", action: STIMULUS_ACTION }
|
|
70
73
|
}
|
|
71
74
|
)
|
|
72
75
|
) { @template.capture(&block) }
|
|
@@ -5,22 +5,67 @@ module StimulusPlumbers
|
|
|
5
5
|
module Fields
|
|
6
6
|
module Inputs
|
|
7
7
|
module Submit
|
|
8
|
+
include Components::Button::IconLayout
|
|
9
|
+
|
|
8
10
|
def submit(value = nil, options = {})
|
|
9
|
-
|
|
10
|
-
options = value
|
|
11
|
-
value = nil
|
|
12
|
-
end
|
|
11
|
+
value, options = normalize_submit_arguments(value, options)
|
|
13
12
|
value ||= submit_default_value
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
submit_options = extract_submit_options(options)
|
|
14
|
+
|
|
15
|
+
validate_submit_accessible_name!(value, options)
|
|
16
|
+
|
|
17
|
+
render_submit_button(value, options, **submit_options)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def normalize_submit_arguments(value, options)
|
|
23
|
+
value.is_a?(Hash) ? [nil, value] : [value, options]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def extract_submit_options(options)
|
|
27
|
+
{
|
|
28
|
+
type: options.delete(:type) { :default },
|
|
29
|
+
variant: options.delete(:variant) { :primary },
|
|
30
|
+
icon_leading: options.delete(:icon_leading),
|
|
31
|
+
icon_trailing: options.delete(:icon_trailing),
|
|
32
|
+
hide_label: options.delete(:hide_label) { false }
|
|
33
|
+
}
|
|
34
|
+
end
|
|
16
35
|
|
|
36
|
+
def render_submit_button(value, options, type:, variant:, icon_leading:, icon_trailing:, hide_label:)
|
|
17
37
|
Components::Button.new(@template).build(type: type, variant: variant) do |attrs|
|
|
18
38
|
@template.tag.button(
|
|
19
39
|
type: "submit",
|
|
20
40
|
**merge_html_options(attrs, theme.resolve(:form_submit, type: type, variant: variant), options)
|
|
21
|
-
) {
|
|
41
|
+
) { build_layout(submit_slots(icon_leading, icon_trailing)) { submit_label(value, hide_label) } }
|
|
22
42
|
end
|
|
23
43
|
end
|
|
44
|
+
|
|
45
|
+
def submit_slots(icon_leading, icon_trailing)
|
|
46
|
+
Components::Button::Slots.new(@template).tap do |slots|
|
|
47
|
+
slots.with_icon_leading(icon_leading) if icon_leading
|
|
48
|
+
slots.with_icon_trailing(icon_trailing) if icon_trailing
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def submit_label(value, hide_label)
|
|
53
|
+
@template.content_tag(
|
|
54
|
+
:span,
|
|
55
|
+
value,
|
|
56
|
+
**merge_html_options(
|
|
57
|
+
theme.resolve(:form_submit_label, hidden: hide_label),
|
|
58
|
+
(hide_label ? { data: { sp_label_hidden: true } } : {})
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def validate_submit_accessible_name!(value, options)
|
|
64
|
+
return if value.present? || options.dig(:aria, :label).present? ||
|
|
65
|
+
options.dig(:aria, :labelledby).present? || options[:"aria-label"].present?
|
|
66
|
+
|
|
67
|
+
raise ArgumentError, "submit button has no accessible name: pass a value or aria: { label: ... }"
|
|
68
|
+
end
|
|
24
69
|
end
|
|
25
70
|
end
|
|
26
71
|
end
|
|
@@ -74,6 +74,7 @@ module StimulusPlumbers
|
|
|
74
74
|
|
|
75
75
|
entry = "/#{relative_to_destination(path)}"
|
|
76
76
|
return if File.readlines(gitignore, chomp: true).include?(entry)
|
|
77
|
+
return if git_ignores?(path)
|
|
77
78
|
|
|
78
79
|
File.open(gitignore, "a") { |file| file.puts(entry) }
|
|
79
80
|
say_status :append, ".gitignore", :green
|
|
@@ -81,6 +82,15 @@ module StimulusPlumbers
|
|
|
81
82
|
say "Could not update .gitignore: #{e.message}. Skipping.", :yellow
|
|
82
83
|
end
|
|
83
84
|
|
|
85
|
+
def git_ignores?(path)
|
|
86
|
+
Dir.chdir(destination_root) do
|
|
87
|
+
system("git", "check-ignore", "-q", relative_to_destination(path), out: File::NULL, err: File::NULL)
|
|
88
|
+
end
|
|
89
|
+
rescue StandardError => e
|
|
90
|
+
say "Could not check .gitignore coverage with git: #{e.message}. Proceeding to append.", :yellow
|
|
91
|
+
false
|
|
92
|
+
end
|
|
93
|
+
|
|
84
94
|
# CSS copied by an installer belongs to the application from this point on.
|
|
85
95
|
# Keep an existing file intact so a generator rerun never overwrites local
|
|
86
96
|
# customizations (the same policy used by tailwindcss-rails' installer).
|
|
@@ -8,19 +8,21 @@ require_relative "dispatcher/klass_proxy"
|
|
|
8
8
|
module StimulusPlumbers
|
|
9
9
|
module Plumber
|
|
10
10
|
module Dispatcher
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
class << self
|
|
12
|
+
def build(callable, *args, method_name: nil, init_args: [], init_kwargs: {}, **kwargs, &block)
|
|
13
|
+
case callable
|
|
14
|
+
when Symbol
|
|
15
|
+
MethodCall.new(callable, *args, **kwargs, &block)
|
|
16
|
+
when Proc
|
|
17
|
+
InstanceExec.new(callable, *args, **kwargs)
|
|
18
|
+
when Module
|
|
19
|
+
KlassProxy.new(callable, method_name, *args, init_args: init_args, init_kwargs: init_kwargs, **kwargs, &block)
|
|
20
|
+
when String
|
|
21
|
+
klass = callable.safe_constantize
|
|
22
|
+
raise ArgumentError, "could not resolve class from: #{callable.inspect}" unless klass
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
KlassProxy.new(klass, method_name, *args, init_args: init_args, init_kwargs: init_kwargs, **kwargs, &block)
|
|
25
|
+
end
|
|
24
26
|
end
|
|
25
27
|
end
|
|
26
28
|
end
|
|
@@ -3,14 +3,6 @@
|
|
|
3
3
|
module StimulusPlumbers
|
|
4
4
|
module Plumber
|
|
5
5
|
class Slots
|
|
6
|
-
def self.slot(*names, by: nil)
|
|
7
|
-
names.each do |name|
|
|
8
|
-
by ? define_by_slot(name, by) : define_flat_slot(name)
|
|
9
|
-
define_reader(name)
|
|
10
|
-
define_predicate(name)
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
6
|
def initialize(template = nil)
|
|
15
7
|
@slots = {}
|
|
16
8
|
@template = template
|
|
@@ -50,6 +42,14 @@ module StimulusPlumbers
|
|
|
50
42
|
end
|
|
51
43
|
|
|
52
44
|
class << self
|
|
45
|
+
def slot(*names, by: nil)
|
|
46
|
+
names.each do |name|
|
|
47
|
+
by ? define_by_slot(name, by) : define_flat_slot(name)
|
|
48
|
+
define_reader(name)
|
|
49
|
+
define_predicate(name)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
53
|
private
|
|
54
54
|
|
|
55
55
|
def define_flat_slot(name)
|
|
@@ -186,6 +186,7 @@ module StimulusPlumbers
|
|
|
186
186
|
form_field_input_code_cell: {
|
|
187
187
|
error: { default: false, validate: Ranges::BOOL }
|
|
188
188
|
}.freeze,
|
|
189
|
+
form_field_input_code_separator: {}.freeze,
|
|
189
190
|
form_field_input_code_overlay: {
|
|
190
191
|
error: { default: false, validate: Ranges::BOOL }
|
|
191
192
|
}.freeze,
|
|
@@ -205,6 +206,9 @@ module StimulusPlumbers
|
|
|
205
206
|
form_submit: {
|
|
206
207
|
type: { default: :default, validate: Button::Ranges::TYPE },
|
|
207
208
|
variant: { default: :primary, validate: Button::Ranges::VARIANT }
|
|
209
|
+
}.freeze,
|
|
210
|
+
form_submit_label: {
|
|
211
|
+
hidden: { default: false, validate: Ranges::BOOL }
|
|
208
212
|
}.freeze
|
|
209
213
|
}.freeze
|
|
210
214
|
|
data/lib/stimulus_plumbers.rb
CHANGED
|
@@ -19,6 +19,7 @@ require_relative "stimulus_plumbers/plumber/base"
|
|
|
19
19
|
require_relative "stimulus_plumbers/components/icon"
|
|
20
20
|
require_relative "stimulus_plumbers/components/indicator"
|
|
21
21
|
require_relative "stimulus_plumbers/components/avatar"
|
|
22
|
+
require_relative "stimulus_plumbers/components/button/icon_layout"
|
|
22
23
|
require_relative "stimulus_plumbers/components/button"
|
|
23
24
|
require_relative "stimulus_plumbers/components/button/slots"
|
|
24
25
|
require_relative "stimulus_plumbers/components/button/group"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: stimulus_plumbers
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.12
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ryan Chang
|
|
@@ -74,6 +74,7 @@ files:
|
|
|
74
74
|
- lib/stimulus_plumbers/components/avatar.rb
|
|
75
75
|
- lib/stimulus_plumbers/components/button.rb
|
|
76
76
|
- lib/stimulus_plumbers/components/button/group.rb
|
|
77
|
+
- lib/stimulus_plumbers/components/button/icon_layout.rb
|
|
77
78
|
- lib/stimulus_plumbers/components/button/slots.rb
|
|
78
79
|
- lib/stimulus_plumbers/components/calendar.rb
|
|
79
80
|
- lib/stimulus_plumbers/components/calendar/turbo.rb
|