1
0
Fork 0
mirror of https://github.com/archtechx/alpine-typescript.git synced 2025-12-12 06:44:03 +00:00
TypeScript support for Alpine.js
Find a file
2021-02-26 15:06:03 +01:00
src initial commit 2021-02-26 14:43:39 +01:00
LICENSE initial commit 2021-02-26 14:43:39 +01:00
package.json Fix main in package.json 2021-02-26 15:06:03 +01:00
README.md Fix main in package.json 2021-02-26 15:06:03 +01:00
tsconfig.json initial commit 2021-02-26 14:43:39 +01:00

TypeScript support for Alpine.js

This package comes with a light TypeScript layer which provides full support for class components in Alpine.js.

It's used like this:

Register a component

import { DarkModeToggle }

Alpine.component('DarkModeToggle', DarkModeToggle);

Use it the template

<div x-data="Alpine.component('DarkModeToggle')()" x-init="init()">
    <button type="button" @click="switchTheme()">Switch theme</button>
</div>

Installation

npm install --save-dev github:leanadmin/alpine-typescript
// todo

Usage

You can get a component by calling Alpine.component('component-name')(arg1, arg2). If your component has no arguments, still append the () after the call.

The component() call itself returns a function that creates an instance of the component. Invoking the function ensures that the component has a unique instance each time.

<div x-data="Alpine.component('DarkModeToggle')()" x-init="init()">
    <button type="button" @click="switchTheme()">Switch theme</button>
</div>
<div x-data="Alpine.component('SearchableSelect')({ options: ['Foo', 'Bar'] })" x-init="init()">
    <div x-spread="options">
        ...
    </div>
</div>

Creating components

To create a component, you need to create the component object and register it using one of the provided helpers.

Component objects can be:

  • functions returning plain objects
  • classes

In the context of plain objects, the wrapper function acts as a constructor that can pass initial data to the object.

Registering components

A component can be registered like this:

import { ExampleComponent } from './ExampleComponent';
import { component } from '@leanadmin/alpine-typescript';

component('example', ExampleComponent);

Which will make it accessible using Alpine.component('example')('foo', 'bar).

Note: It's better to avoid using Alpine.component('example', ExampleComponent) even if it might work in some cases. The reason for this is that window.Alpine might not yet be accessible when you're registering components, and if it is, it's possible that it's already evaluated some of the x-data attributes. component() is guaranteed to work. And of course, you can alias the import if you wish to use a different name.

To register multiple components, you can use the registerComponents() helper.

This can pair well with scripts that crawl your e.g. alpine/ directory to register all components using their file names.

// alpine/index.js

import { registerComponents } from '@leanadmin/alpine-typescript';

const files = require.context('./', true, /.*.ts/)
    .keys()
    .map(file => file.substr(2, file.length - 5)) // Remove ./ and .ts
    .filter(file => file !== 'index')
    .reduce((files: { [name: string]: Function }, file: string) => {
        files[file] = require(`./${file}.ts`).default;

        return files;
}, {});

registerComponents(files);

Class components

You can create class components by extending AlpineComponent and exporting the class as default.

The AlpineComponent provides IDE support for Alpine's magic properties. This means that you can use this.$el, this.$nextTick(() => this.foo = this.bar), and more with full type support.

import { AlpineComponent } from '@leanadmin/alpine-typescript';

export default class DarkModeToggle extends AlpineComponent {
    public theme: string|null = null;

    /** Used for determining the transition direction. */
    public previousTheme: string|null = null;

    public browserTheme(): string {
        return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
    }

    public switchTheme(theme: string): void {
        this.$nextTick(() => this.previousTheme = this.theme);

        this.theme = theme;

        window.localStorage.setItem('leanTheme', theme);

        this.updateDocumentClass(theme);
    }

    // ...

    public init(): void {
        this.loadStoredTheme();
        this.registerListener();
    }
}

Plain object components

To register a plain object as an Alpine component, return a function that wraps the object like this:

export default (foo: string, bar: number) => ({
    foo,
    bar,

    someFunction() {
        console.log(this.foo);
    }
})

The function will serve as a "constructor" for the object, setting default values and anything else you might need.

Note that the => ({ part is just syntactic sugar, you're free to use return if it's useful in your case:

export default (foo: string, bar: number) => {
    return {
        foo,
        bar,

        // ...
    }
}