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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +165 -7
  3. data/app/assets/builds/okonomi_ui_kit/application.tailwind.css +664 -187
  4. data/app/helpers/okonomi_ui_kit/application_helper.rb +8 -0
  5. data/app/helpers/okonomi_ui_kit/attribute_section_helper.rb +5 -5
  6. data/app/helpers/okonomi_ui_kit/component.rb +44 -21
  7. data/app/helpers/okonomi_ui_kit/components/alert.rb +1 -1
  8. data/app/helpers/okonomi_ui_kit/components/badge.rb +5 -5
  9. data/app/helpers/okonomi_ui_kit/components/breadcrumbs.rb +69 -0
  10. data/app/helpers/okonomi_ui_kit/components/button_base.rb +56 -0
  11. data/app/helpers/okonomi_ui_kit/components/button_tag.rb +23 -0
  12. data/app/helpers/okonomi_ui_kit/components/button_to.rb +4 -15
  13. data/app/helpers/okonomi_ui_kit/components/code.rb +41 -37
  14. data/app/helpers/okonomi_ui_kit/components/confirmation_modal.rb +130 -0
  15. data/app/helpers/okonomi_ui_kit/components/forms/check_box_with_label.rb +38 -0
  16. data/app/helpers/okonomi_ui_kit/components/forms/collection_select.rb +57 -0
  17. data/app/helpers/okonomi_ui_kit/components/forms/date_field.rb +9 -0
  18. data/app/helpers/okonomi_ui_kit/components/forms/datetime_local_field.rb +9 -0
  19. data/app/helpers/okonomi_ui_kit/components/forms/email_field.rb +9 -0
  20. data/app/helpers/okonomi_ui_kit/components/forms/field.rb +24 -0
  21. data/app/helpers/okonomi_ui_kit/components/forms/field_set.rb +17 -0
  22. data/app/helpers/okonomi_ui_kit/components/forms/input_base.rb +57 -0
  23. data/app/helpers/okonomi_ui_kit/components/forms/label.rb +27 -0
  24. data/app/helpers/okonomi_ui_kit/components/forms/multi_select.rb +18 -0
  25. data/app/helpers/okonomi_ui_kit/components/forms/number_field.rb +9 -0
  26. data/app/helpers/okonomi_ui_kit/components/forms/password_field.rb +9 -0
  27. data/app/helpers/okonomi_ui_kit/components/forms/search_field.rb +9 -0
  28. data/app/helpers/okonomi_ui_kit/components/forms/select.rb +57 -0
  29. data/app/helpers/okonomi_ui_kit/components/forms/show_if.rb +28 -0
  30. data/app/helpers/okonomi_ui_kit/components/forms/telephone_field.rb +9 -0
  31. data/app/helpers/okonomi_ui_kit/components/forms/text_area.rb +9 -0
  32. data/app/helpers/okonomi_ui_kit/components/forms/text_field.rb +9 -0
  33. data/app/helpers/okonomi_ui_kit/components/forms/time_field.rb +9 -0
  34. data/app/helpers/okonomi_ui_kit/components/forms/upload_field.rb +25 -0
  35. data/app/helpers/okonomi_ui_kit/components/forms/url_field.rb +9 -0
  36. data/app/helpers/okonomi_ui_kit/components/forms.rb +6 -0
  37. data/app/helpers/okonomi_ui_kit/components/icon.rb +36 -0
  38. data/app/helpers/okonomi_ui_kit/components/link_to.rb +8 -19
  39. data/app/helpers/okonomi_ui_kit/components/navigation.rb +98 -0
  40. data/app/helpers/okonomi_ui_kit/components/page.rb +8 -8
  41. data/app/helpers/okonomi_ui_kit/components/table.rb +9 -10
  42. data/app/helpers/okonomi_ui_kit/components/typography.rb +16 -16
  43. data/app/helpers/okonomi_ui_kit/components.rb +4 -0
  44. data/app/helpers/okonomi_ui_kit/config.rb +5 -1
  45. data/app/helpers/okonomi_ui_kit/configs.rb +4 -0
  46. data/app/helpers/okonomi_ui_kit/form_builder.rb +39 -130
  47. data/app/helpers/okonomi_ui_kit/form_component.rb +7 -0
  48. data/app/helpers/okonomi_ui_kit/svg_icons.rb +5 -5
  49. data/app/helpers/okonomi_ui_kit/t_w_merge.rb +114 -0
  50. data/app/helpers/okonomi_ui_kit/ui_helper.rb +17 -58
  51. data/app/views/okonomi/components/breadcrumbs/_breadcrumbs.html.erb +46 -0
  52. data/app/views/okonomi/components/confirmation_modal/_confirmation_modal.html.erb +76 -0
  53. data/app/views/okonomi/components/forms/check_box_with_label/_check_box_with_label.html.erb +6 -0
  54. data/app/views/okonomi/components/forms/field/_field.html.erb +3 -0
  55. data/app/views/okonomi/components/forms/field_set/_field_set.html.erb +3 -0
  56. data/app/views/okonomi/components/forms/upload_field/_upload_field.html.erb +1 -0
  57. data/app/views/okonomi/components/icon/_icon.html.erb +38 -0
  58. data/app/views/okonomi/components/navigation/_link.html.erb +18 -0
  59. data/app/views/okonomi/components/navigation/_navigation.html.erb +4 -0
  60. data/app/views/okonomi/forms/tailwind/_checkbox_label.html.erb +2 -2
  61. data/app/views/okonomi/forms/tailwind/_field.html.erb +6 -6
  62. data/app/views/okonomi/forms/tailwind/_multi_select.html.erb +2 -4
  63. data/app/views/okonomi/forms/tailwind/_upload_field.html.erb +10 -10
  64. data/config/importmap.rb +1 -1
  65. data/lib/okonomi_ui_kit/engine.rb +0 -3
  66. data/lib/okonomi_ui_kit/version.rb +1 -1
  67. metadata +43 -12
  68. data/app/helpers/okonomi_ui_kit/breadcrumbs_helper.rb +0 -60
  69. data/app/helpers/okonomi_ui_kit/icon_helper.rb +0 -39
  70. data/app/helpers/okonomi_ui_kit/navigation_helper.rb +0 -72
  71. data/app/helpers/okonomi_ui_kit/theme.rb +0 -159
  72. data/app/helpers/okonomi_ui_kit/theme_helper.rb +0 -17
  73. data/app/views/okonomi/forms/tailwind/_field_set.html.erb +0 -3
  74. data/app/views/okonomi/modals/_confirmation_modal.html.erb +0 -77
  75. data/app/views/okonomi/navigation/_link.html.erb +0 -15
  76. data/app/views/okonomi/navigation/_menu.html.erb +0 -3
  77. data/app/views/okonomi/navigation/_navbar.html.erb +0 -105
