Giter Site home page Giter Site logo

spatie / laravel-blade-x Goto Github PK

View Code? Open in Web Editor NEW
530.0 11.0 41.0 912 KB

Use custom HTML components in your Blade views

Home Page: https://docs.spatie.be/laravel-blade-x

License: MIT License

PHP 90.80% HTML 9.20%
laravel php blade view rendering components

laravel-blade-x's Introduction

Notice

We have abandoned this package because Laravel 7 introduced native support for Blade-X style components.

Only use this package if you're on Laravel 6 or below.

When upgrading to Laravel 7 you should convert your Blade X components to native Laravel Blade components

Supercharged Blade components

Latest Version on Packagist GitHub Workflow Status Quality Score StyleCI Total Downloads

This package provides an easy way to render custom HTML components in your Blade views.

Here's an example. Instead of this

<h1>My view</h1>

@include('myAlert', ['type' => 'error', 'message' => $message])

you can write this:

<h1>My view</h1>

<my-alert type="error" :message="$message" />

You can place the content of that alert in a simple Blade view that needs to be registered before using the my-alert component.

{{-- resources/views/components/myAlert.blade.php --}}

<div class="{{ $type }}">
   {{ $message }}
</div>

Installation

You can install the package via Composer:

composer require spatie/laravel-blade-x

The package will automatically register itself.

Documentation

You'll find the documentation on https://docs.spatie.be/laravel-blade-x/v2/introduction.

Find yourself stuck using the package? Found a bug? Do you have general questions or suggestions for improving the media library? Feel free to create an issue on GitHub, we'll try to address it as soon as possible.

If you've found a bug regarding security please mail [email protected] instead of using the issue tracker.

Upgrading major versions

Please see UPGRADING for more information on how to upgrade from one major version to the other.

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Postcardware

You're free to use this package, but if it makes it to your production environment we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using.

Our address is: Spatie, Samberstraat 69D, 2060 Antwerp, Belgium.

We publish all received postcards on our company website.

Credits

Support us

Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects on our website.

Does your business depend on our contributions? Reach out and support us on Patreon. All pledges will be dedicated to allocating workforce on maintenance and new awesome stuff.

License

The MIT License (MIT). Please see License File for more information.

laravel-blade-x's People

Contributors

alexbowers avatar alexvanderbist avatar amaelftah avatar brendt avatar cashlion avatar connectkushal avatar dinhquochan avatar driesvints avatar emre-kaya avatar freekmurze avatar gjm avatar gummibeer avatar izshreyansh avatar jmlallier avatar lloople avatar markstaun avatar richardkeep avatar rubenvanassche avatar ryangjchandler avatar sebastiaanluca avatar sebastiandedeyne avatar snellingio avatar stayallive avatar telkins avatar vdbelt avatar willemvb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-blade-x's Issues

Ugly Livewire attributes

Sometimes in livewire attributes you have to combine static string with blade rendered text. Like this:

<button wire:click="edit({{ $language->id }})">edit</button>
<!-- produces this: -->
<button wire:click="edit(1)">edit</button>

If it was just the variable we could have used a :action attribute on our blade-x element, but now we have to write something like this:

<edit-button :action="'edit('.$language->id.')'"></edit-button>

I've red this issue #52 but double quotes inside single quotes is just as messy, and using slots for attributes doesn't seem like the best solution either. Can we do anything to make this a bit more strait forward?

Move away from the XmlSnapshotDriver for tests

For #112 we'd like to move away from the XmlSnapshotDriver to something that would support having attributes like this: ...$variable.

The phpunit-snapshot package also supports an HtmlSnapshotDriver that might be more flexible. Otherwise we might have to good old text-based snapshots.

DomCrawler instead of regular expressions?

Is there a reason you opted to use regular expressions to parse the XML rather than something like Symfony's DomCrawler library? Here's a basic gist of how the parsing might be implemented with a crawler:

https://gist.github.com/inxilpro/7717982cfaecd54da923277e29a114de

It just strikes me that relying on regular expressions to parse HTML is notoriously difficult to maintain—it seems like using an actual XML parsing library could make a lot of sense. Another upside is that you can remove the need for the :attribute syntax, and let everything work as "regular" blade/HTML.

<alert level="{{ $alert_level }}">{{ $alert_message }}</alert>

Effectively translates to:

@component('alert')
  @slot('level'){{ $alert_level }}@endslot
  {{ $alert_message }}
@endcomponent

If you're interested in pursuing this, I'd be willing to work on a PR. Just wanted to try a proof-of-concept first.

Issue when both spatie/laravel-blade-x and thepinecode/blade-filters are used

Hi there,

I'm having an issue where if I'm using both spatie/laravel-blade-x and thepinecode/blade-filters.

php artisan commands stop working.

I'm unsure which package is truly the cause here, but hopefully someone might know what might be up.

Here is the log/stacktrace:
[2019-05-24 10:18:20] local.ERROR: Could not register component 'context' because view 'bladex::context' was not found. {"exception":"[object] (Spatie\\BladeX\\Exceptions\\CouldNotRegisterComponent(code: 0): Could not register component 'context' because view 'bladex::context' was not found. at /home/michael/Documents/Projects/xxx/vendor/spatie/laravel-blade-x/src/Exceptions/CouldNotRegisterComponent.php:12) [stacktrace] #0 /home/michael/Documents/Projects/xxx/vendor/spatie/laravel-blade-x/src/BladeX.php(53): Spatie\\BladeX\\Exceptions\\CouldNotRegisterComponent::viewNotFound('bladex::context', 'context') #1 /home/michael/Documents/Projects/xxx/vendor/spatie/laravel-blade-x/src/BladeXServiceProvider.php(27): Spatie\\BladeX\\BladeX->component('bladex::context', 'context') #2 [internal function]: Spatie\\BladeX\\BladeXServiceProvider->boot() #3 /home/michael/Documents/Projects/xxx/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(32): call_user_func_array(Array, Array) #4 /home/michael/Documents/Projects/xxx/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(90): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}() #5 /home/michael/Documents/Projects/xxx/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(34): Illuminate\\Container\\BoundMethod::callBoundMethod(Object(Illuminate\\Foundation\\Application), Array, Object(Closure)) #6 /home/michael/Documents/Projects/xxx/vendor/laravel/framework/src/Illuminate/Container/Container.php(576): Illuminate\\Container\\BoundMethod::call(Object(Illuminate\\Foundation\\Application), Array, Array, NULL) #7 /home/michael/Documents/Projects/xxx/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(817): Illuminate\\Container\\Container->call(Array) #8 /home/michael/Documents/Projects/xxx/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(800): Illuminate\\Foundation\\Application->bootProvider(Object(Spatie\\BladeX\\BladeXServiceProvider)) #9 [internal function]: Illuminate\\Foundation\\Application->Illuminate\\Foundation\\{closure}(Object(Spatie\\BladeX\\BladeXServiceProvider), 29) #10 /home/michael/Documents/Projects/xxx/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(801): array_walk(Array, Object(Closure)) #11 /home/michael/Documents/Projects/xxx/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/BootProviders.php(17): Illuminate\\Foundation\\Application->boot() #12 /home/michael/Documents/Projects/xxx/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(210): Illuminate\\Foundation\\Bootstrap\\BootProviders->bootstrap(Object(Illuminate\\Foundation\\Application)) #13 /home/michael/Documents/Projects/xxx/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(322): Illuminate\\Foundation\\Application->bootstrapWith(Array) #14 /home/michael/Documents/Projects/xxx/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(131): Illuminate\\Foundation\\Console\\Kernel->bootstrap() #15 /home/michael/Documents/Projects/xxx/artisan(37): Illuminate\\Foundation\\Console\\Kernel->handle(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput)) #16 {main} "}

Order of BladeX Component instantiation matters

So I have I component within a component to deal with breadcrumbs:

<tw-breadcrumb-group>
    <tw-breadcrumb href="#">
        Link 1
    </tw-breadcrumb>
    <tw-breadcrumb href="#">
        Link 2
    </tw-breadcrumb>
    <tw-breadcrumb href="#" active="true">
        Link 3
    </tw-breadcrumb>
</tw-breadcrumb-group>

In my AppServiceProvider, I have the following BladeX Components defined:

public function boot()
{
    [...]

    BladeX::component('_components.breadcrumb', 'tw-breadcrumb');
    BladeX::component('_components.breadcrumbgroup', 'tw-breadcrumb-group');

This errors!

/vendor/spatie/laravel-blade-x/src/Exceptions/CouldNotParseBladeXComponent.php

Could not parse a usage of BladeX component `tw-breadcrumb` that uses the `_components/breadcrumb` view because of invalid html. Html found: `<tw-breadcrumb-group></tw-breadcrumb>

What is odd is that if I reverse them in the boot method, it works without errors.

So this works!

public function boot()
{
    [...]

    BladeX::component('_components.breadcrumbgroup', 'tw-breadcrumb-group');
    BladeX::component('_components.breadcrumb', 'tw-breadcrumb');

For right this second, I've just fixed the ordering in my app. But it would be nice if the ordering didn't error. Especially since the invalid html error is not clear at all.

Does this get confusing for larger applications using Vue?

First off, love your work and packages!

I was just wondering if you have a large project with a large amount of both BladeX and Vue components, does mixing them get confusing? What I mean is how do you know whether the component you're looking at in your templates is a BladeX component or a Vue component? If you need to modify it you'd have to go searching your service provider or looking through all your vue assets.

Assign slot directly to component

I would be really handy to be able to assign slots directly to components instead of using the <slot name="whatever"> syntax.

It could look like <component #whatever> or <component x-slot="whatever">.

Example behaviour

Blade-X template:

<parent-component>
    <sub-component-1 #someSlot />
    <sub-component-2 x-slot="anotherSlot">
        Hello World!
    </sub-component-2>
</parent-component>

Compiled Blade template:

@component('components.parent-component')
    @slot('someSlot')
        @component('components.sub-component-1')@endcomponent
    @endslot

    @slot('anotherSlot')
        @component('components.sub-component-2')
            Hello World!
        @endcomponent
    @endslot
@endcomponent

Allow additional attributes to be passed to component on registration

Currently it seems very tedious to create components that are all based on a single generic and determine their behaviour based on a handful of properties.

I would propose something like below code as a solution to that issue. I've used inputs as an example as that is where I noticed the most duplication in a medium sized application.

Old

// Provider
BladeX::component('components.form.input.date')->tag('input-date');
BladeX::component('components.form.input.date-time')->tag('input-date-time');
BladeX::component('components.form.input.email')->tag('input-email');
BladeX::component('components.form.input.number')->tag('input-number');
BladeX::component('components.form.input.text')->tag('input-text');
BladeX::component('components.form.input.password')->tag('input-password');
BladeX::component('components.form.input.textarea')->tag('input-textarea');

// Generic Input
<input type="{{ $type }}" />

// Components
@include('components.form.input._input', ['type' => 'text'])
@include('components.form.input._input', ['type' => 'email'])
@include('components.form.input._input', ['type' => 'password'])
...

New

BladeX::component('components.form.input', 'input-password', ['type' => "password"])
BladeX::component('components.form.input', 'input-date', ['type' => "date"]);
BladeX::component('components.form.input', 'input-date-time', ['type' => "datetime-local"]);
BladeX::component('components.form.input', 'input-email', ['type' => "email"]);
BladeX::component('components.form.input', 'input-number', ['type' => "number"]);
BladeX::component('components.form.input', 'input-text', ['type' => "text"]);
BladeX::component('components.form.input', 'input-password', ['type' => "password"]);
BladeX::component('components.form.input', 'input-textarea', ['type' => "textarea"]);

Pulling out model logic out of blade-x component

This is my date-field component. If you notice inside of the value attribute of the input element it has a value that is situational to the form that it is on. What can I do so that I can pull that logic out so that the value is determined out of the component?

<field-label :for="$name" :label="$label ?? ''" />

<div class="kt-input-icon kt-input-icon--right">
    <input 
        type="text" 
        class="form-control @error($name) is-invalid @enderror"
        name="{{ $name }}" 
        placeholder="Enter {{ $label }}"
        value="{{ old($name, optional($employee->employment->started_at ?? null)->toDateTimeString()) }}"
        data-datetimepicker 
        data-input
    >
    <span class="kt-input-icon__icon kt-input-icon__icon--right">
        <span><i class="flaticon-calendar-with-a-clock-time-tools"></i></span>
    </span>
    @error($name)
        <form-error name="{{ $name }}" />
    @enderror
</div>

Let attributes cascade

I didn't find an issue about this so thought to open one about it. This is more of a question than a feature request I guess.

From Blade I'm used that variables which are passed to includes are cascaded down into includes inside includes. With Blade components you need to explicitly set anything you want to cascade through.

For example:

login.blade.php

<x-checkbox-field field="remember" :label="__('Remember Me')" />

checkboxField.blade.php

<div>
    <input type="checkbox" name="{{ $field }}" id="{{ $field }}" {{ old($field) ? 'checked' : '' }}>

    <x-label :field="$field" :label="$label" />
    <x-error :field="$field" />
</div>

label.blade.php

<label for="{{ $field }}">
    {{ $label }}
</label>

My question: why do I need to define <x-label :field="$field" :label="$label" /> instead of just <x-label />? I'm okay with doing it explicitly but was just wondering about the difference in behavior from the @include tag.

Multiple version of same component possible?

I’ve not dug into BladeX yet but is it possible to have multiple ways to render the same component? For instance parsing the template as normal, or when logged in as an admin? It would be cool to use this in a CMS where editable controls can be added in some states.

Restructure tests

  • directories per feature
  • assert against both Blade output and BladeX output

Add empty item in select

I am using ViewModels for populate a select input.
I would like to add an empty options like "Select item" as first options.

How to archive this?

Thanks

Component inside component throws `View [] not found` error

First of all - thanks for such a great package!

My issue is as follows - can one component be called from another component ?

I've registered several components in ServiceProvider with

BladeX::component('components.*');
BladeX::prefix('component');

everything works like charm but after calling one component from another, eg in <component-advert-preview/> from resources/views/components/advert-preview.blade.php I'm calling

<component-button type="primary" @isset($href) href="{{$href}}" @endisset>{{$cta}}</component-button>

from resources/views/components/button.blade.php which throws and error View [] not found

I'm assuming that issue is related to nesting one component into another which might not be supported.

Not registering correctly if used in a package

I have a package (PageBuilder) that I want to use BladeX in but components aren't registering correctly. I have added the following into my package's ServiceProvider...

        BladeX::component([
            'page-builder::components.blocks.*',
            'page-builder::components.headers.*',
            'page-builder::components.widgets.myText'
         ]);

         BladeX::prefix('x');

The components in the blocks and headers directories are not registering even though I have "*" in the registration paths. The myText component that I register directly by name is registering but not with the prefix (x). It displays correct with a tag but not with as I would expect.

Load components from vendor not work

I am trying to load a components inside a vendor like:

    BladeX::component('core::components.bladex.select')->viewModel(SelectViewModel::class);

But it not working, appear message:

Could not register component `` because view core::components.bladex.select was not found.

If I check if(view()->exists('core::components.bladex.select')) then it return true.

Any idea what I am missing?

Thanks

SelectViewModel with multiple options

How to make selected multiple option with SelectViewModel?

I am currently using the one of examples, and I change isSelected() method like below, but not work:

    public function isSelected(string $optionName): bool
    {
        if(is_string($this->selected))
            return $optionName === $this->selected;
        else
            return array_key_exists($optionName, $this->selected);
    }

Component hierarchy and tag naming

I have some components in a structure under views:

frontend/components/item.blade.php
frontend/components/widgets/search.blade.php
frontend/components/modals/save.blade.php

If I register all these, I am able to use each component as a top-level tag:

<x-item id="25">...</x-item>
<x-search section="Events"></x-search>
<x-save></x-save>  

In the template files, it isn't clear upfront if I'm using a widget, a modal or a regular partial. Is there any way to overcome this problem without naming the component something like searchWidget.blade.php? I am wondering if it is a good idea to indicate a "root" components path and use folder names below that path as prefixes, so we get...

<x-item id="25">...</x-item>
<x-widgets-search section="Events"></x-widgets-search>
<x-modals-save></x-widgets-save>  

Attribute spread operator support

The idea I have is something like ...attr="$el" as a replacement for :class="$el['class']" :src="$el['src']". So like the opposite of compact(). Or even only ...$el because I would say that the spreaded attribute name would be ignored anyway.

<x-img ...$img />
// vs
<x-img :src="$img['src']" :alt="$img['alt']" :class="$img['class']" />

The $img variable should be an array or arrayable but has to have strings, which should get kebabed, as keys.

Attribute Inheritance

It would be nice to let attributes passed into the component be able to automatically be inherited in the root element of the component.

Say we have a component x-button defined with BladeX:

<button>{{ $slot }}</button>

We may use it like so:

<x-button class="btn btn-primary">Click me!</button>

However, since we didn't explicitly declare how the "class" variable should be used within the component, it isn't used at all in the final rendered HTML.

Unfortunately, this makes the package feel very unnatural to write HTML with, or even coming from something like Vue which has this concept of "non-prop attributes" that supports this exact behaviour - as BladeX would force you to explicitly declare every possible attribute that could go on an element, just to make using the component itself feel like HTML.

I'm not entirely sure how this could be implemented into BladeX since it doesn't keep its own list of props used in the current component as Vue does. My initial idea would be to use something like get_defined_vars() in scope and converting the appropriate values to a string of HTML attributes that can be output on the root element (or even a sub-element manually using a directive?)

$variablesInScope = get_defined_vars();
$except = ['__path', '__data', '__env', 'obLevel', 'app', 'errors', 'slot'];
$attributes = array_filter($variablesInScope, fn ($key) => !in_array($key, $except), ARRAY_FILTER_USE_KEY);

// Convert $attributes array to a string of HTML attributes?

Unfortunately, this approach means everything will be added as an attribute, which probably isn't the intention of the developer. I'm not sure if there would be any decent way to filter it down any further.

Just opening this issue as a discussion - does anyone have any ideas for a better approach? Is this even behaviour you would want to be available in BladeX?

View not found error when prop is empty

Ran into this today:

<tw-form-input name="name" placeholder=""></tw-form-input>

Throws the following error:
ErrorException (E_ERROR) View [] not found.

However:

<tw-form-input name="name" placeholder="Your name"></tw-form-input>

Works totally fine.

Will investigate and create a PR with tests later this weekend if I have time

Error in registration

My rierctory structure is resources/views/components/delete.blade.php

when I try to register component in boot method

    public function boot()
    {
       BladeX::component('delete', 'components.delete');
    }

its giving me following error

Could not register component `components.delete` because view `delete` was not found. 

but I can confirm that the view delete.blade.php exists

How to use BladeX outside of Laravel

First off, I'm excited to use this package on pretty much every Laravel project, moving forward!

However, I also would like to use this in a Wordpress site. I'm using a fork of the latest Sage/Roots theme, which incorporates Blade into the Wordpress template files. It also includes a package to give you "Controllers", which gives Wordpress a more MVC feel.

I've tried to register this package multiple ways within the theme, but I keep getting a few errors that I don't know how to resolve.

First: Is it even possible to use this package without Laravel?

Second: Here's a couple of the errors I get:

$bladex = \Spatie\BladeX\BladeX();

$bladex->component('components.*');

Fatal error: Uncaught RuntimeException: A facade root has not been set.

And

use Spatie\BladeX\BladeX;

BladeX::component('components.*');

Fatal error: Uncaught Error: Using $this when not in object context in

Any help would be greatly appreciated!

Can't get it work with Laravel modules

I'm trying to use laravel-blade-x with "Laravel modules" package but can't get it to work.

My app service provider boot method looks like this:

public function register()
    {
        $this->loadViewsFrom(base_path().'/Modules/MyModule/Resources/views','mymodule');

        \BladeX::component([
            'mymodule::components.*'          
        ]);
    }

I get no error message, so it seems like it registers the components.

In the view I use this:

<div class="col-lg-9">
     <alert type="error" message="test" />
</div>

Unfortunately, the code is left untouched after access and I see this in the rendered HTML file.

<alert type="error" message="test"></alert>

I've tried php artisan view:clear . Didn't help.

When I place the component to regular laravel views folder it works OK.

Quirk custom component spaces

Will update this issue once I dig into potential fixes.

I have a custom component, avatar, which I call like so:

                @avatar(['size' => 'large'])
                SS
                @endavatar

This was nice and easy to convert to a BladeX component:

                <tw-avatar size="large">
                    SS
                </tw-avatar>

The problem seems to be when you do not have any spaces in the slot:

<tw-avatar size="large">SS</tw-avatar>

The reason this fails is because @endcomponent is right up against the slot, which returns SS@endcomponent. This is how blade currently works.

So the following works:

@avatar(['size' => 'large']) SS @endavatar
<tw-avatar size="large">SS </tw-avatar>

Note the spaces before & after on the component, and after on the BladeX.

I'm thinking that we could just add a space to the BladeX output for slots. Although I'm not 100% sure of the ramifications yet. I'd like to be able to not add a space, just like html.

Better support for packages

I want to register a set of components from a ui package:

BladeX::component('ui::components.*')

As an example, if I have a panel component it will be registered with the ui::panel tag. AFAIK looking at the code, this a feature to prevent name clash, correct?

Would be great if we could have the possibility to omit the package prefix or, at least, convert it to kebab case (ui-panel).

I know I can specify the tag for each component but that would force me to register each one manually.

Maybe something like:

BladeX::component('ui::components.*')->prefix('ui');  // would prefix with 'ui-'
BladeX::component('ui::components.*')->noPrefix();  // place components in "global" namespace

Not Compatible with Laravel 6.^

Can you update the code to work with latest Laravel version.
I can`t get it to install in my project.

The package looks fantastic and I want to use in my next project. :)

