okonomi_ui_kit 0.1.7 → 0.1.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/README.md +165 -7
- data/app/assets/builds/okonomi_ui_kit/application.tailwind.css +664 -187
- data/app/helpers/okonomi_ui_kit/application_helper.rb +8 -0
- data/app/helpers/okonomi_ui_kit/attribute_section_helper.rb +5 -5
- data/app/helpers/okonomi_ui_kit/component.rb +44 -21
- data/app/helpers/okonomi_ui_kit/components/alert.rb +1 -1
- data/app/helpers/okonomi_ui_kit/components/badge.rb +5 -5
- data/app/helpers/okonomi_ui_kit/components/breadcrumbs.rb +69 -0
- data/app/helpers/okonomi_ui_kit/components/button_base.rb +56 -0
- data/app/helpers/okonomi_ui_kit/components/button_tag.rb +23 -0
- data/app/helpers/okonomi_ui_kit/components/button_to.rb +4 -15
- data/app/helpers/okonomi_ui_kit/components/code.rb +41 -37
- data/app/helpers/okonomi_ui_kit/components/confirmation_modal.rb +130 -0
- data/app/helpers/okonomi_ui_kit/components/forms/check_box_with_label.rb +38 -0
- data/app/helpers/okonomi_ui_kit/components/forms/collection_select.rb +57 -0
- data/app/helpers/okonomi_ui_kit/components/forms/date_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/datetime_local_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/email_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/field.rb +24 -0
- data/app/helpers/okonomi_ui_kit/components/forms/field_set.rb +17 -0
- data/app/helpers/okonomi_ui_kit/components/forms/input_base.rb +57 -0
- data/app/helpers/okonomi_ui_kit/components/forms/label.rb +27 -0
- data/app/helpers/okonomi_ui_kit/components/forms/multi_select.rb +18 -0
- data/app/helpers/okonomi_ui_kit/components/forms/number_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/password_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/search_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/select.rb +57 -0
- data/app/helpers/okonomi_ui_kit/components/forms/show_if.rb +28 -0
- data/app/helpers/okonomi_ui_kit/components/forms/telephone_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/text_area.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/text_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/time_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/upload_field.rb +25 -0
- data/app/helpers/okonomi_ui_kit/components/forms/url_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms.rb +6 -0
- data/app/helpers/okonomi_ui_kit/components/icon.rb +36 -0
- data/app/helpers/okonomi_ui_kit/components/link_to.rb +8 -19
- data/app/helpers/okonomi_ui_kit/components/navigation.rb +98 -0
- data/app/helpers/okonomi_ui_kit/components/page.rb +8 -8
- data/app/helpers/okonomi_ui_kit/components/table.rb +9 -10
- data/app/helpers/okonomi_ui_kit/components/typography.rb +16 -16
- data/app/helpers/okonomi_ui_kit/components.rb +4 -0
- data/app/helpers/okonomi_ui_kit/config.rb +5 -1
- data/app/helpers/okonomi_ui_kit/configs.rb +4 -0
- data/app/helpers/okonomi_ui_kit/form_builder.rb +39 -130
- data/app/helpers/okonomi_ui_kit/form_component.rb +7 -0
- data/app/helpers/okonomi_ui_kit/svg_icons.rb +5 -5
- data/app/helpers/okonomi_ui_kit/t_w_merge.rb +114 -0
- data/app/helpers/okonomi_ui_kit/ui_helper.rb +17 -58
- data/app/views/okonomi/components/breadcrumbs/_breadcrumbs.html.erb +46 -0
- data/app/views/okonomi/components/confirmation_modal/_confirmation_modal.html.erb +76 -0
- data/app/views/okonomi/components/forms/check_box_with_label/_check_box_with_label.html.erb +6 -0
- data/app/views/okonomi/components/forms/field/_field.html.erb +3 -0
- data/app/views/okonomi/components/forms/field_set/_field_set.html.erb +3 -0
- data/app/views/okonomi/components/forms/upload_field/_upload_field.html.erb +1 -0
- data/app/views/okonomi/components/icon/_icon.html.erb +38 -0
- data/app/views/okonomi/components/navigation/_link.html.erb +18 -0
- data/app/views/okonomi/components/navigation/_navigation.html.erb +4 -0
- data/app/views/okonomi/forms/tailwind/_checkbox_label.html.erb +2 -2
- data/app/views/okonomi/forms/tailwind/_field.html.erb +6 -6
- data/app/views/okonomi/forms/tailwind/_multi_select.html.erb +2 -4
- data/app/views/okonomi/forms/tailwind/_upload_field.html.erb +10 -10
- data/config/importmap.rb +1 -1
- data/lib/okonomi_ui_kit/engine.rb +0 -3
- data/lib/okonomi_ui_kit/version.rb +1 -1
- metadata +43 -12
- data/app/helpers/okonomi_ui_kit/breadcrumbs_helper.rb +0 -60
- data/app/helpers/okonomi_ui_kit/icon_helper.rb +0 -39
- data/app/helpers/okonomi_ui_kit/navigation_helper.rb +0 -72
- data/app/helpers/okonomi_ui_kit/theme.rb +0 -159
- data/app/helpers/okonomi_ui_kit/theme_helper.rb +0 -17
- data/app/views/okonomi/forms/tailwind/_field_set.html.erb +0 -3
- data/app/views/okonomi/modals/_confirmation_modal.html.erb +0 -77
- data/app/views/okonomi/navigation/_link.html.erb +0 -15
- data/app/views/okonomi/navigation/_menu.html.erb +0 -3
- data/app/views/okonomi/navigation/_navbar.html.erb +0 -105
@@ -35,7 +35,7 @@ module OkonomiUiKit
|
|
35
35
|
def render_content
|
36
36
|
@template.safe_join(@content_parts)
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
def to_s
|
40
40
|
render_content
|
41
41
|
end
|
@@ -62,7 +62,7 @@ module OkonomiUiKit
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def breadcrumbs(&block)
|
65
|
-
@breadcrumbs_content = @template.breadcrumbs(&block)
|
65
|
+
@breadcrumbs_content = @template.ui.breadcrumbs(&block)
|
66
66
|
end
|
67
67
|
|
68
68
|
def row(&block)
|
@@ -163,7 +163,7 @@ module OkonomiUiKit
|
|
163
163
|
if block_given?
|
164
164
|
# Capture the content first to see if attributes were used
|
165
165
|
content = capture { yield(self) }
|
166
|
-
|
166
|
+
|
167
167
|
@body_content = if @attributes.any?
|
168
168
|
# If attributes were added, wrap them in dl
|
169
169
|
tag.div do
|
@@ -192,10 +192,10 @@ module OkonomiUiKit
|
|
192
192
|
attribute_html = tag.div(class: "py-6 sm:grid sm:grid-cols-3 sm:gap-4") do
|
193
193
|
dt_content = tag.dt(label, class: "text-sm font-medium text-gray-900")
|
194
194
|
dd_content = tag.dd(content, class: "mt-1 text-sm/6 text-gray-700 sm:col-span-2 sm:mt-0")
|
195
|
-
|
195
|
+
|
196
196
|
dt_content + dd_content
|
197
197
|
end
|
198
|
-
|
198
|
+
|
199
199
|
@attributes << attribute_html
|
200
200
|
end
|
201
201
|
|
@@ -213,7 +213,7 @@ module OkonomiUiKit
|
|
213
213
|
|
214
214
|
def build_header
|
215
215
|
return nil unless @title_content || @subtitle_content || @actions_content
|
216
|
-
|
216
|
+
|
217
217
|
tag.div(class: "py-6") do
|
218
218
|
if @actions_content
|
219
219
|
tag.div(class: "flex w-full justify-between items-start") do
|
@@ -223,7 +223,7 @@ module OkonomiUiKit
|
|
223
223
|
content_parts << @subtitle_content if @subtitle_content
|
224
224
|
@template.safe_join(content_parts.compact)
|
225
225
|
end
|
226
|
-
|
226
|
+
|
227
227
|
title_section + @actions_content
|
228
228
|
end
|
229
229
|
else
|
@@ -244,4 +244,4 @@ module OkonomiUiKit
|
|
244
244
|
end
|
245
245
|
end
|
246
246
|
end
|
247
|
-
end
|
247
|
+
end
|
@@ -4,8 +4,8 @@ module OkonomiUiKit
|
|
4
4
|
def render(options = {}, &block)
|
5
5
|
options = options.with_indifferent_access
|
6
6
|
variant = (options.delete(:variant) || :default).to_sym
|
7
|
-
|
8
|
-
builder = TableBuilder.new(view,
|
7
|
+
|
8
|
+
builder = TableBuilder.new(view, self, variant)
|
9
9
|
view.render(template_path, builder: builder, options: options, &block)
|
10
10
|
end
|
11
11
|
|
@@ -48,9 +48,8 @@ module OkonomiUiKit
|
|
48
48
|
include ActionView::Helpers::TagHelper
|
49
49
|
include ActionView::Helpers::CaptureHelper
|
50
50
|
|
51
|
-
def initialize(template,
|
51
|
+
def initialize(template, style_provider, variant = :default)
|
52
52
|
@template = template
|
53
|
-
@theme = theme
|
54
53
|
@style_provider = style_provider
|
55
54
|
@variant = variant
|
56
55
|
@current_row_cells = []
|
@@ -127,8 +126,8 @@ module OkonomiUiKit
|
|
127
126
|
capture(&block)
|
128
127
|
else
|
129
128
|
tag.div(class: style(:empty_state, :wrapper)) do
|
130
|
-
icon_content = if @template.respond_to?(:
|
131
|
-
@template.
|
129
|
+
icon_content = if @template.respond_to?(:ui)
|
130
|
+
@template.ui.icon(icon, class: style(:empty_state, :icon))
|
132
131
|
else
|
133
132
|
tag.div(class: style(:empty_state, :icon))
|
134
133
|
end
|
@@ -157,7 +156,7 @@ module OkonomiUiKit
|
|
157
156
|
|
158
157
|
def render_th(cell, is_first, is_last)
|
159
158
|
align_class = style(:alignment, cell[:align]) || style(:alignment, :left)
|
160
|
-
|
159
|
+
|
161
160
|
position_class = if is_first
|
162
161
|
style(:th, :first)
|
163
162
|
elsif is_last
|
@@ -171,7 +170,7 @@ module OkonomiUiKit
|
|
171
170
|
position_class,
|
172
171
|
align_class,
|
173
172
|
cell[:options][:class]
|
174
|
-
].compact.join(
|
173
|
+
].compact.join(" ")
|
175
174
|
|
176
175
|
options = cell[:options].except(:class)
|
177
176
|
tag.th(cell[:content], scope: cell[:scope], class: classes, **options)
|
@@ -179,7 +178,7 @@ module OkonomiUiKit
|
|
179
178
|
|
180
179
|
def render_td(cell, is_first, is_last)
|
181
180
|
align_class = style(:alignment, cell[:align]) || style(:alignment, :left)
|
182
|
-
|
181
|
+
|
183
182
|
position_class = if is_first
|
184
183
|
style(:td, :first)
|
185
184
|
elsif is_last
|
@@ -193,7 +192,7 @@ module OkonomiUiKit
|
|
193
192
|
position_class,
|
194
193
|
align_class,
|
195
194
|
cell[:options][:class]
|
196
|
-
].compact.join(
|
195
|
+
].compact.join(" ")
|
197
196
|
|
198
197
|
options = cell[:options].except(:class)
|
199
198
|
tag.td(cell[:content], class: classes, **options)
|
@@ -2,14 +2,14 @@ module OkonomiUiKit
|
|
2
2
|
module Components
|
3
3
|
class Typography < OkonomiUiKit::Component
|
4
4
|
TYPOGRAPHY_COMPONENTS = {
|
5
|
-
body1:
|
6
|
-
body2:
|
7
|
-
h1:
|
8
|
-
h2:
|
9
|
-
h3:
|
10
|
-
h4:
|
11
|
-
h5:
|
12
|
-
h6:
|
5
|
+
body1: "p",
|
6
|
+
body2: "p",
|
7
|
+
h1: "h1",
|
8
|
+
h2: "h2",
|
9
|
+
h3: "h3",
|
10
|
+
h4: "h4",
|
11
|
+
h5: "h5",
|
12
|
+
h6: "h6"
|
13
13
|
}.freeze
|
14
14
|
|
15
15
|
def render(text = nil, options = {}, &block)
|
@@ -17,15 +17,15 @@ module OkonomiUiKit
|
|
17
17
|
options ||= {}
|
18
18
|
options = options.with_indifferent_access
|
19
19
|
|
20
|
-
variant = (options.delete(:variant) ||
|
21
|
-
component = (TYPOGRAPHY_COMPONENTS[variant] ||
|
22
|
-
color = (options.delete(:color) ||
|
20
|
+
variant = (options.delete(:variant) || "body1").to_sym
|
21
|
+
component = (TYPOGRAPHY_COMPONENTS[variant] || "span").to_s
|
22
|
+
color = (options.delete(:color) || "default").to_sym
|
23
23
|
|
24
24
|
classes = [
|
25
|
-
style(:variants, variant) ||
|
26
|
-
style(:colors, color) ||
|
27
|
-
options.delete(:class) ||
|
28
|
-
].reject(&:blank?).join(
|
25
|
+
style(:variants, variant) || "",
|
26
|
+
style(:colors, color) || "",
|
27
|
+
options.delete(:class) || ""
|
28
|
+
].reject(&:blank?).join(" ")
|
29
29
|
|
30
30
|
view.render(
|
31
31
|
template_path,
|
@@ -65,4 +65,4 @@ module OkonomiUiKit
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
68
|
-
end
|
68
|
+
end
|
@@ -6,11 +6,15 @@ module OkonomiUiKit
|
|
6
6
|
raise ArgumentError, "Styles must be a Hash" unless styles.is_a?(Hash)
|
7
7
|
|
8
8
|
styles_registry[theme] ||= {}
|
9
|
-
styles_registry[theme] = styles_registry[theme]
|
9
|
+
styles_registry[theme] = deep_merge({}, styles_registry[theme], styles)
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.styles_registry
|
13
13
|
@styles_registry ||= {}
|
14
14
|
end
|
15
|
+
|
16
|
+
def self.deep_merge(*hashes)
|
17
|
+
OkonomiUiKit::TWMerge.deep_merge_all(*hashes)
|
18
|
+
end
|
15
19
|
end
|
16
20
|
end
|
@@ -7,202 +7,111 @@ module OkonomiUiKit
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def field_set(options = {}, &block)
|
10
|
-
|
10
|
+
ui.forms.field_set(self, options, &block)
|
11
11
|
end
|
12
12
|
|
13
13
|
def field(field_id = nil, options = {}, &block)
|
14
|
-
|
14
|
+
ui.forms.field(self, field_id, options, &block)
|
15
15
|
end
|
16
16
|
|
17
17
|
def upload_field(method, options = {})
|
18
|
-
|
18
|
+
ui.forms.upload_field(self, method, options)
|
19
19
|
end
|
20
20
|
|
21
21
|
def text_field(method, options = {})
|
22
|
-
|
23
|
-
super(method, { autocomplete: "off" }.merge(options).merge(class: css))
|
22
|
+
super(*resolve_arguments(:text_field, method, options))
|
24
23
|
end
|
25
24
|
|
26
25
|
def email_field(method, options = {})
|
27
|
-
|
28
|
-
super(method, options.merge(class: css))
|
26
|
+
super(*resolve_arguments(:email_field, method, options))
|
29
27
|
end
|
30
28
|
|
31
29
|
def url_field(method, options = {})
|
32
|
-
|
33
|
-
|
30
|
+
super(*resolve_arguments(:url_field, method, options))
|
31
|
+
end
|
32
|
+
|
33
|
+
def resolve_arguments(component_name, *args)
|
34
|
+
component = ui.forms.resolve_component(component_name)
|
35
|
+
|
36
|
+
if component.nil?
|
37
|
+
args
|
38
|
+
else
|
39
|
+
component.render_arguments(object, *args)
|
40
|
+
end
|
34
41
|
end
|
35
42
|
|
36
43
|
def password_field(method, options = {})
|
37
|
-
|
38
|
-
super(method, options.merge(class: css))
|
44
|
+
super(*resolve_arguments(:password_field, method, options))
|
39
45
|
end
|
40
46
|
|
41
47
|
def number_field(method, options = {})
|
42
|
-
|
43
|
-
super(method, options.merge(class: css))
|
48
|
+
super(*resolve_arguments(:number_field, method, options))
|
44
49
|
end
|
45
50
|
|
46
51
|
def telephone_field(method, options = {})
|
47
|
-
|
48
|
-
super(method, options.merge(class: css))
|
52
|
+
super(*resolve_arguments(:telephone_field, method, options))
|
49
53
|
end
|
50
54
|
|
51
55
|
def search_field(method, options = {})
|
52
|
-
|
53
|
-
super(method, options.merge(class: css))
|
56
|
+
super(*resolve_arguments(:search_field, method, options))
|
54
57
|
end
|
55
58
|
|
56
59
|
def date_field(method, options = {})
|
57
|
-
|
58
|
-
super(method, options.merge(class: css))
|
60
|
+
super(*resolve_arguments(:date_field, method, options))
|
59
61
|
end
|
60
62
|
|
61
63
|
def datetime_local_field(method, options = {})
|
62
|
-
|
63
|
-
super(method, options.merge(class: css))
|
64
|
+
super(*resolve_arguments(:datetime_local_field, method, options))
|
64
65
|
end
|
65
66
|
|
66
67
|
def time_field(method, options = {})
|
67
|
-
|
68
|
-
super(method, options.merge(class: css))
|
68
|
+
super(*resolve_arguments(:time_field, method, options))
|
69
69
|
end
|
70
70
|
|
71
71
|
def text_area(method, options = {})
|
72
|
-
|
73
|
-
super(method, options.merge(class: css))
|
72
|
+
super(*resolve_arguments(:text_area, method, options))
|
74
73
|
end
|
75
74
|
|
76
75
|
def select(method, choices = nil, options = {}, html_options = {}, &block)
|
77
|
-
|
78
|
-
ui.get_theme.dig(:components, :select, :root),
|
79
|
-
when_errors(
|
80
|
-
method,
|
81
|
-
ui.get_theme.dig(:components, :select, :error),
|
82
|
-
ui.get_theme.dig(:components, :select, :valid)
|
83
|
-
),
|
84
|
-
html_options[:class]
|
85
|
-
].compact.join(' ').split(' ').uniq
|
86
|
-
|
87
|
-
select_html = super(method, choices, options, html_options.merge(class: css), &block)
|
88
|
-
icon_html = @template.svg_icon(
|
89
|
-
ui.get_theme.dig(:components, :select, :icon, :file),
|
90
|
-
class: ui.get_theme.dig(:components, :select, :icon, :class)
|
91
|
-
)
|
92
|
-
|
93
|
-
@template.content_tag(:div, class: ui.get_theme.dig(:components, :select, :wrapper)) do
|
94
|
-
@template.concat(select_html)
|
95
|
-
@template.concat(icon_html)
|
96
|
-
end
|
76
|
+
ui.forms.select(self, method, choices, options, html_options, &block)
|
97
77
|
end
|
98
78
|
|
99
79
|
def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
|
100
|
-
|
101
|
-
ui.get_theme.dig(:components, :select, :root),
|
102
|
-
when_errors(
|
103
|
-
method,
|
104
|
-
ui.get_theme.dig(:components, :select, :error),
|
105
|
-
ui.get_theme.dig(:components, :select, :valid)
|
106
|
-
),
|
107
|
-
html_options[:class]
|
108
|
-
].compact.join(' ').split(' ').uniq
|
109
|
-
|
110
|
-
select_html = super(method, collection, value_method, text_method, options, html_options.merge(class: css))
|
111
|
-
icon_html = @template.svg_icon(
|
112
|
-
ui.get_theme.dig(:components, :select, :icon, :file),
|
113
|
-
class: ui.get_theme.dig(:components, :select, :icon, :class)
|
114
|
-
)
|
115
|
-
|
116
|
-
@template.content_tag(:div, class: ui.get_theme.dig(:components, :select, :wrapper)) do
|
117
|
-
@template.concat(select_html)
|
118
|
-
@template.concat(icon_html)
|
119
|
-
end
|
80
|
+
ui.forms.collection_select(self, method, collection, value_method, text_method, options, html_options)
|
120
81
|
end
|
121
82
|
|
122
83
|
def multi_select(method, **options)
|
123
|
-
|
124
|
-
partial: 'okonomi/forms/tailwind/multi_select',
|
125
|
-
locals: {
|
126
|
-
form: self,
|
127
|
-
method: method,
|
128
|
-
options: options
|
129
|
-
}
|
130
|
-
)
|
84
|
+
ui.forms.multi_select(self, method, options)
|
131
85
|
end
|
132
86
|
|
133
87
|
def label(method, text = nil, options = {}, &block)
|
134
|
-
|
135
|
-
super(method, text, merge_class(options, base_classes), &block)
|
88
|
+
ui.forms.label(self, method, text, options, &block)
|
136
89
|
end
|
137
90
|
|
138
91
|
def submit(value = nil, options = {})
|
139
|
-
|
140
|
-
|
92
|
+
value, options = nil, value if value.is_a?(Hash)
|
93
|
+
value ||= submit_default_value
|
141
94
|
|
142
|
-
|
143
|
-
|
95
|
+
options ||= {}
|
96
|
+
options[:type] = "submit"
|
97
|
+
options[:variant] ||= "contained"
|
98
|
+
options[:color] ||= "primary"
|
99
|
+
|
100
|
+
ui.button_tag(value, options)
|
144
101
|
end
|
145
102
|
|
146
103
|
def check_box_with_label(method, options = {}, checked_value = true, unchecked_value = false)
|
147
|
-
|
148
|
-
@template.concat check_box(
|
149
|
-
method,
|
150
|
-
{
|
151
|
-
class: ui.get_theme.dig(:components, :checkbox, :input, :root)
|
152
|
-
}.merge(options || {}),
|
153
|
-
checked_value,
|
154
|
-
unchecked_value
|
155
|
-
)
|
156
|
-
@template.concat @template.render('okonomi/forms/tailwind/checkbox_label', method:, options:, form: self)
|
157
|
-
end
|
104
|
+
ui.forms.check_box_with_label(self, method, options, checked_value, unchecked_value)
|
158
105
|
end
|
159
106
|
|
160
107
|
def show_if(field:, equals:, &block)
|
161
|
-
|
162
|
-
@template.tag.div(
|
163
|
-
class: "hidden",
|
164
|
-
data: {
|
165
|
-
controller: "form-field-visibility",
|
166
|
-
"form-field-visibility-field-id-value": field_id,
|
167
|
-
"form-field-visibility-equals-value": equals
|
168
|
-
},
|
169
|
-
&block
|
170
|
-
)
|
108
|
+
ui.forms.show_if(self, field: field, equals: equals, &block)
|
171
109
|
end
|
172
110
|
|
173
111
|
private
|
174
112
|
|
175
|
-
def input_field_classes(method, type, options, include_disabled: true)
|
176
|
-
css_classes = [
|
177
|
-
ui.get_theme.dig(:components, :input, :types, type, :root) || ui.get_theme.dig(:components, :input, :types, :text, :root),
|
178
|
-
when_errors(
|
179
|
-
method,
|
180
|
-
ui.get_theme.dig(:components, :input, :types, type, :error) || ui.get_theme.dig(:components, :input, :types, :text, :error),
|
181
|
-
ui.get_theme.dig(:components, :input, :types, type, :valid) || ui.get_theme.dig(:components, :input, :types, :text, :valid)
|
182
|
-
),
|
183
|
-
options[:class]
|
184
|
-
]
|
185
|
-
|
186
|
-
if include_disabled
|
187
|
-
css_classes << (
|
188
|
-
ui.get_theme.dig(:components, :input, :types, type, :disabled) || ui.get_theme.dig(:components, :input, :types, :text, :disabled)
|
189
|
-
)
|
190
|
-
end
|
191
|
-
|
192
|
-
css_classes.compact.join(' ').split(' ').uniq
|
193
|
-
end
|
194
|
-
|
195
|
-
def when_errors(method, value, default_value = nil)
|
196
|
-
key = method.to_s.gsub('_id', '').to_sym
|
197
|
-
if object.errors.include?(key) || object.errors.include?(method)
|
198
|
-
value
|
199
|
-
else
|
200
|
-
default_value
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
113
|
def merge_class(options, new_class)
|
205
|
-
options[:class] =
|
114
|
+
options[:class] = OkonomiUiKit::TWMerge.merge(options[:class] || "", new_class)
|
206
115
|
options
|
207
116
|
end
|
208
117
|
end
|
@@ -13,16 +13,16 @@ module OkonomiUiKit
|
|
13
13
|
|
14
14
|
def self.file_path(name)
|
15
15
|
# First check in the host application
|
16
|
-
host_path = Rails.root.join(
|
16
|
+
host_path = Rails.root.join("app", "assets", "images", "#{name}.svg")
|
17
17
|
return host_path if File.exist?(host_path)
|
18
|
-
|
18
|
+
|
19
19
|
# Fall back to the engine's icons
|
20
|
-
engine_path = OkonomiUiKit::Engine.root.join(
|
20
|
+
engine_path = OkonomiUiKit::Engine.root.join("app", "assets", "images", "#{name}.svg")
|
21
21
|
return engine_path if File.exist?(engine_path)
|
22
|
-
|
22
|
+
|
23
23
|
nil
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
# Deprecated, kept for backwards compatibility
|
27
27
|
def self.file_name(name)
|
28
28
|
file_path(name)
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
class TWMerge
|
3
|
+
# ---- Public API -----------------------------------------------------------
|
4
|
+
|
5
|
+
# Merge two Tailwind class strings with conflict resolution.
|
6
|
+
def self.merge(a, b)
|
7
|
+
tokens = "#{a} #{b}".split(/\s+/).reject(&:empty?)
|
8
|
+
result = []
|
9
|
+
index_by_key = {}
|
10
|
+
|
11
|
+
tokens.each do |tok|
|
12
|
+
variants, base = split_variants(tok)
|
13
|
+
group = conflict_group_for(base)
|
14
|
+
key = [ variants, group || "literal:#{base}" ]
|
15
|
+
|
16
|
+
if index_by_key.key?(key)
|
17
|
+
pos = index_by_key[key]
|
18
|
+
result[pos] = tok
|
19
|
+
else
|
20
|
+
index_by_key[key] = result.length
|
21
|
+
result << tok
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
result.join(" ")
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.merge_all(*args)
|
29
|
+
args.compact.reduce do |merged, arg|
|
30
|
+
merge(merged, arg)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Deep-merge two hashes; when both values are strings, merge as Tailwind classes.
|
35
|
+
# For other types, the right-hand value wins unless it is nil.
|
36
|
+
def self.deep_merge(a, b)
|
37
|
+
if a.is_a?(Hash) && b.is_a?(Hash)
|
38
|
+
(a.keys | b.keys).each_with_object({}) do |k, h|
|
39
|
+
h[k] = deep_merge(a[k], b[k])
|
40
|
+
end
|
41
|
+
elsif a.is_a?(String) && b.is_a?(String)
|
42
|
+
merge(a, b)
|
43
|
+
else
|
44
|
+
b.nil? ? a : b
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.deep_merge_all(*hashes)
|
49
|
+
hashes.reduce({}) do |result, hash|
|
50
|
+
if hash.is_a?(Hash)
|
51
|
+
deep_merge(result, hash)
|
52
|
+
else
|
53
|
+
raise ArgumentError, "All arguments must be Hashes"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# ---- Implementation details ----------------------------------------------
|
59
|
+
|
60
|
+
# Conflict groups (minimal, extensible). More specific patterns first.
|
61
|
+
CONFLICT_RULES = [
|
62
|
+
# Typography
|
63
|
+
[ /^text-(?:xs|sm|base|lg|xl|\d+xl|\[\S+\])$/, :text_size ],
|
64
|
+
[ /^text-(?:inherit|current|transparent|black|white|[a-z]+-\d{2,3}|[a-z]+-950|\[.+\])$/, :text_color ],
|
65
|
+
[ /^font-(?:thin|extralight|light|normal|medium|semibold|bold|extrabold|black)$/, :font_weight ],
|
66
|
+
[ /^leading-(?:none|tight|snug|normal|relaxed|loose|\d+|\[.+\])$/, :line_height ],
|
67
|
+
[ /^tracking-(?:tighter|tight|normal|wide|widest|\[.+\])$/, :letter_spacing ],
|
68
|
+
|
69
|
+
# Display & position
|
70
|
+
[ /^(?:hidden|block|inline|inline-block|flex|inline-flex|grid|inline-grid|table|inline-table|flow-root)$/, :display ],
|
71
|
+
[ /^(?:static|fixed|absolute|relative|sticky)$/, :position ],
|
72
|
+
|
73
|
+
# Flexbox
|
74
|
+
[ /^flex-(?:row|col|row-reverse|col-reverse)$/, :flex_direction ],
|
75
|
+
[ /^flex-(?:wrap|nowrap|wrap-reverse)$/, :flex_wrap ],
|
76
|
+
[ /^items-(?:start|end|center|baseline|stretch)$/, :align_items ],
|
77
|
+
[ /^justify-(?:start|end|center|between|around|evenly)$/, :justify_content ],
|
78
|
+
|
79
|
+
# Borders
|
80
|
+
[ /^(?:border|border-(?:\d+|\[\S+\]))$/, :border_width_overall ],
|
81
|
+
[ /^border-[trblxy](?:-\d+|\[\S+\])?$/, :border_width_side ],
|
82
|
+
[ /^border-(?:solid|dashed|dotted|double|none)$/, :border_style ],
|
83
|
+
[ /^border-(?:inherit|current|transparent|black|white|[a-z]+-\d{2,3}|[a-z]+-950|\[.+\])$/, :border_color ],
|
84
|
+
|
85
|
+
# Radius
|
86
|
+
[ /^rounded(?:-(?:none|sm|md|lg|xl|2xl|3xl|full|\[.+\]))?$/, :rounded_overall ],
|
87
|
+
[ /^rounded-(?:t|r|b|l|tl|tr|br|bl)-(?:none|sm|md|lg|xl|2xl|3xl|full|\[.+\])$/, :rounded_corner ],
|
88
|
+
|
89
|
+
# Background
|
90
|
+
[ /^bg-(?:inherit|current|transparent|black|white|[a-z]+-\d{2,3}|[a-z]+-950|\[.+\])$/, :bg_color ],
|
91
|
+
|
92
|
+
# Overflow & opacity
|
93
|
+
[ /^overflow-(?:auto|hidden|visible|scroll|clip)$/, :overflow ],
|
94
|
+
[ /^overflow-[xy]-(?:auto|hidden|visible|scroll|clip)$/, :overflow_axis ],
|
95
|
+
[ /^opacity-(?:\d{1,3}|\[.+\])$/, :opacity ]
|
96
|
+
].freeze
|
97
|
+
|
98
|
+
class << self
|
99
|
+
private
|
100
|
+
|
101
|
+
# "sm:hover:text-lg" -> ["sm:hover", "text-lg"]
|
102
|
+
def split_variants(token)
|
103
|
+
parts = token.split(":")
|
104
|
+
return [ "", token ] if parts.size == 1
|
105
|
+
[ parts[0..-2].join(":"), parts[-1] ]
|
106
|
+
end
|
107
|
+
|
108
|
+
def conflict_group_for(base)
|
109
|
+
rule = CONFLICT_RULES.find { |(rx, _)| base.match?(rx) }
|
110
|
+
rule ? rule[1] : nil
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|