datastar/sdk/go/fragments.go

173 lines
4.6 KiB
Go

package datastar
import (
"fmt"
"strconv"
"strings"
"time"
)
type MergeFragmentOptions struct {
EventID string
RetryDuration time.Duration
Selector string
MergeMode FragmentMergeMode
SettleDuration time.Duration
UseViewTransitions bool
}
type MergeFragmentOption func(*MergeFragmentOptions)
func WithSelectorf(selectorFormat string, args ...any) MergeFragmentOption {
selector := fmt.Sprintf(selectorFormat, args...)
return WithSelector(selector)
}
func WithSelector(selector string) MergeFragmentOption {
return func(o *MergeFragmentOptions) {
o.Selector = selector
}
}
func WithMergeMode(merge FragmentMergeMode) MergeFragmentOption {
return func(o *MergeFragmentOptions) {
o.MergeMode = merge
}
}
func WithSettleDuration(d time.Duration) MergeFragmentOption {
return func(o *MergeFragmentOptions) {
o.SettleDuration = d
}
}
func WithUseViewTransitions(useViewTransition bool) MergeFragmentOption {
return func(o *MergeFragmentOptions) {
o.UseViewTransitions = useViewTransition
}
}
func (sse *ServerSentEventGenerator) MergeFragments(fragment string, opts ...MergeFragmentOption) error {
options := &MergeFragmentOptions{
EventID: "",
RetryDuration: DefaultSseRetryDuration,
Selector: "",
MergeMode: FragmentMergeModeMorph,
SettleDuration: DefaultFragmentsSettleDuration,
}
for _, opt := range opts {
opt(options)
}
sendOptions := make([]SSEEventOption, 0, 2)
if options.EventID != "" {
sendOptions = append(sendOptions, WithSSEEventId(options.EventID))
}
if options.RetryDuration > 0 {
sendOptions = append(sendOptions, WithSSERetryDuration(options.RetryDuration))
}
dataRows := make([]string, 0, 4)
if options.Selector != "" {
dataRows = append(dataRows, SelectorDatalineLiteral+options.Selector)
}
if options.MergeMode != FragmentMergeModeMorph {
dataRows = append(dataRows, MergeModeDatalineLiteral+string(options.MergeMode))
}
if options.SettleDuration > 0 && options.SettleDuration != DefaultFragmentsSettleDuration {
settleDuration := strconv.Itoa(int(options.SettleDuration.Milliseconds()))
dataRows = append(dataRows, SettleDurationDatalineLiteral+settleDuration)
}
if options.UseViewTransitions {
dataRows = append(dataRows, UseViewTransitionDatalineLiteral+"true")
}
if fragment != "" {
parts := strings.Split(fragment, "\n")
for _, part := range parts {
dataRows = append(dataRows, FragmentsDatalineLiteral+part)
}
}
if err := sse.Send(
EventTypeMergeFragments,
dataRows,
sendOptions...,
); err != nil {
return fmt.Errorf("failed to send fragment: %w", err)
}
return nil
}
type RemoveFragmentsOptions struct {
EventID string
RetryDuration time.Duration
SettleDuration time.Duration
UseViewTransitions *bool
}
type RemoveFragmentsOption func(*RemoveFragmentsOptions)
func WithRemoveEventID(id string) RemoveFragmentsOption {
return func(o *RemoveFragmentsOptions) {
o.EventID = id
}
}
func WithRemoveRetryDuration(d time.Duration) RemoveFragmentsOption {
return func(o *RemoveFragmentsOptions) {
o.RetryDuration = d
}
}
func WithRemoveSettleDuration(d time.Duration) RemoveFragmentsOption {
return func(o *RemoveFragmentsOptions) {
o.SettleDuration = d
}
}
func WithRemoveUseViewTransitions(useViewTransition bool) RemoveFragmentsOption {
return func(o *RemoveFragmentsOptions) {
o.UseViewTransitions = &useViewTransition
}
}
func (sse *ServerSentEventGenerator) RemoveFragments(selector string, opts ...RemoveFragmentsOption) error {
if selector == "" {
panic("missing " + SelectorDatalineLiteral)
}
options := &RemoveFragmentsOptions{
EventID: "",
RetryDuration: DefaultSseRetryDuration,
SettleDuration: DefaultFragmentsSettleDuration,
UseViewTransitions: nil,
}
for _, opt := range opts {
opt(options)
}
dataRows := []string{SelectorDatalineLiteral + selector}
if options.SettleDuration > 0 && options.SettleDuration != DefaultFragmentsSettleDuration {
settleDuration := strconv.Itoa(int(options.SettleDuration.Milliseconds()))
dataRows = append(dataRows, SettleDurationDatalineLiteral+settleDuration)
}
if options.UseViewTransitions != nil {
dataRows = append(dataRows, UseViewTransitionDatalineLiteral+strconv.FormatBool(*options.UseViewTransitions))
}
sendOptions := make([]SSEEventOption, 0, 2)
if options.EventID != "" {
sendOptions = append(sendOptions, WithSSEEventId(options.EventID))
}
if options.RetryDuration > 0 {
sendOptions = append(sendOptions, WithSSERetryDuration(options.RetryDuration))
}
if err := sse.Send(EventTypeRemoveFragments, dataRows, sendOptions...); err != nil {
return fmt.Errorf("failed to send remove: %w", err)
}
return nil
}