Component replaces wrong HTML tag when both start with the same name

In a view, we're using some simple Vue components:

<budget-input></budget-input>
<budget-date-range-picker ></budget-date-range-picker>

In our BladeServiceProvider, we register a completely different BladeX component:

BladeX::component('components.content.Budget')->tag('budget')->viewModel(BudgetViewModel::class);

This results in an error, because BladeX tries to replace all Vue components that start with the budget tag/name/string:

View [] not found.

Similar to #36 and #59.

A quick and easy solution would be to prefix BladeX components, but IMO it remains a bug nonetheless. I'd be happy to submit a PR if pointed in the right direction!


My RegEx voodoo skills are inadequate to add the correct check 😄 Need to prevent the rest of the tag name from being tagged as an attribute in the regex pattern:

$pattern = "/<\s*{$prefix}{$component->tag}(?<attributes>(?:\s+[\w\-:]+(=(?:\\\"[^\\\"]*\\\"|\'[^\']*\'|[^\'\\\"=<>]+))?)*\s*)(?<![\/=\-])>/";

Problem with Vue...?

Hello,

I'm using Vue and, as such, I'm also employing the prefix per the docs. Nevertheless, I get the following warning when I hit my page:

[Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.

I'm a little weak on Vue but it's been working fine before beginning to use this package. I'm wondering if I'm missing something that I need to do with either Vue or BladeX...or both.

Any suggestions...?

Thanks. :-)

