okonomi_ui_kit 0.1.8 → 0.1.10

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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +50 -6
  3. data/app/assets/builds/okonomi_ui_kit/application.tailwind.css +508 -225
  4. data/app/helpers/okonomi_ui_kit/CLAUDE.md +619 -0
  5. data/app/helpers/okonomi_ui_kit/application_helper.rb +8 -0
  6. data/app/helpers/okonomi_ui_kit/attribute_section_helper.rb +5 -5
  7. data/app/helpers/okonomi_ui_kit/component.rb +14 -6
  8. data/app/helpers/okonomi_ui_kit/components/alert.rb +1 -1
  9. data/app/helpers/okonomi_ui_kit/components/badge.rb +4 -4
  10. data/app/helpers/okonomi_ui_kit/components/breadcrumbs.rb +4 -4
  11. data/app/helpers/okonomi_ui_kit/components/button_base.rb +94 -22
  12. data/app/helpers/okonomi_ui_kit/components/button_tag.rb +14 -8
  13. data/app/helpers/okonomi_ui_kit/components/button_to.rb +8 -7
  14. data/app/helpers/okonomi_ui_kit/components/code.rb +41 -37
  15. data/app/helpers/okonomi_ui_kit/components/confirmation_modal.rb +130 -0
  16. data/app/helpers/okonomi_ui_kit/components/dropdown_button.rb +147 -0
  17. data/app/helpers/okonomi_ui_kit/components/forms/check_box_with_label.rb +38 -0
  18. data/app/helpers/okonomi_ui_kit/components/forms/collection_select.rb +57 -0
  19. data/app/helpers/okonomi_ui_kit/components/forms/date_field.rb +9 -0
  20. data/app/helpers/okonomi_ui_kit/components/forms/datetime_local_field.rb +9 -0
  21. data/app/helpers/okonomi_ui_kit/components/forms/email_field.rb +9 -0
  22. data/app/helpers/okonomi_ui_kit/components/forms/field.rb +24 -0
  23. data/app/helpers/okonomi_ui_kit/components/forms/field_set.rb +17 -0
  24. data/app/helpers/okonomi_ui_kit/components/forms/input_base.rb +57 -0
  25. data/app/helpers/okonomi_ui_kit/components/forms/label.rb +27 -0
  26. data/app/helpers/okonomi_ui_kit/components/forms/multi_select.rb +18 -0
  27. data/app/helpers/okonomi_ui_kit/components/forms/number_field.rb +9 -0
  28. data/app/helpers/okonomi_ui_kit/components/forms/password_field.rb +9 -0
  29. data/app/helpers/okonomi_ui_kit/components/forms/search_field.rb +9 -0
  30. data/app/helpers/okonomi_ui_kit/components/forms/select.rb +57 -0
  31. data/app/helpers/okonomi_ui_kit/components/forms/show_if.rb +28 -0
  32. data/app/helpers/okonomi_ui_kit/components/forms/telephone_field.rb +9 -0
  33. data/app/helpers/okonomi_ui_kit/components/forms/text_area.rb +9 -0
  34. data/app/helpers/okonomi_ui_kit/components/forms/text_field.rb +9 -0
  35. data/app/helpers/okonomi_ui_kit/components/forms/time_field.rb +9 -0
  36. data/app/helpers/okonomi_ui_kit/components/forms/upload_field.rb +25 -0
  37. data/app/helpers/okonomi_ui_kit/components/forms/url_field.rb +9 -0
  38. data/app/helpers/okonomi_ui_kit/components/forms.rb +6 -0
  39. data/app/helpers/okonomi_ui_kit/components/icon.rb +6 -6
  40. data/app/helpers/okonomi_ui_kit/components/link_to.rb +11 -10
  41. data/app/helpers/okonomi_ui_kit/components/navigation.rb +98 -0
  42. data/app/helpers/okonomi_ui_kit/components/page.rb +18 -203
  43. data/app/helpers/okonomi_ui_kit/components/page_header.rb +111 -0
  44. data/app/helpers/okonomi_ui_kit/components/page_section.rb +145 -0
  45. data/app/helpers/okonomi_ui_kit/components/table.rb +7 -8
  46. data/app/helpers/okonomi_ui_kit/components/typography.rb +16 -16
  47. data/app/helpers/okonomi_ui_kit/components.rb +4 -0
  48. data/app/helpers/okonomi_ui_kit/configs.rb +4 -0
  49. data/app/helpers/okonomi_ui_kit/form_builder.rb +39 -130
  50. data/app/helpers/okonomi_ui_kit/form_component.rb +7 -0
  51. data/app/helpers/okonomi_ui_kit/svg_icons.rb +5 -5
  52. data/app/helpers/okonomi_ui_kit/t_w_merge.rb +33 -27
  53. data/app/helpers/okonomi_ui_kit/ui_helper.rb +17 -58
  54. data/app/javascript/okonomi_ui_kit/controllers/dropdown_controller.js +6 -0
  55. data/app/views/okonomi/components/confirmation_modal/_confirmation_modal.html.erb +76 -0
  56. data/app/views/okonomi/components/dropdown_button/_dropdown_button.html.erb +282 -0
  57. data/app/views/okonomi/components/forms/check_box_with_label/_check_box_with_label.html.erb +6 -0
  58. data/app/views/okonomi/{forms/tailwind → components/forms/field}/_field.html.erb +7 -7
  59. data/app/views/okonomi/components/forms/field_set/_field_set.html.erb +3 -0
  60. data/app/views/okonomi/components/forms/upload_field/_upload_field.html.erb +1 -0
  61. data/app/views/okonomi/components/navigation/_link.html.erb +18 -0
  62. data/app/views/okonomi/components/navigation/_navigation.html.erb +4 -0
  63. data/app/views/okonomi/components/page/_page.html.erb +1 -1
  64. data/app/views/okonomi/components/page_header/_page_header.html.erb +4 -0
  65. data/app/views/okonomi/components/page_section/_page_section.html.erb +4 -0
  66. data/app/views/okonomi/forms/tailwind/_checkbox_label.html.erb +2 -2
  67. data/app/views/okonomi/forms/tailwind/_multi_select.html.erb +2 -4
  68. data/app/views/okonomi/forms/tailwind/_upload_field.html.erb +10 -10
  69. data/config/importmap.rb +1 -1
  70. data/lib/okonomi_ui_kit/engine.rb +0 -1
  71. data/lib/okonomi_ui_kit/version.rb +1 -1
  72. metadata +47 -16
  73. data/app/helpers/okonomi_ui_kit/navigation_helper.rb +0 -72
  74. data/app/helpers/okonomi_ui_kit/theme.rb +0 -136
  75. data/app/helpers/okonomi_ui_kit/theme_helper.rb +0 -17
  76. data/app/views/okonomi/forms/tailwind/_field_set.html.erb +0 -3
  77. data/app/views/okonomi/modals/_confirmation_modal.html.erb +0 -77
  78. data/app/views/okonomi/navigation/_link.html.erb +0 -15
  79. data/app/views/okonomi/navigation/_menu.html.erb +0 -3
  80. data/app/views/okonomi/navigation/_navbar.html.erb +0 -105
  81. data/app/views/okonomi/page_builder/_page.html.erb +0 -3
