Options
All
  • Public
  • Public/Protected
  • All
Menu

WebCell

WebCell logo

WebCell

Web Components engine based on JSX & TypeScript

NPM Dependency Build Status Slideshow

Edit WebCell demo

NPM

Usage

Demo & GitHub template: https://web-cell.dev/scaffold/

Project bootstrap

Command

npm init -y
npm install web-cell
npm install parcel-bundler -D

package.json

{
    "scripts": {
        "start": "parcel source/index.html",
        "build": "parcel build source/index.html"
    }
}

tsconfig.json

source/index.html

<script src="https://polyfill.io/v3/polyfill.min.js?flags=gated&features=Object.fromEntries%2CArray.prototype.flat"></script>
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/[email protected]/webcomponents-bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/[email protected]/custom-elements-es5-adapter.js"></script>

<script src="source/SubTag.tsx"></script>
<script src="source/TestTag.tsx"></script>

<sub-tag></sub-tag>
<test-tag></test-tag>

Simple component

source/SubTag.tsx

import { createCell, component, mixin } from 'web-cell';

export function InlineTag({ defaultSlot }: any) {
    return <span>{defaultSlot}</span>;
}

@component({
    tagName: 'sub-tag',
    renderTarget: 'children'
})
export class SubTag extends mixin() {
    render() {
        return <InlineTag>test</InlineTag>;
    }
}

Advanced component

source/TestTag.tsx

import {
    createCell,
    component,
    mixin,
    attribute,
    watch,
    on,
    Fragment
} from 'web-cell';

import { SubTag } from './SubTag';

interface Props {
    title?: string;
}

interface State {
    status: string;
}

@component({
    tagName: 'test-tag',
    style: {
        '.title': {
            color: 'lightblue'
        },
        '.title.active': {
            color: 'lightpink'
        }
    }
})
export class TestTag extends mixin<Props, State>() {
    @attribute
    @watch
    title = 'Test';

    state = { status: '' };

    onClick = () => (this.title = 'Example');

    @on('click', ':host h1')
    onDelegate() {
        this.setState({ status: 'active' });
    }

    render({ title }: Props, { status }: State) {
        return (
            <Fragment>
                <h1 title={title} className={`title ${status}`}>
                    {title}
                    <img alt={title} onClick={this.onClick} />

                    <SubTag />
                </h1>
            </Fragment>
        );
    }
}

Internationalization

tsconfig.json

{
    "compilerOptions": {
        "module": "ESNext"
    }
}

source/i18n/en-US.ts

export enum en_US {
    title = 'Test'
}

export type I18nMap = typeof en_US;

source/i18n/zh-CN.ts

export enum zh_CN {
    title = '测试'
}

source/index.tsx

import {
    createI18nScope,
    documentReady,
    render,
    createCell
} from 'web-cell';

import { I18nMap } from './i18n/en-US';

console.log(navigator.languages.includes('zh-CN')); // true

const { loaded, i18nTextOf } = createI18nScope<I18nMap>({
    'en-US': async () => (await import('./i18n/en-US')).en_US,
    'zh-CN': async () => (await import('./i18n/zh-CN')).zh_CN
}, 'en-US');

Promise.all([loaded, documentReady]).then(() =>
    render(<h1>{i18nTextOf('title')}</h1>); // <h1>测试</h1>
);

Life Cycle hooks

  1. connectedCallback

  2. disconnectedCallback

  3. attributeChangedCallback

  4. adoptedCallback

  5. shouldUpdate

  6. updatedCallback

Ecosystem

We recommend these libraries to use with WebCell:

Roadmap

Go to contribute!

Generated using TypeDoc