flowbite-components 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -4
  3. data/README.md +56 -8
  4. data/app/components/flowbite/breadcrumb/home_icon.rb +28 -0
  5. data/app/components/flowbite/breadcrumb/item/current.rb +35 -0
  6. data/app/components/flowbite/breadcrumb/item/first.rb +37 -0
  7. data/app/components/flowbite/breadcrumb/item.rb +50 -0
  8. data/app/components/flowbite/breadcrumb/separator_icon.rb +34 -0
  9. data/app/components/flowbite/breadcrumb.rb +54 -0
  10. data/app/components/flowbite/button/outline.rb +25 -10
  11. data/app/components/flowbite/button/pill.rb +26 -26
  12. data/app/components/flowbite/button.rb +39 -35
  13. data/app/components/flowbite/card/card.html.erb +7 -0
  14. data/app/components/flowbite/card/title.rb +39 -0
  15. data/app/components/flowbite/card.rb +71 -16
  16. data/app/components/flowbite/input/checkbox.rb +13 -11
  17. data/app/components/flowbite/input/date.rb +2 -2
  18. data/app/components/flowbite/input/date_time.rb +11 -0
  19. data/app/components/flowbite/input/email.rb +2 -2
  20. data/app/components/flowbite/input/file.rb +13 -11
  21. data/app/components/flowbite/input/hint.rb +16 -8
  22. data/app/components/flowbite/input/label.rb +15 -10
  23. data/app/components/flowbite/input/number.rb +2 -2
  24. data/app/components/flowbite/input/password.rb +2 -2
  25. data/app/components/flowbite/input/phone.rb +2 -2
  26. data/app/components/flowbite/input/radio_button.rb +13 -11
  27. data/app/components/flowbite/input/select.rb +7 -7
  28. data/app/components/flowbite/input/textarea.rb +13 -11
  29. data/app/components/flowbite/input/url.rb +2 -2
  30. data/app/components/flowbite/input/validation_error.rb +32 -2
  31. data/app/components/flowbite/input.rb +155 -0
  32. data/app/components/flowbite/input_field/checkbox.html.erb +2 -4
  33. data/app/components/flowbite/input_field/checkbox.rb +8 -4
  34. data/app/components/flowbite/input_field/date_time.rb +13 -0
  35. data/app/components/flowbite/input_field/input_field.html.erb +2 -2
  36. data/app/components/flowbite/input_field/radio_button.html.erb +2 -4
  37. data/app/components/flowbite/input_field/radio_button.rb +19 -21
  38. data/app/components/flowbite/input_field.rb +117 -49
  39. data/app/components/flowbite/link.rb +43 -0
  40. data/app/components/flowbite/styles.rb +34 -0
  41. data/app/components/flowbite/toast/icon.html.erb +5 -0
  42. data/app/components/flowbite/toast/icon.rb +57 -0
  43. data/app/components/flowbite/toast/toast.html.erb +40 -0
  44. data/app/components/flowbite/toast.rb +37 -0
  45. data/lib/flowbite/components/version.rb +1 -1
  46. data/lib/yard/flowbite_viewcomponent.rb +24 -0
  47. metadata +37 -5
  48. data/app/components/flowbite/input/field.rb +0 -117
@@ -1,21 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Flowbite
4
- module Input
5
- class Textarea < Field
4
+ class Input
5
+ class Textarea < Input
6
6
  class << self
7
7
  # rubocop:disable Layout/LineLength
8
8
  def styles
9
- {
10
- default: Flowbite::Style.new(
11
- default: ["block", "w-full", "text-gray-900", "bg-gray-50", "rounded-lg", "border", "border-gray-300", "focus:ring-blue-500", "focus:border-blue-500", "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"],
12
- disabled: ["block", "w-full", "bg-gray-100", "rounded-lg", "border", "border-gray-300", "text-gray-900", "cursor-not-allowed"],
13
- error: ["block", "w-full", "bg-red-50", "border", "border-red-500", "text-red-900", "placeholder-red-700", "rounded-lg", "focus:ring-red-500", "focus:border-red-500", "dark:bg-gray-700", "dark:text-red-500", "dark:placeholder-red-500", "dark:border-red-500"]
14
- )
15
- }.freeze
9
+ Flowbite::Styles.from_hash(
10
+ {
11
+ default: {
12
+ 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"],
13
+ 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"],
14
+ 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"]
15
+ }
16
+ }.freeze
17
+ )
16
18
  end
