New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

@sebgroup/green-core-ng

Package Overview
Dependencies
Maintainers
3
Versions
195
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sebgroup/green-core-ng

Angular wrappers for @sebgroup/green-core web components.

latest
Source
npmnpm
Version
3.33.2
Version published
Maintainers
3
Created
Source

@sebgroup/green-core-ng

Angular wrappers for @sebgroup/green-core web components.

npm version License

Status: Beta

Overview

@sebgroup/green-core-ng provides type-safe Angular component wrappers for all Green Design System web components. These wrappers are automatically generated from the Custom Elements Manifest, ensuring they stay in sync with the underlying web components while providing a native Angular development experience.

The wrappers eliminates the need to use CUSTOM_ELEMENTS_SCHEMA.

Versioning

@sebgroup/green-core-ng is versioned and released in tandem with @sebgroup/green-core, and includes @sebgroup/green-core as a dependency. Angular consumers should generally only need to specify @sebgroup/green-core-ng as a direct dependency in their package.json, and the correct version of the underlying @sebgroup/green-core should be automatically installed.

Key Features

  • Fully type-safe - Complete TypeScript definitions for all components, properties, and events
  • Automatic property syncing - Angular @Input properties automatically sync to web component properties
  • Native Angular events - Web component custom events are exposed as Angular @Output EventEmitters
  • Form integration - Form controls implement ControlValueAccessor and work seamlessly with Angular forms
  • Router integration - Link components work natively with Angular's RouterLink directive
  • Standalone components - All components are standalone
  • Auto-generated - Components are generated from the web component manifest, ensuring consistency

Installation

npm install @sebgroup/green-core-ng

Quick Start

Import components directly in your standalone components or NgModules:

import { Component } from '@angular/core';
import { GdsButtonComponent, GdsInputComponent } from '@sebgroup/green-core-ng';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [GdsButtonComponent, GdsInputComponent],
  template: `
    <gds-input
      label="Email"
      type="email"
      [(ngModel)]="email">
    </gds-input>
    
    <gds-button (click)="submit()">
      Submit
    </gds-button>
  `
})
export class ExampleComponent {
  email = '';
  
  submit() {
    console.log('Email:', this.email);
  }
}

How It Works

Code Generation Pipeline

Pipeline Steps:

  • Source: Web components in @sebgroup/green-core are built with Lit
  • Manifest: The build process for Core generates a Custom Elements Manifest (CEM) describing all components. The information is then by the component-meta module i Core, and accessed by this libarary from there.
  • Analysis: The generator (generate-wrappers.ts) fetches the component-meta data to determine:
    • General component metadata (tag names, descriptions)
    • Properties (inputs with types)
    • Events (outputs with payload types)
    • Slots (content projection)
    • Methods (public API)
    • Special characteristics (form controls, linkable components)
  • Generation: For each component, TypeScript files are generated:
    • Angular component wrapper (.component.ts)
    • Unit test file (.component.spec.ts)
    • Barrel export (index.ts)
  • Build: The generated code is compiled and packaged using ng-packagr
graph TB
    subgraph "1. @sebgroup/green-core"
        A[Web Components TypeScript Source Files<br/>libs/core/src/components/]
        A --> B[CEM Analyzer<br/>npx cem analyze --litelement]
        B --> C[custom-elements.json<br/>Custom Elements Manifest]
        C --> E[component-meta<br/>CemParser.parseAllComponents]
        E --> F[Extract Properties]
        E --> G[Extract Events]
        E --> H[Extract Slots]
        E --> I[Extract Methods]
        E --> J[Detect Special Types<br/>Form Controls, Links]
        F & G & H & I & J --> K[ComponentData Objects]
    end
    
    subgraph "2. @sebgroup/green-core-ng"
        K --> L[AngularGenerator]
        L --> M[Generate Imports<br/>Angular decorators, base classes]
        L --> N[Generate Component Class<br/>@Component decorator + metadata]
        L --> O[Generate Properties<br/>@Input with transformations]
        L --> P[Generate Events<br/>@Output EventEmitters]
        L --> Q[Generate Lifecycle Hooks<br/>OnInit, OnChanges, AfterViewInit]
        M & N & O & P & Q --> R[Component Files]
        
        K --> S[TestGenerator]
        S --> T[Test Files<br/>.component.spec.ts]

        R --Output--> V["src/generated/*"]
      
          V --> W["ng-packagr<br/>nx/angular:package"]
        subgraph "Build & package"
          W --> X["dist/libs/core-ng/<br/>Published NPM Package"]
        end

    end

    class B,D,L,S,W process

