Skip to content

Commit

Permalink
Add a low-level ui/input component
Browse files Browse the repository at this point in the history
This will represent all input shaped elements like `input`, `textarea`
and `select`.
  • Loading branch information
elia committed Sep 18, 2023
1 parent 0fe3507 commit c240f04
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 0 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions admin/app/components/solidus_admin/ui/forms/input/component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
static values = {
customValidity: String,
}

connect() {
if (this.customValidityValue)
this.element.setCustomValidity(this.customValidityValue)
}

clearCustomValidity() {
this.element.setCustomValidity('')
}
}
96 changes: 96 additions & 0 deletions admin/app/components/solidus_admin/ui/forms/input/component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# frozen_string_literal: true

class SolidusAdmin::UI::Forms::Input::Component < SolidusAdmin::BaseComponent
SIZES = {
s: "form-control-sm px-3 py-1.5 body-small",
m: "form-control-md px-3 py-1.5 body-small",
l: "form-control-lg px-3 py-1.5 body-text"
}.freeze

HEIGHTS = {
s: "h-7",
m: "h-9",
l: "h-12"
}.freeze

MULTILINE_HEIGHTS = {
s: %w[min-h-[84px]],
m: %w[min-h-[108px]],
l: %w[min-h-[144px]],
}.freeze

TYPES = Set.new(%i[
text
password
number
email
tel
url
search
color
date
datetime-local
month
week
time
]).freeze

def initialize(tag: :input, size: :m, error: nil, **attributes)
@tag = tag
@attributes = attributes
@size = size

specialized_classes = []

case @tag
when :input
specialized_classes << "form-input"
specialized_classes << HEIGHTS[size]
if @attributes[:type] && !TYPES.include?(@attributes[:type])
raise ArgumentError, "unsupported type attribute: attributes[:type]}"
end
when :textarea
specialized_classes << "form-textarea"
specialized_classes << MULTILINE_HEIGHTS[size]
when :select
if @attributes[:multiple]
specialized_classes << "form-multiselect"
specialized_classes << MULTILINE_HEIGHTS[size]
else
specialized_classes << "form-select"
specialized_classes << "bg-arrow-down-s-fill-gray-700 invalid:bg-arrow-down-s-fill-red-400 aria-invalid:bg-arrow-down-s-fill-red-400"
specialized_classes << HEIGHTS[size]
end
end

@attributes[:class] = [
%w[
w-full
text-black bg-white border border-gray-300 rounded-sm placeholder:text-gray-400
hover:border-gray-500
focus:ring focus:ring-gray-300 focus:ring-0.5 focus:bg-white focus:ring-offset-0 [&:focus-visible]:outline-none
disabled:bg-gray-50 disabled:text-gray-500 disabled:placeholder:text-gray-300 disabled:cursor-not-allowed
invalid:border-red-400 invalid:hover:border-red-400 invalid:text-red-400
aria-invalid:border-red-400 aria-invalid:hover:border-red-400 aria-invalid:text-red-400
],
SIZES[size],
specialized_classes,
@attributes[:class],
].compact.join(" ")

@error = error

raise ArgumentError, "unsupported tag: #{tag}" unless %i[input textarea select].include?(@tag)
end

def call
tag.public_send(
@tag,
content,
"data-controller": stimulus_id,
"data-#{stimulus_id}-custom-validity-value": @error.presence,
"data-action": "#{stimulus_id}#clearCustomValidity",
**@attributes
)
end
end
2 changes: 2 additions & 0 deletions admin/config/solidus_admin/tailwind.config.js.erb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ module.exports = {
},
backgroundImage: {
'arrow-right-up-line': "url('solidus_admin/arrow_right_up_line.svg')",
'arrow-down-s-fill-gray-700': "url('solidus_admin/arrow_down_s_fill_gray_700.svg')",
'arrow-down-s-fill-red-400': "url('solidus_admin/arrow_down_s_fill_red_400.svg')",
},
boxShadow: {
sm: '0px 1px 2px 0px rgba(0, 0, 0, 0.04)',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# frozen_string_literal: true

# @component "ui/forms/input"
class SolidusAdmin::UI::Forms::Input::ComponentPreview < ViewComponent::Preview
include SolidusAdmin::Preview

def overview
render_with_template
end

# @param error toggle
# @param size select { choices: [s, m, l] }
# @param value text
# @param type select :input_types
def input_playground(error: false, size: "m", value: "value", type: "text")
render component("ui/forms/input").new(
tag: :input,
type: type.to_sym,
error: error ? "There is an error" : nil,
size: size.to_sym,
value: value,
)
end

# @param error toggle
# @param size select { choices: [s, m, l] }
# @param multiple toggle
# @param rows number
# @param options number
# @param include_blank toggle
def select_playground(error: false, inlcude_blank: true, options: 3, rows: 1, size: "m")
options = (1..options).map { |i| ["Option #{i}", i] }
options.unshift(["", ""]) if inlcude_blank
options.map! { tag.option(_1, value: _2) }

render component("ui/forms/input").new(
tag: :select,
"size" => rows > 1 ? rows : nil,
error: error ? "There is an error" : nil,
size: size.to_sym,
).with_content(options.reduce(:+))
end

# @param error toggle
# @param size select { choices: [s, m, l] }
# @param content textarea
def textarea_playground(error: false, size: "m", content: "value")
render component("ui/forms/input").new(
tag: :textarea,
size: size.to_sym,
error: error ? "There is an error" : nil,
).with_content(content)
end

private

def input_types
current_component::TYPES.to_a
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<section>
<h3>Input</h3>

<div class="mb-8">
<h6 class="text-gray-500 mb-3 mt-0">Default</h6>
<%= render current_component.new(placeholder: "Placeholder") %>
</div>

<div class="mb-8">
<h6 class="text-gray-500 mb-3 mt-0">Filled</h6>
<%= render current_component.new(value: "My value") %>
</div>

<div class="mb-8">
<h6 class="text-gray-500 mb-3 mt-0">Error</h6>
<%= render current_component.new(value: "Bad value", error: "The value is wrong!") %>
</div>

<div class="mb-8">
<h6 class="text-gray-500 mb-3 mt-0">Disabled</h6>
<%= render current_component.new(placeholder: "Placeholder", disabled: true) %>
</div>

<div class="mb-8">
<h6 class="text-gray-500 mb-3 mt-0">Disabled filled</h6>
<%= render current_component.new(value: "My value", disabled: true) %>
</div>
</section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

require "spec_helper"

RSpec.describe SolidusAdmin::UI::Forms::Input::Component, type: :component do
it "renders the overview preview" do
render_preview(:overview)
render_preview(:input_playground)
render_preview(:select_playground)
render_preview(:textarea_playground)
end
end

0 comments on commit c240f04

Please sign in to comment.