17
- # rubocop:enable Layout/LineLength
18
19
  end
20
+ # rubocop:enable Layout/LineLength
19
21
 
20
22
  # Returns the HTML to use for the actual input field element.
21
23
  def call
@@ -30,7 +32,7 @@ module Flowbite
30
32
 
31
33
  # Returns the CSS classes to apply to the input field
32
34
  def classes
33
- self.class.classes(size: size, state: state)
35
+ self.class.classes(size: size, state: state) + @class
34
36
  end
35
37
 
36
38
  # Returns the name of the method used to generate HTML for the input field
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Flowbite
4
- module Input
5
- class Url < Field
4
+ class Input
5
+ class Url < Input
6
6
  # Returns the name of the method used to generate HTML for the input field
7
7
  def input_field_type
8
8
  :url_field
@@ -1,10 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Flowbite
4
- module Input
4
+ class Input
5
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
+ Flowbite::Styles.from_hash(
15
+ {
16
+ default: {
17
+ default: ["mt-2", "text-sm", "text-red-600", "dark:text-red-500"]
18
+ }
19
+ }.freeze
20
+ )
21
+ end
22
+ # rubocop:enable Layout/LineLength
23
+ end
24
+
6
25
  def call
7
- tag.p(content, class: "mt-2 text-sm text-red-600 dark:text-red-500")
26
+ tag.p(content, class: classes)
27
+ end
28
+
29
+ def initialize(class: nil)
30
+ @class = Array.wrap(binding.local_variable_get(:class))
31
+ end
32
+
33
+ protected
34
+
35
+ # Returns the CSS classes to apply to the validation error
36
+ def classes
37
+ self.class.classes + @class
8
38
  end
9
39
  end
