npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

appify-domain-spic-lang-components

v0.0.2

Published

> **Reusable Angular component library for rendering DSL-based mobile applications**

Downloads

5

Readme

@appify/dsl-components

Reusable Angular component library for rendering DSL-based mobile applications

Angular 20 component library for the Appify project that provides recursive, constraint-based component rendering for building mobile apps visually.


📦 Installation

# Build the library
cd lib
npm run build

# Use in Appify_FE (already configured)
# Import from: 'appify-domain-spic-lang-components'

🎯 Overview

This library provides:

  • 18 Pre-built Components across 6 categories
  • Recursive Component Trees with nested children support
  • Constraint System for parent-child validation
  • Event System for actions and triggers
  • i18n Support built into all components
  • Data Binding through ComponentContext
  • Two Specialized Renderers (builder vs runtime)

🧩 Component Categories

Basic Components (4)

  • Text - Display text with i18n and interpolation
  • Button - Interactive buttons with actions
  • Image - Images with loading states
  • Icon - Ionic icon display

Layout Components (4)

  • Container - Generic layout container
  • Grid - Responsive grid layout
  • Card - Card-based layouts
  • Tabs - Tabbed content sections

Input Components (6)

  • Input - Single-line text input
  • Textarea - Multi-line text input
  • Select - Dropdown selection
  • Checkbox - Boolean checkbox
  • Radio - Radio button group
  • Searchbar - Search input with debounce

Data Components (2)

  • List - Scrollable list with data binding
  • Repeater - Repeat components from array

Media Components (2)

  • Video - Video player
  • Avatar - User avatar display

🏗️ Architecture

Component Model

interface DslComponent {
  id: string;
  type: string;
  props: Record<string, any>;
  children?: DslComponent[];  // Recursive nesting
  events?: DslComponentEvents;
  style?: Record<string, any>;
  cssClass?: string;
}

Constraint System

Components define what children they can accept:

{
  type: 'Form',
  acceptsChildren: true,
  allowedChildren: ['Input', 'Textarea', 'Select', 'Button'],
  minChildren: 1,
  maxChildren: 20
}

Validation:

  • canAcceptChild(parent, child) - Validates if child can be added
  • getAllowedChildTypes(parent) - Gets list of valid child types
  • validateMinChildren(component) - Checks minimum requirements

Component Context

Runtime data passed to all components:

interface ComponentContext {
  user?: any;              // Current user
  data?: any;              // Component data
  apis?: Record<string, any>;  // API responses
  i18n?: (key: string) => string;  // Translation function
  navigateTo?: (pageId: string) => void;  // Navigation
  executeAction?: (action: any) => void;   // Action handler
}

🎨 Two Renderers

1. DslRendererComponent (Production)

For final built apps - pure runtime rendering.

<app-dsl-renderer 
  [dslTree]="rootComponent" 
  [context]="runtimeContext"
  (actionTriggered)="handleAction($event)">
</app-dsl-renderer>

Features:

  • Minimal overhead
  • Performance optimized
  • No editor UI
  • Pure component rendering

2. BuilderRendererComponent (Editor)

For builder environment with editing controls.

<app-builder-renderer 
  [components]="pageComponents" 
  [selectedComponent]="selected"
  [context]="editorContext"
  (componentSelected)="onSelect($event)"
  (componentDeleted)="onDelete($event)">
</app-builder-renderer>

Features:

  • Visual component hierarchy
  • Selection highlighting
  • Quick action buttons (move, delete)
  • Drag & drop reordering
  • Component icons and previews

🔌 Usage Examples

Creating a Component

const button: DslComponent = {
  id: 'btn_1',
  type: 'Button',
  props: {
    labelI18nKey: 'common.submit',  // i18n support
    color: 'primary',
    expand: 'block',
    action: 'navigate:home'  // Action trigger
  }
};

Nested Components

const form: DslComponent = {
  id: 'form_1',
  type: 'Form',
  props: { submitLabel: 'Submit' },
  children: [
    {
      id: 'input_1',
      type: 'Input',
      props: { 
        label: 'Email', 
        type: 'email',
        binding: 'data.user.email'  // Data binding
      }
    },
    {
      id: 'btn_1',
      type: 'Button',
      props: { label: 'Submit', action: 'submit' }
    }
  ]
};

Using Context

const context: ComponentContext = {
  user: { name: 'John', email: '[email protected]' },
  data: { user: { email: '' } },
  i18n: (key: string) => translations[key],
  navigateTo: (pageId: string) => router.navigate([pageId]),
  executeAction: (action) => console.log('Action:', action)
};

🔧 Development

Building

# From lib/ directory
npm run build

# Output: lib/dist/appify-domain-spic-lang-components/
# Build time: ~6 seconds

Using in Angular Project

// Import components
import { 
  DslRendererComponent,
  BuilderRendererComponent,
  DslComponent,
  ComponentContext
} from 'appify-domain-spic-lang-components';

// Import in standalone component
@Component({
  selector: 'app-my-component',
  standalone: true,
  imports: [DslRendererComponent],
  template: `<app-dsl-renderer [dslTree]="root" />`
})

Component Registry

Access component definitions:

import { ComponentRegistryProvider } from 'appify-domain-spic-lang-components';

const registry = ComponentRegistryProvider.getRegistry();
const buttonDef = registry.getComponent('Button');
const allComponents = registry.getAllComponents();
const layoutComponents = registry.getComponentsByCategory('layout');

📋 Component Props Reference

Common Props (All Components)

| Prop | Type | Description | |------|------|-------------| | style | Object | Inline CSS styles | | cssClass | string | CSS class names | | i18nKey | string | Translation key for text |

Button Props

| Prop | Type | Description | |------|------|-------------| | label | string | Button text | | labelI18nKey | string | Translation key | | action | string | Action to trigger | | color | string | Ionic color | | expand | string | 'block' | 'full' | | fill | string | 'solid' | 'outline' | 'clear' | | disabled | boolean | Disable button | | icon | string | Icon name | | iconPosition | string | 'start' | 'end' |

Input Props

| Prop | Type | Description | |------|------|-------------| | label | string | Input label | | placeholder | string | Placeholder text | | type | string | Input type | | binding | string | Data binding path | | required | boolean | Required validation | | minLength | number | Min length | | maxLength | number | Max length | | pattern | string | Regex pattern | | helperText | string | Helper text |

Container Props

| Prop | Type | Description | |------|------|-------------| | layout | string | 'vertical' | 'horizontal' | | padding | number | Padding in pixels | | gap | number | Gap between children | | backgroundColor | string | Background color |


✅ Features

  • [x] Recursive component rendering
  • [x] Constraint-based validation
  • [x] Event system with action triggers
  • [x] i18n support
  • [x] Data binding preparation
  • [x] Two specialized renderers
  • [x] 18 production-ready components
  • [x] OnPush change detection
  • [x] Standalone components (Angular 20)
  • [x] TypeScript strict mode
  • [x] Full type safety

🔜 Roadmap

  • [ ] Add more components (Switch, Slider, Date Picker)
  • [ ] Component animation support
  • [ ] Advanced validation rules
  • [ ] Custom component registration
  • [ ] Component templates
  • [ ] Accessibility improvements
  • [ ] Unit tests
  • [ ] Storybook documentation

📚 Documentation

See the main project documentation:


🛠️ Technical Details

  • Angular: 20.3.0
  • Ionic: 8.x
  • TypeScript: 5.x (Strict mode)
  • Change Detection: OnPush
  • Component Type: Standalone
  • Build Output: ES2022 modules

📝 License

Internal project library for Appify MVP.