@@ -1,4 +1,12 @@
1
1
  module OkonomiUiKit
2
2
  module ApplicationHelper
3
+ def active_link_to(path, options = {}, &block)
4
+ path_to_check = path.split("?").first
5
+ if (options[:exact] && request.path == path_to_check) || (!options[:exact] && request.path.include?(path_to_check))
6
+ options[:class] = options[:active_class].presence || [ options[:class], "active" ].compact.join(" ")
7
+ end
8
+
9
+ link_to(path, options, &block)
10
+ end
3
11
  end
4
12
  end
@@ -3,7 +3,7 @@ module OkonomiUiKit
3
3
  def attribute_section(title:, description: nil, **options, &block)
4
4
  builder = AttributeSectionBuilder.new(self)
5
5
 
6
- render 'okonomi/attribute_sections/section',
6
+ render "okonomi/attribute_sections/section",
7
7
  builder: builder,
8
8
  title: title,
9
9
  description: description,
@@ -22,11 +22,11 @@ module OkonomiUiKit
22
22
  def attribute(label, value = nil, **options, &block)
23
23
  content = if block_given?
24
24
  capture(&block)
25
- elsif value.respond_to?(:call)
25
+ elsif value.respond_to?(:call)
26
26
  value.call
27
- else
27
+ else
28
28
  value
29
- end
29
+ end
30
30
 
31
31
  tag.div(class: "py-6 sm:grid sm:grid-cols-3 sm:gap-4") do
32
32
  dt_content = tag.dt(label, class: "text-sm font-medium text-gray-900")
@@ -47,4 +47,4 @@ module OkonomiUiKit
47
47
  end
48
48
  end
49
49
  end
50
- end
50
+ end
@@ -1,14 +1,13 @@
1
1
  module OkonomiUiKit
2
2
  class Component
3
- attr_reader :view, :theme
3
+ attr_reader :view
4
4
 
