@a.nemreen/dga-ui
v0.3.2
Published
DGA Angular UI library — standalone forms, overlays, navigation, and portal shell with RTL-first Tailwind styling
Maintainers
Readme
@a.nemreen/dga-ui
Standalone Angular UI components for the DGA design system — forms, overlays, navigation, portal shell, and layout. Styled with Tailwind utilities mapped to @a.nemreen/dga-tokens.
Live demo: nemreen.info/dga
Version 0.2.x until public API freeze.
Features
- Standalone Angular 19 components (no NgModules)
- RTL-first / Arabic-ready (logical CSS + locale-aware chrome)
- Forms: input, select, checkbox, radio, switch, OTP, upload, date picker, …
- Overlays: dialog, modal, drawer, toast, menu, tooltip
- Shell: header, top bar, hero, footer, preloader
- Feedback & a11y: alert, cookies, skip link (accessibility panel →
@a.nemreen/a11y) - Layout: card, section, grid, clamp, expandable
Install
npm install @a.nemreen/dga-ui @a.nemreen/dga-tokensPeers: @angular/core / @angular/common / @angular/forms / @angular/platform-browser ^19–22, @a.nemreen/dga-tokens ^0.2 || ^0.3.
Library layout
Sources live under src/lib/<domain>/<component>/. Place new work in the matching domain — do not add new top-level peers under lib/.
| Domain | Use for |
|--------|---------|
| primitives/ | Visual atoms (button, icon, badge, …) |
| forms/ | Inputs, selects, field chrome |
| overlays/ | Floating UI (dialog, toast, menu, …) |
| feedback/ | Status and user-response UI (alert, cookies, a11y, …) |
| navigation/ | Wayfinding (tabs, breadcrumb, side-nav, …) |
| layout/ | Structure wrappers (card, section, grid, …) |
| shell/ | Page chrome (header, footer, hero, …) |
| content/ | Content presentation (list, quote, metric, …) |
| data/ | Tables, charts, export |
| domain/ | Locale/region data helpers (not UI) |
| utils/ | Internal helpers only (not exported) |
Import from the public package surface — do not deep-import src/lib/... paths.
Secondary entry points
Heavier shell pieces ship as separate FESMs so the primary bundle stays lean:
import { DgaHeader } from '@a.nemreen/dga-ui/header';
import { DgaCookies } from '@a.nemreen/dga-ui/cookies';
import { DgaDatePicker } from '@a.nemreen/dga-ui/date-picker';Accessibility tools live in a separate package — @a.nemreen/a11y — mount with Accessibility.mount().
Setup
@import 'tailwindcss';
@import '@a.nemreen/dga-tokens/styles.css';Load Arabic Google Fonts (IBM Plex default; see @a.nemreen/dga-tokens README / DgaFontService).
Scan library sources so Tailwind keeps component utilities (path may vary):
@source "../node_modules/@a.nemreen/dga-ui/**/*.{mjs,js}";import {
DgaButton,
DgaInput,
DgaLabel,
DgaBadge,
DgaAlert,
DgaCheckbox,
DgaRadio,
DgaSelect,
DgaNativeSelect,
DgaField,
DgaSpinner,
DgaDialog,
DgaToast,
DgaCard,
DgaDivider,
DgaIcon,
} from '@a.nemreen/dga-ui';Components
Icon
Two layers:
- Chrome — curated inline SVG via
name(paints with the first frame; use in buttons, fields, menus). - Content — HugeIcons Stroke Rounded font via
glyph(opt into@a.nemreen/dga-tokens/styles/icon-font.css).
<!-- Chrome (always available) -->
<dga-icon name="search" size="sm" />
<dga-icon name="arrowNext" size="sm" label="التالي" />
<!-- Content (requires icon-font.css) -->
<dga-icon glyph="search-01" size="xl" />
<dga-icon glyph="notification-02" size="xl" tone="primary" />Use arrowNext / arrowPrev for forward/back — they mirror under dir="rtl". Prefer literal arrowLeft / arrowRight only when you mean that physical direction.
Sizes (px): 2xs 10 · xs 14 · sm 16 · md 18 · lg 20 · xl 24 · 2xl 28 · 3xl 32.
Chrome icons are vendored in the library (no @platformscode/icons peer). For content glyphs, use the optional icon font from @a.nemreen/dga-tokens.
Scroll to top
Floating control that appears after the page scrolls past a threshold. Mount once at the app root; it stacks above @a.nemreen/a11y by default.
<dga-scroll-top position="end" [threshold]="320" />Button
<button dgaButton type="button">حفظ</button>
<button dgaButton variant="outline" size="sm">إلغاء</button>
<button dgaButton variant="danger" disabled>حذف</button>Input + Label + Field
<label dgaLabel dgaRequired for="email">البريد</label>
<input dgaInput id="email" type="email" />
<textarea dgaInput rows="3"></textarea>
<dga-field label="البريد" controlId="email" required hint="لن نشارك بريدك.">
<input dgaInput id="email" type="email" />
</dga-field>Select
Configurable select (search, multi, always-open):
<dga-select [options]="cities" [(value)]="city" />
<dga-select searchable [options]="cities" [(value)]="city" />
<dga-select multiple [options]="cities" [(value)]="cities" />
<dga-select multiple searchable [options]="cities" [(value)]="cities" />
<dga-select openMode="always" [options]="cities" [(value)]="city" />Native <select> styling for simple forms:
<select dgaSelect>
<option value="riyadh">الرياض</option>
</select>Checkbox + Radio
<label>
<input dgaCheckbox type="checkbox" />
أوافق
</label>
<label>
<input dgaRadio type="radio" name="plan" value="basic" />
أساسية
</label>Badge
<dga-badge variant="success">مكتمل</dga-badge>Alert
<dga-alert variant="warning" title="تنبيه">تحقق من البيانات.</dga-alert>
<dga-alert dismissible (dismissed)="onDismiss()">يمكن إغلاقه</dga-alert>Spinner
<dga-spinner />
<dga-spinner size="lg" tone="neutral" />Preloader (optional first-load)
Full-screen brand overlay; auto-hides when the document is ready and minDuration elapses. Omit the tag if you do not want it.
<dga-preloader
brand="بوابة الخدمات"
label="جاري التحميل"
[minDuration]="1000"
[once]="true"
persist="local"
/>once+persist="local"- show only on the visitor’s first visitpersist="session"- once per tab sessionpersist="none"or[once]="false"- every load- Optional
logoSrcreplaces the default geometric mark (closed)fires after the exit animation
import { DgaPreloader } from '@a.nemreen/dga-ui';Dialog
<dga-dialog [(open)]="open" title="تأكيد">
<p>هل أنت متأكد؟</p>
<div dgaDialogActions>
<button dgaButton variant="ghost" (click)="open = false">إلغاء</button>
<button dgaButton (click)="confirm()">تأكيد</button>
</div>
</dga-dialog>Modal
<dga-modal
[(open)]="open"
title="تفاصيل الطلب"
description="راجع البيانات قبل المتابعة"
size="lg"
animation="scale"
>
<p>محتوى النافذة المنبثقة.</p>
<div dgaModalActions>
<button dgaButton variant="ghost" (click)="open = false">إلغاء</button>
<button dgaButton (click)="confirm()">تأكيد</button>
</div>
</dga-modal>Toast
<dga-toast [(open)]="show" variant="success" title="تم">حُفظ السجل.</dga-toast>Tooltip / Switch / Progress / Nav (Wave I)
<dga-switch [(checked)]="on" label="الإشعارات" />
<a dgaLink href="#">رابط</a>
<dga-progress [value]="60" />
<dga-skeleton />
<dga-skeleton [lines]="3" animation="shimmer" />
<dga-skeleton shape="circle" size="lg" />
<dga-tooltip title="مساعدة" text="وصف مختصر">
<button dgaButton size="sm">؟</button>
</dga-tooltip>
<dga-breadcrumb [items]="[{ label: 'الرئيسية', href: '#' }, { label: 'الحالي' }]" />
<dga-tabs [(selected)]="tab">
<dga-tab value="a" label="أ">...</dga-tab>
</dga-tabs>
<dga-content-switcher [(selected)]="view">
<dga-content-switcher-panel value="all" label="الكل">...</dga-content-switcher-panel>
</dga-content-switcher>
<dga-accordion>
<dga-accordion-item title="سؤال">جواب</dga-accordion-item>
</dga-accordion>
<dga-pagination [(page)]="page" [totalPages]="10" />Layout recipes
Prefer DGA spacing tokens (gap-md, p-xl, py-3xl) over raw pixel values. For page width, use max-w-(--container-*) - plain max-w-5xl binds to the spacing scale in Tailwind v4.
Stack (column)
<div class="flex flex-col gap-md">
<p>صف واحد</p>
<p>صف آخر</p>
</div>Inline row
<div class="flex flex-wrap items-center gap-md">
<button dgaButton>حفظ</button>
<button dgaButton variant="ghost">إلغاء</button>
</div>Split (space between)
<div class="flex items-center justify-between gap-xl">
<h2 class="text-display-sm">العنوان</h2>
<div class="flex gap-sm">…</div>
</div>Responsive grid
<div class="grid grid-cols-1 gap-lg md:grid-cols-2 lg:grid-cols-3">
<dga-card title="أ">…</dga-card>
<dga-card title="ب">…</dga-card>
<dga-card title="ج">…</dga-card>
</div>Or use the thin wrapper:
<dga-grid [cols]="3" gap="lg">
<dga-card title="أ">…</dga-card>
<dga-card title="ب">…</dga-card>
<dga-card title="ج">…</dga-card>
</dga-grid>Contained section
<dga-section title="القسم" subtitle="وصف قصير" contained>
محتوى القسم
</dga-section>Portal home shell (consumable across apps)
Compose the official home template with library primitives only - no page-local CSS required:
<dga-top-bar registrationId="00000000000" />
<dga-header
appearance="portal"
mobileNav="sheet"
brand="شعار المنصة"
brandSlogan="بوابة الجهة"
brandHref="/"
[items]="navItems"
[actions]="headerActions"
(actionClick)="onAction($event)"
/>
<!-- mobileNav: sheet | fullscreen | push -->
<dga-hero appearance="portal" [slides]="heroSlides" [(activeIndex)]="i" />
<dga-section
width="wide"
tone="surface"
title="قسم من نحن"
subtitle="…"
>
<button dgaSectionActions dgaButton variant="outline">إجراء ثانوي</button>
<dga-grid [cols]="4" gap="xl">
<dga-metric appearance="stat" value="1.5M" label="شخص">
<dga-icon-badge dgaMetricIcon>
<dga-icon name="user" tone="primary" />
</dga-icon-badge>
</dga-metric>
</dga-grid>
</dga-section>
<dga-card title="عنوان البطاقة" description="نص إضافي">
<dga-icon-badge dgaCardLead>
<dga-icon name="home" tone="primary" />
</dga-icon-badge>
<div dgaCardActions>
<button dgaButton variant="outline" size="sm">اجراء ثانوي</button>
<button dgaButton size="sm">اجراء</button>
</div>
</dga-card>
<dga-card>
<dga-card-media dgaCardMedia alt="خبر" />
…
</dga-card>
<dga-logo-tile label="شريك" />
<dga-footer [columns]="footerColumns" copyright="…" />Portal tokens (layout sizes): --size-hero-portal (491px), --size-header-portal (72px), --size-icon-badge (40px), --size-dot (16px).
Content + sticky aside
<div class="mx-auto grid max-w-(--container-7xl) gap-3xl px-xl md:grid-cols-[1fr_auto]">
<main class="min-w-0">…</main>
<dga-side-info title="في هذه الصفحة" [items]="tocItems" />
</div>License
MIT — see LICENSE. Copyright (c) 2026 Ahmed Nemreen.
Use it in any project. Do not rebrand and sell it as your own unique product.
