rblade 0.5.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,22 +1,68 @@
1
+ <a name="rblade-templates"></a>
1
2
  # RBlade Templates
2
3
 
3
- - [Introduction](#introduction)
4
- - [Supercharging Blade With Livewire](#supercharging-blade-with-livewire)
5
- - [Displaying Data](#displaying-data)
6
- - [HTML Entity Encoding](#html-entity-encoding)
7
- - [Blade and JavaScript Frameworks](#blade-and-javascript-frameworks)
8
-
9
- **TODO redo TOC**
4
+ RBlade is a simple, yet powerful templating engine for Ruby on Rails, inspired by [Laravel Blade](https://laravel.com/docs/blade). Unlike other Rails templating engines, RBlade prioritises the use of components and partials within templates.
10
5
 
11
- <a name="introduction"></a>
12
- ## Introduction
6
+ RBlade template files use the `.rblade` file extension and are typically stored in the `app/views` directory.
7
+
8
+ <a name="displaying-data"></a>
9
+ ## Table of Contents
10
+ - [RBlade Templates](#rblade-templates)
11
+ * [Table of Contents](#table-of-contents)
12
+ * [Getting Started](#getting-started)
13
+ * [Displaying Data](#displaying-data)
14
+ + [HTML Entity Encoding](#html-entity-encoding)
15
+ + [RBlade and JavaScript Frameworks](#rblade-and-javascript-frameworks)
16
+ - [The `@verbatim` Directive](#the-at-verbatim-directive)
17
+ * [RBlade Directives](#rblade-directives)
18
+ + [If Statements](#if-statements)
19
+ - [Environment Directives](#environment-directives)
20
+ + [Case Statements](#case-statements)
21
+ + [Loops](#loops)
22
+ + [Conditional Classes & Styles](#conditional-classes-and-styles)
23
+ + [Additional Attributes](#additional-attributes)
24
+ + [The `@once` Directive](#the-once-directive)
25
+ + [Raw Ruby](#raw-ruby)
26
+ + [Comments](#comments)
27
+ * [Components](#components)
28
+ + [Rendering Components](#rendering-components)
29
+ - [Namespaces](#namespaces)
30
+ + [Passing Data to Components](#passing-data-to-components)
31
+ - [Component Properties](#component-properties)
32
+ - [Short Attribute Syntax](#short-attribute-syntax)
33
+ - [Escaping Attribute Rendering](#escaping-attribute-rendering)
34
+ + [Component Attributes](#component-attributes)
35
+ - [Default & Merged Attributes](#default-and-merged-attributes)
36
+ - [Non-Class Attribute Merging](#non-class-attribute-merging)
37
+ - [Conditionally Merge Classes](#conditionally-merge-classes)
38
+ - [Retrieving and Filtering Attributes](#retrieving-and-filtering-attributes)
39
+ + [Slots](#slots)
40
+ - [Slot Attributes](#slot-attributes)
41
+ + [Registering Additional Component Directories](#registering-additional-component-directories)
42
+ + [Index Components](#index-components)
43
+ * [Forms](#forms)
44
+ + [Old Input](#old-input)
45
+ + [Method Field](#method-field)
46
+ * [Stacks](#stacks)
47
+
48
+ <a name="getting-started"></a>
49
+ ## Getting Started
50
+
51
+ Add RBlade to your Rails project by adding it to your Gemfile:
52
+
53
+ ```
54
+ bundle add rblade
55
+ ```
56
+
57
+ RBlade will automatically be detected and start parsing templates ending in `.rblade`.
58
+
59
+ For a quick overview of RBlade's capabilities, refer to the [reference file](REFERENCE.md) or take a look at the [examples](examples/README.md).
13
60
 
14
- RBlade is a simple, yet powerful templating engine for Ruby on Rails, inspired by [Laravel Blade](https://laravel.com/docs/blade). Unlike some templating engines, RBlade does not restrict you from using plain Ruby code in your templates. Blade template files use the `.rblade` file extension and are typically stored in the `app/views` directory.
15
61
 
16
62
  <a name="displaying-data"></a>
17
63
  ## Displaying Data
18
64
 
19
- You may display data that is passed to your RBlade views by wrapping the variable in curly braces. For example, given the following controller method:
65
+ You can display data that is passed to your RBlade views by wrapping the variable in curly braces. For example, given the following controller method:
20
66
 
21
67
  ```ruby
22
68
  def index
@@ -24,16 +70,16 @@ def index
24
70
  end
25
71
  ```
26
72
 
27
- You may display the contents of the `name` variable like so:
73
+ You can display the contents of the `name` variable like so:
28
74
 
29
75
  ```rblade
30
76
  Hello, {{ name }}.
31
77
  ```
32
78
 
33
79
  > [!NOTE]
34
- > RBlade's `{{ }}` print statements are automatically sent through Rails' `h` function to prevent XSS attacks.
80
+ > RBlade's `{{ }}` print directives are automatically sent through Rails' `h` function to prevent XSS attacks.
35
81
 
36
- You are not limited to displaying the contents of the variables passed to the view. You may also print the results of any Ruby function. In fact, you can put any Ruby code you wish inside of a RBlade print directive:
82
+ You are not limited to displaying the contents of the variables passed to the view. You can also print the results of any Ruby function. In fact, you can put any Ruby code you wish inside of a RBlade print directive:
37
83
 
38
84
  ```rblade
39
85
  The current UNIX timestamp is {{ Time.now.to_i }}.
@@ -42,19 +88,19 @@ The current UNIX timestamp is {{ Time.now.to_i }}.
42
88
  <a name="html-entity-encoding"></a>
43
89
  ### HTML Entity Encoding
44
90
 
45
- By default, RBlade `{{ }}` statements are automatically sent through Rails' `h` function to prevent XSS attacks. If you do not want your data to be escaped, you may use the following syntax:
91
+ By default, RBlade `{{ }}` directives are automatically sent through Rails' `h` function to prevent XSS attacks. If you do not want your data to be escaped, you can use the following syntax:
46
92
 
47
93
  ```rblade
48
94
  Hello, {!! name !!}.
49
95
  ```
50
96
 
51
97
  > [!WARNING]
52
- > Be very careful when echoing content that is supplied by users of your application. You should typically use the escaped, double curly brace syntax to prevent XSS attacks when displaying user supplied data.
98
+ > Be very careful when printing content that is supplied by users of your application. You should typically use the escaped, double curly brace syntax to prevent XSS attacks when displaying user supplied data.
53
99
 
54
- <a name="blade-and-javascript-frameworks"></a>
55
- ### Blade and JavaScript Frameworks
100
+ <a name="rblade-and-javascript-frameworks"></a>
101
+ ### RBlade and JavaScript Frameworks
56
102
 
57
- Since many JavaScript frameworks also use "curly" braces to indicate a given expression should be displayed in the browser, you may use the `@` symbol to inform the RBlade rendering engine an expression should remain untouched. For example:
103
+ Since many JavaScript frameworks also use "curly" braces to indicate a given expression should be displayed in the browser, you can use the `@` symbol to inform the RBlade rendering engine an expression should remain untouched. For example:
58
104
 
59
105
  ```rblade
60
106
  <h1>Laravel</h1>
@@ -62,12 +108,12 @@ Since many JavaScript frameworks also use "curly" braces to indicate a given exp
62
108
  Hello, @{{ name }}.
63
109
  ```
64
110
 
65
- In this example, the `@` symbol will be removed by Blade; however, `{{ name }}` expression will remain untouched by the RBlade engine, allowing it to be rendered by your JavaScript framework.
111
+ In this example, the `@` symbol will be removed by RBlade; however, `{{ name }}` expression will remain untouched by the RBlade engine, allowing it to be rendered by your JavaScript framework.
66
112
 
67
- The `@` symbol may also be used to escape RBlade directives:
113
+ The `@` symbol can also be used to escape RBlade directives:
68
114
 
69
115
  ```rblade
70
- {{-- Blade template --}}
116
+ {{-- RBlade template --}}
71
117
  @@if()
72
118
 
73
119
  <!-- HTML output -->
@@ -77,7 +123,7 @@ The `@` symbol may also be used to escape RBlade directives:
77
123
  <a name="the-at-verbatim-directive"></a>
78
124
  #### The `@verbatim` Directive
79
125
 
80
- If you are displaying JavaScript variables in a large portion of your template, you may wrap the HTML in the `@verbatim` directive so that you do not have to prefix each Blade print directive with an `@` symbol:
126
+ If you are displaying JavaScript variables in a large portion of your template, you can wrap the HTML in the `@verbatim` directive so that you do not have to prefix each RBlade print directive with an `@` symbol:
81
127
 
82
128
  ```rblade
83
129
  @verbatim
@@ -87,110 +133,68 @@ If you are displaying JavaScript variables in a large portion of your template,
87
133
  @endverbatim
88
134
  ```
89
135
 
90
- <a name="blade-directives"></a>
136
+ <a name="rblade-directives"></a>
91
137
  ## RBlade Directives
92
138
 
93
139
  In addition to template inheritance and displaying data, RBlade also provides convenient shortcuts for common Ruby control structures, such as conditional statements and loops. These shortcuts provide a very clean, terse way of working with Ruby control structures while also remaining familiar to their ruby counterparts.
94
140
 
95
141
  > [!NOTE]
96
- > RBlade directives are case insensitive and ignore underscores, so depending on your preference, all of `@endif`, `@endIf` and `@end_if` are identical.
142
+ > RBlade directives are case insensitive and ignore underscores, so depending on your preference, all of `@endIf`, `@endIf` and `@end_if` are identical.
97
143
 
98
144
  <a name="if-statements"></a>
99
145
  ### If Statements
100
146
 
101
- You may construct `if` statements using the `@if`, `@elseif`, `@else`, `@endif`, `@unless`, and `@endunless` directives. These directives function identically to their Ruby counterparts:
147
+ You can construct `if` statements using the `@if`, `@elseIf`, `@else`, `@endIf`, `@unless`, and `@endUnless` directives. These directives function identically to their Ruby counterparts:
102
148
 
103
149
  ```rblade
104
150
  @unless(records.nil?)
105
151
  @if (records.count === 1)
106
152
  I have one record!
107
- @elseif (records.count > 1)
153
+ @elseIf (records.count > 1)
108
154
  I have multiple records!
109
155
  @else
110
156
  I don't have any records!
111
- @endif
112
- @endunless
113
- ```
114
-
115
- In addition to the conditional directives already discussed, the `@isset` and `@empty` directives may be used as convenient shortcuts for their respective PHP functions:
116
- **TODO add nil? directive?**
117
- ```rblade
118
- @isset($records)
119
- // $records is defined and is not null...
120
- @endisset
121
-
122
- @empty($records)
123
- // $records is "empty"...
124
- @endempty
125
- ```
126
-
127
- <a name="authentication-directives"></a>
128
- #### Authentication Directives
129
- **TODO add authentication directives?**
130
- The `@auth` and `@guest` directives may be used to quickly determine if the current user is [authenticated](/docs/{{version}}/authentication) or is a guest:
131
-
132
- ```rblade
133
- @auth
134
- // The user is authenticated...
135
- @endauth
136
-
137
- @guest
138
- // The user is not authenticated...
139
- @endguest
157
+ @endIf
158
+ @endUnless
140
159
  ```
141
160
 
142
- If needed, you may specify the authentication guard that should be checked when using the `@auth` and `@guest` directives:
161
+ In addition to the conditional directives above, the `@blank?`, `defined?`, `@empty?`, `@nil?` and `@present` directives can be used as convenient shortcuts:
143
162
 
144
163
  ```rblade
145
- @auth('admin')
146
- // The user is authenticated...
147
- @endauth
148
-
149
- @guest('admin')
150
- // The user is not authenticated...
151
- @endguest
164
+ @present?(records)
165
+ // records is defined and is not nil
166
+ @else
167
+ // Since these directives are compiled to if statements, you can also use the @else directive
168
+ @endempty?
152
169
  ```
153
170
 
154
171
  <a name="environment-directives"></a>
155
172
  #### Environment Directives
156
173
 
157
- You may check if the application is running in the production environment using the `@production` directive:
174
+ You can check if the application is running in the production environment using the `@production` directive:
158
175
 
159
176
  ```rblade
160
177
  @production
161
178
  // Production specific content...
162
- @endproduction
179
+ @endProduction
163
180
  ```
164
181
 
165
- Or, you may determine if the application is running in a specific environment using the `@env` directive:
182
+ Or, you can determine if the application is running in a specific environment using the `@env` directive:
166
183
 
167
184
  ```rblade
168
185
  @env('staging')
169
186
  // The application is running in "staging"...
170
- @endenv
187
+ @endEnv
171
188
 
172
189
  @env(['staging', 'production'])
173
190
  // The application is running in "staging" or "production"...
174
- @endenv
175
- ```
176
-
177
- <a name="session-directives"></a>
178
- #### Session Directives
179
- **TODO add sessuib directives**
180
- The `@session` directive may be used to determine if a [session](/docs/{{version}}/session) value exists. If the session value exists, the template contents within the `@session` and `@endsession` directives will be evaluated. Within the `@session` directive's contents, you may echo the `$value` variable to display the session value:
181
-
182
- ```rblade
183
- @session('status')
184
- <div class="p-4 bg-green-100">
185
- {{ $value }}
186
- </div>
187
- @endsession
191
+ @endEnv
188
192
  ```
189
193
 
190
194
  <a name="switch-statements"></a>
191
195
  ### Case Statements
192
196
 
193
- Case statements can be constructed using the `@case`, `@when`, `@else` and `@endcase` directives:
197
+ Case statements can be constructed using the `@case`, `@when`, `@else` and `@endCase` directives:
194
198
 
195
199
  ```rblade
196
200
  @case(i)
@@ -200,7 +204,7 @@ Case statements can be constructed using the `@case`, `@when`, `@else` and `@end
200
204
  Second case...
201
205
  @else
202
206
  Default case...
203
- @endcase
207
+ @endCase
204
208
  ```
205
209
 
206
210
  <a name="loops"></a>
@@ -211,28 +215,28 @@ In addition to conditional statements, RBlade provides simple directives for wor
211
215
  ```rblade
212
216
  @for (i in 0...10)
213
217
  The current value is {{ i }}
214
- @endfor
218
+ @endFor
215
219
 
216
220
  {{-- Compiles to users.each do |user| ... --}}
217
221
  @each (user in users)
218
222
  <p>This is user {{ user.id }}</p>
219
- @endeach
223
+ @endEach
220
224
 
221
- @forelse (name in [])
225
+ @forElse (name in [])
222
226
  <li>{{ name }}</li>
223
227
  @empty
224
228
  <p>No names</p>
225
- @endforelse
229
+ @endForElse
226
230
 
227
- @eachelse (user in users)
231
+ @eachElse (user in users)
228
232
  <li>{{ user.name }}</li>
229
233
  @empty
230
234
  <p>No users</p>
231
- @endeachelse
235
+ @endEachElse
232
236
 
233
237
  @while (true)
234
238
  <p>I'm looping forever.</p>
235
- @endwhile
239
+ @endWhile
236
240
  ```
237
241
 
238
242
  When using loops you can also skip the current iteration or end the loop using the `@next` and `@break` directives:
@@ -241,88 +245,38 @@ When using loops you can also skip the current iteration or end the loop using t
241
245
  for (user in users)
242
246
  @if (user.type == 1)
243
247
  @next
244
- @endif
248
+ @endIf
245
249
 
246
250
  <li>{{ user.name }}</li>
247
251
 
248
252
  @if (user.number == 5)
249
253
  @break
250
- @endif
251
- @endfor
254
+ @endIf
255
+ @endFor
252
256
  ```
253
257
 
254
- You may also include the continuation or break condition within the directive declaration:
258
+ You can also include the continuation or break condition within the directive declaration:
255
259
 
256
260
  ```rblade
257
- @foreach (user in users)
261
+ @for (user in users)
258
262
  @next(user.type == 1)
259
263
 
260
- <li>{{ $user->name }}</li>
264
+ <li>{{ user.name }}</li>
261
265
 
262
266
  @break(user.number == 5)
263
- @endforeach
264
- ```
265
-
266
- <a name="the-loop-variable"></a>
267
- ### The Loop Variable
268
- **TODO can/should we add this?**
269
- While iterating through a `foreach` loop, a `$loop` variable will be available inside of your loop. This variable provides access to some useful bits of information such as the current loop index and whether this is the first or last iteration through the loop:
270
-
271
- ```rblade
272
- @foreach ($users as $user)
273
- @if ($loop->first)
274
- This is the first iteration.
275
- @endif
276
-
277
- @if ($loop->last)
278
- This is the last iteration.
279
- @endif
280
-
281
- <p>This is user {{ $user->id }}</p>
282
- @endforeach
283
- ```
284
-
285
- If you are in a nested loop, you may access the parent loop's `$loop` variable via the `parent` property:
286
-
287
- ```rblade
288
- @foreach ($users as $user)
289
- @foreach ($user->posts as $post)
290
- @if ($loop->parent->first)
291
- This is the first iteration of the parent loop.
292
- @endif
293
- @endforeach
294
- @endforeach
267
+ @endFor
295
268
  ```
296
269
 
297
- The `$loop` variable also contains a variety of other useful properties:
298
-
299
- <div class="overflow-auto">
300
-
301
- | Property | Description |
302
- | ------------------ | ------------------------------------------------------ |
303
- | `$loop->index` | The index of the current loop iteration (starts at 0). |
304
- | `$loop->iteration` | The current loop iteration (starts at 1). |
305
- | `$loop->remaining` | The iterations remaining in the loop. |
306
- | `$loop->count` | The total number of items in the array being iterated. |
307
- | `$loop->first` | Whether this is the first iteration through the loop. |
308
- | `$loop->last` | Whether this is the last iteration through the loop. |
309
- | `$loop->even` | Whether this is an even iteration through the loop. |
310
- | `$loop->odd` | Whether this is an odd iteration through the loop. |
311
- | `$loop->depth` | The nesting level of the current loop. |
312
- | `$loop->parent` | When in a nested loop, the parent's loop variable. |
313
-
314
- </div>
315
-
316
- <a name="conditional-classes"></a>
270
+ <a name="conditional-classes-and-styles"></a>
317
271
  ### Conditional Classes & Styles
318
272
 
319
- The `@class` directive conditionally adds CSS classes. The directive accepts a `Hash` of classes where the key contains the class or classes you wish to add, and the value is a boolean expression:
273
+ The `@class` directive conditionally adds CSS classes. The directive accepts a Hash of classes where the key contains the class or classes you wish to add, and the value is a boolean expression:
320
274
 
321
275
  ```rblade
322
276
  @ruby
323
277
  isActive = false;
324
278
  hasError = true;
325
- @endruby
279
+ @endRuby
326
280
 
327
281
  <span @class({
328
282
  "p-4": true,
@@ -334,12 +288,12 @@ The `@class` directive conditionally adds CSS classes. The directive accepts a `
334
288
  <span class="p-4 text-gray-500 bg-red"></span>
335
289
  ```
336
290
 
337
- Likewise, the `@style` directive may be used to conditionally add inline CSS styles to an HTML element:
291
+ Likewise, the `@style` directive can be used to conditionally add inline CSS styles to an HTML element:
338
292
 
339
293
  ```rblade
340
294
  @ruby
341
295
  isActive = true;
342
- @endruby
296
+ @endRuby
343
297
 
344
298
  <span @style({
345
299
  "background-color: red": true,
@@ -352,7 +306,7 @@ Likewise, the `@style` directive may be used to conditionally add inline CSS sty
352
306
  <a name="additional-attributes"></a>
353
307
  ### Additional Attributes
354
308
 
355
- For convenience, you may use the `@checked` directive to easily indicate if a given HTML checkbox input is "checked". This directive will print `checked` if the provided condition evaluates to `true`:
309
+ For convenience, you can use the `@checked` directive to easily indicate if a given HTML checkbox input is "checked". This directive will print `checked` if the provided condition evaluates to `true`:
356
310
 
357
311
  ```rblade
358
312
  <input type="checkbox"
@@ -361,7 +315,7 @@ For convenience, you may use the `@checked` directive to easily indicate if a gi
361
315
  @checked(user.active)) />
362
316
  ```
363
317
 
364
- Likewise, the `@selected` directive may be used to indicate if a given select option should be "selected":
318
+ Likewise, the `@selected` directive can be used to indicate if a given select option should be "selected":
365
319
 
366
320
  ```rblade
367
321
  <select name="version">
@@ -369,17 +323,17 @@ Likewise, the `@selected` directive may be used to indicate if a given select op
369
323
  <option value="{{ version }}" @selected(version == selectedVersion)>
370
324
  {{ version }}
371
325
  </option>
372
- @endeach
326
+ @endEach
373
327
  </select>
374
328
  ```
375
329
 
376
- Additionally, the `@disabled` directive may be used to indicate if a given element should be "disabled":
330
+ Additionally, the `@disabled` directive can be used to indicate if a given element should be "disabled":
377
331
 
378
332
  ```rblade
379
333
  <button type="submit" @disabled(isDisabled)>Submit</button>
380
334
  ```
381
335
 
382
- Moreover, the `@readonly` directive may be used to indicate if a given element should be "readonly":
336
+ Moreover, the `@readonly` directive can be used to indicate if a given element should be "readonly":
383
337
 
384
338
  ```rblade
385
339
  <input type="email"
@@ -388,7 +342,7 @@ Moreover, the `@readonly` directive may be used to indicate if a given element s
388
342
  @readonly(!user.isAdmin) />
389
343
  ```
390
344
 
391
- In addition, the `@required` directive may be used to indicate if a given element should be "required":
345
+ In addition, the `@required` directive can be used to indicate if a given element should be "required":
392
346
 
393
347
  ```rblade
394
348
  <input type="text"
@@ -400,7 +354,7 @@ In addition, the `@required` directive may be used to indicate if a given elemen
400
354
  <a name="the-once-directive"></a>
401
355
  ### The `@once` Directive
402
356
 
403
- The `@once` directive allows you to define a portion of the template that will only be evaluated once per rendering cycle. This may be useful for pushing a given piece of JavaScript into the page's header using [stacks](#stacks). For example, if you are rendering a given [component](#components) within a loop, you may wish to only push the JavaScript to the header the first time the component is rendered:
357
+ The `@once` directive allows you to define a portion of the template that will only be evaluated once per rendering cycle. This can be useful for pushing a given piece of JavaScript into the page's header using [stacks](#stacks). For example, if you are rendering a given [component](#components) within a loop, you may wish to only push the JavaScript to the header the first time the component is rendered:
404
358
 
405
359
  ```rblade
406
360
  @once
@@ -446,20 +400,7 @@ In some situations, it's useful to embed Ruby code into your views. You can use
446
400
  ```rblade
447
401
  @ruby
448
402
  counter = 1;
449
- @endruby
450
- ```
451
-
452
- **TODO add require?**
453
- Or, if you only need to use PHP to import a class, you may use the `@use` directive:
454
-
455
- ```rblade
456
- @use('App\Models\Flight')
457
- ```
458
-
459
- A second argument may be provided to the `@use` directive to alias the imported class:
460
-
461
- ```php
462
- @use('App\Models\Flight', 'FlightModel')
403
+ @endRuby
463
404
  ```
464
405
 
465
406
  <a name="comments"></a>
@@ -478,7 +419,7 @@ Components are a way of including sub-views into your templates. To illustrate h
478
419
 
479
420
  First, we will create a new `alert.rblade` file in the `app/views/components/forms` directory. Templates in the `app/views/components` directory and its subdirectories are are automatically discovered as components, so no further registration is required. Both `.rblade` and `.html.rblade` are valid extensions for RBlade components.
480
421
 
481
- Once your component has been created, it may be rendered using its tag alias:
422
+ Once your component has been created, it can be rendered using its tag alias:
482
423
 
483
424
  ```rblade
484
425
  <x-forms.alert/>
@@ -487,7 +428,7 @@ Once your component has been created, it may be rendered using its tag alias:
487
428
  <a name="rendering-components"></a>
488
429
  ### Rendering Components
489
430
 
490
- To display a component, you may use a Blade component tag within one of your Blade templates. Blade component tags start with the string `x-` followed by the kebab case name of the component class:
431
+ To display a component, you can use a RBlade component tag within one of your RBlade templates. RBlade component tags start with the string `x-` followed by the kebab case name of the component class:
491
432
 
492
433
  ```rblade
493
434
  {{-- Render the `alert` component in app/views/components/ --}}
@@ -538,7 +479,7 @@ You can define a component's data properties using a `@props` directive at the t
538
479
  <div class="{{ type }}">{{ message }}</div>
539
480
  ```
540
481
 
541
- The `@props` directive accepts a `Hash` where the key is the name of the attribute, and the value is the default value for the property. You can use the special `_required` value to represent a property with no default that must always be defined:
482
+ The `@props` directive accepts a Hash where the key is the name of the attribute, and the value is the default value for the property. You can use the special `_required` value to represent a property with no default that must always be defined:
542
483
 
543
484
  ```rblade
544
485
  {{-- This will give an error because the alert component requires a message propery --}}
@@ -555,7 +496,7 @@ All properties in the `@props` directive are automatically removed from `attribu
555
496
  <a name="short-attribute-syntax"></a>
556
497
  #### Short Attribute Syntax
557
498
 
558
- When passing attributes to components, you may also use a "short attribute" syntax. This is often convenient since attribute names frequently match the variable names they correspond to:
499
+ When passing attributes to components, you can also use a "short attribute" syntax. This is often convenient since attribute names frequently match the variable names they correspond to:
559
500
 
560
501
  ```rblade
561
502
  {{-- Short attribute syntax... --}}
@@ -568,7 +509,7 @@ When passing attributes to components, you may also use a "short attribute" synt
568
509
  <a name="escaping-attribute-rendering"></a>
569
510
  #### Escaping Attribute Rendering
570
511
 
571
- Since some JavaScript frameworks such as Alpine.js also use colon-prefixed attributes, you may use a double colon (`::`) prefix to inform RBlade that the attribute is not a PHP expression. For example, given the following component:
512
+ Since some JavaScript frameworks such as Alpine.js also use colon-prefixed attributes, you can use a double colon (`::`) prefix to inform RBlade that the attribute is not a Ruby expression. For example, given the following component:
572
513
 
573
514
  ```rblade
574
515
  <x-button ::class="{ danger: isDeleting }">
@@ -587,15 +528,13 @@ The following HTML will be rendered by RBlade:
587
528
  <a name="component-attributes"></a>
588
529
  ### Component Attributes
589
530
 
590
- We've already examined how to pass data attributes to a component; however, sometimes you may need to specify additional HTML attributes, such as `class`, that are not part of the data required for a component to function. Typically, you want to pass these additional attributes down to the root element of the component template. For example, imagine we want to render an `alert` component like so:
531
+ We've already examined how to pass data attributes to a component; however, sometimes you can need to specify additional HTML attributes, such as `class`, that are not part of the data required for a component to function. Typically, you want to pass these additional attributes down to the root element of the component template. For example, imagine we want to render an `alert` component like so:
591
532
 
592
533
  ```rblade
593
534
  <x-alert type="error" :message class="mt-4"/>
594
535
  ```
595
536
 
596
- **TODO remove from attributes bag using @props? Rename to attributes bag?**
597
-
598
- All of the attributes that are not part of the component's constructor will automatically be added to the component's "attribute manager". This attribute manager is automatically made available to the component via the `attributes` variable. All of the attributes may be rendered within the component by printing this variable:
537
+ All of the attributes that are not part of the component's constructor will automatically be added to the component's "attribute manager". This attribute manager is automatically made available to the component via the `attributes` variable. All of the attributes can be rendered within the component by printing this variable:
599
538
 
600
539
  ```rblade
601
540
  <div {{ attributes }}>
@@ -603,10 +542,10 @@ All of the attributes that are not part of the component's constructor will auto
603
542
  </div>
604
543
  ```
605
544
 
606
- <a name="default-merged-attributes"></a>
607
- #### Default / Merged Attributes
545
+ <a name="default-and-merged-attributes"></a>
546
+ #### Default & Merged Attributes
608
547
 
609
- Sometimes you may need to specify default values for attributes or merge additional values into some of the component's attributes. To accomplish this, you may use the attribute manager's `merge` method. This method is particularly useful for defining a set of default CSS classes that should always be applied to a component:
548
+ Sometimes you can need to specify default values for attributes or merge additional values into some of the component's attributes. To accomplish this, you can use the attribute manager's `merge` method. This method is particularly useful for defining a set of default CSS classes that should always be applied to a component:
610
549
 
611
550
  ```rblade
612
551
  <div {{ attributes.merge({"class": "alert alert-#{type}"}) }}>
@@ -657,31 +596,22 @@ The rendered HTML of the `button` component in this example would be:
657
596
  </button>
658
597
  ```
659
598
 
660
- **Todo add prepends**
661
- If you would like an attribute other than `class` or `style` to have its default value and injected values joined together, you can use the `prepends` method. In this example, the `data-controller` attribute will always begin with `profile-controller` and any additional injected `data-controller` values will be placed after this default value:
662
-
663
- ```rblade
664
- <div {{ attributes.merge({"data-controller": attributes.prepends("profile-controller")}) }}>
665
- {{ slot }}
666
- </div>
667
- ```
668
-
669
599
  <a name="conditionally-merge-classes"></a>
670
600
  #### Conditionally Merge Classes
671
- **TODO this**
672
- Sometimes you may wish to merge classes if a given condition is `true`. You can accomplish this via the `class` method, which accepts an array of classes where the array key contains the class or classes you wish to add, while the value is a boolean expression. If the array element has a numeric key, it will always be included in the rendered class list:
601
+
602
+ Sometimes you may wish to merge classes if a given condition is `true`. You can accomplish this via the `class` method, which accepts a Hash of classes where the array key contains the class or classes you wish to add, while the value is a boolean expression:
673
603
 
674
604
  ```rblade
675
- <div {{ $attributes->class(['p-4', 'bg-red' => $hasError]) }}>
676
- {{ $message }}
605
+ <div {{ attributes.class({'p-4': true, 'bg-red': hasError}) }}>
606
+ {{ message }}
677
607
  </div>
678
608
  ```
679
609
 
680
610
  If you need to merge other attributes onto your component, you can chain the `merge` method onto the `class` method:
681
611
 
682
612
  ```rblade
683
- <button {{ $attributes->class(['p-4'])->merge(['type' => 'button']) }}>
684
- {{ $slot }}
613
+ <button {{ attributes.class({'bg-red': hasError}).merge({type: 'button'}) }}>
614
+ {{ slot }}
685
615
  </button>
686
616
  ```
687
617
 
@@ -691,60 +621,37 @@ If you need to merge other attributes onto your component, you can chain the `me
691
621
  <a name="filtering-attributes"></a>
692
622
  #### Retrieving and Filtering Attributes
693
623
 
694
- **Todo this**
695
-
696
- You may filter attributes using the `filter` method. This method accepts a closure which should return `true` if you wish to retain the attribute in the attribute bag:
697
-
698
- ```rblade
699
- {{ $attributes->filter(fn (string $value, string $key) => $key == 'foo') }}
700
- ```
701
-
702
- For convenience, you may use the `whereStartsWith` method to retrieve all attributes whose keys begin with a given string:
624
+ The attributes manager is a wrapper around the Ruby Hash class. Unless explicitly overwritten, any methods called on the attributes manager will call that same method on the underlying Hash.
703
625
 
704
- ```rblade
705
- {{ $attributes->whereStartsWith('wire:model') }}
706
- ```
707
-
708
- Conversely, the `whereDoesntStartWith` method may be used to exclude all attributes whose keys begin with a given string:
626
+ You can filter attributes using the `filter` and `slice` methods. These methods call `filter` and `slice` on the underlying Hash and return a new attributes manager with the result.
709
627
 
710
628
  ```rblade
711
- {{ $attributes->whereDoesntStartWith('wire:model') }}
629
+ {{ attributes.filter { |k, v| k == 'foo'} }}
630
+ {{ attributes.slice :foo }}
712
631
  ```
713
632
 
714
- Using the `first` method, you may render the first attribute in a given attribute bag:
633
+ If you would like to check if an attribute is present on the component, you can use the `has?` method. This method accepts the attribute name as its only argument and returns a boolean indicating whether or not the attribute is present:
715
634
 
716
635
  ```rblade
717
- {{ $attributes->whereStartsWith('wire:model')->first() }}
718
- ```
719
-
720
- If you would like to check if an attribute is present on the component, you may use the `has` method. This method accepts the attribute name as its only argument and returns a boolean indicating whether or not the attribute is present:
721
-
722
- ```rblade
723
- @if ($attributes->has('class'))
636
+ @if (attributes.has?(:class))
724
637
  <div>Class attribute is present</div>
725
- @endif
638
+ @endIf
726
639
  ```
727
640
 
728
- If an array is passed to the `has` method, the method will determine if all of the given attributes are present on the component:
641
+ If multiple parameters are passed to the `has?` method, the method will determine if all of the given attributes are present on the component:
729
642
 
730
643
  ```rblade
731
- @if ($attributes->has(['name', 'class']))
644
+ @if (attributes.has?('name', 'class'))
732
645
  <div>All of the attributes are present</div>
733
- @endif
646
+ @endIf
734
647
  ```
735
648
 
736
- The `hasAny` method may be used to determine if any of the given attributes are present on the component:
649
+ The `has_any?` method can be used to determine if any of the given attributes are present on the component:
737
650
 
738
651
  ```rblade
739
- @if ($attributes->hasAny(['href', ':href', 'v-bind:href']))
652
+ @if (attributes.has_any?('href', ':href', 'v-bind:href'))
740
653
  <div>One of the attributes is present</div>
741
- @endif
742
- ```
743
-
744
- You may retrieve a specific attribute's value using the `get` method:
745
-
746
- ```rblade
747
- {{ $attributes->get('class') }}
654
+ @endIf
748
655
  ```
749
656
 
750
657
  <a name="slots"></a>
@@ -759,7 +666,7 @@ You will often need to pass additional content to your component via "slots". Th
759
666
  </div>
760
667
  ```
761
668
 
762
- We may pass content to the `slot` by injecting content into the component:
669
+ We can pass content to the `slot` by injecting content into the component:
763
670
 
764
671
  ```rblade
765
672
  <x-alert>
@@ -767,6 +674,9 @@ We may pass content to the `slot` by injecting content into the component:
767
674
  </x-alert>
768
675
  ```
769
676
 
677
+ > [!NOTE]
678
+ > You can instead use `<//>` as the closing tag of RBlade components; however, this will bypass some of the template sanity checking that the compiler performs.
679
+
770
680
  Sometimes a component may need to render multiple different slots in different locations within the component. Let's modify our alert component to allow for the injection of a "title" slot:
771
681
 
772
682
  ```rblade
@@ -778,7 +688,7 @@ Sometimes a component may need to render multiple different slots in different l
778
688
  </div>
779
689
  ```
780
690
 
781
- You may define the content of the named slot using the `x-slot` tag. Any content not within an explicit `x-slot` tag will be passed to the component in the `slot` variable:
691
+ You can define the content of the named slot using the `x-slot` tag. Any content not within an explicit `x-slot` tag will be passed to the component in the `slot` variable:
782
692
 
783
693
  ```xml
784
694
  <x-alert>
@@ -789,48 +699,25 @@ You may define the content of the named slot using the `x-slot` tag. Any content
789
699
  <strong>Whoops!</strong> Something went wrong!
790
700
  </x-alert>
791
701
  ```
792
- **TODO this**
793
- You may invoke a slot's `isEmpty` method to determine if the slot contains content:
702
+
703
+ The slot object extends the String interface, so you can invoke a slot's `empty?` method to determine if the slot contains content:
794
704
 
795
705
  ```rblade
796
706
  <span class="alert-title">{{ title }}</span>
797
707
 
798
708
  <div class="alert alert-danger">
799
- @if (slot.isEmpty)
709
+ @if (slot.empty?)
800
710
  This is default content if the slot is empty.
801
711
  @else
802
712
  {{ slot }}
803
- @endif
713
+ @endIf
804
714
  </div>
805
715
  ```
806
716
 
807
- Additionally, the `hasActualContent` method may be used to determine if the slot contains any "actual" content that is not an HTML comment:
808
-
809
- ```rblade
810
- @if (slot.hasActualContent)
811
- The scope has non-comment content.
812
- @endif
813
- ```
814
-
815
- <a name="scoped-slots"></a>
816
- #### Scoped Slots
817
- **TODO can we do this easily?**
818
- If you have used a JavaScript framework such as Vue, you may be familiar with "scoped slots", which allow you to access data or methods from the component within your slot. You may achieve similar behavior in Laravel by defining public methods or properties on your component and accessing the component within your slot via the `$component` variable. In this example, we will assume that the `x-alert` component has a public `formatAlert` method defined on its component class:
819
-
820
- ```rblade
821
- <x-alert>
822
- <x-slot:title>
823
- {{ $component->formatAlert('Server Error') }}
824
- </x-slot>
825
-
826
- <strong>Whoops!</strong> Something went wrong!
827
- </x-alert>
828
- ```
829
-
830
717
  <a name="slot-attributes"></a>
831
718
  #### Slot Attributes
832
719
 
833
- Like RBlade components, you may assign additional [attributes](#component-attributes) to slots such as CSS class names:
720
+ Like RBlade components, you can assign additional [attributes](#component-attributes) to slots such as CSS class names:
834
721
 
835
722
  ```xml
836
723
  <x-card class="shadow-sm">
@@ -846,17 +733,16 @@ Like RBlade components, you may assign additional [attributes](#component-attrib
846
733
  </x-card>
847
734
  ```
848
735
 
849
- To interact with slot attributes, you may access the `attributes` property of the slot's variable. For more information on how to interact with attributes, please consult the documentation on [component attributes](#component-attributes):
736
+ To interact with slot attributes, you can access the `attributes` property of the slot's variable. For more information on how to interact with attributes, please consult the documentation on [component attributes](#component-attributes):
850
737
 
851
- **TODO allow class to contain a string**
852
738
  ```rblade
853
739
  @props({
854
740
  "heading": _required,
855
741
  "footer": _required,
856
742
  })
857
743
 
858
- <div {{ attributes.class(['border']) }}>
859
- <h1 {{ heading.attributes->class('text-lg': true) }}>
744
+ <div {{ attributes.class('border') }}>
745
+ <h1 {{ heading.attributes.class('text-lg') }}>
860
746
  {{ heading }}
861
747
  </h1>
862
748
 
@@ -868,14 +754,16 @@ To interact with slot attributes, you may access the `attributes` property of th
868
754
  </div>
869
755
  ```
870
756
 
871
- <a name="dynamic-components"></a>
872
- ### Dynamic Components
873
- **TODO add this**
874
- Sometimes you may need to render a component without knowing which component should be rendered until runtime. In this situation, you may use RBlade's built-in `dynamic-component` component to render the component based on a runtime value or variable:
757
+ <a name="conditional-rendering"></a>
758
+ #### Conditional Rendering
759
+
760
+ Sometimes, you may wish to return early from a component without printing anything. For example, if you make an error component and no errors are passed in as properties, you might want to skip rendering. You can use the `@shouldRender` directive anywhere within a component to prevent the component from being rendered:
875
761
 
876
762
  ```rblade
877
- @ruby(componentName = "secondary-button")
878
- <x-dynamic-component :component="componentName" class="mt-4" />
763
+ {{-- components/error.rblade --}}
764
+ @props({errors: []})
765
+ @shouldRender(errors.present?)
766
+ ...
879
767
  ```
880
768
 
881
769
  <a name="registering-additional-component-directories"></a>
@@ -895,33 +783,6 @@ RBlade::ComponentStore.add_path(Rails.root.join("app", "views", "partials"), "pa
895
783
 
896
784
  If multiple directories are registered with the same namespace, RBlade will search for components in all the directories in the order they were registered.
897
785
 
898
- <a name="manually-registering-components"></a>
899
- ### Manually Registering Components
900
- **TODO would this be useful? It'd be useful for testing...**
901
- > [!WARNING]
902
- > The following documentation on manually registering components is primarily applicable to those who are writing Laravel packages that include view components. If you are not writing a package, this portion of the component documentation may not be relevant to you.
903
-
904
- When writing components for your own application, components are automatically discovered within the `app/View/Components` directory and `resources/views/components` directory.
905
-
906
- However, if you are building a package that utilizes Blade components or placing components in non-conventional directories, you will need to manually register your component class and its HTML tag alias so that Laravel knows where to find the component. You should typically register your components in the `boot` method of your package's service provider:
907
-
908
- use Illuminate\Support\Facades\Blade;
909
- use VendorPackage\View\Components\AlertComponent;
910
-
911
- /**
912
- * Bootstrap your package's services.
913
- */
914
- public function boot(): void
915
- {
916
- Blade::component('package-alert', AlertComponent::class);
917
- }
918
-
919
- Once your component has been registered, it may be rendered using its tag alias:
920
-
921
- ```rblade
922
- <x-package-alert/>
923
- ```
924
-
925
786
  <a name="anonymous-index-components"></a>
926
787
  ### Index Components
927
788
 
@@ -949,64 +810,26 @@ However, when an `index.rblade` template exists in a directory, it will be rende
949
810
  /app/views/components/accordion/item.rblade
950
811
  ```
951
812
 
952
- <a name="accessing-parent-data"></a>
953
- ### Accessing Parent Data
954
- **TODO this? It might be complicated**
955
- Sometimes you may want to access data from a parent component inside a child component. In these cases, you may use the `@aware` directive. For example, imagine we are building a complex menu component consisting of a parent `<x-menu>` and child `<x-menu.item>`:
956
-
957
- ```rblade
958
- <x-menu color="purple">
959
- <x-menu.item>...</x-menu.item>
960
- <x-menu.item>...</x-menu.item>
961
- </x-menu>
962
- ```
963
-
964
- The `<x-menu>` component may have an implementation like the following:
965
-
966
- ```rblade
967
- <!-- /resources/views/components/menu/index.rblade -->
968
-
969
- @props(['color' => 'gray'])
813
+ <a name="forms"></a>
814
+ ## Forms
970
815
 
971
- <ul {{ $attributes->merge(['class' => 'bg-'.$color.'-200']) }}>
972
- {{ $slot }}
973
- </ul>
974
- ```
816
+ ### Old Input
975
817
 
976
- Because the `color` prop was only passed into the parent (`<x-menu>`), it won't be available inside `<x-menu.item>`. However, if we use the `@aware` directive, we can make it available inside `<x-menu.item>` as well:
818
+ The Rails `params` Hash is available in views and components. However, the `@old` directive is a useful shortcut that will output the old input value for a given key:
977
819
 
978
820
  ```rblade
979
- <!-- /resources/views/components/menu/item.rblade -->
980
-
981
- @aware(['color' => 'gray'])
982
-
983
- <li {{ $attributes->merge(['class' => 'text-'.$color.'-800']) }}>
984
- {{ $slot }}
985
- </li>
821
+ <input type="text" name="email" value="@old('email', user.email)">
986
822
  ```
987
823
 
988
- > [!WARNING]
989
- > The `@aware` directive can not access parent data that is not explicitly passed to the parent component via HTML attributes. Default `@props` values that are not explicitly passed to the parent component can not be accessed by the `@aware` directive.
990
-
991
- <a name="forms"></a>
992
- ## Forms
993
-
994
- <a name="csrf-field"></a>
995
- ### CSRF Field
996
- **TODO I don't think we need this?**
997
- Anytime you define an HTML form in your application, you should include a hidden CSRF token field in the form so that [the CSRF protection](/docs/{{version}}/csrf) middleware can validate the request. You may use the `@csrf` Blade directive to generate the token field:
824
+ The first parameter is the name of the previous input, and the second input is the default if the key isn't present in `params`. The previous example is the equivalent of calling `params.fetch`:
998
825
 
999
826
  ```rblade
1000
- <form method="POST" action="/profile">
1001
- @csrf
1002
-
1003
- ...
1004
- </form>
827
+ <input type="text" name="email" value="{{ params.fetch(:email, user.email) }}">
1005
828
  ```
1006
829
 
1007
830
  <a name="method-field"></a>
1008
831
  ### Method Field
1009
- **TODO add this**
832
+
1010
833
  Since HTML forms can't make `PUT`, `PATCH`, or `DELETE` requests, you will need to add a hidden `_method` field to spoof these HTTP verbs. The `@method` RBlade directive can create this field for you:
1011
834
 
1012
835
  ```rblade
@@ -1017,52 +840,8 @@ Since HTML forms can't make `PUT`, `PATCH`, or `DELETE` requests, you will need
1017
840
  </form>
1018
841
  ```
1019
842
 
1020
- <a name="validation-errors"></a>
1021
- ### Validation Errors
1022
- **TODO this**
1023
- The `@error` directive may be used to quickly check if [validation error messages](/docs/{{version}}/validation#quick-displaying-the-validation-errors) exist for a given attribute. Within an `@error` directive, you may echo the `$message` variable to display the error message:
1024
-
1025
- ```rblade
1026
- <!-- /resources/views/post/create.rblade -->
1027
-
1028
- <label for="title">Post Title</label>
1029
-
1030
- <input id="title"
1031
- type="text"
1032
- class="@error('title') is-invalid @enderror">
1033
-
1034
- @error('title')
1035
- <div class="alert alert-danger">{{ $message }}</div>
1036
- @enderror
1037
- ```
1038
-
1039
- Since the `@error` directive compiles to an "if" statement, you may use the `@else` directive to render content when there is not an error for an attribute:
1040
-
1041
- ```rblade
1042
- <!-- /resources/views/auth.rblade -->
1043
-
1044
- <label for="email">Email address</label>
1045
-
1046
- <input id="email"
1047
- type="email"
1048
- class="@error('email') is-invalid @else is-valid @enderror">
1049
- ```
1050
-
1051
- You may pass [the name of a specific error bag](/docs/{{version}}/validation#named-error-bags) as the second parameter to the `@error` directive to retrieve validation error messages on pages containing multiple forms:
1052
-
1053
- ```rblade
1054
- <!-- /resources/views/auth.rblade -->
1055
-
1056
- <label for="email">Email address</label>
1057
-
1058
- <input id="email"
1059
- type="email"
1060
- class="@error('email', 'login') is-invalid @enderror">
843
+ Alternatively, you can use the dedicated directives for each method: `@put`, `@patch`, or `@delete`.
1061
844
 
1062
- @error('email', 'login')
1063
- <div class="alert alert-danger">{{ $message }}</div>
1064
- @enderror
1065
- ```
1066
845
 
1067
846
  <a name="stacks"></a>
1068
847
  ## Stacks
@@ -1072,18 +851,18 @@ RBlade allows you to push to named stacks which can be rendered elsewhere in ano
1072
851
  ```rblade
1073
852
  @push('scripts')
1074
853
  <script src="/example.js"></script>
1075
- @endpush
854
+ @endPush
1076
855
  ```
1077
856
 
1078
- If you would like to `@push` content if a given boolean expression evaluates to `true`, you may use the `@pushIf` directive:
1079
- **TODO add this**
857
+ If you would like to `@push` content if a given boolean expression evaluates to `true`, you can use the `@pushif` directive:
858
+
1080
859
  ```rblade
1081
860
  @pushIf(shouldPush, 'scripts')
1082
861
  <script src="/example.js"></script>
1083
862
  @endPushIf
1084
863
  ```
1085
864
 
1086
- You may push to a stack as many times as needed. To render the complete stack contents, pass the name of the stack to the `@stack` directive:
865
+ You can push to a stack as many times as needed. To render the complete stack contents, pass the name of the stack to the `@stack` directive:
1087
866
 
1088
867
  ```rblade
1089
868
  <head>
@@ -1098,153 +877,11 @@ If you would like to prepend content onto the beginning of a stack, you should u
1098
877
  ```rblade
1099
878
  @push('scripts')
1100
879
  This will be second...
1101
- @endpush
880
+ @endPush
1102
881
 
1103
882
  // Later...
1104
883
 
1105
884
  @prepend('scripts')
1106
885
  This will be first...
1107
- @endprepend
1108
- ```
1109
-
1110
- <a name="rendering-blade-fragments"></a>
1111
- ## Rendering Blade Fragments
1112
- **TODO this?**
1113
- When using frontend frameworks such as [Turbo](https://turbo.hotwired.dev/) and [htmx](https://htmx.org/), you may occasionally need to only return a portion of a Blade template within your HTTP response. Blade "fragments" allow you to do just that. To get started, place a portion of your Blade template within `@fragment` and `@endfragment` directives:
1114
-
1115
- ```rblade
1116
- @fragment('user-list')
1117
- <ul>
1118
- @foreach ($users as $user)
1119
- <li>{{ $user->name }}</li>
1120
- @endforeach
1121
- </ul>
1122
- @endfragment
1123
- ```
1124
-
1125
- Then, when rendering the view that utilizes this template, you may invoke the `fragment` method to specify that only the specified fragment should be included in the outgoing HTTP response:
1126
-
1127
- ```php
1128
- return view('dashboard', ['users' => $users])->fragment('user-list');
1129
- ```
1130
-
1131
- The `fragmentIf` method allows you to conditionally return a fragment of a view based on a given condition. Otherwise, the entire view will be returned:
1132
-
1133
- ```php
1134
- return view('dashboard', ['users' => $users])
1135
- ->fragmentIf($request->hasHeader('HX-Request'), 'user-list');
1136
- ```
1137
-
1138
- The `fragments` and `fragmentsIf` methods allow you to return multiple view fragments in the response. The fragments will be concatenated together:
1139
-
1140
- ```php
1141
- view('dashboard', ['users' => $users])
1142
- ->fragments(['user-list', 'comment-list']);
1143
-
1144
- view('dashboard', ['users' => $users])
1145
- ->fragmentsIf(
1146
- $request->hasHeader('HX-Request'),
1147
- ['user-list', 'comment-list']
1148
- );
1149
- ```
1150
-
1151
- <a name="extending-blade"></a>
1152
- ## Extending Blade
1153
- **TODO this?**
1154
- Blade allows you to define your own custom directives using the `directive` method. When the Blade compiler encounters the custom directive, it will call the provided callback with the expression that the directive contains.
1155
-
1156
- The following example creates a `@datetime($var)` directive which formats a given `$var`, which should be an instance of `DateTime`:
1157
-
1158
- <?php
1159
-
1160
- namespace App\Providers;
1161
-
1162
- use Illuminate\Support\Facades\Blade;
1163
- use Illuminate\Support\ServiceProvider;
1164
-
1165
- class AppServiceProvider extends ServiceProvider
1166
- {
1167
- /**
1168
- * Register any application services.
1169
- */
1170
- public function register(): void
1171
- {
1172
- // ...
1173
- }
1174
-
1175
- /**
1176
- * Bootstrap any application services.
1177
- */
1178
- public function boot(): void
1179
- {
1180
- Blade::directive('datetime', function (string $expression) {
1181
- return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
1182
- });
1183
- }
1184
- }
1185
-
1186
- As you can see, we will chain the `format` method onto whatever expression is passed into the directive. So, in this example, the final PHP generated by this directive will be:
1187
-
1188
- <?php echo ($var)->format('m/d/Y H:i'); ?>
1189
-
1190
- > [!WARNING]
1191
- > After updating the logic of a Blade directive, you will need to delete all of the cached Blade views. The cached Blade views may be removed using the `view:clear` Artisan command.
1192
-
1193
- <a name="custom-echo-handlers"></a>
1194
- ### Custom Echo Handlers
1195
- **TODO this? Need to do something similar for attribute manager anyway**
1196
- If you attempt to "echo" an object using Blade, the object's `__toString` method will be invoked. The [`__toString`](https://www.php.net/manual/en/language.oop5.magic.php#object.tostring) method is one of PHP's built-in "magic methods". However, sometimes you may not have control over the `__toString` method of a given class, such as when the class that you are interacting with belongs to a third-party library.
1197
-
1198
- In these cases, Blade allows you to register a custom echo handler for that particular type of object. To accomplish this, you should invoke Blade's `stringable` method. The `stringable` method accepts a closure. This closure should type-hint the type of object that it is responsible for rendering. Typically, the `stringable` method should be invoked within the `boot` method of your application's `AppServiceProvider` class:
1199
-
1200
- use Illuminate\Support\Facades\Blade;
1201
- use Money\Money;
1202
-
1203
- /**
1204
- * Bootstrap any application services.
1205
- */
1206
- public function boot(): void
1207
- {
1208
- Blade::stringable(function (Money $money) {
1209
- return $money->formatTo('en_GB');
1210
- });
1211
- }
1212
-
1213
- Once your custom echo handler has been defined, you may simply echo the object in your Blade template:
1214
-
1215
- ```rblade
1216
- Cost: {{ $money }}
1217
- ```
1218
-
1219
- <a name="custom-if-statements"></a>
1220
- ### Custom If Statements
1221
- **TODO this**
1222
- Programming a custom directive is sometimes more complex than necessary when defining simple, custom conditional statements. For that reason, Blade provides a `Blade::if` method which allows you to quickly define custom conditional directives using closures. For example, let's define a custom conditional that checks the configured default "disk" for the application. We may do this in the `boot` method of our `AppServiceProvider`:
1223
-
1224
- use Illuminate\Support\Facades\Blade;
1225
-
1226
- /**
1227
- * Bootstrap any application services.
1228
- */
1229
- public function boot(): void
1230
- {
1231
- Blade::if('disk', function (string $value) {
1232
- return config('filesystems.default') === $value;
1233
- });
1234
- }
1235
-
1236
- Once the custom conditional has been defined, you can use it within your templates:
1237
-
1238
- ```rblade
1239
- @disk('local')
1240
- <!-- The application is using the local disk... -->
1241
- @elsedisk('s3')
1242
- <!-- The application is using the s3 disk... -->
1243
- @else
1244
- <!-- The application is using some other disk... -->
1245
- @enddisk
1246
-
1247
- @unlessdisk('local')
1248
- <!-- The application is not using the local disk... -->
1249
- @enddisk
886
+ @endPrepend
1250
887
  ```