5
- def initialize(view, theme)
5
+ def initialize(view)
6
6
  @view = view
7
- @theme = theme || OkonomiUiKit::Theme::DEFAULT_THEME
8
7
  end
9
8
 
10
9
  def template_path
11
- "okonomi/components/#{name}/#{name}"
10
+ [ self.class.name.underscore.gsub("okonomi_ui_kit/", "okonomi/"), name ].join("/")
12
11
  end
13
12
 
14
13
  def name
@@ -30,7 +29,7 @@ module OkonomiUiKit
30
29
  internal_styles = internal_styles_registry[internal_name] || {}
31
30
  config_styles = config_styles_registry[config_name] || {}
32
31
 
33
- {}.deep_merge(internal_styles).deep_merge(config_styles)
32
+ deep_merge({}, internal_styles, config_styles)
34
33
  end
35
34
 
36
35
  def internal_styles_registry
@@ -45,36 +44,60 @@ module OkonomiUiKit
45
44
  :default
46
45
  end
47
46
 
48
- def self.config_styles_registry
49
- return Hash.new({}) unless config_class?
47
+ def self.register_styles(theme = :default, &block)
48
+ styles = block.call if block_given?
50
49
 
51
- config_class.styles_registry
50
+ raise ArgumentError, "Styles must be a Hash" unless styles.is_a?(Hash)
51
+
52
+ internal_styles_registry[theme] ||= {}
53
+ internal_styles_registry[theme] = deep_merge(internal_styles_registry[theme], styles)
52
54
  end
53
55
 
54
- def self.config_class
55
- return nil unless config_class?
56
+ def self.internal_styles_registry
57
+ @internal_styles_registry ||= deep_merge({}, parent_styles_registry)
58
+ end
56
59
 
57
- Object.const_get(config_class_name)
60
+ def self.parent_styles_registry
61
+ if superclass.respond_to?(:internal_styles_registry)
62
+ superclass.internal_styles_registry
63
+ else
64
+ {}
65
+ end
58
66
  end
59
67
 
60
- def self.config_class_name
61
- "OkonomiUiKit::Configs::#{name.demodulize}"
68
+ def self.config_styles_registry
69
+ @config_styles_registry ||= config_classes.reverse.reduce({}) do |hash, klass|
70
+ deep_merge(hash, klass.styles_registry)
71
+ end
62
72
  end
63
73
 
64
- def self.config_class?
65
- Object.const_defined?(config_class_name)
74
+ def self.config_classes
75
+ @config_classes ||= resolve_config_classes
66
76
  end
67
77
 
68
- def self.register_styles(theme = :default, &block)
69
- styles = block.call if block_given?
78
+ def self.resolve_config_classes
79
+ classes = []
80
+ classes << Object.const_get(config_class_name) if config_class?
81
+ classes += superclass.config_classes if superclass <= OkonomiUiKit::Component
70
82
 
71
- raise ArgumentError, "Styles must be a Hash" unless styles.is_a?(Hash)
83
+ classes.compact
84
+ end
72
85
 
73
- internal_styles_registry[theme] = styles if styles.is_a?(Hash)
86
+ def self.config_class_name
87
+ "#{config_namespace.name}::#{name.demodulize}"
74
88
  end
75
89
 
76
- def self.internal_styles_registry
77
- @internal_styles_registry ||= {}
90
+ def self.config_namespace
91
+ OkonomiUiKit::Configs
92
+ end
93
+
94
+ def self.config_class?
95
+ Object.const_defined?(config_class_name)
96
+ end
97
+
98
+ def self.deep_merge(*hashes)
99
+ OkonomiUiKit::TWMerge.deep_merge_all(*hashes)
78
100
  end
101
+ delegate :deep_merge, to: :class
79
102
  end
80
103
  end
@@ -2,7 +2,7 @@ module OkonomiUiKit
2
2
  module Components
3
3
  class Alert < OkonomiUiKit::Component
4
4
  def render(title, options = {}, &block)
5
- view.render(template_path, title:, options: options.with_indifferent_access, &block)
5
+ view.render(template_path, title: title, options: options.with_indifferent_access, &block)
6
6
  end
7
7
  end
8
8
  end
@@ -3,13 +3,13 @@ module OkonomiUiKit
3
3
  class Badge < OkonomiUiKit::Component
4
4
  def render(text, options = {})
5
5
  options = options.with_indifferent_access