Runtime Behavior

Property Synchronization (@ProxyInputs decorator):

  • Angular @Input properties are defined with the same names and types as web component properties
  • The @ProxyInputs decorator intercepts ngOnChanges and ngAfterViewInit lifecycle hooks
  • Property changes are synchronized to the underlying web component DOM element outside Angular's zone for optimal performance

Event Handling:

  • Web component custom events are captured during ngOnInit
  • Event listeners are set up for custom events in order to rename them from gds-event-name to gdsEventName (kebab case to camel case)
  • When events fire, they're emitted through Angular @Output EventEmitters
  • This allows standard Angular event binding syntax: (gdsClose)="handler()"

Change Detection:

  • Components use ChangeDetectionStrategy.OnPush for performance
  • The change detector is detached in the constructor for non-form-control components
  • Form control components use the base class's change detection strategy

Project Structure

libs/core-ng/
├── src/
│   ├── generated/              # Auto-generated component wrappers. This directory is gitignored
│   ├── form-control-base.ts    # Base class for form control components
│   ├── proxy-inputs.decorator.ts  # Decorator for property syncing
│   └── index.ts                # Main entry point
│
├── build-scripts/
│   ├── generate-wrappers.ts    # Orchestrates the generation process
│   ├── generator.ts            # Core generator logic. Component code generation templates are in here
│   └── test-generator.ts       # Test generator
│
├── documentation/              # Implementation docs

Special Features

Form Controls

Components that extend GdsFormControlElement in Green Core automatically implement ControlValueAccessor. This means they work out-of-the-box with:

  • Reactive Forms: formControl, formControlName, formGroup
  • Template-driven Forms: ngModel, ngModelGroup
  • Form validation: Validation states sync to the web component's invalid property

See full documentation

Components with an href property (like gds-link, gds-button, gds-menu-button) automatically integrate with Angular's RouterLink. No additional directives needed - the integration is built in!

See full documentation

Development Workflow

Generating Wrappers

Wrappers are automatically regenerated during the build process, but you can trigger generation manually:

# Only generate component wrapper sources, withoput build or test
nx run core-ng:generate-wrappers

# Generates wrappers and runs the generated test suite
nx run core-ng:test

# Gnereates the wrappers and builds with @nx/angular:package
nx run core-ng:build

Generated Files

⚠️ Do not manually edit files in src/generated/ - they will be overwritten on the next generation.

Instead:

  • Modify the generator logic in build-scripts/
  • Update base classes (form-control-base.ts, proxy-inputs.decorator.ts)
  • Adjust component detection logic in libs/core/src/utils/helpers/component-meta.ts

Implementation Details

Essentially, the wrappers are dummy classes decorated with Angulars @Component, @Input and @Output decorators.

By using the web components element name as the selector for the decorated class, Angular is "tricked" into creating an instance of the web component at run-time.

@Component({
  selector: 'gds-button', // <-- Angular will create a <gds-button> element in DOM
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `<ng-content></ng-content>` // <-- Wrapper itself contains no template or logic, other than <ng-content>
})

Property Type Mapping

The generator extracts component structure info from the Custom Elements Manifest and maps it to Angular component properties:

// In web component (Green Core):
@property()
variant: 'primary' | 'secondary' = 'primary'

// Generated Angular wrapper:
@Input()
variant?: GdsButton['variant']  // Type: 'primary' | 'secondary' | undefined

This approach ensures:

  • Type safety: Angular's compiler knows the exact types
  • Single source of truth: Types come from the web component definitions
  • Automatic updates: If web components change, wrappers reflect those changes after regeneration

Kebab-case properties are converted to camelCase to align more with Angular conventions.

Event Type Mapping

@Output decorators are added for all events, and any kebab-cased events (like gds-close) will be automatically mapped to a camelCased output (gdsClose) for better alignment with Angular conventions.

Boolean Input Transformation

Boolean inputs automatically use Angular's booleanAttribute transform:

@Input({ transform: booleanAttribute })
disabled?: GdsButton['disabled']

This allows both attribute and property binding:

<!-- Both work -->
<gds-button disabled></gds-button>
<gds-button [disabled]="true"></gds-button>

FAQs

Package last updated on 05 Nov 2026

Related posts