Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
86c0fdf
feat(listbox): add baseline implementation of ListBox and ListBoxItem…
desmondinho Dec 5, 2024
e2abc1b
feat(listbox): add `Color` and `Variant` params to Listbox and Listbo…
desmondinho Dec 5, 2024
78bb3bc
refactor(listbox): move Items list into the context
desmondinho Dec 8, 2024
f92b5a0
feat: add a new `transition-colors-shadow` transition
desmondinho Dec 8, 2024
d6e98a6
feat: defer content rendering to collect the items first
desmondinho Dec 8, 2024
778af3a
feat: allow single and multiple selection
desmondinho Dec 8, 2024
ffc5d07
feat: add start/end content parameters
desmondinho Dec 8, 2024
83ab5bd
feat: add `Description` param to the ListboxItem
desmondinho Dec 8, 2024
83d55ce
feat: add Disabled state
desmondinho Dec 9, 2024
2f4ffd9
feat: add OnClick callback on the ListboxItem component
desmondinho Dec 9, 2024
cc9acae
chore: XML summaries
desmondinho Dec 9, 2024
fac2667
feat(docs): add baseline for the listbox component page
desmondinho Dec 9, 2024
d81cc17
feat(popover): add `MatchRefWidth` parameter to the popover component
desmondinho Dec 11, 2024
c2c2354
feat(popover): add 2-way-bindable `Opened` param to the popover compo…
desmondinho Dec 11, 2024
eee0245
feat(popover): make the `Id` a public param
desmondinho Dec 11, 2024
247e5b2
feat(listbox-item): rename `Id` param to `Value`
desmondinho Dec 11, 2024
afae751
chore(input): nits
desmondinho Dec 11, 2024
183010f
feat(extensions): add baseline implementation of the Select component
desmondinho Dec 11, 2024
6498a3c
refactor: allow binding to a single item or multiple items
desmondinho Dec 21, 2024
7523539
feat: implement slots for the listbox and listbox item components
desmondinho Dec 22, 2024
f4a5ae0
feat(docs): complete the listbox component page
desmondinho Dec 22, 2024
fcb4713
feat(popover): add `MatchRefWidth` parameter to the popover component
desmondinho Dec 11, 2024
1a38eeb
feat(popover): add 2-way-bindable `Opened` param to the popover compo…
desmondinho Dec 11, 2024
8c4777f
feat(popover): make the `Id` a public param
desmondinho Dec 11, 2024
4108557
chore(input): nits
desmondinho Dec 11, 2024
241d519
feat(extensions): add baseline implementation of the Select component
desmondinho Dec 11, 2024
4c97b83
feat: add `TextValue` param to the SelectItem component
desmondinho Dec 13, 2024
2f69757
fix: styles
desmondinho Dec 13, 2024
6f41ac5
chore: rebase feat/select onto feat/listbox
desmondinho Dec 22, 2024
fc080c0
chore(listbox): nits
desmondinho Dec 23, 2024
bbab444
chore: improve rendering logic
desmondinho Dec 24, 2024
083f200
feat(plugin): add 'scrollbar-hide' CSS utility
desmondinho Dec 25, 2024
6186624
feat: implement slots
desmondinho Dec 25, 2024
989c607
feat: add `ListboxMaxHeight` parameter
desmondinho Dec 25, 2024
e42dde3
feat: add `DisabledItems` parameter
desmondinho Dec 25, 2024
7072077
feat: add `ValueContent` parameter
desmondinho Dec 25, 2024
ba9f5e8
chore: nits
desmondinho Dec 25, 2024
d2e5162
chore: add missing XML docs
desmondinho Dec 25, 2024
6900664
fix(listbox): apply CSS classes of an individual listbox item to its …
desmondinho Dec 25, 2024
50f5070
feat: add `PopoverClasses` and `ListboxClasses` parameters
desmondinho Dec 25, 2024
4fea1d4
feat(docs): add the `New` component status badge
desmondinho Dec 25, 2024
853b989
feat(docs): add the Select page
desmondinho Dec 25, 2024
95bb0ae
test(popover): fix broken tests
desmondinho Dec 25, 2024
9fb7378
chore: exclude slots from code coverage; nits
desmondinho Dec 26, 2024
1e4a42a
refactor: move value(s) selection logic into the listbox component
desmondinho Dec 26, 2024
2d37e99
test: add tests
desmondinho Dec 26, 2024
bcf081d
feat(popover): add `MatchRefWidth` parameter to the popover component
desmondinho Dec 11, 2024
308988a
feat(popover): add 2-way-bindable `Opened` param to the popover compo…
desmondinho Dec 11, 2024
b2fbec5
feat(popover): make the `Id` a public param
desmondinho Dec 11, 2024
de83d23
chore(input): nits
desmondinho Dec 11, 2024
fee6d07
feat(extensions): add baseline implementation of the Select component
desmondinho Dec 11, 2024
e98b79d
feat: add `TextValue` param to the SelectItem component
desmondinho Dec 13, 2024
089e42d
fix: styles
desmondinho Dec 13, 2024
4dfcaf3
feat(popover): add `MatchRefWidth` parameter to the popover component
desmondinho Dec 11, 2024
23a85f7
feat(popover): add 2-way-bindable `Opened` param to the popover compo…
desmondinho Dec 11, 2024
ace679f
feat(popover): make the `Id` a public param
desmondinho Dec 11, 2024
5f51855
feat(listbox-item): rename `Id` param to `Value`
desmondinho Dec 11, 2024
4acf515
feat(extensions): add baseline implementation of the Select component
desmondinho Dec 11, 2024
420439b
chore(listbox): nits
desmondinho Dec 23, 2024
2985122
chore: improve rendering logic
desmondinho Dec 24, 2024
0e1ac0a
feat(plugin): add 'scrollbar-hide' CSS utility
desmondinho Dec 25, 2024
29d6817
feat: implement slots
desmondinho Dec 25, 2024
b4b5cce
feat: add `ListboxMaxHeight` parameter
desmondinho Dec 25, 2024
39a48bd
feat: add `DisabledItems` parameter
desmondinho Dec 25, 2024
e14b6a7
feat: add `ValueContent` parameter
desmondinho Dec 25, 2024
90e2cc4
chore: nits
desmondinho Dec 25, 2024
212dc87
chore: add missing XML docs
desmondinho Dec 25, 2024
f6ee4d2
fix(listbox): apply CSS classes of an individual listbox item to its …
desmondinho Dec 25, 2024
98cbc20
feat: add `PopoverClasses` and `ListboxClasses` parameters
desmondinho Dec 25, 2024
b8701af
feat(docs): add the `New` component status badge
desmondinho Dec 25, 2024
b56f5ce
feat(docs): add the Select page
desmondinho Dec 25, 2024
da0baee
test(popover): fix broken tests
desmondinho Dec 25, 2024
8911805
chore: merge feat/listbox into feat/select
desmondinho Dec 26, 2024
46f80c6
chore: fix part of incorrectly merged code
desmondinho Dec 26, 2024
a8f619d
docs(listbox): replace the "Selection" section with "Two-way Data Bin…
desmondinho Dec 26, 2024
b4400e6
docs(select): wording
desmondinho Dec 26, 2024
0743058
chore: nits
desmondinho Dec 27, 2024
1b1f919
test: add tests
desmondinho Dec 27, 2024
318a21b
docs(listbox/select): nits
desmondinho Dec 27, 2024
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
Prev Previous commit
Next Next commit
feat: implement slots for the listbox and listbox item components
  • Loading branch information