10
40
  end
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ # The individual input form element used in forms - without labels, error
5
+ # messages, hints, etc.
6
+ #
7
+ # Use this when you want to render an input field on its own without any
8
+ # surrounding elements, i.e. as a building block in more complex input
9
+ # components. To render a complete input field with labels and error messages,
10
+ # use {Flowbite::InputField} instead.
11
+ #
12
+ # By default this renders a text input field. To render other types of input
13
+ # fields, use one of the subclasses, such as {Flowbite::Input::Checkbox} or
14
+ # {Flowbite::Input::Textarea}.
15
+ #
16
+ # @example Usage
17
+ # <%= render(Flowbite::Input::Email.new(attribute: :email, form: form)) %>
18
+ #
19
+ # @lookbook_embed InputPreview
20
+ class Input < ViewComponent::Base
21
+ SIZES = {
22
+ sm: ["px-2.5", "py-2", "text-sm"],
23
+ default: ["px-3", "py-2.5", "text-sm"],
24
+ lg: ["px-3.5", "py-3", "text-base"]
25
+ }.freeze
26
+
27
+ STATES = [
28
+ DEFAULT = :default,
29
+ DISABLED = :disabled,
30
+ ERROR = :error
31
+ ].freeze
32
+
33
+ attr_reader :options, :size, :style
34
+
35
+ class << self
36
+ # @return [Array<String>] The CSS classes to apply to the input field
37
+ # given the specified +size+, +state+, and +style+.
38
+ def classes(size: :default, state: :default, style: :default)
39
+ style = styles.fetch(style)
40
+ state_classes = style.fetch(state)
41
+ state_classes + sizes.fetch(size)
42
+ end
43
+
44
+ # Returns the sizes this Input supports.
45
+ #
46
+ # This is effectively the {SIZES} constant, but provided as a method to
47
+ # return the constant from the current class, not the superclass.
48
+ #
49
+ # @return [Hash] A hash mapping size names to their corresponding CSS
50
+ # classes.
51
+ def sizes
52
+ const_get(:SIZES)
53
+ end
54
+
55
+ # @return [Flowbite::Styles] The available styles for this input field.
56
+ def styles
57
+ # rubocop:disable Layout/LineLength
58
+ Flowbite::Styles.from_hash(
59
+ {
60
+ default: {
61
+ 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"],
62
+ 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"],
63
+ 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"]
64
+ }
65
+ }.freeze
66
+ )
67
+ # rubocop:enable Layout/LineLength
68
+ end
69
+ end
70
+
71
+ # @param attribute [Symbol] The attribute on the form's object this input
72
+ # field is for.
73
+ #
74
+ # @param form [ActionView::Helpers::FormBuilder] The form builder this
75
+ # input field is part of.
76
+ #
77
+ # @param class [String, Array<String>] Additional CSS classes to apply to
78
+ # the input field.
79
+ #
80
+ # @param disabled [Boolean] Whether the input field should be disabled.
81
+ #
82
+ # @param options [Hash] Additional HTML attributes to pass to the input
83
+ # field. For example, you can use this to set placeholder text by
84
+ # passing +options: {placeholder: "Enter your name"}+
85
+ #
86
+ # @param size [Symbol] The size of the input field. Can be one of +:sm+,
87
+ # +:default+, or +:lg+.
88
+ def initialize(attribute:, form:, class: nil, disabled: false, options: {}, size: :default)
89
+ @attribute = attribute
90
+ @class = Array.wrap(binding.local_variable_get(:class))
91
+ @disabled = disabled
92
+ @form = form
93
+ @options = options || {}
94
+ @object = form.object
95
+ @size = size
96
+ end
97
+
98
+ # Returns the HTML to use for the actual input field element.
99
+ def call
100
+ @form.send(
101
+ input_field_type,
102
+ @attribute,
103
+ **input_options
104
+ )
105
+ end
106
+
107
+ # Returns the CSS classes to apply to the input field
108
+ #
109
+ # @return [Array<String>] An array of CSS classes.
110
+ def classes
111
+ self.class.classes(size: size, state: state) + @class
112
+ end
113
+
114
+ # Returns the name of the method used to generate HTML for the input field
115
+ #
116
+ # @return [Symbol] The form helper method name to call on +form+.
117
+ def input_field_type
118
+ :text_field
119
+ end
120
+
121
+ protected
122
+
123
+ # @return [Boolean] Returns true if the field is disabled
124
+ def disabled?
125
+ !!@disabled
126
+ end
127
+
128
+ # Returns true if the object has errors. Returns false if there is no
129
+ # object.
130
+ #
131
+ # @return [Boolean] true if there are errors, false otherwise.
132
+ def errors?
133
+ return false unless @object
134
+
135
+ @object.errors.include?(@attribute.intern)
136
+ end
137
+
138
+ private
139
+
140
+ # Returns the options argument for the input field
141
+ def input_options
142
+ {
143
+ class: classes,
144
+ disabled: disabled?
145
+ }.merge(options)
146
+ end
147
+
148
+ def state
149
+ return DISABLED if disabled?
150
+ return ERROR if errors?
151
+
152
+ DEFAULT
153
+ end
154
+ end
155
+ end
@@ -1,7 +1,5 @@
1
- <div class="flex">
2
- <div class="flex items-center h-5">
3
- <%= input %>
4
- </div>
1
+ <div class="<%= classes.join(" ") %>">
2
+ <div class="flex items-center h-5"><%= input %></div>
5
3
 
6
4
  <div class="ms-2 text-sm">
7
5
  <%= label %>
@@ -5,6 +5,10 @@ module Flowbite
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
 
@@ -29,9 +33,9 @@ module Flowbite
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
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ class InputField
5
+ class DateTime < InputField
6
+ protected
7
+
8
+ def input_component
9
+ Flowbite::Input::DateTime
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,8 +1,8 @@
1
- <div>
1
+ <%= content_tag(:div, container_options) do %>
2
2
  <%= label %>
3
3
  <%= input %>
4
4
  <%= hint %>
5
5
  <% errors.each do |error| %>
6
6
  <%= render(Flowbite::Input::ValidationError.new) { error.upcase_first } %>
7
7
  <% end %>
8
- </div>
8
+ <% end %>
@@ -1,7 +1,5 @@
1
- <div class="flex">
2
- <div class="flex items-center h-5">
3
- <%= input %>
4
- </div>
1
+ <div class="<%= classes.join(" ") %>">
2
+ <div class="flex items-center h-5"><%= input %></div>
5
3
 
