@@ -6,7 +6,7 @@ namespace Htmxor.Http;
6
6
/// <summary>
7
7
/// A builder class for constructing a swap style command string for HTMX responses.
8
8
/// </summary>
9
- public class SwapStyleBuilder
9
+ public sealed class SwapStyleBuilder
10
10
{
11
11
private readonly SwapStyle ? style ;
12
12
private readonly OrderedDictionary modifiers = new ( ) ;
@@ -21,21 +21,50 @@ public SwapStyleBuilder(SwapStyle? style = null)
21
21
}
22
22
23
23
/// <summary>
24
- /// Adds a delay to the swap operation.
24
+ /// Modifies the amount of time that htmx will wait after receiving a
25
+ /// response to swap the content by including the modifier <c>swap:<paramref name="time"/></c>.
25
26
/// </summary>
26
- /// <param name="span">The time span to delay the swap.</param>
27
- /// <returns>The SwapStyleBuilder instance for chaining.</returns>
28
- public SwapStyleBuilder After ( TimeSpan span )
27
+ /// <remarks>
28
+ /// <paramref name="time"/> will be converted to milliseconds if less than 1000, otherwise seconds,
29
+ /// meaning the resulting modifier will be <c>swap:500ms</c> for a <see cref="TimeSpan"/> of 500 milliseconds
30
+ /// or <c>swap:2s</c> for a <see cref="TimeSpan"/> of 2 seconds..
31
+ /// </remarks>
32
+ /// <param name="style">The swap style.</param>
33
+ /// <param name="time">The amount of time htmx should wait after receiving a
34
+ /// response to swap the content.</param>
35
+ public SwapStyleBuilder AfterSwapDelay ( TimeSpan time )
29
36
{
30
- AddModifier ( "swap" , span . TotalMilliseconds < 1000 ? $ "{ span . TotalMilliseconds } ms" : $ "{ span . TotalSeconds } s") ;
37
+ AddModifier ( "swap" , time . TotalMilliseconds < 1000 ? $ "{ time . TotalMilliseconds } ms" : $ "{ time . TotalSeconds } s") ;
31
38
32
39
return this ;
33
40
}
34
41
35
42
/// <summary>
36
- /// Specifies the direction to scroll the page after the swap.
43
+ /// Modifies the amount of time that htmx will wait between the swap
44
+ /// and the settle logic by including the modifier <c>settle:<paramref name="time"/></c>.
45
+ /// </summary>
46
+ /// <remarks>
47
+ /// <paramref name="time"/> will be converted to milliseconds if less than 1000, otherwise seconds,
48
+ /// meaning the resulting modifier will be <c>swap:500ms</c> for a <see cref="TimeSpan"/> of 500 milliseconds
49
+ /// or <c>swap:2s</c> for a <see cref="TimeSpan"/> of 2 seconds..
50
+ /// </remarks>
51
+ /// <param name="time">The amount of time htmx should wait after receiving a
52
+ /// response to swap the content.</param>
53
+ public SwapStyleBuilder AfterSettleDelay ( TimeSpan time )
54
+ {
55
+ AddModifier ( "settle" , time . TotalMilliseconds < 1000 ? $ "{ time . TotalMilliseconds } ms" : $ "{ time . TotalSeconds } s") ;
56
+
57
+ return this ;
58
+ }
59
+
60
+ /// <summary>
61
+ /// Specifies the direction to scroll the page after the swap and appends the modifier <c>scroll:{direction}</c>.
37
62
/// </summary>
38
- /// <param name="direction">The scroll direction.</param>
63
+ /// <remarks>
64
+ /// Sets the scroll direction on the page after swapping. For instance, using <see cref="ScrollDirection.Top"/>
65
+ /// will add the modifier <c>scroll:top</c> which instructs the page to scroll to the top after the swap.
66
+ /// </remarks>
67
+ /// <param name="direction">The scroll direction after the swap.</param>
39
68
/// <returns>The SwapStyleBuilder instance for chaining.</returns>
40
69
public SwapStyleBuilder Scroll ( ScrollDirection direction )
41
70
{
@@ -53,20 +82,60 @@ public SwapStyleBuilder Scroll(ScrollDirection direction)
53
82
}
54
83
55
84
/// <summary>
56
- /// Determines whether to ignore the document title in the swap response.
85
+ /// Automatically scrolls to the top of the page after a swap.
86
+ /// </summary>
87
+ /// <remarks>
88
+ /// This method adds the modifier <c>scroll:top</c> to the swap commands, instructing the page to scroll to
89
+ /// the top after content is swapped.
90
+ /// </remarks>
91
+ /// <returns>The SwapStyleBuilder instance for chaining.</returns>
92
+ public SwapStyleBuilder ScrollTop ( ) => Scroll ( ScrollDirection . Top ) ;
93
+
94
+ /// <summary>
95
+ /// Automatically scrolls to the bottom of the page after a swap.
96
+ /// </summary>
97
+ /// <remarks>
98
+ /// This method adds the modifier <c>scroll:bottom</c> to the swap commands, instructing the page to scroll to
99
+ /// the bottom after content is swapped.
100
+ /// </remarks>
101
+ /// <returns>The SwapStyleBuilder instance for chaining.</returns>
102
+ public SwapStyleBuilder ScrollBottom ( ) => Scroll ( ScrollDirection . Bottom ) ;
103
+
104
+ /// <summary>
105
+ /// Determines whether to ignore the document title in the swap response by appending the modifier
106
+ /// <c>ignoreTitle:{ignore}</c>.
57
107
/// </summary>
108
+ /// <remarks>
109
+ /// When set to true, the document title in the swap response will be ignored by adding the modifier
110
+ /// <c>ignoreTitle:true</c>.
111
+ /// This keeps the current title unchanged regardless of the incoming swap content's title tag.
112
+ /// </remarks>
58
113
/// <param name="ignore">Whether to ignore the title.</param>
59
114
/// <returns>The SwapStyleBuilder instance for chaining.</returns>
60
- public SwapStyleBuilder IgnoreTitle ( bool ignore )
115
+ public SwapStyleBuilder IgnoreTitle ( bool ignore = true )
61
116
{
62
117
AddModifier ( "ignoreTitle" , ignore ) ;
63
118
64
119
return this ;
65
120
}
66
121
67
122
/// <summary>
68
- /// Enables or disables transition effects for the swap.
123
+ /// Includes the document title from the swap response in the current page.
124
+ /// </summary>
125
+ /// <remarks>
126
+ /// This method ensures the title of the document is updated according to the swap response by removing any
127
+ /// ignoreTitle modifiers, effectively setting <c>ignoreTitle:false</c>.
128
+ /// </remarks>
129
+ /// <returns>The SwapStyleBuilder instance for chaining.</returns>
130
+ public SwapStyleBuilder IncludeTitle ( ) => IgnoreTitle ( false ) ;
131
+
132
+ /// <summary>
133
+ /// Enables or disables transition effects for the swap by appending the modifier <c>transition:{show}</c>.
69
134
/// </summary>
135
+ /// <remarks>
136
+ /// Controls the display of transition effects during the swap. For example, setting <paramref name="show"/> to true
137
+ /// will add the modifier <c>transition:true</c> to enable smooth transitions.
138
+ /// </remarks>
70
139
/// <param name="show">Whether to show transition effects.</param>
71
140
/// <returns>The SwapStyleBuilder instance for chaining.</returns>
72
141
public SwapStyleBuilder Transition ( bool show )
@@ -77,20 +146,49 @@ public SwapStyleBuilder Transition(bool show)
77
146
}
78
147
79
148
/// <summary>
80
- /// Sets whether to focus and scroll to the swapped content.
149
+ /// Explicitly includes transition effects for the swap.
150
+ /// </summary>
151
+ /// <remarks>
152
+ /// By calling this method, transition effects are enabled for the swap, adding the modifier <c>transition:true</c>.
153
+ /// </remarks>
154
+ /// <returns>The SwapStyleBuilder instance for chaining.</returns>
155
+ public SwapStyleBuilder IncludeTransition ( ) => Transition ( true ) ;
156
+
157
+ /// <summary>
158
+ /// Explicitly ignores transition effects for the swap.
81
159
/// </summary>
160
+ /// <remarks>
161
+ /// This method disables transition effects by adding the modifier <c>transition:false</c> to the swap commands.
162
+ /// </remarks>
163
+ /// <returns>The SwapStyleBuilder instance for chaining.</returns>
164
+ public SwapStyleBuilder IgnoreTransition ( ) => Transition ( false ) ;
165
+
166
+ /// <summary>
167
+ /// htmx preserves focus between requests for inputs that have a defined id attribute. By
168
+ /// default htmx prevents auto-scrolling to focused inputs between requests which can be
169
+ /// unwanted behavior on longer requests when the user has already scrolled away.
170
+ /// </summary>
171
+ /// <remarks>
172
+ /// <paramref name="scroll"/> when true will be <c>focus-scroll:true</c>, otherwise when false
173
+ /// will be <c>focus-scroll:false</c>
174
+ /// </remarks>
82
175
/// <param name="scroll">Whether to scroll to the focus element.</param>
83
176
/// <returns>The SwapStyleBuilder instance for chaining.</returns>
84
- public SwapStyleBuilder FocusScroll ( bool scroll )
177
+ public SwapStyleBuilder ScrollFocus ( bool scroll = true )
85
178
{
86
179
AddModifier ( "focus-scroll" , scroll ) ;
87
180
88
181
return this ;
89
182
}
90
183
184
+ public SwapStyleBuilder PreserveFocus ( ) => ScrollFocus ( false ) ;
185
+
91
186
/// <summary>
92
- /// Specifies a CSS selector to dynamically target for the swap operation.
187
+ /// Specifies a CSS selector to dynamically target for the swap operation, with an optional scroll direction after the swap .
93
188
/// </summary>
189
+ /// <remarks>
190
+ /// Adds a show modifier with the specified CSS selector and scroll direction. For example, if <paramref name="selector"/> is ".item" and <paramref name="direction"/> is <see cref="ScrollDirection.Top"/>, the modifier <c>show:.item:top</c> is added.
191
+ /// </remarks>
94
192
/// <param name="selector">The CSS selector of the target element.</param>
95
193
/// <param name="direction">The scroll direction after swap.</param>
96
194
/// <returns>The SwapStyleBuilder instance for chaining.</returns>
@@ -109,12 +207,35 @@ public SwapStyleBuilder ShowOn(string selector, ScrollDirection direction)
109
207
return this ;
110
208
}
111
209
210
+ /// <summary>
211
+ /// Specifies that the swap should show the element matching the CSS selector at the top of the window.
212
+ /// </summary>
213
+ /// <remarks>
214
+ /// This method adds the modifier <c>show:{selector}:top</c>, directing the swap to display the specified element at the top of the window.
215
+ /// </remarks>
216
+ /// <param name="selector">The CSS selector of the target element.</param>
217
+ /// <returns>The SwapStyleBuilder instance for chaining.</returns>
218
+ public SwapStyleBuilder ShowOnTop ( string selector ) => ShowOn ( selector , ScrollDirection . Top ) ;
219
+
220
+ /// <summary>
221
+ /// Specifies that the swap should show the element matching the CSS selector at the bottom of the window.
222
+ /// </summary>
223
+ /// <remarks>
224
+ /// This method adds the modifier <c>show:{selector}:bottom</c>, directing the swap to display the specified element at the bottom of the window.
225
+ /// </remarks>
226
+ /// <param name="selector">The CSS selector of the target element.</param>
227
+ /// <returns>The SwapStyleBuilder instance for chaining.</returns>
228
+ public SwapStyleBuilder ShowOnBottom ( string selector ) => ShowOn ( selector , ScrollDirection . Bottom ) ;
229
+
112
230
/// <summary>
113
231
/// Specifies that the swap should show in the window, with an optional scroll direction.
114
232
/// </summary>
115
233
/// <param name="direction">The direction to scroll the window after the swap.</param>
234
+ /// <remarks>
235
+ /// This method adds the modifier <c>show:window:{direction}</c>, directing the swap to display the specified element at the bottom of the window.
236
+ /// </remarks>
116
237
/// <returns>The SwapStyleBuilder instance for chaining.</returns>
117
- public SwapStyleBuilder ShowWindow ( ScrollDirection direction )
238
+ public SwapStyleBuilder ShowOnWindow ( ScrollDirection direction )
118
239
{
119
240
switch ( direction )
120
241
{
@@ -130,8 +251,34 @@ public SwapStyleBuilder ShowWindow(ScrollDirection direction)
130
251
}
131
252
132
253
/// <summary>
133
- /// Turns off scrolling after swap
254
+ /// Specifies that the swap should show content at the top of the window.
255
+ /// </summary>
256
+ /// <remarks>
257
+ /// This method adds the modifier <c>show:window:top</c>, instructing the content to be displayed
258
+ /// at the top of the window following a swap. This can be useful for ensuring that important content or
259
+ /// notifications are immediately visible to the user after a swap operation.
260
+ /// </remarks>
261
+ /// <returns>The SwapStyleBuilder instance for chaining.</returns>
262
+ public SwapStyleBuilder ShowOnWindowTop ( ) => ShowOnWindow ( ScrollDirection . Top ) ;
263
+
264
+ /// <summary>
265
+ /// Specifies that the swap should show content at the bottom of the window.
134
266
/// </summary>
267
+ /// <remarks>
268
+ /// This method adds the modifier <c>show:window:bottom</c>, instructing the content to be displayed
269
+ /// at the bottom of the window following a swap. This positioning can be used for infinite scrolling, footers or
270
+ /// lower-priority information that should not immediately distract from other content.
271
+ /// </remarks>
272
+ /// <returns>The SwapStyleBuilder instance for chaining.</returns>
273
+ public SwapStyleBuilder ShowOnWindowBottom ( ) => ShowOnWindow ( ScrollDirection . Bottom ) ;
274
+
275
+ /// <summary>
276
+ /// Turns off scrolling after swap.
277
+ /// </summary>
278
+ /// <remarks>
279
+ /// This method disables automatic scrolling by setting the modifier <c>show:none</c>, ensuring the page
280
+ /// position remains unchanged after the swap.
281
+ /// </remarks>
135
282
/// <returns>The SwapStyleBuilder instance for chaining.</returns>
136
283
public SwapStyleBuilder ShowNone ( )
137
284
{
@@ -167,11 +314,11 @@ private void AddModifier(string modifier, string options)
167
314
{
168
315
if ( modifiers . Contains ( modifier ) )
169
316
modifiers . Remove ( modifier ) ;
170
-
317
+
171
318
modifiers . Add ( modifier , options ) ;
172
319
}
173
320
174
- private void AddModifier ( string modifier , bool option ) => AddModifier ( modifier , option . ToString ( ) . ToLowerInvariant ( ) ) ;
321
+ private void AddModifier ( string modifier , bool option ) => AddModifier ( modifier , option ? "true" : "false" ) ;
175
322
}
176
323
177
324
/// <summary>
@@ -182,12 +329,23 @@ public static class SwapStyleBuilderExtension
182
329
// Each method below returns a SwapStyleBuilder instance initialized with the respective SwapStyle
183
330
// and applies the specified modifier to it. This allows for fluent configuration of swap style commands.
184
331
185
- public static SwapStyleBuilder After ( this SwapStyle style , TimeSpan span ) => new SwapStyleBuilder ( style ) . After ( span ) ;
332
+ public static SwapStyleBuilder AfterSwapDelay ( this SwapStyle style , TimeSpan time ) => new SwapStyleBuilder ( style ) . AfterSwapDelay ( time ) ;
333
+ public static SwapStyleBuilder AfterSettleDelay ( this SwapStyle style , TimeSpan time ) => new SwapStyleBuilder ( style ) . AfterSettleDelay ( time ) ;
186
334
public static SwapStyleBuilder Scroll ( this SwapStyle style , ScrollDirection direction ) => new SwapStyleBuilder ( style ) . Scroll ( direction ) ;
187
- public static SwapStyleBuilder IgnoreTitle ( this SwapStyle style , bool ignore ) => new SwapStyleBuilder ( style ) . IgnoreTitle ( ignore ) ;
335
+ public static SwapStyleBuilder ScrollTop ( this SwapStyle style ) => new SwapStyleBuilder ( style ) . ScrollTop ( ) ;
336
+ public static SwapStyleBuilder ScrollBottom ( this SwapStyle style ) => new SwapStyleBuilder ( style ) . ScrollBottom ( ) ;
337
+ public static SwapStyleBuilder IgnoreTitle ( this SwapStyle style , bool ignore = true ) => new SwapStyleBuilder ( style ) . IgnoreTitle ( ignore ) ;
338
+ public static SwapStyleBuilder IncludeTitle ( this SwapStyle style ) => new SwapStyleBuilder ( style ) . IncludeTitle ( ) ;
188
339
public static SwapStyleBuilder Transition ( this SwapStyle style , bool show ) => new SwapStyleBuilder ( style ) . Transition ( show ) ;
189
- public static SwapStyleBuilder FocusScroll ( this SwapStyle style , bool scroll ) => new SwapStyleBuilder ( style ) . FocusScroll ( scroll ) ;
340
+ public static SwapStyleBuilder IncludeTransition ( this SwapStyle style ) => new SwapStyleBuilder ( style ) . IncludeTransition ( ) ;
341
+ public static SwapStyleBuilder IgnoreTransition ( this SwapStyle style ) => new SwapStyleBuilder ( style ) . IgnoreTransition ( ) ;
342
+ public static SwapStyleBuilder ScrollFocus ( this SwapStyle style , bool scroll = true ) => new SwapStyleBuilder ( style ) . ScrollFocus ( scroll ) ;
343
+ public static SwapStyleBuilder PreserveFocus ( this SwapStyle style , bool scroll = true ) => new SwapStyleBuilder ( style ) . PreserveFocus ( ) ;
190
344
public static SwapStyleBuilder ShowOn ( this SwapStyle style , string selector , ScrollDirection direction ) => new SwapStyleBuilder ( style ) . ShowOn ( selector , direction ) ;
191
- public static SwapStyleBuilder ShowWindow ( this SwapStyle style , ScrollDirection direction ) => new SwapStyleBuilder ( style ) . ShowWindow ( direction ) ;
345
+ public static SwapStyleBuilder ShowOnTop ( this SwapStyle style , string selector ) => new SwapStyleBuilder ( style ) . ShowOnTop ( selector ) ;
346
+ public static SwapStyleBuilder ShowOnBottom ( this SwapStyle style , string selector ) => new SwapStyleBuilder ( style ) . ShowOnBottom ( selector ) ;
347
+ public static SwapStyleBuilder ShowOnWindow ( this SwapStyle style , ScrollDirection direction ) => new SwapStyleBuilder ( style ) . ShowOnWindow ( direction ) ;
348
+ public static SwapStyleBuilder ShowOnWindowTop ( this SwapStyle style ) => new SwapStyleBuilder ( style ) . ShowOnWindowTop ( ) ;
349
+ public static SwapStyleBuilder ShowOnWindowBottom ( this SwapStyle style ) => new SwapStyleBuilder ( style ) . ShowOnWindowBottom ( ) ;
192
350
public static SwapStyleBuilder ShowNone ( this SwapStyle style ) => new SwapStyleBuilder ( style ) . ShowNone ( ) ;
193
351
}
0 commit comments