rblade 0.4.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -1
- data/README.md +115 -517
- data/lib/rblade/compiler/compiles_components.rb +29 -11
- data/lib/rblade/compiler/compiles_echos.rb +4 -4
- data/lib/rblade/compiler/compiles_ruby.rb +1 -1
- data/lib/rblade/compiler/compiles_statements.rb +21 -13
- data/lib/rblade/compiler/statements/compiles_conditionals.rb +40 -0
- data/lib/rblade/compiler/statements/compiles_form.rb +48 -0
- data/lib/rblade/compiler/statements/compiles_props.rb +23 -4
- data/lib/rblade/compiler/statements/compiles_stacks.rb +39 -15
- data/lib/rblade/compiler/tokenizes_statements.rb +13 -2
- data/lib/rblade/compiler.rb +9 -0
- data/lib/rblade/component_store.rb +1 -1
- data/lib/rblade/helpers/attributes_manager.rb +37 -7
- data/lib/rblade/helpers/html_string.rb +4 -0
- data/lib/rblade/helpers/slot_manager.rb +31 -0
- data/lib/rblade/helpers/stack_manager.rb +4 -0
- data/lib/rblade/rails_template.rb +1 -0
- data/rblade.gemspec +1 -1
- metadata +9 -7
- data/TODO.md +0 -2
    
        data/README.md
    CHANGED
    
    | @@ -1,12 +1,41 @@ | |
| 1 1 | 
             
            # RBlade Templates
         | 
| 2 2 |  | 
| 3 | 
            -
            - [ | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
                 | 
| 7 | 
            -
                 | 
| 8 | 
            -
             
         | 
| 9 | 
            -
             | 
| 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 `{{ }}`  | 
| 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  | 
| 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  | 
| 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`, `@ | 
| 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 | 
            -
              @ | 
| 136 | 
            +
              @elseIf (records.count > 1)
         | 
| 108 137 | 
             
                  I have multiple records!
         | 
| 109 138 | 
             
              @else
         | 
| 110 139 | 
             
                  I don't have any records!
         | 
| 111 | 
            -
              @ | 
| 112 | 
            -
            @ | 
| 140 | 
            +
              @endIf
         | 
| 141 | 
            +
            @endUnless
         | 
| 113 142 | 
             
            ```
         | 
| 114 143 |  | 
| 115 | 
            -
            In addition to the conditional directives  | 
| 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 | 
            -
            @ | 
| 146 | 
            -
                //  | 
| 147 | 
            -
            @ | 
| 148 | 
            -
             | 
| 149 | 
            -
            @ | 
| 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 | 
            -
            @ | 
| 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 | 
            -
            @ | 
| 170 | 
            +
            @endEnv
         | 
| 171 171 |  | 
| 172 172 | 
             
            @env(['staging', 'production'])
         | 
| 173 173 | 
             
                // The application is running in "staging" or "production"...
         | 
| 174 | 
            -
            @ | 
| 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 `@ | 
| 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 | 
            -
            @ | 
| 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 | 
            -
            @ | 
| 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 | 
            -
            @ | 
| 206 | 
            +
            @endEach
         | 
| 220 207 |  | 
| 221 | 
            -
            @ | 
| 208 | 
            +
            @forElse (name in [])
         | 
| 222 209 | 
             
                <li>{{ name }}</li>
         | 
| 223 210 | 
             
            @empty
         | 
| 224 211 | 
             
                <p>No names</p>
         | 
| 225 | 
            -
            @ | 
| 212 | 
            +
            @endForElse
         | 
| 226 213 |  | 
| 227 | 
            -
            @ | 
| 214 | 
            +
            @eachElse (user in users)
         | 
| 228 215 | 
             
                <li>{{ user.name }}</li>
         | 
| 229 216 | 
             
            @empty
         | 
| 230 217 | 
             
                <p>No users</p>
         | 
| 231 | 
            -
            @ | 
| 218 | 
            +
            @endEachElse
         | 
| 232 219 |  | 
| 233 220 | 
             
            @while (true)
         | 
| 234 221 | 
             
                <p>I'm looping forever.</p>
         | 
| 235 | 
            -
            @ | 
| 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 | 
            -
                @ | 
| 231 | 
            +
                @endIf
         | 
| 245 232 |  | 
| 246 233 | 
             
                <li>{{ user.name }}</li>
         | 
| 247 234 |  | 
| 248 235 | 
             
                @if (user.number == 5)
         | 
| 249 236 | 
             
                    @break
         | 
| 250 | 
            -
                @ | 
| 251 | 
            -
            @ | 
| 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 | 
            -
            @ | 
| 244 | 
            +
            @for (user in users)
         | 
| 258 245 | 
             
                @next(user.type == 1)
         | 
| 259 246 |  | 
| 260 | 
            -
                <li>{{  | 
| 247 | 
            +
                <li>{{ user.name }}</li>
         | 
| 261 248 |  | 
| 262 249 | 
             
                @break(user.number == 5)
         | 
| 263 | 
            -
            @ | 
| 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 | 
            -
             | 
| 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 | 
            -
            @ | 
| 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 | 
            -
            @ | 
| 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 | 
            -
              @ | 
| 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 | 
            -
            @ | 
| 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`  | 
| 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`  | 
| 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 | 
            -
             | 
| 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  | 
| 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  | 
| 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 | 
            -
             | 
| 679 | 
            -
            Sometimes you may wish to merge classes if a given condition is `true`. You can accomplish this via the `class` method, which accepts  | 
| 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 {{  | 
| 683 | 
            -
                {{  | 
| 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 {{  | 
| 691 | 
            -
                {{  | 
| 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 | 
            -
             | 
| 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`  | 
| 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 | 
            -
            {{  | 
| 612 | 
            +
            {{ attributes.filter { |k, v| k == 'foo'} }}
         | 
| 613 | 
            +
            {{ attributes.slice :foo }}
         | 
| 707 614 | 
             
            ```
         | 
| 708 615 |  | 
| 709 | 
            -
             | 
| 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 | 
            -
             | 
| 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  | 
| 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 ( | 
| 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 ` | 
| 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 ( | 
| 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 | 
            -
             | 
| 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. | 
| 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( | 
| 866 | 
            -
                <h1 {{ heading.attributes | 
| 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=" | 
| 960 | 
            -
             | 
| 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 | 
            -
             | 
| 784 | 
            +
            ### Old Input
         | 
| 977 785 |  | 
| 978 | 
            -
             | 
| 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 | 
            -
             | 
| 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 | 
            -
             | 
| 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 | 
            -
            < | 
| 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 | 
            -
             | 
| 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 | 
            -
             | 
| 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 | 
            -
            @ | 
| 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 `@ | 
| 1086 | 
            -
             | 
| 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 | 
            -
            @ | 
| 848 | 
            +
            @endPush
         | 
| 1109 849 |  | 
| 1110 850 | 
             
            // Later...
         | 
| 1111 851 |  | 
| 1112 852 | 
             
            @prepend('scripts')
         | 
| 1113 853 | 
             
                This will be first...
         | 
| 1114 | 
            -
            @ | 
| 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 | 
             
            ```
         |