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
Next Next commit
feat(listbox): add baseline implementation of ListBox and ListBoxItem…
… components
  • Loading branch information
desmondinho committed Dec 5, 2024
commit 86c0fdf0ceca837ab723de26e6cc590c5e80b7ee
8 changes: 8 additions & 0 deletions src/LumexUI/Components/Listbox/ListboxContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using LumexUI.Common;

namespace LumexUI;

internal class ListboxContext<T>( LumexListbox<T> owner ) : IComponentContext<LumexListbox<T>>
{
public LumexListbox<T> Owner { get; } = owner;
}
24 changes: 24 additions & 0 deletions src/LumexUI/Components/Listbox/ListboxItemSlots.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using LumexUI.Common;

namespace LumexUI;

/// <summary>
///
/// </summary>
public class ListboxItemSlots : ISlot
{
/// <summary>
///
/// </summary>
public string? Root { get; set; }

/// <summary>
///
/// </summary>
public string? Wrapper { get; set; }

/// <summary>
///
/// </summary>
public string? Title { get; set; }
}
24 changes: 24 additions & 0 deletions src/LumexUI/Components/Listbox/ListboxSlots.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using LumexUI.Common;

namespace LumexUI;

/// <summary>
///
/// </summary>
public class ListboxSlots : ISlot
{
/// <summary>
///
/// </summary>
public string? Root { get; set; }

/// <summary>
///
/// </summary>
public string? List { get; set; }

/// <summary>
///
/// </summary>
public string? EmptyContent { get; set; }
}
36 changes: 36 additions & 0 deletions src/LumexUI/Components/Listbox/LumexListbox.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
@namespace LumexUI
@inherits LumexComponentBase
@typeparam T

<CascadingValue TValue="ListboxContext<T>" Value="@_context" IsFixed="@true">
<div class="@_slots.Root"
style="@RootStyle"
data-slot="base"
@attributes="@AdditionalAttributes">
<LumexComponent As="@As"
Class="@_slots.List"
data-slot="list">
@if( !Items?.Any() ?? false )
{
<li>
<div class="@_slots.EmptyContent" data-slot="empty-content">
@EmptyContent
</div>
</li>
}
@if( Items is not null )
{
foreach( var item in Items )
{
<LumexListboxItem T="T" @key="@item">
@item
</LumexListboxItem>
}
}
else if( ChildContent is not null )
{
@ChildContent
}
</LumexComponent>
</div>
</CascadingValue>
52 changes: 52 additions & 0 deletions src/LumexUI/Components/Listbox/LumexListbox.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) LumexUI 2024
// LumexUI licenses this file to you under the MIT license
// See the license here https://github.com/LumexUI/lumexui/blob/main/LICENSE

using LumexUI.Styles;

using Microsoft.AspNetCore.Components;

namespace LumexUI;

/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
[CascadingTypeParameter( nameof( T ) )]
public partial class LumexListbox<T> : LumexComponentBase
{
/// <summary>
///
/// </summary>
[Parameter] public RenderFragment? ChildContent { get; set; }

/// <summary>
///
/// </summary>
[Parameter] public RenderFragment? EmptyContent { get; set; }

/// <summary>
///
/// </summary>
[Parameter] public IEnumerable<T>? Items { get; set; }

private readonly ListboxContext<T> _context;

private ListboxSlots _slots = default!;

/// <summary>
/// Initializes a new instance of the <see cref="LumexListbox{T}"/>.
/// </summary>
public LumexListbox()
{
_context = new ListboxContext<T>( this );

As = "ul";
}

/// <inheritdoc />
protected override void OnParametersSet()
{
_slots ??= Listbox.GetStyles( this, TwMerge );
}
}
13 changes: 13 additions & 0 deletions src/LumexUI/Components/Listbox/LumexListboxItem.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@namespace LumexUI
@inherits LumexComponentBase
@typeparam T

