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
@@ -1,4 +1,4 @@
<FluentSelect TOption="ImageFit" Items="@(Enum.GetValues<ImageFit>())" @bind-Value="@_selectedFit" />
<FluentSelect Items="@(Enum.GetValues<ImageFit>())" @bind-Value="@_selectedFit" />
<div style="width: auto; height: 400px; margin-top: 10px">
<FluentImage Fit="@_selectedFit" Source="/big-heart.jpg" AlternateText="Placeholder Image" />
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<FluentSelect TOption="ImageShape" Items="@(Enum.GetValues<ImageShape>())" @bind-Value="@_selectedShape" />
<FluentSelect Items="@(Enum.GetValues<ImageShape>())" @bind-Value="@_selectedShape" />
<div style="width: auto; height: 300px; margin-top: 10px">
<FluentImage Shape="@_selectedShape" Source="/big-heart.jpg" AlternateText="Placeholder Image" />
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<FluentCombobox Label="Countries"
TOption="@SampleData.Olympics2024.Country"
Placeholder="Select your countries"
Multiple="true"
OptionText="@(i => i?.Name)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,20 @@ You can customize the items in the **FluentSelect** component by using Lambda ex
The following example shows how to customize the items:
- `OptionText`: This function is used to customize the text of the option. <br />
- `OptionValue`: This function is used to customize the value of the option. <br />
- `OptionValueToString`: This function is used to customize the HTML value of the option. <br />
- `OptionDisabled`: This function is used to define the disabled options. <br />

