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 @@ -22,6 +22,8 @@ internal override IEnumerable<NavItem> GetNavItems()
new (){ Id = "402", Text = "Currency Input", Href = DemoRouteConstants.Demos_URL_CurrencyInput, IconName = IconName.CurrencyDollar, ParentId = "4" },
new (){ Id = "403", Text = "Date Input", Href = DemoRouteConstants.Demos_URL_DateInput, IconName = IconName.CalendarDate, ParentId = "4" },
new (){ Id = "404", Text = "Enum Input", Href = DemoRouteConstants.Demos_URL_EnumInput, IconName = IconName.MenuButtonWideFill, ParentId = "4" },
new (){ Id = "414", Text = "File Input", Href = DemoRouteConstants.Demos_URL_FileInput, IconName = IconName.FileEarmarkArrowUp, ParentId = "4" },
new (){ Id = "415", Text = "Drag and Drop File Input", Href = DemoRouteConstants.Demos_URL_DragAndDropFileInput, IconName = IconName.FileEarmarkArrowUp, ParentId = "4" },
new (){ Id = "405", Text = "Number Input", Href = DemoRouteConstants.Demos_URL_NumberInput, IconName = IconName.InputCursor, ParentId = "4" },
new (){ Id = "406", Text = "OTP Input", Href = DemoRouteConstants.Demos_URL_OTPInput, IconName = IconName.Asterisk, ParentId = "4" },
new (){ Id = "407", Text = "Password Input", Href = DemoRouteConstants.Demos_URL_PasswordInput, IconName = IconName.EyeSlashFill, ParentId = "4" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ internal override IEnumerable<NavItem> GetNavItems()
new (){ Id = "402", Text = "Currency Input", Href = DemoRouteConstants.Docs_URL_CurrencyInput, IconName = IconName.CurrencyDollar, ParentId = "4" },
new (){ Id = "403", Text = "Date Input", Href = DemoRouteConstants.Docs_URL_DateInput, IconName = IconName.CalendarDate, ParentId = "4" },
new (){ Id = "404", Text = "Enum Input", Href = DemoRouteConstants.Docs_URL_EnumInput, IconName = IconName.MenuButtonWideFill, ParentId = "4" },
new (){ Id = "414", Text = "File Input", Href = DemoRouteConstants.Docs_URL_FileInput, IconName = IconName.FileEarmarkArrowUp, ParentId = "4" },
new (){ Id = "415", Text = "Drag and Drop File Input", Href = DemoRouteConstants.Docs_URL_DragAndDropFileInput, IconName = IconName.FileEarmarkArrowUp, ParentId = "4" },
new (){ Id = "405", Text = "Number Input", Href = DemoRouteConstants.Docs_URL_NumberInput, IconName = IconName.InputCursor, ParentId = "4" },
new (){ Id = "406", Text = "OTP Input", Href = DemoRouteConstants.Docs_URL_OTPInput, IconName = IconName.Asterisk, ParentId = "4" },
new (){ Id = "407", Text = "Password Input", Href = DemoRouteConstants.Docs_URL_PasswordInput, IconName = IconName.EyeSlashFill, ParentId = "4" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ internal override IEnumerable<NavItem> GetNavItems()
new (){ Id = "402", Text = "Currency Input", Href = DemoRouteConstants.Demos_URL_CurrencyInput, IconName = IconName.CurrencyDollar, ParentId = "4" },
new (){ Id = "403", Text = "Date Input", Href = DemoRouteConstants.Demos_URL_DateInput, IconName = IconName.CalendarDate, ParentId = "4" },
new (){ Id = "404", Text = "Enum Input", Href = DemoRouteConstants.Demos_URL_EnumInput, IconName = IconName.MenuButtonWideFill, ParentId = "4" },
new (){ Id = "413", Text = "File Input", Href = DemoRouteConstants.Demos_URL_FileInput, IconName = IconName.FileEarmarkArrowUp, ParentId = "4" },
new (){ Id = "414", Text = "Drag and Drop File Input", Href = DemoRouteConstants.Demos_URL_DragAndDropFileInput, IconName = IconName.FileEarmarkArrowUp, ParentId = "4" },
new (){ Id = "405", Text = "Number Input", Href = DemoRouteConstants.Demos_URL_NumberInput, IconName = IconName.InputCursor, ParentId = "4" },
new (){ Id = "406", Text = "Password Input", Href = DemoRouteConstants.Demos_URL_PasswordInput, IconName = IconName.EyeSlashFill, ParentId = "4" },
new (){ Id = "407", Text = "Radio Input", Href = DemoRouteConstants.Demos_URL_RadioInput, IconName = IconName.RecordCircle, ParentId = "4" },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
@using System.ComponentModel.DataAnnotations

<style>
.valid.modified:not([type=checkbox]) {
outline: 1px solid #26b050;
}

.invalid {
outline: 1px solid red;
}

.validation-message {
color: red;
}
</style>

<EditForm EditContext="@_editContext" OnValidSubmit="HandleOnValidSubmit">
<DataAnnotationsValidator />

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
@using System.ComponentModel.DataAnnotations

<style>
.valid.modified:not([type=checkbox]) {
outline: 1px solid #26b050;
}

.invalid {
outline: 1px solid red;
}

.validation-message {
color: red;
}
</style>

<EditForm EditContext="@editContext" OnValidSubmit="HandleOnValidSubmit">
<DataAnnotationsValidator />

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
@using System.ComponentModel.DataAnnotations

<style>
.valid.modified:not([type=checkbox]) {
outline: 1px solid #26b050;
}

.invalid {
outline: 1px solid red;
}

.validation-message {
color: red;
}
</style>

<EditForm EditContext="@editContext" OnValidSubmit="HandleOnValidSubmit" novalidate>
<DataAnnotationsValidator />

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
@using System.ComponentModel.DataAnnotations

<style>
.valid.modified:not([type=checkbox]) {
outline: 1px solid #26b050;
}

.invalid {
outline: 1px solid red;
}

.validation-message {
color: red;
}
</style>

<EditForm EditContext="@editContext" OnValidSubmit="HandleValidSubmit" novalidate>
<DataAnnotationsValidator />

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
@page "/drag-and-drop-file-input"

@attribute [Route(pageUrl)]
@layout DemosMainLayout

<DemosPageHeadSection PageUrl="@pageUrl"
PageTitle="@pageTitle"
PageDescription="@pageDescription"
MetaTitle="@metaTitle"
MetaDescription="@metaDescription"
ImageUrl="@imageUrl" />

<DocsLink Href="@DemoRouteConstants.Docs_URL_DragAndDropFileInput" />

<Section Size="HeadingSize.H2" Name="Basic usage" PageUrl="@pageUrl" Link="basic-usage">
<div class="mb-3">Drop files onto the area on desktop, or tap it on touch devices to open the native file picker.</div>
<Demo Type="typeof(DragAndDropFileInput_Demo_01_Basic_Usage)" Tabs="true" />
</Section>

<Section Size="HeadingSize.H2" Name="Validation" PageUrl="@pageUrl" Link="validation">
<div class="mb-3">Drop and picker selection share the same extension, size, and count validation behavior. Configure validation-message templates with <code>{FileName}</code>, <code>{MaxFileSize}</code>, <code>{AllowedFileTypes}</code>, or <code>{MaxFileCount}</code> where applicable; the single-file message is static.</div>
<Demo Type="typeof(DragAndDropFileInput_Demo_02_Validation)" Tabs="true" />
</Section>

<Section Size="HeadingSize.H2" Name="Form validation" PageUrl="@pageUrl" Link="form-validation">
<div class="mb-3">Use <code>FilesChanged</code> to update a form model while retaining the drag-and-drop area and touch picker fallback.</div>
<Demo Type="typeof(DragAndDropFileInput_Demo_03_Form_Validation)" Tabs="true" />
</Section>

@code {
private const string pageUrl = DemoRouteConstants.Demos_URL_DragAndDropFileInput;
private const string pageTitle = "Blazor DragAndDropFileInput";
private const string pageDescription = "The Blazor Bootstrap DragAndDropFileInput component supports desktop drag and drop and touch file-picker selection.";
private const string metaTitle = "Blazor DragAndDropFileInput Component";
private const string metaDescription = "The Blazor Bootstrap DragAndDropFileInput component supports desktop drag and drop and touch file-picker selection.";
private const string imageUrl = DemoScreenshotSrcConstants.Demos_URL_Forms_Prefix;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<DragAndDropFileInput HintText="Drop files here on desktop, or tap to browse on touch devices." />
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<DragAndDropFileInput Multiple="true"
MaxFileCount="3"
MaxFileSize="1048576"
AllowedFileTypes="@allowedFileTypes"
InvalidFileTypeErrorMessage="{FileName} must use one of: {AllowedFileTypes}."
MaxFileCountErrorMessage="{FileName} would exceed the {MaxFileCount}-file limit."
MaxFileSizeErrorMessage="{FileName} exceeds the {MaxFileSize}-byte limit."
SingleFileErrorMessage="Select only one file."
HintText="Select up to three PDF or PNG files, each no larger than 1 MB." />

@code {
private readonly string[] allowedFileTypes = [".pdf", "png"];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@using System.ComponentModel.DataAnnotations
@using Microsoft.AspNetCore.Components.Forms

<EditForm EditContext="@editContext" OnValidSubmit="HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />

<div class="mb-3">
<label class="form-label">Supporting document <span class="text-danger">*</span></label>
<DragAndDropFileInput AllowedFileTypes="@allowedFileTypes"
MaxFileSize="1048576"
FilesChanged="OnFilesChanged"
HintText="Drop a PDF up to 1 MB, or tap to browse." />
<ValidationMessage For="@(() => upload.DocumentName)" />
</div>

<Button Type="ButtonType.Submit" Color="ButtonColor.Primary">Submit</Button>

@if (submitted)
{
<div class="alert alert-success mt-3" role="status">Form submitted with @upload.DocumentName.</div>
}
</EditForm>

@code {
private readonly string[] allowedFileTypes = ["pdf"];
private readonly UploadModel upload = new();
private EditContext editContext = null!;
private bool submitted;

protected override void OnInitialized()
{
editContext = new EditContext(upload);
}

private void HandleValidSubmit() => submitted = true;

private void OnFilesChanged(IReadOnlyList<IBrowserFile> files)
{
upload.DocumentName = files.FirstOrDefault()?.Name;
submitted = false;
editContext.NotifyFieldChanged(new FieldIdentifier(upload, nameof(upload.DocumentName)));
}

private sealed class UploadModel
{
[Required(ErrorMessage = "A supporting document is required.")]
public string? DocumentName { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
@page "/file-input"

@attribute [Route(pageUrl)]
@layout DemosMainLayout

<DemosPageHeadSection PageUrl="@pageUrl"
PageTitle="@pageTitle"
PageDescription="@pageDescription"
MetaTitle="@metaTitle"
MetaDescription="@metaDescription"
ImageUrl="@imageUrl" />

<DocsLink Href="@DemoRouteConstants.Docs_URL_FileInput" />

<Section Size="HeadingSize.H2" Name="Basic usage" PageUrl="@pageUrl" Link="basic-usage">
<div class="mb-3">FileInput uses Bootstrap's standard visible file-control presentation. Use DragAndDropFileInput when a drop area is needed.</div>
<Demo Type="typeof(FileInput_Demo_01_Basic_Usage)" Tabs="true" />
</Section>

<Section Size="HeadingSize.H2" Name="Multiple files and removal" PageUrl="@pageUrl" Link="multiple-files-and-removal">
<div class="mb-3">Set <code>Multiple</code> to allow a selected file to be removed without clearing the others.</div>
<Demo Type="typeof(FileInput_Demo_02_Multiple_Files_And_Removal)" Tabs="true" />
</Section>

<Section Size="HeadingSize.H2" Name="Sizes" PageUrl="@pageUrl" Link="sizes">
<div class="mb-3">Use <code>Size</code> to apply Bootstrap's <code>form-control-lg</code> and <code>form-control-sm</code> file-control sizes.</div>
<Demo Type="typeof(FileInput_Demo_03_Colors_And_Sizes)" Tabs="true" />
</Section>

<Section Size="HeadingSize.H2" Name="Validation" PageUrl="@pageUrl" Link="validation">
<div class="mb-3">FileInput validates sizes, counts, and extensions selected from the file dialog. Configure validation-message templates with <code>{FileName}</code>, <code>{MaxFileSize}</code>, <code>{AllowedFileTypes}</code>, or <code>{MaxFileCount}</code> where applicable; the single-file message is static.</div>
<Demo Type="typeof(FileInput_Demo_04_Validation)" Tabs="true" />
</Section>

<Section Size="HeadingSize.H2" Name="Form validation" PageUrl="@pageUrl" Link="form-validation">
<div class="mb-3">Use <code>FilesChanged</code> to update a form model and combine file-selection rules with standard form validation.</div>
<Demo Type="typeof(FileInput_Demo_06_Form_Validation)" Tabs="true" />
</Section>

<Section Size="HeadingSize.H2" Name="Hint text and unrestricted extensions" PageUrl="@pageUrl" Link="hint-text-and-unrestricted-extensions">
<div class="mb-3">An empty <code>AllowedFileTypes</code> collection accepts every extension while other configured rules remain active.</div>
<Demo Type="typeof(FileInput_Demo_05_Hint_And_Unrestricted_Extensions)" Tabs="true" />
</Section>

@code {
private const string pageUrl = DemoRouteConstants.Demos_URL_FileInput;
private const string pageTitle = "Blazor FileInput";
private const string pageDescription = "The Blazor Bootstrap FileInput component provides a standard Bootstrap file control with validation and removal.";
private const string metaTitle = "Blazor FileInput Component";
private const string metaDescription = "The Blazor Bootstrap FileInput component provides a standard Bootstrap file control with validation and removal.";
private const string imageUrl = DemoScreenshotSrcConstants.Demos_URL_Forms_Prefix;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<FileInput HintText="Select a file with the standard Bootstrap file control." />
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<FileInput Multiple="true" HintText="Select multiple files, then remove individual files from the list." />
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div class="vstack gap-3">
<FileInput Size="FileInputSize.Large" HintText="Large file input." />
<FileInput Size="FileInputSize.Small" HintText="Small file input." />
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<FileInput Multiple="true"
MaxFileCount="3"
MaxFileSize="1048576"
AllowedFileTypes="@allowedFileTypes"
InvalidFileTypeErrorMessage="{FileName} must use one of: {AllowedFileTypes}."
MaxFileCountErrorMessage="{FileName} would exceed the {MaxFileCount}-file limit."
MaxFileSizeErrorMessage="{FileName} exceeds the {MaxFileSize}-byte limit."
SingleFileErrorMessage="Select only one file."
HintText="Select up to three PDF or PNG files, each no larger than 1 MB." />

@code {
private readonly string[] allowedFileTypes = [".pdf", "png"];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<FileInput Multiple="true"
AllowedFileTypes="@allowedFileTypes"
MaxFileSize="5242880"
HintText="Any extension is accepted because the allowed-extension collection is empty; the 5 MB size limit still applies." />

@code {
private readonly string[] allowedFileTypes = [];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@using System.ComponentModel.DataAnnotations
@using Microsoft.AspNetCore.Components.Forms

<EditForm EditContext="@editContext" OnValidSubmit="HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />

<div class="mb-3">
<label class="form-label">Supporting document <span class="text-danger">*</span></label>
<FileInput AllowedFileTypes="@allowedFileTypes"
MaxFileSize="1048576"
FilesChanged="OnFilesChanged"
HintText="A PDF document up to 1 MB is required." />
<ValidationMessage For="@(() => upload.DocumentName)" />
</div>

<Button Type="ButtonType.Submit" Color="ButtonColor.Primary">Submit</Button>

@if (submitted)
{
<div class="alert alert-success mt-3" role="status">Form submitted with @upload.DocumentName.</div>
}
</EditForm>

@code {
private readonly string[] allowedFileTypes = ["pdf"];
private readonly UploadModel upload = new();
private EditContext editContext = null!;
private bool submitted;

protected override void OnInitialized()
{
editContext = new EditContext(upload);
}

private void HandleValidSubmit() => submitted = true;

private void OnFilesChanged(IReadOnlyList<IBrowserFile> files)
{
upload.DocumentName = files.FirstOrDefault()?.Name;
submitted = false;
editContext.NotifyFieldChanged(new FieldIdentifier(upload, nameof(upload.DocumentName)));
}

private sealed class UploadModel
{
[Required(ErrorMessage = "A supporting document is required.")]
public string? DocumentName { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
@using System.ComponentModel.DataAnnotations

<style>
.valid.modified:not([type=checkbox]) {
outline: 1px solid #26b050;
}

.invalid {
outline: 1px solid red;
}

.validation-message {
color: red;
}
</style>

<EditForm EditContext="@editContext" OnValidSubmit="HandleOnValidSubmit">
<DataAnnotationsValidator />

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
@using System.ComponentModel.DataAnnotations

<style>
.valid.modified:not([type=checkbox]) {
outline: 1px solid #26b050;
}

.invalid {
outline: 1px solid red;
}

.validation-message {
color: red;
}
</style>

<EditForm EditContext="@editContext" OnValidSubmit="HandleOnValidSubmit">
<DataAnnotationsValidator />

Expand Down
Loading
Loading