datastar-hs-0.1.0.1: src/Hypermedia/Datastar/PatchSignals.hs
{- |
Module : Hypermedia.Datastar.PatchSignals
Description : Update the browser's reactive signal store
Signals are Datastar's reactive state — key-value pairs that live in the
browser and drive the UI. The server can update signals at any time by
sending a @datastar-patch-signals@ event.
Signal patching uses JSON Merge Patch semantics: set a key to update it,
set a key to @null@ to remove it, and omit a key to leave it unchanged.
@
sendPatchSignals gen (patchSignals \"{\\\"count\\\": 42}\")
@
To set initial state without overwriting values the user may have already
changed (e.g. form inputs), use 'psOnlyIfMissing':
@
sendPatchSignals gen
(patchSignals \"{\\\"name\\\": \\\"default\\\"}\")
{ psOnlyIfMissing = True }
@
-}
module Hypermedia.Datastar.PatchSignals where
import Data.Text (Text)
import Data.Text qualified as T
import Hypermedia.Datastar.Types
{- | Configuration for a @datastar-patch-signals@ SSE event.
Construct values with 'patchSignals', then customise with record updates.
-}
data PatchSignals = PatchSignals
{ psSignals :: Text
{- ^ JSON object containing the signal values to patch. Uses JSON Merge
Patch semantics: set a key to update it, set to @null@ to remove it.
-}
, psOnlyIfMissing :: Bool
{- ^ When 'True', signal values are only set if the key doesn't already
exist in the browser's store. Useful for setting initial state that
shouldn't overwrite user changes (e.g. form input defaults).
Default: 'False'.
-}
, psEventId :: Maybe Text
-- ^ Optional SSE event ID for reconnection. See 'Hypermedia.Datastar.PatchElements.PatchElements' for details.
, psRetryDuration :: Int
-- ^ SSE retry interval in milliseconds. Default: @1000@.
}
deriving (Eq, Show)
{- | Build a 'PatchSignals' event with sensible defaults.
The argument is a JSON object (as 'Text') describing the signals to update.
@
patchSignals \"{\\\"count\\\": 42, \\\"label\\\": \\\"hello\\\"}\"
@
-}
patchSignals :: Text -> PatchSignals
patchSignals sigs =
PatchSignals
{ psSignals = sigs
, psOnlyIfMissing = defaultOnlyIfMissing
, psEventId = Nothing
, psRetryDuration = defaultRetryDuration
}
toDatastarEvent :: PatchSignals -> DatastarEvent
toDatastarEvent ps =
DatastarEvent
{ eventType = EventPatchSignals
, eventId = psEventId ps
, retry = psRetryDuration ps
, dataLines = ifMissingLine ++ signalLines
}
where
ifMissingLine = ["onlyIfMissing true" | psOnlyIfMissing ps]
signalLines = map ("signals " <>) $ T.lines $ psSignals ps