6
- severity = (options.delete(:severity) || :default).to_sym
7
-
6
+ severity = (options.delete(:severity) || options.delete(:variant) || :default).to_sym
7
+
8
8
  classes = [
9
9
  style(:base),
10
- style(:severities, severity) || '',
11
- options.delete(:class) || ''
12
- ].reject(&:blank?).join(' ')
10
+ style(:severities, severity) || "",
11
+ options.delete(:class) || ""
12
+ ].reject(&:blank?).join(" ")
13
13
 
14
14
  view.tag.span(text, class: classes, **options)
15
15
  end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OkonomiUiKit
4
+ module Components
5
+ class Breadcrumbs < Component
6
+ register_styles do
7
+ {
8
+ base: "flex",
9
+ container: "isolate flex -space-x-px rounded-lg shadow-sm",
10
+ nav: "",
11
+ list: "flex items-center space-x-4",
12
+ item: {
13
+ base: "",
14
+ first: "",
15
+ last: "",
16
+ current: ""
17
+ },
18
+ link: {
19
+ base: "ml-4 text-sm font-medium text-gray-500 hover:text-gray-700",
20
+ first: "text-sm font-medium text-gray-500 hover:text-gray-700",
21
+ current: "ml-4 text-sm font-medium text-gray-500"
22
+ },
23
+ separator: {
24
+ base: "size-5 shrink-0 text-gray-400",
25
+ wrapper: ""
26
+ },
27
+ icon: "size-5 text-gray-400"
28
+ }
29
+ end
30
+
31
+ def initialize(template)
32
+ super
33
+ @items = []
34
+ @builder = BreadcrumbBuilder.new(self)
35
+ end
36
+
37
+ def render(options = {}, &block)
38
+ return "" if block.nil?
39
+
40
+ block.call(@builder)
41
+ view.render("okonomi/components/breadcrumbs/breadcrumbs",
42
+ component: self,
43
+ items: @items,
44
+ options: options
45
+ )
46
+ end
47
+
48
+ def add_item(text, path = nil, current: false, icon: nil)
49
+ @items << {
50
+ text: text,
51
+ path: path,
52
+ current: current,
53
+ icon: icon
54
+ }
55
+ end
56
+
57
+ class BreadcrumbBuilder
58
+ def initialize(component)
59
+ @component = component
60
+ end
61
+
62
+ def link(text, path = nil, current: false, icon: nil, **options)
63
+ # Ignore extra options for now
64
+ @component.add_item(text, path, current: current, icon: icon)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,56 @@
1
+ module OkonomiUiKit
2
+ module Components
3
+ class ButtonBase < OkonomiUiKit::Component
4
+ def build_button_class(variant:, color:, classes: "")
5
+ [
6
+ style(:root) || "",
7
+ style(variant.to_sym, :root) || "",
8
+ style(variant.to_sym, :colors, color.to_sym) || "",
9
+ classes
10
+ ].reject(&:blank?).join(" ")
11
+ end
12
+
13
+ register_styles :default do
14
+ {
15
+ root: "hover:cursor-pointer text-sm",
16
+ outlined: {
17
+ root: "inline-flex border items-center justify-center px-2 py-1 rounded-md font-medium focus:outline-none focus:ring-2 focus:ring-offset-2",
18
+ colors: {
19
+ default: "bg-white text-default-700 border-default-700 hover:bg-default-50",
20
+ primary: "bg-white text-primary-600 border-primary-600 hover:bg-primary-50",
21
+ secondary: "bg-white text-secondary-600 border-secondary-600 hover:bg-secondary-50",
22
+ success: "bg-white text-success-600 border-success-600 hover:bg-success-50",
23
+ danger: "bg-white text-danger-600 border-danger-600 hover:bg-danger-50",
24
+ warning: "bg-white text-warning-600 border-warning-600 hover:bg-warning-50",
25
+ info: "bg-white text-info-600 border-info-600 hover:bg-info-50"
26
+ }
27
+ },
28
+ contained: {
29
+ root: "inline-flex border items-center justify-center px-2 py-1 rounded-md font-medium focus:outline-none focus:ring-2 focus:ring-offset-2",
30
+ colors: {
31
+ default: "border-default-700 bg-default-600 text-white hover:bg-default-700",
32
+ primary: "border-primary-700 bg-primary-600 text-white hover:bg-primary-700",
33
+ secondary: "border-secondary-700 bg-secondary-600 text-white hover:bg-secondary-700",
34
+ success: "border-success-700 bg-success-600 text-white hover:bg-success-700",
35
+ danger: "border-danger-700 bg-danger-600 text-white hover:bg-danger-700",
36
+ warning: "border-warning-700 bg-warning-600 text-white hover:bg-warning-700",
37
+ info: "border-info-700 bg-info-600 text-white hover:bg-info-700"
38
+ }
39
+ },
40
+ text: {
41
+ root: "text-base",
42
+ colors: {
43
+ default: "text-default-700 hover:underline",
44
+ primary: "text-primary-600 hover:underline",
45
+ secondary: "text-secondary-600 hover:underline",
46
+ success: "text-success-600 hover:underline",
47
+ danger: "text-danger-600 hover:underline",
48
+ warning: "text-warning-600 hover:underline",
49
+ info: "text-info-600 hover:underline"
50
+ }
51
+ }
52
+ }
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,23 @@
1
+ module OkonomiUiKit
2
+ module Components
3
+ class ButtonTag < OkonomiUiKit::Components::ButtonBase
4
+ def render(name = nil, options = {}, &block)
5
+ options, name = options, block if block_given?
6
+
7
+ options ||= {}
8
+ options = options.with_indifferent_access
9
+
10
+ variant = (options.delete(:variant) || "contained").to_sym
11
+ color = (options.delete(:color) || "default").to_sym
12
+
13
+ options[:class] = build_button_class(variant: variant, color: color, classes: options[:class])
14
+
15
+ if block_given?
16
+ view.button_tag(options, &block)
17
+ else
18
+ view.button_tag(name, options)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,14 +1,14 @@
1
1
  module OkonomiUiKit
