uchi 0.1.5 → 0.1.6

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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/uchi/application.js +2655 -24
  3. data/app/assets/javascripts/uchi.js +11 -0
  4. data/app/assets/stylesheets/uchi/application.css +982 -1311
  5. data/app/assets/tailwind/uchi.css +4 -4
  6. data/app/components/uchi/field/belongs_to/edit.html.erb +1 -1
  7. data/app/components/uchi/field/belongs_to/index.html.erb +1 -1
  8. data/app/components/uchi/field/belongs_to/show.html.erb +3 -5
  9. data/app/components/uchi/field/belongs_to.rb +30 -7
  10. data/app/components/uchi/field/boolean/edit.html.erb +1 -1
  11. data/app/components/uchi/field/date/edit.html.erb +1 -1
  12. data/app/components/uchi/field/date_time/edit.html.erb +1 -1
  13. data/app/components/uchi/field/file/edit.html.erb +1 -1
  14. data/app/components/uchi/field/file/index.html.erb +2 -1
  15. data/app/components/uchi/field/file/show.html.erb +3 -2
  16. data/app/components/uchi/field/has_and_belongs_to_many/show.html.erb +5 -3
  17. data/app/components/uchi/field/has_many/show.html.erb +5 -3
  18. data/app/components/uchi/field/id/index.html.erb +1 -1
  19. data/app/components/uchi/field/id/show.html.erb +1 -1
  20. data/app/components/uchi/field/image/edit.html.erb +1 -1
  21. data/app/components/uchi/field/image/index.html.erb +2 -1
  22. data/app/components/uchi/field/image/show.html.erb +2 -1
  23. data/app/components/uchi/field/number/edit.html.erb +1 -1
  24. data/app/components/uchi/field/string/edit.html.erb +1 -1
  25. data/app/components/uchi/field/text/edit.html.erb +1 -1
  26. data/app/components/{flowbite → uchi/flowbite}/breadcrumb.rb +5 -5
  27. data/app/components/{flowbite → uchi/flowbite}/breadcrumb_home.rb +2 -2
  28. data/app/components/{flowbite → uchi/flowbite}/breadcrumb_item/current.rb +3 -3
  29. data/app/components/{flowbite → uchi/flowbite}/breadcrumb_item/first.rb +4 -4
  30. data/app/components/{flowbite → uchi/flowbite}/breadcrumb_item.rb +4 -4
  31. data/app/components/{flowbite → uchi/flowbite}/breadcrumb_separator.rb +7 -5
  32. data/app/components/uchi/flowbite/button/outline.rb +37 -0
  33. data/app/components/uchi/flowbite/button/pill.rb +40 -0
  34. data/app/components/uchi/flowbite/button.rb +93 -0
  35. data/app/components/uchi/flowbite/card/card.html.erb +7 -0
  36. data/app/components/uchi/flowbite/card/title.rb +37 -0
  37. data/app/components/uchi/flowbite/card.rb +84 -0
  38. data/app/components/{flowbite → uchi/flowbite}/input/checkbox.rb +7 -7
  39. data/app/components/{flowbite → uchi/flowbite}/input/date.rb +1 -1
  40. data/app/components/{flowbite → uchi/flowbite}/input/date_time.rb +1 -1
  41. data/app/components/{flowbite → uchi/flowbite}/input/email.rb +1 -1
  42. data/app/components/{flowbite → uchi/flowbite}/input/field.rb +11 -10
  43. data/app/components/uchi/flowbite/input/file.rb +30 -0
  44. data/app/components/{flowbite → uchi/flowbite}/input/hint.rb +6 -5
  45. data/app/components/{flowbite → uchi/flowbite}/input/label.rb +8 -7
  46. data/app/components/{flowbite → uchi/flowbite}/input/number.rb +1 -1
  47. data/app/components/{flowbite → uchi/flowbite}/input/password.rb +1 -1
  48. data/app/components/{flowbite → uchi/flowbite}/input/phone.rb +1 -1
  49. data/app/components/{flowbite → uchi/flowbite}/input/radio_button.rb +7 -7
  50. data/app/components/{flowbite → uchi/flowbite}/input/select.rb +16 -7
  51. data/app/components/uchi/flowbite/input/textarea.rb +42 -0
  52. data/app/components/{flowbite → uchi/flowbite}/input/url.rb +1 -1
  53. data/app/components/uchi/flowbite/input/validation_error.rb +39 -0
  54. data/app/components/uchi/flowbite/input_field/checkbox.html.erb +9 -0
  55. data/app/components/{flowbite → uchi/flowbite}/input_field/checkbox.rb +10 -6
  56. data/app/components/{flowbite → uchi/flowbite}/input_field/date.rb +2 -2
  57. data/app/components/{flowbite → uchi/flowbite}/input_field/date_time.rb +2 -2
  58. data/app/components/{flowbite → uchi/flowbite}/input_field/email.rb +2 -2
  59. data/app/components/{flowbite → uchi/flowbite}/input_field/file.rb +2 -2
  60. data/app/components/uchi/flowbite/input_field/input_field.html.erb +9 -0
  61. data/app/components/{flowbite → uchi/flowbite}/input_field/number.rb +2 -2
  62. data/app/components/{flowbite → uchi/flowbite}/input_field/password.rb +2 -2
  63. data/app/components/{flowbite → uchi/flowbite}/input_field/phone.rb +2 -2
  64. data/app/components/uchi/flowbite/input_field/radio_button.html.erb +9 -0
  65. data/app/components/{flowbite → uchi/flowbite}/input_field/radio_button.rb +13 -9
  66. data/app/components/{flowbite → uchi/flowbite}/input_field/select.rb +7 -3
  67. data/app/components/{flowbite → uchi/flowbite}/input_field/text.rb +1 -1
  68. data/app/components/{flowbite → uchi/flowbite}/input_field/textarea.rb +2 -2
  69. data/app/components/{flowbite → uchi/flowbite}/input_field/url.rb +2 -2
  70. data/app/components/{flowbite → uchi/flowbite}/input_field.rb +19 -5
  71. data/app/components/uchi/flowbite/link.rb +41 -0
  72. data/app/components/{flowbite → uchi/flowbite}/style.rb +1 -1
  73. data/app/components/{flowbite → uchi/flowbite}/toast/icon.rb +1 -1
  74. data/app/components/uchi/flowbite/toast/toast.html.erb +40 -0
  75. data/app/components/{flowbite → uchi/flowbite}/toast.rb +2 -2
  76. data/app/components/uchi/ui/actions/dropdown/dropdown.html.erb +59 -0
  77. data/app/components/uchi/ui/actions/dropdown.rb +32 -0
  78. data/app/components/uchi/ui/breadcrumb/breadcrumb.html.erb +4 -4
  79. data/app/components/uchi/ui/form/input/collection_checkboxes.html.erb +2 -1
  80. data/app/components/uchi/ui/form/input/collection_checkboxes.rb +12 -17
  81. data/app/components/uchi/ui/frame/frame.html.erb +6 -1
  82. data/app/components/uchi/ui/index/records_table/records_table.html.erb +109 -18
  83. data/app/components/uchi/ui/index/records_table/search_form/search_form.html.erb +21 -5
  84. data/app/components/uchi/ui/navigation/navigation.html.erb +9 -0
  85. data/app/components/uchi/ui/navigation.rb +37 -0
  86. data/app/components/uchi/ui/no_value/no_value.html.erb +1 -0
  87. data/app/components/uchi/ui/no_value.rb +8 -0
  88. data/app/components/uchi/ui/page_header/page_header.html.erb +7 -2
  89. data/app/components/uchi/ui/pagination/current_link.html.erb +1 -1
  90. data/app/components/uchi/ui/pagination/gap.html.erb +7 -1
  91. data/app/components/uchi/ui/pagination/link.html.erb +1 -1
  92. data/app/components/uchi/ui/pagination/next_link.html.erb +18 -3
  93. data/app/components/uchi/ui/pagination/pagination.html.erb +3 -1
  94. data/app/components/uchi/ui/pagination/previous_link.html.erb +18 -3
  95. data/app/components/uchi/ui/pagination.rb +1 -1
  96. data/app/components/uchi/ui/show/attribute_fields/attribute_fields.html.erb +4 -3
  97. data/app/components/uchi/ui/spinner/spinner.html.erb +17 -3
  98. data/app/controllers/uchi/actions/executions_controller.rb +107 -0
  99. data/app/controllers/uchi/repository_controller.rb +21 -1
  100. data/app/views/layouts/uchi/_flash_messages.html.erb +1 -1
  101. data/app/views/layouts/uchi/application.html.erb +10 -16
  102. data/app/views/uchi/navigation/_main.html.erb +9 -0
  103. data/app/views/uchi/repository/edit.html.erb +2 -2
  104. data/app/views/uchi/repository/index.html.erb +12 -3
  105. data/app/views/uchi/repository/new.html.erb +2 -2
  106. data/app/views/uchi/repository/show.html.erb +13 -2
  107. data/lib/generators/uchi/controller/templates/controller.rb.tt +0 -5
  108. data/lib/generators/uchi/scaffold/scaffold_generator.rb +15 -0
  109. data/lib/uchi/action.rb +84 -0
  110. data/lib/uchi/action_response.rb +108 -0
  111. data/lib/uchi/repository/translate.rb +14 -0
  112. data/lib/uchi/repository.rb +25 -0
  113. data/lib/uchi/version.rb +1 -1
  114. data/lib/uchi.rb +2 -0
  115. metadata +63 -50
  116. data/app/components/flowbite/button/outline.rb +0 -22
  117. data/app/components/flowbite/button/pill.rb +0 -40
  118. data/app/components/flowbite/button.rb +0 -92
  119. data/app/components/flowbite/card.rb +0 -45
  120. data/app/components/flowbite/input/file.rb +0 -30
  121. data/app/components/flowbite/input/textarea.rb +0 -42
  122. data/app/components/flowbite/input/validation_error.rb +0 -11
  123. data/app/components/flowbite/input_field/checkbox.html.erb +0 -14
  124. data/app/components/flowbite/input_field/input_field.html.erb +0 -8
  125. data/app/components/flowbite/input_field/radio_button.html.erb +0 -14
  126. data/app/components/flowbite/link.rb +0 -21
  127. data/app/components/flowbite/toast/toast.html.erb +0 -11
  128. /data/app/components/{flowbite → uchi/flowbite}/toast/icon.html.erb +0 -0
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Uchi::Flowbite
4
+ # Renders a card element.
5
+ #
6
+ # See https://flowbite.com/docs/components/cards/
7
+ class Card < ViewComponent::Base
8
+ renders_one :title
9
+
10
+ class << self
11
+ def classes(state: :default, style: :default)
12
+ style = styles.fetch(style)
13
+ style.fetch(state)
14
+ end
15
+
16
+ # rubocop:disable Layout/LineLength
17
+ def styles
18
+ {
19
+ default: Uchi::Flowbite::Style.new(
20
+ default: ["p-6", "bg-neutral-primary-soft", "border", "border-default", "rounded-base", "shadow-xs"]
21
+ )
22
+ }.freeze
23
+ end
24
+ # rubocop:enable Layout/LineLength
25
+ end
26
+
27
+ # @param class [Array<String>] Additional CSS classes for the card
28
+ # container.
29
+ #
30
+ # @param options [Hash] Additional HTML options for the card container
31
+ # (e.g., custom classes, data attributes). These options are merged into
32
+ # the card's root element.
33
+ #
34
+ # @param title [Hash] An optional title for the card. If provided,
35
+ # it will be rendered at the top of the card in a h5 tag using the
36
+ # Card::Title component. The hash can contain:
37
+ # - `content`: The text content of the title
38
+ # - `options`: Additional HTML options to pass to the title element
39
+ # Alternatively, you can use the `title` slot to provide the entire
40
+ # title element yourself.
41
+ def initialize(class: [], options: {}, title: {})
42
+ @class = Array(binding.local_variable_get(:class)) || []
43
+ @options = options || {}
44
+ @title = title
45
+ end
46
+
47
+ protected
48
+
49
+ def card_options
50
+ card_options = {}
51
+ card_options[:class] = self.class.classes + @class
52
+ card_options.merge(@options)
53
+ end
54
+
55
+ # Returns the HTML to use for the title element if any
56
+ def default_title
57
+ component = Uchi::Flowbite::Card::Title.new(**default_title_options)
58
+
59
+ if default_title_content
60
+ component.with_content(default_title_content)
61
+ else
62
+ component
63
+ end
64
+
65
+ render(component)
66
+ end
67
+
68
+ def default_title_content
69
+ return nil unless @title
70
+
71
+ @title[:content]
72
+ end
73
+
74
+ # @return [Hash] The options to pass to the default title component
75
+ def default_title_options
76
+ title_options = @title.dup
77
+ title_options[:options] || {}
78
+ end
79
+
80
+ def title?
81
+ @title.present?
82
+ end
83
+ end
84
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  module Input
5
5
  # The checkbox component can be used to receive one or more selected options