6
4
  <div class="ms-2 text-sm">
7
5
  <%= label %>
@@ -3,13 +3,17 @@
3
3
  module Flowbite
4
4
  class InputField
5
5
  class RadioButton < InputField
6
- def initialize(attribute:, form:, value:, disabled: false, hint: nil, input: {}, label: {})
7
- super(attribute: attribute, form: form, disabled: disabled, hint: hint, input: input, label: label)
6
+ def initialize(attribute:, form:, value:, class: nil, disabled: false, hint: nil, input: {}, label: {}, options: {})
7
+ super(attribute: attribute, class: binding.local_variable_get(:class), form: form, disabled: disabled, hint: hint, input: input, label: label, options: options)
8
8
  @value = value
9
9
  end
10
10
 
11
11
  protected
12
12
 
13
+ def default_container_classes
14
+ ["flex"]
15
+ end
16
+
13
17
  def default_input
14
18
  args = {
15
19
  attribute: @attribute,
@@ -22,6 +26,15 @@ module Flowbite
22
26
  input_component.new(**args)
23
27
  end
24
28
 
29
+ def default_hint_options
30
+ return {} unless @hint
31
+
32
+ {
33
+ class: hint_classes,
34
+ id: id_for_hint_element
35
+ }.merge(@hint[:options] || {})
36
+ end
37
+
25
38
  # Returns options for the default label element. This includes CSS classes
26
39
  # since they are specific to RadioButton labels (and Checkbox ones).
27
40
  def default_label_options
@@ -33,21 +46,6 @@ module Flowbite
33
46
  })
34
47
  end
35
48
 
36
- # Returns the HTML to use for the hint element if any
37
- def hint
38
- return unless hint?
39
-
40
- component = Flowbite::Input::Hint.new(
41
- attribute: @attribute,
42
- form: @form,
43
- options: {
44
- class: hint_classes,
45
- id: id_for_hint_element
46
- }
47
- ).with_content(@hint)
48
- render(component)
49
- end
50
-
51
49
  def input_component
52
50
  ::Flowbite::Input::RadioButton
53
51
  end
@@ -56,9 +54,9 @@ module Flowbite
56
54
 
57
55
  def hint_classes
58
56
  if disabled?
59
- "text-xs font-normal text-gray-400 dark:text-gray-500"
57
+ "text-xs font-normal text-fg-disabled"
60
58
  else
61
- "text-xs font-normal text-gray-500 dark:text-gray-300"
59
+ "text-xs font-normal text-body"
62
60
  end
63
61
  end
64
62
 
@@ -76,9 +74,9 @@ module Flowbite
76
74
 
77
75
  def label_classes
78
76
  if disabled?
79
- "font-medium text-gray-400 dark:text-gray-500"
77
+ "font-medium text-fg-disabled"
80
78
  else
81
- "font-medium text-gray-900 dark:text-gray-300"
79
+ "font-medium text-heading"
82
80
  end
83
81
  end
84
82
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Flowbite
4
- # A form element for a single field, containing label, input field, error
5
- # messages, helper text and whatever else is needed for a user friendly input
6
- # experience.
4
+ # A fully fledged form element for an attribute containing label, input field,
5
+ # error messages, helper text and whatever else is needed for a user-friendly
6
+ # input experience.
7
7
  #
8
8
  # @see https://flowbite.com/docs/forms/input-field/
9
9
  #
@@ -13,81 +13,143 @@ module Flowbite
13
13
  # more.
14
14
  #
15
15
  # Usually you'd use one of the subclasses of this class which implement the
16
- # different input types, like `Flowbite::InputField::Text`,
17
- # `Flowbite::InputField::Email`, etc.
16
+ # different input types, like {Flowbite::InputField::Text},
17
+ # {Flowbite::InputField::Email}, etc.
18
18
  #
19
- # Expects 2 arguments:
19
+ # To render an input without labels or error messages etc, see
20
+ # {Flowbite::Input} instead and one of its subclasses.
20
21
  #
21
- # @param attribute [Symbol] The name of the attribute to render in this input
22
- # field.
22
+ # @example Basic usage
23
+ # <% form_for @person do |form| %>
24
+ # <%= render(
25
+ # Flowbite::InputField::Number.new(
26
+ # attribute: :name,
27
+ # form: form
28
+ # )
29
+ # ) %>
30
+ # <% end %>
23
31
  #
