diff --git a/README.md b/README.md
index 805a9e6..2c4b1d6 100644
--- a/README.md
+++ b/README.md
@@ -126,8 +126,7 @@ Some important notes: Signals defined later in the DOM tree override those defin
- [Binding to Signals](#signal-binding)
- [Events and Triggers](#events-and-triggers)
- [Actions and Functions](#actions-and-functions)
-- [Miscellaneous Actions](#miscellaneous-actions)
-- [When to $](#_when-to-_)
+- [When to $](#when-to-)
## _Attribute Index_
@@ -136,15 +135,14 @@ Some important notes: Signals defined later in the DOM tree override those defin
- [data-class](#dsclass--data-class)
- [data-computed](#dscomputed--data-computed)
- [data-effect](#dseffect--data-effect)
-- [data-ignore](#dsignore-dsignorethis-dsignoremorph--data-star-ignore)
+- [data-ignore](#dsignore--dsignoreself--dsignoremorph--data-star-ignore)
- [data-indicator](#dsindicator--data-indicator)
- [data-json-signals](#dssignals--dssignal--data-signals)
+- [data-init](#dsinit--data-init)
- [data-on](#dsonevent--data-on)
- [data-on-intersect](#dsonintersect--data-on-intersect)
- [data-on-interval](#dsoninterval--data-on-interval)
-- [data-on-load](#dsonload--data-on-load)
- [data-on-signal-patch](#dsonsignalpatch--dsonsignalpatchfilter--data-on-signal-patch)
-- [data-on-signal-patch-filter](#dsonsignalpatch--dsonsignalpatchfilter--data-on-signal-patch)
- [data-ref](#dsref--data-ref)
- [data-show](#dsshow--data-show)
- [data-signals](#dssignals--dssignal--data-signals)
@@ -228,7 +226,7 @@ Example: setting the innerText of a `
` to a value that is updated by a serv
### [Ds.bind : `data-bind`](https://data-star.dev/reference/attributes#data-bind)
Creates a two-way binding from a signal to the "value" of an HTML "input" element. Can be placed on any HTML element on which data can be input or choices
-selected (e.g. `input`, `textarea`, `select`, `checkbox` and `radio` elements, as well as web components. (Although not necessary, you can find the `switch` statement in the
+selected (e.g. `input`, `textarea`, `select`, `checkbox` and `radio` elements, as well as web components. Although not necessary, you can find the `switch` statement in the
[source](https://github.com/starfederation/datastar/blob/main/library/src/plugins/attributes/bind.ts) to see how signals are translated).
The signal will be created if it does not already exist. And the type of the signal is preserved during binding; if an element's value changes,
the signal value is automatically converted to match the original (see the [documentation](https://data-star.dev/reference/attributes#data-bind) for an example.)
@@ -285,6 +283,16 @@ Elem.div [ Ds.style "display" "$hiding && 'none'" ] [ Text.raw "Might be hiding"
Events and triggers result in [Datastar expressions](https://data-star.dev/guide/datastar_expressions) being executed. This can result in signal changes and other expressions being run.
Example: clicking a button to send a request or an element scrolling into view.
+### [Ds.init : `data-init`](https://data-star.dev/reference/attributes#data-init)
+
+Runs an expression when the element is loaded into the DOM. **Important:** when patching elements,
+`ElementPatchMode.Replace` the [Datastar expression](https://data-star.dev/guide/datastar_expressions)
+will be fired a second time, but will not with `ElementPatchMode.Outer`.
+
+```fsharp
+Elem.div [ Ds.init (Ds.get "/moreAgents") ] []
+```
+
### [Ds.onEvent : `data-on`](https://data-star.dev/reference/attributes#data-on)
Attaches an event listener to an element, executing a [Datastar expression](https://data-star.dev/guide/datastar_expressions) whenever the event is triggered.
@@ -297,7 +305,7 @@ Elem.div [ Ds.onEvent("mouseenter", "$show = !$show"); Ds.onEvent("mouseexit", "
```fsharp
Elem.button [ Ds.onClick "$show = !$show" ] [ Text.raw "Peek-a-boo!" ]
-Elem.div [ Ds.onLoad (Ds.get "/edit") ] []
+Elem.div [ Ds.init (Ds.get "/edit") ] []
```
#### `data-on` Modifiers
@@ -310,9 +318,9 @@ Modifiers allow you to alter the behavior when events are triggered. (Modifiers
| Passive // * - can only be used with built-in events
| Capture // * - can only be used with built-in events
| Delay of TimeSpan
- | DelayMs of int // identical to Delay, but just milliseconds
- | Debounce of Debounce // timespan, leading, and notrail
- | Throttle of Throttle // timepan, noleading, and trail
+ | DelayMs of int // identical to Delay, but using milliseconds instead
+ | Debounce of Debounce // timespan, leading, and notrailing
+ | Throttle of Throttle // timepan, noleading, and trailing
| ViewTransition
| Window
| Outside
@@ -329,16 +337,7 @@ Elem.div [
Results in:
```html
-
-```
-
-### [Ds.onLoad : `data-on-load`](https://data-star.dev/reference/attributes#data-on-load)
-
-Runs an expression when the element is loaded into the DOM. **Important:** when patching elements, `ElementPatchMode.Replace` the [Datastar expression](https://data-star.dev/guide/datastar_expressions)
-will be fired a second time, but will not with `ElementPatchMode.Outer`.
-
-```fsharp
-Elem.div [ Ds.onLoad (Ds.get "/moreAgents") ] []
+
```
### [Ds.effect : `data-effect`](https://data-star.dev/reference/attributes#data-effect)
@@ -367,12 +366,14 @@ Elem.div [ Ds.onIntersect ("$intersected = true", visibility = Half, onlyOnce =
Elem.div [ Ds.onIntersect ("$intersected = true", visibility = Half, onlyOnce = true, throttle = Throttle.With(TimeSpan.FromSeconds(1.0))) ] []
```
-### [Ds.onSignalPatch | Ds.onSignalPatchFilter: `data-on-signal-patch`](https://data-star.dev/reference/attributes#data-on-signal-change)
+### [Ds.onSignalPatch | Ds.onSignalPatchFilter : `data-on-signal-patch`](https://data-star.dev/reference/attributes#data-on-signal-patch)
Runs an expression any signal changes. This should be used sparingly, as it is cost intensive.
```fsharp
-Elem.div [ Ds.onAnySignalChange "$show = !$show" ] []
+Elem.div [ Ds.onSignalPatch "$show = !$show" ] []
+
+Elem.div [ Ds.onSignalPatchFilter (SignalsFilter.Include "/foo/") ] []
```
### [Ds.onInterval : `data-on-interval`](https://data-star.dev/reference/attributes#data-on-interval)
@@ -407,7 +408,7 @@ All signals, that do not have an underscore prefix, are sent in the request.
`@get` will send the signal values as query parameters. All others are sent within a JSON body.
```fsharp
-Elem.div [ Ds.onLoad (Ds.get "/get") ] []
+Elem.div [ Ds.init (Ds.get "/get") ] []
Elem.button [ Ds.onClick (Ds.post "/post") ] [ Text.raw "Post" ]
@@ -450,21 +451,21 @@ Toggles all the signals that start with the prefix. This is useful for toggling
Elem.div [ Ds.onEvent (OnEvent.SignalsChanged, (Ds.toggleAll "foo.")) ] []
```
-### [Ds.ignore | Ds.ignoreThis | Ds.ignoreMorph : `data-star-ignore`](https://data-star.dev/reference/attributes#data-star-ignore)
+### [Ds.ignore | Ds.ignoreSelf | Ds.ignoreMorph : `data-star-ignore`](https://data-star.dev/reference/attributes#data-ignore)
Datastar walks the entire DOM and applies plugins to each element it encounters.
It’s possible to tell Datastar to ignore an element and its descendants by placing a data-star-ignore attribute on it.
This can be useful for preventing naming conflicts with third-party libraries.
`Ds.ignore` will force Datastar to ignore the element and all child elements.
-`Ds.ignoreThis` only affects the attribute it is attached to.
+`Ds.ignoreSelf` only affects the attribute it is attached to.
```fsharp
Elem.div [ Ds.ignore ] [
Elem.div [ Ds.text "ignoredAsWell" ] []
]
-Elem.div [ Ds.ignoreThis ] [
+Elem.div [ Ds.ignoreSelf ] [
Elem.div [ Ds.text "thisIsNotIgnored" ] []
]
@@ -487,7 +488,7 @@ Elem.pre [ Ds.jsonSignalsOptions (SignalsFilter.Include "/foo/") ] []
## _When to `$`_
You may have noticed in the sample code that the `$` is used in some places, but not others. At first, it might be
-confusing when a `$` is required, but it really isn't all that complicated when you think of it as either being a signal path or an expression.
+confusing when a `$` is required, but it really isn't all that complicated when you think of it as either being a signal path or not.
The `$` symbol is a shorthand to get the value of the signal (e.g. `$count` -> `count.value`), so when the `$` is elided, you are referring to the signal directly.
[`Ds.bind signalPath`](#dsbind--data-bind) is two-way binding to the signal, so it requires the signal path, no `$`.
@@ -627,15 +628,16 @@ are mirrored with a function with `sse` as their prefix instead of `of`.
```fsharp
let handleStream = (fun ctx -> task {
- do! Response.sseStartResponse ctx
+ do! Response.sseStartResponse ctx // make sure this is called first; sends the appropriate headers
let mutable counter = 0
- while true do // all Datastar methods (unless requested otherwise) will throw on ctx.RequestAborted
+ while true do // all Datastar methods will throw on ctx.RequestAborted
do! Response.ssePatchSignal ctx (sp"counter") counter
do! Response.sseHtmlElements ctx ( Elem.pre [ Attr.id "counterId" ] [ Text.raw counter.ToString() ] )
do! Task.Delay(TimeSpan.FromSeconds 1L, ctx.RequestAborted)
counter <- counter + 1
+ })
```
See the [Streaming example](examples/Streaming) for more.
diff --git a/examples/ClickToEdit/ClickToEdit.fs b/examples/ClickToEdit/ClickToEdit.fs
index 74c459c..5a1860f 100644
--- a/examples/ClickToEdit/ClickToEdit.fs
+++ b/examples/ClickToEdit/ClickToEdit.fs
@@ -16,7 +16,7 @@ let ofMainBody : HttpHandler =
]
Elem.body [] [
Text.h1 "Example: Click to Edit"
- Elem.div [ Attr.id "contact"; Ds.onLoad (Ds.get "clickToEdit/view") ] []
+ Elem.div [ Attr.id "contact"; Ds.onInit (Ds.get "clickToEdit/view") ] []
]
]
Response.ofHtml htmlXml
diff --git a/examples/ClickToLoad/ClickToLoad.fs b/examples/ClickToLoad/ClickToLoad.fs
index b0fecfd..417d2e9 100644
--- a/examples/ClickToLoad/ClickToLoad.fs
+++ b/examples/ClickToLoad/ClickToLoad.fs
@@ -35,7 +35,7 @@ let handleIndex: HttpHandler =
[ Elem.th [] [ Text.raw "Name" ]
Elem.th [] [ Text.raw "Email" ]
Elem.th [] [ Text.raw "ID" ] ]
- Elem.tbody [ Attr.id "agent_rows"; Ds.onLoad (Ds.get "/moreAgents") ] [] ] ] ]
+ Elem.tbody [ Attr.id "agent_rows"; Ds.onInit (Ds.get "/moreAgents") ] [] ] ] ]
Response.ofHtml html
diff --git a/examples/Signals/Signals.fs b/examples/Signals/Signals.fs
index f528f1d..d2b47fe 100644
--- a/examples/Signals/Signals.fs
+++ b/examples/Signals/Signals.fs
@@ -125,7 +125,7 @@ let handleIndex : HttpHandler =
Elem.label [ Attr.for' "r6" ] [ Text.raw "Six" ]
Elem.br [
// note that this must follow AFTER the refs are created above
- Ds.filterOnSignalPatch (sf"^checkBoxSignal$")
+ Ds.onSignalPatchFilter (sf"^checkBoxSignal$")
Ds.onSignalPatch "$r4.name = $r5.name = $r6.name = ($checkBoxSignal ? 'radioGroup2' : 'radioGroup1')"
]
]
diff --git a/examples/Streaming/Streaming.fs b/examples/Streaming/Streaming.fs
index 8cf618a..ff43572 100644
--- a/examples/Streaming/Streaming.fs
+++ b/examples/Streaming/Streaming.fs
@@ -41,11 +41,11 @@ let handleIndex ctx = task {
Elem.body [
Ds.signal (SignalPath.userName, user)
Ds.signal (SignalPath.displayType, UserState.displayBadApple)
- Ds.filterOnSignalPatch (SignalsFilter.Include SignalPath.displayType)
+ Ds.onSignalPatchFilter (SignalsFilter.Include SignalPath.displayType)
Ds.onSignalPatch (Ds.get "/channel")
Ds.safariStreamingFix
] [
- Elem.div [ Ds.onLoad (Ds.get "/stream") ] []
+ Elem.div [ Ds.onInit (Ds.get "/stream") ] []
Text.h1 "Example: Streaming"
diff --git a/src/Falco.Datastar/Ds.fs b/src/Falco.Datastar/Ds.fs
index 4186f8b..1a2cc97 100644
--- a/src/Falco.Datastar/Ds.fs
+++ b/src/Falco.Datastar/Ds.fs
@@ -10,7 +10,7 @@ open StarFederation.Datastar.FSharp
[
]
type Ds =
static member cdnSrc =
- @"https://cdn.jsdelivr.net/gh/starfederation/datastar@1.0.0-RC.5/bundles/datastar.js"
+ @"https://cdn.jsdelivr.net/gh/starfederation/datastar@1.0.0-RC.6/bundles/datastar.js"
///
/// Shorthand for `Elem.script [ Attr.type' "module"; Attr.src cdnSrc ] []`
@@ -120,7 +120,7 @@ type Ds =
///
/// Create a signal that refers to the HTML element it is assigned to; after a data-ref is created, you can access attributes of the element.
- /// e.g. data-on-click="$signalRefName.value='newValue'".
+ /// e.g. data-on:click="$signalRefName.value='newValue'".
/// Note: that if an element's attribute changes, the expressions containing this signal will not fire.
/// https://data-star.dev/reference/attributes#data-ref
///
@@ -188,7 +188,7 @@ type Ds =
/// https://data-star.dev/reference/attributes#data-ignore
///
/// Attribute
- static member ignoreThis =
+ static member ignoreSelf =
DsAttr.start "ignore"
|> DsAttr.addModifier { Name="self"; Tags = [] }
|> DsAttr.create
@@ -253,14 +253,14 @@ type Ds =
///
/// Fires the expression when the element is loaded.
- /// https://data-star.dev/reference/attributes#data-on-load
+ /// https://data-star.dev/reference/attributes#data-init
///
/// The expression to evaluate when the event is triggered; https://data-star.dev/guide/datastar_expressions
/// The time to wait before executing the expression in milliseconds; default = 0
/// Wrap expression in document.startViewTransition(); default = false
/// Attribute
- static member onLoad (expression, ?delayMs, ?viewTransition) =
- DsAttr.start "on-load"
+ static member onInit (expression, ?delayMs, ?viewTransition) =
+ DsAttr.start "init"
|> DsAttr.addModifierOption (delayMs |> Option.map DsAttrModifier.DelayMs)
|> DsAttr.addModifierNameIf "viewtransition" (defaultArg viewTransition false)
|> DsAttr.addValue expression
@@ -283,7 +283,7 @@ type Ds =
///
/// Fires the expression when a signal is changed. Filter using Ds.filterOnSignalPatch
- /// hhttps://data-star.dev/reference/attributes#data-on-signal-patch
+ /// https://data-star.dev/reference/attributes#data-on-signal-patch
///
/// The expression to evaluate when the event is triggered; https://data-star.dev/guide/datastar_expressions
/// The time to wait before executing the expression in milliseconds; default = 0
@@ -304,7 +304,7 @@ type Ds =
///
/// Regex of signal paths to be included and excluded
/// Attribute
- static member filterOnSignalPatch (signalsFilter:SignalsFilter) =
+ static member onSignalPatchFilter (signalsFilter:SignalsFilter) =
DsAttr.start "on-signal-patch-filter"
|> DsAttr.addValue (signalsFilter |> SignalsFilter.serialize)
|> DsAttr.create
@@ -437,4 +437,4 @@ type Ds =
/// https://stackoverflow.com/questions/8788802/prevent-safari-loading-from-cache-when-back-button-is-clicked
///
static member safariStreamingFix =
- Attr.create "data-on-pageshow.window" "evt?.persisted && window.location.reload()"
+ Attr.create "data-on:pageshow.window" "evt?.persisted && window.location.reload()"
diff --git a/src/Falco.Datastar/Falco.Datastar.fsproj b/src/Falco.Datastar/Falco.Datastar.fsproj
index 83f9116..d51bbd4 100644
--- a/src/Falco.Datastar/Falco.Datastar.fsproj
+++ b/src/Falco.Datastar/Falco.Datastar.fsproj
@@ -1,7 +1,7 @@
Falco.Datastar
- 1.0.0
+ 1.1.0
Datastar Bindings for the Falco web toolkit.
@@ -19,7 +19,7 @@
Falco.Datastar
- 1.0.0
+ 1.1.0
fsharp;web;falco;falco-sharp;data-star
https://github.com/falcoframework/Falco.Datastar
Apache-2.0
@@ -33,6 +33,7 @@
true
true
true
+ Falco.Datastar
diff --git a/src/Falco.Datastar/Types.fs b/src/Falco.Datastar/Types.fs
index db87d84..6bbf0d8 100644
--- a/src/Falco.Datastar/Types.fs
+++ b/src/Falco.Datastar/Types.fs
@@ -5,7 +5,6 @@ open System.Collections.Generic
open System.Text
open System.Text.Json
open System.Text.Json.Nodes
-open System.Text.RegularExpressions
open System.Web
open Falco.Markup
open StarFederation.Datastar.FSharp
@@ -189,20 +188,20 @@ type RequestOptions =
type Debounce =
{ TimeSpan:TimeSpan
Leading:bool
- NoTrail:bool }
- static member With (timeSpan:TimeSpan, ?leading:bool, ?noTrail:bool) =
- { TimeSpan = timeSpan; Leading = (defaultArg leading false); NoTrail = (defaultArg noTrail false) }
- static member With (milliseconds:int, ?leading:bool, ?noTrail:bool) =
- { TimeSpan = TimeSpan.FromMilliseconds(milliseconds); Leading = (defaultArg leading false); NoTrail = (defaultArg noTrail false) }
+ NoTrailing:bool }
+ static member inline With (timeSpan:TimeSpan, ?leading:bool, ?noTrailing:bool) =
+ { TimeSpan = timeSpan; Leading = (defaultArg leading false); NoTrailing = (defaultArg noTrailing false) }
+ static member inline With (milliseconds:int, ?leading:bool, ?noTrailing:bool) =
+ { TimeSpan = TimeSpan.FromMilliseconds(milliseconds); Leading = (defaultArg leading false); NoTrailing = (defaultArg noTrailing false) }
type Throttle =
{ TimeSpan:TimeSpan
NoLeading:bool
- Trail:bool }
- static member With (timeSpan:TimeSpan, ?noLeading:bool, ?trail:bool) =
- { TimeSpan = timeSpan; NoLeading = (defaultArg noLeading false); Trail = (defaultArg trail false) }
- static member With (milliseconds:int, ?noLeading:bool, ?trail:bool) =
- { TimeSpan = TimeSpan.FromMilliseconds(milliseconds); NoLeading = (defaultArg noLeading false); Trail = (defaultArg trail false) }
+ Trailing:bool }
+ static member inline With (timeSpan:TimeSpan, ?noLeading:bool, ?trailing:bool) =
+ { TimeSpan = timeSpan; NoLeading = (defaultArg noLeading false); Trailing = (defaultArg trailing false) }
+ static member inline With (milliseconds:int, ?noLeading:bool, ?trailing:bool) =
+ { TimeSpan = TimeSpan.FromMilliseconds(milliseconds); NoLeading = (defaultArg noLeading false); Trailing = (defaultArg trailing false) }
type OnEventModifier =
/// Trigger event once. Can only be used with the built-in events
@@ -237,36 +236,36 @@ type DsAttrModifier =
{ Name:string
Tags:string list }
with
- static member Delay (delay:TimeSpan) =
+ static member inline Delay (delay:TimeSpan) =
{ Name = "delay"; Tags = [ $"{delay.TotalMilliseconds}ms" ] }
- static member DelayMs (delay:int) =
+ static member inline DelayMs (delay:int) =
{ Name = "delay"; Tags = [ $"{delay}ms" ] }
- static member DurationMs (duration:int, leading:bool) =
+ static member inline DurationMs (duration:int, leading:bool) =
{ Name = "duration"
Tags = [
$"{duration}ms"
if leading then "leading"
] }
- static member Throttle (throttle:Throttle) =
+ static member inline Throttle (throttle:Throttle) =
{ Name = "throttle"
Tags = [
$"{throttle.TimeSpan.TotalMilliseconds}ms"
if throttle.NoLeading then "noleading"
- if throttle.Trail then "trail"
+ if throttle.Trailing then "trailing"
] }
- static member Debounce (debounce:Debounce) =
+ static member inline Debounce (debounce:Debounce) =
{ Name = "debounce"
Tags = [
$"{debounce.TimeSpan.TotalMilliseconds}ms"
if debounce.Leading then "leading"
- if debounce.NoTrail then "notrail"
+ if debounce.NoTrailing then "notrailing"
] }
- static member OnEventModifier (onEventModifier:OnEventModifier) =
+ static member inline OnEventModifier (onEventModifier:OnEventModifier) =
match onEventModifier with
| Once -> { Name = "once"; Tags = [] }
| Passive -> { Name = "passive"; Tags = [] }
@@ -291,22 +290,16 @@ type DsAttr =
HasCaseModifier:bool
Value:string voption }
with
- static member private removeOnRegex = Regex("(^on-?|^data-on-?)", RegexOptions.Compiled)
-
static member inline start name =
{ Name = name; Target = ValueNone; Modifiers = []; Value = ValueNone; HasCaseModifier = false }
- static member startEvent eventName =
- let removeOn str =
- match str with
- | "online" -> "online"
- | str -> DsAttr.removeOnRegex.Replace(str, "")
- { Name = $"on-{(removeOn eventName)}"; Target = ValueNone; Modifiers = []; Value = ValueNone; HasCaseModifier = false }
+ static member inline startEvent eventName =
+ { Name = $"on"; Target = ValueSome eventName; Modifiers = []; Value = ValueNone; HasCaseModifier = false }
static member inline addTarget name dsAttr=
{ dsAttr with Target = ValueSome name }
- static member addSignalPathTarget (signalPath:SignalPath) =
+ static member inline addSignalPathTarget (signalPath:SignalPath) =
signalPath
|> SignalPath.keys
|> Seq.map SignalPath.kebabValue
@@ -339,7 +332,7 @@ type DsAttr =
|> (fun sb ->
match dsAttr.Target with
| ValueNone -> sb
- | ValueSome target -> sb.Append('-') |> _.Append(target)
+ | ValueSome target -> sb.Append(':') |> _.Append(target)
)
|> (fun sb ->
match dsAttr.Modifiers with
@@ -353,7 +346,7 @@ type DsAttr =
)
|> _.ToString()
- static member create dsAttr =
+ static member inline create dsAttr =
let dsAttrKey = dsAttr |> DsAttr.generateKey
match dsAttr.Value with
| ValueSome value -> Attr.create dsAttrKey value
diff --git a/test/Falco.Datastar.Tests/DsTests.fs b/test/Falco.Datastar.Tests/DsTests.fs
index a16b5e5..ccf8b21 100644
--- a/test/Falco.Datastar.Tests/DsTests.fs
+++ b/test/Falco.Datastar.Tests/DsTests.fs
@@ -15,4 +15,4 @@ module DsTests =
[]
let ``Ds.bind should create an attribute`` () =
testElem [ Ds.bind "signalPath" ]
- |> should equal """div
"""
+ |> should equal """div
"""