6
6
  # from the user in the form of a square box available in multiple styles,
@@ -23,10 +23,10 @@ module Flowbite
23
23
  # rubocop:disable Layout/LineLength
24
24
  def styles
25
25
  {
26
- default: Flowbite::Style.new(
27
- default: ["text-blue-600", "bg-gray-100", "border-gray-300", "rounded-sm", "focus:ring-blue-500", "dark:focus:ring-blue-600", "dark:ring-offset-gray-800", "focus:ring-2", "dark:bg-gray-700", "dark:border-gray-600"],
28
- disabled: ["text-blue-600", "bg-gray-100", "border-gray-300", "rounded-sm", "focus:ring-blue-500", "dark:focus:ring-blue-600", "dark:ring-offset-gray-800", "focus:ring-2", "dark:bg-gray-700", "dark:border-gray-600"],
29
- error: ["text-red-600", "bg-red-50", "border-red-500", "rounded-sm", "focus:ring-red-500", "dark:focus:ring-red-600", "dark:ring-offset-gray-800", "focus:ring-2", "dark:bg-gray-700", "dark:border-red-500"]
26
+ default: Uchi::Flowbite::Style.new(
27
+ default: ["text-brand", "bg-neutral-secondary-medium", "border-default-medium", "rounded-sm", "focus:ring-brand", "focus:ring-2"],
28
+ disabled: ["text-brand", "bg-neutral-secondary-medium", "border-default-medium", "rounded-sm", "focus:ring-brand", "focus:ring-2", "cursor-not-allowed"],
29
+ error: ["text-danger", "bg-danger-soft", "border-danger-subtle", "rounded-sm", "focus:ring-danger", "focus:ring-2"]
30
30
  )
31
31
  }.freeze
32
32
  end
@@ -43,8 +43,8 @@ module Flowbite
43
43
  )
