@alimuhnad/universal-mask
v0.1.0
Published
Lightweight, dependency-free input mask for Angular (Standalone Directive). Supports number/integer with locale formatting and custom pattern masks.
Maintainers
Readme
universal-mask
Input mask خفيف لأنغولار (Angular 17+) يعمل كـ Standalone Directive، بدون تبعيات خارجية. يدعم:
- 🧮 أرقام (عشري/صحيح) مع تنسيق محلي عبر
Intl.NumberFormat(مثال:ar-IQ) - #️⃣ أقنعة نمطية Pattern عبر رموز:
#رقم،Aحرف،*حرف/رقم، والباقي ثوابت - ✂️ لصق ذكي، وحماية IME (الكتابة المركبة)، ومحافظة عملية على مؤشر الكتابة
- ⚙️ تخصيص شامل عبر Inputs أو مزود عالمي
UNIVERSAL_MASK_CONFIG - ✅ يعمل مع Template-driven و Reactive Forms (بفضل
ControlValueAccessor)
إن أردت نسخة NgModule تقليدية بدل Standalone، راجع قسم “الاستعمال داخل NgModule”.
المحتويات
- التثبيت
- التوافق
- البدء السريع (Standalone)
- الاستعمال داخل NgModule
- الخيارات (API)
- أمثلة
- التكوين العام (Provider)
- بناء المكتبة وتجربة ديمو
- استكشاف الأخطاء الشائعة
- خريطة الرموز في الـPattern
- سياسة الإصدارات والترخيص
- المساهمة
التثبيت
# داخل مشروع Angular
npm i universal-maskلو كنت تعمل محلياً على المكتبة في نفس الوركسبيس: قم بالبناء أولاً
ng build universal-maskوستجد الحزمة فيdist/universal-mask.
التوافق
- Angular v17+ (يدعم Standalone)
- TypeScript 5+
- لا توجد تبعيات خارجية
البدء السريع (Standalone)
استورد الـDirective مباشرة داخل الـComponent:
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { UniversalMaskDirective, UNIVERSAL_MASK_CONFIG } from 'universal-mask';
@Component({
selector: 'app-demo',
standalone: true,
imports: [FormsModule, UniversalMaskDirective],
providers: [
// اختياري: تهيئة عامة افتراضية
{ provide: UNIVERSAL_MASK_CONFIG, useValue: { locale: 'ar-IQ', decimalScale: 2, useGrouping: true, emitRaw: true } }
],
template: `
<!-- رقم عشري -->
<input type="text" [universalMask]="'number'" [maskDecimalScale]="2" [maskUseGrouping]="true" [maskLocale]="'ar-IQ'" [maskEmitRaw]="true" [(ngModel)]="price">
<!-- رقم صحيح -->
<input type="text" [universalMask]="'integer'" [maskEmitRaw]="true" [(ngModel)]="qty">
<!-- قناع نمطي -->
<input type="text" [universalMask]="'pattern'" maskPattern="###-###-####" [(ngModel)]="phone">
<pre>price: {{ price | json }} | qty: {{ qty }} | phone: {{ phone }}</pre>
`
})
export class DemoComponent {
price: number | null = null;
qty: number | null = null;
phone = '';
}الاستعمال داخل NgModule
لو مشروعك يعتمد NgModule تقليدي، يمكنك استيراد الـDirective في imports (لا تُعلنها في declarations لأنها Standalone):
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { UniversalMaskDirective, UNIVERSAL_MASK_CONFIG } from 'universal-mask';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, FormsModule, UniversalMaskDirective], // ✅ Standalone directive
exports: [UniversalMaskDirective], // اختياري
providers: [
{ provide: UNIVERSAL_MASK_CONFIG, useValue: { locale: 'ar-IQ', decimalScale: 2, useGrouping: true, emitRaw: true } }
],
bootstrap: [AppComponent]
})
export class AppModule {}الخيارات (API)
Input رئيسي
universalMask: 'number' | 'integer' | 'pattern' | 'raw'number: أرقام عشرية مع دعم منازل عشرية وتجميع آلافinteger: أرقام صحيحة فقطpattern: قناع نمطي (يستلزمmaskPattern)raw: نص خام بدون تنسيق
Inputs إضافية
maskPattern?: string— نمط القناع عندpattern(مثال:###-###-####)maskLocale?: string— مثلar-IQ,en-US(افتراضي: Locale المتصفح)maskDecimalScale?: number— عدد المنازل العشرية عندnumber(افتراضي: 2)maskUseGrouping?: boolean— فصل آلاف عندnumber(افتراضي: true)maskAllowNegative?: boolean— السماح بالسالب عندnumber/integer(افتراضي: true)maskMin?: number | null— حد أدنى (clamp)maskMax?: number | null— حد أعلى (clamp)maskEmitRaw?: boolean— القيمة المرسلة للفورم:- عند
trueتُرسل قيمة رقمية خام (number أو string حسب النمط) - عند
falseتُرسل القيمة المهيأة/المقنّعة كما تظهر في الحقل
- عند
Provider (تكوين عام اختياري)
UNIVERSAL_MASK_CONFIG— نفس الحقول أعلاه كـ defaults على مستوى التطبيق.
أمثلة
هاتف بنمط 3-3-4:
<input type="text" [universalMask]="'pattern'" maskPattern="###-###-####" [(ngModel)]="phone">سعر مع منزلتين عشريتين وتجميع آلاف وLocale عربي:
<input type="text"
[universalMask]="'number'"
[maskDecimalScale]="2"
[maskUseGrouping]="true"
[maskLocale]="'ar-IQ'"
[maskEmitRaw]="true"
[(ngModel)]="price" />كمية صحيحة ضمن حدين:
<input type="text"
[universalMask]="'integer'"
[maskAllowNegative]="false"
[maskMin]="1"
[maskMax]="9999"
[maskEmitRaw]="true"
[(ngModel)]="qty" />التكوين العام (Provider)
import { UNIVERSAL_MASK_CONFIG } from 'universal-mask';
bootstrapApplication(AppComponent, {
providers: [
{ provide: UNIVERSAL_MASK_CONFIG, useValue: { locale: 'ar-IQ', decimalScale: 2, useGrouping: true, emitRaw: true } }
]
});أي Input تمرره على مستوى العنصر يغلّب الإعداد العام.
بناء المكتبة وتجربة ديمو
بناء:
ng build universal-mask
# المخرجات: dist/universal-maskتطبيق ديمو داخل نفس الوركسبيس (اختياري):
ng generate application demo-app --routing --style=scss
# استورد UniversalMaskDirective داخل demo-app كما في الأمثلة أعلاه
ng serve demo-app -oاستكشاف الأخطاء الشائعة
“Can't be exported from this NgModule, as it must be imported first (-996004)”
- هذه تظهر عندما تحاول تصدير شيء من NgModule قبل استيراده أو إعلانه بشكل صحيح.
- بما أن
UniversalMaskDirectiveStandalone:- لا تضعها في
declarations. - ضعها في
importsداخل أي NgModule يحتاجها:imports: [UniversalMaskDirective] - يمكنك كذلك إضافتها في
exportsإن أردت مشاركتها مع موديولات أخرى.
- لا تضعها في
لا يظهر تنسيق الأرقام كما توقعت
- تأكد من
maskLocaleومن أذونات/دعم المتصفح لـIntl.NumberFormat. - تحقق من
maskDecimalScaleوmaskUseGrouping.
لا تصلني قيمة عددية في الـForm
- عيّن
maskEmitRaw="true"عندnumber/integerلإرسال قيمة رقمية خام.
خريطة الرموز في الـPattern
#رقم (0–9)Aحرف لاتيني (A–Z)، يُعادله Uppercase*حرف/رقم (A–Z, 0–9)- أي رمز آخر = يُعامل كـ ثابت يظهر كما هو
أمثلة:
- بطاقة:
####-####-####-#### - تاريخ بسيط:
##/##/#### - رمز مختلط:
AA-***-####
ملاحظة: يمكنك توسيع المنفعة بإضافة أوضاع مثل
dateلاحقاً عبر تعديل دوالparse/formatفيmask.utils.ts.
سياسة الإصدارات والترخيص
- يتبع Semantic Versioning (MAJOR.MINOR.PATCH).
- الترخيص: MIT.
المساهمة
مرحباً بمساهماتك!
- افتح Issue لطلب ميزة أو تبليغ عن مشكلة.
- أنشئ فرعًا، نفّذ التعديل، وافتح Pull Request موثقًا.
