Skip to content

Commit

Permalink
fix: support scoped CSS in Node.Elt (#336)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tarmil committed Nov 20, 2023
1 parent 49b9d02 commit bad1b3a
Show file tree
Hide file tree
Showing 11 changed files with 66 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<Paket>True</Paket>
<Link>paket-files/ProvidedTypes.fs</Link>
</Compile>
<Compile Include="..\Bolero\NodeTypes.fs" Link="NodeTypes.fs" />
<Compile Include="..\Bolero\Attr.fs" Link="Attr.fs" />
<Compile Include="..\Bolero\Node.fs" Link="Node.fs" />
<Compile Include="..\Bolero\Ref.fs" Link="Ref.fs" />
Expand Down
10 changes: 1 addition & 9 deletions src/Bolero/Attr.fs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,7 @@

namespace Bolero

open Microsoft.AspNetCore.Components

/// <summary>
/// HTML attribute or Blazor component parameter.
/// Use <see cref="T:Bolero.Html.attr" /> or <see cref="M:Bolero.Html.op_EqualsGreater" /> to create attributes.
/// </summary>
/// <category>HTML</category>
type Attr = delegate of obj * Rendering.RenderTreeBuilder * int -> int

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Attr =

/// <summary>Create an HTML attribute or a component parameter.</summary>
Expand Down
5 changes: 3 additions & 2 deletions src/Bolero/Bolero.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
<!-- <DefineConstants>DEBUG_RENDERER;$(DefineConstants)</DefineConstants> -->
</PropertyGroup>
<ItemGroup>
<Compile Include="Attr.fs" />
<Compile Include="Node.fs" />
<Compile Include="NodeTypes.fs" />
<Compile Include="Router.fs" />
<Compile Include="ProgramRun.fs" />
<Compile Include="Components.fs" />
<Compile Include="Attr.fs" />
<Compile Include="Node.fs" />
<Compile Include="Virtualize.fs" />
<Compile Include="Ref.fs" />
<Compile Include="TemplatingInternals.fs" />
Expand Down
2 changes: 1 addition & 1 deletion src/Bolero/Components.fs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ and [<AbstractClass>]
inherit Component<'model>()

let mutable oldModel = None
let mutable view = Node.Empty()
let mutable view = Node(fun _ _ s -> s)
let mutable runProgramLoop = fun () -> ()
let mutable dispatch = ignore<'msg>
let mutable program = Unchecked.defaultof<Program<'model, 'msg>>
Expand Down
15 changes: 10 additions & 5 deletions src/Bolero/Node.fs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ open System
open FSharp.Reflection
open Microsoft.AspNetCore.Components

/// <summary>An HTML fragment.</summary>
/// <category>HTML</category>
type Node = delegate of obj * Rendering.RenderTreeBuilder * int -> int

/// <exclude />
[<Sealed; AbstractClass>]
type Matcher<'T> private () =
Expand All @@ -51,6 +47,7 @@ type Matcher<'T> private () =
let tagReader = FSharpValue.PreComputeUnionTagReader(typeof<'T>)
fun (x: 'T) -> tagReader (box x)

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Node =

/// <summary>Create an empty HTML fragment.</summary>
Expand All @@ -65,7 +62,15 @@ module Node =
/// <seealso cref="M:Bolero.Html.elt" />
let inline Elt name (attrs: seq<Attr>) (children: seq<Node>) = Node(fun comp tb i ->
tb.OpenElement(i, name)
let mutable i = i + 1

match comp with
| :? Component as c ->
match c.CssScope with
| null -> ()
| s -> tb.AddAttribute(i + 1, s)
| _ -> ()

let mutable i = i + 2
for attr in attrs do
i <- attr.Invoke(comp, tb, i)
for node in children do
Expand Down
20 changes: 20 additions & 0 deletions src/Bolero/NodeTypes.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Bolero

open Microsoft.AspNetCore.Components.Rendering

/// <summary>
/// HTML attribute or Blazor component parameter.
/// Use <see cref="T:Bolero.Html.attr" /> or <see cref="M:Bolero.Html.op_EqualsGreater" /> to create attributes.
/// </summary>
/// <category>HTML</category>
type Attr = delegate of obj * RenderTreeBuilder * int -> int

/// <summary>An HTML fragment.</summary>
/// <category>HTML</category>
type Node = delegate of obj * RenderTreeBuilder * int -> int

#if IS_DESIGNTIME
type Component() =
inherit Microsoft.AspNetCore.Components.ComponentBase()
member _.CssScope = ""
#endif
4 changes: 3 additions & 1 deletion src/Bolero/Router.fs
Original file line number Diff line number Diff line change
Expand Up @@ -974,4 +974,6 @@ type RouterExtensions =
/// <returns>An <c>href</c> attribute pointing to the given endpoint.</returns>
[<Extension>]
static member HRef(this: Router<'ep, _, _>, endpoint: 'ep, [<Optional>] hash: string) : Attr =
Attr.Make "href" (this.Link(endpoint, hash))
Attr(fun _ tb i ->
tb.AddAttribute(i, "href", this.Link(endpoint, hash))
i + 1)
1 change: 1 addition & 0 deletions src/tpdummy/Microsoft.AspNetCore.Components/Library.fs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type RenderTreeBuilder =
member _.OpenComponent(_: int, _: Type) : unit = raise (NotImplementedException())
member _.CloseComponent() : unit = raise (NotImplementedException())
member _.AddAttribute(_: int, _: string, _: obj) : unit = raise (NotImplementedException())
member _.AddAttribute(_: int, _: string) : unit = raise (NotImplementedException())
member _.AddContent(_: int, _: string) : unit = raise (NotImplementedException())
member _.AddMarkupContent(_: int, _: string) : unit = raise (NotImplementedException())
member _.OpenRegion(_: int) : unit = raise (NotImplementedException())
Expand Down
3 changes: 2 additions & 1 deletion tests/Server/Startup.fs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ type Startup() =
member this.ConfigureServices(services: IServiceCollection) =
services.AddMvc() |> ignore
services.AddServerSideBlazor() |> ignore
services.AddBoleroHost(server = false) |> ignore
services.AddBoleroHost(prerendered = true) |> ignore
services.AddLogging() |> ignore

member this.Configure(app: IApplicationBuilder) =
app
Expand Down
14 changes: 14 additions & 0 deletions tests/Unit.Client/Templating.fs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,19 @@ type RefTester() =
Refs().Elt()
}

type TemplateForScopedCss = Template<"""
<span id="holed-must-be-scoped">${Text}</span>
<span id="non-holed-must-be-scoped"></span>
""">

type ScopedCssTester() =
inherit Component()

override _.CssScope = "dummy-scope"

override _.Render() =
TemplateForScopedCss().Text("content").Elt()

type ``Regression #11`` = Template<"""<span class="${Hole}">${Hole}</span>""">

type ``Regression #256`` = Template<"""
Expand Down Expand Up @@ -243,4 +256,5 @@ let Tests() =
comp<EventTester>
comp<BindTester>
comp<RefTester>
comp<ScopedCssTester>
}
10 changes: 10 additions & 0 deletions tests/Unit/Tests/Templating.fs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,16 @@ module Templating =
btn.Click()
elt.Eventually <@ btn.Text = "Template ref is bound" @>

[<Test>]
let ``Scoped CSS is propagated to elements that have holes``() =
let elt = elt.ById("holed-must-be-scoped")
testNotNull <@ elt.GetAttribute("dummy-scope") @>

[<Test>]
let ``Scoped CSS is propagated to elements that don't have holes``() =
let elt = elt.ById("non-holed-must-be-scoped")
testNotNull <@ elt.GetAttribute("dummy-scope") @>

[<Test>]
let ``Regression #11: common hole in attrs and children``() =
test <@ elt.ByClass("regression-11").Text = "regression-11" @>
Expand Down

0 comments on commit bad1b3a

Please sign in to comment.