Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -182,23 +182,54 @@ private void RenderTextField(RenderTreeBuilder builder, IFieldConfiguration<TMod
builder.AddAttribute(3, "ValueChanged",
EventCallback.Factory.Create<string>(this,
newValue => UpdateFieldValue(field.FieldName, newValue)));

// Add Lines attribute for text area support
if (field.AdditionalAttributes.TryGetValue("Lines", out var linesObj) && linesObj is int lines)
{
builder.AddAttribute(10, "Lines", lines);
}

// Add MaxLength attribute if present
if (field.AdditionalAttributes.TryGetValue("MaxLength", out var maxLengthObj) && maxLengthObj is int maxLength)
{
builder.AddAttribute(11, "MaxLength", maxLength);
}

builder.AddAttribute(12, "Immediate", true);

// Add InputType attribute if present
if (field.InputType != null)
{
builder.AddAttribute(13, "InputType", GetInputType(field.InputType));
}

// Add Adornment attributes for password toggle support
if (field.AdditionalAttributes.TryGetValue("Adornment", out var adornmentObj) && adornmentObj is Adornment adornment)
{
builder.AddAttribute(14, "Adornment", adornment);
}

if (field.AdditionalAttributes.TryGetValue("AdornmentIcon", out var adornmentIconObj) && adornmentIconObj is string adornmentIcon)
{
builder.AddAttribute(15, "AdornmentIcon", adornmentIcon);
}

builder.CloseComponent();
}

private static InputType GetInputType(string inputType)
{
return inputType.ToLowerInvariant() switch
{
"email" => InputType.Email,
"password" => InputType.Password,
"tel" or "telephone" => InputType.Telephone,
"url" => InputType.Url,
"search" => InputType.Search,
_ => InputType.Text
};
}

private void RenderNumericField<T>(RenderTreeBuilder builder, IFieldConfiguration<TModel, object> field, T value)
where T : struct
{
Expand Down
28 changes: 28 additions & 0 deletions FormCraft.UnitTests/Builders/FieldBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,34 @@ public void Build_Should_Return_FormConfiguration()
result.Fields.First().IsRequired.ShouldBeTrue();
}

[Fact]
public void WithInputType_Should_Set_InputType_To_Password()
{
// Arrange & Act
var config = FormBuilder<TestModel>.Create()
.AddField(x => x.Name, field => field
.WithInputType("password"))
.Build();

// Assert
var field = config.Fields.First(f => f.FieldName == "Name");
field.InputType.ShouldBe("password");
}

[Fact]
public void WithInputType_Should_Set_InputType_To_Email()
{
// Arrange & Act
var config = FormBuilder<TestModel>.Create()
.AddField(x => x.Email, field => field
.WithInputType("email"))
.Build();

// Assert
var field = config.Fields.First(f => f.FieldName == "Email");
field.InputType.ShouldBe("email");
}

[Fact]
public void Multiple_Fluent_Calls_Should_Chain_Correctly()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ public void AddPasswordField_Should_Configure_Password_Field_With_MinLength()
var field = config.Fields.First(f => f.FieldName == "Password");
field.Label.ShouldBe("Password");
field.IsRequired.ShouldBeTrue();
field.InputType.ShouldBe("password");
field.Validators.Count.ShouldBe(3); // Required + MinLength + Special chars
}

Expand Down
3 changes: 2 additions & 1 deletion FormCraft/Forms/Extensions/FluentFormBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -312,9 +312,10 @@ public static FormBuilder<TModel> AddPasswordField<TModel>(
int minLength = 8,
bool requireSpecialChars = true) where TModel : new()
{
return builder.AddField(expression, field =>
return builder.AddField(expression, field =>
{
field.WithLabel(label)
.WithInputType("password")
.Required($"{label} is required")
.WithMinLength(minLength, $"Must be at least {minLength} characters");

Expand Down
Loading