uchi 0.1.2 → 0.1.4
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.
- checksums.yaml +4 -4
- data/README.md +222 -0
- data/app/assets/config/uchi_manifest.js +2 -0
- data/app/assets/javascripts/uchi/application.js +6095 -0
- data/app/assets/javascripts/uchi.js +4 -0
- data/app/assets/stylesheets/uchi/application.css +3971 -0
- data/app/assets/stylesheets/uchi/uchi.css +17 -0
- data/app/assets/tailwind/uchi.css +21 -0
- data/app/components/flowbite/breadcrumb.rb +33 -0
- data/app/components/flowbite/breadcrumb_home.rb +26 -0
- data/app/components/flowbite/breadcrumb_item/current.rb +33 -0
- data/app/components/flowbite/breadcrumb_item/first.rb +35 -0
- data/app/components/flowbite/breadcrumb_item.rb +48 -0
- data/app/components/flowbite/breadcrumb_separator.rb +30 -0
- data/app/components/flowbite/button/outline.rb +22 -0
- data/app/components/flowbite/button/pill.rb +40 -0
- data/app/components/flowbite/button.rb +92 -0
- data/app/components/flowbite/card.rb +45 -0
- data/app/components/flowbite/input/checkbox.rb +73 -0
- data/app/components/flowbite/input/date.rb +11 -0
- data/app/components/flowbite/input/date_time.rb +11 -0
- data/app/components/flowbite/input/email.rb +12 -0
- data/app/components/flowbite/input/field.rb +117 -0
- data/app/components/flowbite/input/file.rb +30 -0
- data/app/components/flowbite/input/hint.rb +57 -0
- data/app/components/flowbite/input/label.rb +82 -0
- data/app/components/flowbite/input/number.rb +11 -0
- data/app/components/flowbite/input/password.rb +11 -0
- data/app/components/flowbite/input/phone.rb +11 -0
- data/app/components/flowbite/input/radio_button.rb +50 -0
- data/app/components/flowbite/input/select.rb +49 -0
- data/app/components/flowbite/input/textarea.rb +42 -0
- data/app/components/flowbite/input/url.rb +12 -0
- data/app/components/flowbite/input/validation_error.rb +11 -0
- data/app/components/flowbite/input_field/checkbox.html.erb +14 -0
- data/app/components/flowbite/input_field/checkbox.rb +54 -0
- data/app/components/flowbite/input_field/date.rb +13 -0
- data/app/components/flowbite/input_field/date_time.rb +13 -0
- data/app/components/flowbite/input_field/email.rb +13 -0
- data/app/components/flowbite/input_field/file.rb +13 -0
- data/app/components/flowbite/input_field/input_field.html.erb +8 -0
- data/app/components/flowbite/input_field/number.rb +13 -0
- data/app/components/flowbite/input_field/password.rb +13 -0
- data/app/components/flowbite/input_field/phone.rb +13 -0
- data/app/components/flowbite/input_field/radio_button.html.erb +14 -0
- data/app/components/flowbite/input_field/radio_button.rb +86 -0
- data/app/components/flowbite/input_field/select.rb +31 -0
- data/app/components/flowbite/input_field/text.rb +8 -0
- data/app/components/flowbite/input_field/textarea.rb +13 -0
- data/app/components/flowbite/input_field/url.rb +13 -0
- data/app/components/flowbite/input_field.rb +192 -0
- data/app/components/flowbite/link.rb +21 -0
- data/app/components/flowbite/style.rb +13 -0
- data/app/components/flowbite/toast/icon.html.erb +5 -0
- data/app/components/flowbite/toast/icon.rb +57 -0
- data/app/components/flowbite/toast/toast.html.erb +11 -0
- data/app/components/flowbite/toast.rb +34 -0
- data/app/components/uchi/field/base.rb +57 -0
- data/app/components/uchi/field/belongs_to/edit.html.erb +1 -0
- data/app/components/uchi/field/belongs_to/index.html.erb +1 -0
- data/app/components/uchi/field/belongs_to/show.html.erb +3 -0
- data/app/components/uchi/field/belongs_to.rb +105 -0
- data/app/components/uchi/field/blank/edit.html.erb +1 -0
- data/app/components/uchi/field/blank/index.html.erb +1 -0
- data/app/components/uchi/field/blank/show.html.erb +1 -0
- data/app/components/uchi/field/blank.rb +16 -0
- data/app/components/uchi/field/boolean/edit.html.erb +1 -0
- data/app/components/uchi/field/boolean/index.html.erb +9 -0
- data/app/components/uchi/field/boolean/show.html.erb +9 -0
- data/app/components/uchi/field/boolean.rb +27 -0
- data/app/components/uchi/field/date/edit.html.erb +1 -0
- data/app/components/uchi/field/date/index.html.erb +1 -0
- data/app/components/uchi/field/date/show.html.erb +1 -0
- data/app/components/uchi/field/date.rb +27 -0
- data/app/components/uchi/field/date_time/edit.html.erb +1 -0
- data/app/components/uchi/field/date_time/index.html.erb +1 -0
- data/app/components/uchi/field/date_time/show.html.erb +1 -0
- data/app/components/uchi/field/date_time.rb +27 -0
- data/app/components/uchi/field/file/edit.html.erb +1 -0
- data/app/components/uchi/field/file/index.html.erb +6 -0
- data/app/components/uchi/field/file/show.html.erb +8 -0
- data/app/components/uchi/field/file.rb +37 -0
- data/app/components/uchi/field/has_and_belongs_to_many/edit.html.erb +9 -0
- data/app/components/uchi/field/has_and_belongs_to_many/index.html.erb +1 -0
- data/app/components/uchi/field/has_and_belongs_to_many/show.html.erb +28 -0
- data/app/components/uchi/field/has_and_belongs_to_many.rb +131 -0
- data/app/components/uchi/field/has_many/edit.html.erb +1 -0
- data/app/components/uchi/field/has_many/index.html.erb +1 -0
- data/app/components/uchi/field/has_many/show.html.erb +28 -0
- data/app/components/uchi/field/has_many.rb +107 -0
- data/app/components/uchi/field/id/index.html.erb +4 -0
- data/app/components/uchi/field/id/show.html.erb +4 -0
- data/app/components/uchi/field/id.rb +26 -0
- data/app/components/uchi/field/image/edit.html.erb +1 -0
- data/app/components/uchi/field/image/index.html.erb +6 -0
- data/app/components/uchi/field/image/show.html.erb +6 -0
- data/app/components/uchi/field/image.rb +38 -0
- data/app/components/uchi/field/number/edit.html.erb +1 -0
- data/app/components/uchi/field/number/index.html.erb +1 -0
- data/app/components/uchi/field/number/show.html.erb +1 -0
- data/app/components/uchi/field/number.rb +32 -0
- data/app/components/uchi/field/string/edit.html.erb +1 -0
- data/app/components/uchi/field/string/index.html.erb +1 -0
- data/app/components/uchi/field/string/show.html.erb +1 -0
- data/app/components/uchi/field/string.rb +33 -0
- data/app/components/uchi/field/text/edit.html.erb +1 -0
- data/app/components/uchi/field/text/index.html.erb +1 -0
- data/app/components/uchi/field/text/show.html.erb +1 -0
- data/app/components/uchi/field/text.rb +38 -0
- data/app/components/uchi/ui/breadcrumb/breadcrumb.html.erb +13 -0
- data/app/components/uchi/ui/breadcrumb.rb +14 -0
- data/app/components/uchi/ui/form/footer/footer.html.erb +5 -0
- data/app/components/uchi/ui/form/footer.rb +15 -0
- data/app/components/uchi/ui/form/input/collection_checkboxes.html.erb +32 -0
- data/app/components/uchi/ui/form/input/collection_checkboxes.rb +125 -0
- data/app/components/uchi/ui/frame/frame.html.erb +3 -0
- data/app/components/uchi/ui/frame.rb +10 -0
- data/app/components/uchi/ui/index/records_table/records_table.html.erb +67 -0
- data/app/components/uchi/ui/index/records_table/search_form/search_form.html.erb +21 -0
- data/app/components/uchi/ui/index/records_table/search_form.rb +49 -0
- data/app/components/uchi/ui/index/records_table.rb +29 -0
- data/app/components/uchi/ui/index/turbo_frame.rb +50 -0
- data/app/components/uchi/ui/page_header/page_header.html.erb +24 -0
- data/app/components/uchi/ui/page_header.rb +18 -0
- data/app/components/uchi/ui/pagination/current_link.html.erb +3 -0
- data/app/components/uchi/ui/pagination/current_link.rb +10 -0
- data/app/components/uchi/ui/pagination/gap.html.erb +3 -0
- data/app/components/uchi/ui/pagination/gap.rb +10 -0
- data/app/components/uchi/ui/pagination/item.rb +24 -0
- data/app/components/uchi/ui/pagination/link.html.erb +3 -0
- data/app/components/uchi/ui/pagination/link.rb +10 -0
- data/app/components/uchi/ui/pagination/next_link.html.erb +8 -0
- data/app/components/uchi/ui/pagination/next_link.rb +22 -0
- data/app/components/uchi/ui/pagination/pagination.html.erb +15 -0
- data/app/components/uchi/ui/pagination/previous_link.html.erb +8 -0
- data/app/components/uchi/ui/pagination/previous_link.rb +22 -0
- data/app/components/uchi/ui/pagination.rb +48 -0
- data/app/components/uchi/ui/show/attribute_fields/attribute_fields.html.erb +14 -0
- data/app/components/uchi/ui/show/attribute_fields.rb +18 -0
- data/app/components/uchi/ui/spinner/spinner.html.erb +7 -0
- data/app/components/uchi/ui/spinner.rb +15 -0
- data/app/controllers/uchi/application_controller.rb +4 -0
- data/app/controllers/uchi/controller.rb +13 -0
- data/app/controllers/uchi/repository_controller.rb +166 -0
- data/app/helpers/uchi/application_helper.rb +17 -0
- data/app/jobs/uchi/application_job.rb +4 -0
- data/app/mailers/uchi/application_mailer.rb +6 -0
- data/app/views/layouts/uchi/_flash_messages.html.erb +10 -0
- data/app/views/layouts/uchi/application.html.erb +33 -0
- data/app/views/uchi/repository/edit.html.erb +40 -0
- data/app/views/uchi/repository/index.html.erb +49 -0
- data/app/views/uchi/repository/new.html.erb +37 -0
- data/app/views/uchi/repository/show.html.erb +41 -0
- data/lib/generators/uchi/controller/controller_generator.rb +16 -0
- data/lib/generators/uchi/controller/templates/controller.rb.tt +11 -0
- data/lib/generators/uchi/install/install_generator.rb +13 -0
- data/lib/generators/uchi/repository/repository_generator.rb +16 -0
- data/lib/generators/uchi/repository/templates/repository.rb.tt +11 -0
- data/lib/tasks/uchi_tasks.rake +4 -0
- data/lib/uchi/application_record.rb +5 -0
- data/lib/uchi/engine.rb +24 -0
- data/lib/uchi/field/configuration.rb +142 -0
- data/lib/uchi/field.rb +80 -0
- data/lib/uchi/i18n.rb +13 -0
- data/lib/uchi/pagination/controller.rb +26 -0
- data/lib/uchi/pagination/page.rb +20 -0
- data/lib/uchi/pagy/LICENSE.txt +21 -0
- data/lib/uchi/pagy/classes/exceptions.rb +35 -0
- data/lib/uchi/pagy/classes/offset/offset.rb +56 -0
- data/lib/uchi/pagy/classes/request.rb +38 -0
- data/lib/uchi/pagy/modules/abilities/configurable.rb +38 -0
- data/lib/uchi/pagy/modules/abilities/linkable.rb +62 -0
- data/lib/uchi/pagy/modules/abilities/rangeable.rb +17 -0
- data/lib/uchi/pagy/modules/abilities/shiftable.rb +14 -0
- data/lib/uchi/pagy/modules/console.rb +40 -0
- data/lib/uchi/pagy/toolbox/helpers/loader.rb +19 -0
- data/lib/uchi/pagy/toolbox/helpers/page_url.rb +25 -0
- data/lib/uchi/pagy/toolbox/paginators/method.rb +21 -0
- data/lib/uchi/pagy/toolbox/paginators/offset.rb +35 -0
- data/lib/uchi/pagy.rb +60 -0
- data/lib/uchi/repository/routes.rb +62 -0
- data/lib/uchi/repository/translate.rb +284 -0
- data/lib/uchi/repository.rb +156 -0
- data/lib/uchi/sort_order.rb +35 -0
- data/lib/uchi/version.rb +5 -0
- data/lib/uchi.rb +18 -0
- data/uchi.gemspec +35 -0
- metadata +197 -107
- data/.github/dependabot.yml +0 -17
- data/.github/workflows/build.yml +0 -23
- data/.github/workflows/lint.yml +0 -30
- data/package.json +0 -31
- data/sig/uchi.rbs +0 -4
- data/test/components/uchi/field/belongs_to_test.rb +0 -134
- data/test/components/uchi/field/blank_test.rb +0 -119
- data/test/components/uchi/field/boolean_test.rb +0 -163
- data/test/components/uchi/field/date_test.rb +0 -163
- data/test/components/uchi/field/date_time_test.rb +0 -152
- data/test/components/uchi/field/has_many_test.rb +0 -138
- data/test/components/uchi/field/id_test.rb +0 -113
- data/test/components/uchi/field/number_test.rb +0 -163
- data/test/components/uchi/field/string_test.rb +0 -159
- data/test/controllers/uchi/authors_controller_test.rb +0 -119
- data/test/controllers/uchi/repository_controller_test.rb +0 -93
- data/test/controllers/uchi/scoped_repository_controller_test.rb +0 -73
- data/test/dummy/Rakefile +0 -6
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/stylesheets/application.css +0 -15
- data/test/dummy/app/controllers/application_controller.rb +0 -4
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/controllers/uchi/authors_controller.rb +0 -7
- data/test/dummy/app/controllers/uchi/books_controller.rb +0 -7
- data/test/dummy/app/controllers/uchi/titles_controller.rb +0 -7
- data/test/dummy/app/helpers/application_helper.rb +0 -2
- data/test/dummy/app/jobs/application_job.rb +0 -7
- data/test/dummy/app/mailers/application_mailer.rb +0 -4
- data/test/dummy/app/models/application_record.rb +0 -3
- data/test/dummy/app/models/author.rb +0 -3
- data/test/dummy/app/models/book.rb +0 -3
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/models/title.rb +0 -3
- data/test/dummy/app/uchi/repositories/author.rb +0 -20
- data/test/dummy/app/uchi/repositories/book.rb +0 -16
- data/test/dummy/app/uchi/repositories/title.rb +0 -17
- data/test/dummy/app/views/layouts/application.html.erb +0 -27
- data/test/dummy/app/views/layouts/mailer.html.erb +0 -13
- data/test/dummy/app/views/layouts/mailer.text.erb +0 -1
- data/test/dummy/app/views/pwa/manifest.json.erb +0 -22
- data/test/dummy/app/views/pwa/service-worker.js +0 -26
- data/test/dummy/bin/dev +0 -2
- data/test/dummy/bin/rails +0 -4
- data/test/dummy/bin/rake +0 -4
- data/test/dummy/bin/setup +0 -34
- data/test/dummy/config/application.rb +0 -29
- data/test/dummy/config/boot.rb +0 -5
- data/test/dummy/config/cable.yml +0 -10
- data/test/dummy/config/database.yml +0 -32
- data/test/dummy/config/environment.rb +0 -5
- data/test/dummy/config/environments/development.rb +0 -69
- data/test/dummy/config/environments/production.rb +0 -89
- data/test/dummy/config/environments/test.rb +0 -53
- data/test/dummy/config/initializers/content_security_policy.rb +0 -25
- data/test/dummy/config/initializers/filter_parameter_logging.rb +0 -8
- data/test/dummy/config/initializers/inflections.rb +0 -16
- data/test/dummy/config/locales/da.yml +0 -51
- data/test/dummy/config/locales/en.yml +0 -31
- data/test/dummy/config/puma.rb +0 -38
- data/test/dummy/config/routes.rb +0 -9
- data/test/dummy/config/storage.yml +0 -34
- data/test/dummy/config.ru +0 -6
- data/test/dummy/db/migrate/20251002183635_create_authors.rb +0 -11
- data/test/dummy/db/migrate/20251005131726_create_books.rb +0 -9
- data/test/dummy/db/migrate/20251005131811_create_titles.rb +0 -11
- data/test/dummy/db/schema.rb +0 -38
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/public/400.html +0 -114
- data/test/dummy/public/404.html +0 -114
- data/test/dummy/public/406-unsupported-browser.html +0 -114
- data/test/dummy/public/422.html +0 -114
- data/test/dummy/public/500.html +0 -114
- data/test/dummy/public/icon.png +0 -0
- data/test/dummy/public/icon.svg +0 -3
- data/test/dummy/storage/.keep +0 -0
- data/test/dummy/test/fixtures/authors.yml +0 -11
- data/test/dummy/test/models/author_test.rb +0 -7
- data/test/dummy/tmp/.keep +0 -0
- data/test/dummy/tmp/pids/.keep +0 -0
- data/test/dummy/tmp/storage/.keep +0 -0
- data/test/test_helper.rb +0 -15
- data/test/uchi/field_test.rb +0 -63
- data/test/uchi/i18n_test.rb +0 -18
- data/test/uchi/repository/routes_test.rb +0 -49
- data/test/uchi/repository/translate_test.rb +0 -263
- data/test/uchi/repository_test.rb +0 -137
- data/test/uchi/sort_order_test.rb +0 -47
- data/test/uchi_test.rb +0 -7
|
@@ -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,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Flowbite
|
|
4
|
+
module Input
|
|
5
|
+
# The radio button component can be used to allow the user to choose a
|
|
6
|
+
# single option from one or more available options.
|
|
7
|
+
#
|
|
8
|
+
# https://flowbite.com/docs/forms/radio/
|
|
9
|
+
class RadioButton < Field
|
|
10
|
+
class << self
|
|
11
|
+
# Radio buttons only have their default size.
|
|
12
|
+
def sizes
|
|
13
|
+
{
|
|
14
|
+
default: ["w-4", "h-4"]
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# rubocop:disable Layout/LineLength
|
|
19
|
+
def styles
|
|
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"]
|
|
25
|
+
)
|
|
26
|
+
}.freeze
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Returns the HTML to use for the actual input field element.
|
|
31
|
+
def call
|
|
32
|
+
@form.send(
|
|
33
|
+
input_field_type,
|
|
34
|
+
@attribute,
|
|
35
|
+
@value,
|
|
36
|
+
**input_options
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def initialize(attribute:, form:, value:, disabled: false, options: {})
|
|
41
|
+
super(attribute: attribute, disabled: disabled, form: form, options: options)
|
|
42
|
+
@value = value
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def input_field_type
|
|
46
|
+
:radio_button
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Flowbite
|
|
4
|
+
module Input
|
|
5
|
+
# The `Select` component renders a select input field for use in forms.
|
|
6
|
+
#
|
|
7
|
+
# https://flowbite.com/docs/forms/select/
|
|
8
|
+
#
|
|
9
|
+
# Wraps `ActionView::Helpers::FormOptionsHelper#select`: https://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-select
|
|
10
|
+
class Select < Field
|
|
11
|
+
SIZES = {
|
|
12
|
+
sm: ["p-2", "text-xs"],
|
|
13
|
+
default: ["p-2.5", "text-sm"],
|
|
14
|
+
lg: ["px-4", "py-3", "text-base"]
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
def initialize(form:, attribute:, collection: [], disabled: false, options: {}, size: :default)
|
|
18
|
+
super(form: form, attribute: attribute, disabled: disabled, options: options, size: size)
|
|
19
|
+
@collection = collection
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Returns the HTML to use for the actual input field element.
|
|
23
|
+
def call
|
|
24
|
+
@form.send(
|
|
25
|
+
input_field_type,
|
|
26
|
+
@attribute,
|
|
27
|
+
@collection,
|
|
28
|
+
{},
|
|
29
|
+
html_options
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns the name of the method used to generate HTML for the input field
|
|
34
|
+
def input_field_type
|
|
35
|
+
:select
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
# Returns the html_options argument for the select method
|
|
41
|
+
def html_options
|
|
42
|
+
{
|
|
43
|
+
class: classes,
|
|
44
|
+
disabled: disabled?
|
|
45
|
+
}.merge(options)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Flowbite
|
|
4
|
+
module Input
|
|
5
|
+
class Textarea < Field
|
|
6
|
+
class << self
|
|
7
|
+
# rubocop:disable Layout/LineLength
|
|
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
|
|
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)
|
|
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
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<div class="flex">
|
|
2
|
+
<div class="flex items-center h-5">
|
|
3
|
+
<%= input %>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<div class="ms-2 text-sm">
|
|
7
|
+
<%= label %>
|
|
8
|
+
<%= hint %>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<% errors.each do |error| %>
|
|
12
|
+
<%= render(Flowbite::Input::ValidationError.new) { error.upcase_first } %>
|
|
13
|
+
<% end %>
|
|
14
|
+
</div>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Flowbite
|
|
4
|
+
class InputField
|
|
5
|
+
class Checkbox < InputField
|
|
6
|
+
protected
|
|
7
|
+
|
|
8
|
+
def default_hint_options
|
|
9
|
+
return {} unless @hint
|
|
10
|
+
|
|
11
|
+
{
|
|
12
|
+
class: hint_classes,
|
|
13
|
+
id: id_for_hint_element
|
|
14
|
+
}.merge(@hint[:options] || {})
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def default_label_options
|
|
18
|
+
options = super
|
|
19
|
+
options[:options] ||= {}
|
|
20
|
+
options[:options][:class] = options.dig(:options, :class) || label_classes
|
|
21
|
+
options
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def input_component
|
|
25
|
+
::Flowbite::Input::Checkbox
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def hint_classes
|
|
31
|
+
if disabled?
|
|
32
|
+
"text-xs font-normal text-gray-400 dark:text-gray-500"
|
|
33
|
+
else
|
|
34
|
+
"text-xs font-normal text-gray-500 dark:text-gray-300"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def input_arguments
|
|
39
|
+
args = super
|
|
40
|
+
args[:unchecked_value] = @input[:unchecked_value] if @input.key?(:unchecked_value)
|
|
41
|
+
args[:value] = @input[:value] if @input.key?(:value)
|
|
42
|
+
args
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def label_classes
|
|
46
|
+
if disabled?
|
|
47
|
+
"font-medium text-gray-400 dark:text-gray-500"
|
|
48
|
+
else
|
|
49
|
+
"font-medium text-gray-900 dark:text-gray-300"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|