<LumexComponent As="@As"
Class="@_slots.Root"
Style="@RootStyle"
data-slot="base"
@attributes="@AdditionalAttributes">
<span class="@_slots.Title" data-slot="title">
@ChildContent
</span>
</LumexComponent>
46 changes: 46 additions & 0 deletions src/LumexUI/Components/Listbox/LumexListboxItem.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) LumexUI 2024
// LumexUI licenses this file to you under the MIT license
// See the license here https://github.com/LumexUI/lumexui/blob/main/LICENSE

using LumexUI.Common;
using LumexUI.Styles;

using Microsoft.AspNetCore.Components;

namespace LumexUI;

/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
public partial class LumexListboxItem<T> : LumexComponentBase
{
/// <summary>
///
/// </summary>
[Parameter] public RenderFragment? ChildContent { get; set; }

[CascadingParameter] internal ListboxContext<T> Context { get; set; } = default!;

private ListboxItemSlots _slots = default!;

/// <summary>
/// Initializes a new instance of the <see cref="LumexListboxItem{T}"/>.
/// </summary>
public LumexListboxItem()
{
As = "li";
}

/// <inheritdoc />
protected override void OnInitialized()
{
ContextNullException.ThrowIfNull( Context, nameof( LumexListboxItem<T> ) );
}

/// <inheritdoc />
protected override void OnParametersSet()
{
_slots ??= ListboxItem.GetStyles( this, TwMerge );
}
}
114 changes: 114 additions & 0 deletions src/LumexUI/Styles/Listbox.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System.Diagnostics.CodeAnalysis;

using LumexUI.Utilities;

using TailwindMerge;

namespace LumexUI.Styles;

[ExcludeFromCodeCoverage]
internal class Listbox
{
private readonly static string _base = ElementClass.Empty()
.Add( "relative" )
.Add( "w-full" )
.Add( "p-1" )
.Add( "gap-1" )
.Add( "flex" )
.Add( "flex-col" )
.ToString();

private readonly static string _list = ElementClass.Empty()
.Add( "w-full" )
.Add( "gap-0.5" )
.Add( "flex" )
.Add( "flex-col" )
.ToString();

private readonly static string _emptyContent = ElementClass.Empty()
.Add( "w-full" )
.Add( "h-10" )
.Add( "px-2" )
.Add( "py-1.5" )
.Add( "text-start" )
.Add( "text-foreground-400" )
.ToString();

public static ListboxSlots GetStyles<T>( LumexListbox<T> listbox, TwMerge twMerge )
{
return new ListboxSlots()
{
Root = twMerge.Merge(
ElementClass.Empty()
.Add( _base )
.Add( listbox.Class )
.ToString() ),

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

EmptyContent = twMerge.Merge(
ElementClass.Empty()
.Add( _emptyContent )
.ToString() ),
};
}
}

[ExcludeFromCodeCoverage]
internal class ListboxItem
{
private readonly static string _base = ElementClass.Empty()
.Add( "relative" )
.Add( "group" )
.Add( "w-full" )
.Add( "h-full" )
.Add( "px-2" )
.Add( "py-1.5" )
.Add( "gap-2" )
.Add( "flex" )
.Add( "items-center" )
.Add( "justify-between" )
.Add( "rounded-small" )
.Add( "cursor-pointer" )
// focus ring
.Add( Utils.FocusVisible )
.ToString();

private readonly static string _wrapper = ElementClass.Empty()
.Add( "w-full" )
.Add( "flex" )
.Add( "flex-col" )
.Add( "items-start" )
.Add( "justify-center" )
.ToString();

private readonly static string _title = ElementClass.Empty()
.Add( "flex-1" )
.Add( "text-small" )
.ToString();

public static ListboxItemSlots GetStyles<T>( LumexListboxItem<T> listboxItem, TwMerge twMerge )
{
return new ListboxItemSlots()
{
Root = twMerge.Merge(
ElementClass.Empty()
.Add( _base )
.Add( listboxItem.Class )
.ToString() ),

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

Title = twMerge.Merge(
ElementClass.Empty()
.Add( _title )
.ToString() ),
};
}
}