flowbite-components 0.1.0 → 0.1.2

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -0
  3. data/README.md +34 -7
  4. data/app/assets/tailwind/flowbite_components/engine.css +2 -0
  5. data/app/components/flowbite/button/outline.rb +22 -0
  6. data/app/components/flowbite/button/pill.rb +40 -0
  7. data/app/components/flowbite/button.rb +92 -0
  8. data/app/components/flowbite/card.rb +43 -0
  9. data/app/components/flowbite/input/checkbox.rb +37 -0
  10. data/app/components/flowbite/input/date.rb +11 -0
  11. data/app/components/flowbite/input/email.rb +12 -0
  12. data/app/components/flowbite/input/field.rb +117 -0
  13. data/app/components/flowbite/input/file.rb +30 -0
  14. data/app/components/flowbite/input/hint.rb +57 -0
  15. data/app/components/flowbite/input/label.rb +82 -0
  16. data/app/components/flowbite/input/number.rb +11 -0
  17. data/app/components/flowbite/input/password.rb +11 -0
  18. data/app/components/flowbite/input/phone.rb +11 -0
  19. data/app/components/flowbite/input/radio_button.rb +50 -0
  20. data/app/components/flowbite/input/select.rb +49 -0
  21. data/app/components/flowbite/input/textarea.rb +42 -0
  22. data/app/components/flowbite/input/url.rb +12 -0
  23. data/app/components/flowbite/input/validation_error.rb +11 -0
  24. data/app/components/flowbite/input_field/checkbox.html.erb +14 -0
  25. data/app/components/flowbite/input_field/checkbox.rb +49 -0
  26. data/app/components/flowbite/input_field/date.rb +13 -0
  27. data/app/components/flowbite/input_field/email.rb +13 -0
  28. data/app/components/flowbite/input_field/file.rb +13 -0
  29. data/app/components/flowbite/input_field/input_field.html.erb +8 -0
  30. data/app/components/flowbite/input_field/number.rb +13 -0
  31. data/app/components/flowbite/input_field/password.rb +13 -0
  32. data/app/components/flowbite/input_field/phone.rb +13 -0
  33. data/app/components/flowbite/input_field/radio_button.html.erb +14 -0
  34. data/app/components/flowbite/input_field/radio_button.rb +88 -0
  35. data/app/components/flowbite/input_field/select.rb +31 -0
  36. data/app/components/flowbite/input_field/text.rb +8 -0
  37. data/app/components/flowbite/input_field/textarea.rb +13 -0
  38. data/app/components/flowbite/input_field/url.rb +13 -0
  39. data/app/components/flowbite/input_field.rb +187 -0
  40. data/app/components/flowbite/style.rb +13 -0
  41. data/lib/flowbite/{view_components → components}/engine.rb +2 -2
  42. data/lib/flowbite/{view_components → components}/version.rb +2 -2
  43. data/lib/flowbite/{view_components.rb → components.rb} +3 -3
  44. metadata +49 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8801080d6b51d7c4fef754dcd189ebaea34c8dd17a496c7dda80eb31e37f9737
4
- data.tar.gz: a50284e6b62c7713edbaadec851d34ec87ad698986431ca407539c9282033928
3
+ metadata.gz: afc7f639fa9f28b2310d7f68cd3d8939e3eaa526ba80ee028c471664597e4581
4
+ data.tar.gz: 1b4e73f0bd471b9b3d36db8aba2e614e28f5573cbf7fd214de360a985767eade
5
5
  SHA512:
6
- metadata.gz: 894c82db7d448e8a444e4fb3df781e0ccea35df068ae5711d358e83d3651dfc30e2b086e55dcfd8afabd5d84db5f777b1dd0fc497382cab1531f0dcf6623ab3f
7
- data.tar.gz: cd0bb587980b19ff4d4b6ec9f6cfad3d3ec42a624a87f2a88f28eafd77608956a3cd2d3de6135c1b118ab0f85505a8c390dc0e6be53a548ef794e0aeb3bb228e
6
+ metadata.gz: 6d56824ba5b7d0c13bca6b31e4dac90a1859ec35c3c50478b90a4f67aae2cd7e7efcfb53dc29ddfcae9f4839695610ea5602e0f29b2ddd53c64a00b34562806d
7
+ data.tar.gz: efe21d27318e44196ecd0024663a143ba577ab8b2ca0a2b9e085263d4be3d7f472c22c68c5442d802c58717306a575d320325c4d9d8bb3d5f8b5e48fb444c992
data/CHANGELOG.md CHANGED
@@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
10
10
  * Button component (first component, wee!)
11
11
  * Input components
12
12
  * InputField components
13
+ * Basic Card component
13
14
 
14
15
  ### Changes
15
16
 
data/README.md CHANGED
@@ -1,11 +1,11 @@
1
- # Flowbite ViewComponents
1
+ # Flowbite Components
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/flowbite-view_components.svg)](https://rubygems.org/gems/flowbite-view_components)
4
- [![Ruby Tests](https://github.com/substancelab/flowbite-view_components/workflows/Ruby/badge.svg)](https://github.com/substancelab/flowbite-view_components/actions)
3
+ [![Gem Version](https://badge.fury.io/rb/flowbite-components.svg)](https://rubygems.org/gems/flowbite-components)
4
+ [![Ruby Tests](https://github.com/substancelab/flowbite-components/workflows/Ruby/badge.svg)](https://github.com/substancelab/flowbite-components/actions)
5
5
 
6
6
  Unofficial, open source implementation of [Flowbite](https://flowbite.com/) components for Rails applications, built using [ViewComponent](https://viewcomponent.org/).
7
7
 
8
- Flowbite ViewComponents provides a comprehensive library of UI components following the Flowbite design system, implemented as Rails ViewComponents with full Tailwind CSS integration and dark mode support.
8
+ Flowbite Components provides a comprehensive library of UI components following the Flowbite design system, implemented as Rails ViewComponents with full Tailwind CSS integration and dark mode support.
9
9
 
10
10
  ## Features
11
11
 
@@ -22,7 +22,7 @@ Flowbite ViewComponents provides a comprehensive library of UI components follow
22
22
  Add the gem to your application's Gemfile:
23
23
 
24
24
  ```ruby
25
- gem 'flowbite-view_components'
25
+ gem 'flowbite-components'
26
26
  ```
27
27
 
28
28
  Then execute:
@@ -52,7 +52,7 @@ Add Flowbite to your Tailwind CSS configuration. In your `app/assets/tailwind/ap
52
52
  ```css
53
53
  @import "flowbite/src/themes/default";
54
54
  @plugin "flowbite/plugin";
55
- @import "../builds/tailwind/flowbite_view_components";
55
+ @import "../builds/tailwind/flowbite_components";
56
56
  ```
57
57
 
58
58
  ## Usage examples
@@ -147,6 +147,33 @@ Add Flowbite to your Tailwind CSS configuration. In your `app/assets/tailwind/ap
147
147
  ) %>
148
148
  ```
149
149
 
150
+ ## How to customize components
151
+
152
+ ### Add specific CSS classes
153
+
154
+ A common use case for customizing a component is to add more CSS classes when
155
+ rendering it, fx to change the size or spacing. flowbite-components is optimized
156
+ for this case and all you need to do is specify the extra classes:
157
+
158
+ ```erb
159
+ <%= render(Flowbite::Card.new(class: "w-full my-8")) { "Content" } %>
160
+ ```
161
+ renders
162
+ ```html
163
+ <div class="... all the usual classes... w-full my-8">
164
+ ```
165
+
166
+ If you want to fully replace the existing classes, you can pass an entirely new
167
+ `class` attribute via options:
168
+
169
+ ```erb
170
+ <%= render(Flowbite::Card.new(options: {class: "w-full my-8"})) { "Content" } %>
171
+ ```
172
+ renders
173
+ ```html
174
+ <div class="w-full my-8">
175
+ ```
176
+
150
177
  ## Available Components
151
178
 
152
179
  ### Form Components
@@ -223,7 +250,7 @@ This library includes Lookbook previews for all components. To view them:
223
250
 
224
251
  ## Contributing
225
252
 
226
- Bug reports and pull requests are welcome on GitHub at [https://github.com/substancelab/flowbite-view_components](https://github.com/substancelab/flowbite-view_components).
253
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/substancelab/flowbite-components](https://github.com/substancelab/flowbite-components).
227
254
 
228
255
  ### Development Guidelines
229
256
 
@@ -0,0 +1,2 @@
1
+ /* Make sure Tailwind doens't prune our classes away */
2
+ @source "../../../components"
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ class Button
5
+ class Outline < Flowbite::Button
6
+ class << self
7
+ # rubocop:disable Layout/LineLength
8
+ def styles
9
+ {
10
+ default: Flowbite::Style.new(
11
+ default: ["text-blue-700", "hover:text-white", "border", "border-blue-700", "hover:bg-blue-800", "focus:ring-4", "focus:outline-none", "focus:ring-blue-300", "font-medium", "rounded-lg", "text-center", "me-2", "mb-2", "dark:border-blue-500", "dark:text-blue-500", "dark:hover:text-white", "dark:hover:bg-blue-500", "dark:focus:ring-blue-800"]
12
+ ),
13
+ green: Flowbite::Style.new(
14
+ default: ["text-green-700", "hover:text-white", "border", "border-green-700", "hover:bg-green-800", "focus:ring-4", "focus:outline-none", "focus:ring-green-300", "font-medium", "rounded-lg", "text-center", "me-2", "mb-2", "dark:border-green-500", "dark:text-green-500", "dark:hover:text-white", "dark:hover:bg-green-600", "dark:focus:ring-green-800"]
15
+ )
16
+ }
17
+ end
18
+ # rubocop:enable Layout/LineLength
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ class Button
5
+ class Pill < Flowbite::Button
6
+ class << self
7
+ # rubocop:disable Layout/LineLength, Metrics/MethodLength
8
+ def styles
9
+ {
10
+ alternative: Flowbite::Style.new(
11
+ default: ["text-sm", "font-medium", "text-gray-900", "focus:outline-none", "bg-white", "rounded-full", "border", "border-gray-200", "hover:bg-gray-100", "hover:text-blue-700", "focus:z-10", "focus:ring-4", "focus:ring-gray-100", "dark:focus:ring-gray-700", "dark:bg-gray-800", "dark:text-gray-400", "dark:border-gray-600", "dark:hover:text-white", "dark:hover:bg-gray-700"]
12
+ ),
13
+ dark: Flowbite::Style.new(
14
+ default: ["text-white", "bg-gray-800", "hover:bg-gray-900", "focus:outline-none", "focus:ring-4", "focus:ring-gray-300", "font-medium", "rounded-full", "dark:bg-gray-800", "dark:hover:bg-gray-700", "dark:focus:ring-gray-700", "dark:border-gray-700"]
15
+ ),
16
+ default: Flowbite::Style.new(
17
+ default: ["text-white", "bg-blue-700", "hover:bg-blue-800", "focus:outline-none", "focus:ring-4", "focus:ring-blue-300", "font-medium", "rounded-full", "text-center", "dark:bg-blue-600", "dark:hover:bg-blue-700", "dark:focus:ring-blue-800"]
18
+ ),
19
+ green: Flowbite::Style.new(
20
+ default: ["text-white", "bg-green-700", "hover:bg-green-800", "focus:outline-none", "focus:ring-4", "focus:ring-green-300", "font-medium", "rounded-full", "text-center", "dark:bg-green-600", "dark:hover:bg-green-700", "dark:focus:ring-green-800"]
21
+ ),
22
+ light: Flowbite::Style.new(
23
+ default: ["text-gray-900", "bg-white", "border", "border-gray-300", "focus:outline-none", "hover:bg-gray-100", "focus:ring-4", "focus:ring-gray-100", "font-medium", "rounded-full", "dark:bg-gray-800", "dark:text-white", "dark:border-gray-600", "dark:hover:bg-gray-700", "dark:hover:border-gray-600", "dark:focus:ring-gray-700"]
24
+ ),
25
+ purple: Flowbite::Style.new(
26
+ default: ["text-white", "bg-purple-700", "hover:bg-purple-800", "focus:outline-none", "focus:ring-4", "focus:ring-purple-300", "font-medium", "rounded-full", "text-center", "dark:bg-purple-600", "dark:hover:bg-purple-700", "dark:focus:ring-purple-900"]
27
+ ),
28
+ red: Flowbite::Style.new(
29
+ default: ["text-white", "bg-red-700", "hover:bg-red-800", "focus:outline-none", "focus:ring-4", "focus:ring-red-300", "font-medium", "rounded-full", "text-center", "dark:bg-red-600", "dark:hover:bg-red-700", "dark:focus:ring-red-900"]
30
+ ),
31
+ yellow: Flowbite::Style.new(
32
+ default: ["text-white", "bg-yellow-400", "hover:bg-yellow-500", "focus:outline-none", "focus:ring-4", "focus:ring-yellow-300", "font-medium", "rounded-full", "text-center", "dark:focus:ring-yellow-900"]
33
+ )
34
+ }
35
+ end
36
+ # rubocop:enable Layout/LineLength, Metrics/MethodLength
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ # Renders a HTML button element.
5
+ #
6
+ # See https://flowbite.com/docs/components/buttons/
7
+ #
8
+ # @param label [String] The text to display on the button.
9
+ #
10
+ # All other parameters are optional and are passed directly to the button tag
11
+ # as HTML attributes.
12
+ class Button < ViewComponent::Base
13
+ SIZES = {
14
+ xs: ["text-xs", "px-3", "py-2"],
15
+ sm: ["text-sm", "px-3", "py-2"],
16
+ default: ["text-sm", "px-5", "py-2.5"],
17
+ lg: ["text-base", "px-5", "py-3"],
18
+ xl: ["text-base", "px-6", "py-3.5"]
19
+ }.freeze
20
+
21
+ class << self
22
+ def classes(size: :default, state: :default, style: :default)
23
+ style = styles.fetch(style)
24
+ classes = style.fetch(state)
25
+ classes + sizes.fetch(size)
26
+ end
27
+
28
+ def sizes
29
+ SIZES
30
+ end
31
+
32
+ # rubocop:disable Layout/LineLength
33
+ def styles
34
+ {
35
+ alternative: Flowbite::Style.new(
36
+ default: ["font-medium", "text-gray-900", "focus:outline-none", "bg-white", "rounded-lg", "border", "border-gray-200", "hover:bg-gray-100", "hover:text-blue-700", "focus:z-10", "focus:ring-4", "focus:ring-gray-100", "dark:focus:ring-gray-700", "dark:bg-gray-800", "dark:text-gray-400", "dark:border-gray-600", "dark:hover:text-white", "dark:hover:bg-gray-700"]
37
+ ),
38
+ dark: Flowbite::Style.new(
39
+ default: ["text-white", "bg-gray-800", "hover:bg-gray-900", "focus:ring-4", "focus:ring-gray-300", "font-medium", "rounded-lg", "dark:bg-gray-800", "dark:hover:bg-gray-700", "dark:focus:ring-gray-700", "dark:border-gray-700"]
40
+ ),
41
+ default: Flowbite::Style.new(
42
+ default: ["text-white", "bg-blue-700", "hover:bg-blue-800", "focus:ring-4", "focus:ring-blue-300", "font-medium", "rounded-lg", "dark:bg-blue-600", "dark:hover:bg-blue-700", "focus:outline-none", "dark:focus:ring-blue-800"]
43
+ ),
44
+ green: Flowbite::Style.new(
45
+ default: ["focus:outline-none", "text-white", "bg-green-700", "hover:bg-green-800", "focus:ring-4", "focus:ring-green-300", "font-medium", "rounded-lg", "dark:bg-green-600", "dark:hover:bg-green-700", "dark:focus:ring-green-800"]
46
+ ),
47
+ light: Flowbite::Style.new(
48
+ default: ["text-gray-900", "bg-white", "border", "border-gray-300", "hover:bg-gray-100", "focus:ring-4", "focus:ring-gray-100", "font-medium", "rounded-lg", "dark:bg-gray-800", "dark:text-white", "dark:border-gray-600", "dark:hover:bg-gray-700", "dark:hover:border-gray-600", "dark:focus:ring-gray-700"]
49
+ ),
50
+ purple: Flowbite::Style.new(
51
+ default: ["focus:outline-none", "text-white", "bg-purple-700", "hover:bg-purple-800", "focus:ring-4", "focus:ring-purple-300", "font-medium", "rounded-lg", "dark:bg-purple-600", "dark:hover:bg-purple-700", "dark:focus:ring-purple-900"]
52
+ ),
53
+ red: Flowbite::Style.new(
54
+ default: ["focus:outline-none", "text-white", "bg-red-700", "hover:bg-red-800", "focus:ring-4", "focus:ring-red-300", "font-medium", "rounded-lg", "dark:bg-red-600", "dark:hover:bg-red-700", "dark:focus:ring-red-900"]
55
+ ),
56
+ yellow: Flowbite::Style.new(
57
+ default: ["focus:outline-none", "text-white", "bg-yellow-400", "hover:bg-yellow-500", "focus:ring-4", "focus:ring-yellow-300", "font-medium", "rounded-lg", "dark:focus:ring-yellow-900"]
58
+ )
59
+ }.freeze
60
+ end
61
+ # rubocop:enable Layout/LineLength
62
+ end
63
+
64
+ attr_reader :button_attributes, :size, :style
65
+
66
+ def initialize(size: :default, style: :default, **button_attributes)
67
+ @size = size
68
+ @style = style
69
+ @button_attributes = button_attributes
70
+ end
71
+
72
+ def call
73
+ content_tag(
74
+ :button,
75
+ content,
76
+ **options
77
+ )
78
+ end
79
+
80
+ private
81
+
82
+ def classes
83
+ self.class.classes(size: size, state: :default, style: style)
84
+ end
85
+
86
+ def options
87
+ {
88
+ class: classes
89
+ }.merge(button_attributes)
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,43 @@
1
+ module Flowbite
2
+ # Renders a card element.
3
+ #
4
+ # See https://flowbite.com/docs/components/cards/
5
+ class Card < 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: Flowbite::Style.new(
16
+ default: ["p-6", "bg-white", "border", "border-gray-200", "rounded-lg", "shadow-sm", "dark:bg-gray-800", "dark:border-gray-700"]
17
+ )
18
+ }.freeze
19
+ end
20
+ # rubocop:enable Layout/LineLength
21
+ end
22
+
23
+ def call
24
+ card_options = {}
25
+ card_options[:class] = self.class.classes + @class
26
+
27
+ content_tag(:div, card_options.merge(@options)) do
28
+ concat(content_tag(:div, content, class: "font-normal text-gray-700 dark:text-gray-400"))
29
+ end
30
+ end
31
+
32
+ # @param class [Array<String>] Additional CSS classes for the card
33
+ # container.
34
+ #
35
+ # @param options [Hash] Additional HTML options for the card container
36
+ # (e.g., custom classes, data attributes). These options are merged into
37
+ # the card's root element.
38
+ def initialize(class: [], options: {})
39
+ @class = Array(binding.local_variable_get(:class)) || []
40
+ @options = options || {}
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ module Input
5
+ # The checkbox component can be used to receive one or more selected options
6
+ # from the user in the form of a square box available in multiple styles,
7
+ # sizes, colors, and variants coded with the utility classes from Tailwind
8
+ # CSS and with support for dark mode.
9
+ #
10
+ # https://flowbite.com/docs/forms/checkbox/
11
+ class Checkbox < Field
12
+ class << self
13
+ # Checkboxes only have their default size.
14
+ def sizes
15
+ {
16
+ default: ["w-4", "h-4"]
17
+ }
18
+ end
19
+
20
+ # rubocop:disable Layout/LineLength
21
+ def styles
22
+ {
23
+ default: Flowbite::Style.new(
24
+ 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"],
25
+ 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"],
26
+ 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"]
27
+ )
28
+ }.freeze
29
+ end
30
+ end
31
+
32
+ def input_field_type
33
+ :check_box
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ module Input
5
+ class Date < Field
6
+ def input_field_type
7
+ :date_field
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ module Input
5
+ class Email < Field
6
+ # Returns the name of the method used to generate HTML for the input field
7
+ def input_field_type
8
+ :email_field
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ module Input
5
+ # The indivdual input component for use in forms without labels or error
6
+ # messages.
7
+ #
8
+ # Use this when you want to render an input field on its own without any
9
+ # surrounding elements, ie as a building block in more complex input
10
+ # components.
11
+ #
12
+ # To render a complete input field with labels and error messages, use
13
+ # `Flowbite::InputField` instead.
14
+ class Field < ViewComponent::Base
15
+ SIZES = {
16
+ sm: ["p-2", "text-xs"],
17
+ default: ["p-2.5", "text-sm"],
18
+ lg: ["p-4", "text-base"]
19
+ }.freeze
20
+
21
+ STATES = [
22
+ DEFAULT = :default,
23
+ DISABLED = :disabled,
24
+ ERROR = :error
25
+ ].freeze
26
+
27
+ attr_reader :options, :size, :style
28
+
29
+ class << self
30
+ def classes(size: :default, state: :default, style: :default)
31
+ style = styles.fetch(style)
32
+ state_classes = style.fetch(state)
33
+ state_classes + sizes.fetch(size)
34
+ end
35
+
36
+ # Returns the sizes this Field supports.
37
+ #
38
+ # This is effectively the SIZES constant, but provided as a method to
39
+ # return the constant from the current class, not the superclass.
40
+ #
41
+ # @return [Hash] A hash mapping size names to their corresponding CSS
42
+ # classes.
43
+ def sizes
44
+ const_get(:SIZES)
45
+ end
46
+
47
+ # rubocop:disable Layout/LineLength
48
+ def styles
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"]
54
+ )
55
+ }.freeze
56
+ end
57
+ # rubocop:enable Layout/LineLength
58
+ end
59
+
60
+ def initialize(attribute:, form:, disabled: false, options: {}, size: :default)
61
+ @attribute = attribute
62
+ @disabled = disabled
63
+ @form = form
64
+ @options = options || {}
65
+ @object = form.object
66
+ @size = size
67
+ end
68
+
69
+ # Returns the HTML to use for the actual input field element.
70
+ def call
71
+ @form.send(
72
+ input_field_type,
73
+ @attribute,
74
+ **input_options
75
+ )
76
+ end
77
+
78
+ # Returns the CSS classes to apply to the input field
79
+ def classes
80
+ self.class.classes(size: size, state: state)
81
+ end
82
+
83
+ # Returns the name of the method used to generate HTML for the input field
84
+ def input_field_type
85
+ :text_field
86
+ end
87
+
88
+ protected
89
+
90
+ # Returns true if the field is disabled
91
+ def disabled?
92
+ !!@disabled
93
+ end
94
+
95
+ def errors?
96
+ @object.errors.include?(@attribute.intern)
97
+ end
98
+
99
+ private
100
+
101
+ # Returns the options argument for the input field
102
+ def input_options
103
+ {
104
+ class: classes,
105
+ disabled: disabled?
106
+ }.merge(options)
107
+ end
108
+
109
+ def state
110
+ return DISABLED if disabled?
111
+ return ERROR if errors?
112
+
113
+ DEFAULT
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ module Input
5
+ class File < Field
6
+ SIZES = {
7
+ sm: ["text-xs"],
8
+ default: ["text-sm"],
9
+ lg: ["text-lg"]
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: Flowbite::Style.new(
21
+ default: ["block", "w-full", "text-gray-900", "border", "border-gray-300", "rounded-lg", "cursor-pointer", "bg-gray-50", "focus:outline-none", "dark:text-gray-400", "dark:bg-gray-700", "dark:border-gray-600"],
22
+ disabled: ["block", "w-full", "text-gray-400", "border", "border-gray-300", "rounded-lg", "cursor-not-allowed", "bg-gray-100", "dark:text-gray-500", "dark:bg-gray-600", "dark:border-gray-500"],
23
+ error: ["block", "w-full", "text-red-900", "border", "border-red-500", "rounded-lg", "cursor-pointer", "bg-red-50", "focus:outline-none", "dark:text-red-400", "dark:bg-gray-700", "dark:border-red-500"]
24
+ )
25
+ }.freeze
26
+ end
27
+ # rubocop:enable Layout/LineLength
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ module Input
5
+ class Hint < ViewComponent::Base
6
+ STATES = [
7
+ DEFAULT = :default
8
+ ].freeze
9
+
10
+ class << self
11
+ def classes(state: :default, style: :default)
12
+ style = styles.fetch(style)
13
+ style.fetch(state)
14
+ end
15
+
16
+ def styles
17
+ {
18
+ default: Flowbite::Style.new(
19
+ default: ["mt-2", "text-sm", "text-gray-500", "dark:text-gray-400"]
20
+ )
21
+ }.freeze
22
+ end
23
+ end
24
+
25
+ def call
26
+ tag.p(
27
+ content,
28
+ class: classes,
29
+ **@options
30
+ )
31
+ end
32
+
33
+ def initialize(attribute:, form:, options: {})
34
+ @attribute = attribute
35
+ @form = form
36
+ @options = options
37
+ @object = form.object
38
+ end
39
+
40
+ # Returns an array with the CSS classes to apply to the label element
41
+ def classes
42
+ self.class.classes(state: state)
43
+ end
44
+
45
+ protected
46
+
47
+ # Returns the state of the label.
48
+ #
49
+ # See the STATES constant for valid values.
50
+ #
51
+ # @return [Symbol] the state of the label
52
+ def state
53
+ DEFAULT
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ module Input
5
+ # https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-label
6
+ class Label < ViewComponent::Base
7
+ STATES = [
8
+ DEFAULT = :default,
9
+ DISABLED = :disabled,
10
+ ERROR = :error
11
+ ].freeze
12
+
13
+ class << self
14
+ def classes(state: :default, style: :default)
15
+ style = styles.fetch(style)
16
+ style.fetch(state)
17
+ end
18
+
19
+ def styles
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"]
25
+ )
26
+ }.freeze
27
+ end
28
+ end
29
+
30
+ def call
31
+ if content?
32
+ @form.label(@attribute, content, **options)
33
+ else
34
+ @form.label(@attribute, **options)
35
+ end
36
+ end
37
+
38
+ def errors?
39
+ @object.errors.include?(@attribute.intern)
40
+ end
41
+
42
+ def initialize(attribute:, form:, disabled: false, options: {})
43
+ @attribute = attribute
44
+ @disabled = disabled
45
+ @form = form
46
+ @object = form.object
47
+ @options = options
48
+ end
49
+
50
+ # Returns an array with the CSS classes to apply to the label element
51
+ def classes
52
+ self.class.classes(state: state)
53
+ end
54
+
55
+ protected
56
+
57
+ def disabled?
58
+ !!@disabled
59
+ end
60
+
61
+ # Returns the state of the label.
62
+ #
63
+ # See the STATES constant for valid values.
64
+ #
65
+ # @return [Symbol] the state of the label
66
+ def state
67
+ return DISABLED if disabled?
68
+ return ERROR if errors?
69
+
70
+ DEFAULT
71
+ end
72
+
73
+ private
74
+
75
+ def options
76
+ {
77
+ class: classes
78
+ }.merge(@options)
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ module Input
5
+ class Number < Field
6
+ def input_field_type
7
+ :number_field
8
+ end
9
+ end
10
+ end
11
+ end