Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 31 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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_

Expand All @@ -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)
Expand Down Expand Up @@ -228,7 +226,7 @@ Example: setting the innerText of a `<div>` 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.)
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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
Expand All @@ -329,16 +337,7 @@ Elem.div [

Results in:
```html
<div data-on-click__window__debounce.1000ms.leading="$foo = ''"></div>
```

### [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") ] []
<div data-on:click__window__debounce.1000ms.leading="$foo = ''"></div>
```

### [Ds.effect : `data-effect`](https://data-star.dev/reference/attributes#data-effect)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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" ]

Expand Down Expand Up @@ -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" ] []
]

Expand All @@ -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 `$`.
Expand Down Expand Up @@ -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.
2 changes: 1 addition & 1 deletion examples/ClickToEdit/ClickToEdit.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion examples/ClickToLoad/ClickToLoad.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion examples/Signals/Signals.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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')"
]
]
Expand Down
4 changes: 2 additions & 2 deletions examples/Streaming/Streaming.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
18 changes: 9 additions & 9 deletions src/Falco.Datastar/Ds.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ open StarFederation.Datastar.FSharp
[<AbstractClass; Sealed; RequireQualifiedAccess>]
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"

/// <summary>
/// Shorthand for `Elem.script [ Attr.type' "module"; Attr.src cdnSrc ] []`
Expand Down Expand Up @@ -120,7 +120,7 @@ type Ds =

/// <summary>
/// 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
/// </summary>
Expand Down Expand Up @@ -188,7 +188,7 @@ type Ds =
/// https://data-star.dev/reference/attributes#data-ignore
/// </summary>
/// <returns>Attribute</returns>
static member ignoreThis =
static member ignoreSelf =
DsAttr.start "ignore"
|> DsAttr.addModifier { Name="self"; Tags = [] }
|> DsAttr.create
Expand Down Expand Up @@ -253,14 +253,14 @@ type Ds =

/// <summary>
/// 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
/// </summary>
/// <param name="expression">The expression to evaluate when the event is triggered; https://data-star.dev/guide/datastar_expressions</param>
/// <param name="delayMs">The time to wait before executing the expression in milliseconds; default = 0</param>
/// <param name="viewTransition">Wrap expression in document.startViewTransition(); default = false</param>
/// <returns>Attribute</returns>
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
Expand All @@ -283,7 +283,7 @@ type Ds =

/// <summary>
/// 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
/// </summary>
/// <param name="expression">The expression to evaluate when the event is triggered; https://data-star.dev/guide/datastar_expressions</param>
/// <param name="delayMs">The time to wait before executing the expression in milliseconds; default = 0</param>
Expand All @@ -304,7 +304,7 @@ type Ds =
/// </summary>
/// <param name="signalsFilter">Regex of signal paths to be included and excluded</param>
/// <returns>Attribute</returns>
static member filterOnSignalPatch (signalsFilter:SignalsFilter) =
static member onSignalPatchFilter (signalsFilter:SignalsFilter) =
DsAttr.start "on-signal-patch-filter"
|> DsAttr.addValue (signalsFilter |> SignalsFilter.serialize)
|> DsAttr.create
Expand Down Expand Up @@ -437,4 +437,4 @@ type Ds =
/// https://stackoverflow.com/questions/8788802/prevent-safari-loading-from-cache-when-back-button-is-clicked
/// </summary>
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()"
5 changes: 3 additions & 2 deletions src/Falco.Datastar/Falco.Datastar.fsproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>Falco.Datastar</AssemblyName>
<Version>1.0.0</Version>
<Version>1.1.0</Version>

<!-- General info -->
<Description>Datastar Bindings for the Falco web toolkit.</Description>
Expand All @@ -19,7 +19,7 @@

<!-- NuGet config -->
<PackageId>Falco.Datastar</PackageId>
<PackageVersion>1.0.0</PackageVersion>
<PackageVersion>1.1.0</PackageVersion>
<PackageTags>fsharp;web;falco;falco-sharp;data-star</PackageTags>
<PackageProjectUrl>https://github.com/falcoframework/Falco.Datastar</PackageProjectUrl>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
Expand All @@ -33,6 +33,7 @@
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSymbols>true</IncludeSymbols>
<Title>Falco.Datastar</Title>
</PropertyGroup>

<ItemGroup>
Expand Down
Loading