@@ -7,202 +7,111 @@ module OkonomiUiKit
7
7
  end
8
8
 
9
9
  def field_set(options = {}, &block)
10
- @template.render('okonomi/forms/tailwind/field_set', options:, form: self, &block)
10
+ ui.forms.field_set(self, options, &block)
11
11
  end
12
12
 
13
13
  def field(field_id = nil, options = {}, &block)
14
- @template.render('okonomi/forms/tailwind/field', field_id:, options:, form: self, &block)
14
+ ui.forms.field(self, field_id, options, &block)
15
15
  end
16
16
 
17
17
  def upload_field(method, options = {})
18
- @template.render('okonomi/forms/tailwind/upload_field', method:, options:, form: self)
18
+ ui.forms.upload_field(self, method, options)
19
19
  end
20
20
 
21
21
  def text_field(method, options = {})
22
- css = input_field_classes(method, :text, options)
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
- css = input_field_classes(method, :email, options)
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
- css = input_field_classes(method, :url, options)
33
- super(method, options.merge(class: css))
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
- css = input_field_classes(method, :password, options)
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
- css = input_field_classes(method, :number, options)
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
- css = input_field_classes(method, :telephone_field, options)
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
- css = input_field_classes(method, :search, options)
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
- css = input_field_classes(method, :date, options)
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
- css = input_field_classes(method, :datetime_local, options)
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
- css = input_field_classes(method, :time, options)
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
- css = input_field_classes(method, :textarea, options, include_disabled: false)
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
- css = [
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.ui.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
- css = [
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.ui.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
- @template.render(
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
- base_classes = ui.get_theme.dig(:components, :label, :root)
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
- variant = options.delete(:variant) || 'contained'
140
- color = options.delete(:color) || 'primary'
92
+ value, options = nil, value if value.is_a?(Hash)
93
+ value ||= submit_default_value
141
94
 
142
- base_classes = ui.button_class(variant:, color:)
143
- super(value, merge_class(options, base_classes))
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
- @template.content_tag(:div, class: ui.get_theme.dig(:components, :checkbox, :wrapper)) do
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
- field_id = "#{object_name}_#{field}"
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] = [options[:class], new_class].compact.join(" ")
114
+ options[:class] = OkonomiUiKit::TWMerge.merge(options[:class] || "", new_class)
206
115
  options
207
116
  end
208
117
  end
@@ -0,0 +1,7 @@
1
+ module OkonomiUiKit
2
+ class FormComponent < Component
3
+ def self.namespace
4
+ OkonomiUiKit::Components::Forms
5
+ end
6
+ end
7
+ 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('app', 'assets', 'images', "#{name}.svg")
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('app', 'assets', 'images', "#{name}.svg")
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)
@@ -11,7 +11,7 @@ module OkonomiUiKit
11
11
  tokens.each do |tok|
12
12
  variants, base = split_variants(tok)
13
13
  group = conflict_group_for(base)
14
- key = [variants, group || "literal:#{base}"]
14
+ key = [ variants, group || "literal:#{base}" ]
15
15
 
16
16
  if index_by_key.key?(key)
17
17
  pos = index_by_key[key]
@@ -22,7 +22,13 @@ module OkonomiUiKit
22
22
  end
23
23
  end
24
24
 
25
- result.join(' ')
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
26
32
  end
27
33
 
28
34
  # Deep-merge two hashes; when both values are strings, merge as Tailwind classes.
@@ -54,39 +60,39 @@ module OkonomiUiKit
54
60
  # Conflict groups (minimal, extensible). More specific patterns first.
55
61
  CONFLICT_RULES = [
56
62
  # Typography
57
- [/^text-(?:xs|sm|base|lg|xl|\d+xl|\[\S+\])$/, :text_size],
58
- [/^text-(?:inherit|current|transparent|black|white|[a-z]+-\d{2,3}|[a-z]+-950|\[.+\])$/, :text_color],
59
- [/^font-(?:thin|extralight|light|normal|medium|semibold|bold|extrabold|black)$/, :font_weight],
60
- [/^leading-(?:none|tight|snug|normal|relaxed|loose|\d+|\[.+\])$/, :line_height],
61
- [/^tracking-(?:tighter|tight|normal|wide|widest|\[.+\])$/, :letter_spacing],
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 ],
62
68
 
63
69
  # Display & position
64
- [/^(?:hidden|block|inline|inline-block|flex|inline-flex|grid|inline-grid|table|inline-table|flow-root)$/, :display],
65
- [/^(?:static|fixed|absolute|relative|sticky)$/, :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 ],
66
72
 
67
73
  # Flexbox
68
- [/^flex-(?:row|col|row-reverse|col-reverse)$/, :flex_direction],
69
- [/^flex-(?:wrap|nowrap|wrap-reverse)$/, :flex_wrap],
70
- [/^items-(?:start|end|center|baseline|stretch)$/, :align_items],
71
- [/^justify-(?:start|end|center|between|around|evenly)$/, :justify_content],
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 ],
72
78
 
