Exported source
text_input = SingleValueFactory("input", "Base text_input component for <input type=\"text\"> tag or a wrapper of <input type=\"text\"> tag") # Base text_input componenttest_text_input_basic_examples ()
Test basic text_input utilities.
def test_text_input_basic_examples():
"""Test basic text_input utilities."""
# Basic text_input
assert str(text_input) == "input"
# Test with modifiers
assert str(text_input.hover) == "hover:input"
assert str(text_input.md) == "md:input"
assert str(text_input.dark) == "dark:input"
# Run the tests
test_text_input_basic_examples()test_text_input_styles_examples ()
Test text_input style variants.
test_text_input_colors_examples ()
Test text_input color variants.
def test_text_input_colors_examples():
"""Test text_input color variants."""
# All color variants
assert str(text_input_colors.neutral) == "input-neutral"
assert str(text_input_colors.primary) == "input-primary"
assert str(text_input_colors.secondary) == "input-secondary"
assert str(text_input_colors.accent) == "input-accent"
assert str(text_input_colors.info) == "input-info"
assert str(text_input_colors.success) == "input-success"
assert str(text_input_colors.warning) == "input-warning"
assert str(text_input_colors.error) == "input-error"
# With modifiers
assert str(text_input_colors.primary.hover) == "hover:input-primary"
assert str(text_input_colors.success.focus) == "focus:input-success"
# Run the tests
test_text_input_colors_examples()test_text_input_sizes_examples ()
Test text_input size variants.
def test_text_input_sizes_examples():
"""Test text_input size variants."""
assert str(text_input_sizes.xs) == "input-xs"
assert str(text_input_sizes.sm) == "input-sm"
assert str(text_input_sizes.md) == "input-md"
assert str(text_input_sizes.lg) == "input-lg"
assert str(text_input_sizes.xl) == "input-xl"
# With responsive modifiers
assert str(text_input_sizes.xs.sm) == "sm:input-xs"
assert str(text_input_sizes.lg.md) == "md:input-lg"
# Run the tests
test_text_input_sizes_examples()test_text_input_basic_fasthtml_examples ()
Test basic text input examples from daisyUI v5 documentation.
def test_text_input_basic_fasthtml_examples():
"""Test basic text input examples from daisyUI v5 documentation."""
from fasthtml.common import Input, Div
# Basic text input
basic_input = Input(
type="text",
placeholder="Type here",
cls=str(text_input)
)
assert basic_input.tag == "input"
assert basic_input.attrs['type'] == "text"
assert basic_input.attrs['placeholder'] == "Type here"
assert basic_input.attrs['class'] == "input"
# Disabled input
disabled_input = Input(
type="text",
placeholder="You can't touch this",
cls=str(text_input),
disabled=True
)
assert disabled_input.tag == "input"
assert disabled_input.attrs['disabled'] == True
assert disabled_input.attrs['placeholder'] == "You can't touch this"
assert disabled_input.attrs['class'] == "input"
# Return all elements in a Div
return Div(
basic_input,
disabled_input
)
# Run the tests
test_text_input_basic_fasthtml_examples()test_text_input_with_labels_fasthtml_examples ()
Test text input with labels from daisyUI v5 documentation.
def test_text_input_with_labels_fasthtml_examples():
"""Test text input with labels from daisyUI v5 documentation."""
from fasthtml.common import Label, Input, Span, Kbd, Div
from fasthtml.svg import Svg, G, Circle, Path, Rect
from cjm_fasthtml_tailwind.utilities.sizing import size_util, h
from cjm_fasthtml_tailwind.utilities.effects import opacity
from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import grow
from cjm_fasthtml_daisyui.components.data_display.kbd import kbd, kbd_sizes
from cjm_fasthtml_daisyui.components.data_display.badge import badge, badge_colors, badge_sizes
# Create search icon SVG
search_icon = Svg(
G(
Circle(cx="11", cy="11", r="8"),
Path(d="m21 21-4.3-4.3"),
stroke_linejoin="round",
stroke_linecap="round",
stroke_width="2.5",
fill="none",
stroke="currentColor"
),
cls=combine_classes(h("[1em]"), opacity._50),
xmlns="http://www.w3.org/2000/svg",
viewBox="0 0 24 24"
)
# Create file icon SVG
file_icon = Svg(
G(
Path(d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"),
Path(d="M14 2v4a2 2 0 0 0 2 2h4"),
stroke_linejoin="round",
stroke_linecap="round",
stroke_width="2.5",
fill="none",
stroke="currentColor"
),
cls=combine_classes(h("[1em]"), opacity._50),
xmlns="http://www.w3.org/2000/svg",
viewBox="0 0 24 24"
)
# Search input with icon and keyboard shortcuts
search_input = Label(
search_icon,
Input(
type="search",
cls=str(grow(1)),
placeholder="Search"
),
Kbd("⌘", cls=combine_classes(kbd, kbd_sizes.sm)),
Kbd("K", cls=combine_classes(kbd, kbd_sizes.sm)),
cls=str(text_input)
)
assert search_input.tag == "label"
assert search_input.attrs['class'] == "input"
assert search_input.children[0].tag == "svg" # Search icon
assert search_input.children[1].tag == "input"
assert search_input.children[1].attrs['type'] == "search"
assert search_input.children[1].attrs['class'] == "grow-1"
assert search_input.children[2].tag == "kbd"
assert "kbd" in search_input.children[2].attrs['class']
assert "kbd-sm" in search_input.children[2].attrs['class']
assert search_input.children[2].children[0] == "⌘"
assert search_input.children[3].children[0] == "K"
# File input with icon
file_input = Label(
file_icon,
Input(
type="text",
cls=str(grow),
placeholder="index.php"
),
cls=str(text_input)
)
assert file_input.tag == "label"
assert file_input.attrs['class'] == "input"
assert file_input.children[0].tag == "svg" # File icon
assert file_input.children[1].tag == "input"
assert file_input.children[1].attrs['placeholder'] == "index.php"
# Path input with text label and badge
path_input = Label(
"Path",
Input(
type="text",
cls=str(grow),
placeholder="src/app/"
),
Span("Optional", cls=combine_classes(badge, badge_colors.neutral, badge_sizes.xs)),
cls=str(text_input)
)
assert path_input.tag == "label"
assert path_input.attrs['class'] == "input"
assert path_input.children[0] == "Path"
assert path_input.children[1].tag == "input"
assert path_input.children[1].attrs['placeholder'] == "src/app/"
assert path_input.children[2].tag == "span"
assert "badge" in path_input.children[2].attrs['class']
assert "badge-neutral" in path_input.children[2].attrs['class']
assert "badge-xs" in path_input.children[2].attrs['class']
assert path_input.children[2].children[0] == "Optional"
# Return all elements in a Div
return Div(
search_input,
file_input,
path_input
)
# Run the tests
test_text_input_with_labels_fasthtml_examples()<div>
<label class="input"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="h-[1em] opacity-50"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2.5" fill="none" stroke="currentColor"><circle r="8" cx="11" cy="11"></circle><path d="m21 21-4.3-4.3"></path></g></svg> <input type="search" placeholder="Search" class="grow-1">
<kbd class="kbd kbd-sm">⌘</kbd><kbd class="kbd kbd-sm">K</kbd></label><label class="input"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="h-[1em] opacity-50"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2.5" fill="none" stroke="currentColor"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"></path><path d="M14 2v4a2 2 0 0 0 2 2h4"></path></g></svg> <input type="text" placeholder="index.php" class="<cjm_fasthtml_tailwind.utilities.flexbox_and_grid.GrowFactory object at 0x7feee9cb8990>">
</label><label class="input">Path <input type="text" placeholder="src/app/" class="<cjm_fasthtml_tailwind.utilities.flexbox_and_grid.GrowFactory object at 0x7feee9cb8990>">
<span class="badge badge-neutral badge-xs">Optional</span></label></div>test_text_input_styles_and_fieldset_fasthtml_examples ()
Test text input styles and fieldset from daisyUI v5 documentation.
def test_text_input_styles_and_fieldset_fasthtml_examples():
"""Test text input styles and fieldset from daisyUI v5 documentation."""
from fasthtml.common import Input, Fieldset, Legend, P, Div
from cjm_fasthtml_daisyui.components.data_input.fieldset import fieldset, fieldset_legend
from cjm_fasthtml_daisyui.components.data_input.label import label
# Ghost style input
ghost_input = Input(
type="text",
placeholder="Type here",
cls=combine_classes(text_input, text_input_styles.ghost)
)
assert ghost_input.tag == "input"
assert "input" in ghost_input.attrs['class']
assert "input-ghost" in ghost_input.attrs['class']
assert ghost_input.attrs['placeholder'] == "Type here"
# With fieldset and fieldset-legend
fieldset_example = Fieldset(
Legend("What is your name?", cls=str(fieldset_legend)),
Input(
type="text",
cls=str(text_input),
placeholder="Type here"
),
P("Optional", cls=str(label)),
cls=str(fieldset)
)
assert fieldset_example.tag == "fieldset"
assert fieldset_example.attrs['class'] == "fieldset"
assert fieldset_example.children[0].tag == "legend"
assert fieldset_example.children[0].attrs['class'] == "fieldset-legend"
assert fieldset_example.children[0].children[0] == "What is your name?"
assert fieldset_example.children[1].tag == "input"
assert fieldset_example.children[1].attrs['class'] == "input"
assert fieldset_example.children[2].tag == "p"
assert fieldset_example.children[2].attrs['class'] == "label"
assert fieldset_example.children[2].children[0] == "Optional"
# Return all elements in a Div
return Div(
ghost_input,
fieldset_example
)
# Run the tests
test_text_input_styles_and_fieldset_fasthtml_examples()test_text_input_colors_fasthtml_examples ()
Test text input color variants from daisyUI v5 documentation.
def test_text_input_colors_fasthtml_examples():
"""Test text input color variants from daisyUI v5 documentation."""
from fasthtml.common import Input, Div
# Neutral color
neutral_input = Input(
type="text",
placeholder="neutral",
cls=combine_classes(text_input, text_input_colors.neutral)
)
assert "input" in neutral_input.attrs['class']
assert "input-neutral" in neutral_input.attrs['class']
assert neutral_input.attrs['placeholder'] == "neutral"
# Primary color
primary_input = Input(
type="text",
placeholder="Primary",
cls=combine_classes(text_input, text_input_colors.primary)
)
assert "input-primary" in primary_input.attrs['class']
assert primary_input.attrs['placeholder'] == "Primary"
# Secondary color
secondary_input = Input(
type="text",
placeholder="Secondary",
cls=combine_classes(text_input, text_input_colors.secondary)
)
assert "input-secondary" in secondary_input.attrs['class']
assert secondary_input.attrs['placeholder'] == "Secondary"
# Accent color
accent_input = Input(
type="text",
placeholder="Accent",
cls=combine_classes(text_input, text_input_colors.accent)
)
assert "input-accent" in accent_input.attrs['class']
assert accent_input.attrs['placeholder'] == "Accent"
# Info color
info_input = Input(
type="text",
placeholder="Info",
cls=combine_classes(text_input, text_input_colors.info)
)
assert "input-info" in info_input.attrs['class']
assert info_input.attrs['placeholder'] == "Info"
# Success color
success_input = Input(
type="text",
placeholder="Success",
cls=combine_classes(text_input, text_input_colors.success)
)
assert "input-success" in success_input.attrs['class']
assert success_input.attrs['placeholder'] == "Success"
# Warning color
warning_input = Input(
type="text",
placeholder="Warning",
cls=combine_classes(text_input, text_input_colors.warning)
)
assert "input-warning" in warning_input.attrs['class']
assert warning_input.attrs['placeholder'] == "Warning"
# Error color
error_input = Input(
type="text",
placeholder="Error",
cls=combine_classes(text_input, text_input_colors.error)
)
assert "input-error" in error_input.attrs['class']
assert error_input.attrs['placeholder'] == "Error"
# Return all elements in a Div
return Div(
neutral_input,
primary_input,
secondary_input,
accent_input,
info_input,
success_input,
warning_input,
error_input
)
# Run the tests
test_text_input_colors_fasthtml_examples()<div>
<input type="text" placeholder="neutral" class="input input-neutral">
<input type="text" placeholder="Primary" class="input input-primary">
<input type="text" placeholder="Secondary" class="input input-secondary">
<input type="text" placeholder="Accent" class="input input-accent">
<input type="text" placeholder="Info" class="input input-info">
<input type="text" placeholder="Success" class="input input-success">
<input type="text" placeholder="Warning" class="input input-warning">
<input type="text" placeholder="Error" class="input input-error">
</div>test_text_input_sizes_fasthtml_examples ()
Test text input size variants from daisyUI v5 documentation.
def test_text_input_sizes_fasthtml_examples():
"""Test text input size variants from daisyUI v5 documentation."""
from fasthtml.common import Input, Div
# Xsmall size
xs_input = Input(
type="text",
placeholder="Xsmall",
cls=combine_classes(text_input, text_input_sizes.xs)
)
assert "input" in xs_input.attrs['class']
assert "input-xs" in xs_input.attrs['class']
assert xs_input.attrs['placeholder'] == "Xsmall"
# Small size
sm_input = Input(
type="text",
placeholder="Small",
cls=combine_classes(text_input, text_input_sizes.sm)
)
assert "input-sm" in sm_input.attrs['class']
assert sm_input.attrs['placeholder'] == "Small"
# Medium size
md_input = Input(
type="text",
placeholder="Medium",
cls=combine_classes(text_input, text_input_sizes.md)
)
assert "input-md" in md_input.attrs['class']
assert md_input.attrs['placeholder'] == "Medium"
# Large size
lg_input = Input(
type="text",
placeholder="Large",
cls=combine_classes(text_input, text_input_sizes.lg)
)
assert "input-lg" in lg_input.attrs['class']
assert lg_input.attrs['placeholder'] == "Large"
# Xlarge size
xl_input = Input(
type="text",
placeholder="Xlarge",
cls=combine_classes(text_input, text_input_sizes.xl)
)
assert "input-xl" in xl_input.attrs['class']
assert xl_input.attrs['placeholder'] == "Xlarge"
# Return all elements in a Div
return Div(
xs_input,
sm_input,
md_input,
lg_input,
xl_input
)
# Run the tests
test_text_input_sizes_fasthtml_examples()<div>
<input type="text" placeholder="Xsmall" class="input input-xs">
<input type="text" placeholder="Small" class="input input-sm">
<input type="text" placeholder="Medium" class="input input-md">
<input type="text" placeholder="Large" class="input input-lg">
<input type="text" placeholder="Xlarge" class="input input-xl">
</div>test_text_input_special_types_fasthtml_examples ()
Test special input types from daisyUI v5 documentation.
def test_text_input_special_types_fasthtml_examples():
"""Test special input types from daisyUI v5 documentation."""
from fasthtml.common import Input, Datalist, Option, Div
# Text input with data list suggestion
datalist_input = Input(
type="text",
cls=str(text_input),
placeholder="Which browser do you use",
list="browsers"
)
datalist = Datalist(
Option(value="Chrome"),
Option(value="Firefox"),
Option(value="Safari"),
Option(value="Opera"),
Option(value="Edge"),
id="browsers"
)
assert datalist_input.tag == "input"
assert datalist_input.attrs['type'] == "text"
assert datalist_input.attrs['class'] == "input"
assert datalist_input.attrs['list'] == "browsers"
assert datalist_input.attrs['placeholder'] == "Which browser do you use"
assert datalist.tag == "datalist"
assert datalist.attrs['id'] == "browsers"
assert len(datalist.children) == 5
assert datalist.children[0].attrs['value'] == "Chrome"
assert datalist.children[1].attrs['value'] == "Firefox"
assert datalist.children[2].attrs['value'] == "Safari"
assert datalist.children[3].attrs['value'] == "Opera"
assert datalist.children[4].attrs['value'] == "Edge"
# Date input
date_input = Input(
type="date",
cls=str(text_input)
)
assert date_input.tag == "input"
assert date_input.attrs['type'] == "date"
assert date_input.attrs['class'] == "input"
# Time input
time_input = Input(
type="time",
cls=str(text_input)
)
assert time_input.tag == "input"
assert time_input.attrs['type'] == "time"
assert time_input.attrs['class'] == "input"
# Datetime-local input
datetime_input = Input(
type="datetime-local",
cls=str(text_input)
)
assert datetime_input.tag == "input"
assert datetime_input.attrs['type'] == "datetime-local"
assert datetime_input.attrs['class'] == "input"
# Return all elements in a Div
return Div(
datalist_input,
datalist,
date_input,
time_input,
datetime_input
)
# Run the tests
test_text_input_special_types_fasthtml_examples()<div>
<input type="text" placeholder="Which browser do you use" list="browsers" class="input">
<datalist id="browsers"><option value="Chrome"></option><option value="Firefox"></option><option value="Safari"></option><option value="Opera"></option><option value="Edge"></option></datalist> <input type="date" class="input">
<input type="time" class="input">
<input type="datetime-local" class="input">
</div>test_text_input_validators_part1_fasthtml_examples ()
Test text input validators part 1: username, search, email from daisyUI v5 documentation.
def test_text_input_validators_part1_fasthtml_examples():
"""Test text input validators part 1: username, search, email from daisyUI v5 documentation."""
from fasthtml.common import Label, Input, P, Div, Button
from fasthtml.svg import Svg, G, Circle, Path, Rect
from cjm_fasthtml_tailwind.utilities.sizing import size_util, h
from cjm_fasthtml_tailwind.utilities.effects import opacity
from cjm_fasthtml_tailwind.utilities.layout import display_tw
from cjm_fasthtml_daisyui.components.data_input.validator import validator, validator_hint
from cjm_fasthtml_daisyui.components.layout.join import join, join_item
from cjm_fasthtml_daisyui.components.actions.button import btn, btn_colors
# User icon SVG
user_icon = Svg(
G(
Path(d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"),
Circle(cx="12", cy="7", r="4"),
stroke_linejoin="round",
stroke_linecap="round",
stroke_width="2.5",
fill="none",
stroke="currentColor"
),
cls=combine_classes(h("[1em]"), opacity._50),
xmlns="http://www.w3.org/2000/svg",
viewBox="0 0 24 24"
)
# Search icon SVG
search_icon = Svg(
G(
Circle(cx="11", cy="11", r="8"),
Path(d="m21 21-4.3-4.3"),
stroke_linejoin="round",
stroke_linecap="round",
stroke_width="2.5",
fill="none",
stroke="currentColor"
),
cls=combine_classes(h("[1em]"), opacity._50),
xmlns="http://www.w3.org/2000/svg",
viewBox="0 0 24 24"
)
# Email icon SVG
email_icon = Svg(
G(
Rect(width="20", height="16", x="2", y="4", rx="2"),
Path(d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"),
stroke_linejoin="round",
stroke_linecap="round",
stroke_width="2.5",
fill="none",
stroke="currentColor"
),
cls=combine_classes(h("[1em]"), opacity._50),
xmlns="http://www.w3.org/2000/svg",
viewBox="0 0 24 24"
)
# Username text input with icon and validator
username_input = Label(
user_icon,
Input(
type="text",
required=True,
placeholder="Username",
pattern="[A-Za-z][A-Za-z0-9\\-]*",
minlength="3",
maxlength="30",
title="Only letters, numbers or dash"
),
cls=combine_classes(text_input, validator)
)
username_hint = P(
"Must be 3 to 30 characters",
Br(),
"containing only letters, numbers or dash",
cls=str(validator_hint)
)
assert username_input.tag == "label"
assert "input" in username_input.attrs['class']
assert "validator" in username_input.attrs['class']
assert username_input.children[1].attrs['required'] == True
assert username_input.children[1].attrs['pattern'] == "[A-Za-z][A-Za-z0-9\\-]*"
assert username_hint.attrs['class'] == "validator-hint"
# Search input with icon
search_input = Label(
search_icon,
Input(
type="search",
required=True,
placeholder="Search"
),
cls=str(text_input)
)
assert search_input.tag == "label"
assert search_input.attrs['class'] == "input"
assert search_input.children[1].attrs['type'] == "search"
assert search_input.children[1].attrs['required'] == True
# Email input with icon and validator
email_input = Label(
email_icon,
Input(
type="email",
placeholder="[email protected]",
required=True
),
cls=combine_classes(text_input, validator)
)
email_hint = Div(
"Enter valid email address",
cls=combine_classes(validator_hint, display_tw.hidden)
)
assert email_input.tag == "label"
assert "validator" in email_input.attrs['class']
assert email_input.children[1].attrs['type'] == "email"
assert email_input.children[1].attrs['required'] == True
assert "hidden" in email_hint.attrs['class']
# Email input with icon, validator, button, join
email_join = Div(
Div(
Label(
email_icon,
Input(
type="email",
placeholder="[email protected]",
required=True
),
cls=combine_classes(text_input, validator, join_item)
),
Div(
"Enter valid email address",
cls=combine_classes(validator_hint, display_tw.hidden)
)
),
Button("Join", cls=combine_classes(btn, btn_colors.neutral, join_item)),
cls=str(join)
)
assert email_join.tag == "div"
assert email_join.attrs['class'] == "join"
assert "join-item" in email_join.children[0].children[0].attrs['class']
assert "join-item" in email_join.children[1].attrs['class']
# Return all elements in a Div
return Div(
username_input,
username_hint,
search_input,
email_input,
email_hint,
email_join
)
# Fix missing import
from fasthtml.common import Br
# Run the tests
test_text_input_validators_part1_fasthtml_examples()<div>
<label class="input validator"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="h-[1em] opacity-50"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2.5" fill="none" stroke="currentColor"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"></path><circle r="4" cx="12" cy="7"></circle></g></svg> <input type="text" required placeholder="Username" pattern="[A-Za-z][A-Za-z0-9\-]*" minlength="3" maxlength="30" title="Only letters, numbers or dash">
</label> <p class="validator-hint">
Must be 3 to 30 characters<br>containing only letters, numbers or dash </p>
<label class="input"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="h-[1em] opacity-50"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2.5" fill="none" stroke="currentColor"><circle r="8" cx="11" cy="11"></circle><path d="m21 21-4.3-4.3"></path></g></svg> <input type="search" required placeholder="Search">
</label><label class="input validator"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="h-[1em] opacity-50"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2.5" fill="none" stroke="currentColor"><rect width="20" height="16" x="2" y="4" rx="2"></rect><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"></path></g></svg> <input type="email" placeholder="[email protected]" required>
</label> <div class="validator-hint hidden">Enter valid email address</div>
<div class="join">
<div>
<label class="input validator join-item"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="h-[1em] opacity-50"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2.5" fill="none" stroke="currentColor"><rect width="20" height="16" x="2" y="4" rx="2"></rect><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"></path></g></svg> <input type="email" placeholder="[email protected]" required>
</label> <div class="validator-hint hidden">Enter valid email address</div>
</div>
<button class="btn btn-neutral join-item">Join</button> </div>
</div>test_text_input_validators_part2_fasthtml_examples ()
Test text input validators part 2: password, number, phone, URL from daisyUI v5 documentation.
def test_text_input_validators_part2_fasthtml_examples():
"""Test text input validators part 2: password, number, phone, URL from daisyUI v5 documentation."""
from fasthtml.common import Label, Input, P, Div, Br
from fasthtml.svg import Svg, G, Circle, Path
from cjm_fasthtml_tailwind.utilities.sizing import size_util, h
from cjm_fasthtml_tailwind.utilities.effects import opacity
from cjm_fasthtml_tailwind.utilities.layout import display_tw
from cjm_fasthtml_tailwind.utilities.typography import tabular_nums
from cjm_fasthtml_daisyui.components.data_input.validator import validator, validator_hint
# Password icon SVG
password_icon = Svg(
G(
Path(
d="M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z"
),
Circle(cx="16.5", cy="7.5", r=".5", fill="currentColor"),
stroke_linejoin="round",
stroke_linecap="round",
stroke_width="2.5",
fill="none",
stroke="currentColor"
),
cls=combine_classes(h("[1em]"), opacity._50),
xmlns="http://www.w3.org/2000/svg",
viewBox="0 0 24 24"
)
# Phone icon SVG (using 16x16 viewBox as per the HTML)
phone_icon = Svg(
G(
Path(
d="M7.25 11.5C6.83579 11.5 6.5 11.8358 6.5 12.25C6.5 12.6642 6.83579 13 7.25 13H8.75C9.16421 13 9.5 12.6642 9.5 12.25C9.5 11.8358 9.16421 11.5 8.75 11.5H7.25Z",
fill="currentColor"
),
Path(
fill_rule="evenodd",
clip_rule="evenodd",
d="M6 1C4.61929 1 3.5 2.11929 3.5 3.5V12.5C3.5 13.8807 4.61929 15 6 15H10C11.3807 15 12.5 13.8807 12.5 12.5V3.5C12.5 2.11929 11.3807 1 10 1H6ZM10 2.5H9.5V3C9.5 3.27614 9.27614 3.5 9 3.5H7C6.72386 3.5 6.5 3.27614 6.5 3V2.5H6C5.44771 2.5 5 2.94772 5 3.5V12.5C5 13.0523 5.44772 13.5 6 13.5H10C10.5523 13.5 11 13.0523 11 12.5V3.5C11 2.94772 10.5523 2.5 10 2.5Z",
fill="currentColor"
),
fill="none"
),
cls=combine_classes(h("[1em]"), opacity._50),
xmlns="http://www.w3.org/2000/svg",
viewBox="0 0 16 16"
)
# URL icon SVG
url_icon = Svg(
G(
Path(d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"),
Path(d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"),
stroke_linejoin="round",
stroke_linecap="round",
stroke_width="2.5",
fill="none",
stroke="currentColor"
),
cls=combine_classes(h("[1em]"), opacity._50),
xmlns="http://www.w3.org/2000/svg",
viewBox="0 0 24 24"
)
# Password input with icon and validator
password_input = Label(
password_icon,
Input(
type="password",
required=True,
placeholder="Password",
minlength="8",
pattern="(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,}",
title="Must be more than 8 characters, including number, lowercase letter, uppercase letter"
),
cls=combine_classes(text_input, validator)
)
password_hint = P(
"Must be more than 8 characters, including",
Br(),
"At least one number ",
Br(),
"At least one lowercase letter ",
Br(),
"At least one uppercase letter",
cls=combine_classes(validator_hint, display_tw.hidden)
)
assert password_input.tag == "label"
assert "validator" in password_input.attrs['class']
assert password_input.children[1].attrs['type'] == "password"
assert password_input.children[1].attrs['minlength'] == "8"
assert "hidden" in password_hint.attrs['class']
# Number input with validator
number_input = Input(
type="number",
cls=combine_classes(text_input, validator),
required=True,
placeholder="Type a number between 1 to 10",
min="1",
max="10",
title="Must be between be 1 to 10"
)
number_hint = P(
"Must be between be 1 to 10",
cls=str(validator_hint)
)
assert number_input.tag == "input"
assert number_input.attrs['type'] == "number"
assert "validator" in number_input.attrs['class']
assert number_input.attrs['min'] == "1"
assert number_input.attrs['max'] == "10"
# Telephone number input with icon and validator
tel_input = Label(
phone_icon,
Input(
type="tel",
cls=str(tabular_nums),
required=True,
placeholder="Phone",
pattern="[0-9]*",
minlength="10",
maxlength="10",
title="Must be 10 digits"
),
cls=combine_classes(text_input, validator)
)
tel_hint = P(
"Must be 10 digits",
cls=str(validator_hint)
)
assert tel_input.tag == "label"
assert "validator" in tel_input.attrs['class']
assert tel_input.children[1].attrs['type'] == "tel"
assert tel_input.children[1].attrs['class'] == "tabular-nums"
assert tel_input.children[1].attrs['pattern'] == "[0-9]*"
# URL with icon and validator
url_input = Label(
url_icon,
Input(
type="url",
required=True,
placeholder="https://",
value="https://",
pattern="^(https?://)?([a-zA-Z0-9]([a-zA-Z0-9\\-].*[a-zA-Z0-9])?\\.)+[a-zA-Z].*",
title="Must be valid URL"
),
cls=combine_classes(text_input, validator)
)
url_hint = P(
"Must be valid URL",
cls=str(validator_hint)
)
assert url_input.tag == "label"
assert "validator" in url_input.attrs['class']
assert url_input.children[1].attrs['type'] == "url"
assert url_input.children[1].attrs['value'] == "https://"
# Return all elements in a Div
return Div(
password_input,
password_hint,
number_input,
number_hint,
tel_input,
tel_hint,
url_input,
url_hint
)
# Run the tests
test_text_input_validators_part2_fasthtml_examples()<div>
<label class="input validator"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="h-[1em] opacity-50"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2.5" fill="none" stroke="currentColor"><path d="M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z"></path><circle r=".5" cx="16.5" cy="7.5" fill="currentColor"></circle></g></svg> <input type="password" required placeholder="Password" minlength="8" pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}" title="Must be more than 8 characters, including number, lowercase letter, uppercase letter">
</label> <p class="validator-hint hidden">
Must be more than 8 characters, including<br>At least one number <br>At least one lowercase letter <br>At least one uppercase letter </p>
<input type="number" required placeholder="Type a number between 1 to 10" min="1" max="10" class="input validator" title="Must be between be 1 to 10">
<p class="validator-hint">Must be between be 1 to 10</p>
<label class="input validator"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 16 16" class="h-[1em] opacity-50"><g fill="none"><path d="M7.25 11.5C6.83579 11.5 6.5 11.8358 6.5 12.25C6.5 12.6642 6.83579 13 7.25 13H8.75C9.16421 13 9.5 12.6642 9.5 12.25C9.5 11.8358 9.16421 11.5 8.75 11.5H7.25Z" fill="currentColor"></path><path d="M6 1C4.61929 1 3.5 2.11929 3.5 3.5V12.5C3.5 13.8807 4.61929 15 6 15H10C11.3807 15 12.5 13.8807 12.5 12.5V3.5C12.5 2.11929 11.3807 1 10 1H6ZM10 2.5H9.5V3C9.5 3.27614 9.27614 3.5 9 3.5H7C6.72386 3.5 6.5 3.27614 6.5 3V2.5H6C5.44771 2.5 5 2.94772 5 3.5V12.5C5 13.0523 5.44772 13.5 6 13.5H10C10.5523 13.5 11 13.0523 11 12.5V3.5C11 2.94772 10.5523 2.5 10 2.5Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></g></svg> <input type="tel" required placeholder="Phone" pattern="[0-9]*" minlength="10" maxlength="10" class="tabular-nums" title="Must be 10 digits">
</label> <p class="validator-hint">Must be 10 digits</p>
<label class="input validator"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="h-[1em] opacity-50"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2.5" fill="none" stroke="currentColor"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></g></svg> <input type="url" required placeholder="https://" value="https://" pattern="^(https?://)?([a-zA-Z0-9]([a-zA-Z0-9\-].*[a-zA-Z0-9])?\.)+[a-zA-Z].*" title="Must be valid URL">
</label> <p class="validator-hint">Must be valid URL</p>
</div>