24
- # @param form [ActionView::Helpers::FormBuilder] The form builder object that
25
- # will be used to generate the input field.
32
+ # @example Kitchen sink
33
+ # <% form_for @person do |form| %>
34
+ # <%= render(
35
+ # Flowbite::InputField::Number.new(
36
+ # attribute: :name,
37
+ # class: ["mb-4", "w-full"],
38
+ # disabled: true,
39
+ # form: form,
40
+ # hint: {
41
+ # content: "Please enter your full name.",
42
+ # options: {id: "name-helper-text"}
43
+ # },
44
+ # input: {
45
+ # options: {placeholder: "All of your names here"}
46
+ # },
47
+ # label: {
48
+ # content: "Full name",
49
+ # options: {class: ["mb-2", "font-medium"]}
50
+ # },
51
+ # options: {data: {controller: "form-field"}},
52
+ # size: :lg
53
+ # )
54
+ # ) %>
55
+ # <% end %>
26
56
  #
27
- # Supports additional arguments:
57
+ # @viewcomponent_slot [Flowbite::Input::Hint] hint Helper text displayed
58
+ # below the input field to provide additional context or instructions.
59
+ # @viewcomponent_slot [Flowbite::Input] input The input element itself.
60
+ # Usually auto-generated based on the input type subclass.
61
+ # @viewcomponent_slot [Flowbite::Input::Label] label The label for the input
62
+ # field, rendered above the input element.
28
63
  #
29
- # @param hint [String] A hint to display below the input field, providing
30
- # additional context or instructions for the user. This is optional. See
31
- # https://flowbite.com/docs/forms/input-field/#helper-text
32
- #
33
- # @param label [Hash] A hash with options for the label. These are passed to
34
- # Flowbite::Input::Label, see that for details. Can contain:
35
- # - `content`: The content of the label. If not provided, the label will
36
- # default to the attribute name.
37
- # - `options`: A hash of additional options to pass to the label component.
38
- # This can be used to set the class, for example.
39
- #
40
- # @param disabled [Boolean] Whether the input field should be disabled.
41
- # Defaults to `false`.
42
- #
43
- # @param input [Hash] A hash with options for the default input component.
44
- # These are passed to the input components constructor, so see whatever
45
- # component is being used for details. Can contain:
46
- # - `options`: Additional HTML attributes to pass to the input element.
47
- #
48
- # @param size [Symbol] The size of the input field. Can be one of `:sm`,
49
- # `:md`, or `:lg`. Defaults to `:md`.
50
- #
51
- # Sample usage
52
- #
53
- # <% form_for @person do |form| %>
54
- # <%= render(
55
- # Flowbite::InputField::Number.new(
56
- # :attribute => :name,
57
- # :form => form
58
- # )
59
- # ) %>
60
- # <% end %>
61
- #
62
- # To render an input without labels or error messages etc, use
63
- # `Flowbite::Input::Field` instead.
64
+ # @lookbook_embed InputFieldPreview
64
65
  class InputField < ViewComponent::Base
65
66
  renders_one :hint
66
67
  renders_one :input
67
68
  renders_one :label
68
69
 
69
70
  # Returns the errors for attribute
71
+ #
72
+ # @return [Array<String>] An array of error messages for the attribute.
70
73
  def errors
74
+ return [] unless @object
75
+
71
76
  @object.errors[@attribute] || []
72
77
  end
73
78
 