73
79
  # Borders
74
- [/^(?:border|border-(?:\d+|\[\S+\]))$/, :border_width_overall],
75
- [/^border-[trblxy](?:-\d+|\[\S+\])?$/, :border_width_side],
76
- [/^border-(?:solid|dashed|dotted|double|none)$/, :border_style],
77
- [/^border-(?:inherit|current|transparent|black|white|[a-z]+-\d{2,3}|[a-z]+-950|\[.+\])$/, :border_color],
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 ],
78
84
 
79
85
  # Radius
80
- [/^rounded(?:-(?:none|sm|md|lg|xl|2xl|3xl|full|\[.+\]))?$/, :rounded_overall],
81
- [/^rounded-(?:t|r|b|l|tl|tr|br|bl)-(?:none|sm|md|lg|xl|2xl|3xl|full|\[.+\])$/, :rounded_corner],
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 ],
82
88
 
83
89
  # Background
84
- [/^bg-(?:inherit|current|transparent|black|white|[a-z]+-\d{2,3}|[a-z]+-950|\[.+\])$/, :bg_color],
90
+ [ /^bg-(?:inherit|current|transparent|black|white|[a-z]+-\d{2,3}|[a-z]+-950|\[.+\])$/, :bg_color ],
85
91
 
86
92
  # Overflow & opacity