2
2
  module Components
3
- class ButtonTo < OkonomiUiKit::Component
3
+ class ButtonTo < OkonomiUiKit::Components::ButtonBase
4
4
  def render(name = nil, options = nil, html_options = nil, &block)
5
5
  html_options, options, name = options, name, block if block_given?
6
6
 
7
7
  html_options ||= {}
8
8
  html_options = html_options.with_indifferent_access
9
9
 
10
- variant = (html_options.delete(:variant) || 'contained').to_sym
11
- color = (html_options.delete(:color) || 'default').to_sym
10
+ variant = (html_options.delete(:variant) || "contained").to_sym
11
+ color = (html_options.delete(:color) || "default").to_sym
12
12
 
13
13
  html_options[:class] = build_button_class(variant: variant, color: color, classes: html_options[:class])
14
14
 
@@ -18,17 +18,6 @@ module OkonomiUiKit
18
18
  view.button_to(name, options, html_options)
19
19
  end
20
20
  end
21
-
22
- private
23
-
24
- def build_button_class(variant:, color:, classes: '')
25
- [
26
- theme.dig(:components, :link, :root) || '',
27
- theme.dig(:components, :link, variant.to_sym, :root) || '',
28
- theme.dig(:components, :link, variant.to_sym, :colors, color.to_sym) || '',
29
- classes,
30
- ].reject(&:blank?).join(' ')
31
- end
32
21
  end
33
22
  end
34
- end
23
+ end
@@ -8,61 +8,65 @@ module OkonomiUiKit
8
8
 
9
9
  # Extract component-specific options
10
10
  language = options.delete(:language) || options.delete(:lang)
11
- variant = (options.delete(:variant) || 'default').to_sym
12
- size = (options.delete(:size) || 'default').to_sym
11
+ variant = (options.delete(:variant) || "default").to_sym
12
+ size = (options.delete(:size) || "default").to_sym
13
13
  wrap = options.delete(:wrap) != false # Default to true
14
14
 
15
15
  # Build classes
16
16
  classes = build_classes(variant: variant, size: size, wrap: wrap, custom_class: options.delete(:class))
17
17
 
18
18
  # Escape HTML entities in content
19
- escaped_content = if block_given?
20
- view.capture(&block)
21
- elsif content
22
- content
23
- else
24
- ""
25
- end
19
+ raw_content = if block_given?
20
+ view.capture(&block)
21
+ elsif content
22
+ content
23
+ else
24
+ ""
25
+ end
26
+
27
+ escaped_content = html_escape(raw_content)
26
28
 
