nitro_kit 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/MIT-LICENSE +20 -0
- data/README.md +28 -1
- data/Rakefile +6 -4
- data/app/components/nitro_kit/accordion.rb +69 -33
- data/app/components/nitro_kit/alert.rb +69 -0
- data/app/components/nitro_kit/avatar.rb +52 -0
- data/app/components/nitro_kit/badge.rb +47 -23
- data/app/components/nitro_kit/button.rb +97 -65
- data/app/components/nitro_kit/button_group.rb +18 -13
- data/app/components/nitro_kit/card.rb +49 -9
- data/app/components/nitro_kit/checkbox.rb +59 -41
- data/app/components/nitro_kit/checkbox_group.rb +38 -0
- data/app/components/nitro_kit/combobox.rb +138 -0
- data/app/components/nitro_kit/component.rb +46 -17
- data/app/components/nitro_kit/datepicker.rb +9 -0
- data/app/components/nitro_kit/dialog.rb +95 -0
- data/app/components/nitro_kit/dropdown.rb +116 -73
- data/app/components/nitro_kit/field.rb +281 -30
- data/app/components/nitro_kit/field_group.rb +10 -5
- data/app/components/nitro_kit/fieldset.rb +42 -7
- data/app/components/nitro_kit/form_builder.rb +45 -22
- data/app/components/nitro_kit/icon.rb +29 -8
- data/app/components/nitro_kit/input.rb +26 -0
- data/app/components/nitro_kit/label.rb +18 -5
- data/app/components/nitro_kit/pagination.rb +98 -0
- data/app/components/nitro_kit/radio_button.rb +28 -27
- data/app/components/nitro_kit/radio_button_group.rb +53 -0
- data/app/components/nitro_kit/select.rb +72 -0
- data/app/components/nitro_kit/switch.rb +49 -39
- data/app/components/nitro_kit/table.rb +56 -0
- data/app/components/nitro_kit/tabs.rb +98 -0
- data/app/components/nitro_kit/textarea.rb +26 -0
- data/app/components/nitro_kit/toast.rb +104 -0
- data/app/components/nitro_kit/tooltip.rb +53 -0
- data/app/helpers/nitro_kit/accordion_helper.rb +3 -1
- data/app/helpers/nitro_kit/alert_helper.rb +11 -0
- data/app/helpers/nitro_kit/avatar_helper.rb +9 -0
- data/app/helpers/nitro_kit/badge_helper.rb +3 -5
- data/app/helpers/nitro_kit/button_group_helper.rb +2 -0
- data/app/helpers/nitro_kit/button_helper.rb +37 -28
- data/app/helpers/nitro_kit/card_helper.rb +2 -0
- data/app/helpers/nitro_kit/checkbox_helper.rb +19 -16
- data/app/helpers/nitro_kit/combobox_helper.rb +9 -0
- data/app/helpers/nitro_kit/datepicker_helper.rb +9 -0
- data/app/helpers/nitro_kit/dialog_helper.rb +9 -0
- data/app/helpers/nitro_kit/dropdown_helper.rb +3 -1
- data/app/helpers/nitro_kit/field_group_helper.rb +9 -0
- data/app/helpers/nitro_kit/field_helper.rb +4 -2
- data/app/helpers/nitro_kit/fieldset_helper.rb +9 -0
- data/app/helpers/nitro_kit/form_helper.rb +13 -0
- data/app/helpers/nitro_kit/icon_helper.rb +3 -1
- data/app/helpers/nitro_kit/input_helper.rb +35 -0
- data/app/helpers/nitro_kit/label_helper.rb +12 -8
- data/app/helpers/nitro_kit/pagination_helper.rb +42 -0
- data/app/helpers/nitro_kit/radio_button_helper.rb +15 -12
- data/app/helpers/nitro_kit/select_helper.rb +24 -0
- data/app/helpers/nitro_kit/switch_helper.rb +4 -10
- data/app/helpers/nitro_kit/table_helper.rb +9 -0
- data/app/helpers/nitro_kit/tabs_helper.rb +9 -0
- data/app/helpers/nitro_kit/textarea_helper.rb +9 -0
- data/app/helpers/nitro_kit/toast_helper.rb +36 -0
- data/app/helpers/nitro_kit/tooltip_helper.rb +9 -0
- data/lib/generators/nitro_kit/add_generator.rb +38 -41
- data/lib/generators/nitro_kit/install_generator.rb +2 -1
- data/lib/nitro_kit/engine.rb +4 -0
- data/lib/nitro_kit/schema_builder.rb +90 -16
- data/lib/nitro_kit/version.rb +1 -1
- data/lib/nitro_kit.rb +39 -1
- data/lib/tasks/nitro_kit_tasks.rake +4 -0
- metadata +40 -12
- data/app/components/nitro_kit/radio_group.rb +0 -35
- data/app/helpers/application_helper.rb +0 -89
- data/lib/nitro_kit/railtie.rb +0 -8
@@ -1,110 +1,153 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module NitroKit
|
2
4
|
class Dropdown < Component
|
3
|
-
|
4
|
-
|
5
|
-
CONTENT = [
|
6
|
-
"w-max-content absolute top-0 left-0",
|
7
|
-
"p-1 bg-background rounded-md border shadow-sm",
|
8
|
-
"w-fit max-w-sm flex-col text-left",
|
9
|
-
"[&[aria-hidden=true]]:hidden flex"
|
10
|
-
].freeze
|
5
|
+
ITEM_VARIANTS = %i[default destructive]
|
11
6
|
|
12
|
-
|
13
|
-
"px-3 py-1.5 rounded",
|
14
|
-
"font-medium truncate",
|
15
|
-
"cursor-default"
|
16
|
-
].freeze
|
17
|
-
|
18
|
-
ITEM_VARIANTS = {
|
19
|
-
default: ["hover:bg-muted"],
|
20
|
-
destructive: ["text-destructive-foreground hover:bg-destructive hover:text-white"]
|
21
|
-
}.freeze
|
22
|
-
|
23
|
-
SEPARATOR = "border-t my-1 -mx-1"
|
7
|
+
include Phlex::Rails::Helpers::LinkTo
|
24
8
|
|
25
9
|
def initialize(placement: nil, **attrs)
|
26
10
|
@placement = placement
|
27
|
-
|
11
|
+
|
12
|
+
super(
|
13
|
+
attrs,
|
14
|
+
data: {
|
15
|
+
controller: "nk--dropdown",
|
16
|
+
nk__dropdown_placement_value: placement
|
17
|
+
}
|
18
|
+
)
|
28
19
|
end
|
29
20
|
|
30
21
|
attr_reader :placement
|
31
22
|
|
32
|
-
def view_template
|
33
|
-
div(
|
23
|
+
def view_template
|
24
|
+
div(**mattr(attrs)) do
|
25
|
+
yield
|
26
|
+
end
|
34
27
|
end
|
35
28
|
|
36
|
-
def trigger(**attrs, &block)
|
37
|
-
|
38
|
-
|
39
|
-
:"nk--dropdown-target" => "trigger",
|
40
|
-
:action => "click->nk--dropdown#toggle",
|
41
|
-
**attrs.fetch(:data, {})
|
42
|
-
}
|
43
|
-
div(
|
44
|
-
**attrs,
|
45
|
-
class: class_list,
|
46
|
-
data:,
|
29
|
+
def trigger(text = nil, as: NitroKit::Button, **attrs, &block)
|
30
|
+
trigger_attrs = mattr(
|
31
|
+
attrs,
|
47
32
|
aria: {haspopup: "true", expanded: "false"},
|
48
|
-
|
33
|
+
data: {nk__dropdown_target: "trigger", action: "click->nk--dropdown#toggle"}
|
49
34
|
)
|
50
|
-
end
|
51
35
|
|
52
|
-
|
53
|
-
|
36
|
+
case as
|
37
|
+
when Symbol
|
38
|
+
send(as, **trigger_attrs) do
|
39
|
+
text_or_block(text, &block)
|
40
|
+
end
|
41
|
+
else
|
42
|
+
render(as.new(**trigger_attrs)) do
|
43
|
+
text_or_block(text, &block)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
54
47
|
|
55
|
-
|
56
|
-
:"nk--dropdown-target" => "content",
|
57
|
-
**attrs.fetch(:data, {})
|
58
|
-
}
|
48
|
+
def content(as: :div, **attrs)
|
59
49
|
div(
|
60
|
-
**
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
50
|
+
**mattr(
|
51
|
+
attrs,
|
52
|
+
role: "menu",
|
53
|
+
aria: {hidden: "true"},
|
54
|
+
class: content_class,
|
55
|
+
data: {nk__dropdown_target: "content"},
|
56
|
+
popover: true
|
57
|
+
)
|
58
|
+
) do
|
59
|
+
yield
|
60
|
+
end
|
67
61
|
end
|
68
62
|
|
69
63
|
def title(text = nil, **attrs, &block)
|
70
|
-
|
71
|
-
|
64
|
+
div(**mattr(attrs, class: title_class)) do
|
65
|
+
text_or_block(text, &block)
|
66
|
+
end
|
72
67
|
end
|
73
68
|
|
74
|
-
def item(
|
75
|
-
|
76
|
-
|
77
|
-
variant: :default,
|
78
|
-
**attrs,
|
79
|
-
&block
|
80
|
-
)
|
81
|
-
class_list = merge([ITEM, ITEM_VARIANTS[variant], attrs[:class]])
|
82
|
-
|
83
|
-
common_attrs = {
|
84
|
-
**attrs,
|
85
|
-
class: class_list,
|
69
|
+
def item(text = nil, href: nil, variant: :default, **attrs, &block)
|
70
|
+
common_attrs = mattr(
|
71
|
+
attrs,
|
86
72
|
role: "menuitem",
|
87
|
-
tabindex: "-1"
|
88
|
-
|
73
|
+
tabindex: "-1",
|
74
|
+
class: [item_class, item_variant_class(variant)]
|
75
|
+
)
|
89
76
|
|
90
77
|
if href
|
91
|
-
link_to(
|
92
|
-
|
93
|
-
|
94
|
-
) {
|
95
|
-
text || block.call
|
96
|
-
}
|
78
|
+
link_to(href, **common_attrs) do
|
79
|
+
text_or_block(text, &block)
|
80
|
+
end
|
97
81
|
else
|
98
|
-
div(**common_attrs)
|
82
|
+
div(**common_attrs) do
|
83
|
+
text_or_block(text, &block)
|
84
|
+
end
|
99
85
|
end
|
100
86
|
end
|
101
87
|
|
88
|
+
def item_to(
|
89
|
+
text_or_href,
|
90
|
+
href = nil,
|
91
|
+
**attrs,
|
92
|
+
&block
|
93
|
+
)
|
94
|
+
href = text_or_href if block_given?
|
95
|
+
item(text_or_href, href: href, **attrs, &block)
|
96
|
+
end
|
97
|
+
|
102
98
|
def destructive_item(*args, **attrs, &block)
|
103
99
|
item(*args, **attrs, variant: :destructive, &block)
|
104
100
|
end
|
105
101
|
|
102
|
+
def destructive_item_to(text_or_block, href = nil, **attrs, &block)
|
103
|
+
href = args.shift if block_given?
|
104
|
+
destructive_item(text_or_block, href: href, **attrs, &block)
|
105
|
+
end
|
106
|
+
|
106
107
|
def separator
|
107
|
-
|
108
|
+
hr(class: separator_class)
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def content_class
|
114
|
+
[
|
115
|
+
"z-10 w-max-content absolute top-0 left-0",
|
116
|
+
"p-1 bg-background text-foreground rounded-md border shadow-sm",
|
117
|
+
"w-fit max-w-sm flex-col text-left",
|
118
|
+
"[&[aria-hidden=true]]:hidden flex"
|
119
|
+
]
|
120
|
+
end
|
121
|
+
|
122
|
+
def trigger_class
|
123
|
+
""
|
124
|
+
end
|
125
|
+
|
126
|
+
def title_class
|
127
|
+
"px-3 pt-2 pb-1.5 text-muted-foreground text-sm"
|
128
|
+
end
|
129
|
+
|
130
|
+
def item_class
|
131
|
+
[
|
132
|
+
"px-3 py-1.5 rounded",
|
133
|
+
"font-medium truncate",
|
134
|
+
"cursor-default"
|
135
|
+
]
|
136
|
+
end
|
137
|
+
|
138
|
+
def item_variant_class(variant)
|
139
|
+
case variant
|
140
|
+
when :default
|
141
|
+
"[&[href]]:hover:bg-muted"
|
142
|
+
when :destructive
|
143
|
+
"text-destructive-foreground [&[href]]:hover:bg-destructive [&[href]]:hover:text-white"
|
144
|
+
else
|
145
|
+
raise ArgumentError, "Unknown variant: #{variant.inspect}"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def separator_class
|
150
|
+
"border-t my-1 -mx-1"
|
108
151
|
end
|
109
152
|
end
|
110
153
|
end
|
@@ -1,37 +1,288 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module NitroKit
|
2
4
|
class Field < Component
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
@
|
18
|
-
|
19
|
-
|
20
|
-
@
|
21
|
-
|
22
|
-
@
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
5
|
+
def initialize(
|
6
|
+
form = nil,
|
7
|
+
field_name = nil,
|
8
|
+
as: :string,
|
9
|
+
label: nil,
|
10
|
+
description: nil,
|
11
|
+
errors: nil,
|
12
|
+
**attrs
|
13
|
+
)
|
14
|
+
@form = form
|
15
|
+
@field_name = field_name.to_s
|
16
|
+
@as = as.to_sym
|
17
|
+
|
18
|
+
@name = attrs[:name] || form&.field_name(field_name)
|
19
|
+
@id = attrs[:id] || form&.field_id(field_name)
|
20
|
+
|
21
|
+
# select
|
22
|
+
@options = attrs[:options]
|
23
|
+
|
24
|
+
@field_attrs = attrs
|
25
|
+
@field_label = label || field_name.to_s.humanize
|
26
|
+
@field_description = description
|
27
|
+
@field_error_messages = errors
|
28
|
+
|
29
|
+
super(
|
30
|
+
attrs,
|
31
|
+
data: {as: @as},
|
32
|
+
class: base_class
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader(
|
37
|
+
:as,
|
38
|
+
:form,
|
39
|
+
:name,
|
40
|
+
:id,
|
41
|
+
:field_attrs,
|
42
|
+
:field_label,
|
43
|
+
:field_description,
|
44
|
+
:field_error_messages
|
45
|
+
)
|
46
|
+
|
47
|
+
def view_template
|
48
|
+
div(**attrs) do
|
49
|
+
if block_given?
|
50
|
+
yield
|
51
|
+
else
|
52
|
+
default_field
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
alias :html_label :label
|
58
|
+
|
59
|
+
def label(text = nil, **attrs)
|
60
|
+
text ||= field_label
|
61
|
+
|
62
|
+
return unless text
|
63
|
+
|
64
|
+
render(Label.new(**mattr(attrs, for: id, data: {slot: "label"}))) do
|
65
|
+
text
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def description(text = nil, **attrs, &block)
|
70
|
+
text ||= field_description
|
71
|
+
|
72
|
+
return unless text || block_given?
|
73
|
+
|
74
|
+
div(**mattr(attrs, data: {slot: "description"}, class: description_class)) do
|
75
|
+
text_or_block(text, &block)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def errors(error_messages = nil, **attrs)
|
80
|
+
error_messages ||= field_error_messages
|
81
|
+
|
82
|
+
return unless error_messages&.any?
|
83
|
+
|
84
|
+
ul(**mattr(attrs, data: {slot: "error"}, class: error_class)) do |msg|
|
85
|
+
error_messages.each do |msg|
|
86
|
+
li { msg }
|
33
87
|
end
|
34
88
|
end
|
35
89
|
end
|
90
|
+
|
91
|
+
def control(**attrs)
|
92
|
+
case as
|
93
|
+
when :string
|
94
|
+
input(**attrs)
|
95
|
+
when
|
96
|
+
:button,
|
97
|
+
:color,
|
98
|
+
:date,
|
99
|
+
:datetime,
|
100
|
+
:datetime_local,
|
101
|
+
:email,
|
102
|
+
:file,
|
103
|
+
:hidden,
|
104
|
+
:month,
|
105
|
+
:number,
|
106
|
+
:password,
|
107
|
+
:range,
|
108
|
+
:search,
|
109
|
+
:tel,
|
110
|
+
:text,
|
111
|
+
:time,
|
112
|
+
:url,
|
113
|
+
:week
|
114
|
+
input(type: as, **attrs)
|
115
|
+
when :select
|
116
|
+
select(**attrs)
|
117
|
+
when :textarea
|
118
|
+
textarea(**attrs)
|
119
|
+
when :checkbox
|
120
|
+
checkbox(**attrs)
|
121
|
+
when :combobox
|
122
|
+
combobox(**attrs)
|
123
|
+
when :radio, :radio_button, :radio_group
|
124
|
+
radio_group(**attrs)
|
125
|
+
when :switch
|
126
|
+
switch(**attrs)
|
127
|
+
else
|
128
|
+
raise ArgumentError, "Invalid field type `#{as}'"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def default_field
|
135
|
+
case as
|
136
|
+
when :checkbox
|
137
|
+
control
|
138
|
+
label
|
139
|
+
description
|
140
|
+
errors
|
141
|
+
else
|
142
|
+
label
|
143
|
+
description
|
144
|
+
control
|
145
|
+
errors
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def control_attrs(**attrs)
|
150
|
+
mattr(
|
151
|
+
attrs,
|
152
|
+
name:,
|
153
|
+
id:,
|
154
|
+
value: value_before_typecast,
|
155
|
+
data: {slot: "control"}
|
156
|
+
)
|
157
|
+
end
|
158
|
+
|
159
|
+
alias :html_input :input
|
160
|
+
|
161
|
+
def input(**attrs)
|
162
|
+
render(
|
163
|
+
Input.new(
|
164
|
+
**control_attrs(
|
165
|
+
**field_attrs,
|
166
|
+
**attrs
|
167
|
+
)
|
168
|
+
)
|
169
|
+
)
|
170
|
+
end
|
171
|
+
|
172
|
+
alias :html_select :select
|
173
|
+
|
174
|
+
def select(options: nil, **attrs)
|
175
|
+
render(
|
176
|
+
Select.new(
|
177
|
+
options || @options || [],
|
178
|
+
**control_attrs(
|
179
|
+
**field_attrs,
|
180
|
+
**attrs
|
181
|
+
)
|
182
|
+
)
|
183
|
+
)
|
184
|
+
end
|
185
|
+
|
186
|
+
alias :html_textarea :textarea
|
187
|
+
|
188
|
+
def textarea(**attrs)
|
189
|
+
render(
|
190
|
+
Textarea.new(
|
191
|
+
**control_attrs(
|
192
|
+
**field_attrs,
|
193
|
+
**attrs
|
194
|
+
)
|
195
|
+
)
|
196
|
+
)
|
197
|
+
end
|
198
|
+
|
199
|
+
def checkbox(**attrs)
|
200
|
+
render(
|
201
|
+
Checkbox.new(
|
202
|
+
**control_attrs(
|
203
|
+
**field_attrs,
|
204
|
+
**attrs
|
205
|
+
)
|
206
|
+
)
|
207
|
+
)
|
208
|
+
end
|
209
|
+
|
210
|
+
def combobox(**attrs)
|
211
|
+
render(
|
212
|
+
Combobox.new(
|
213
|
+
**control_attrs(
|
214
|
+
**field_attrs,
|
215
|
+
**attrs
|
216
|
+
)
|
217
|
+
)
|
218
|
+
)
|
219
|
+
end
|
220
|
+
|
221
|
+
def radio_group(options: nil, **attrs)
|
222
|
+
render(
|
223
|
+
RadioButtonGroup.new(
|
224
|
+
options || @options || [],
|
225
|
+
**control_attrs(
|
226
|
+
**field_attrs,
|
227
|
+
**attrs
|
228
|
+
)
|
229
|
+
)
|
230
|
+
)
|
231
|
+
end
|
232
|
+
|
233
|
+
def switch(**attrs)
|
234
|
+
# TODO: support use in forms
|
235
|
+
render(
|
236
|
+
Switch.new(
|
237
|
+
**control_attrs(
|
238
|
+
**field_attrs,
|
239
|
+
**attrs
|
240
|
+
)
|
241
|
+
)
|
242
|
+
)
|
243
|
+
end
|
244
|
+
|
245
|
+
private
|
246
|
+
|
247
|
+
def base_class
|
248
|
+
[
|
249
|
+
"grid align-start",
|
250
|
+
# Margins
|
251
|
+
"[&>[data-slot=label]+[data-slot=control]]:mt-2 [&>[data-slot=label]+[data-slot=description]]:mt-1 [&>[data-slot=description]+[data-slot=control]]:mt-3 [&>[data-slot=control]+[data-slot=description]]:mt-3 [&>[data-slot=control]+[data-slot=error]]:mt-2",
|
252
|
+
# When checkbox
|
253
|
+
"[&[data-as=checkbox]]:grid-cols-[auto_1fr] data-[as=checkbox]:gap-x-2 [&[data-as=checkbox]_[data-slot=description]]:col-start-2",
|
254
|
+
"[&:has([data-slot=error])_[data-slot=control]]:border-destructive"
|
255
|
+
]
|
256
|
+
end
|
257
|
+
|
258
|
+
def description_class
|
259
|
+
"text-sm text-muted-foreground"
|
260
|
+
end
|
261
|
+
|
262
|
+
def error_class
|
263
|
+
"text-sm text-destructive"
|
264
|
+
end
|
265
|
+
|
266
|
+
def value
|
267
|
+
return attrs[:value] if attrs[:value]
|
268
|
+
return unless object = form&.object
|
269
|
+
|
270
|
+
if object.respond_to?(@field_name)
|
271
|
+
object.public_send(@field_name)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def value_before_typecast
|
276
|
+
return attrs[:value] if attrs[:value]
|
277
|
+
return unless object = form&.object
|
278
|
+
|
279
|
+
method_before_type_cast = @field_name + "_before_type_cast"
|
280
|
+
|
281
|
+
if object.respond_to?(method_before_type_cast)
|
282
|
+
object.public_send(method_before_type_cast)
|
283
|
+
else
|
284
|
+
value
|
285
|
+
end
|
286
|
+
end
|
36
287
|
end
|
37
288
|
end
|
@@ -1,14 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module NitroKit
|
2
4
|
class FieldGroup < Component
|
3
|
-
FIELD_GROUP_BASE = "space-y-6"
|
4
|
-
|
5
5
|
def initialize(**attrs)
|
6
|
-
|
7
|
-
@class_list = merge([FIELD_GROUP_BASE, attrs[:class]])
|
6
|
+
super(attrs, class: base_class, data: {slot: "control"})
|
8
7
|
end
|
9
8
|
|
10
9
|
def view_template(&block)
|
11
|
-
div(**attrs,
|
10
|
+
div(**attrs, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def base_class
|
16
|
+
"space-y-6"
|
12
17
|
end
|
13
18
|
end
|
14
19
|
end
|
@@ -1,16 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module NitroKit
|
2
4
|
class Fieldset < Component
|
3
|
-
|
4
|
-
|
5
|
-
def initialize(legend, **attrs)
|
5
|
+
def initialize(legend: nil, description: nil, **attrs)
|
6
6
|
@legend = legend
|
7
|
-
@
|
7
|
+
@description = description
|
8
|
+
super(
|
9
|
+
attrs,
|
10
|
+
class: base_class
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def view_template
|
15
|
+
fieldset(**attrs) do
|
16
|
+
legend(@legend) if @legend
|
17
|
+
description(@description) if @description
|
18
|
+
|
19
|
+
yield
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
alias :html_legend :legend
|
24
|
+
|
25
|
+
def legend(text = nil, **attrs, &block)
|
26
|
+
html_legend(**mattr(attrs, class: legend_class)) do
|
27
|
+
text_or_block(text, &block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def description(text = nil, **attrs, &block)
|
32
|
+
div(**mattr(attrs, class: description_class, data: {slot: "text"})) do
|
33
|
+
text_or_block(text, &block)
|
34
|
+
end
|
8
35
|
end
|
9
36
|
|
10
|
-
|
37
|
+
private
|
38
|
+
|
39
|
+
def base_class
|
40
|
+
"[&>*+[data-slot=control]]:mt-6 [&>*+[data-slot=text]]:mt-1"
|
41
|
+
end
|
42
|
+
|
43
|
+
def legend_class
|
44
|
+
"text-lg font-semibold"
|
45
|
+
end
|
11
46
|
|
12
|
-
def
|
13
|
-
|
47
|
+
def description_class
|
48
|
+
"text-sm text-muted-foreground"
|
14
49
|
end
|
15
50
|
end
|
16
51
|
end
|