Compare commits

...

2 Commits

Author SHA1 Message Date
danieljsummers cfd8d7eb68 v2,0.10 (#21)
Update script to 2.0.10, convert sln to slnx

Reviewed-on: #21
2026-07-03 23:44:51 +00:00
danieljsummers 8f93aa4d35 Add htmx 4 notes to README 2026-06-30 14:02:34 +00:00
13 changed files with 171 additions and 208 deletions
+2
View File
@@ -6,6 +6,8 @@
htmx uses attributes and HTTP headers to attain its interactivity; the libraries here contain extensions to both Giraffe and Giraffe View Engine to enable strongly-typed development of htmx applications. htmx uses attributes and HTTP headers to attain its interactivity; the libraries here contain extensions to both Giraffe and Giraffe View Engine to enable strongly-typed development of htmx applications.
> **NOTE** htmx v4 is curently in beta; this library is supporting it on the [`htmx-v4` branch](https://git.bitbadger.solutions/bit-badger/Giraffe.Htmx/src/branch/htmx-v4/). Beta versions of the v4 library include warnings about obsolete constructs. The htmx project intends to continue supporting the 2.x line (just as they still do the 1.x line, which we track on the [`htmx-v1` branch](https://git.bitbadger.solutions/bit-badger/Giraffe.Htmx/src/branch/htmx-v1/)); the upgrade is available, not forced. See the [htmx v4 migration docs](https://four.htmx.org/docs#migration) for more information.
## Installation ## Installation
`Giraffe.Htmx` provides extensions that facilitate using htmx on the server side, primarily reading and setting headers. `Giraffe.ViewEngine.Htmx` provides attributes and helpers to produce views that utilize htmx. Both can be installed from NuGet via standard methods. `Giraffe.Htmx` provides extensions that facilitate using htmx on the server side, primarily reading and setting headers. `Giraffe.ViewEngine.Htmx` provides attributes and helpers to produce views that utilize htmx. Both can be installed from NuGet via standard methods.
+8 -8
View File
@@ -3,7 +3,7 @@
module Giraffe.Htmx.Common module Giraffe.Htmx.Common
/// <summary>The version of htmx embedded in the package</summary> /// <summary>The version of htmx embedded in the package</summary>
let HtmxVersion = "2.0.8" let HtmxVersion = "2.0.10"
/// <summary>The path for the provided htmx script</summary> /// <summary>The path for the provided htmx script</summary>
let internal htmxLocalScript = $"/_content/Giraffe.Htmx.Common/htmx.min.js?ver={HtmxVersion}" let internal htmxLocalScript = $"/_content/Giraffe.Htmx.Common/htmx.min.js?ver={HtmxVersion}"
@@ -29,31 +29,31 @@ let internal toLowerBool (boolValue: bool) =
/// <seealso href="https://htmx.org/attributes/hx-swap/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-swap/">Documentation</seealso>
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module HxSwap = module HxSwap =
/// <summary>The default, replace the inner HTML of the target element</summary> /// <summary>The default, replace the inner HTML of the target element</summary>
[<Literal>] [<Literal>]
let InnerHtml = "innerHTML" let InnerHtml = "innerHTML"
/// <summary>Replace the entire target element with the response</summary> /// <summary>Replace the entire target element with the response</summary>
[<Literal>] [<Literal>]
let OuterHtml = "outerHTML" let OuterHtml = "outerHTML"
/// <summary>Insert the response before the target element</summary> /// <summary>Insert the response before the target element</summary>
[<Literal>] [<Literal>]
let BeforeBegin = "beforebegin" let BeforeBegin = "beforebegin"
/// <summary>Insert the response before the first child of the target element</summary> /// <summary>Insert the response before the first child of the target element</summary>
[<Literal>] [<Literal>]
let AfterBegin = "afterbegin" let AfterBegin = "afterbegin"
/// <summary>Insert the response after the last child of the target element</summary> /// <summary>Insert the response after the last child of the target element</summary>
[<Literal>] [<Literal>]
let BeforeEnd = "beforeend" let BeforeEnd = "beforeend"
/// <summary>Insert the response after the target element</summary> /// <summary>Insert the response after the target element</summary>
[<Literal>] [<Literal>]
let AfterEnd = "afterend" let AfterEnd = "afterend"
/// <summary>Does not append content from response (out of band items will still be processed).</summary> /// <summary>Does not append content from response (out of band items will still be processed).</summary>
[<Literal>] [<Literal>]
let None = "none" let None = "none"
+1 -1
View File
@@ -2,4 +2,4 @@
This package contains common code shared between [`Giraffe.Htmx`](https://www.nuget.org/packages/Giraffe.Htmx) and [`Giraffe.ViewEngine.Htmx`](https://www.nuget.org/packages/Giraffe.ViewEngine.Htmx), and will be automatically installed when you install either one. It also contains htmx as a static web asset, allowing it to be loaded from your local (or published) project. This package contains common code shared between [`Giraffe.Htmx`](https://www.nuget.org/packages/Giraffe.Htmx) and [`Giraffe.ViewEngine.Htmx`](https://www.nuget.org/packages/Giraffe.ViewEngine.Htmx), and will be automatically installed when you install either one. It also contains htmx as a static web asset, allowing it to be loaded from your local (or published) project.
**htmx version: 2.0.8** **htmx version: 2.0.10**
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -7
View File
@@ -2,14 +2,9 @@
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks> <TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
<VersionPrefix>2.0.8</VersionPrefix> <VersionPrefix>2.0.10</VersionPrefix>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageReleaseNotes>- Adds package-provided script (available via Giraffe.Htmx.Common); use app.MapStaticAssets() for publish support, use builder.UseStaticWebAssets() for non-development/non-published execution <PackageReleaseNotes>- Updates provided script and CDN links to serve htmx 2.0.10 (no header or attribute changes)
- [View Engine] Deprecates Script.minified and Script.unminified (use Script.cdnMinified and Script.cdnUnminified instead)
- Updates script tags to pull htmx 2.0.8 (no header or attribute changes)
- Adds .NET 10 support
See full release notes, including more info about the package-provided script, at https://git.bitbadger.solutions/bit-badger/Giraffe.Htmx/releases/tag/v2.0.8
NOTE: As of 2.0.6, the CDN for htmx changed from unpkg.com to cdn.jsdelivr.net; sites with Content-Security-Policy headers will want to update their allowed script-src domains accordingly NOTE: As of 2.0.6, the CDN for htmx changed from unpkg.com to cdn.jsdelivr.net; sites with Content-Security-Policy headers will want to update their allowed script-src domains accordingly
</PackageReleaseNotes> </PackageReleaseNotes>
-40
View File
@@ -1,40 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Giraffe.Htmx", "Htmx\Giraffe.Htmx.fsproj", "{8AB3085C-5236-485A-8565-A09106E72E1E}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Giraffe.ViewEngine.Htmx", "ViewEngine.Htmx\Giraffe.ViewEngine.Htmx.fsproj", "{F718B3C1-EE01-4F04-ABCE-BF2AE700FDA9}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Giraffe.Htmx.Common", "Common\Giraffe.Htmx.Common.fsproj", "{75D66845-F93A-4463-AD29-A8B16E4D4BA9}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Tests", "Tests\Tests.fsproj", "{39823773-4311-4E79-9CA0-F9DDC40CAF6A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8AB3085C-5236-485A-8565-A09106E72E1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8AB3085C-5236-485A-8565-A09106E72E1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8AB3085C-5236-485A-8565-A09106E72E1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8AB3085C-5236-485A-8565-A09106E72E1E}.Release|Any CPU.Build.0 = Release|Any CPU
{F718B3C1-EE01-4F04-ABCE-BF2AE700FDA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F718B3C1-EE01-4F04-ABCE-BF2AE700FDA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F718B3C1-EE01-4F04-ABCE-BF2AE700FDA9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F718B3C1-EE01-4F04-ABCE-BF2AE700FDA9}.Release|Any CPU.Build.0 = Release|Any CPU
{75D66845-F93A-4463-AD29-A8B16E4D4BA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{75D66845-F93A-4463-AD29-A8B16E4D4BA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{75D66845-F93A-4463-AD29-A8B16E4D4BA9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75D66845-F93A-4463-AD29-A8B16E4D4BA9}.Release|Any CPU.Build.0 = Release|Any CPU
{39823773-4311-4E79-9CA0-F9DDC40CAF6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{39823773-4311-4E79-9CA0-F9DDC40CAF6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{39823773-4311-4E79-9CA0-F9DDC40CAF6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{39823773-4311-4E79-9CA0-F9DDC40CAF6A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
+6
View File
@@ -0,0 +1,6 @@
<Solution>
<Project Path="Common/Giraffe.Htmx.Common.fsproj" />
<Project Path="Htmx/Giraffe.Htmx.fsproj" />
<Project Path="Tests/Tests.fsproj" />
<Project Path="ViewEngine.Htmx/Giraffe.ViewEngine.Htmx.fsproj" />
</Solution>
+1 -1
View File
@@ -2,7 +2,7 @@
This package enables server-side support for [htmx](https://htmx.org) within [Giraffe](https://giraffe.wiki) and ASP.NET's `HttpContext`. This package enables server-side support for [htmx](https://htmx.org) within [Giraffe](https://giraffe.wiki) and ASP.NET's `HttpContext`.
**htmx version: 2.0.8** **htmx version: 2.0.10**
_Upgrading from v1.x: the [migration guide](https://htmx.org/migration-guide-htmx-1/) does not currently specify any request or response header changes. This means that there are no required code changes in moving from v1.* to v2.*._ _Upgrading from v1.x: the [migration guide](https://htmx.org/migration-guide-htmx-1/) does not currently specify any request or response header changes. This means that there are no required code changes in moving from v1.* to v2.*._
+1 -1
View File
@@ -6,7 +6,7 @@ open Giraffe.Htmx
/// Test to ensure the version was updated /// Test to ensure the version was updated
let version = let version =
test "HtmxVersion is correct" { test "HtmxVersion is correct" {
Expect.equal HtmxVersion "2.0.8" "htmx version incorrect" Expect.equal HtmxVersion "2.0.10" "htmx version incorrect"
} }
/// Tests for the HxSwap module /// Tests for the HxSwap module
+4 -4
View File
@@ -167,7 +167,7 @@ let reqExtensions =
let ctx = Substitute.For<HttpContext>() let ctx = Substitute.For<HttpContext>()
ctx.Request.Headers.ReturnsForAnyArgs(HeaderDictionary()) |> ignore ctx.Request.Headers.ReturnsForAnyArgs(HeaderDictionary()) |> ignore
Expect.isFalse ctx.Request.IsHtmx "The request should not be an htmx request" Expect.isFalse ctx.Request.IsHtmx "The request should not be an htmx request"
} }
test "succeeds when request is from htmx" { test "succeeds when request is from htmx" {
let ctx = Substitute.For<HttpContext>() let ctx = Substitute.For<HttpContext>()
let dic = HeaderDictionary() let dic = HeaderDictionary()
@@ -204,7 +204,7 @@ open System.Threading.Tasks
/// Dummy "next" parameter to get the pipeline to execute/terminate /// Dummy "next" parameter to get the pipeline to execute/terminate
let next (ctx: HttpContext) = Task.FromResult(Some ctx) let next (ctx: HttpContext) = Task.FromResult(Some ctx)
/// Tests for the HttpHandler functions provided in the Handlers module /// Tests for the HttpHandler functions provided in the Handlers module
let handlers = let handlers =
testList "HandlerTests" [ testList "HandlerTests" [
@@ -281,7 +281,7 @@ let handlers =
let! _ = withHxReselect "#test" next ctx let! _ = withHxReselect "#test" next ctx
Expect.isTrue (dic.ContainsKey "HX-Reselect") "The HX-Reselect header should be present" Expect.isTrue (dic.ContainsKey "HX-Reselect") "The HX-Reselect header should be present"
Expect.equal dic["HX-Reselect"].[0] "#test" "The HX-Reselect value was incorrect" Expect.equal dic["HX-Reselect"].[0] "#test" "The HX-Reselect value was incorrect"
} }
testTask "withHxReswap succeeds" { testTask "withHxReswap succeeds" {
let ctx = Substitute.For<HttpContext>() let ctx = Substitute.For<HttpContext>()
let dic = HeaderDictionary() let dic = HeaderDictionary()
@@ -289,7 +289,7 @@ let handlers =
let! _ = withHxReswap HxSwap.BeforeEnd next ctx let! _ = withHxReswap HxSwap.BeforeEnd next ctx
Expect.isTrue (dic.ContainsKey "HX-Reswap") "The HX-Reswap header should be present" Expect.isTrue (dic.ContainsKey "HX-Reswap") "The HX-Reswap header should be present"
Expect.equal dic["HX-Reswap"].[0] HxSwap.BeforeEnd "The HX-Reswap value was incorrect" Expect.equal dic["HX-Reswap"].[0] HxSwap.BeforeEnd "The HX-Reswap value was incorrect"
} }
testTask "withHxRetarget succeeds" { testTask "withHxRetarget succeeds" {
let ctx = Substitute.For<HttpContext>() let ctx = Substitute.For<HttpContext>()
let dic = HeaderDictionary() let dic = HeaderDictionary()
+7 -7
View File
@@ -610,7 +610,7 @@ let hxTrigger =
testList "FromDocument" [ testList "FromDocument" [
test "succeeds when it is the first modifier" { test "succeeds when it is the first modifier" {
Expect.equal (HxTrigger.FromDocument "") "from:document" "FromDocument modifier incorrect" Expect.equal (HxTrigger.FromDocument "") "from:document" "FromDocument modifier incorrect"
} }
test "succeeds when it is not the first modifier" { test "succeeds when it is not the first modifier" {
Expect.equal (HxTrigger.FromDocument "click") "click from:document" "FromDocument modifier incorrect" Expect.equal (HxTrigger.FromDocument "click") "click from:document" "FromDocument modifier incorrect"
} }
@@ -715,7 +715,7 @@ let hxVals =
] ]
] ]
/// Pipe-able assertion for a rendered node /// Pipe-able assertion for a rendered node
let shouldRender expected node = let shouldRender expected node =
Expect.equal (RenderView.AsString.htmlNode node) expected "Rendered HTML incorrect" Expect.equal (RenderView.AsString.htmlNode node) expected "Rendered HTML incorrect"
@@ -858,14 +858,14 @@ let script =
let html = RenderView.AsString.htmlNode Script.cdnMinified let html = RenderView.AsString.htmlNode Script.cdnMinified
Expect.equal Expect.equal
html html
$"""<script src="https://cdn.jsdelivr.net/npm/htmx.org@{HtmxVersion}/dist/htmx.min.js" integrity="sha256-Iig+9oy3VFkU8KiKG97cclanA9HVgMHSVSF9ClDTExM=" crossorigin="anonymous"></script>""" $"""<script src="https://cdn.jsdelivr.net/npm/htmx.org@{HtmxVersion}/dist/htmx.min.js" integrity="sha384-H5SrcfygHmAuTDZphMHqBJLc3FhssKjG7w/CeCpFReSfwBWDTKpkzPP8c+cLsK+V" crossorigin="anonymous"></script>"""
"CDN minified script tag is incorrect" "CDN minified script tag is incorrect"
} }
test "cdnUnminified succeeds" { test "cdnUnminified succeeds" {
let html = RenderView.AsString.htmlNode Script.cdnUnminified let html = RenderView.AsString.htmlNode Script.cdnUnminified
Expect.equal Expect.equal
html html
$"""<script src="https://cdn.jsdelivr.net/npm/htmx.org@{HtmxVersion}/dist/htmx.js" integrity="sha256-upUwYnay6R+DA68rROTAP+EdfO3NvOqtE513PgDyAYM=" crossorigin="anonymous"></script>""" $"""<script src="https://cdn.jsdelivr.net/npm/htmx.org@{HtmxVersion}/dist/htmx.js" integrity="sha384-Q+Dky3iHVJOr6wUjQ4ulh6uQ76an/t+ak1+PjMVaxRjbZamFLAG+u9InkfjbsEQf" crossorigin="anonymous"></script>"""
"CDN unminified script tag is incorrect" "CDN unminified script tag is incorrect"
} }
] ]
@@ -875,11 +875,11 @@ open System.Text
/// Tests for the RenderFragment module /// Tests for the RenderFragment module
let renderFragment = let renderFragment =
testList "RenderFragment" [ testList "RenderFragment" [
/// Validate that the two object references are the same object /// Validate that the two object references are the same object
let isSame obj1 obj2 message = let isSame obj1 obj2 message =
Expect.isTrue (obj.ReferenceEquals(obj1, obj2)) message Expect.isTrue (obj.ReferenceEquals(obj1, obj2)) message
testList "findIdNode" [ testList "findIdNode" [
test "fails with a Text node" { test "fails with a Text node" {
Expect.isNone (RenderFragment.findIdNode "blue" (Text "")) "There should not have been a node found" Expect.isNone (RenderFragment.findIdNode "blue" (Text "")) "There should not have been a node found"
@@ -945,7 +945,7 @@ let renderFragment =
] ]
] ]
testList "AsBytes" [ testList "AsBytes" [
/// Alias for UTF-8 encoding /// Alias for UTF-8 encoding
let utf8 = Encoding.UTF8 let utf8 = Encoding.UTF8
+137 -137
View File
@@ -4,11 +4,11 @@ module Giraffe.ViewEngine.Htmx
/// <summary>Valid values for the <c>hx-encoding</c> attribute</summary> /// <summary>Valid values for the <c>hx-encoding</c> attribute</summary>
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module HxEncoding = module HxEncoding =
/// <summary>A standard HTTP form</summary> /// <summary>A standard HTTP form</summary>
[<Literal>] [<Literal>]
let Form = "application/x-www-form-urlencoded" let Form = "application/x-www-form-urlencoded"
/// <summary>A multipart form (used for file uploads)</summary> /// <summary>A multipart form (used for file uploads)</summary>
[<Literal>] [<Literal>]
let MultipartForm = "multipart/form-data" let MultipartForm = "multipart/form-data"
@@ -17,137 +17,137 @@ module HxEncoding =
/// <summary>The events recognized by htmx</summary> /// <summary>The events recognized by htmx</summary>
[<Struct>] [<Struct>]
type HxEvent = type HxEvent =
/// <summary>Send this event to an element to abort a request</summary> /// <summary>Send this event to an element to abort a request</summary>
| Abort | Abort
/// <summary>Triggered after an AJAX request has completed processing a successful response</summary> /// <summary>Triggered after an AJAX request has completed processing a successful response</summary>
| AfterOnLoad | AfterOnLoad
/// <summary>Triggered after htmx has initialized a node</summary> /// <summary>Triggered after htmx has initialized a node</summary>
| AfterProcessNode | AfterProcessNode
/// <summary>Triggered after an AJAX request has completed</summary> /// <summary>Triggered after an AJAX request has completed</summary>
| AfterRequest | AfterRequest
/// <summary>Triggered after the DOM has settled</summary> /// <summary>Triggered after the DOM has settled</summary>
| AfterSettle | AfterSettle
/// <summary>Triggered after new content has been swapped in</summary> /// <summary>Triggered after new content has been swapped in</summary>
| AfterSwap | AfterSwap
/// <summary>Triggered before htmx disables an element or removes it from the DOM</summary> /// <summary>Triggered before htmx disables an element or removes it from the DOM</summary>
| BeforeCleanupElement | BeforeCleanupElement
/// <summary>Triggered before any response processing occurs</summary> /// <summary>Triggered before any response processing occurs</summary>
| BeforeOnLoad | BeforeOnLoad
/// <summary>Triggered before htmx initializes a node</summary> /// <summary>Triggered before htmx initializes a node</summary>
| BeforeProcessNode | BeforeProcessNode
/// <summary>Triggered before an AJAX request is made</summary> /// <summary>Triggered before an AJAX request is made</summary>
| BeforeRequest | BeforeRequest
/// <summary>Triggered before a swap is done, allows you to configure the swap</summary> /// <summary>Triggered before a swap is done, allows you to configure the swap</summary>
| BeforeSwap | BeforeSwap
/// <summary>Triggered just before an ajax request is sent</summary> /// <summary>Triggered just before an ajax request is sent</summary>
| BeforeSend | BeforeSend
/// <summary>Triggered before the request, allows you to customize parameters, headers</summary> /// <summary>Triggered before the request, allows you to customize parameters, headers</summary>
| ConfigRequest | ConfigRequest
/// <summary> /// <summary>
/// Triggered after a trigger occurs on an element, allows you to cancel (or delay) issuing the AJAX request /// Triggered after a trigger occurs on an element, allows you to cancel (or delay) issuing the AJAX request
/// </summary> /// </summary>
| Confirm | Confirm
/// <summary>Triggered on an error during cache writing</summary> /// <summary>Triggered on an error during cache writing</summary>
| HistoryCacheError | HistoryCacheError
/// <summary>Triggered on a cache miss in the history subsystem</summary> /// <summary>Triggered on a cache miss in the history subsystem</summary>
| HistoryCacheMiss | HistoryCacheMiss
/// <summary>Triggered on a unsuccessful remote retrieval</summary> /// <summary>Triggered on a unsuccessful remote retrieval</summary>
| HistoryCacheMissError | HistoryCacheMissError
/// <summary>Triggered on a successful remote retrieval</summary> /// <summary>Triggered on a successful remote retrieval</summary>
| HistoryCacheMissLoad | HistoryCacheMissLoad
/// <summary>Triggered when htmx handles a history restoration action</summary> /// <summary>Triggered when htmx handles a history restoration action</summary>
| HistoryRestore | HistoryRestore
/// <summary>Triggered before content is saved to the history cache</summary> /// <summary>Triggered before content is saved to the history cache</summary>
| BeforeHistorySave | BeforeHistorySave
/// <summary>Triggered when new content is added to the DOM</summary> /// <summary>Triggered when new content is added to the DOM</summary>
| Load | Load
/// <summary> /// <summary>
/// Triggered when an element refers to a SSE event in its trigger, but no parent SSE source has been defined /// Triggered when an element refers to a SSE event in its trigger, but no parent SSE source has been defined
/// </summary> /// </summary>
| NoSseSourceError | NoSseSourceError
/// <summary>Triggered when an exception occurs during the onLoad handling in htmx</summary> /// <summary>Triggered when an exception occurs during the onLoad handling in htmx</summary>
| OnLoadError | OnLoadError
/// <summary>Triggered after an out of band element as been swapped in</summary> /// <summary>Triggered after an out of band element as been swapped in</summary>
| OobAfterSwap | OobAfterSwap
/// <summary>Triggered before an out of band element swap is done, allows you to configure the swap</summary> /// <summary>Triggered before an out of band element swap is done, allows you to configure the swap</summary>
| OobBeforeSwap | OobBeforeSwap
/// <summary>Triggered when an out of band element does not have a matching ID in the current DOM</summary> /// <summary>Triggered when an out of band element does not have a matching ID in the current DOM</summary>
| OobErrorNoTarget | OobErrorNoTarget
/// <summary>Triggered after a prompt is shown</summary> /// <summary>Triggered after a prompt is shown</summary>
| Prompt | Prompt
/// <summary>Triggered after an url is pushed into history</summary> /// <summary>Triggered after an url is pushed into history</summary>
| PushedIntoHistory | PushedIntoHistory
/// <summary>Triggered when an HTTP response error (non-200 or 300 response code) occurs</summary> /// <summary>Triggered when an HTTP response error (non-200 or 300 response code) occurs</summary>
| ResponseError | ResponseError
/// <summary>Triggered when a network error prevents an HTTP request from happening</summary> /// <summary>Triggered when a network error prevents an HTTP request from happening</summary>
| SendError | SendError
/// <summary>Triggered when an error occurs with a SSE source</summary> /// <summary>Triggered when an error occurs with a SSE source</summary>
| SseError | SseError
/// <summary>Triggered when a SSE source is opened</summary> /// <summary>Triggered when a SSE source is opened</summary>
| SseOpen | SseOpen
/// <summary>Triggered when an error occurs during the swap phase</summary> /// <summary>Triggered when an error occurs during the swap phase</summary>
| SwapError | SwapError
/// <summary>Triggered when an invalid target is specified</summary> /// <summary>Triggered when an invalid target is specified</summary>
| TargetError | TargetError
/// <summary>Triggered when a request timeout occurs</summary> /// <summary>Triggered when a request timeout occurs</summary>
| Timeout | Timeout
/// <summary>Triggered before an element is validated</summary> /// <summary>Triggered before an element is validated</summary>
| ValidationValidate | ValidationValidate
/// <summary>Triggered when an element fails validation</summary> /// <summary>Triggered when an element fails validation</summary>
| ValidationFailed | ValidationFailed
/// <summary>Triggered when a request is halted due to validation errors</summary> /// <summary>Triggered when a request is halted due to validation errors</summary>
| ValidationHalted | ValidationHalted
/// <summary>Triggered when an ajax request aborts</summary> /// <summary>Triggered when an ajax request aborts</summary>
| XhrAbort | XhrAbort
/// <summary>Triggered when an ajax request ends</summary> /// <summary>Triggered when an ajax request ends</summary>
| XhrLoadEnd | XhrLoadEnd
/// <summary>Triggered when an ajax request starts</summary> /// <summary>Triggered when an ajax request starts</summary>
| XhrLoadStart | XhrLoadStart
/// <summary>Triggered periodically during an ajax request that supports progress events</summary> /// <summary>Triggered periodically during an ajax request that supports progress events</summary>
| XhrProgress | XhrProgress
/// The htmx event name (fst) and kebab-case name (snd, for use with hx-on) /// The htmx event name (fst) and kebab-case name (snd, for use with hx-on)
static member private Values = Map [ static member private Values = Map [
Abort, ("abort", "abort") Abort, ("abort", "abort")
@@ -193,10 +193,10 @@ type HxEvent =
XhrLoadStart, ("xhr:loadstart", "xhr:loadstart") XhrLoadStart, ("xhr:loadstart", "xhr:loadstart")
XhrProgress, ("xhr:progress", "xhr:progress") XhrProgress, ("xhr:progress", "xhr:progress")
] ]
/// <summary>The htmx event name</summary> /// <summary>The htmx event name</summary>
override this.ToString() = fst HxEvent.Values[this] override this.ToString() = fst HxEvent.Values[this]
/// <summary>The <c>hx-on</c> variant of the htmx event name</summary> /// <summary>The <c>hx-on</c> variant of the htmx event name</summary>
member this.ToHxOnString() = snd HxEvent.Values[this] member this.ToHxOnString() = snd HxEvent.Values[this]
@@ -204,7 +204,7 @@ type HxEvent =
/// <summary>Helper to create the <c>hx-headers</c> attribute</summary> /// <summary>Helper to create the <c>hx-headers</c> attribute</summary>
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module HxHeaders = module HxHeaders =
/// <summary>Create headers from a list of key/value pairs</summary> /// <summary>Create headers from a list of key/value pairs</summary>
let From = Giraffe.Htmx.Common.toJson let From = Giraffe.Htmx.Common.toJson
@@ -213,21 +213,21 @@ module HxHeaders =
/// <seealso href="https://htmx.org/attributes/hx-params/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-params/">Documentation</seealso>
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module HxParams = module HxParams =
/// <summary>Include all parameters</summary> /// <summary>Include all parameters</summary>
[<Literal>] [<Literal>]
let All = "*" let All = "*"
/// <summary>Include no parameters</summary> /// <summary>Include no parameters</summary>
[<Literal>] [<Literal>]
let None = "none" let None = "none"
/// <summary>Include the specified parameters</summary> /// <summary>Include the specified parameters</summary>
/// <param name="fields">One or more fields to include in the request</param> /// <param name="fields">One or more fields to include in the request</param>
/// <returns>The list of fields for the <c>hx-params</c> attribute value</returns> /// <returns>The list of fields for the <c>hx-params</c> attribute value</returns>
let With fields = let With fields =
match fields with [] -> "" | _ -> fields |> List.reduce (fun acc it -> $"{acc},{it}") match fields with [] -> "" | _ -> fields |> List.reduce (fun acc it -> $"{acc},{it}")
/// <summary>Exclude the specified parameters</summary> /// <summary>Exclude the specified parameters</summary>
/// <param name="fields">One or more fields to exclude from the request</param> /// <param name="fields">One or more fields to exclude from the request</param>
/// <returns>The list of fields for the <c>hx-params</c> attribute value prefixed with "not"</returns> /// <returns>The list of fields for the <c>hx-params</c> attribute value prefixed with "not"</returns>
@@ -239,9 +239,9 @@ module HxParams =
/// <seealso href="https://htmx.org/attributes/hx-request/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-request/">Documentation</seealso>
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module HxRequest = module HxRequest =
open Giraffe.Htmx.Common open Giraffe.Htmx.Common
/// <summary>Configure the request with various options</summary> /// <summary>Configure the request with various options</summary>
/// <param name="opts">The options to configure</param> /// <param name="opts">The options to configure</param>
/// <returns>A string with the configured options</returns> /// <returns>A string with the configured options</returns>
@@ -249,19 +249,19 @@ module HxRequest =
opts opts
|> String.concat ", " |> String.concat ", "
|> sprintf "{ %s }" |> sprintf "{ %s }"
/// <summary>Set a timeout (in milliseconds)</summary> /// <summary>Set a timeout (in milliseconds)</summary>
/// <param name="ms">The milliseconds for the request timeout</param> /// <param name="ms">The milliseconds for the request timeout</param>
/// <returns>A string with the configured request timeout</returns> /// <returns>A string with the configured request timeout</returns>
let Timeout (ms: int) = let Timeout (ms: int) =
$"\"timeout\": {ms}" $"\"timeout\": {ms}"
/// <summary>Include or exclude credentials from the request</summary> /// <summary>Include or exclude credentials from the request</summary>
/// <param name="send"><c>true</c> if credentials should be sent, <c>false</c> if not</param> /// <param name="send"><c>true</c> if credentials should be sent, <c>false</c> if not</param>
/// <returns>A string with the configured credential options</returns> /// <returns>A string with the configured credential options</returns>
let Credentials send = let Credentials send =
(toLowerBool >> sprintf "\"credentials\": %s") send (toLowerBool >> sprintf "\"credentials\": %s") send
/// <summary>Exclude or include headers from the request</summary> /// <summary>Exclude or include headers from the request</summary>
/// <param name="exclude"> /// <param name="exclude">
/// <c>true</c> if no headers should be sent; <c>false</c> if headers should be sent /// <c>true</c> if no headers should be sent; <c>false</c> if headers should be sent
@@ -275,35 +275,35 @@ module HxRequest =
/// <seealso href="https://htmx.org/attributes/hx-sync/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-sync/">Documentation</seealso>
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module HxSync = module HxSync =
/// <summary>Drop (ignore) this request if a request is already in flight</summary> /// <summary>Drop (ignore) this request if a request is already in flight</summary>
/// <remarks>This is the default for <c>hx-sync</c></remarks> /// <remarks>This is the default for <c>hx-sync</c></remarks>
[<Literal>] [<Literal>]
let Drop = "drop" let Drop = "drop"
/// <summary> /// <summary>
/// Drop (ignore) this request if a request is already in flight, and if another request occurs while this one is in /// Drop (ignore) this request if a request is already in flight, and if another request occurs while this one is in
/// flight, abort this request /// flight, abort this request
/// </summary> /// </summary>
[<Literal>] [<Literal>]
let Abort = "abort" let Abort = "abort"
/// <summary>Abort any current in-flight request and replace it with this one</summary> /// <summary>Abort any current in-flight request and replace it with this one</summary>
[<Literal>] [<Literal>]
let Replace = "replace" let Replace = "replace"
/// <summary>Place this request in an element-associated queue</summary> /// <summary>Place this request in an element-associated queue</summary>
[<Literal>] [<Literal>]
let Queue = "queue" let Queue = "queue"
/// <summary>Queue only the first request received while another request is in flight</summary> /// <summary>Queue only the first request received while another request is in flight</summary>
[<Literal>] [<Literal>]
let QueueFirst = "queue first" let QueueFirst = "queue first"
/// <summary>Queue only the last request received while another request is in flight</summary> /// <summary>Queue only the last request received while another request is in flight</summary>
[<Literal>] [<Literal>]
let QueueLast = "queue last" let QueueLast = "queue last"
/// <summary>Queue all requests received while another request is in flight</summary> /// <summary>Queue all requests received while another request is in flight</summary>
[<Literal>] [<Literal>]
let QueueAll = "queue all" let QueueAll = "queue all"
@@ -313,7 +313,7 @@ module HxSync =
/// <seealso href="https://htmx.org/attributes/hx-trigger/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-trigger/">Documentation</seealso>
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module HxTrigger = module HxTrigger =
/// Append a filter to a trigger /// Append a filter to a trigger
let private appendFilter filter (trigger : string) = let private appendFilter filter (trigger : string) =
match trigger.Contains "[" with match trigger.Contains "[" with
@@ -321,125 +321,125 @@ module HxTrigger =
let parts = trigger.Split ('[', ']') let parts = trigger.Split ('[', ']')
$"{parts[0]}[{parts[1]}&&{filter}]" $"{parts[0]}[{parts[1]}&&{filter}]"
| false -> $"{trigger}[{filter}]" | false -> $"{trigger}[{filter}]"
/// <summary>Trigger the event on a click</summary> /// <summary>Trigger the event on a click</summary>
[<Literal>] [<Literal>]
let Click = "click" let Click = "click"
/// <summary>Trigger the event on page load</summary> /// <summary>Trigger the event on page load</summary>
[<Literal>] [<Literal>]
let Load = "load" let Load = "load"
/// <summary>Trigger the event when the item is visible</summary> /// <summary>Trigger the event when the item is visible</summary>
[<Literal>] [<Literal>]
let Revealed = "revealed" let Revealed = "revealed"
/// <summary>Trigger this event every [timing declaration]</summary> /// <summary>Trigger this event every [timing declaration]</summary>
/// <param name="duration">The duration on which this trigger should fire (e.g., "1s", "500ms")</param> /// <param name="duration">The duration on which this trigger should fire (e.g., "1s", "500ms")</param>
/// <returns>A trigger timing specification</returns> /// <returns>A trigger timing specification</returns>
let Every duration = let Every duration =
$"every %s{duration}" $"every %s{duration}"
/// <summary>Helpers for defining filters</summary> /// <summary>Helpers for defining filters</summary>
module Filter = module Filter =
/// <summary>Only trigger the event if the <c>ALT</c> key is pressed</summary> /// <summary>Only trigger the event if the <c>ALT</c> key is pressed</summary>
let Alt = appendFilter "altKey" let Alt = appendFilter "altKey"
/// <summary>Only trigger the event if the <c>CTRL</c> key is pressed</summary> /// <summary>Only trigger the event if the <c>CTRL</c> key is pressed</summary>
let Ctrl = appendFilter "ctrlKey" let Ctrl = appendFilter "ctrlKey"
/// <summary>Only trigger the event if the <c>SHIFT</c> key is pressed</summary> /// <summary>Only trigger the event if the <c>SHIFT</c> key is pressed</summary>
let Shift = appendFilter "shiftKey" let Shift = appendFilter "shiftKey"
/// <summary>Only trigger the event if <c>CTRL</c> and <c>ALT</c> are pressed</summary> /// <summary>Only trigger the event if <c>CTRL</c> and <c>ALT</c> are pressed</summary>
let CtrlAlt = Ctrl >> Alt let CtrlAlt = Ctrl >> Alt
/// <summary>Only trigger the event if <c>CTRL</c> and <c>SHIFT</c> are pressed</summary> /// <summary>Only trigger the event if <c>CTRL</c> and <c>SHIFT</c> are pressed</summary>
let CtrlShift = Ctrl >> Shift let CtrlShift = Ctrl >> Shift
/// <summary>Only trigger the event if <c>CTRL</c>, <c>ALT</c>, and <c>SHIFT</c> are pressed</summary> /// <summary>Only trigger the event if <c>CTRL</c>, <c>ALT</c>, and <c>SHIFT</c> are pressed</summary>
let CtrlAltShift = CtrlAlt >> Shift let CtrlAltShift = CtrlAlt >> Shift
/// <summary>Only trigger the event if <c>ALT</c> and <c>SHIFT</c> are pressed</summary> /// <summary>Only trigger the event if <c>ALT</c> and <c>SHIFT</c> are pressed</summary>
let AltShift = Alt >> Shift let AltShift = Alt >> Shift
/// Append a modifier to the current trigger /// Append a modifier to the current trigger
let private appendModifier modifier current = let private appendModifier modifier current =
if current = "" then modifier else $"{current} {modifier}" if current = "" then modifier else $"{current} {modifier}"
/// <summary>Only trigger once</summary> /// <summary>Only trigger once</summary>
/// <param name="action">The action which should only be fired once</param> /// <param name="action">The action which should only be fired once</param>
/// <returns>A trigger spec to fire the given action once</returns> /// <returns>A trigger spec to fire the given action once</returns>
let Once action = let Once action =
appendModifier "once" action appendModifier "once" action
/// <summary>Trigger when changed</summary> /// <summary>Trigger when changed</summary>
/// <param name="elt">The element from which the <c>onchange</c> event will be emitted</param> /// <param name="elt">The element from which the <c>onchange</c> event will be emitted</param>
/// <returns>A trigger spec to fire when the given element changes</returns> /// <returns>A trigger spec to fire when the given element changes</returns>
let Changed elt = let Changed elt =
appendModifier "changed" elt appendModifier "changed" elt
/// <summary>Delay execution; resets every time the event is seen</summary> /// <summary>Delay execution; resets every time the event is seen</summary>
/// <param name="duration">The duration for the delay (e.g., "1s", "500ms")</param> /// <param name="duration">The duration for the delay (e.g., "1s", "500ms")</param>
/// <param name="action">The action which should be fired after the given delay</param> /// <param name="action">The action which should be fired after the given delay</param>
/// <returns>A trigger spec to fire the given action after the specified delay</returns> /// <returns>A trigger spec to fire the given action after the specified delay</returns>
let Delay duration action = let Delay duration action =
appendModifier $"delay:%s{duration}" action appendModifier $"delay:%s{duration}" action
/// <summary>Throttle execution; ignore other events, fire when duration passes</summary> /// <summary>Throttle execution; ignore other events, fire when duration passes</summary>
/// <param name="duration">The duration for the throttling (e.g., "1s", "500ms")</param> /// <param name="duration">The duration for the throttling (e.g., "1s", "500ms")</param>
/// <param name="action">The action which should be fired after the given duration</param> /// <param name="action">The action which should be fired after the given duration</param>
/// <returns>A trigger spec to fire the given action after the specified duration</returns> /// <returns>A trigger spec to fire the given action after the specified duration</returns>
let Throttle duration action = let Throttle duration action =
appendModifier $"throttle:%s{duration}" action appendModifier $"throttle:%s{duration}" action
/// <summary>Trigger this event from a CSS selector</summary> /// <summary>Trigger this event from a CSS selector</summary>
/// <param name="selector">A CSS selector to identify elements which may fire this trigger</param> /// <param name="selector">A CSS selector to identify elements which may fire this trigger</param>
/// <param name="action">The action to be fired</param> /// <param name="action">The action to be fired</param>
/// <returns>A trigger spec to fire from the given element(s)</returns> /// <returns>A trigger spec to fire from the given element(s)</returns>
let From selector action = let From selector action =
appendModifier $"from:%s{selector}" action appendModifier $"from:%s{selector}" action
/// <summary>Trigger this event from the <c>document</c> object</summary> /// <summary>Trigger this event from the <c>document</c> object</summary>
/// <param name="action">The action to be fired</param> /// <param name="action">The action to be fired</param>
/// <returns>A trigger spec to fire from the <c>document</c> element</returns> /// <returns>A trigger spec to fire from the <c>document</c> element</returns>
let FromDocument action = let FromDocument action =
From "document" action From "document" action
/// <summary>Trigger this event from the <c>window</c> object</summary> /// <summary>Trigger this event from the <c>window</c> object</summary>
/// <param name="action">The action to be fired</param> /// <param name="action">The action to be fired</param>
/// <returns>A trigger spec to fire from the <c>window</c> object</returns> /// <returns>A trigger spec to fire from the <c>window</c> object</returns>
let FromWindow action = let FromWindow action =
From "window" action From "window" action
/// <summary>Trigger this event from the closest parent CSS selector</summary> /// <summary>Trigger this event from the closest parent CSS selector</summary>
/// <param name="selector">The CSS selector from which the action should be fired</param> /// <param name="selector">The CSS selector from which the action should be fired</param>
/// <param name="action">The action to be fired</param> /// <param name="action">The action to be fired</param>
/// <returns>A trigger spec to fire from the closest element</returns> /// <returns>A trigger spec to fire from the closest element</returns>
let FromClosest selector action = let FromClosest selector action =
From $"closest %s{selector}" action From $"closest %s{selector}" action
/// <summary>Trigger this event from the closest child CSS selector</summary> /// <summary>Trigger this event from the closest child CSS selector</summary>
/// <param name="selector">The child CSS selector from which the action should be fired</param> /// <param name="selector">The child CSS selector from which the action should be fired</param>
/// <param name="action">The action to be fired</param> /// <param name="action">The action to be fired</param>
/// <returns>A trigger spec to fire from the closest child element</returns> /// <returns>A trigger spec to fire from the closest child element</returns>
let FromFind selector action = let FromFind selector action =
From $"find %s{selector}" action From $"find %s{selector}" action
/// <summary>Target the given CSS selector with the results of this event</summary> /// <summary>Target the given CSS selector with the results of this event</summary>
/// <param name="selector">The CSS selector to which the result of the action will be applied</param> /// <param name="selector">The CSS selector to which the result of the action will be applied</param>
/// <param name="action">The action to be fired</param> /// <param name="action">The action to be fired</param>
/// <returns>A trigger spec to target the given selector</returns> /// <returns>A trigger spec to target the given selector</returns>
let Target selector action = let Target selector action =
appendModifier $"target:%s{selector}" action appendModifier $"target:%s{selector}" action
/// <summary>Prevent any further events from occurring after this one fires</summary> /// <summary>Prevent any further events from occurring after this one fires</summary>
/// <param name="action">The action to be fired</param> /// <param name="action">The action to be fired</param>
/// <returns>A trigger spec to fire the given action and prevent further events</returns> /// <returns>A trigger spec to fire the given action and prevent further events</returns>
let Consume action = let Consume action =
appendModifier "consume" action appendModifier "consume" action
/// <summary> /// <summary>
/// Configure queueing when events fire when others are in flight; if unspecified, the default is <c>last</c> /// Configure queueing when events fire when others are in flight; if unspecified, the default is <c>last</c>
/// </summary> /// </summary>
@@ -452,25 +452,25 @@ module HxTrigger =
let Queue how action = let Queue how action =
let qSpec = if how = "" then "" else $":{how}" let qSpec = if how = "" then "" else $":{how}"
appendModifier $"queue{qSpec}" action appendModifier $"queue{qSpec}" action
/// <summary>Queue the first event, discard all others (i.e., a FIFO queue of 1)</summary> /// <summary>Queue the first event, discard all others (i.e., a FIFO queue of 1)</summary>
/// <param name="action">The action to be fired</param> /// <param name="action">The action to be fired</param>
/// <returns>A trigger spec to queue the given action</returns> /// <returns>A trigger spec to queue the given action</returns>
let QueueFirst action = let QueueFirst action =
Queue "first" action Queue "first" action
/// <summary>Queue the last event; discards current when another is received (i.e., a LIFO queue of 1)</summary> /// <summary>Queue the last event; discards current when another is received (i.e., a LIFO queue of 1)</summary>
/// <param name="action">The action to be fired</param> /// <param name="action">The action to be fired</param>
/// <returns>A trigger spec to queue the given action</returns> /// <returns>A trigger spec to queue the given action</returns>
let QueueLast action = let QueueLast action =
Queue "last" action Queue "last" action
/// <summary>Queue all events; discard none</summary> /// <summary>Queue all events; discard none</summary>
/// <param name="action">The action to be fired</param> /// <param name="action">The action to be fired</param>
/// <returns>A trigger spec to queue the given action</returns> /// <returns>A trigger spec to queue the given action</returns>
let QueueAll action = let QueueAll action =
Queue "all" action Queue "all" action
/// <summary>Queue no events; discard all</summary> /// <summary>Queue no events; discard all</summary>
/// <param name="action">The action to be fired</param> /// <param name="action">The action to be fired</param>
/// <returns>A trigger spec to queue the given action</returns> /// <returns>A trigger spec to queue the given action</returns>
@@ -482,7 +482,7 @@ module HxTrigger =
/// <seealso href="https://htmx.org/attributes/hx-vals/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-vals/">Documentation</seealso>
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module HxVals = module HxVals =
/// <summary>Create values from a list of key/value pairs</summary> /// <summary>Create values from a list of key/value pairs</summary>
let From = Giraffe.Htmx.Common.toJson let From = Giraffe.Htmx.Common.toJson
@@ -492,30 +492,30 @@ open Giraffe.Htmx
/// <summary>Attributes and flags for htmx</summary> /// <summary>Attributes and flags for htmx</summary>
[<AutoOpen>] [<AutoOpen>]
module HtmxAttrs = module HtmxAttrs =
/// <summary>Progressively enhances anchors and forms to use AJAX requests</summary> /// <summary>Progressively enhances anchors and forms to use AJAX requests</summary>
/// <remarks>Use <c>_hxNoBoost</c> to set to false</remarks> /// <remarks>Use <c>_hxNoBoost</c> to set to false</remarks>
/// <seealso href="https://htmx.org/attributes/hx-boost/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-boost/">Documentation</seealso>
let _hxBoost = attr "hx-boost" "true" let _hxBoost = attr "hx-boost" "true"
/// <summary>Shows a <c>confirm()</c> dialog before issuing a request</summary> /// <summary>Shows a <c>confirm()</c> dialog before issuing a request</summary>
/// <param name="prompt">The prompt to present to the user when seeking their confirmation</param> /// <param name="prompt">The prompt to present to the user when seeking their confirmation</param>
/// <returns>A configured <c>hx-confirm</c> attribute</returns> /// <returns>A configured <c>hx-confirm</c> attribute</returns>
/// <seealso href="https://htmx.org/attributes/hx-confirm/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-confirm/">Documentation</seealso>
let _hxConfirm prompt = let _hxConfirm prompt =
attr "hx-confirm" prompt attr "hx-confirm" prompt
/// <summary>Issues a <c>DELETE</c> to the specified URL</summary> /// <summary>Issues a <c>DELETE</c> to the specified URL</summary>
/// <param name="url">The URL to which the <c>DELETE</c> request should be sent</param> /// <param name="url">The URL to which the <c>DELETE</c> request should be sent</param>
/// <returns>A configured <c>hx-delete</c> attribute</returns> /// <returns>A configured <c>hx-delete</c> attribute</returns>
/// <seealso href="https://htmx.org/attributes/hx-delete/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-delete/">Documentation</seealso>
let _hxDelete url = let _hxDelete url =
attr "hx-delete" url attr "hx-delete" url
/// <summary>Disables htmx processing for the given node and any children nodes</summary> /// <summary>Disables htmx processing for the given node and any children nodes</summary>
/// <seealso href="https://htmx.org/attributes/hx-disable/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-disable/">Documentation</seealso>
let _hxDisable = flag "hx-disable" let _hxDisable = flag "hx-disable"
/// <summary>Specifies elements that should be disabled when an htmx request is in flight</summary> /// <summary>Specifies elements that should be disabled when an htmx request is in flight</summary>
/// <param name="elt">The element to disable when an htmx request is in flight</param> /// <param name="elt">The element to disable when an htmx request is in flight</param>
/// <returns>A configured <c>hx-disabled-elt</c> attribute</returns> /// <returns>A configured <c>hx-disabled-elt</c> attribute</returns>
@@ -529,7 +529,7 @@ module HtmxAttrs =
/// <seealso href="https://htmx.org/attributes/hx-disinherit/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-disinherit/">Documentation</seealso>
let _hxDisinherit hxAttrs = let _hxDisinherit hxAttrs =
attr "hx-disinherit" hxAttrs attr "hx-disinherit" hxAttrs
/// <summary>Changes the request encoding type</summary> /// <summary>Changes the request encoding type</summary>
/// <param name="enc">The encoding type (use <c>HxEncoding</c> constants)</param> /// <param name="enc">The encoding type (use <c>HxEncoding</c> constants)</param>
/// <returns>A configured <c>hx-encoding</c> attribute</returns> /// <returns>A configured <c>hx-encoding</c> attribute</returns>
@@ -537,28 +537,28 @@ module HtmxAttrs =
/// <seealso href="https://htmx.org/attributes/hx-encoding/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-encoding/">Documentation</seealso>
let _hxEncoding enc = let _hxEncoding enc =
attr "hx-encoding" enc attr "hx-encoding" enc
/// <summary>Extensions to use for this element</summary> /// <summary>Extensions to use for this element</summary>
/// <param name="exts">A list of extensions to apply to this element</param> /// <param name="exts">A list of extensions to apply to this element</param>
/// <returns>A configured <c>hx-ext</c> attribute</returns> /// <returns>A configured <c>hx-ext</c> attribute</returns>
/// <seealso href="https://htmx.org/attributes/hx-ext/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-ext/">Documentation</seealso>
let _hxExt exts = let _hxExt exts =
attr "hx-ext" exts attr "hx-ext" exts
/// <summary>Issues a <c>GET</c> to the specified URL</summary> /// <summary>Issues a <c>GET</c> to the specified URL</summary>
/// <param name="url">The URL to which the <c>GET</c> request should be sent</param> /// <param name="url">The URL to which the <c>GET</c> request should be sent</param>
/// <returns>A configured <c>hx-get</c> attribute</returns> /// <returns>A configured <c>hx-get</c> attribute</returns>
/// <seealso href="https://htmx.org/attributes/hx-get/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-get/">Documentation</seealso>
let _hxGet url = let _hxGet url =
attr "hx-get" url attr "hx-get" url
/// <summary>Adds to the headers that will be submitted with the request</summary> /// <summary>Adds to the headers that will be submitted with the request</summary>
/// <param name="hdrs">The headers to include with the request</param> /// <param name="hdrs">The headers to include with the request</param>
/// <returns>A configured <c>hx-headers</c> attribute</returns> /// <returns>A configured <c>hx-headers</c> attribute</returns>
/// <seealso href="https://htmx.org/attributes/hx-headers/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-headers/">Documentation</seealso>
let _hxHeaders hdrs = let _hxHeaders hdrs =
attr "hx-headers" hdrs attr "hx-headers" hdrs
/// <summary> /// <summary>
/// Set to "false" to prevent pages with sensitive information from being stored in the history cache /// Set to "false" to prevent pages with sensitive information from being stored in the history cache
/// </summary> /// </summary>
@@ -567,31 +567,31 @@ module HtmxAttrs =
/// <seealso href="https://htmx.org/attributes/hx-history/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-history/">Documentation</seealso>
let _hxHistory shouldStore = let _hxHistory shouldStore =
attr "hx-history" (toLowerBool shouldStore) attr "hx-history" (toLowerBool shouldStore)
/// <summary>The element to snapshot and restore during history navigation</summary> /// <summary>The element to snapshot and restore during history navigation</summary>
/// <seealso href="https://htmx.org/attributes/hx-history-elt/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-history-elt/">Documentation</seealso>
let _hxHistoryElt = let _hxHistoryElt =
flag "hx-history-elt" flag "hx-history-elt"
/// <summary>Includes additional data in AJAX requests</summary> /// <summary>Includes additional data in AJAX requests</summary>
/// <param name="spec">The specification of what should be included in the request</param> /// <param name="spec">The specification of what should be included in the request</param>
/// <returns>A configured <c>hx-include</c> attribute</returns> /// <returns>A configured <c>hx-include</c> attribute</returns>
/// <seealso href="https://htmx.org/attributes/hx-include/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-include/">Documentation</seealso>
let _hxInclude spec = let _hxInclude spec =
attr "hx-include" spec attr "hx-include" spec
/// <summary>The element to put the <c>htmx-request</c> class on during the AJAX request</summary> /// <summary>The element to put the <c>htmx-request</c> class on during the AJAX request</summary>
/// <param name="selector">The selector for the indicator element</param> /// <param name="selector">The selector for the indicator element</param>
/// <returns>A configured <c>hx-indicator</c> attribute</returns> /// <returns>A configured <c>hx-indicator</c> attribute</returns>
/// <seealso href="https://htmx.org/attributes/hx-indicator/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-indicator/">Documentation</seealso>
let _hxIndicator selector = let _hxIndicator selector =
attr "hx-indicator" selector attr "hx-indicator" selector
/// <summary>Overrides a previous <c>hx-boost</c> (hx-boost="false")</summary> /// <summary>Overrides a previous <c>hx-boost</c> (hx-boost="false")</summary>
/// <seealso href="https://htmx.org/attributes/hx-boost/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-boost/">Documentation</seealso>
let _hxNoBoost = let _hxNoBoost =
attr "hx-boost" "false" attr "hx-boost" "false"
/// <summary>Attach an event handler for DOM events</summary> /// <summary>Attach an event handler for DOM events</summary>
/// <param name="evtName">The name of the event</param> /// <param name="evtName">The name of the event</param>
/// <param name="handler">The script to be executed when the event occurs</param> /// <param name="handler">The script to be executed when the event occurs</param>
@@ -616,26 +616,26 @@ module HtmxAttrs =
/// <seealso href="https://htmx.org/attributes/hx-params/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-params/">Documentation</seealso>
let _hxParams toInclude = let _hxParams toInclude =
attr "hx-params" toInclude attr "hx-params" toInclude
/// <summary>Issues a <c>PATCH</c> to the specified URL</summary> /// <summary>Issues a <c>PATCH</c> to the specified URL</summary>
/// <param name="url">The URL to which the request should be directed</param> /// <param name="url">The URL to which the request should be directed</param>
/// <returns>A configured <c>hx-patch</c> attribute</returns> /// <returns>A configured <c>hx-patch</c> attribute</returns>
/// <seealso href="https://htmx.org/attributes/hx-patch/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-patch/">Documentation</seealso>
let _hxPatch url = let _hxPatch url =
attr "hx-patch" url attr "hx-patch" url
/// <summary>Issues a <c>POST</c> to the specified URL</summary> /// <summary>Issues a <c>POST</c> to the specified URL</summary>
/// <param name="url">The URL to which the request should be directed</param> /// <param name="url">The URL to which the request should be directed</param>
/// <returns>A configured <c>hx-post</c> attribute</returns> /// <returns>A configured <c>hx-post</c> attribute</returns>
/// <seealso href="https://htmx.org/attributes/hx-post/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-post/">Documentation</seealso>
let _hxPost url = let _hxPost url =
attr "hx-post" url attr "hx-post" url
/// <summary>Preserves an element between requests</summary> /// <summary>Preserves an element between requests</summary>
/// <seealso href="https://htmx.org/attributes/hx-preserve/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-preserve/">Documentation</seealso>
let _hxPreserve = let _hxPreserve =
flag "hx-preserve" flag "hx-preserve"
/// <summary>Shows a <c>prompt()</c> dialog before submitting a request</summary> /// <summary>Shows a <c>prompt()</c> dialog before submitting a request</summary>
/// <param name="text">The text for the prompt</param> /// <param name="text">The text for the prompt</param>
/// <returns>A configured <c>hx-prompt</c> attribute</returns> /// <returns>A configured <c>hx-prompt</c> attribute</returns>
@@ -643,7 +643,7 @@ module HtmxAttrs =
/// <seealso href="https://htmx.org/attributes/hx-prompt/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-prompt/">Documentation</seealso>
let _hxPrompt text = let _hxPrompt text =
attr "hx-prompt" text attr "hx-prompt" text
/// <summary>Pushes the URL into the location bar, creating a new history entry</summary> /// <summary>Pushes the URL into the location bar, creating a new history entry</summary>
/// <param name="spec"> /// <param name="spec">
/// <ul> /// <ul>
@@ -656,14 +656,14 @@ module HtmxAttrs =
/// <seealso href="https://htmx.org/attributes/hx-push-url/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-push-url/">Documentation</seealso>
let _hxPushUrl spec = let _hxPushUrl spec =
attr "hx-push-url" spec attr "hx-push-url" spec
/// <summary>Issues a <c>PUT</c> to the specified URL</summary> /// <summary>Issues a <c>PUT</c> to the specified URL</summary>
/// <param name="url">The URL to which the request should be directed</param> /// <param name="url">The URL to which the request should be directed</param>
/// <returns>A configured <c>hx-put</c> attribute</returns> /// <returns>A configured <c>hx-put</c> attribute</returns>
/// <seealso href="https://htmx.org/attributes/hx-put/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-put/">Documentation</seealso>
let _hxPut url = let _hxPut url =
attr "hx-put" url attr "hx-put" url
/// <summary>Replaces the current URL in the browser's history stack</summary> /// <summary>Replaces the current URL in the browser's history stack</summary>
/// <param name="spec"> /// <param name="spec">
/// <ul> /// <ul>
@@ -676,7 +676,7 @@ module HtmxAttrs =
/// <seealso href="https://htmx.org/attributes/hx-replace-url/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-replace-url/">Documentation</seealso>
let _hxReplaceUrl spec = let _hxReplaceUrl spec =
attr "hx-replace-url" spec attr "hx-replace-url" spec
/// <summary>Configures various aspects of the request</summary> /// <summary>Configures various aspects of the request</summary>
/// <param name="spec">The configuration spec (use <c>HxRequest.Configure</c> to create value)</param> /// <param name="spec">The configuration spec (use <c>HxRequest.Configure</c> to create value)</param>
/// <returns>A configured <c>hx-request</c> attribute</returns> /// <returns>A configured <c>hx-request</c> attribute</returns>
@@ -684,21 +684,21 @@ module HtmxAttrs =
/// <seealso href="https://htmx.org/attributes/hx-request/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-request/">Documentation</seealso>
let _hxRequest spec = let _hxRequest spec =
attr "hx-request" spec attr "hx-request" spec
/// <summary>Selects a subset of the server response to process</summary> /// <summary>Selects a subset of the server response to process</summary>
/// <param name="selector">A CSS selector for the content to be selected</param> /// <param name="selector">A CSS selector for the content to be selected</param>
/// <returns>A configured <c>hx-select</c> attribute</returns> /// <returns>A configured <c>hx-select</c> attribute</returns>
/// <seealso href="https://htmx.org/attributes/hx-select/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-select/">Documentation</seealso>
let _hxSelect selector = let _hxSelect selector =
attr "hx-select" selector attr "hx-select" selector
/// <summary>Selects a subset of an out-of-band server response</summary> /// <summary>Selects a subset of an out-of-band server response</summary>
/// <param name="selectors">One or more comma-delimited CSS selectors for the content to be selected</param> /// <param name="selectors">One or more comma-delimited CSS selectors for the content to be selected</param>
/// <returns>A configured <c>hx-select-oob</c> attribute</returns> /// <returns>A configured <c>hx-select-oob</c> attribute</returns>
/// <seealso href="https://htmx.org/attributes/hx-select-oob/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-select-oob/">Documentation</seealso>
let _hxSelectOob selectors = let _hxSelectOob selectors =
attr "hx-select-oob" selectors attr "hx-select-oob" selectors
/// <summary> /// <summary>
/// Controls how the response content is swapped into the DOM (e.g. <c>outerHTML</c> or <c>beforeEnd</c>) /// Controls how the response content is swapped into the DOM (e.g. <c>outerHTML</c> or <c>beforeEnd</c>)
/// </summary> /// </summary>
@@ -707,7 +707,7 @@ module HtmxAttrs =
/// <seealso href="https://htmx.org/attributes/hx-swap/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-swap/">Documentation</seealso>
let _hxSwap swap = let _hxSwap swap =
attr "hx-swap" swap attr "hx-swap" swap
/// <summary> /// <summary>
/// Controls how the response content is swapped into the DOM (e.g. <c>outerHTML</c> or <c>beforeEnd</c>), enabling /// Controls how the response content is swapped into the DOM (e.g. <c>outerHTML</c> or <c>beforeEnd</c>), enabling
/// CSS transitions /// CSS transitions
@@ -717,7 +717,7 @@ module HtmxAttrs =
/// <seealso href="https://htmx.org/attributes/hx-swap/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-swap/">Documentation</seealso>
let _hxSwapWithTransition swap = let _hxSwapWithTransition swap =
_hxSwap $"%s{swap} transition:true" _hxSwap $"%s{swap} transition:true"
/// <summary> /// <summary>
/// Marks content in a response as being "Out of Band", i.e. swapped somewhere other than the target /// Marks content in a response as being "Out of Band", i.e. swapped somewhere other than the target
/// </summary> /// </summary>
@@ -732,7 +732,7 @@ module HtmxAttrs =
/// <seealso href="https://htmx.org/attributes/hx-swap-oob/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-swap-oob/">Documentation</seealso>
let _hxSwapOob swap = let _hxSwapOob swap =
attr "hx-swap-oob" swap attr "hx-swap-oob" swap
/// <summary>Synchronize events based on another element</summary> /// <summary>Synchronize events based on another element</summary>
/// <param name="selector">A CSS selector for the element with which this one should sync</param> /// <param name="selector">A CSS selector for the element with which this one should sync</param>
/// <param name="action">The request synchronization action to perform (use <c>HxSync</c> values)</param> /// <param name="action">The request synchronization action to perform (use <c>HxSync</c> values)</param>
@@ -741,14 +741,14 @@ module HtmxAttrs =
/// <seealso href="https://htmx.org/attributes/hx-sync/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-sync/">Documentation</seealso>
let _hxSync selector action = let _hxSync selector action =
attr "hx-sync" $"%s{selector}:%s{action}" attr "hx-sync" $"%s{selector}:%s{action}"
/// <summary>Specifies the target element to be swapped</summary> /// <summary>Specifies the target element to be swapped</summary>
/// <param name="selector">A CSS selector or relative reference (or both) to identify the target</param> /// <param name="selector">A CSS selector or relative reference (or both) to identify the target</param>
/// <returns>A configured <c>hx-target</c> attribute</returns> /// <returns>A configured <c>hx-target</c> attribute</returns>
/// <seealso href="https://htmx.org/attributes/hx-target/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-target/">Documentation</seealso>
let _hxTarget selector = let _hxTarget selector =
attr "hx-target" selector attr "hx-target" selector
/// <summary>Specifies the event that triggers the request</summary> /// <summary>Specifies the event that triggers the request</summary>
/// <param name="spec">The trigger specification (use <c>HxTrigger</c> to create)</param> /// <param name="spec">The trigger specification (use <c>HxTrigger</c> to create)</param>
/// <returns>A configured <c>hx-trigger</c> attribute</returns> /// <returns>A configured <c>hx-trigger</c> attribute</returns>
@@ -756,12 +756,12 @@ module HtmxAttrs =
/// <seealso href="https://htmx.org/attributes/hx-trigger/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-trigger/">Documentation</seealso>
let _hxTrigger spec = let _hxTrigger spec =
attr "hx-trigger" spec attr "hx-trigger" spec
/// <summary>Validate an input element (uses HTML5 validation API)</summary> /// <summary>Validate an input element (uses HTML5 validation API)</summary>
/// <seealso href="https://htmx.org/attributes/hx-validate/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-validate/">Documentation</seealso>
let _hxValidate = let _hxValidate =
flag "hx-validate" flag "hx-validate"
/// <summary>Adds to the parameters that will be submitted with the request</summary> /// <summary>Adds to the parameters that will be submitted with the request</summary>
/// <param name="values">The values for the parameters (use <c>HxVals.From</c> to create)</param> /// <param name="values">The values for the parameters (use <c>HxVals.From</c> to create)</param>
/// <returns>A configured <c>hx-vals</c> attribute</returns> /// <returns>A configured <c>hx-vals</c> attribute</returns>
@@ -769,7 +769,7 @@ module HtmxAttrs =
/// <seealso href="https://htmx.org/attributes/hx-vals/">Documentation</seealso> /// <seealso href="https://htmx.org/attributes/hx-vals/">Documentation</seealso>
let _hxVals values = let _hxVals values =
attr "hx-vals" values attr "hx-vals" values
/// <summary>The URL of the SSE server</summary> /// <summary>The URL of the SSE server</summary>
/// <param name="url">The URL from which events will be received</param> /// <param name="url">The URL from which events will be received</param>
/// <returns>A configured <c>sse-connect</c> attribute</returns> /// <returns>A configured <c>sse-connect</c> attribute</returns>
@@ -792,19 +792,19 @@ module Script =
/// <summary>Script tag to load the package-provided version of htmx</summary> /// <summary>Script tag to load the package-provided version of htmx</summary>
let local = script [ _src htmxLocalScript ] [] let local = script [ _src htmxLocalScript ] []
/// <summary>Script tag to load the minified version from jsdelivr.net</summary> /// <summary>Script tag to load the minified version from jsdelivr.net</summary>
/// <remarks>Ensure <c>cdn.jsdelivr.net</c> is in your CSP <c>script-src</c> list (if applicable)</remarks> /// <remarks>Ensure <c>cdn.jsdelivr.net</c> is in your CSP <c>script-src</c> list (if applicable)</remarks>
let cdnMinified = let cdnMinified =
script [ _src "https://cdn.jsdelivr.net/npm/htmx.org@2.0.8/dist/htmx.min.js" script [ _src $"https://cdn.jsdelivr.net/npm/htmx.org@{HtmxVersion}/dist/htmx.min.js"
_integrity "sha256-Iig+9oy3VFkU8KiKG97cclanA9HVgMHSVSF9ClDTExM=" _integrity "sha384-H5SrcfygHmAuTDZphMHqBJLc3FhssKjG7w/CeCpFReSfwBWDTKpkzPP8c+cLsK+V"
_crossorigin "anonymous" ] [] _crossorigin "anonymous" ] []
/// <summary>Script tag to load the unminified version from jsdelivr.net</summary> /// <summary>Script tag to load the unminified version from jsdelivr.net</summary>
/// <remarks>Ensure <c>cdn.jsdelivr.net</c> is in your CSP <c>script-src</c> list (if applicable)</remarks> /// <remarks>Ensure <c>cdn.jsdelivr.net</c> is in your CSP <c>script-src</c> list (if applicable)</remarks>
let cdnUnminified = let cdnUnminified =
script [ _src "https://cdn.jsdelivr.net/npm/htmx.org@2.0.8/dist/htmx.js" script [ _src $"https://cdn.jsdelivr.net/npm/htmx.org@{HtmxVersion}/dist/htmx.js"
_integrity "sha256-upUwYnay6R+DA68rROTAP+EdfO3NvOqtE513PgDyAYM=" _integrity "sha384-Q+Dky3iHVJOr6wUjQ4ulh6uQ76an/t+ak1+PjMVaxRjbZamFLAG+u9InkfjbsEQf"
_crossorigin "anonymous" ] [] _crossorigin "anonymous" ] []
/// <summary>Script tag to load the minified version from jsdelivr.net</summary> /// <summary>Script tag to load the minified version from jsdelivr.net</summary>
@@ -819,7 +819,7 @@ module Script =
/// <summary>Functions to extract and render an HTML fragment from a document</summary> /// <summary>Functions to extract and render an HTML fragment from a document</summary>
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module RenderFragment = module RenderFragment =
/// Does this element have an ID matching the requested ID name? /// Does this element have an ID matching the requested ID name?
let private isIdElement nodeId (elt: XmlElement) = let private isIdElement nodeId (elt: XmlElement) =
snd elt snd elt
@@ -831,7 +831,7 @@ module RenderFragment =
/// Generate a message if the requested ID node is not found /// Generate a message if the requested ID node is not found
let private nodeNotFound (nodeId: string) = let private nodeNotFound (nodeId: string) =
$"<em>&ndash; ID {nodeId} not found &ndash;</em>" $"<em>&ndash; ID {nodeId} not found &ndash;</em>"
/// <summary>Find the node with the named ID</summary> /// <summary>Find the node with the named ID</summary>
/// <param name="nodeId">The <c>id</c> attribute to find</param> /// <param name="nodeId">The <c>id</c> attribute to find</param>
/// <param name="node">The node tree to search</param> /// <param name="node">The node tree to search</param>
@@ -842,7 +842,7 @@ module RenderFragment =
| VoidElement elt -> if isIdElement nodeId elt then Some node else None | VoidElement elt -> if isIdElement nodeId elt then Some node else None
| ParentNode (elt, children) -> | ParentNode (elt, children) ->
if isIdElement nodeId elt then Some node else children |> List.tryPick (findIdNode nodeId) if isIdElement nodeId elt then Some node else children |> List.tryPick (findIdNode nodeId)
/// <summary>Functions to render a fragment as a string</summary> /// <summary>Functions to render a fragment as a string</summary>
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module AsString = module AsString =
+1 -1
View File
@@ -2,7 +2,7 @@
This package enables [htmx](https://htmx.org) support within the [Giraffe](https://giraffe.wiki) view engine. This package enables [htmx](https://htmx.org) support within the [Giraffe](https://giraffe.wiki) view engine.
**htmx version: 2.0.8** **htmx version: 2.0.10**
_Upgrading from v1.x: see [the migration guide](https://htmx.org/migration-guide-htmx-1/) for changes_ _Upgrading from v1.x: see [the migration guide](https://htmx.org/migration-guide-htmx-1/) for changes_