Skip to main content

upp-wdgt -- Overview

upp-wdgt is the widget library of the unpispas monorepo. It provides the complete set of reusable Angular components, directives, and services that form the visual building blocks used by the applications (unpispas-pos, upp-test) and the feature libraries (libs/feature/*).

Purpose and Design Philosophy

The library encapsulates every UI primitive the applications need -- layout shells, panels, headers, form controls, grids, media pickers, navigation tabs, and utility directives -- so that every application and feature shares a consistent look, feel, and behaviour.

Three principles guide the library's design:

  1. Slot-based composition -- Components expose named content-projection slots (<ng-content select="...">) rather than deeply nested configuration objects. You compose complex UIs by placing small, single-purpose components inside container components. For example, upp-panel has slots for header, content, and footer; upp-thumb has slots for top-left, top-right, and bottom overlays; upp-header has slots for title, buttons, and content. This keeps each component's API surface small while enabling rich layouts through composition.

  2. OnPush everywhere -- Every component uses ChangeDetectionStrategy.OnPush to minimise unnecessary change detection cycles. Components communicate state changes through explicit markForCheck() calls and the ViewRenderer service (see below), not through zone-triggered dirty checking.

  3. Grid-aware adaptability -- Components like upp-thumb extend ViewModeDirective so they automatically adapt their layout (GRID card vs LIST row) based on the parent upp-grid's view mode. This means a single template works for both grid and list presentations without *ngIf branching in the consuming code.


Component Map

The library exports the following components, grouped by functional area. Each links to its detailed documentation page.

Application Shell

The top-level structure for the entire application.

ComponentSelectorPurpose
UppApplicationComponentupp-applicationRoot shell: sidebar menu + main content area
UppApplicationMenuComponentupp-application-menuSidebar menu slot
UppApplicationMainComponentupp-application-mainMain content area slot
UppApplicationPageComponentupp-application-pageIndividual page within the main area

See upp-application, upp-panel, upp-header.

Layout

Panels, headers, dropdowns, scrollable containers, and visibility control.

ComponentSelectorPurpose
UppPanelComponentupp-panelCard-like container with header/content/footer slots
UppPanelHeaderComponentupp-panel-headerPanel header slot
UppPanelContentComponentupp-panel-contentPanel content slot
UppPanelFooterComponentupp-panel-footerPanel footer slot
UppHeaderComponentupp-headerPage or section header with title, buttons, and content
UppHeaderTitleComponentupp-header-titleHeader title slot
UppHeaderButtonComponentupp-header-buttonHeader action button slot
UppHeaderContentComponentupp-header-contentHeader custom content slot
UppDropdownComponentupp-dropdownExpandable/collapsible section
UppDropdownTitleComponentupp-dropdown-titleDropdown title slot
UppDropdownSplitComponentupp-dropdown-splitDropdown split-action slot
UppDropdownContentComponentupp-dropdown-contentDropdown body slot
UppScrollableComponentupp-scrollableScrollable container with virtual-scroll-like optimisations
UppVisibleControlComponentupp-visible-controlWraps uppVisible directive with automatic change-detection detach/reattach

See upp-dropdown, upp-scrollable.

Grid

View-mode-aware grid with item and empty-state slots.

ComponentSelectorPurpose
UppGridComponentupp-gridGrid/list container that propagates view mode to children
UppGridItemComponentupp-grid-itemIndividual grid item slot
UppGridEmptyComponentupp-grid-emptyEmpty-state content shown when no items exist
ViewModeDirective[uppViewMode]Base directive for view-mode propagation (extended by UppThumbComponent)

See upp-grid.

Media

Image display, cropping, and thumbnail cards.

ComponentSelectorPurpose
UppImageComponentupp-imageImage display with lazy loading, EXIF handling, crop modal, and form binding
UppCropComponentupp-crop-imageStandalone image cropper (wraps ngx-img-cropper)
UppModalCropComponentupp-modal-crop-imageModal wrapper for the cropper (used by UppImageComponent)
UppThumbComponentupp-thumbThumbnail card with overlays, adapts to GRID/LIST mode
UppThumbTopLeftComponentupp-thumb-top-leftOverlay slot: top-left corner
UppThumbTopRightComponentupp-thumb-top-rightOverlay slot: top-right corner
UppThumbBottomComponentupp-thumb-bottomOverlay slot: bottom edge

See upp-image, upp-thumb, upp-crop.

Form Controls

Input fields, text areas, address fields, and search.

ComponentSelectorPurpose
UppInputComponentupp-inputText input with label, error display, and form binding
UppKbInputComponentupp-kb-inputKeyboard-aware input variant
UppErInputComponentupp-er-inputError-annotated input variant
UppTextAreaComponentupp-textareaMulti-line text area with form binding
UppKbTextAreaComponentupp-kb-textareaKeyboard-aware text area variant
UppErTextAreaComponentupp-er-textareaError-annotated text area variant
UppAddressComponentupp-addressAddress input with Google Maps autocomplete
UppMdAddressComponentupp-md-addressMap-display address variant
UppErAddressComponentupp-er-addressError-annotated address variant
UppSearchComponentupp-searchSearch bar with debounced input

See upp-input, upp-textarea, upp-search, upp-address.

Form Layout

Structured form containers for consistent form presentation.

ComponentSelectorPurpose
UppFormComponentupp-formForm container with image, sections, and button bars
UppFormImageComponentupp-form-imageImage slot inside a form
UppFormSectionComponentupp-form-sectionLabelled section divider
UppFormActionComponentupp-form-actionAction row inside a form
UppFormWarningComponentupp-form-warningWarning message display
UppFormButtonBarComponentupp-form-button-barFixed button bar at the form bottom
UppFormBarButtonComponentupp-form-bar-buttonIndividual button inside the bar
UppFormButtonsComponentupp-form-buttonsInline button group

See upp-form.

Select

Custom select/dropdown with list, items, and options.

ComponentSelectorPurpose
UppSelectComponentupp-selectSelect container with search and selection management
UppSelectItemComponentupp-select-itemIndividual selectable item
UppSelectListComponentupp-select-listScrollable option list
UppSelectOptionComponentupp-select-optionOption definition

See upp-select.

Tab-based content switching.

ComponentSelectorPurpose
UppTabBarComponentupp-tab-barTab bar container managing selection state
UppTabButtonComponentupp-tab-buttonIndividual tab with icon and label

See upp-tab-bar.

Directives

Utility directives for test automation, touch handling, and visibility detection.

DirectiveSelectorPurpose
DataIdDirective[uppDataid]Normalised data-id attribute for test automation
TouchDirective[uppTouch]Zone-optimised touch/click event handling
VisibleDirective[uppVisible]Viewport visibility detection via IntersectionObserver

See Directives.


Module: UppWdgtModule

All components, directives, and services are registered in a single Angular module.

import { UppWdgtModule } from '@unpispas/upp-wdgt';

@NgModule({
imports: [UppWdgtModule],
})
export class AppModule {}

Dependencies

UppWdgtModule imports the following modules:

ModulePackagePurpose
CommonModule@angular/commonStandard Angular directives (*ngIf, *ngFor, etc.)
IonicModule@ionic/angularIonic UI primitives (ion-button, ion-icon, etc.)
FormsModule@angular/formsTemplate-driven forms support
ReactiveFormsModule@angular/formsReactive forms -- also re-exported so consumers do not need to import it separately
ImageCropperModulengx-img-cropperImage cropping used by UppCropComponent and UppImageComponent
GoogleMapsModule@angular/google-mapsGoogle Maps integration for UppAddressComponent
UppBaseModule@unpispas/upp-baseBase services (platformService, viewService, configService, httpService, preloadService, languageService, etc.)

Providers

ProviderDescription
ViewRendererBatched change-detection service (see below)

Schema

The module registers CUSTOM_ELEMENTS_SCHEMA to allow Ionic web-component selectors (e.g. ion-button, ion-icon) in templates without Angular treating them as unknown elements.


ViewRenderer Service

ViewRenderer is a lightweight injectable that optimises change detection by coalescing multiple markForCheck() calls into a single detectChanges() per microtask tick.

Why It Exists

In an OnPush component tree, multiple data changes within the same synchronous execution (e.g. processing a batch of observable emissions) can each call ChangeDetectorRef.markForCheck(). Without ViewRenderer, each call would schedule a separate check. ViewRenderer deduplicates these: it sets a flag on the first call and schedules a single detectChanges() via Promise.resolve().then(...). Subsequent calls within the same tick are no-ops. This reduces rendering work, especially in components that react to multiple streams.

Setup

Because ViewRenderer needs a ChangeDetectorRef (which is component-scoped, not injectable at the module level), you must provide it per-component:

import { ViewRenderer } from '@unpispas/upp-wdgt';

@Component({
selector: 'app-example',
providers: [
{
provide: ViewRenderer,
useFactory: (cdRef: ChangeDetectorRef) => new ViewRenderer(cdRef),
deps: [ChangeDetectorRef],
},
],
})
export class ExampleComponent {
constructor(private renderer: ViewRenderer) {}

update() {
this.renderer.markForCheck();
}
}

API

MemberTypeDescription
cdrefChangeDetectorRef (getter)Access the underlying ChangeDetectorRef for cases where you need direct control.
markForCheck(force?)voidSchedule a change-detection cycle. When force is true, detectChanges() runs synchronously and immediately. When false (the default), it is deferred to the next microtask and deduplicated -- multiple calls within the same tick result in a single detectChanges().

Usage Example

export class ProductListComponent {
constructor(private renderer: ViewRenderer, private dataService: DataService) {}

ngOnInit() {
this.dataService.products$.subscribe(products => {
this.products = products;
this.renderer.markForCheck();
});

this.dataService.categories$.subscribe(categories => {
this.categories = categories;
this.renderer.markForCheck();
});
}
}

Even though both subscriptions fire in the same tick, only one detectChanges() executes.


Slot-Based Composition Pattern

The recurring composition pattern across all upp-wdgt components works as follows:

  1. Container component defines the layout structure and exposes named <ng-content> slots using CSS selectors (e.g. select="upp-panel-header").
  2. Slot components are thin wrappers (template: '<ng-content></ng-content>') whose only purpose is to serve as projection targets. They carry no logic.
  3. Consumer code composes the UI by nesting slot components inside the container:
<upp-panel>
<upp-panel-header>Title here</upp-panel-header>
<upp-panel-content>Body here</upp-panel-content>
<upp-panel-footer>Actions here</upp-panel-footer>
</upp-panel>

This pattern is used by upp-panel, upp-header, upp-dropdown, upp-thumb, upp-form, and upp-application. Understanding it once means you can use any container component in the library.

Why Slots Instead of Inputs?

  • Flexibility -- Slots accept arbitrary Angular templates, not just strings or simple values. A header slot can contain buttons, icons, badges, or custom components.
  • Encapsulation -- The container component controls where each slot renders without exposing its internal DOM structure.
  • Readability -- The consuming template reads like a declarative layout description rather than a configuration object.

Exported Surface

The public API is defined in libs/upp-wdgt/src/index.ts and re-exports every component, directive, and service:

  • Directives -- DataIdDirective, TouchDirective, VisibleDirective
  • Components -- Application shell (UppApplicationComponent, menu, main, page), visibility control, panels (panel, header, content, footer), headers (header, title, button, content), dropdown (dropdown, title, split, content), scrollable, grid (grid, item, empty), media (image, crop, modal crop, thumb with overlays), form controls (input, textarea, address, search), select (select, item, list, option), tab bar (tab-bar, tab-button), form layout (form, image, section, action, warning, button-bar, bar-button, buttons)
  • Services -- ViewRenderer

Theme and Styles

Global theme variables live in libs/upp-wdgt/src/styles/theme.scss. Each component also has its own .scss file co-located with the component source. The theme file should be included in the consuming application's styles array or imported from a global stylesheet.


Assets

Static assets (icons, images) that the widgets depend on are located under libs/upp-wdgt/src/assets/. Ensure the consuming application's build configuration includes this path in its assets array so that the assets are copied to the build output.