diff --git a/CHANGELOG.md b/CHANGELOG.md index aca3930..65f4c21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). * Flowbite::Link component to render links. * Flowbite::Card now displays a title via the title argument/slot. +* Improved error message when an unknown style is requested. ### Changed diff --git a/app/components/flowbite/button.rb b/app/components/flowbite/button.rb index 7cdbd8d..1a21418 100644 --- a/app/components/flowbite/button.rb +++ b/app/components/flowbite/button.rb @@ -31,32 +31,34 @@ def sizes # rubocop:disable Layout/LineLength def styles - { - danger: Flowbite::Style.new( - default: ["focus:outline-none", "text-white", "bg-danger", "box-border", "border", "border-transparent", "hover:bg-danger-strong", "focus:ring-4", "focus:ring-danger-medium", "shadow-xs", "font-medium", "leading-5", "rounded-base"] - ), - dark: Flowbite::Style.new( - default: ["focus:outline-none", "text-white", "bg-dark", "box-border", "border", "border-transparent", "hover:bg-dark-strong", "focus:ring-4", "focus:ring-neutral-tertiary", "shadow-xs", "font-medium", "leading-5", "rounded-base"] - ), - default: Flowbite::Style.new( - default: ["focus:outline-none", "text-white", "bg-brand", "box-border", "border", "border-transparent", "hover:bg-brand-strong", "focus:ring-4", "focus:ring-brand-medium", "shadow-xs", "font-medium", "leading-5", "rounded-base"] - ), - ghost: Flowbite::Style.new( - default: ["focus:outline-none", "text-heading", "bg-transparent", "box-border", "border", "border-transparent", "hover:bg-neutral-secondary-medium", "focus:ring-4", "focus:ring-neutral-tertiary", "font-medium", "leading-5", "rounded-base"] - ), - secondary: Flowbite::Style.new( - default: ["focus:outline-none", "text-body", "bg-neutral-secondary-medium", "box-border", "border", "border-default-medium", "hover:bg-neutral-tertiary-medium", "focus:ring-4", "focus:ring-neutral-tertiary", "shadow-xs", "font-medium", "leading-5", "rounded-base"] - ), - success: Flowbite::Style.new( - default: ["focus:outline-none", "text-white", "bg-success", "box-border", "border", "border-transparent", "hover:bg-success-strong", "focus:ring-4", "focus:ring-success-medium", "shadow-xs", "font-medium", "leading-5", "rounded-base"] - ), - tertiary: Flowbite::Style.new( - default: ["focus:outline-none", "text-body", "bg-neutral-primary-soft", "box-border", "border", "border-default", "hover:bg-neutral-secondary-medium", "focus:ring-4", "focus:ring-neutral-tertiary-soft", "shadow-xs", "font-medium", "leading-5", "rounded-base"] - ), - warning: Flowbite::Style.new( - default: ["focus:outline-none", "text-white", "bg-warning", "box-border", "border", "border-transparent", "hover:bg-warning-strong", "focus:ring-4", "focus:ring-warning-medium", "shadow-xs", "font-medium", "leading-5", "rounded-base"] - ) - }.freeze + Flowbite::Styles.from_hash( + { + danger: { + default: ["focus:outline-none", "text-white", "bg-danger", "box-border", "border", "border-transparent", "hover:bg-danger-strong", "focus:ring-4", "focus:ring-danger-medium", "shadow-xs", "font-medium", "leading-5", "rounded-base"] + }, + dark: { + default: ["focus:outline-none", "text-white", "bg-dark", "box-border", "border", "border-transparent", "hover:bg-dark-strong", "focus:ring-4", "focus:ring-neutral-tertiary", "shadow-xs", "font-medium", "leading-5", "rounded-base"] + }, + default: { + default: ["focus:outline-none", "text-white", "bg-brand", "box-border", "border", "border-transparent", "hover:bg-brand-strong", "focus:ring-4", "focus:ring-brand-medium", "shadow-xs", "font-medium", "leading-5", "rounded-base"] + }, + ghost: { + default: ["focus:outline-none", "text-heading", "bg-transparent", "box-border", "border", "border-transparent", "hover:bg-neutral-secondary-medium", "focus:ring-4", "focus:ring-neutral-tertiary", "font-medium", "leading-5", "rounded-base"] + }, + secondary: { + default: ["focus:outline-none", "text-body", "bg-neutral-secondary-medium", "box-border", "border", "border-default-medium", "hover:bg-neutral-tertiary-medium", "focus:ring-4", "focus:ring-neutral-tertiary", "shadow-xs", "font-medium", "leading-5", "rounded-base"] + }, + success: { + default: ["focus:outline-none", "text-white", "bg-success", "box-border", "border", "border-transparent", "hover:bg-success-strong", "focus:ring-4", "focus:ring-success-medium", "shadow-xs", "font-medium", "leading-5", "rounded-base"] + }, + tertiary: { + default: ["focus:outline-none", "text-body", "bg-neutral-primary-soft", "box-border", "border", "border-default", "hover:bg-neutral-secondary-medium", "focus:ring-4", "focus:ring-neutral-tertiary-soft", "shadow-xs", "font-medium", "leading-5", "rounded-base"] + }, + warning: { + default: ["focus:outline-none", "text-white", "bg-warning", "box-border", "border", "border-transparent", "hover:bg-warning-strong", "focus:ring-4", "focus:ring-warning-medium", "shadow-xs", "font-medium", "leading-5", "rounded-base"] + } + }.freeze + ) end # rubocop:enable Layout/LineLength end diff --git a/app/components/flowbite/button/outline.rb b/app/components/flowbite/button/outline.rb index eb30584..8deea3c 100644 --- a/app/components/flowbite/button/outline.rb +++ b/app/components/flowbite/button/outline.rb @@ -6,29 +6,29 @@ class Outline < Flowbite::Button class << self # rubocop:disable Layout/LineLength, Metrics/MethodLength def styles - { - danger: Flowbite::Style.new( + Flowbite::Styles.from_hash({ + danger: { default: ["focus:outline-none", "text-danger", "bg-transparent", "box-border", "border", "border-danger", "hover:text-white", "hover:bg-danger-strong", "focus:ring-4", "focus:ring-danger-medium", "shadow-xs", "font-medium", "leading-5", "rounded-base", "text-center", "me-2", "mb-2"] - ), - dark: Flowbite::Style.new( + }, + dark: { default: ["focus:outline-none", "text-dark", "bg-transparent", "box-border", "border", "border-dark", "hover:text-white", "hover:bg-dark-strong", "focus:ring-4", "focus:ring-neutral-tertiary", "shadow-xs", "font-medium", "leading-5", "rounded-base", "text-center", "me-2", "mb-2"] - ), - default: Flowbite::Style.new( + }, + default: { default: ["focus:outline-none", "text-brand", "bg-transparent", "box-border", "border", "border-brand", "hover:text-white", "hover:bg-brand-strong", "focus:ring-4", "focus:ring-brand-medium", "shadow-xs", "font-medium", "leading-5", "rounded-base", "text-center", "me-2", "mb-2"] - ), - secondary: Flowbite::Style.new( + }, + secondary: { default: ["focus:outline-none", "text-body", "bg-transparent", "box-border", "border", "border-default-medium", "hover:bg-neutral-tertiary-medium", "focus:ring-4", "focus:ring-neutral-tertiary", "shadow-xs", "font-medium", "leading-5", "rounded-base", "text-center", "me-2", "mb-2"] - ), - success: Flowbite::Style.new( + }, + success: { default: ["focus:outline-none", "text-success", "bg-transparent", "box-border", "border", "border-success", "hover:text-white", "hover:bg-success-strong", "focus:ring-4", "focus:ring-success-medium", "shadow-xs", "font-medium", "leading-5", "rounded-base", "text-center", "me-2", "mb-2"] - ), - tertiary: Flowbite::Style.new( + }, + tertiary: { default: ["focus:outline-none", "text-body", "bg-transparent", "box-border", "border", "border-default", "hover:bg-neutral-secondary-medium", "focus:ring-4", "focus:ring-neutral-tertiary-soft", "shadow-xs", "font-medium", "leading-5", "rounded-base", "text-center", "me-2", "mb-2"] - ), - warning: Flowbite::Style.new( + }, + warning: { default: ["focus:outline-none", "text-warning", "bg-transparent", "box-border", "border", "border-warning", "hover:text-white", "hover:bg-warning-strong", "focus:ring-4", "focus:ring-warning-medium", "shadow-xs", "font-medium", "leading-5", "rounded-base", "text-center", "me-2", "mb-2"] - ) - } + } + }.freeze) end # rubocop:enable Layout/LineLength, Metrics/MethodLength end diff --git a/app/components/flowbite/button/pill.rb b/app/components/flowbite/button/pill.rb index c7f3719..c7ea50c 100644 --- a/app/components/flowbite/button/pill.rb +++ b/app/components/flowbite/button/pill.rb @@ -6,32 +6,32 @@ class Pill < Flowbite::Button class << self # rubocop:disable Layout/LineLength, Metrics/MethodLength def styles - { - danger: Flowbite::Style.new( + Flowbite::Styles.from_hash({ + danger: { default: ["focus:outline-none", "text-white", "bg-danger", "box-border", "border", "border-transparent", "hover:bg-danger-strong", "focus:ring-4", "focus:ring-danger-medium", "shadow-xs", "font-medium", "leading-5", "rounded-full", "text-center"] - ), - dark: Flowbite::Style.new( + }, + dark: { default: ["focus:outline-none", "text-white", "bg-dark", "box-border", "border", "border-transparent", "hover:bg-dark-strong", "focus:ring-4", "focus:ring-neutral-tertiary", "shadow-xs", "font-medium", "leading-5", "rounded-full", "text-center"] - ), - default: Flowbite::Style.new( + }, + default: { default: ["focus:outline-none", "text-white", "bg-brand", "box-border", "border", "border-transparent", "hover:bg-brand-strong", "focus:ring-4", "focus:ring-brand-medium", "shadow-xs", "font-medium", "leading-5", "rounded-full", "text-center"] - ), - ghost: Flowbite::Style.new( + }, + ghost: { default: ["focus:outline-none", "text-heading", "bg-transparent", "box-border", "border", "border-transparent", "hover:bg-neutral-secondary-medium", "focus:ring-4", "focus:ring-neutral-tertiary", "font-medium", "leading-5", "rounded-full", "text-center"] - ), - secondary: Flowbite::Style.new( + }, + secondary: { default: ["focus:outline-none", "text-body", "bg-neutral-secondary-medium", "box-border", "border", "border-default-medium", "hover:bg-neutral-tertiary-medium", "focus:ring-4", "focus:ring-neutral-tertiary", "shadow-xs", "font-medium", "leading-5", "rounded-full", "text-center"] - ), - success: Flowbite::Style.new( + }, + success: { default: ["focus:outline-none", "text-white", "bg-success", "box-border", "border", "border-transparent", "hover:bg-success-strong", "focus:ring-4", "focus:ring-success-medium", "shadow-xs", "font-medium", "leading-5", "rounded-full", "text-center"] - ), - tertiary: Flowbite::Style.new( + }, + tertiary: { default: ["focus:outline-none", "text-body", "bg-neutral-primary-soft", "box-border", "border", "border-default", "hover:bg-neutral-secondary-medium", "focus:ring-4", "focus:ring-neutral-tertiary-soft", "shadow-xs", "font-medium", "leading-5", "rounded-full", "text-center"] - ), - warning: Flowbite::Style.new( + }, + warning: { default: ["focus:outline-none", "text-white", "bg-warning", "box-border", "border", "border-transparent", "hover:bg-warning-strong", "focus:ring-4", "focus:ring-warning-medium", "shadow-xs", "font-medium", "leading-5", "rounded-full", "text-center"] - ) - } + } + }.freeze) end # rubocop:enable Layout/LineLength, Metrics/MethodLength end diff --git a/app/components/flowbite/card.rb b/app/components/flowbite/card.rb index 603ce92..aff151c 100644 --- a/app/components/flowbite/card.rb +++ b/app/components/flowbite/card.rb @@ -15,11 +15,13 @@ def classes(state: :default, style: :default) # rubocop:disable Layout/LineLength def styles - { - default: Flowbite::Style.new( - default: ["p-6", "bg-neutral-primary-soft", "border", "border-default", "rounded-base", "shadow-xs"] - ) - }.freeze + Flowbite::Styles.from_hash( + { + default: { + default: ["p-6", "bg-neutral-primary-soft", "border", "border-default", "rounded-base", "shadow-xs"] + } + }.freeze + ) end # rubocop:enable Layout/LineLength end diff --git a/app/components/flowbite/card/title.rb b/app/components/flowbite/card/title.rb index 3bcea9a..625535e 100644 --- a/app/components/flowbite/card/title.rb +++ b/app/components/flowbite/card/title.rb @@ -12,11 +12,13 @@ def classes(state: :default, style: :default) # rubocop:disable Layout/LineLength def styles - { - default: Flowbite::Style.new( - default: ["mb-2", "text-2xl", "font-semibold", "tracking-tight", "text-heading"] - ) - }.freeze + Flowbite::Styles.from_hash( + { + default: { + default: ["mb-2", "text-2xl", "font-semibold", "tracking-tight", "text-heading"] + } + }.freeze + ) end # rubocop:enable Layout/LineLength end diff --git a/app/components/flowbite/input/checkbox.rb b/app/components/flowbite/input/checkbox.rb index 2dfc3d5..0f38f0d 100644 --- a/app/components/flowbite/input/checkbox.rb +++ b/app/components/flowbite/input/checkbox.rb @@ -22,13 +22,15 @@ def sizes # rubocop:disable Layout/LineLength def styles - { - default: Flowbite::Style.new( - default: ["text-brand", "bg-neutral-secondary-medium", "border-default-medium", "rounded-sm", "focus:ring-brand", "focus:ring-2"], - disabled: ["text-brand", "bg-neutral-secondary-medium", "border-default-medium", "rounded-sm", "focus:ring-brand", "focus:ring-2", "cursor-not-allowed"], - error: ["text-danger", "bg-danger-soft", "border-danger-subtle", "rounded-sm", "focus:ring-danger", "focus:ring-2"] - ) - }.freeze + Flowbite::Styles.from_hash( + { + default: { + default: ["text-brand", "bg-neutral-secondary-medium", "border-default-medium", "rounded-sm", "focus:ring-brand", "focus:ring-2"], + disabled: ["text-brand", "bg-neutral-secondary-medium", "border-default-medium", "rounded-sm", "focus:ring-brand", "focus:ring-2", "cursor-not-allowed"], + error: ["text-danger", "bg-danger-soft", "border-danger-subtle", "rounded-sm", "focus:ring-danger", "focus:ring-2"] + } + }.freeze + ) end end diff --git a/app/components/flowbite/input/field.rb b/app/components/flowbite/input/field.rb index 8fa5cd7..5c6ca68 100644 --- a/app/components/flowbite/input/field.rb +++ b/app/components/flowbite/input/field.rb @@ -46,13 +46,15 @@ def sizes # rubocop:disable Layout/LineLength def styles - { - default: Flowbite::Style.new( - 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"], - 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"], - 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"] - ) - }.freeze + Flowbite::Styles.from_hash( + { + default: { + 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"], + 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"], + 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"] + } + }.freeze + ) end # rubocop:enable Layout/LineLength end diff --git a/app/components/flowbite/input/file.rb b/app/components/flowbite/input/file.rb index eafcf1f..77414a0 100644 --- a/app/components/flowbite/input/file.rb +++ b/app/components/flowbite/input/file.rb @@ -16,13 +16,15 @@ def input_field_type # rubocop:disable Layout/LineLength def self.styles - { - default: Flowbite::Style.new( - default: ["block", "w-full", "text-heading", "border", "border-default-medium", "rounded-base", "cursor-pointer", "bg-neutral-secondary-medium", "focus:outline-none"], - disabled: ["block", "w-full", "text-fg-disabled", "border", "border-default-medium", "rounded-base", "cursor-not-allowed", "bg-neutral-secondary-medium"], - error: ["block", "w-full", "text-fg-danger-strong", "border", "border-danger-subtle", "rounded-base", "cursor-pointer", "bg-danger-soft", "focus:outline-none"] - ) - }.freeze + Flowbite::Styles.from_hash( + { + default: { + default: ["block", "w-full", "text-heading", "border", "border-default-medium", "rounded-base", "cursor-pointer", "bg-neutral-secondary-medium", "focus:outline-none"], + disabled: ["block", "w-full", "text-fg-disabled", "border", "border-default-medium", "rounded-base", "cursor-not-allowed", "bg-neutral-secondary-medium"], + error: ["block", "w-full", "text-fg-danger-strong", "border", "border-danger-subtle", "rounded-base", "cursor-pointer", "bg-danger-soft", "focus:outline-none"] + } + }.freeze + ) end # rubocop:enable Layout/LineLength end diff --git a/app/components/flowbite/input/hint.rb b/app/components/flowbite/input/hint.rb index f7128c0..5795632 100644 --- a/app/components/flowbite/input/hint.rb +++ b/app/components/flowbite/input/hint.rb @@ -14,11 +14,13 @@ def classes(state: :default, style: :default) end def styles - { - default: Flowbite::Style.new( - default: ["mt-2.5", "text-sm", "text-body"] - ) - }.freeze + Flowbite::Styles.from_hash( + { + default: { + default: ["mt-2.5", "text-sm", "text-body"] + } + }.freeze + ) end end diff --git a/app/components/flowbite/input/label.rb b/app/components/flowbite/input/label.rb index cb81dc3..f3293dd 100644 --- a/app/components/flowbite/input/label.rb +++ b/app/components/flowbite/input/label.rb @@ -17,13 +17,15 @@ def classes(state: :default, style: :default) end def styles - { - default: Flowbite::Style.new( - default: ["block", "mb-2.5", "text-sm", "font-medium", "text-heading"], - disabled: ["block", "mb-2.5", "text-sm", "font-medium", "text-fg-disabled"], - error: ["block", "mb-2.5", "text-sm", "font-medium", "text-fg-danger-strong"] - ) - }.freeze + Flowbite::Styles.from_hash( + { + default: { + default: ["block", "mb-2.5", "text-sm", "font-medium", "text-heading"], + disabled: ["block", "mb-2.5", "text-sm", "font-medium", "text-fg-disabled"], + error: ["block", "mb-2.5", "text-sm", "font-medium", "text-fg-danger-strong"] + } + }.freeze + ) end end diff --git a/app/components/flowbite/input/radio_button.rb b/app/components/flowbite/input/radio_button.rb index e600964..3d2facc 100644 --- a/app/components/flowbite/input/radio_button.rb +++ b/app/components/flowbite/input/radio_button.rb @@ -17,13 +17,15 @@ def sizes # rubocop:disable Layout/LineLength def styles - { - default: Flowbite::Style.new( - default: ["text-brand", "bg-neutral-secondary-medium", "border-default-medium", "focus:ring-brand", "focus:ring-2"], - disabled: ["text-brand", "bg-neutral-secondary-medium", "border-default-medium", "focus:ring-brand", "focus:ring-2", "cursor-not-allowed"], - error: ["text-danger", "bg-danger-soft", "border-danger-subtle", "focus:ring-danger", "focus:ring-2"] - ) - }.freeze + Flowbite::Styles.from_hash( + { + default: { + default: ["text-brand", "bg-neutral-secondary-medium", "border-default-medium", "focus:ring-brand", "focus:ring-2"], + disabled: ["text-brand", "bg-neutral-secondary-medium", "border-default-medium", "focus:ring-brand", "focus:ring-2", "cursor-not-allowed"], + error: ["text-danger", "bg-danger-soft", "border-danger-subtle", "focus:ring-danger", "focus:ring-2"] + } + }.freeze + ) end end diff --git a/app/components/flowbite/input/textarea.rb b/app/components/flowbite/input/textarea.rb index f4cb216..c29ff7e 100644 --- a/app/components/flowbite/input/textarea.rb +++ b/app/components/flowbite/input/textarea.rb @@ -6,16 +6,18 @@ class Textarea < Field class << self # rubocop:disable Layout/LineLength def styles - { - default: Flowbite::Style.new( - 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"], - 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"], - 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"] - ) - }.freeze + Flowbite::Styles.from_hash( + { + default: { + 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"], + 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"], + 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"] + } + }.freeze + ) end - # rubocop:enable Layout/LineLength end + # rubocop:enable Layout/LineLength # Returns the HTML to use for the actual input field element. def call diff --git a/app/components/flowbite/input/validation_error.rb b/app/components/flowbite/input/validation_error.rb index 5f71c22..887d23f 100644 --- a/app/components/flowbite/input/validation_error.rb +++ b/app/components/flowbite/input/validation_error.rb @@ -11,11 +11,13 @@ def classes(state: :default, style: :default) # rubocop:disable Layout/LineLength def styles - { - default: Flowbite::Style.new( - default: ["mt-2", "text-sm", "text-red-600", "dark:text-red-500"] - ) - }.freeze + Flowbite::Styles.from_hash( + { + default: { + default: ["mt-2", "text-sm", "text-red-600", "dark:text-red-500"] + } + }.freeze + ) end # rubocop:enable Layout/LineLength end diff --git a/app/components/flowbite/styles.rb b/app/components/flowbite/styles.rb new file mode 100644 index 0000000..74c91a6 --- /dev/null +++ b/app/components/flowbite/styles.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Flowbite + class Styles + class StyleNotFoundError < ::KeyError; end + + class << self + def from_hash(styles_hash) + styles = Styles.new + styles_hash.each do |style_name, states_hash| + styles.add_style(style_name, states_hash) + end + styles + end + end + + def add_style(style_name, states_hash) + @styles[style_name] = Flowbite::Style.new(states_hash) + end + + def fetch(style_name) + return @styles[style_name] if @styles.key?(style_name) + + raise \ + StyleNotFoundError, + "Style not found: #{style_name}. Available styles: " \ + "#{@styles.keys.sort.join(", ")}" + end + + def initialize + @styles = {} + end + end +end