44
44
  end
45
45
 
46
- def initialize(attribute:, form:, disabled: false, options: {}, size: :default, unchecked_value: DEFAULT_UNCHECKED_VALUE, value: DEFAULT_CHECKED_VALUE)
47
- super(attribute: attribute, form: form, disabled: disabled, options: options, size: size)
46
+ def initialize(attribute:, form:, class: nil, disabled: false, options: {}, size: :default, unchecked_value: DEFAULT_UNCHECKED_VALUE, value: DEFAULT_CHECKED_VALUE)
47
+ super(attribute: attribute, class: binding.local_variable_get(:class), form: form, disabled: disabled, options: options, size: size)
48
48
  @unchecked_value = unchecked_value
49
49
  @value = value
50
50
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  module Input
5
5
  class Date < Field
6
6
  def input_field_type
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  module Input
5
5
  class DateTime < Field
6
6
  def input_field_type
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  module Input
5
5
  class Email < Field
6
6
  # Returns the name of the method used to generate HTML for the input field
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  module Input
5
5
  # The indivdual input component for use in forms without labels or error
6
6
  # messages.
@@ -13,9 +13,9 @@ module Flowbite
13
13
  # `Flowbite::InputField` instead.
14
14
  class Field < ViewComponent::Base
15
15
  SIZES = {
16
- sm: ["p-2", "text-xs"],
17
- default: ["p-2.5", "text-sm"],
18
- lg: ["p-4", "text-base"]
16
+ sm: ["px-2.5", "py-2", "text-sm"],
17
+ default: ["px-3", "py-2.5", "text-sm"],
18
+ lg: ["px-3.5", "py-3", "text-base"]
19
19
  }.freeze