See a similar example on the [FluentSelect](/List/Select#customize-the-items) page.

## API FluentCombobox

{{ API Type=FluentCombobox }}
{{ API Type=FluentCombobox<string,string> }}

> [!NOTE] The `Width` parameter is not yet implemented.

## API FluentOption

{{ API Type=FluentOption }}
{{ API Type=FluentOption<string> }}

## Migrating to v5

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<FluentOption Selected>
<FluentOption TValue="string" Selected>
<FluentAvatar Size="AvatarSize.Size16" Color="AvatarColor.Blue" Slot="@FluentSlot.Start">16</FluentAvatar>
Option with 16px avatar
</FluentOption>
<br />

<FluentOption>
<FluentOption TValue="string">
<FluentIcon Value="@(new Icons.Regular.Size24.Globe())" Color="Color.Error" Slot="@FluentSlot.Start" />
Option with 24px icon
</FluentOption>
<br />
<FluentOption Selected Description="Additional information can be provided with the description parameter">
<FluentOption TValue="string" Selected Description="Additional information can be provided with the description parameter">
<FluentAvatar Size="AvatarSize.Size32" Color="AvatarColor.Blue" Slot="@FluentSlot.Start">32</FluentAvatar>
Option with 32px avatar
</FluentOption>
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,5 @@

@code {
static string[] Colors = ["Red", "Green", "Blue"];
string Value = "Red";
string Value = "Green";
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Items="@Coworkers"
@bind-Value="@Value"
OptionText="@(item => item?.FirstName)"
OptionValue="@(item => item?.Id)"
OptionValueToString="@(item => item?.Id)"
OptionDisabled="@(item => item == Coworkers.ElementAt(3))" />

<div>
Expand All @@ -14,8 +14,7 @@

@code {
static Samples.Person?[] OneNullPerson = new Samples.Person?[] { null };
static Samples.Person?[] Coworkers =>
OneNullPerson.Union(Samples.Persons.Take(5).ToArray()).ToArray();
static Samples.Person?[] Coworkers = OneNullPerson.Union(Samples.Persons.Take(5).ToArray()).ToArray();

Samples.Person? Value = Coworkers.ElementAt(2);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Items="@GetEnumValues()"
@bind-Value="@Value">
<OptionTemplate>
<FluentStack>
<FluentStack Style="pointer-events: none;">
<div class="color-block" style="--item-color: @context.ToAttributeValue()"></div>
<span>@context</span>
</FluentStack>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!-- Using Items -->
<FluentSelect Label="Language"
Items="@Languages"
@bind-Value="@SelectedId1"
OptionText="@(i => i.Name)"
OptionValue="@(i => i.Id)" />

<!-- Using FluentOptions -->
<FluentSelect Label="Language"
TOption="Language"
TValue="int?"
@bind-Value="@SelectedId2">
<FluentOption TValue="int?" Value="@(null)" Text="[Select]" />
@foreach (var language in Languages)
{
<FluentOption TValue="int?" Value="@language.Id">
@language.Name
</FluentOption>
}
</FluentSelect>

<div>
IDs: (@SelectedId1, @SelectedId2)
</div>

@code {

int SelectedId1 = 3;
int? SelectedId2 = 3;

static Language[] Languages = new Language[]
{
new(1, "C#"),
new(2, "Java"),
new(3, "Python"),
new(4, "JavaScript"),
new(5, "Go")
};

record Language(int Id, string Name);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
<FluentSelect Label="RGB Color"
<FluentSelect TOption="string"
TValue="string"
Label="RGB Color"
Placeholder="Select a color"
@bind-Value="@Value">
<FluentOption Value="#ff0000">Red</FluentOption>
<FluentOption Value="#00ff00">Green</FluentOption>
<FluentOption Value="#0000ff">Blue</FluentOption>
<FluentOptionString Value="ff0000">Red</FluentOptionString>
<FluentOptionString Value="00ff00">Green</FluentOptionString>
<FluentOptionString Value="0000ff">Blue</FluentOptionString>
</FluentSelect>

<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
Placeholder="Select a name"
Items="@Persons"
OptionText="@(i => $"{i?.FirstName} {i?.LastName}")"
OptionValue="@(i => $"{i?.Id}")"
OptionValueToString="@(i => $"{i?.Id}")"
Height="200px"
Width="300px"
@bind-Value="@Selected" />

<div>
Selected: @Selected?.FirstName
Selected: @Selected?.FirstName @Selected?.LastName
</div>

@code {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
<FluentSelect Label="Color"
Placeholder="Select colors"
Items="@Colors"
TOption="string"
TValue="string"
@bind-SelectedItems="@SelectedItems"
Multiple="true" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ The following example shows how to customize the items:
In the following example, the **FirstName** is used.
- `OptionValue`: This function is used to customize the value of the option.
In the following example, the **Id** is returned.
- `OptionValueToString`: This function is used to customize the HTML value of the option.
- `OptionDisabled`: This function is used to define the disabled options.
In the following example, the third element is disabled.

Expand All @@ -49,6 +50,10 @@ on the checkbox to select an item.

{{ SelectEnum }}

> [!NOTE] In some situation, the option elements may not catch the click event to select the item.
> To avoid this, you can use the `Style="pointer-events: none;"` to disable the pointer events
> on the element and let the click event pass through to the parent element.

## Multiple

Use the **Multiple** parameter to enable multiple selections.
Expand Down Expand Up @@ -77,8 +82,21 @@ An option can also use the `Description` parameter to display additional informa

An example of using the `FluentOption` components directly in the `Select` is shown below.

**Notes:**
1. The two parameters `TOption="string"` and `TValue="string"` are required to indicate the type of options.
1. To simplify writing a `<FluentOption TValue="string">` we introduced a `<FluentOptionString>`.
This component simply and directly inherits from `FluentOption<string>`.

{{ SelectManual }}

Demonstrates two-way data binding with `FluentSelect` using `@bind-Value` to bind an integer value from a collection of a complex object.

{{ SelectLanguage }}

**Note:** If you programmatically change the value of a manually constructed list (using `FluentOption`),
you will likely need to add an attribute `@key=“@SelectedId”` to force Blazor to redraw the component correctly.
This is the case in the above example: `@key="@(SelectedId2 ?? 0)"`.

## Many items

You can use this component with a large number of items.
Expand All @@ -89,13 +107,11 @@ If you have a very large number of items, you should use the **FluentAutocomplet

## API FluentSelect

{{ API Type=FluentSelect }}

> [!NOTE] The `Width` parameter is not yet implemented.
{{ API Type=FluentSelect<string,string> }}

## API FluentOption

{{ API Type=FluentOption }}
{{ API Type=FluentOption<string> }}

## Migrating to v5

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<FluentSelect Items="@([true, false, null])"
OptionText="@(i => GetVisibleText(i) )"
TOption="bool?"
TValue="bool?"
@bind-Value="@Visible" />

@code
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<FluentSelect Items="@([true, false, null])"
OptionText="@(i => GetVisibleText(i) )"
TOption="bool?"
TValue="bool?"
@bind-Value="@Visible" />

@code
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,28 +122,42 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
var componentType = "";

// Convert "MyComponent<MyType>" to ("MyComponent", "MyType")
var match = Regex.Match(name, @"(\w+)<(\w+)>");
var match = Regex.Match(name, @"(\w+)(&lt;|<)(.+)(>|&gt;)");
if (match.Success)
{
componentName = match.Groups[1].Value;
componentType = match.Groups[2].Value;
componentType = match.Groups[3].Value;
}

// Get the component type
var type = DocViewerService.ApiAssembly
?.GetTypes()
?.FirstOrDefault(i => i.Name == componentName || i.Name.StartsWith($"{componentName}`1"));
?.FirstOrDefault(i => i.Name == componentName
|| i.Name.StartsWith($"{componentName}`1")
|| i.Name.StartsWith($"{componentName}`2"));

// Create the ApiClass
var result = type is null ? null : new ApiClass(DocViewerService, type, allProperties);

// if the component type is specified, set the InstanceTypes
if (result != null && !string.IsNullOrEmpty(componentType))
{
type = ReflectionExtensions.KnownTypeNames
.FirstOrDefault(i => string.Compare(i.Value, componentType, StringComparison.InvariantCultureIgnoreCase) == 0)
.Key;
result.InstanceTypes = [type];
var listOfTypes = new List<Type>();

foreach (var typeName in componentType.Split(','))
{
var t = ReflectionExtensions.KnownTypeNames
.FirstOrDefault(i => string.Compare(i.Value, typeName.Trim(), StringComparison.InvariantCultureIgnoreCase) == 0)
.Key;

if (t is not null)
{
listOfTypes.Add(t);
}
}


result.InstanceTypes = listOfTypes.ToArray();
}

return result;
Expand Down
6 changes: 6 additions & 0 deletions examples/Tools/FluentUI.Demo.SampleData/People.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ public record Person(string Id, string FirstName, string LastName, bool Male, st
/// Gets the age of the person
/// </summary>
public int Age => DateTime.Today.Year - BirthDay.Year;

/// <summary />
public override string ToString()
{
return $"{Id} - {FirstName} {LastName}";
}
}

/// <summary>
Expand Down
5 changes: 3 additions & 2 deletions src/Core/Components/DateTime/FluentTimePicker.razor
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
{
<FluentCombobox @ref="_fluentCombobox"
Id="@Id"
TOption="DateTime ?"
TOption="DateTime?"
TValue="DateTime?"
Class="@ClassValue"
Style="@StyleValue"
Label="@Label"
Expand All @@ -21,7 +22,7 @@
@bind-Value="SelectedValue"
@onkeydown="@KeyDownHandlerAsync"
OptionText="@(i => i?.ToString(TimePattern))"
OptionValue="@(i => FormatValueAsString(i))"
OptionValueToString="@(i => FormatValueAsString(i))"
OptionSelectedComparer="@((i, j) => i?.Hour == j?.Hour && i?.Minute == j?.Minute)"
OptionDisabled="@DisableHourHandler"
Required="@Required"
Expand Down
6 changes: 3 additions & 3 deletions src/Core/Components/DateTime/FluentTimePicker.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Microsoft.FluentUI.AspNetCore.Components;
public partial class FluentTimePicker<TValue> : FluentInputBase<TValue>
{
private DateTime DefaultTime => Culture.Calendar.MinSupportedDateTime;
private FluentCombobox<DateTime?> _fluentCombobox = default!;
private FluentCombobox<DateTime?, DateTime?> _fluentCombobox = default!;

/// <summary />
public FluentTimePicker(LibraryConfiguration configuration) : base(configuration)
Expand Down Expand Up @@ -186,7 +186,7 @@ protected override bool TryParseValueFromString(string? value, [MaybeNullWhen(fa
{
DateTime dt => dt.ToString("HH:mm:ss", CultureInfo.InvariantCulture),
TimeOnly to => to.ToString("HH:mm:ss", CultureInfo.InvariantCulture),
_ => null
_ => null,
};
}

Expand Down Expand Up @@ -241,7 +241,7 @@ private TextInputAppearance TextInputAppearance
ListAppearance.FilledDarker => TextInputAppearance.FilledDarker,
ListAppearance.Outline => TextInputAppearance.Outline,
ListAppearance.Transparent => TextInputAppearance.Underline,
_ => TextInputAppearance.Outline
_ => TextInputAppearance.Outline,
};
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Core/Components/List/FluentCombobox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ namespace Microsoft.FluentUI.AspNetCore.Components;
/// <summary>
/// A FluentCombobox allows one option to be selected from multiple items.
/// </summary>
/// <typeparam name="TOption"></typeparam>
public partial class FluentCombobox<TOption> : FluentSelect<TOption>
[CascadingTypeParameter(nameof(TValue))]
public partial class FluentCombobox<TOption, TValue> : FluentSelect<TOption, TValue>
{
/// <summary />
public FluentCombobox(LibraryConfiguration configuration) : base(configuration) { }
Expand Down
8 changes: 5 additions & 3 deletions src/Core/Components/List/FluentListBase.razor
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
@namespace Microsoft.FluentUI.AspNetCore.Components
@using Microsoft.AspNetCore.Components.Rendering
@inherits FluentInputBase<TOption>
@inherits FluentInputBase<TValue>
@typeparam TOption
@typeparam TValue

@code
{
Expand All @@ -24,8 +25,9 @@
}

foreach (var item in Items)
{
<FluentOption Data="@item"
{
<FluentOption TValue="TValue"
Data="@item"
Text="@GetOptionText(item)"
Value="@GetOptionValue(item)"
Selected="@(GetOptionSelected(item))"
Expand Down
Loading
Loading