74
- def initialize(attribute:, form:, disabled: false, hint: nil, input: {}, label: {}, size: :default)
79
+ # @param attribute [Symbol] The name of the attribute to render in this
80
+ # input field.
81
+ #
82
+ # @param form [ActionView::Helpers::FormBuilder] The form builder object that
83
+ # will be used to generate the input field.
84
+ #
85
+ # @param class [String, Array<String>] Additional CSS classes to apply to
86
+ # the input field container, i.e. the outermost element. To add classes to
87
+ # individual components of the InputField, use the +input+, +label+ and
88
+ # +hint+ arguments.
89
+ #
90
+ # @param disabled [Boolean] Whether the input field should be disabled.
91
+ #
92
+ # @param hint [Hash] A hint to display below the input field, providing
93
+ # additional context or instructions for the user. If provided, this Hash
94
+ # is passed to the {Flowbite::Input::Hint} constructor.
95
+ # @option hint [String] content The content of the hint element.
96
+ # @option hint [Hash] options Additional options to pass to the hint
97
+ # component. This can be used to set the class, for example.
98
+ #
99
+ # @param input [Hash] A hash with options for the input component.
100
+ # These are passed to the input component's constructor, see the
101
+ # documentation for whatever input component is being used.
102
+ # See {Flowbite::Input}.
103
+ # @option input [Hash] options Additional HTML attributes to pass to
104
+ # the input element.
105
+ #
106
+ # @param label [Hash] A hash with options for the label element. If
107
+ # provided, this Hash is passed to the {Flowbite::Input::Label}
108
+ # constructor.
109
+ # @option label [String] content The content of the label element.
110
+ # @option label [Hash] options Additional options to pass to the label
111
+ # component. This can be used to set the class, for example.
112
+ #
113
+ # @param options [Hash] Additional HTML attributes to pass to the input
114
+ # field container element.
115
+ #
116
+ # @param size [Symbol] The size of the input field. Can be one of +:sm+,
117
+ # +:default+, or +:lg+.
118
+ def initialize(attribute:, form:, class: nil, disabled: false, hint: nil, input: {}, label: {}, options: {}, size: :default)
75
119
  @attribute = attribute
120
+ @class = Array.wrap(binding.local_variable_get(:class))
76
121
  @disabled = disabled
77
122
  @form = form
78
123
  @hint = hint
79
124
  @input = input
80
125
  @label = label
81
126
  @object = form.object
127
+ @options = options || {}
82
128
  @size = size
83
129
  end
84
130
 
85
131
  def input_component
86
- ::Flowbite::Input::Field
132
+ ::Flowbite::Input
87
133
  end
88
134
 
89
135
  protected
90
136
 
137
+ def classes
138
+ if @options[:class]
139
+ Array.wrap(@options[:class])
140
+ else
141
+ [default_container_classes, @class].flatten.compact
142
+ end
143
+ end
144
+
145
+ def container_options
146
+ @options.merge({class: classes.join(" ")})
147
+ end
148
+
149
+ def default_container_classes
150
+ []
151
+ end
152
+
91
153
  # Returns the HTML to use for the hint element if any
92
154
  def default_hint
93
155
  return unless hint?
@@ -171,7 +233,13 @@ module Flowbite
171
233
  end
172
234
 
173
235
  def id_for_hint_element
174
- "#{@form.object_name}_#{@attribute}_hint"
236
+ [
237
+ @form.object_name,
238
+ @attribute,
239
+ "hint"
240
+ ]
241
+ .compact_blank
242
+ .join("_")
175
243
  end
176
244
 
177
245
  # @return [Hash] The keyword arguments for the input component.
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ # The link component can be used to set hyperlinks from one page to another or
5
+ # to an external website when clicking on an inline text item, button, or card
6
+ #
7
+ # Use this component to add default styles to an inline link element.
8
+ #
9
+ # @lookbook_embed LinkPreview
10
+ class Link < ViewComponent::Base
11
+ attr_reader :href, :options
12
+
13
+ class << self
14
+ def classes
15
+ ["font-medium", "text-fg-brand", "hover:underline"]
16
+ end
17
+ end
18
+
19
+ # Initialize the Link component.
20
+ #
21
+ # @param href What to link to. This can be a String or anything else that
22
+ # `link_to` supports. See `ActionView::Helpers::UrlHelper#link_to` for more
23
+ # details.
24
+ #
25
+ # @param options [Hash] Additional HTML options for the link element
26
+ def initialize(href:, class: nil, **options)
27
+ super()
28
+ @class = Array.wrap(binding.local_variable_get(:class))
29
+ @href = href
30
+ @options = options
31
+ end
32
+
33
+ def call
34
+ link_to(content, href, {class: classes}.merge(options))
35
+ end
36
+
37
+ private
38
+
39
+ def classes
40
+ self.class.classes + @class
41
+ end
42
+ end
43
+ end