20
20
 
21
21
  STATES = [
@@ -47,18 +47,19 @@ module Flowbite
47
47
  # rubocop:disable Layout/LineLength
48
48
  def styles
49
49
  {
50
- default: Flowbite::Style.new(
51
- default: ["bg-gray-50", "border", "border-gray-300", "text-gray-900", "rounded-lg", "focus:ring-blue-500", "focus:border-blue-500", "block", "w-full", "dark:bg-gray-700", "dark:border-gray-600", "dark:placeholder-gray-400", "dark:text-white", "dark:focus:ring-blue-500", "dark:focus:border-blue-500"],
52
- disabled: ["bg-gray-100", "border", "border-gray-300", "text-gray-900", "text-sm", "rounded-lg", "focus:ring-blue-500", "focus:border-blue-500", "block", "w-full", "p-2.5", "cursor-not-allowed", "dark:bg-gray-700", "dark:border-gray-600", "dark:placeholder-gray-400", "dark:text-gray-400", "dark:focus:ring-blue-500", "dark:focus:border-blue-500"],
53
- error: ["bg-red-50", "border", "border-red-500", "text-red-900", "placeholder-red-700", "rounded-lg", "focus:ring-red-500", "dark:bg-gray-700", "focus:border-red-500", "block", "w-full", "dark:text-red-500", "dark:placeholder-red-500", "dark:border-red-500"]
50
+ default: Uchi::Flowbite::Style.new(
51
+ default: ["bg-neutral-secondary-medium", "border", "border-default-medium", "text-heading", "rounded-base", "focus:ring-brand", "focus:border-brand", "block", "w-full", "shadow-xs", "placeholder:text-body"],
52
+ disabled: ["bg-neutral-secondary-medium", "border", "border-default-medium", "text-fg-disabled", "rounded-base", "focus:ring-brand", "focus:border-brand", "block", "w-full", "shadow-xs", "cursor-not-allowed", "placeholder:text-fg-disabled"],
53
+ error: ["bg-danger-soft", "border", "border-danger-subtle", "text-fg-danger-strong", "rounded-base", "focus:ring-danger", "focus:border-danger", "block", "w-full", "shadow-xs", "placeholder:text-fg-danger-strong"]
54
54
  )
55
55
  }.freeze
56
56
  end
57
57
  # rubocop:enable Layout/LineLength
58
58
  end
59
59
 
60
- def initialize(attribute:, form:, disabled: false, options: {}, size: :default)
60
+ def initialize(attribute:, form:, class: nil, disabled: false, options: {}, size: :default)
61
61
  @attribute = attribute
62
+ @class = Array.wrap(binding.local_variable_get(:class))
62
63
  @disabled = disabled
63
64
  @form = form
64
65
  @options = options || {}
@@ -77,7 +78,7 @@ module Flowbite
77
78
 
78
79
  # Returns the CSS classes to apply to the input field
79
80
  def classes
80
- self.class.classes(size: size, state: state)
81
+ self.class.classes(size: size, state: state) + @class
81
82
  end
82
83
 
83
84
  # Returns the name of the method used to generate HTML for the input field
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Uchi::Flowbite
4
+ module Input
5
+ class File < Field
6
+ SIZES = {
7
+ sm: ["text-sm"],
8
+ default: ["text-sm"],
9
+ lg: ["text-base"]
10
+ }.freeze
11
+
12
+ # Returns the name of the method used to generate HTML for the input field
13
+ def input_field_type
14
+ :file_field
15
+ end
16
+
17
+ # rubocop:disable Layout/LineLength
18
+ def self.styles
19
+ {
20
+ default: Uchi::Flowbite::Style.new(
21
+ default: ["block", "w-full", "text-heading", "border", "border-default-medium", "rounded-base", "cursor-pointer", "bg-neutral-secondary-medium", "focus:outline-none"],
22
+ disabled: ["block", "w-full", "text-fg-disabled", "border", "border-default-medium", "rounded-base", "cursor-not-allowed", "bg-neutral-secondary-medium"],
23
+ error: ["block", "w-full", "text-fg-danger-strong", "border", "border-danger-subtle", "rounded-base", "cursor-pointer", "bg-danger-soft", "focus:outline-none"]
24
+ )
25
+ }.freeze
26
+ end
27
+ # rubocop:enable Layout/LineLength
28
+ end
29
+ end
30
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  module Input
5
5
  class Hint < ViewComponent::Base
6
6
  STATES = [
@@ -15,8 +15,8 @@ module Flowbite
15
15
 
16
16
  def styles
17
17
  {
18
- default: Flowbite::Style.new(
19
- default: ["mt-2", "text-sm", "text-gray-500", "dark:text-gray-400"]
18
+ default: Uchi::Flowbite::Style.new(
19
+ default: ["mt-2.5", "text-sm", "text-body"]
20
20
  )
21
21
  }.freeze
22
22
  end
@@ -30,8 +30,9 @@ module Flowbite
30
30
  )
31
31
  end
32
32
 
33
- def initialize(attribute:, form:, options: {})
33
+ def initialize(attribute:, form:, class: nil, options: {})
34
34
  @attribute = attribute
35
+ @class = Array.wrap(binding.local_variable_get(:class))
35
36
  @form = form
36
37
  @options = options
37
38
  @object = form.object
@@ -39,7 +40,7 @@ module Flowbite
39
40
 
40
41
  # Returns an array with the CSS classes to apply to the label element
41
42
  def classes
42
- self.class.classes(state: state)
43
+ self.class.classes(state: state) + @class
43
44
  end
44
45
 
45
46
  protected
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  module Input
5
5
  # https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-label
6
6
  class Label < ViewComponent::Base
@@ -18,10 +18,10 @@ module Flowbite
18
18
 
19
19
  def styles
20
20
  {
21
- default: Flowbite::Style.new(
22
- default: ["block", "mb-2", "text-sm", "font-medium", "text-gray-900", "dark:text-white"],
23
- disabled: ["block", "mb-2", "text-sm", "font-medium", "text-gray-400", "dark:text-gray-500"],
24
- error: ["block", "mb-2", "text-sm", "font-medium", "text-red-700", "dark:text-red-500"]
21
+ default: Uchi::Flowbite::Style.new(
22
+ default: ["block", "mb-2.5", "text-sm", "font-medium", "text-heading"],
23
+ disabled: ["block", "mb-2.5", "text-sm", "font-medium", "text-fg-disabled"],
24
+ error: ["block", "mb-2.5", "text-sm", "font-medium", "text-fg-danger-strong"]
25
25
  )
26
26
  }.freeze
27
27
  end
@@ -39,8 +39,9 @@ module Flowbite
39
39
  @object.errors.include?(@attribute.intern)
40
40
  end
41
41
 
42
- def initialize(attribute:, form:, disabled: false, options: {})
42
+ def initialize(attribute:, form:, class: nil, disabled: false, options: {})
43
43
  @attribute = attribute
44
+ @class = Array.wrap(binding.local_variable_get(:class))
44
45
  @disabled = disabled
45
46
  @form = form
46
47
  @object = form.object
@@ -49,7 +50,7 @@ module Flowbite
49
50
 
50
51
  # Returns an array with the CSS classes to apply to the label element
51
52
  def classes
52
- self.class.classes(state: state)
53
+ self.class.classes(state: state) + @class
53
54
  end
54
55
 
55
56
  protected
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  module Input
5
5
  class Number < Field
6
6
  def input_field_type
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  module Input
5
5
  class Password < Field
6
6
  def input_field_type
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  module Input
5
5
  class Phone < Field
6
6
  def input_field_type
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  module Input
5
5
  # The radio button component can be used to allow the user to choose a
6
6
  # single option from one or more available options.
@@ -18,10 +18,10 @@ module Flowbite
18
18
  # rubocop:disable Layout/LineLength
19
19
  def styles
20
20
  {
21
- default: Flowbite::Style.new(
22
- default: ["text-blue-600", "bg-gray-100", "border-gray-300", "focus:ring-blue-500", "dark:focus:ring-blue-600", "dark:ring-offset-gray-800", "focus:ring-2", "dark:bg-gray-700", "dark:border-gray-600"],
23
- disabled: ["text-blue-600", "bg-gray-100", "border-gray-300", "focus:ring-blue-500", "dark:focus:ring-blue-600", "dark:ring-offset-gray-800", "focus:ring-2", "dark:bg-gray-700", "dark:border-gray-600"],
24
- error: ["text-red-600", "bg-red-50", "border-red-500", "focus:ring-red-500", "dark:focus:ring-red-600", "dark:ring-offset-gray-800", "focus:ring-2", "dark:bg-gray-700", "dark:border-red-500"]
21
+ default: Uchi::Flowbite::Style.new(
22
+ default: ["text-brand", "bg-neutral-secondary-medium", "border-default-medium", "focus:ring-brand", "focus:ring-2"],
23
+ disabled: ["text-brand", "bg-neutral-secondary-medium", "border-default-medium", "focus:ring-brand", "focus:ring-2", "cursor-not-allowed"],
24
+ error: ["text-danger", "bg-danger-soft", "border-danger-subtle", "focus:ring-danger", "focus:ring-2"]
25
25
  )
26
26
  }.freeze
27
27
  end
@@ -37,8 +37,8 @@ module Flowbite
37
37
  )
38
38
  end
39
39
 
40
- def initialize(attribute:, form:, value:, disabled: false, options: {})
41
- super(attribute: attribute, disabled: disabled, form: form, options: options)
40
+ def initialize(attribute:, form:, value:, class: nil, disabled: false, options: {})
41
+ super(attribute: attribute, class: binding.local_variable_get(:class), disabled: disabled, form: form, options: options)
42
42
  @value = value
43
43
  end
44
44
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  module Input
5
5
  # The `Select` component renders a select input field for use in forms.
6
6
  #
@@ -9,14 +9,16 @@ module Flowbite
9
9
  # Wraps `ActionView::Helpers::FormOptionsHelper#select`: https://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-select
10
10
  class Select < Field
11
11
  SIZES = {
12
- sm: ["p-2", "text-xs"],
13
- default: ["p-2.5", "text-sm"],
14
- lg: ["px-4", "py-3", "text-base"]
12
+ sm: ["px-2.5", "py-2", "text-sm"],
13
+ default: ["px-3", "py-2.5", "text-sm"],
14
+ lg: ["px-3.5", "py-3", "text-base"]
15
15
  }.freeze
16
16
 
17
- def initialize(form:, attribute:, collection: [], disabled: false, options: {}, size: :default)
18
- super(form: form, attribute: attribute, disabled: disabled, options: options, size: size)
17
+ def initialize(form:, attribute:, class: nil, collection: [], disabled: false, include_blank: false, multiple: false, options: {}, size: :default)
18
+ super(form: form, attribute: attribute, class: binding.local_variable_get(:class), disabled: disabled, options: options, size: size)
19
19
  @collection = collection
20
+ @include_blank = include_blank
21
+ @multiple = multiple
20
22
  end
21
23
 
22
24
  # Returns the HTML to use for the actual input field element.
@@ -25,7 +27,7 @@ module Flowbite
25
27
  input_field_type,
26
28
  @attribute,
27
29
  @collection,
28
- {},
30
+ select_options,
29
31
  html_options
30
32
  )
31
33
  end
@@ -37,6 +39,13 @@ module Flowbite
37
39
 
38
40
  private
39
41
 
42
+ def select_options
43
+ {
44
+ include_blank: @include_blank,
45
+ multiple: @multiple
46
+ }
47
+ end
48
+
40
49
  # Returns the html_options argument for the select method
41
50
  def html_options
42
51
  {
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Uchi::Flowbite
4
+ module Input
5
+ class Textarea < Field
6
+ class << self
7
+ # rubocop:disable Layout/LineLength
8
+ def styles
9
+ {
10
+ default: Uchi::Flowbite::Style.new(
11
+ default: ["block", "w-full", "text-heading", "bg-neutral-secondary-medium", "rounded-base", "border", "border-default-medium", "focus:ring-brand", "focus:border-brand", "shadow-xs", "placeholder:text-body"],
12
+ disabled: ["block", "w-full", "bg-neutral-secondary-medium", "rounded-base", "border", "border-default-medium", "text-fg-disabled", "cursor-not-allowed", "shadow-xs", "placeholder:text-fg-disabled"],
13
+ error: ["block", "w-full", "bg-danger-soft", "border", "border-danger-subtle", "text-fg-danger-strong", "placeholder:text-fg-danger-strong", "rounded-base", "focus:ring-danger", "focus:border-danger", "shadow-xs"]
14
+ )
15
+ }.freeze
16
+ end
17
+ # rubocop:enable Layout/LineLength
18
+ end
19
+
20
+ # Returns the HTML to use for the actual input field element.
21
+ def call
22
+ @form.send(
23
+ input_field_type,
24
+ @attribute,
25
+ **input_options
26
+ )
27
+ end
28
+
29
+ protected
30
+
31
+ # Returns the CSS classes to apply to the input field
32
+ def classes
33
+ self.class.classes(size: size, state: state) + @class
34
+ end
35
+
36
+ # Returns the name of the method used to generate HTML for the input field
37
+ def input_field_type
38
+ :text_area
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  module Input
5
5
  class Url < Field
6
6
  # Returns the name of the method used to generate HTML for the input field
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Uchi::Flowbite
4
+ module Input
5
+ class ValidationError < ViewComponent::Base
6
+ class << self
7
+ def classes(state: :default, style: :default)
8
+ style = styles.fetch(style)
9
+ style.fetch(state)
10
+ end
11
+
12
+ # rubocop:disable Layout/LineLength
13
+ def styles
14
+ {
15
+ default: Uchi::Flowbite::Style.new(
16
+ default: ["mt-2", "text-sm", "text-red-600", "dark:text-red-500"]
17
+ )
18
+ }.freeze
19
+ end
20
+ # rubocop:enable Layout/LineLength
21
+ end
22
+
23
+ def call
24
+ tag.p(content, class: classes)
25
+ end
26
+
27
+ def initialize(class: nil)
28
+ @class = Array.wrap(binding.local_variable_get(:class))
29
+ end
30
+
31
+ protected
32
+
33
+ # Returns the CSS classes to apply to the validation error
34
+ def classes
35
+ self.class.classes + @class
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,9 @@
1
+ <div class="<%= classes.join(" ") %>">
2
+ <div class="flex items-center h-5"><%= input %></div>
3
+
4
+ <div class="ms-2 text-sm"><%= label %><%= hint %></div>
5
+
6
+ <% errors.each do |error| %>
7
+ <%= render(Uchi::Flowbite::Input::ValidationError.new) { error.upcase_first } %>
8
+ <% end %>
9
+ </div>
@@ -1,10 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  class InputField
5
5
  class Checkbox < InputField
6
6
  protected
7
7
 
8
+ def default_container_classes
9
+ ["flex"]
10
+ end
11
+
8
12
  def default_hint_options
9
13
  return {} unless @hint
10
14
 
@@ -22,16 +26,16 @@ module Flowbite
22
26
  end
23
27
 
24
28
  def input_component
25
- ::Flowbite::Input::Checkbox
29
+ Uchi::Flowbite::Input::Checkbox
26
30
  end
27
31
 
28
32
  private
29
33
 
30
34
  def hint_classes
31
35
  if disabled?
32
- "text-xs font-normal text-gray-400 dark:text-gray-500"
36
+ "text-xs font-normal text-fg-disabled"
33
37
  else
34
- "text-xs font-normal text-gray-500 dark:text-gray-300"
38
+ "text-xs font-normal text-body"
35
39
  end
36
40
  end
37
41
 
@@ -44,9 +48,9 @@ module Flowbite
44
48
 
45
49
  def label_classes
46
50
  if disabled?
47
- "font-medium text-gray-400 dark:text-gray-500"
51
+ "font-medium text-fg-disabled"
48
52
  else
49
- "font-medium text-gray-900 dark:text-gray-300"
53
+ "font-medium text-heading"
50
54
  end
51
55
  end
52
56
  end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  class InputField
5
5
  class Date < InputField
6
6
  protected
7
7
 
8
8
  def input_component
9
- ::Flowbite::Input::Date
9
+ Uchi::Flowbite::Input::Date
10
10
  end
11
11
  end
12
12
  end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  class InputField
5
5
  class DateTime < InputField
6
6
  protected
7
7
 
8
8
  def input_component
9
- ::Flowbite::Input::DateTime
9
+ Uchi::Flowbite::Input::DateTime
10
10
  end
11
11
  end
12
12
  end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  class InputField
5
5
  class Email < InputField
6
6
  protected
7
7
 
8
8
  def input_component
9
- ::Flowbite::Input::Email
9
+ Uchi::Flowbite::Input::Email
10
10
  end
11
11
  end
12
12
  end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  class InputField
5
5
  class File < InputField
6
6
  protected
7
7
 
8
8
  def input_component
9
- ::Flowbite::Input::File
9
+ Uchi::Flowbite::Input::File
10
10
  end
11
11
  end
12
12
  end
@@ -0,0 +1,9 @@
1
+ <div class="<%= classes.join(" ") %>">
2
+ <%= label %>
3
+ <%= input %>
4
+ <%= hint %>
5
+
6
+ <% errors.each do |error| %>
7
+ <%= render(Uchi::Flowbite::Input::ValidationError.new) { error.upcase_first } %>
8
+ <% end %>
9
+ </div>