rblade 0.4.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,12 +1,41 @@
1
1
  # RBlade Templates
2
2
 
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**
3
+ - [RBlade Templates](#rblade-templates)
4
+ * [Introduction](#introduction)
5
+ * [Displaying Data](#displaying-data)
6
+ + [HTML Entity Encoding](#html-entity-encoding)
7
+ + [Blade and JavaScript Frameworks](#blade-and-javascript-frameworks)
8
+ - [The `@verbatim` Directive](#the-at-verbatim-directive)
9
+ * [RBlade Directives](#rblade-directives)
10
+ + [If Statements](#if-statements)
11
+ - [Environment Directives](#environment-directives)
12
+ + [Case Statements](#case-statements)
13
+ + [Loops](#loops)
14
+ + [Conditional Classes & Styles](#conditional-classes-and-styles)
15
+ + [Additional Attributes](#additional-attributes)
16
+ + [The `@once` Directive](#the-once-directive)
17
+ + [Raw Ruby](#raw-ruby)
18
+ + [Comments](#comments)
19
+ * [Components](#components)
20
+ + [Rendering Components](#rendering-components)
21
+ - [Namespaces](#namespaces)
22
+ + [Passing Data to Components](#passing-data-to-components)
23
+ - [Component Properties](#component-properties)
24
+ - [Short Attribute Syntax](#short-attribute-syntax)
25
+ - [Escaping Attribute Rendering](#escaping-attribute-rendering)
26
+ + [Component Attributes](#component-attributes)
27
+ - [Default & Merged Attributes](#default-and-merged-attributes)
28
+ - [Non-Class Attribute Merging](#non-class-attribute-merging)
29
+ - [Conditionally Merge Classes](#conditionally-merge-classes)
30
+ - [Retrieving and Filtering Attributes](#retrieving-and-filtering-attributes)
31
+ + [Slots](#slots)
32
+ - [Slot Attributes](#slot-attributes)
33
+ + [Registering Additional Component Directories](#registering-additional-component-directories)
34
+ + [Index Components](#index-components)
35
+ * [Forms](#forms)
36
+ + [Old Input](#old-input)
37
+ + [Method Field](#method-field)
38
+ * [Stacks](#stacks)
10
39
 
11
40
  <a name="introduction"></a>
12
41
  ## Introduction
@@ -31,9 +60,9 @@ Hello, {{ name }}.
31
60
  ```
32
61
 
33
62
  > [!NOTE]
34
- > RBlade's `{{ }}` echo statements are automatically sent through Rails' `h` function to prevent XSS attacks.
63
+ > RBlade's `{{ }}` print statements are automatically sent through Rails' `h` function to prevent XSS attacks.
35
64
 
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 Blade echo statement:
65
+ 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:
37
66
 
38
67
  ```rblade
39
68
  The current UNIX timestamp is {{ Time.now.to_i }}.
@@ -77,7 +106,7 @@ The `@` symbol may also be used to escape RBlade directives:
77
106
  <a name="the-at-verbatim-directive"></a>
78
107
  #### The `@verbatim` Directive
79
108
 
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 echo statement with an `@` symbol:
109
+ 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:
81
110
 
82
111
  ```rblade
83
112
  @verbatim
@@ -98,57 +127,28 @@ In addition to template inheritance and displaying data, RBlade also provides co
98
127
  <a name="if-statements"></a>
99
128
  ### If Statements
100
129
 
101
- You may construct `if` statements using the `@if`, `@elseif`, `@else`, `@endif`, `@unless`, and `@endunless` directives. These directives function identically to their Ruby counterparts:
130
+ You may construct `if` statements using the `@if`, `@elseIf`, `@else`, `@endIf`, `@unless`, and `@endUnless` directives. These directives function identically to their Ruby counterparts:
102
131
 
103
132
  ```rblade
104
133
  @unless(records.nil?)
105
134
  @if (records.count === 1)
106
135
  I have one record!
107
- @elseif (records.count > 1)
136
+ @elseIf (records.count > 1)
108
137
  I have multiple records!
109
138
  @else
110
139
  I don't have any records!
111
- @endif
112
- @endunless
140
+ @endIf
141
+ @endUnless
113
142
  ```
114
143
 
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
140
- ```
141
-
142
- If needed, you may specify the authentication guard that should be checked when using the `@auth` and `@guest` directives:
144
+ In addition to the conditional directives above, the `@blank?`, `defined?`, `@empty?`, `@nil?` and `@present` directives may be used as convenient shortcuts:
143
145
 
144
146
  ```rblade
145
- @auth('admin')
146
- // The user is authenticated...
147
- @endauth
148
-
149
- @guest('admin')
150
- // The user is not authenticated...
151
- @endguest
147
+ @present?(records)
148
+ // records is defined and is not nil
149
+ @else
150
+ // These directives are shortcuts to if statements so @else may be used
151
+ @endempty?
152
152
  ```
153
153
 
154
154
  <a name="environment-directives"></a>
@@ -159,7 +159,7 @@ You may check if the application is running in the production environment using
159
159
  ```rblade
160
160
  @production
161
161
  // Production specific content...
162
- @endproduction
162
+ @endProduction
163
163
  ```
164
164
 
165
165
  Or, you may determine if the application is running in a specific environment using the `@env` directive:
@@ -167,30 +167,17 @@ Or, you may determine if the application is running in a specific environment us
167
167
  ```rblade
168
168
  @env('staging')
169
169
  // The application is running in "staging"...
170
- @endenv
170
+ @endEnv
171
171
 
172
172
  @env(['staging', 'production'])
173
173
  // 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
174
+ @endEnv
188
175
  ```
189
176
 
190
177
  <a name="switch-statements"></a>
191
178
  ### Case Statements
192
179
 
193
- Case statements can be constructed using the `@case`, `@when`, `@else` and `@endcase` directives:
180
+ Case statements can be constructed using the `@case`, `@when`, `@else` and `@endCase` directives:
194
181
 
195
182
  ```rblade
196
183
  @case(i)
@@ -200,7 +187,7 @@ Case statements can be constructed using the `@case`, `@when`, `@else` and `@end
200
187
  Second case...
201
188
  @else
202
189
  Default case...
203
- @endcase
190
+ @endCase
204
191
  ```
205
192
 
206
193
  <a name="loops"></a>
@@ -211,28 +198,28 @@ In addition to conditional statements, RBlade provides simple directives for wor
211
198
  ```rblade
212
199
  @for (i in 0...10)
213
200
  The current value is {{ i }}
214
- @endfor
201
+ @endFor
215
202
 
216
203
  {{-- Compiles to users.each do |user| ... --}}
217
204
  @each (user in users)
218
205
  <p>This is user {{ user.id }}</p>
219
- @endeach
206
+ @endEach
220
207
 
221
- @forelse (name in [])
208
+ @forElse (name in [])
222
209
  <li>{{ name }}</li>
223
210
  @empty
224
211
  <p>No names</p>
225
- @endforelse
212
+ @endForElse
226
213
 
227
- @eachelse (user in users)
214
+ @eachElse (user in users)
228
215
  <li>{{ user.name }}</li>
229
216
  @empty
230
217
  <p>No users</p>
231
- @endeachelse
218
+ @endEachElse
232
219
 
233
220
  @while (true)
234
221
  <p>I'm looping forever.</p>
235
- @endwhile
222
+ @endWhile
236
223
  ```
237
224
 
238
225
  When using loops you can also skip the current iteration or end the loop using the `@next` and `@break` directives:
@@ -241,79 +228,29 @@ When using loops you can also skip the current iteration or end the loop using t
241
228
  for (user in users)
242
229
  @if (user.type == 1)
243
230
  @next
244
- @endif
231
+ @endIf
245
232
 
246
233
  <li>{{ user.name }}</li>
247
234
 
248
235
  @if (user.number == 5)
249
236
  @break
250
- @endif
251
- @endfor
237
+ @endIf
238
+ @endFor
252
239
  ```
253
240
 
254
241
  You may also include the continuation or break condition within the directive declaration:
255
242
 
256
243
  ```rblade
257
- @foreach (user in users)
244
+ @for (user in users)
258
245
  @next(user.type == 1)
259
246
 
260
- <li>{{ $user->name }}</li>
247
+ <li>{{ user.name }}</li>
261
248
 
262
249
  @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
250
+ @endFor
295
251
  ```
296
252
 
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>
253
+ <a name="conditional-classes-and-styles"></a>
317
254
  ### Conditional Classes & Styles
318
255
 
319
256
  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:
@@ -322,7 +259,7 @@ The `@class` directive conditionally adds CSS classes. The directive accepts a `
322
259
  @ruby
323
260
  isActive = false;
324
261
  hasError = true;
325
- @endruby
262
+ @endRuby
326
263
 
327
264
  <span @class({
328
265
  "p-4": true,
@@ -339,7 +276,7 @@ Likewise, the `@style` directive may be used to conditionally add inline CSS sty
339
276
  ```rblade
340
277
  @ruby
341
278
  isActive = true;
342
- @endruby
279
+ @endRuby
343
280
 
344
281
  <span @style({
345
282
  "background-color: red": true,
@@ -369,7 +306,7 @@ Likewise, the `@selected` directive may be used to indicate if a given select op
369
306
  <option value="{{ version }}" @selected(version == selectedVersion)>
370
307
  {{ version }}
371
308
  </option>
372
- @endeach
309
+ @endEach
373
310
  </select>
374
311
  ```
375
312
 
@@ -446,20 +383,7 @@ In some situations, it's useful to embed Ruby code into your views. You can use
446
383
  ```rblade
447
384
  @ruby
448
385
  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')
386
+ @endRuby
463
387
  ```
464
388
 
465
389
  <a name="comments"></a>
@@ -530,7 +454,7 @@ You can pass data to RBlade components using HTML attributes. Hard-coded strings
530
454
 
531
455
  #### Component Properties
532
456
 
533
- You can define a component's data properties using a `@props` statement at the top of the component. You can then reference these properties using local variables within the template:
457
+ You can define a component's data properties using a `@props` directive at the top of the component. You can then reference these properties using local variables within the template:
534
458
 
535
459
  ```rblade
536
460
  {{-- alert.rblade --}}
@@ -538,25 +462,18 @@ You can define a component's data properties using a `@props` statement at the t
538
462
  <div class="{{ type }}">{{ message }}</div>
539
463
  ```
540
464
 
541
- The `@props` statement 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:
465
+ 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
466
 
543
467
  ```rblade
544
468
  {{-- This will give an error because the alert component requires a message propery --}}
545
469
  <x-alert/>
546
470
  ```
547
471
 
548
- Kebab-case properties can be referenced using underscores in place of the dashes:
549
-
550
- ```rblade
551
- @props({"data-value": _required})
552
- <div>{{ data_value }}</div>
553
- ```
554
-
555
- Properties that contain other non-alphanumeric characters or are Ruby reserved keywords are not created as local variables. However, you can reference them via the `attributes` local variable:
472
+ All properties in the `@props` directive are automatically removed from `attributes`. Properties with names that aren't valid Ruby variable names or are Ruby reserved keywords are not created as local variables. However, you can reference them via the `attributes` local variable:
556
473
 
557
474
  ```rblade
558
- @props({"for": _required})
559
- <div>{{ attributes[:for] }}</div>
475
+ @props({"for": _required, "data-value": nil})
476
+ <div>{{ attributes[:for] }} {{ attributes[:'data-value'] }}</div>
560
477
  ```
561
478
 
562
479
  <a name="short-attribute-syntax"></a>
@@ -575,7 +492,7 @@ When passing attributes to components, you may also use a "short attribute" synt
575
492
  <a name="escaping-attribute-rendering"></a>
576
493
  #### Escaping Attribute Rendering
577
494
 
578
- 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:
495
+ 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 Ruby expression. For example, given the following component:
579
496
 
580
497
  ```rblade
581
498
  <x-button ::class="{ danger: isDeleting }">
@@ -600,8 +517,6 @@ We've already examined how to pass data attributes to a component; however, some
600
517
  <x-alert type="error" :message class="mt-4"/>
601
518
  ```
602
519
 
603
- **TODO remove from attributes bag using @props? Rename to attributes bag?**
604
-
605
520
  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:
606
521
 
607
522
  ```rblade
@@ -610,8 +525,8 @@ All of the attributes that are not part of the component's constructor will auto
610
525
  </div>
611
526
  ```
612
527
 
613
- <a name="default-merged-attributes"></a>
614
- #### Default / Merged Attributes
528
+ <a name="default-and-merged-attributes"></a>
529
+ #### Default & Merged Attributes
615
530
 
616
531
  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:
617
532
 
@@ -664,31 +579,22 @@ The rendered HTML of the `button` component in this example would be:
664
579
  </button>
665
580
  ```
666
581
 
667
- **Todo add prepends**
668
- 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:
669
-
670
- ```rblade
671
- <div {{ attributes.merge({"data-controller": attributes.prepends("profile-controller")}) }}>
672
- {{ slot }}
673
- </div>
674
- ```
675
-
676
582
  <a name="conditionally-merge-classes"></a>
677
583
  #### Conditionally Merge Classes
678
- **TODO this**
679
- 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:
584
+
585
+ 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:
680
586
 
681
587
  ```rblade
682
- <div {{ $attributes->class(['p-4', 'bg-red' => $hasError]) }}>
683
- {{ $message }}
588
+ <div {{ attributes.class({'p-4': true, 'bg-red': hasError}) }}>
589
+ {{ message }}
684
590
  </div>
685
591
  ```
686
592
 
687
593
  If you need to merge other attributes onto your component, you can chain the `merge` method onto the `class` method:
688
594
 
689
595
  ```rblade
690
- <button {{ $attributes->class(['p-4'])->merge(['type' => 'button']) }}>
691
- {{ $slot }}
596
+ <button {{ attributes.class({'bg-red': hasError}).merge({type: 'button'}) }}>
597
+ {{ slot }}
692
598
  </button>
693
599
  ```
694
600
 
@@ -698,62 +604,39 @@ If you need to merge other attributes onto your component, you can chain the `me
698
604
  <a name="filtering-attributes"></a>
699
605
  #### Retrieving and Filtering Attributes
700
606
 
701
- **Todo this**
607
+ 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.
702
608
 
703
- 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:
609
+ You may 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.
704
610
 
705
611
  ```rblade
706
- {{ $attributes->filter(fn (string $value, string $key) => $key == 'foo') }}
612
+ {{ attributes.filter { |k, v| k == 'foo'} }}
613
+ {{ attributes.slice :foo }}
707
614
  ```
708
615
 
709
- For convenience, you may use the `whereStartsWith` method to retrieve all attributes whose keys begin with a given string:
616
+ 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:
710
617
 
711
618
  ```rblade
712
- {{ $attributes->whereStartsWith('wire:model') }}
713
- ```
714
-
715
- Conversely, the `whereDoesntStartWith` method may be used to exclude all attributes whose keys begin with a given string:
716
-
717
- ```rblade
718
- {{ $attributes->whereDoesntStartWith('wire:model') }}
719
- ```
720
-
721
- Using the `first` method, you may render the first attribute in a given attribute bag:
722
-
723
- ```rblade
724
- {{ $attributes->whereStartsWith('wire:model')->first() }}
725
- ```
726
-
727
- 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:
728
-
729
- ```rblade
730
- @if ($attributes->has('class'))
619
+ @if (attributes.has?(:class))
731
620
  <div>Class attribute is present</div>
732
621
  @endif
733
622
  ```
734
623
 
735
- If an array is passed to the `has` method, the method will determine if all of the given attributes are present on the component:
624
+ If multiple parameters are passed to the `has?` method, the method will determine if all of the given attributes are present on the component:
736
625
 
737
626
  ```rblade
738
- @if ($attributes->has(['name', 'class']))
627
+ @if (attributes.has?('name', 'class'))
739
628
  <div>All of the attributes are present</div>
740
629
  @endif
741
630
  ```
742
631
 
743
- The `hasAny` method may be used to determine if any of the given attributes are present on the component:
632
+ The `has_any?` method may be used to determine if any of the given attributes are present on the component:
744
633
 
745
634
  ```rblade
746
- @if ($attributes->hasAny(['href', ':href', 'v-bind:href']))
635
+ @if (attributes.has_any?('href', ':href', 'v-bind:href'))
747
636
  <div>One of the attributes is present</div>
748
637
  @endif
749
638
  ```
750
639
 
751
- You may retrieve a specific attribute's value using the `get` method:
752
-
753
- ```rblade
754
- {{ $attributes->get('class') }}
755
- ```
756
-
757
640
  <a name="slots"></a>
758
641
  ### Slots
759
642
 
@@ -774,11 +657,11 @@ We may pass content to the `slot` by injecting content into the component:
774
657
  </x-alert>
775
658
  ```
776
659
 
777
- **TODO this**
778
660
  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:
779
661
 
780
662
  ```rblade
781
663
  {{-- /app/views/components/alert.rblade --}}
664
+ @props({title: _required})
782
665
  <span class="alert-title">{{ title }}</span>
783
666
  <div class="alert alert-danger">
784
667
  {{ slot }}
@@ -797,13 +680,13 @@ You may define the content of the named slot using the `x-slot` tag. Any content
797
680
  </x-alert>
798
681
  ```
799
682
 
800
- You may invoke a slot's `isEmpty` method to determine if the slot contains content:
683
+ The slot object extends the String interface, so you can invoke a slot's `empty?` method to determine if the slot contains content:
801
684
 
802
685
  ```rblade
803
686
  <span class="alert-title">{{ title }}</span>
804
687
 
805
688
  <div class="alert alert-danger">
806
- @if (slot.isEmpty)
689
+ @if (slot.empty?)
807
690
  This is default content if the slot is empty.
808
691
  @else
809
692
  {{ slot }}
@@ -811,29 +694,6 @@ You may invoke a slot's `isEmpty` method to determine if the slot contains conte
811
694
  </div>
812
695
  ```
813
696
 
814
- Additionally, the `hasActualContent` method may be used to determine if the slot contains any "actual" content that is not an HTML comment:
815
-
816
- ```rblade
817
- @if (slot.hasActualContent)
818
- The scope has non-comment content.
819
- @endif
820
- ```
821
-
822
- <a name="scoped-slots"></a>
823
- #### Scoped Slots
824
- **TODO can we do this easily?**
825
- 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:
826
-
827
- ```rblade
828
- <x-alert>
829
- <x-slot:title>
830
- {{ $component->formatAlert('Server Error') }}
831
- </x-slot>
832
-
833
- <strong>Whoops!</strong> Something went wrong!
834
- </x-alert>
835
- ```
836
-
837
697
  <a name="slot-attributes"></a>
838
698
  #### Slot Attributes
839
699
 
@@ -855,15 +715,14 @@ Like RBlade components, you may assign additional [attributes](#component-attrib
855
715
 
856
716
  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):
857
717
 
858
- **TODO allow class to contain a string**
859
718
  ```rblade
860
719
  @props({
861
720
  "heading": _required,
862
721
  "footer": _required,
863
722
  })
864
723
 
865
- <div {{ attributes.class(['border']) }}>
866
- <h1 {{ heading.attributes->class('text-lg': true) }}>
724
+ <div {{ attributes.class('border') }}>
725
+ <h1 {{ heading.attributes.class('text-lg') }}>
867
726
  {{ heading }}
868
727
  </h1>
869
728
 
@@ -875,16 +734,6 @@ To interact with slot attributes, you may access the `attributes` property of th
875
734
  </div>
876
735
  ```
877
736
 
878
- <a name="dynamic-components"></a>
879
- ### Dynamic Components
880
- **TODO add this**
881
- 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:
882
-
883
- ```rblade
884
- @ruby(componentName = "secondary-button")
885
- <x-dynamic-component :component="componentName" class="mt-4" />
886
- ```
887
-
888
737
  <a name="registering-additional-component-directories"></a>
889
738
  ### Registering Additional Component Directories
890
739
 
@@ -902,33 +751,6 @@ RBlade::ComponentStore.add_path(Rails.root.join("app", "views", "partials"), "pa
902
751
 
903
752
  If multiple directories are registered with the same namespace, RBlade will search for components in all the directories in the order they were registered.
904
753
 
905
- <a name="manually-registering-components"></a>
906
- ### Manually Registering Components
907
- **TODO would this be useful? It'd be useful for testing...**
908
- > [!WARNING]
909
- > 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.
910
-
911
- When writing components for your own application, components are automatically discovered within the `app/View/Components` directory and `resources/views/components` directory.
912
-
913
- 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:
914
-
915
- use Illuminate\Support\Facades\Blade;
916
- use VendorPackage\View\Components\AlertComponent;
917
-
918
- /**
919
- * Bootstrap your package's services.
920
- */
921
- public function boot(): void
922
- {
923
- Blade::component('package-alert', AlertComponent::class);
924
- }
925
-
926
- Once your component has been registered, it may be rendered using its tag alias:
927
-
928
- ```rblade
929
- <x-package-alert/>
930
- ```
931
-
932
754
  <a name="anonymous-index-components"></a>
933
755
  ### Index Components
934
756
 
@@ -956,64 +778,26 @@ However, when an `index.rblade` template exists in a directory, it will be rende
956
778
  /app/views/components/accordion/item.rblade
957
779
  ```
958
780
 
959
- <a name="accessing-parent-data"></a>
960
- ### Accessing Parent Data
961
- **TODO this? It might be complicated**
962
- 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>`:
963
-
964
- ```rblade
965
- <x-menu color="purple">
966
- <x-menu.item>...</x-menu.item>
967
- <x-menu.item>...</x-menu.item>
968
- </x-menu>
969
- ```
970
-
971
- The `<x-menu>` component may have an implementation like the following:
972
-
973
- ```rblade
974
- <!-- /resources/views/components/menu/index.rblade -->
781
+ <a name="forms"></a>
782
+ ## Forms
975
783
 
976
- @props(['color' => 'gray'])
784
+ ### Old Input
977
785
 
978
- <ul {{ $attributes->merge(['class' => 'bg-'.$color.'-200']) }}>
979
- {{ $slot }}
980
- </ul>
981
- ```
982
-
983
- 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:
786
+ 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:
984
787
 
985
788
  ```rblade
986
- <!-- /resources/views/components/menu/item.rblade -->
987
-
988
- @aware(['color' => 'gray'])
989
-
990
- <li {{ $attributes->merge(['class' => 'text-'.$color.'-800']) }}>
991
- {{ $slot }}
992
- </li>
789
+ <input type="text" name="email" value="@old('email', user.email)">
993
790
  ```
994
791
 
995
- > [!WARNING]
996
- > 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.
997
-
998
- <a name="forms"></a>
999
- ## Forms
1000
-
1001
- <a name="csrf-field"></a>
1002
- ### CSRF Field
1003
- **TODO I don't think we need this?**
1004
- 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:
792
+ 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`:
1005
793
 
1006
794
  ```rblade
1007
- <form method="POST" action="/profile">
1008
- @csrf
1009
-
1010
- ...
1011
- </form>
795
+ <input type="text" name="email" value="{{ params.fetch(:email, user.email) }}">
1012
796
  ```
1013
797
 
1014
798
  <a name="method-field"></a>
1015
799
  ### Method Field
1016
- **TODO add this**
800
+
1017
801
  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:
1018
802
 
1019
803
  ```rblade
@@ -1024,52 +808,8 @@ Since HTML forms can't make `PUT`, `PATCH`, or `DELETE` requests, you will need
1024
808
  </form>
1025
809
  ```
1026
810
 
1027
- <a name="validation-errors"></a>
1028
- ### Validation Errors
1029
- **TODO this**
1030
- 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:
1031
-
1032
- ```rblade
1033
- <!-- /resources/views/post/create.rblade -->
1034
-
1035
- <label for="title">Post Title</label>
1036
-
1037
- <input id="title"
1038
- type="text"
1039
- class="@error('title') is-invalid @enderror">
1040
-
1041
- @error('title')
1042
- <div class="alert alert-danger">{{ $message }}</div>
1043
- @enderror
1044
- ```
1045
-
1046
- 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:
1047
-
1048
- ```rblade
1049
- <!-- /resources/views/auth.rblade -->
1050
-
1051
- <label for="email">Email address</label>
1052
-
1053
- <input id="email"
1054
- type="email"
1055
- class="@error('email') is-invalid @else is-valid @enderror">
1056
- ```
1057
-
1058
- 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:
1059
-
1060
- ```rblade
1061
- <!-- /resources/views/auth.rblade -->
1062
-
1063
- <label for="email">Email address</label>
811
+ Alternatively, you can use the dedicated directives for each method: `@put`, `@patch`, or `@delete`.
1064
812
 
1065
- <input id="email"
1066
- type="email"
1067
- class="@error('email', 'login') is-invalid @enderror">
1068
-
1069
- @error('email', 'login')
1070
- <div class="alert alert-danger">{{ $message }}</div>
1071
- @enderror
1072
- ```
1073
813
 
1074
814
  <a name="stacks"></a>
1075
815
  ## Stacks
@@ -1079,11 +819,11 @@ RBlade allows you to push to named stacks which can be rendered elsewhere in ano
1079
819
  ```rblade
1080
820
  @push('scripts')
1081
821
  <script src="/example.js"></script>
1082
- @endpush
822
+ @endPush
1083
823
  ```
1084
824
 
1085
- If you would like to `@push` content if a given boolean expression evaluates to `true`, you may use the `@pushIf` directive:
1086
- **TODO add this**
825
+ If you would like to `@push` content if a given boolean expression evaluates to `true`, you may use the `@pushif` directive:
826
+
1087
827
  ```rblade
1088
828
  @pushIf(shouldPush, 'scripts')
1089
829
  <script src="/example.js"></script>
@@ -1105,153 +845,11 @@ If you would like to prepend content onto the beginning of a stack, you should u
1105
845
  ```rblade
1106
846
  @push('scripts')
1107
847
  This will be second...
1108
- @endpush
848
+ @endPush
1109
849
 
1110
850
  // Later...
1111
851
 
1112
852
  @prepend('scripts')
1113
853
  This will be first...
1114
- @endprepend
1115
- ```
1116
-
1117
- <a name="rendering-blade-fragments"></a>
1118
- ## Rendering Blade Fragments
1119
- **TODO this?**
1120
- 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:
1121
-
1122
- ```rblade
1123
- @fragment('user-list')
1124
- <ul>
1125
- @foreach ($users as $user)
1126
- <li>{{ $user->name }}</li>
1127
- @endforeach
1128
- </ul>
1129
- @endfragment
1130
- ```
1131
-
1132
- 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:
1133
-
1134
- ```php
1135
- return view('dashboard', ['users' => $users])->fragment('user-list');
1136
- ```
1137
-
1138
- 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:
1139
-
1140
- ```php
1141
- return view('dashboard', ['users' => $users])
1142
- ->fragmentIf($request->hasHeader('HX-Request'), 'user-list');
1143
- ```
1144
-
1145
- The `fragments` and `fragmentsIf` methods allow you to return multiple view fragments in the response. The fragments will be concatenated together:
1146
-
1147
- ```php
1148
- view('dashboard', ['users' => $users])
1149
- ->fragments(['user-list', 'comment-list']);
1150
-
1151
- view('dashboard', ['users' => $users])
1152
- ->fragmentsIf(
1153
- $request->hasHeader('HX-Request'),
1154
- ['user-list', 'comment-list']
1155
- );
1156
- ```
1157
-
1158
- <a name="extending-blade"></a>
1159
- ## Extending Blade
1160
- **TODO this?**
1161
- 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.
1162
-
1163
- The following example creates a `@datetime($var)` directive which formats a given `$var`, which should be an instance of `DateTime`:
1164
-
1165
- <?php
1166
-
1167
- namespace App\Providers;
1168
-
1169
- use Illuminate\Support\Facades\Blade;
1170
- use Illuminate\Support\ServiceProvider;
1171
-
1172
- class AppServiceProvider extends ServiceProvider
1173
- {
1174
- /**
1175
- * Register any application services.
1176
- */
1177
- public function register(): void
1178
- {
1179
- // ...
1180
- }
1181
-
1182
- /**
1183
- * Bootstrap any application services.
1184
- */
1185
- public function boot(): void
1186
- {
1187
- Blade::directive('datetime', function (string $expression) {
1188
- return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
1189
- });
1190
- }
1191
- }
1192
-
1193
- 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:
1194
-
1195
- <?php echo ($var)->format('m/d/Y H:i'); ?>
1196
-
1197
- > [!WARNING]
1198
- > 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.
1199
-
1200
- <a name="custom-echo-handlers"></a>
1201
- ### Custom Echo Handlers
1202
- **TODO this? Need to do something similar for attribute manager anyway**
1203
- 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.
1204
-
1205
- 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:
1206
-
1207
- use Illuminate\Support\Facades\Blade;
1208
- use Money\Money;
1209
-
1210
- /**
1211
- * Bootstrap any application services.
1212
- */
1213
- public function boot(): void
1214
- {
1215
- Blade::stringable(function (Money $money) {
1216
- return $money->formatTo('en_GB');
1217
- });
1218
- }
1219
-
1220
- Once your custom echo handler has been defined, you may simply echo the object in your Blade template:
1221
-
1222
- ```rblade
1223
- Cost: {{ $money }}
1224
- ```
1225
-
1226
- <a name="custom-if-statements"></a>
1227
- ### Custom If Statements
1228
- **TODO this**
1229
- 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`:
1230
-
1231
- use Illuminate\Support\Facades\Blade;
1232
-
1233
- /**
1234
- * Bootstrap any application services.
1235
- */
1236
- public function boot(): void
1237
- {
1238
- Blade::if('disk', function (string $value) {
1239
- return config('filesystems.default') === $value;
1240
- });
1241
- }
1242
-
1243
- Once the custom conditional has been defined, you can use it within your templates:
1244
-
1245
- ```rblade
1246
- @disk('local')
1247
- <!-- The application is using the local disk... -->
1248
- @elsedisk('s3')
1249
- <!-- The application is using the s3 disk... -->
1250
- @else
1251
- <!-- The application is using some other disk... -->
1252
- @enddisk
1253
-
1254
- @unlessdisk('local')
1255
- <!-- The application is not using the local disk... -->
1256
- @enddisk
854
+ @endPrepend
1257
855
  ```