27
29
  view.render(
28
30
  template_path,
29
- content: escaped_content.strip.html_safe,
31
+ content: escaped_content,
30
32
  options: options,
31
33
  classes: classes,
32
34
  language: language
33
35
  )
34
36
  end
35
37
 
38
+ register_styles :default do
39
+ {
40
+ base: "",
41
+ variants: {
42
+ default: "bg-gray-900 text-gray-100 p-4 rounded-lg",
43
+ inline: "bg-gray-100 text-gray-900 px-1 py-0.5 rounded text-sm font-mono",
44
+ minimal: "bg-gray-900 text-gray-100 p-3 rounded text-xs"
45
+ },
46
+ sizes: {
47
+ xs: "text-xs",
48
+ sm: "text-sm",
49
+ default: "text-sm",
50
+ lg: "text-base"
51
+ },
52
+ wrap: {
53
+ true: "overflow-x-auto",
54
+ false: "overflow-hidden"
55
+ }
56
+ }
57
+ end
58
+
36
59
  private
37
60
 
38
61
  def build_classes(variant:, size:, wrap:, custom_class: nil)
39
- base_classes = theme.dig(:components, :code, :base) || "bg-gray-900 text-gray-100 rounded-lg"
40
-
41
- variant_classes = case variant
42
- when :inline
43
- "bg-gray-100 text-gray-900 px-1 py-0.5 rounded text-sm font-mono"
44
- when :minimal
45
- "bg-gray-900 text-gray-100 p-3 rounded text-xs"
46
- else
47
- # :default
48
- "bg-gray-900 text-gray-100 p-4 rounded-lg"
49
- end
50
-
51
- size_classes = case size
52
- when :xs
53
- "text-xs"
54
- when :sm
55
- "text-sm"
56
- when :lg
57
- "text-base"
58
- else
59
- # :default
60
- "text-sm"
61
- end
62
-
63
- wrap_classes = wrap ? "overflow-x-auto" : "overflow-hidden"
62
+ base_classes = style(:base) || ""
63
+ variant_classes = style(:variants, variant) || ""
64
+ size_classes = style(:sizes, size) || ""
65
+ # Convert boolean wrap to symbol for hash access
66
+ wrap_key = wrap ? :true : :false
67
+ wrap_classes = style(:wrap, wrap_key) || ""
64
68
 
65
- [base_classes, variant_classes, size_classes, wrap_classes, custom_class].compact.join(' ')
69
+ [ base_classes, variant_classes, size_classes, wrap_classes, custom_class ].reject(&:blank?).join(" ")
66
70
  end
67
71
 
68
72
  def html_escape(content)
@@ -70,4 +74,4 @@ module OkonomiUiKit
70
74
  end
71
75
  end
72
76
  end
