Search code examples
javascriptphplaravelviteorchid

How to create a custom field with CodeMirror support in Laravel Orchid, and why JavaScript doesn't work in the layout?


I have a question about how to create my own custom field in Laravel (Orchid) with the support of CodeMirror library. I followed the documentation and one video on this topic and followed the following steps:

  1. Wrote a dashboard.js file.
  2. Integrated this file into the project using Vite.
  3. Created my own JavaScript controller.
  4. Wrote the logic in this controller.
  5. Created a Blade template for my field, specifying a data-controller attribute with an alias that is registered in dashboard.js.
  6. Created a custom PHP class for the field.

However, when I paste this field into some layout, it seems that JavaScript doesn't work and the output is only HTML. Can you please tell me how I can fix this problem?

this is my dashboard js

import MirrorTextArea from "./controllers/mirrorTextArea.js"

application.register("mirrorTextArea", MirrorTextArea);

this is my vite conf

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            input: [
                'resources/css/app.css',
                'resources/js/app.js',
                'resources/js/dashboard.js'
            ],
            refresh: true,
        }),
    ],
});

this is my blade

@component($typeForm, get_defined_vars())

    <div data-controller="mirrorTextArea"
        data-mirrorTextArea-mode="{{ $mode }}"
        data-mirrorTextArea-lineNumbers="{{ $line_numbers }}"
        data-mirrorTextArea-theme="{{ $theme }}">
        <textarea name="query" id="editor"></textarea>
    </div>


@endcomponent

this is my controller

import { EditorState } from '@codemirror/state';
import { EditorView, keymap } from '@codemirror/view';
import { defaultKeymap } from '@codemirror/commands';

export default class extends window.Controller {
    connect() {
        const options = {
            mode: this.data.get('mode'),
            lineNumbers: this.data.get('lineNumbers'),
            theme: this.data.get('theme'),
        };

        const textarea = this.element.querySelector('textarea'); // Find the textarea within the controller's element

        const state = EditorState.create({
            doc: textarea.value, // You can set the initial content from the textarea
        });

        const view = new EditorView({
            state,
            parent: textarea,
            handleDOMEvents: {
                focus: () => view.focus(),
            },
        });

        const viewDOM = view.dom;
        const viewState = view.state;
        view.dom = viewDOM;
        view.state = viewState.extend([keymap(defaultKeymap)]);

        view.focus();
    }
}

this is my field

<?php

namespace App\Orchid\Fields;

use Orchid\Screen\Field;

class MirrorTextArea extends Field
{
    /**
     * @var string
     */
    protected $view = 'fields.mirror-text-area';

    /**
     * @var string
     */
    protected string $type = 'text';

    /**
     * @var array
     */
    protected $attributes = [
        'mode' => "text/x-mysql",
        'line_numbers' => true,
        'theme' => "default",
        'extraKeys' => ["Ctrl-Space" => "autocomplete"]
    ];

    /**
     * Attributes available for particular tag
     *
     * @var string[]
     */
//    protected $inlineAttributes = [
//        'query'
//    ];
}

Solution

  • I found the answer, it turns out that in the new version of Laravel Orchid when building the front-end with the help of the vite builder it is necessary to write the mandatory path to the file "dashboard.js", which stores the initialization of all controllers. It should be written in the config/platform.php file.