desmondinho committed Dec 22, 2024
commit 7523539ebe6a9b3ad29afe95a333c70d2f9e4fa4
28 changes: 26 additions & 2 deletions src/LumexUI/Components/Listbox/LumexListbox.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using LumexUI.Common;
using LumexUI.Styles;
using LumexUI.Utilities;

using Microsoft.AspNetCore.Components;

Expand All @@ -14,7 +15,7 @@ namespace LumexUI;
/// </summary>
/// <typeparam name="TValue">The type of the values associated with the items in the listbox.</typeparam>
[CascadingTypeParameter( nameof( TValue ) )]
public partial class LumexListbox<TValue> : LumexComponentBase
public partial class LumexListbox<TValue> : LumexComponentBase, ISlotComponent<ListboxSlots>
{
/// <summary>
/// Gets or sets content to be rendered inside the listbox.
Expand Down Expand Up @@ -67,12 +68,23 @@ public partial class LumexListbox<TValue> : LumexComponentBase
/// </summary>
[Parameter] public EventCallback<ICollection<TValue?>> ValuesChanged { get; set; }

/// <summary>
/// Gets or sets the CSS class names for the listbox slots.
/// </summary>
[Parameter] public ListboxSlots? Classes { get; set; }

/// <summary>
/// Gets or sets the CSS class names for the listbox items slots.
/// </summary>
[Parameter] public ListboxItemSlots? ItemClasses { get; set; }

private readonly static RenderFragment _emptyContent = builder =>
{
builder.AddContent( 0, "No items." );
};

private readonly ListboxContext<TValue> _context;
private readonly Memoizer<ListboxSlots> _slotsMemoizer;
private readonly RenderFragment _renderItems;
private readonly RenderFragment _renderEmptyContent;

Expand All @@ -84,6 +96,7 @@ public partial class LumexListbox<TValue> : LumexComponentBase
public LumexListbox()
{
_context = new ListboxContext<TValue>( this );
_slotsMemoizer = new Memoizer<ListboxSlots>();
_renderItems = RenderItems;
_renderEmptyContent = RenderEmptyContent;

Expand Down Expand Up @@ -119,6 +132,17 @@ public override Task SetParametersAsync( ParameterView parameters )
/// <inheritdoc />
protected override void OnParametersSet()
{
_slots ??= Listbox.GetStyles( this, TwMerge );
// Perform a re-building only if the dependencies have changed
_slots = _slotsMemoizer.Memoize( GetSlots, [
Color,
Variant,
Classes,
Class
] );
}

private ListboxSlots GetSlots()
{
return Listbox.GetStyles( this, TwMerge );
}
}
27 changes: 24 additions & 3 deletions src/LumexUI/Components/Listbox/LumexListboxItem.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

using LumexUI.Common;
using LumexUI.Styles;
using LumexUI.Utilities;

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
Expand All @@ -16,7 +17,8 @@ namespace LumexUI;
/// A component representing an item within the <see cref="LumexListbox{T}"/>.
/// </summary>
/// <typeparam name="TValue">The type of the value associated with the listbox item.</typeparam>
public partial class LumexListboxItem<TValue> : LumexComponentBase, IDisposable
[CompositionComponent( typeof( LumexListbox<> ) )]
public partial class LumexListboxItem<TValue> : LumexComponentBase, ISlotComponent<ListboxItemSlots>, IDisposable
{
/// <summary>
/// Gets or sets content to be rendered inside the listbox item.
Expand Down Expand Up @@ -69,10 +71,16 @@ public partial class LumexListboxItem<TValue> : LumexComponentBase, IDisposable
/// </summary>
[Parameter] public EventCallback<MouseEventArgs> OnClick { get; set; }

/// <summary>
/// Gets or sets the CSS class names for the listbox item slots.
/// </summary>
[Parameter] public ListboxItemSlots? Classes { get; set; }

[CascadingParameter] internal ListboxContext<TValue>? Context { get; set; }

private LumexListbox<TValue>? Listbox => Context?.Owner;

private readonly Memoizer<ListboxItemSlots> _slotsMemoizer;
private readonly RenderFragment _renderSelectedIcon;

private ListboxItemSlots _slots = default!;
Expand All @@ -82,6 +90,7 @@ public partial class LumexListboxItem<TValue> : LumexComponentBase, IDisposable
/// </summary>
public LumexListboxItem()
{
_slotsMemoizer = new Memoizer<ListboxItemSlots>();
_renderSelectedIcon = RenderSelectedIcon;

As = "li";
Expand Down Expand Up @@ -117,15 +126,22 @@ protected override void OnInitialized()
/// <inheritdoc />
protected override void OnParametersSet()
{
_slots ??= ListboxItem.GetStyles( this, TwMerge );
// Perform a re-building only if the dependencies have changed
_slots = _slotsMemoizer.Memoize( GetSlots, [
Color,
Variant,
GetDisabledState(),
Classes,
Class
] );
}

internal bool GetSelectedState() =>
Listbox?.Value?.Equals( Value ) is true ||
Listbox?.Values?.Contains( Value ) is true;

internal bool GetDisabledState() =>
Listbox?.DisabledItems?.Contains( Value ) is true;
Disabled || Listbox?.DisabledItems?.Contains( Value ) is true;

private async Task OnClickAsync( MouseEventArgs args )
{
Expand Down Expand Up @@ -164,6 +180,11 @@ private Task SelectAsync()
return Task.CompletedTask;
}

private ListboxItemSlots GetSlots()
{
return ListboxItem.GetStyles( this, TwMerge );
}

/// <inheritdoc />
public virtual void Dispose()
{
Expand Down
26 changes: 18 additions & 8 deletions src/LumexUI/Styles/Listbox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,20 @@ public static ListboxSlots GetStyles<T>( LumexListbox<T> listbox, TwMerge twMerg
Root = twMerge.Merge(
ElementClass.Empty()
.Add( _base )
.Add( listbox.Classes?.Root )
.Add( listbox.Class )
.ToString() ),

List = twMerge.Merge(
ElementClass.Empty()
.Add( _list )
.Add( listbox.Classes?.List )
.ToString() ),

EmptyContent = twMerge.Merge(
ElementClass.Empty()
.Add( _emptyContent )
.Add( listbox.Classes?.EmptyContent )
.ToString() ),
};
}
Expand Down Expand Up @@ -115,35 +118,42 @@ internal class ListboxItem

public static ListboxItemSlots GetStyles<T>( LumexListboxItem<T> listboxItem, TwMerge twMerge )
{
var listbox = listboxItem.Context?.Owner;

return new ListboxItemSlots()
{
Root = twMerge.Merge(
ElementClass.Empty()
.Add( _base )
.Add( _disabled, when: listboxItem.GetDisabledState() )
.Add( listboxItem.Class )
.Add( GetVariantStyles( listboxItem.Variant, slot: nameof( _base ) ) )
.Add( GetCompoundStyles( listboxItem.Variant, listboxItem.Color, slot: nameof( _base ) ) )
.Add( listbox?.ItemClasses?.Root )
.Add( listboxItem.Class )
.ToString() ),

Wrapper = twMerge.Merge(
ElementClass.Empty()
.Add( _wrapper )
.Add( listbox?.ItemClasses?.Wrapper )
.ToString() ),

Title = twMerge.Merge(
ElementClass.Empty()
.Add( _title )
.Add( listbox?.ItemClasses?.Title )
.ToString() ),

Description = twMerge.Merge(
ElementClass.Empty()
.Add( _description )
.Add( listbox?.ItemClasses?.Description )
.ToString() ),

SelectedIcon = twMerge.Merge(
ElementClass.Empty()
.Add( _selectedIcon )
.Add( listbox?.ItemClasses?.SelectedIcon )
.ToString() ),
};
}
Expand All @@ -156,7 +166,7 @@ private static ElementClass GetVariantStyles( ListboxVariant variant, string slo
.Add( "", when: slot is nameof( _base ) ),

ListboxVariant.Outlined => ElementClass.Empty()
.Add( "border-medium border-transparent bg-transparent", when: slot is nameof( _base ) ),
.Add( "border-2 border-transparent bg-transparent", when: slot is nameof( _base ) ),

ListboxVariant.Flat => ElementClass.Empty()
.Add( "", when: slot is nameof( _base ) ),
Expand Down Expand Up @@ -213,27 +223,27 @@ private static ElementClass GetCompoundStyles( ListboxVariant variant, ThemeColo

(ListboxVariant.Outlined, ThemeColor.Primary ) => ElementClass.Empty()
.Add( ElementClass.Empty()
.Add( "hover:border-primary" ), when: slot is nameof( _base ) ),
.Add( "hover:border-primary hover:text-primary" ), when: slot is nameof( _base ) ),

(ListboxVariant.Outlined, ThemeColor.Secondary ) => ElementClass.Empty()
.Add( ElementClass.Empty()
.Add( "hover:border-secondary" ), when: slot is nameof( _base ) ),
.Add( "hover:border-secondary hover:text-secondary" ), when: slot is nameof( _base ) ),

(ListboxVariant.Outlined, ThemeColor.Success ) => ElementClass.Empty()
.Add( ElementClass.Empty()
.Add( "hover:border-success" ), when: slot is nameof( _base ) ),
.Add( "hover:border-success hover:text-success" ), when: slot is nameof( _base ) ),

(ListboxVariant.Outlined, ThemeColor.Warning ) => ElementClass.Empty()
.Add( ElementClass.Empty()
.Add( "hover:border-warning" ), when: slot is nameof( _base ) ),
.Add( "hover:border-warning hover:text-warning" ), when: slot is nameof( _base ) ),

(ListboxVariant.Outlined, ThemeColor.Danger ) => ElementClass.Empty()
.Add( ElementClass.Empty()
.Add( "hover:border-danger" ), when: slot is nameof( _base ) ),
.Add( "hover:border-danger hover:text-danger" ), when: slot is nameof( _base ) ),

(ListboxVariant.Outlined, ThemeColor.Info ) => ElementClass.Empty()
.Add( ElementClass.Empty()
.Add( "hover:border-info" ), when: slot is nameof( _base ) ),
.Add( "hover:border-info hover:text-info" ), when: slot is nameof( _base ) ),

// flat / color

Expand Down