stimulus_plumbers 0.4.5 → 0.4.9
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 +23 -0
- data/README.md +15 -1
- data/app/assets/javascripts/stimulus-plumbers/controllers.manifest.json +331 -20
- data/app/assets/javascripts/stimulus-plumbers/index.es.js +493 -226
- data/app/assets/javascripts/stimulus-plumbers/index.es.js.map +1 -1
- data/app/assets/javascripts/stimulus-plumbers/index.umd.js +1 -1
- data/app/assets/javascripts/stimulus-plumbers/index.umd.js.map +1 -1
- data/app/assets/stylesheets/stimulus_plumbers/tokens.css +58 -53
- data/docs/architecture.md +0 -2
- data/docs/component/avatar.md +1 -0
- data/docs/component/button.md +2 -1
- data/docs/component/calendar.md +18 -20
- data/docs/component/card.md +14 -12
- data/docs/component/checklist.md +153 -0
- data/docs/component/combobox.md +2 -2
- data/docs/component/form.md +32 -6
- data/docs/component/icon.md +7 -5
- data/docs/component/indicator.md +55 -0
- data/docs/component/list.md +4 -5
- data/docs/component/ordered_list.md +118 -0
- data/docs/component/plumber.md +43 -0
- data/docs/component/popover.md +1 -2
- data/docs/component/progress.md +65 -0
- data/docs/component/theme.md +15 -2
- data/docs/component/timeline.md +49 -14
- data/docs/guide.md +39 -0
- data/lib/generators/stimulus_plumbers/install/install_generator.rb +33 -0
- data/lib/stimulus_plumbers/components/button.rb +2 -1
- data/lib/stimulus_plumbers/components/card.rb +1 -1
- data/lib/stimulus_plumbers/components/checklist/item/slots.rb +13 -0
- data/lib/stimulus_plumbers/components/checklist/item.rb +64 -0
- data/lib/stimulus_plumbers/components/checklist.rb +50 -0
- data/lib/stimulus_plumbers/components/combobox/typeahead.rb +1 -0
- data/lib/stimulus_plumbers/components/combobox.rb +1 -1
- data/lib/stimulus_plumbers/components/icon.rb +2 -2
- data/lib/stimulus_plumbers/components/indicator.rb +30 -0
- data/lib/stimulus_plumbers/components/link.rb +2 -1
- data/lib/stimulus_plumbers/components/list/item.rb +1 -1
- data/lib/stimulus_plumbers/components/ordered_list/item/slots.rb +13 -0
- data/lib/stimulus_plumbers/components/ordered_list/item.rb +129 -0
- data/lib/stimulus_plumbers/components/ordered_list.rb +24 -0
- data/lib/stimulus_plumbers/components/progress_bar.rb +48 -0
- data/lib/stimulus_plumbers/components/progress_meter.rb +37 -0
- data/lib/stimulus_plumbers/components/progress_ring.rb +40 -0
- data/lib/stimulus_plumbers/components/timeline/event.rb +3 -2
- data/lib/stimulus_plumbers/components/timeline/group.rb +5 -3
- data/lib/stimulus_plumbers/engine.rb +4 -0
- data/lib/stimulus_plumbers/form/fields/inputs/password.rb +1 -0
- data/lib/stimulus_plumbers/form/fields/inputs/search.rb +1 -0
- data/lib/stimulus_plumbers/generators/css_entrypoint.rb +80 -0
- data/lib/stimulus_plumbers/generators/tokens_directive.rb +24 -0
- data/lib/stimulus_plumbers/helpers/avatar_helper.rb +1 -7
- data/lib/stimulus_plumbers/helpers/button_helper.rb +1 -7
- data/lib/stimulus_plumbers/helpers/calendar_helper.rb +2 -9
- data/lib/stimulus_plumbers/helpers/calendar_turbo_helper.rb +3 -6
- data/lib/stimulus_plumbers/helpers/checklist_helper.rb +11 -0
- data/lib/stimulus_plumbers/helpers/indicator_helper.rb +11 -0
- data/lib/stimulus_plumbers/helpers/ordered_list_helper.rb +11 -0
- data/lib/stimulus_plumbers/helpers/popover_helper.rb +1 -7
- data/lib/stimulus_plumbers/helpers/progress_helper.rb +21 -0
- data/lib/stimulus_plumbers/helpers.rb +8 -0
- data/lib/stimulus_plumbers/plumber/slots.rb +10 -3
- data/lib/stimulus_plumbers/themes/base.rb +4 -0
- data/lib/stimulus_plumbers/themes/schema/icon.rb +21 -4
- data/lib/stimulus_plumbers/themes/schema/indicator/ranges.rb +14 -0
- data/lib/stimulus_plumbers/themes/schema.rb +39 -3
- data/lib/stimulus_plumbers/version.rb +1 -1
- data/lib/stimulus_plumbers.rb +10 -0
- data/lib/tasks/stimulus_plumbers.rake +18 -0
- data/vendor/ARIA.md +108 -0
- data/vendor/component/manifest.json +212 -0
- data/vendor/controller/docs/calendar.md +212 -0
- data/vendor/controller/docs/checklist.md +45 -0
- data/vendor/controller/docs/clipboard.md +61 -0
- data/vendor/controller/docs/combobox.md +212 -0
- data/vendor/controller/docs/dismisser.md +39 -0
- data/vendor/controller/docs/flipper.md +46 -0
- data/vendor/controller/docs/input-clearable.md +43 -0
- data/vendor/controller/docs/input-formatter.md +89 -0
- data/vendor/controller/docs/modal.md +57 -0
- data/vendor/controller/docs/panner.md +24 -0
- data/vendor/controller/docs/popover.md +111 -0
- data/vendor/controller/docs/progress.md +82 -0
- data/vendor/controller/docs/reorderable.md +82 -0
- data/vendor/controller/docs/timeline.md +84 -0
- data/vendor/controller/docs/visibility.md +31 -0
- data/vendor/controller/guide.md +16 -0
- data/vendor/{controllers.manifest.json → controller/manifest.json} +331 -20
- metadata +44 -2
|
@@ -6,7 +6,7 @@ module StimulusPlumbers
|
|
|
6
6
|
def render(content = nil, url:, icon_leading: nil, icon_trailing: nil, **kwargs, &block)
|
|
7
7
|
icon_trailing ||= "external-link" if kwargs[:target] == "_blank"
|
|
8
8
|
|
|
9
|
-
slots = Link::Slots.new
|
|
9
|
+
slots = Link::Slots.new(template)
|
|
10
10
|
slots.with_icon_leading(icon_leading) if icon_leading
|
|
11
11
|
slots.with_icon_trailing(icon_trailing) if icon_trailing
|
|
12
12
|
|
|
@@ -45,6 +45,7 @@ module StimulusPlumbers
|
|
|
45
45
|
|
|
46
46
|
Components::Icon.new(template).render(
|
|
47
47
|
name: value,
|
|
48
|
+
size: :sm,
|
|
48
49
|
classes: theme.resolve(:link_icon).fetch(:classes, ""),
|
|
49
50
|
aria: { hidden: "true" }
|
|
50
51
|
)
|
|
@@ -5,7 +5,7 @@ module StimulusPlumbers
|
|
|
5
5
|
class List
|
|
6
6
|
class Item < Plumber::Base
|
|
7
7
|
def render(content = nil, **kwargs, &block)
|
|
8
|
-
slots = List::Item::Slots.new
|
|
8
|
+
slots = List::Item::Slots.new(template)
|
|
9
9
|
slots.with_title(content) if content
|
|
10
10
|
slots.with_icon_trailing("external-link") if kwargs[:url].present? && kwargs[:target] == "_blank"
|
|
11
11
|
yield slots if block_given?
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Components
|
|
5
|
+
class OrderedList
|
|
6
|
+
class Item < Plumber::Base
|
|
7
|
+
HANDLE_ACTION = "pointerdown->reorderable#onPointerDown pointermove->reorderable#onPointerMove " \
|
|
8
|
+
"pointerup->reorderable#onPointerUp"
|
|
9
|
+
|
|
10
|
+
def render(content = nil, id:, handle: :item, url: nil, target: nil, active: false, **html_options, &block)
|
|
11
|
+
validate_options!(id, url, html_options)
|
|
12
|
+
|
|
13
|
+
slots = build_slots(content, &block)
|
|
14
|
+
|
|
15
|
+
build(id: id, handle: handle) do |attrs|
|
|
16
|
+
template.content_tag(:li, **attrs) do
|
|
17
|
+
template.safe_join(
|
|
18
|
+
[
|
|
19
|
+
render_icon_position(slots, :leading),
|
|
20
|
+
render_body(slots, url: url, target: target, active: active, **html_options),
|
|
21
|
+
render_icon_position(slots, :trailing)
|
|
22
|
+
]
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def build(id:, handle: :item, &block)
|
|
29
|
+
@handle = handle
|
|
30
|
+
html_options = merge_html_options(theme.resolve(:ordered_list_item), { id: id }, item_target_attrs)
|
|
31
|
+
template.capture(html_options, &block)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def validate_options!(id, url, html_options)
|
|
37
|
+
raise ArgumentError, "id: is required so the item appears in reorderable:reordered's itemIds" if id.blank?
|
|
38
|
+
return unless url.blank? && html_options.present?
|
|
39
|
+
|
|
40
|
+
raise ArgumentError, "html_options are only applied to the <a> rendered when url: is set"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def build_slots(content, &block)
|
|
44
|
+
slots = OrderedList::Item::Slots.new(template)
|
|
45
|
+
slots.with_title(content) if content
|
|
46
|
+
yield slots if block_given?
|
|
47
|
+
slots
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def item_target_attrs
|
|
51
|
+
if @handle == :item
|
|
52
|
+
{ data: { "reorderable-target": "item handle", action: HANDLE_ACTION } }
|
|
53
|
+
else
|
|
54
|
+
{ data: { "reorderable-target": "item" } }
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def render_body(slots, url:, target:, active:, **html_options)
|
|
59
|
+
content = render_content_slot(slots)
|
|
60
|
+
return content unless url.present?
|
|
61
|
+
|
|
62
|
+
aria = active ? { aria: { current: "page" } } : {}
|
|
63
|
+
attrs = merge_html_options(html_options, { data: { "reorderable-target": "trigger" } }, aria)
|
|
64
|
+
template.content_tag(:a, content, href: url, target: target, **attrs)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def render_icon_position(slots, position)
|
|
68
|
+
slot_name = position == :leading ? :icon_leading : :icon_trailing
|
|
69
|
+
is_handle = @handle == position
|
|
70
|
+
custom_icon = render_icon_slot(slots, slot_name)
|
|
71
|
+
return unless custom_icon || is_handle
|
|
72
|
+
|
|
73
|
+
html_options = merge_html_options(theme.resolve(:ordered_list_item_handle), handle_target_attrs(is_handle))
|
|
74
|
+
template.content_tag(:span, custom_icon || default_handle_icon, **html_options)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def handle_target_attrs(is_handle)
|
|
78
|
+
return {} unless is_handle
|
|
79
|
+
|
|
80
|
+
{ data: { "reorderable-target": "handle", action: HANDLE_ACTION } }
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def render_icon_slot(slots, name)
|
|
84
|
+
slots.resolve(name) do |value|
|
|
85
|
+
next value unless Components::Icon.icon_name?(value)
|
|
86
|
+
|
|
87
|
+
Components::Icon.new(template).render(
|
|
88
|
+
name: value,
|
|
89
|
+
size: :sm,
|
|
90
|
+
classes: theme.resolve(:ordered_list_item_handle).fetch(:classes, ""),
|
|
91
|
+
aria: { hidden: "true" }
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def default_handle_icon
|
|
97
|
+
Components::Icon.new(template).render(
|
|
98
|
+
name: "grip-vertical",
|
|
99
|
+
size: :sm,
|
|
100
|
+
classes: theme.resolve(:ordered_list_item_handle).fetch(:classes, ""),
|
|
101
|
+
aria: { hidden: "true" }
|
|
102
|
+
)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def render_content_slot(slots)
|
|
106
|
+
title = render_title_slot(slots)
|
|
107
|
+
description = render_description_slot(slots)
|
|
108
|
+
return unless title || description
|
|
109
|
+
|
|
110
|
+
template.content_tag(:span, **merge_html_options(theme.resolve(:ordered_list_item_content))) do
|
|
111
|
+
template.safe_join([title, description])
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def render_title_slot(slots)
|
|
116
|
+
slots.resolve(:title) do |v|
|
|
117
|
+
template.content_tag(:span, v, **merge_html_options(theme.resolve(:ordered_list_item_title)))
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def render_description_slot(slots)
|
|
122
|
+
slots.resolve(:description) do |v|
|
|
123
|
+
template.content_tag(:span, v, **merge_html_options(theme.resolve(:ordered_list_item_description)))
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Components
|
|
5
|
+
class OrderedList < Plumber::Base
|
|
6
|
+
def render(move_key: "Alt", editing: false, orientation: nil, role: "list", **kwargs, &block)
|
|
7
|
+
stimulus = {
|
|
8
|
+
data: {
|
|
9
|
+
controller: "reorderable",
|
|
10
|
+
"reorderable-move-key-value": move_key,
|
|
11
|
+
"reorderable-editing-value": editing,
|
|
12
|
+
"reorderable-orientation-value": orientation
|
|
13
|
+
}.compact
|
|
14
|
+
}
|
|
15
|
+
html_options = merge_html_options(theme.resolve(:ordered_list), kwargs, stimulus)
|
|
16
|
+
template.content_tag(:ol, template.capture(self, &block), **html_options, role: role)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def item(content = nil, **kwargs, &block)
|
|
20
|
+
OrderedList::Item.new(template).render(content, **kwargs, &block)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Components
|
|
5
|
+
class ProgressBar < Plumber::Base
|
|
6
|
+
def render(...) = render_bar(...)
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def render_bar(value:, min: 0, max: 100, indeterminate: false, **kwargs)
|
|
11
|
+
html_options = merge_html_options(
|
|
12
|
+
theme.resolve(:progress_bar),
|
|
13
|
+
kwargs,
|
|
14
|
+
stimulus_data(value: value, min: min, max: max, indeterminate: indeterminate),
|
|
15
|
+
{ role: "progressbar", aria: progress_aria(value: value, min: min, max: max, indeterminate: indeterminate) }
|
|
16
|
+
)
|
|
17
|
+
template.content_tag(:div, render_fill, **html_options)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def render_fill
|
|
21
|
+
template.content_tag(
|
|
22
|
+
:div,
|
|
23
|
+
nil,
|
|
24
|
+
**merge_html_options(theme.resolve(:progress_bar_fill), { data: { "progress-target": "fill" } })
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def progress_aria(value:, min:, max:, indeterminate:)
|
|
29
|
+
aria = { valuemin: min, valuemax: max }
|
|
30
|
+
aria[:valuenow] = value unless indeterminate
|
|
31
|
+
aria
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def stimulus_data(value:, min:, max:, indeterminate:)
|
|
35
|
+
{
|
|
36
|
+
data: {
|
|
37
|
+
controller: "progress",
|
|
38
|
+
"progress-variant-value": "bar",
|
|
39
|
+
"progress-current-value": value,
|
|
40
|
+
"progress-min-value": min,
|
|
41
|
+
"progress-max-value": max,
|
|
42
|
+
"progress-indeterminate-value": indeterminate
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Components
|
|
5
|
+
class ProgressMeter < Plumber::Base
|
|
6
|
+
def render(...) = render_meter(...)
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def render_meter(value:, min: 0, max: 100, low: nil, high: nil, optimum: nil, **kwargs)
|
|
11
|
+
attrs = { value: value, min: min, max: max, low: low, high: high, optimum: optimum }.compact
|
|
12
|
+
html_options = merge_html_options(
|
|
13
|
+
theme.resolve(:progress_meter),
|
|
14
|
+
kwargs,
|
|
15
|
+
stimulus_data(value: value, min: min, max: max, low: low, high: high, optimum: optimum),
|
|
16
|
+
attrs
|
|
17
|
+
)
|
|
18
|
+
template.content_tag(:meter, nil, **html_options)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def stimulus_data(value:, min:, max:, low:, high:, optimum:)
|
|
22
|
+
data = {
|
|
23
|
+
controller: "progress",
|
|
24
|
+
"progress-target": "meter",
|
|
25
|
+
"progress-variant-value": "meter",
|
|
26
|
+
"progress-current-value": value,
|
|
27
|
+
"progress-min-value": min,
|
|
28
|
+
"progress-max-value": max
|
|
29
|
+
}
|
|
30
|
+
data["progress-low-value"] = low if low
|
|
31
|
+
data["progress-high-value"] = high if high
|
|
32
|
+
data["progress-optimum-value"] = optimum if optimum
|
|
33
|
+
{ data: data }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Components
|
|
5
|
+
class ProgressRing < Plumber::Base
|
|
6
|
+
def render(...) = render_ring(...)
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def render_ring(value:, max: 100, min: 0, indeterminate: false, **kwargs)
|
|
11
|
+
icon_options = merge_html_options(
|
|
12
|
+
theme.resolve(:progress_ring),
|
|
13
|
+
kwargs,
|
|
14
|
+
stimulus_data(value: value, min: min, max: max, indeterminate: indeterminate),
|
|
15
|
+
{ role: "progressbar", aria: progress_aria(value: value, min: min, max: max, indeterminate: indeterminate) }
|
|
16
|
+
)
|
|
17
|
+
Components::Icon.new(template).render(name: "progress-ring", **icon_options)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def progress_aria(value:, min:, max:, indeterminate:)
|
|
21
|
+
aria = { valuemin: min, valuemax: max }
|
|
22
|
+
aria[:valuenow] = value unless indeterminate
|
|
23
|
+
aria
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def stimulus_data(value:, min:, max:, indeterminate:)
|
|
27
|
+
{
|
|
28
|
+
data: {
|
|
29
|
+
controller: "progress",
|
|
30
|
+
"progress-variant-value": "ring",
|
|
31
|
+
"progress-current-value": value,
|
|
32
|
+
"progress-min-value": min,
|
|
33
|
+
"progress-max-value": max,
|
|
34
|
+
"progress-indeterminate-value": indeterminate
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -13,7 +13,7 @@ module StimulusPlumbers
|
|
|
13
13
|
def render(datetime: nil, id: nil, interactive: false, orientation: :vertical, **kwargs, &block)
|
|
14
14
|
@detail_id = self.class.detail_id_for(id || template.sp_dom_id)
|
|
15
15
|
|
|
16
|
-
slots = Timeline::Event::Slots.new
|
|
16
|
+
slots = Timeline::Event::Slots.new(template)
|
|
17
17
|
yield slots if block_given?
|
|
18
18
|
|
|
19
19
|
validate_slots!(slots, datetime: datetime)
|
|
@@ -107,11 +107,12 @@ module StimulusPlumbers
|
|
|
107
107
|
if type == :icon && icon_name
|
|
108
108
|
Components::Icon.new(template).render(
|
|
109
109
|
name: icon_name,
|
|
110
|
+
size: :sm,
|
|
110
111
|
classes: theme.resolve(:timeline_item_indicator_icon_slot).fetch(:classes, ""),
|
|
111
112
|
aria: { hidden: "true" }
|
|
112
113
|
)
|
|
113
114
|
else
|
|
114
|
-
template.
|
|
115
|
+
Components::Indicator.new(template).render(type: :dot, variant: :primary)
|
|
115
116
|
end
|
|
116
117
|
end
|
|
117
118
|
|
|
@@ -4,7 +4,8 @@ module StimulusPlumbers
|
|
|
4
4
|
module Components
|
|
5
5
|
class Timeline
|
|
6
6
|
class Group < Plumber::Base
|
|
7
|
-
def render(**kwargs, &block)
|
|
7
|
+
def render(orientation: :vertical, **kwargs, &block)
|
|
8
|
+
@orientation = orientation
|
|
8
9
|
content = template.capture(self, &block)
|
|
9
10
|
html_options = merge_html_options(theme.resolve(:timeline_group), kwargs)
|
|
10
11
|
template.content_tag(:div, content, **html_options)
|
|
@@ -12,7 +13,7 @@ module StimulusPlumbers
|
|
|
12
13
|
|
|
13
14
|
def section(date:, datetime: nil, **kwargs, &block)
|
|
14
15
|
inner_tl = Timeline.new(template)
|
|
15
|
-
inner_tl.instance_variable_set(:@orientation,
|
|
16
|
+
inner_tl.instance_variable_set(:@orientation, @orientation)
|
|
16
17
|
inner_tl.instance_variable_set(:@interactive, false)
|
|
17
18
|
|
|
18
19
|
events_html = template.capture(inner_tl, &block)
|
|
@@ -29,10 +30,11 @@ module StimulusPlumbers
|
|
|
29
30
|
theme.resolve(:timeline_group_section_date),
|
|
30
31
|
datetime ? { datetime: datetime } : {}
|
|
31
32
|
)
|
|
33
|
+
list_attrs = merge_html_options(theme.resolve(:timeline_group_section_list, orientation: @orientation))
|
|
32
34
|
template.safe_join(
|
|
33
35
|
[
|
|
34
36
|
template.content_tag(:time, date, **date_attrs),
|
|
35
|
-
template.content_tag(:ol, events_html, **
|
|
37
|
+
template.content_tag(:ol, events_html, **list_attrs)
|
|
36
38
|
]
|
|
37
39
|
)
|
|
38
40
|
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Generators
|
|
5
|
+
module CssEntrypoint
|
|
6
|
+
STIMULUS_PLUMBERS_CSS_ENTRY = "STIMULUS_PLUMBERS_CSS_ENTRY"
|
|
7
|
+
|
|
8
|
+
# Shared with stimulus_plumbers_tailwind's InstallGenerator — checked in order,
|
|
9
|
+
# each path is another gem/tool's own default entry file. Detection is theme-
|
|
10
|
+
# agnostic: any of these may be the CSS entry regardless of which theme is active.
|
|
11
|
+
ENTRY_CANDIDATES = [
|
|
12
|
+
"app/assets/stylesheets/application.tailwind.css", # tailwindcss-rails 2.x default
|
|
13
|
+
"app/assets/tailwind/application.css", # tailwindcss-rails 3.x+ default
|
|
14
|
+
"app/assets/stylesheets/application.css", # Rails/Propshaft default manifest
|
|
15
|
+
"app/javascript/entrypoints/application.css" # jsbundling-rails (esbuild/webpack) default
|
|
16
|
+
].freeze
|
|
17
|
+
|
|
18
|
+
def entry_css_file(candidates:, env_var:)
|
|
19
|
+
if ENV[env_var]
|
|
20
|
+
path = File.expand_path(ENV.fetch(env_var, nil))
|
|
21
|
+
return path if File.exist?(path)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
candidates
|
|
25
|
+
.map { |c| File.join(destination_root, c) }
|
|
26
|
+
.find { |f| File.exist?(f) }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def warn_entry_css_not_found(candidates:, env_var:, label:)
|
|
30
|
+
tried = candidates.map { |c| File.join(destination_root, c) }
|
|
31
|
+
tried.unshift(File.expand_path(ENV[env_var])) if ENV[env_var]
|
|
32
|
+
say "Could not find a #{label} entry file. Tried: #{tried.join(", ")}. " \
|
|
33
|
+
"Set #{env_var}=/path/to/entry.css and re-run.",
|
|
34
|
+
:red
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def apply_edit(css_file, directive, stale_pattern:, anchor_pattern: nil)
|
|
38
|
+
content = File.read(css_file)
|
|
39
|
+
new_content, status = content_edit(content, directive, stale_pattern: stale_pattern, anchor_pattern: anchor_pattern)
|
|
40
|
+
|
|
41
|
+
if new_content
|
|
42
|
+
File.write(css_file, new_content)
|
|
43
|
+
say_status status, relative_to_destination(css_file), :green
|
|
44
|
+
else
|
|
45
|
+
say_status :identical, relative_to_destination(css_file)
|
|
46
|
+
end
|
|
47
|
+
rescue Errno::EROFS, Errno::EACCES => e
|
|
48
|
+
say "Could not update #{relative_to_destination(css_file)}: #{e.message}. Skipping.", :yellow
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# `stale_pattern:` is required — every call site needs stale-import detection,
|
|
52
|
+
# so making it optional would leave an untested "anchor without stale" state.
|
|
53
|
+
def content_edit(content, directive, stale_pattern:, anchor_pattern: nil)
|
|
54
|
+
return nil if content.include?(directive)
|
|
55
|
+
|
|
56
|
+
if (existing = content.match(stale_pattern))
|
|
57
|
+
return [content.sub(existing[0], directive), :update]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
anchor_pattern ? insert_near_anchor(content, directive, anchor_pattern) : prepend(content, directive)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def prepend(content, directive)
|
|
64
|
+
["#{directive}\n#{content}", :prepend]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def insert_near_anchor(content, directive, anchor_pattern)
|
|
68
|
+
if (anchor = content.match(anchor_pattern))
|
|
69
|
+
[content.sub(anchor[0], "#{anchor[0]}\n#{directive}"), :insert]
|
|
70
|
+
else
|
|
71
|
+
["#{content.rstrip}\n#{directive}\n", :append]
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def relative_to_destination(path)
|
|
76
|
+
path.delete_prefix("#{destination_root}/")
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pathname"
|
|
4
|
+
|
|
5
|
+
module StimulusPlumbers
|
|
6
|
+
module Generators
|
|
7
|
+
module TokensDirective
|
|
8
|
+
GEM_ROOT = File.expand_path("../../..", __dir__)
|
|
9
|
+
TOKENS_CSS_REL_PATH = "app/assets/stylesheets/stimulus_plumbers/tokens.css"
|
|
10
|
+
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def directive(from:)
|
|
14
|
+
path = Pathname.new(GEM_ROOT).join(TOKENS_CSS_REL_PATH)
|
|
15
|
+
rel = path.relative_path_from(Pathname.new(from))
|
|
16
|
+
%(@import "#{rel}";)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def stale_pattern
|
|
20
|
+
%r{@import "[^"]*#{Regexp.escape(TOKENS_CSS_REL_PATH)}";}
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -4,13 +4,7 @@ module StimulusPlumbers
|
|
|
4
4
|
module Helpers
|
|
5
5
|
module AvatarHelper
|
|
6
6
|
def sp_avatar(...)
|
|
7
|
-
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
private
|
|
11
|
-
|
|
12
|
-
def avatar_renderer
|
|
13
|
-
Components::Avatar.new(self)
|
|
7
|
+
Components::Avatar.new(self).render(...)
|
|
14
8
|
end
|
|
15
9
|
end
|
|
16
10
|
end
|
|
@@ -4,18 +4,12 @@ module StimulusPlumbers
|
|
|
4
4
|
module Helpers
|
|
5
5
|
module ButtonHelper
|
|
6
6
|
def sp_button(content = nil, **kwargs, &block)
|
|
7
|
-
|
|
7
|
+
Components::Button.new(self).render(content, **kwargs, &block)
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def sp_button_group(...)
|
|
11
11
|
Components::Button::Group.new(self).render(...)
|
|
12
12
|
end
|
|
13
|
-
|
|
14
|
-
private
|
|
15
|
-
|
|
16
|
-
def button_renderer
|
|
17
|
-
Components::Button.new(self)
|
|
18
|
-
end
|
|
19
13
|
end
|
|
20
14
|
end
|
|
21
15
|
end
|
|
@@ -9,20 +9,13 @@ module StimulusPlumbers
|
|
|
9
9
|
kwargs.deep_merge(
|
|
10
10
|
data: {
|
|
11
11
|
"calendar-month-year-value": date.year,
|
|
12
|
-
"calendar-month-month-value": date.month - 1
|
|
13
|
-
"calendar-month-day-value": date.day
|
|
12
|
+
"calendar-month-month-value": date.month - 1
|
|
14
13
|
}
|
|
15
14
|
)
|
|
16
15
|
else
|
|
17
16
|
kwargs
|
|
18
17
|
end
|
|
19
|
-
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
private
|
|
23
|
-
|
|
24
|
-
def calendar_renderer
|
|
25
|
-
Components::Calendar.new(self)
|
|
18
|
+
Components::Calendar.new(self).month(**html_options)
|
|
26
19
|
end
|
|
27
20
|
end
|
|
28
21
|
end
|
|
@@ -31,8 +31,7 @@ module StimulusPlumbers
|
|
|
31
31
|
[
|
|
32
32
|
content_tag(
|
|
33
33
|
:turbo_frame,
|
|
34
|
-
id:
|
|
35
|
-
data: { "combobox-date-target": "monthView" }
|
|
34
|
+
id: "calendar-month-frame"
|
|
36
35
|
) do
|
|
37
36
|
calendar_turbo_renderer.month(
|
|
38
37
|
date: date,
|
|
@@ -48,8 +47,7 @@ module StimulusPlumbers
|
|
|
48
47
|
content_tag(
|
|
49
48
|
:turbo_frame,
|
|
50
49
|
id: "calendar-year-frame",
|
|
51
|
-
hidden: true
|
|
52
|
-
data: { "combobox-date-target": "yearView" }
|
|
50
|
+
hidden: true
|
|
53
51
|
) do
|
|
54
52
|
calendar_turbo_renderer.year(
|
|
55
53
|
date: date,
|
|
@@ -63,8 +61,7 @@ module StimulusPlumbers
|
|
|
63
61
|
content_tag(
|
|
64
62
|
:turbo_frame,
|
|
65
63
|
id: "calendar-decade-frame",
|
|
66
|
-
hidden: true
|
|
67
|
-
data: { "combobox-date-target": "decadeView" }
|
|
64
|
+
hidden: true
|
|
68
65
|
) do
|
|
69
66
|
calendar_turbo_renderer.decade(
|
|
70
67
|
date: date,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Helpers
|
|
5
|
+
module IndicatorHelper
|
|
6
|
+
def sp_indicator(variant: :primary, type: :dot, pulse: false, **kwargs, &block)
|
|
7
|
+
Components::Indicator.new(self).render(type: type, variant: variant, pulse: pulse, **kwargs, &block)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -4,13 +4,7 @@ module StimulusPlumbers
|
|
|
4
4
|
module Helpers
|
|
5
5
|
module PopoverHelper
|
|
6
6
|
def sp_popover(...)
|
|
7
|
-
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
private
|
|
11
|
-
|
|
12
|
-
def popover_renderer
|
|
13
|
-
Components::Popover.new(self)
|
|
7
|
+
Components::Popover.new(self).render(...)
|
|
14
8
|
end
|
|
15
9
|
end
|
|
16
10
|
end
|