73
- end
77
+ end
@@ -0,0 +1,130 @@
1
+ module OkonomiUiKit
2
+ module Components
3
+ class ConfirmationModal < OkonomiUiKit::Component
4
+ def render(options = {}, &block)
5
+ options = options.with_indifferent_access
6
+
7
+ # Extract and validate required options
8
+ title = options.fetch(:title) { raise ArgumentError, "title is required" }
9
+ message = options.fetch(:message) { raise ArgumentError, "message is required" }
10
+
11
+ # Extract optional parameters with defaults
12
+ confirm_text = options.delete(:confirm_text) || "Confirm"
13
+ cancel_text = options.delete(:cancel_text) || "Cancel"
14
+ variant = (options.delete(:variant) || :warning).to_sym
15
+ size = (options.delete(:size) || :md).to_sym
16
+ auto_open = options.delete(:auto_open) || false
17
+
18
+ # Build component options
19
+ modal_options = {
20
+ title: title,
21
+ message: message,
22
+ confirm_text: confirm_text,
23
+ cancel_text: cancel_text,
24
+ variant: variant,
25
+ size: size,
26
+ auto_open: auto_open,
27
+ has_custom_actions: block_given?,
28
+ data: options.delete(:data) || {}
29
+ }.merge(options)
30
+
31
+ view.render(template_path, component: self, options: modal_options, &block)
32
+ end
33
+
34
+ # Register default styles for the confirmation modal
35
+ register_styles :default do
36
+ {
37
+ # Modal container and backdrop
38
+ backdrop: "fixed inset-0 bg-gray-500/75 transition-opacity duration-300 ease-out opacity-0",
39
+ container: "fixed inset-0 z-10 w-screen overflow-y-auto",
40
+ wrapper: "flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0",
41
+
42
+ # Modal panel
43
+ panel: {
44
+ base: "relative transform overflow-hidden rounded-lg bg-white px-4 pt-5 pb-4 text-left shadow-xl transition-all duration-300 ease-out sm:my-8 sm:w-full sm:p-6 opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95",
45
+ sizes: {
46
+ sm: "sm:max-w-sm",
47
+ md: "sm:max-w-lg",
48
+ lg: "sm:max-w-2xl",
49
+ xl: "sm:max-w-4xl"
50
+ }
51
+ },
52
+
53
+ # Close button
54
+ close_button: {
55
+ wrapper: "absolute top-0 right-0 hidden pt-4 pr-4 sm:block",
56
+ button: "rounded-md bg-white text-gray-400 hover:text-gray-500 focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:outline-none",
57
+ icon: {
58
+ file: "heroicons/outline/x-mark",
59
+ class: "size-6"
60
+ }
61
+ },
62
+
63
+ # Icon configuration
64
+ icon: {
65
+ wrapper: "mx-auto flex size-12 shrink-0 items-center justify-center rounded-full sm:mx-0 sm:size-10",
66
+ class: "size-6",
67
+ variants: {
68
+ warning: {
69
+ wrapper: "bg-red-100",
70
+ icon: "text-red-600",
71
+ file: "heroicons/outline/exclamation-triangle"
72
+ },
73
+ info: {
74
+ wrapper: "bg-blue-100",
75
+ icon: "text-blue-600",
76
+ file: "heroicons/outline/information-circle"
77
+ },
78
+ success: {
79
+ wrapper: "bg-green-100",
80
+ icon: "text-green-600",
81
+ file: "heroicons/outline/check-circle"
82
+ }
83
+ }
84
+ },
85
+
86
+ # Content styling
87
+ content: {
88
+ wrapper: "sm:flex sm:items-start",
89
+ text_wrapper: "mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left",
90
+ title: "text-base font-semibold text-gray-900",
91
+ message: "mt-2 text-sm text-gray-500"
92
+ },
93
+
94
+ # Actions container
95
+ actions: {
96
+ wrapper: "mt-5 sm:mt-4 sm:flex sm:flex-row-reverse"
97
+ }
98
+ }
99
+ end
100
+
101
+ # Helper methods to build classes from styles
102
+ def modal_panel_class(size)
103
+ [
104
+ style(:panel, :base),
105
+ style(:panel, :sizes, size)
106
+ ].compact.join(" ")
107
+ end
108
+
109
+ def modal_icon_wrapper_class(variant)
110
+ [
111
+ style(:icon, :wrapper),
112
+ style(:icon, :variants, variant, :wrapper)
113
+ ].compact.join(" ")
114
+ end
115
+
116
+ def modal_icon_class(variant)
117
+ [
118
+ style(:icon, :class),
119
+ style(:icon, :variants, variant, :icon)
120
+ ].compact.join(" ")
121
+ end
122
+
123
+ def modal_data_attributes(options)
124
+ return "" unless options[:data]
125
+
126
+ options[:data].map { |k, v| "data-#{k.to_s.dasherize}=\"#{v}\"" }.join(" ").html_safe
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,38 @@
1
+ module OkonomiUiKit
2
+ module Components
3
+ module Forms
4
+ class CheckBoxWithLabel < OkonomiUiKit::FormComponent
5
+ def render(form, method, options = {}, checked_value = true, unchecked_value = false)
6
+ options = options.with_indifferent_access
7
+
8
+ view.content_tag(:div, class: style(:wrapper)) do
9
+ view.concat form.check_box(
10
+ method,
11
+ {
12
+ class: style(:input, :root)
13
+ }.merge(options || {}),
14
+ checked_value,
15
+ unchecked_value
16
+ )
17
+ view.concat view.render(template_path, component: self, method: method, options: options, form: form)
18
+ end
19
+ end
20
+
21
+ register_styles :default do
22
+ {
23
+ wrapper: "flex gap-x-3",
24
+ input: {
25
+ root: "size-4 rounded border-gray-300 text-primary-600 focus:ring-primary-600"
26
+ },
27
+ label: {
28
+ root: "text-sm/6 font-medium text-gray-900"
29
+ },
30
+ hint: {
31
+ root: "text-gray-500"
32
+ }
33
+ }
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end