Multiple Prefixes

Hi there, Nice stuff 🙌

I was thinking it would be good if it was possible to have multiple prefixes for multiple purposed components. like layout-... , partial-..., component-... and more ..

If you think use-case is logical, i can make a PR and adding an optional second parameter to component and components methods as prefix.

Recommended spot to put View Models?

More of a question than an issue.

What the is the best practice around namespacing / folder structure for view models?

Something like App/ViewModels or App/Http/ViewModels?

What about ones specifically for components? App/.../ViewModels/BladeX or App/.../ViewModels/Components?

Just looking for some opinions, as there is no right or wrong answer.

Allow to register subdirectories

At the moment the * wildcard only resolves one level. So I would have to have all components in a single component folder or register every single subfolder by its own.

It would be great to support a multi level wildcard. Something like components.** or the also known components.**.*.

This would allow more structure in larger component collections without the need to add every folder to the service provider.

Issue with SelectFieldViewModel

I am trying to create this example:
https://docs.spatie.be/laravel-blade-x/v2/advanced-usage/transforming-data-with-view-models

For this code:

<option {!!  $isSelected($value) ? 'selected="selected"' : '' !!} name="{{ $value }}">{{ $label }}</option>

I am getting $isSelected is undefined.

I fixed checking directly the $value with $selected in this way:

