adminizer

Back

Controls

Overview

AbstractControls is an abstract base class that defines the common interface for control components in the Adminizer system. It provides the foundational structure that all specific control types must implement.

Type Definitions

ControlType

type ControlType = 'wysiwyg' | 'jsonEditor' | 'geoJson' | 'markdown' | 'table' | 'codeEditor'

Defines the available types of controls that can be implemented.

Path

interface Path {
    jsPath: {
        dev: string
        production: string
    },
    cssPath: string
}

Defines the path structure for JavaScript and CSS assets, with separate paths for development and production environments.

Config

type Config = Record<string, string | string[] | object | number | boolean>

Represents a configuration object that can contain various types of values.

AbstractControls Class

Properties

name

public abstract readonly name: string

The unique name identifier for the control (abstract, must be implemented).

type

public abstract readonly type: ControlType

The type of the control (abstract, must be implemented).

path

public abstract readonly path: Path

The asset paths for the control (abstract, must be implemented).

config

public abstract readonly config: Config

The configuration object for the control (abstract, must be implemented).

routPrefix

public readonly routPrefix: string

The route prefix inherited from the Adminizer instance.

Constructor

protected constructor(adminizer: Adminizer)

Initializes the control with a reference to the Adminizer instance and sets the route prefix.

Parameters:

Returns: The configuration object or undefined getJsPath()

public abstract getJsPath(): string | undefined

Gets the appropriate JavaScript path based on environment (abstract, must be implemented).

Returns: The JavaScript path string or undefined getCssPath()

public abstract getCssPath(): string | undefined

Gets the CSS path (abstract, must be implemented).

Returns: The CSS path string or undefined getName()

public abstract getName(): string

Gets the control name (abstract, must be implemented).

Returns: The control name string

Usage

To create a custom control, extend this abstract class and implement all abstract members:

class MyCustomControl extends AbstractControls {
    public readonly name = "my-control";
    public readonly type: ControlType = 'wysiwyg';
    public readonly path = {
        jsPath: { dev: '/dev/path.js', production: '/prod/path.js' },
        cssPath: '/styles.css'
    };
    public readonly config = { /* ... */ };

    constructor(adminizer: Adminizer) {
        super(adminizer);
    }

    // Implement all abstract methods...
}

ControlsHandler

Overview

The ControlsHandler class provides a centralized management system for control components in the Adminizer framework. It organizes controls by type and name, allowing for easy retrieval, addition, and removal of controls.

Class Structure

Properties

controls

private controls = new Map<ControlType, Map<string, AbstractControls>>()

Internal storage structure that maintains controls in a nested Map:

Adds a new control to the handler.

Parameters:

Example:

handler.add(new MyControl(adminizer));

get<T extends ControlType>(type: T, name: string): AbstractControls | undefined

Retrieves a specific control by its type and name.

Parameters:

Returns: The control instance or undefined if not found

Example:

const editor = handler.get('wysiwyg', 'main-editor');

getByType<T extends ControlType>(type: T): AbstractControls[]

Retrieves all controls of a specific type.

Parameters:

Returns: An array of control instances (empty array if none found)

Example:

const allEditors = handler.getByType('wysiwyg');

remove(type: ControlType, name: string): boolean

Removes a control from the handler.

Parameters:

Returns: true if the control was found and removed, false otherwise

Example:

const wasRemoved = handler.remove('wysiwyg', 'old-editor');

getAll(): Record<ControlType, AbstractControls[]>

Retrieves all controls grouped by type.

Returns: An object where keys are control types and values are arrays of controls

Example:

const allControls = handler.getAll();
// Returns: { wysiwyg: [...], markdown: [...], ... }

collectAndGenerateStyleLinks(): string[] Collects all CSS paths from registered controls.

Returns: An array of CSS paths

Example:

const stylesheets = handler.collectAndGenerateStyleLinks();

Usage Example

// Initialize handler
const handler = new ControlsHandler();

// Add controls
handler.add(new WysiwygControl(adminizer));
handler.add(new MarkdownControl(adminizer));

// Get controls
const mainEditor = handler.get('wysiwyg', 'main-editor');
const allMarkdown = handler.getByType('markdown');

// Get all stylesheets
const styles = handler.collectAndGenerateStyleLinks();

Redefining basic controls

Create a new class, for example:

export class ReactQuill extends AbstractControls {
    readonly name: string = 'react-quill';
    readonly type: ControlType = 'wysiwyg';
    readonly path: Path = {
        cssPath: `${this.routPrefix}/assets/modules/react-quill-editor.css`,
        jsPath:
            {
                dev: "/modules/controls/wysiwyg/react-quill-editor.tsx",
                production: `${this.routPrefix}/assets/modules/react-quill-editor.es.js`
            }
    }
    readonly config: Config = {};

    getConfig(): Config {
        return this.config;
    }

    constructor(adminizer: Adminizer) {
        super(adminizer);
    }

    getJsPath(): string {
        if (process.env.VITE_ENV === 'dev') {
            return this.path.jsPath.dev;
        } else {
            return this.path.jsPath.production
        }
    }

    getCssPath(): string {
        return this.path.cssPath
    }

    getName(): string {
        return this.name
    }
}

Then add it via ControlsHandler, like this:

// add custom control wysiwyg
adminizer.emitter.on('adminizer:loaded', () => {
    adminizer.controlsHandler.add(new ReactQuill(adminizer))
})

After that, you can use in the configuration:

 editor: {
    title: 'Editor',
    type: 'wysiwyg',
    options: {
        name: 'react-quill',
    }
}

See the implementation example here fixture & here modules/controls/wysiwyg

To build the module, you will need custom vite.config

import {defineConfig} from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
import {viteExternalsPlugin} from "vite-plugin-externals";

export default defineConfig({
    define: {
        'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production'),
    },
    plugins: [
        react(),
        viteExternalsPlugin({
            react: 'React',
            'react-dom': 'ReactDOM',
        }),
    ],
    build: {
        outDir: path.resolve(import.meta.dirname, ''),
        emptyOutDir: false,
        lib: {
            entry: path.resolve(import.meta.dirname, 'react-quill-editor.tsx'),
            name: 'ComponentB',
            formats: ['es'],
            fileName: (format) => `react-quill-editor.${format}.js`,
        },
        rollupOptions: {
            output: {
                assetFileNames: ({ names }) => {
                    if (names && names[0].endsWith('.css')) {
                        return 'react-quill-editor.css';
                    }
                    return '[name]-[hash][extname]';
                },
            },
        },
    },
    resolve: {
        alias: {
            '@': path.resolve(import.meta.dirname, '../../../src/assets/js'),
        },
    },
});