Gem Documentation

website·Indexed 31 days ago

https://gemjs.org

A lightweight ECMAScript library for building web applications using WebComponents technology. Gem provides tools for creating reactive custom elements, global state management via Store, routing, internationalization, and theming, with support for ES decorators and a dedicated CLI tool, create-gem-app.

Tokens
16.1K
Snippets
87
Records
131
Agent score
50%

What's inside Gem

  1. Overview of the Gem library

    Gem is a lightweight ECMAScript library that leverages WebComponents technology to build WebApps and UI component libraries. It allows developers to create flexible, extendable custom elements that can work together or be published as independent components.
  2. Manage application routing with Gem

    Gem uses a dynamic routing system where the URL is managed via the History API. The history object maintains a Store (history.store) that tracks the current route. Elements connected to this store automatically update when the route changes. You can retrieve current route parameters using history.getParams().
    import { GemElement, html, history, customElement, connectStore } from '@mantou/gem';
    
    @customElement('app-root')
    @connectStore(history.store)
    class App extends GemElement {
      render = () => {
        return html`${history.getParams().path}`;
      }
    }
  3. Manage global state using Gem Store

    Gem uses a 'Publish/Subscribe' model for global state management, referred to as a 'Store'. This allows multiple elements (components) to share data and receive notifications when that data is updated. When a Store is updated, all connected elements trigger their update method to achieve automatic UI synchronization.
  4. Extend GemElement to create reactive custom elements

    The GemElement class extends HTMLElement and serves as the base class for building reactive web components. It provides a suite of decorators and lifecycle methods to manage state, rendering, and DOM interactions.
    class MyElement extends GemElement {
      constructor() {
        super();
      }
    }
  5. Gem framework architecture overview

    Gem is a WebApp development framework built on native WebComponents. It utilizes the following core technologies for its implementation:

    • Templating: Uses lit-html to provide a declarative UI experience similar to JSX via ES6 template strings.
    • Styling: Uses ShadowDOM to encapsulate CSS and prevent global style conflicts.
    • State Management: Implements observedProperties and observedStores to trigger re-renders when data changes. Stores allow for centralized global data management across components.
  6. Understand Gem's core capabilities and scope

    Gem is designed specifically for web environments to meet common WebApp needs without requiring additional dependencies. However, it is not a full-stack framework: it does not include a UI library and does not provide one-click project build/scaffolding tools.
  7. Convert React components to Gem custom elements

    In Gem, components are defined as classes extending GemElement and registered using the @customElement decorator. Unlike React's JSX, Gem uses JavaScript template literals via the html tag, allowing it to run in vanilla JavaScript without compilation. Component properties (similar to React's IProps) are defined as class fields using decorators like @attribute for reactivity.
    @customElement('my-element')
    class MyElement extends GemElement {
      @attribute name: string;
      @property data?: Record<string, string>;
    
      get str() {
        return JSON.stringify(this.data);
      }
    
      render = () => {
        return html`
          <div>
            ${this.name}
            <pre>${this.str}</pre>
          </div>
        `;
      }
    }
  8. Create and apply shared styles using @adoptedStyle

    Use the css function to create a shared style table and the @adoptedStyle decorator to apply those styles to specific custom elements. This approach leverages Constructable Stylesheets to share styles across elements while respecting ShadowDOM boundaries.
    import { GemElement, adoptedStyle, customElement, css } from '@mantou/gem';
    
    // Create a shared style table
    const styles = css`
      h1 {
        text-decoration: underline;
      }
    `;
    
    @adoptedStyle(styles)
    @customElement('my-element')
    class MyElement extends GemElement {}
  9. Export element internal state for external styling

    Use the @state decorator to export the internal state of an element. This allows external CSS to style the element based on its current state using the :state() pseudo-class (e.g., :state(opened)).
    @customElement('my-element')
    class MyElement extends GemElement {
      @state opened;
    
      open = () => {
        // This element can now be selected by the CSS selector `:state(opened)`
        this.opened = true;
      }
    }
    
  10. Implement scoped and override themes in Gem v2

    v2-intro
    Gem v2 supports global themes, scoped themes, and theme overrides. Global themes are automatically added to the document. Scoped themes and overrides are applied via the @adoptedStyle decorator. Colors ending in Color support relative color syntax weights (e.g., theme.textColor500) to adjust brightness.
    // Global theme
    const theme = createTheme({ textColor: '#eee' });
    // Scoped theme
    const scopedTheme = createScopedTheme({ scopeTextColor: '#333' });
    // Override theme
    const overrideTheme = createOverrideTheme(theme, { textColor: '#eff' });
    
    const styles = css`
      :scope {
        color: ${theme.textColor};
        background: ${scopedTheme.scopeTextColor};
      }
    `;
    
    @customElement('my-element')
    @adoptedStyle(styles)
    @adoptedStyle(scopedTheme)
    @adoptedStyle(overrideTheme)
    class MyElement extends GemElement {}
  11. Debug GemElements using browser DevTools and Gem DevTools extension

    Because GemElement is a standard custom element, it can be inspected and debugged directly within standard browser DevTools. For a more intuitive experience, the Gem DevTools extension can be installed to inspect and modify the data of Gem elements.
  12. Create a Todo list component with styles and store connection

    The TodoListElement demonstrates how to map over a global store (todoData) to render a list of items and use @adoptedStyle for component-specific CSS. It integrates with duoyun-ui icons for the delete action.
    import { icons } from 'duoyun-ui/lib/icons';
    import { todoData, deleteItem } from './store';
    
    const styles = css`
      li:not(:hover) dy-use { opacity: 0; }
    `;
    
    @customElement('todo-list')
    @connectStore(todoData)
    @adoptedStyle(styles)
    export class TodoListElement extends GemElement {
      render = () => {
        return html`
          <ul class="p-0">
            ${todoData.items.map(
              (item) => html`
                <li class="flex items-center justify-between py-1 border-t border-gray-300 last:border-b">
                  <span>${item}</span>
                  <dy-use class="w-5 p-1 hover:bg-gray-200" .element=${icons.close} @click=${() => deleteItem(item)}></dy-use>
                </li>
              `,
            )}
          </ul>
        `;
      };
    }