<option {!! $value === $selected ? 'selected="selected"' : '' !!} name="{{ $value }}">{{ $label }}</option>

However, I would like to know why function isSelected of SelectFieldViewModel is not found.

Thanks

Livewire Support

Consider an app with an input-text blade component like so:

<div>
    <label>...</label>
    <input name="{{ $name }}" type="text">
</div>

You would register this component with BladeX and use it like so:

<input-text name="email">

HOWEVER, if you are using Livewire, you might want to add the wire:model attribute to the input element:

<input-text name="email" wire:model="email">

Unfortunately, BladeX's parser interprets this as an attribute named model that is bound with a PHP expression (because of the colon).

I pulled the project down to add a test for this case, but discovered it's harder than just updating the parser.

You would need a way to make wire:model into a variable $wireModel or something?

Anyhow, I figured I'd open an issue to get the conversation going. It might be an issue outside the scope of this package. But I think this package can pair nicely with Livewire, and this is kind of a deal-breaker.

@driesvints brought this issue to my attention.

Thoughts appreciated. Thanks!

Same component - Different ViewModel

Hi,

I am planning to define components for a small dashboard. Wondering if I could reuse some markup and provide different view model on the fly. e.g.

// dashboard.blade.php
<x-value-widget view-model="App\ViewModels\FooViewModel::class"></x-value-widget>
<x-value-widget view-model="App\ViewModels\BarViewModel::class"></x-value-widget>