87
- [/^overflow-(?:auto|hidden|visible|scroll|clip)$/, :overflow],
88
- [/^overflow-[xy]-(?:auto|hidden|visible|scroll|clip)$/, :overflow_axis],
89
- [/^opacity-(?:\d{1,3}|\[.+\])$/, :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 ]
90
96
  ].freeze
91
97
 
92
98
  class << self
@@ -94,9 +100,9 @@ module OkonomiUiKit
94
100
 
95
101
  # "sm:hover:text-lg" -> ["sm:hover", "text-lg"]
96
102
  def split_variants(token)
97
- parts = token.split(':')
98
- return ["", token] if parts.size == 1
99
- [parts[0..-2].join(':'), parts[-1]]
103
+ parts = token.split(":")
104
+ return [ "", token ] if parts.size == 1
105
+ [ parts[0..-2].join(":"), parts[-1] ]
100
106
  end
101
107
 
102
108
  def conflict_group_for(base)
@@ -105,4 +111,4 @@ module OkonomiUiKit
105
111
  end
106
112
  end
107
113
  end
108
- end
114
+ end
@@ -8,74 +8,33 @@ module OkonomiUiKit
8
8
  include ActionView::Helpers::TagHelper
9
9
  include ActionView::Helpers::CaptureHelper
10
10
 
11
- def initialize(template)
12
- @template = template
13
- end
14
-
15
- def theme(t = {}, &block)
16
- old_theme = get_theme
17
-
18
- @_okonomi_ui_kit_theme = {}.merge(old_theme).merge(t || {})
19
-
20
- yield(@_okonomi_ui_kit_theme)
11
+ attr_reader :template, :namespace
21
12
 
22
- @_okonomi_ui_kit_theme = old_theme
23
- end
24
-
25
- def get_theme
26
- @_okonomi_ui_kit_theme ||= OkonomiUiKit::Theme::DEFAULT_THEME
13
+ def initialize(template, namespace: OkonomiUiKit::Components)
14
+ @template = template
15
+ @namespace = namespace
27
16
  end
28
17
 
29
- def button_class(variant: 'contained', color: 'default', classes: '')
30
- [
31
- get_theme.dig(:components, :link, :root) || '',
32
- get_theme.dig(:components, :link, variant.to_sym, :root) || '',
33
- get_theme.dig(:components, :link, variant.to_sym, :colors, color.to_sym) || '',
34
- classes,
35
- ].join(' ')
36
- end
18
+ def method_missing(method_name, *args, &block)
19
+ component = resolve_component(method_name)
37
20
 
38
- def confirmation_modal(title:, message:, confirm_text: "Confirm", cancel_text: "Cancel", variant: :warning, size: :md, **options, &block)
39
- modal_options = {
40
- title: title,
41
- message: message,
42
- confirm_text: confirm_text,
43
- cancel_text: cancel_text,
44
- variant: variant,
45
- size: size,
46
- has_custom_actions: block_given?,
47
- **options
48
- }
49
- @template.render("okonomi/modals/confirmation_modal", options: modal_options, ui: self, &block)
21
+ if component
22
+ component.render(*args, &block)
23
+ else
24
+ super
25
+ end
50
26
  end
51
27
 
52
- def modal_data_attributes(options)
53
- return "" unless options[:data]
54
-
55
- options[:data].map { |k, v| "data-#{k.to_s.dasherize}=\"#{v}\"" }.join(' ').html_safe
56
- end
28
+ def resolve_component(name)
29
+ component_name = "#{namespace.name}::#{name.to_s.camelize}"
57
30
 
58
- def modal_panel_class(size)
59
- [
60
- get_theme.dig(:components, :modal, :panel, :base),
61
- get_theme.dig(:components, :modal, :panel, :sizes, size)
62
- ].compact.join(' ')
63
- end
31
+ return nil unless Object.const_defined?(component_name)
64
32
 
65
- def modal_icon_wrapper_class(variant)
66
- [
67
- get_theme.dig(:components, :modal, :icon, :wrapper),
68
- get_theme.dig(:components, :modal, :icon, :variants, variant, :wrapper)
69
- ].compact.join(' ')
33
+ component_name.constantize.new(@template)
70
34
  end
71
35
 
72
- def method_missing(method_name, *args, &block)
73
- component_name = "OkonomiUiKit::Components::#{method_name.to_s.camelize}"
74
- if Object.const_defined?(component_name)
75
- return component_name.constantize.new(@template, get_theme).render(*args, &block)
76
- else
77
- super
78
- end
36
+ def forms
37
+ @forms ||= self.class.new(@template, namespace: OkonomiUiKit::Components::Forms)
79
38
  end
80
39
  end
81
40
  end
@@ -19,6 +19,12 @@ export default class extends Controller {
19
19
  this.menuTarget.classList.add("hidden")
20
20
  }
21
21
 
22
+ closeDeferred() {
23
+ setTimeout(() => {
24
+ this.close()
25
+ }, 50)
26
+ }
27
+
22
28
  closeOnClickOutside(event) {
23
29
  if (!this.element.contains(event.target)) {
24
30
  this.close()
@@ -0,0 +1,76 @@
1
+ <div data-controller="modal"
2
+ data-modal-size-value="<%= options[:size] %>"
3
+ <% if options[:auto_open] %>data-modal-auto-open-value="true"<% end %>
4
+ class="relative z-10"
5
+ style="display: none;"
6
+ data-modal-target="container"
7
+ <%= component.modal_data_attributes(options) %>>
8
+
9
+ <!-- Backdrop -->
10
+ <div class="<%= component.style(:backdrop) %>"
11
+ data-modal-target="backdrop"
12
+ data-action="click->modal#close"
13
+ aria-hidden="true"></div>
14
+
15
+ <!-- Modal container -->
16
+ <div class="<%= component.style(:container) %>">
17
+ <div class="<%= component.style(:wrapper) %>">
18
+ <!-- Modal panel -->
19
+ <div class="<%= component.modal_panel_class(options[:size]) %>"
20
+ data-modal-target="panel"
21
+ role="dialog"
22
+ aria-modal="true"
23
+ aria-labelledby="modal-title">
24
+
25
+ <!-- Close button -->
26
+ <div class="<%= component.style(:close_button, :wrapper) %>">
27
+ <button type="button"
28
+ class="<%= component.style(:close_button, :button) %>"
29
+ data-action="click->modal#close">
30
+ <span class="sr-only">Close</span>
31
+ <%= ui.icon(component.style(:close_button, :icon, :file),
32
+ class: component.style(:close_button, :icon, :class)) %>
33
+ </button>
34
+ </div>
35
+
36
+ <!-- Content -->
37
+ <div class="<%= component.style(:content, :wrapper) %>">
38
+ <!-- Icon -->
39
+ <div class="<%= component.modal_icon_wrapper_class(options[:variant]) %>">
40
+ <%= ui.icon(component.style(:icon, :variants, options[:variant], :file),
41
+ class: component.modal_icon_class(options[:variant])) %>
42
+ </div>
43
+
44
+ <!-- Text content -->
45
+ <div class="<%= component.style(:content, :text_wrapper) %>">
46
+ <h3 id="modal-title" class="<%= component.style(:content, :title) %>">
47
+ <%= options[:title] %>
48
+ </h3>
49
+ <div class="<%= component.style(:content, :message) %>">
50
+ <p><%= options[:message] %></p>
51
+ </div>
52
+ </div>
53
+ </div>
54
+
55
+ <!-- Actions -->
56
+ <div class="<%= component.style(:actions, :wrapper) %>">
57
+ <% if options[:has_custom_actions] %>
58
+ <%= yield %>
59
+ <% else %>
60
+ <% button_color = options[:variant] == :warning ? :danger : options[:variant] %>
61
+ <%= ui.button_to options[:confirm_text], "#",
62
+ variant: :contained,
63
+ color: button_color,
64
+ class: "sm:ml-3 sm:w-auto",
65
+ data: { action: "click->modal#confirm" } %>
66
+ <%= ui.button_to options[:cancel_text], "#",
67
+ variant: :outlined,
68
+ color: :default,
69
+ class: "mt-3 sm:mt-0 sm:w-auto",
70
+ data: { action: "click->modal#close" } %>
71
+ <% end %>
72
+ </div>
73
+ </div>
74
+ </div>
75
+ </div>
76
+ </div>