// value-widget.blade.php
<div class="card p-3 bg-primary">
    <div class="display-3">{{ $value }}</div> 
    <div class="display-3">{{ $meaning }}</div> 
</div>

// FooViewModel
class FooViewModel extends ViewModel {
    public function __construct() {
        $this->value = Foo::count();
        $this->meaning = 'New foos this week';
    }
}

// BarViewModel
class BarViewModel extends ViewModel {
    public function __construct() {
        $this->value = Bar::whereStatus('open')->count();
        $this->meaning = 'Opened bars';
    }
}

Obviously benefit starts to show when component markup gets a little hairier.

Improve component registration

It should be possible to do this:

BladeX::component('admin.components.text-field');
BladeX::component('admin.components.*');
BladeX::component('bladex::components.text-field');
BladeX::component('bladex::components.*');

Dealing with checkbox/radio groups

Hi there,

I'm still new to Laravel and the Blade X package, though i can't for the life of me figure out how to structure my custom checkbox group field and the view model to deal with check boxes that are checked. If someone can provide me with some assistance that would be great.

Access variable :model

If I create a component like:

<my-form :model="$user" method="post" :action="route('update')">

....

</my-form>

Then how I can access variable ":model" ? It not work if I use $model->...

Should it bind automatically to form's input name? Because if yes then not work correctly in my case.

Attribute interpolation

Hi, is there a way to do attribute interpolation?

Assume this simple component:

{{-- components/myComponent.blade.php --}}
<div>{{ $attribute }}</div>

I want to do this:

<my-component attribute="This should be {{ $interpolated }}"></my-component>

Currently the output on screen is:

This should be <?php echo e($interpolated); ?>

I didn't look into the code, but I guess the compiler is escaping the output before generating the blade file.

As a workaround, I am doing this:

<my-component :attribute="'This should be ' . $interpolated"></my-component>

Laravel Livewire validation message not showing in form partial

I am looking to implement Blade X form partials in a Livewire setup, combined with form validation.

With this, I have setup a regular text-input like this:

@if( $label )
    <label class="block mb-4" for="{{ $name }}">{{ $label }}</label>
@endif

<input
    class="block appearance-none w-full bg-white border border-gray-400 hover:border-gray-500 px-4 py-2 pr-8 rounded shadow leading-tight focus:outline-none focus:shadow-outline @error($name) border-red-600 @enderror"
    type="text"
    name="{{ $name }}"
    id="{{ $name }}"
    placeholder="{{ $placeholder ?? $label }}"
    value="{{ $value ?? old($name) }}"
    {{ isset($required) && (true === $required) ? 'required' : '' }}
    {{ isset($ref) ? 'ref=' . $ref : '' }}
    {{ isset($autocomplete) ? 'autocomplete=' . $autocomplete : '' }}
    {{ isset($autofocus) ? 'autofocus=' . $autofocus : '' }}
    {{ collect($wire)->map(function ($value, $attribute) { return "wire:$attribute=$value"; })->implode(' ') }}
>

@error($name)
<div class="text-red-600 mt-2" role="alert">{{ $message }}</div>
@enderror

And have called it like this in a Livewire blade component:

<x-input-text
    :label="trans('forms.labels.price')"
    name="price"
    placeholder="price"
    wire:model="price"
/>

Also, I have set the following validation in place in the Livewire component class:

$this->validate(
   ['price' => 'required|integer']
);

However, when I add a non-integer value I see that the form indeed isn't submitting succesfully, but I can't see the validation message. Any idea how I can fix this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.