ngx-kit 5.0.0 → 6.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +3 -2
  2. package/angle-selector/README.md +34 -0
  3. package/box-shadow/README.md +33 -0
  4. package/color-picker/README.md +52 -0
  5. package/data-table/README.md +120 -0
  6. package/date-picker/README.md +74 -0
  7. package/dialog/README.md +94 -169
  8. package/drawer-menu/README.md +76 -0
  9. package/dropzone/README.md +59 -0
  10. package/fesm2022/ngx-kit-angle-selector.mjs +2 -2
  11. package/fesm2022/ngx-kit-angle-selector.mjs.map +1 -1
  12. package/fesm2022/ngx-kit-box-shadow.mjs +28 -27
  13. package/fesm2022/ngx-kit-box-shadow.mjs.map +1 -1
  14. package/fesm2022/ngx-kit-color-picker.mjs +173 -43
  15. package/fesm2022/ngx-kit-color-picker.mjs.map +1 -1
  16. package/fesm2022/ngx-kit-data-table.mjs +9 -2
  17. package/fesm2022/ngx-kit-data-table.mjs.map +1 -1
  18. package/fesm2022/ngx-kit-date-picker.mjs +120 -86
  19. package/fesm2022/ngx-kit-date-picker.mjs.map +1 -1
  20. package/fesm2022/ngx-kit-dialog.mjs +38 -7
  21. package/fesm2022/ngx-kit-dialog.mjs.map +1 -1
  22. package/fesm2022/ngx-kit-drawer-menu.mjs +190 -0
  23. package/fesm2022/ngx-kit-drawer-menu.mjs.map +1 -0
  24. package/fesm2022/ngx-kit-dropzone.mjs +272 -0
  25. package/fesm2022/ngx-kit-dropzone.mjs.map +1 -0
  26. package/fesm2022/ngx-kit-form-field.mjs +87 -0
  27. package/fesm2022/ngx-kit-form-field.mjs.map +1 -0
  28. package/fesm2022/ngx-kit-gallery.mjs +419 -0
  29. package/fesm2022/ngx-kit-gallery.mjs.map +1 -0
  30. package/fesm2022/ngx-kit-gradient-picker.mjs +12 -4
  31. package/fesm2022/ngx-kit-gradient-picker.mjs.map +1 -1
  32. package/fesm2022/ngx-kit-image-editor.mjs +501 -0
  33. package/fesm2022/ngx-kit-image-editor.mjs.map +1 -0
  34. package/fesm2022/ngx-kit-menu.mjs +9 -4
  35. package/fesm2022/ngx-kit-menu.mjs.map +1 -1
  36. package/fesm2022/ngx-kit-message.mjs +50 -24
  37. package/fesm2022/ngx-kit-message.mjs.map +1 -1
  38. package/fesm2022/ngx-kit-notify.mjs +1 -4
  39. package/fesm2022/ngx-kit-notify.mjs.map +1 -1
  40. package/fesm2022/ngx-kit-shared.mjs +126 -83
  41. package/fesm2022/ngx-kit-shared.mjs.map +1 -1
  42. package/fesm2022/ngx-kit-time-picker.mjs +602 -0
  43. package/fesm2022/ngx-kit-time-picker.mjs.map +1 -0
  44. package/fesm2022/ngx-kit.mjs.map +1 -1
  45. package/gallery/README.md +71 -0
  46. package/gradient-picker/README.md +41 -0
  47. package/image-editor/README.md +44 -0
  48. package/menu/README.md +85 -0
  49. package/message/README.md +70 -0
  50. package/notify/README.md +56 -0
  51. package/package.json +25 -1
  52. package/shared/README.md +117 -0
  53. package/styles/all.css +27 -0
  54. package/styles/image-viewer.css +12 -0
  55. package/types/ngx-kit-box-shadow.d.ts +1 -2
  56. package/types/ngx-kit-data-table.d.ts +1 -0
  57. package/types/ngx-kit-date-picker.d.ts +1 -1
  58. package/types/ngx-kit-dialog.d.ts +1 -0
  59. package/types/ngx-kit-drawer-menu.d.ts +101 -0
  60. package/types/ngx-kit-dropzone.d.ts +84 -0
  61. package/types/ngx-kit-form-field.d.ts +31 -0
  62. package/types/ngx-kit-gallery.d.ts +168 -0
  63. package/types/ngx-kit-image-editor.d.ts +175 -0
  64. package/types/ngx-kit-menu.d.ts +1 -0
  65. package/types/ngx-kit-message.d.ts +13 -3
  66. package/types/ngx-kit-notify.d.ts +0 -1
  67. package/types/ngx-kit-shared.d.ts +44 -13
  68. package/types/ngx-kit-time-picker.d.ts +149 -0
@@ -0,0 +1,117 @@
1
+ # ngx-kit/shared
2
+
3
+ ابزارها و سرویس‌های مشترکی که بقیه‌ی بسته‌های `ngx-kit` روشون بنا شدن: مدیریت اورلی/دیالوگ، تشخیص جهت صفحه (RTL/LTR)، تشخیص تنظیمات مرورگر، و چند کامپوننت پایه‌ی قابل‌استفاده‌ی مجدد (اسلایدر، رنج‌اسلایدر، صفحه‌ی اشباع رنگ).
4
+
5
+ معمولاً مستقیم به این پکیج نیازی ندارید — بقیه‌ی بسته‌ها به‌صورت خودکار بهش وابسته‌ان. ولی اگه دارید یه کامپوننت سفارشی می‌سازید که باید با بقیه‌ی کتابخونه هم‌خونی داشته باشه (دارک‌مود، RTL، درگ‌وپرفورمنس)، از همین ابزارها استفاده کنید.
6
+
7
+ ## نصب
8
+
9
+ ```bash
10
+ npm install ngx-kit
11
+ ```
12
+
13
+ سبک‌های پایه (شامل `color-scheme` که دارک‌مود رو فعال می‌کنه) رو یک‌بار در سراسر اپ ایمپورت کنید:
14
+
15
+ ```scss
16
+ // styles.scss
17
+ @import 'ngx-kit/styles/all.css';
18
+ ```
19
+
20
+ ## سرویس‌ها
21
+
22
+ ### `OverlayService`
23
+
24
+ موتور اصلی پشتِ همه‌ی چیزهای شناور کتابخونه (منو، دیالوگ، پاپ‌آپ‌های رنگ/گرادیان/زاویه). یک المنت انگولاری رو داخل یک `<dialog>` بومیِ مرورگر (`showModal()`) نمایش می‌ده و نسبت به یک anchor موقعیت‌دهی می‌کنه.
25
+
26
+ ```ts
27
+ import { OverlayService } from 'ngx-kit/shared';
28
+
29
+ const overlay = inject(OverlayService);
30
+ const viewContainerRef = inject(ViewContainerRef);
31
+
32
+ const ref = overlay.open({
33
+ component: MyComponent,
34
+ viewContainerRef,
35
+ anchor: buttonElementRef.nativeElement,
36
+ placement: 'bottom', // 'top' | 'bottom' | 'auto'
37
+ alignment: 'start', // 'start' | 'center' | 'end'
38
+ margin: 8,
39
+ });
40
+
41
+ ref.close(); // OverlayRef.close() آرگومان یا afterClosed نداره؛ برای اون‌جور رفتار (نتیجه‌ی بازگشتی، افترکلوز) از ngx-kit/dialog استفاده کنید که روی همین سرویس بنا شده
42
+ ```
43
+
44
+ چیزهایی که به‌صورت خودکار برات مدیریت می‌شه:
45
+
46
+ - **موقعیت‌دهی هوشمند**: اگه فضای کافی پایین anchor نباشه، خودکار بالا می‌ره (`placement:'auto'`).
47
+ - **بستن با کلیک بیرون**: با تشخیص کلیک روی backdrop، نه با listener سراسری روی document.
48
+ - **پشته‌بندی درست**: چند اورلیِ هم‌زمان (مثلاً یه منوی زیرمنو‌دار) درست کار می‌کنن؛ Escape فقط آخرین (بالاترین) اورلی رو می‌بنده.
49
+ - **بازگشتِ فوکوس**: بعد از بسته‌شدن، فوکوس به همون المنتی که قبلش فوکوس داشت برمی‌گرده (دسترس‌پذیری).
50
+ - **RTL خودکار**: alignment و placement بر اساس جهت واقعیِ صفحه (نه فقط یه فرض ثابت) حساب می‌شن.
51
+
52
+ ### `DirectionService`
53
+
54
+ یه سیگنال (`isRtl(): boolean`) که با `MutationObserver` روی attribute-ی `dir` عنصر `<html>` گوش می‌ده و به‌محض تغییرش، ری‌اکتیو آپدیت می‌شه — یعنی اگه اپ شما زبان رو runtime عوض کنه، همه‌چیز خودکار هماهنگ می‌مونه.
55
+
56
+ ```ts
57
+ const direction = inject(DirectionService);
58
+ direction.isRtl(); // signal<boolean>
59
+ ```
60
+
61
+ ### `BrowserService`
62
+
63
+ ```ts
64
+ const browser = inject(BrowserService);
65
+ browser.prefersDarkMode; // boolean — یه‌بار در لحظه‌ی ساخت سرویس خونده می‌شه
66
+ ```
67
+
68
+ ## ابزارهای Utility
69
+
70
+ ### `startDragSession(callbacks)`
71
+
72
+ جایگزینِ الگوی مشکل‌دارِ `@HostListener('document:mousemove', ...)` که listener رو برای کل عمر کامپوننت روی `document` نگه می‌داره (حتی وقتی دراگی در جریان نیست — یه مشکل واقعیِ پرفورمنس روی صفحاتی با چند نمونه‌ی هم‌زمان). این تابع فقط در طول یک درگِ واقعی، listener اضافه می‌کنه و خودش پاک می‌کنه؛ `touchmove` هم با `{passive:false}` مدیریت می‌شه، پس درگ‌کردن روی موبایل صفحه رو اسکرول نمی‌کنه.
73
+
74
+ ```ts
75
+ import { startDragSession } from 'ngx-kit/shared';
76
+
77
+ let stop: (() => void) | undefined;
78
+
79
+ function onPointerDown(ev: MouseEvent | TouchEvent) {
80
+ stop?.();
81
+ stop = startDragSession({
82
+ onMove: (ev) => {
83
+ /* آپدیت موقعیت */
84
+ },
85
+ onEnd: () => {
86
+ stop = undefined;
87
+ },
88
+ });
89
+ }
90
+ ```
91
+
92
+ > اگه کامپوننت‌تون `OnPush` هست و از `startDragSession` (به‌جای `@HostListener`) استفاده می‌کنید، حتماً داخل `onMove`/`onEnd` خودتون `ChangeDetectorRef.markForCheck()` رو صدا بزنید — برخلاف `@HostListener` که خودکار view رو dirty می‌کنه، `addEventListener` دستی این کار رو نمی‌کنه.
93
+
94
+ ### `getOffsetPosition(event, element)`
95
+
96
+ موقعیت pointer/touch رو نسبت به گوشه‌ی بالا-چپِ یه المنت مشخص برمی‌گردونه؛ برای پیاده‌سازیِ کامپوننت‌های درگ‌محور (اسلایدر، انتخاب‌گر رنگ و ...) استفاده می‌شه.
97
+
98
+ ### `mergeConfig(base, override)`
99
+
100
+ ادغام عمیقِ دو آبجکت کانفیگ (برای الگوی `provideXxx({...})` که همه‌ی کتابخونه ازش استفاده می‌کنه).
101
+
102
+ ## کامپوننت‌های پایه
103
+
104
+ اینا رو مستقیم هم می‌شه استفاده کرد، ولی بیشتر به‌عنوان بلوک‌های سازنده‌ی کامپوننت‌های دیگه (مثل `color-picker`, `box-shadow`) طراحی شدن:
105
+
106
+ | کامپوننت | Selector | توضیح |
107
+ | ---------------------- | -------------------- | ------------------------------------------------------------------- |
108
+ | `SliderComponent` | `slider` | اسلایدر تک‌مقداره، `ControlValueAccessor`، `[min]`/`[max]`/`[step]` |
109
+ | `RangeSliderComponent` | `range-slider` | اسلایدر بازه‌ای (دو thumb) |
110
+ | `SaturationComponent` | داخلی (color-picker) | صفحه‌ی دوبعدیِ انتخاب اشباع/روشنایی رنگ |
111
+
112
+ ## دارک‌مود و RTL
113
+
114
+ هر دو مستقیماً روی `ngx-kit/shared` تکیه دارن:
115
+
116
+ - **دارک‌مود**: از تابع CSS بومیِ `light-dark()` استفاده می‌شه. برای این‌که کار کنه، باید `color-scheme: light dark` (یا `only light`/`only dark` برای force کردن دستی) روی `:root` ست بشه — این کار با ایمپورت‌کردن `ngx-kit/styles/all.css` خودکار انجام می‌شه. برای force کردن دستیِ تم (مستقل از `prefers-color-scheme` سیستم)، `data-ngx-theme="dark"` یا `"light"` رو روی `<html>`/`<body>` بذارید.
117
+ - **RTL**: با `dir="rtl"` روی `<html>` فعال می‌شه؛ همه‌جای کتابخونه از CSS logical properties (`inset-inline-start` و ...) استفاده شده، پس نیازی به استایل جداگانه نیست.
package/styles/all.css CHANGED
@@ -1,3 +1,17 @@
1
+ :root {
2
+ color-scheme: light dark;
3
+ }
4
+
5
+ :root[data-ngx-theme=light],
6
+ [data-ngx-theme=light] {
7
+ color-scheme: only light;
8
+ }
9
+
10
+ :root[data-ngx-theme=dark],
11
+ [data-ngx-theme=dark] {
12
+ color-scheme: only dark;
13
+ }
14
+
1
15
  dialog.ngx-ui-overlay::backdrop {
2
16
  background: transparent;
3
17
  }
@@ -20,6 +34,19 @@ dialog.ngx-ui-overlay::backdrop {
20
34
  opacity: 0;
21
35
  }
22
36
  }
37
+ dialog.ngx-image-viewer-dialog {
38
+ border: none;
39
+ padding: 1rem;
40
+ max-inline-size: 96vw;
41
+ max-block-size: 96vh;
42
+ inline-size: min(900px, 96vw);
43
+ background: light-dark(#ffffff, #1c1c20);
44
+ border-radius: 12px;
45
+ }
46
+ dialog.ngx-image-viewer-dialog::backdrop {
47
+ background: rgba(0, 0, 0, 0.75);
48
+ }
49
+
23
50
  /* ---------- confetti (success only) ---------- */
24
51
  .confetti {
25
52
  position: absolute;
@@ -0,0 +1,12 @@
1
+ dialog.ngx-image-viewer-dialog {
2
+ border: none;
3
+ padding: 1rem;
4
+ max-inline-size: 96vw;
5
+ max-block-size: 96vh;
6
+ inline-size: min(900px, 96vw);
7
+ background: light-dark(#ffffff, #1c1c20);
8
+ border-radius: 12px;
9
+ }
10
+ dialog.ngx-image-viewer-dialog::backdrop {
11
+ background: rgba(0, 0, 0, 0.75);
12
+ }
@@ -36,6 +36,7 @@ declare class NgxBoxShadowComponent implements OnInit, AfterViewInit, OnDestroy,
36
36
  protected _onChange: (value: string) => void;
37
37
  protected _onTouched: () => void;
38
38
  _onValidateChange: () => void;
39
+ private stopDrag?;
39
40
  pad: ElementRef<HTMLDivElement>;
40
41
  thumb: ElementRef<HTMLDivElement>;
41
42
  browserService: BrowserService;
@@ -53,9 +54,7 @@ declare class NgxBoxShadowComponent implements OnInit, AfterViewInit, OnDestroy,
53
54
  private updateRects;
54
55
  private resetPosition;
55
56
  onResize(): void;
56
- onDrag(ev: MouseEvent | TouchEvent): void;
57
57
  private updatePosition;
58
- onDragEnd(ev: MouseEvent | TouchEvent): void;
59
58
  setValueByPosition(thumbRec: DOMRect, padRec: DOMRect): void;
60
59
  onChangeValue(): void;
61
60
  private convertValueToPosition;
@@ -270,6 +270,7 @@ declare class NgxTable<T extends object> implements OnInit, AfterContentInit {
270
270
  private templateMap;
271
271
  protected readonly resolvedMultiSort: _angular_core.Signal<boolean>;
272
272
  private readonly directionService;
273
+ private readonly destroyRef;
273
274
  protected readonly resolvedDirection: _angular_core.Signal<ngx_kit_shared.Direction>;
274
275
  constructor();
275
276
  ngOnInit(): void;
@@ -285,7 +285,7 @@ declare class NgxInputDatePickerComponent extends NgxDatePickerBase implements C
285
285
  clear(): void;
286
286
  stopPagination(ev: Event): void;
287
287
  static ɵfac: i0.ɵɵFactoryDeclaration<NgxInputDatePickerComponent, never>;
288
- static ɵcmp: i0.ɵɵComponentDeclaration<NgxInputDatePickerComponent, "ngx-datepicker", never, { "setTheme": { "alias": "theme"; "required": false; }; "setConfig": { "alias": "config"; "required": false; }; "locale": { "alias": "locale"; "required": false; }; "setMin": { "alias": "min"; "required": false; }; "setMax": { "alias": "max"; "required": false; }; "view": { "alias": "view"; "required": false; }; }, { "change": "change"; }, never, never, true, never>;
288
+ static ɵcmp: i0.ɵɵComponentDeclaration<NgxInputDatePickerComponent, "ngx-date-picker", never, { "setTheme": { "alias": "theme"; "required": false; }; "setConfig": { "alias": "config"; "required": false; }; "locale": { "alias": "locale"; "required": false; }; "setMin": { "alias": "min"; "required": false; }; "setMax": { "alias": "max"; "required": false; }; "view": { "alias": "view"; "required": false; }; }, { "change": "change"; }, never, never, true, never>;
289
289
  }
290
290
 
291
291
  declare function provideDateAdapters(...additional: DateAdapterRegistration[]): Provider[];
@@ -121,6 +121,7 @@ declare class NgxDialogBodyDirective implements AfterViewInit {
121
121
  }
122
122
 
123
123
  declare class NgxDialogModule {
124
+ private readonly platformId;
124
125
  constructor(parentModule: NgxDialogModule | null, service: NgxOverlayService);
125
126
  static ɵfac: i0.ɵɵFactoryDeclaration<NgxDialogModule, [{ optional: true; skipSelf: true; }, null]>;
126
127
  static ɵmod: i0.ɵɵNgModuleDeclaration<NgxDialogModule, [typeof NgxDialogComponent, typeof NgxDialogHeaderDirective, typeof NgxDialogFooterDirective, typeof NgxDialogBodyDirective], [typeof i5.CommonModule], [typeof NgxDialogComponent, typeof NgxDialogHeaderDirective, typeof NgxDialogFooterDirective, typeof NgxDialogBodyDirective]>;
@@ -0,0 +1,101 @@
1
+ import * as _angular_core from '@angular/core';
2
+
3
+ /**
4
+ * از 'start'/'end' منطقی استفاده می‌کنیم نه 'left'/'right' — یعنی توی
5
+ * RTL خودکار برعکس می‌شه (start یعنی راست در RTL، چپ در LTR)، دقیقاً هماهنگ
6
+ * با بقیه‌ی کتابخونه که همه‌جا از پراپرتی‌های منطقیِ CSS استفاده می‌کنه.
7
+ */
8
+ type NgxDrawerSide = 'start' | 'end';
9
+ /**
10
+ * جلوه‌ی بازوبسته‌شدنِ خودِ پنل:
11
+ * - slide: اسلاید ساده‌ی کلاسیک
12
+ * - curtain: چند نوار عمودیِ هم‌رنگِ پنل که با تأخیرِ پلکانی جمع می‌شن و
13
+ * محتوا رو نمایان می‌کنن — حسِ باز شدنِ یه پرده‌ی چندلَته
14
+ * - jelly: بازشدن با افکتِ ژله‌ای/کشسان — چند نوسانِ فنری که رفته‌رفته
15
+ * فروکش می‌کنه (الهام از https://dribbble.com/shots/2307371)
16
+ * - pull: یه کشیدگیِ لاستیکیِ تک‌ضربه‌ای — لبه‌ی پنل از اندازه‌ی نهایی رد
17
+ * می‌شه و برمی‌گرده سرجاش (rubber-band)
18
+ * - rotate3d: چرخشِ سه‌بعدیِ دور لولا (مثل باز شدنِ یه در)، با perspective
19
+ * - flip3d: پنل و محتوای صفحه با هم مثل ورق‌زدنِ یه کتاب می‌چرخن
20
+ * - scale: بزرگ‌شدن از مرکز همراه با fade
21
+ */
22
+ type NgxDrawerEffect = 'slide' | 'curtain' | 'jelly' | 'pull' | 'rotate3d' | 'flip3d' | 'scale';
23
+ /**
24
+ * رفتار محتوای اصلیِ صفحه وقتی درور باز می‌شه:
25
+ * - overlay: محتوا سرجاش می‌مونه، درور روش شناور می‌شه (با بک‌دراپ)
26
+ * - push: محتوا به‌اندازه‌ی عرضِ درور هل داده می‌شه (کنار می‌ره)
27
+ * - reveal: محتوا کمی کوچیک/عقب می‌ره، انگار درور از زیرش نمایان می‌شه
28
+ * (همون افکت معروف iOS)
29
+ */
30
+ type NgxDrawerContentBehavior = 'overlay' | 'push' | 'reveal';
31
+
32
+ /**
33
+ * درور منو (side drawer) با ۶ جلوه‌ی بازوبسته‌شدنِ متفاوت (از ساده تا
34
+ * سه‌بعدی/ژله‌ای) و ۳ رفتار برای محتوای صفحه (overlay/push/reveal) —
35
+ * دقیقاً مدل کتابخونه‌های حرفه‌ای مثل react-burger-menu یا Ionic Menu، ولی
36
+ * signal-based و بدون هیچ وابستگی خارجی.
37
+ *
38
+ * نکات معماری:
39
+ * - از 'start'/'end' منطقی استفاده می‌کنه، پس با CSS logical properties
40
+ * زیر RTL خودکار برعکس می‌شه؛ فقط ریاضیِ درگ (که برخلاف CSS جهت فیزیکیِ
41
+ * واقعی لازم داره) از DirectionService مشترک استفاده می‌کنه.
42
+ * - وضعیت باز/بسته با model() دوطرفه‌ست، پس هم با [(open)] قابل کنترله و
43
+ * هم می‌تونه به‌صورت خودکار و زنده با عرض صفحه هماهنگ بشه (respondToViewport)
44
+ * — یعنی رد شدن از breakpoint (نه فقط بار اول لود) می‌تونه خودکار باز/بسته‌ش کنه.
45
+ * - افکت‌های jelly/pull با keyframe سه‌مرحله‌ای (overshoot → نوسان → استقرار)
46
+ * پیاده شدن، نه فقط یه transition ساده.
47
+ */
48
+ declare class NgxDrawerMenuComponent {
49
+ side: _angular_core.InputSignal<NgxDrawerSide>;
50
+ effect: _angular_core.InputSignal<NgxDrawerEffect>;
51
+ contentBehavior: _angular_core.InputSignal<NgxDrawerContentBehavior>;
52
+ width: _angular_core.InputSignal<number>;
53
+ swipeEdgeSize: _angular_core.InputSignal<number>;
54
+ curtainStrips: _angular_core.InputSignal<number>;
55
+ backdropClose: _angular_core.InputSignal<boolean>;
56
+ swipeEnabled: _angular_core.InputSignal<boolean>;
57
+ /** اگه true باشه، رد شدن از mobileBreakpoint به‌صورت زنده open رو با openOnDesktop/openOnMobile هماهنگ می‌کنه */
58
+ respondToViewport: _angular_core.InputSignal<boolean>;
59
+ openOnDesktop: _angular_core.InputSignal<boolean>;
60
+ openOnMobile: _angular_core.InputSignal<boolean>;
61
+ mobileBreakpoint: _angular_core.InputSignal<number>;
62
+ /** state دوطرفه‌ی باز/بسته؛ با [(open)] قابل bind هست */
63
+ open: _angular_core.ModelSignal<boolean>;
64
+ private readonly directionService;
65
+ private readonly doc;
66
+ private readonly destroyRef;
67
+ /** فقط حین یه درگِ واقعی مقدار داره؛ null یعنی از روی open() تصمیم بگیر */
68
+ protected readonly dragRatio: _angular_core.WritableSignal<number | null>;
69
+ protected readonly isDragging: _angular_core.Signal<boolean>;
70
+ protected readonly visualOpen: _angular_core.Signal<number>;
71
+ protected readonly strips: _angular_core.Signal<number[]>;
72
+ /**
73
+ * +۱ یعنی این پنل فیزیکاً روی لبه‌ی چپِ صفحه‌ست، -۱ یعنی لبه‌ی راست —
74
+ * برای transform:translateX() محتوای اصلی (که برخلاف inset-inline، به
75
+ * dir=rtl خودکار واکنش نشون نمی‌ده) لازمه. reactive هست چون هم به side()
76
+ * و هم به جهتِ زنده‌ی صفحه (directionService.isRtl()) وابسته‌ست.
77
+ */
78
+ protected readonly pushDirSign: _angular_core.Signal<1 | -1>;
79
+ /** برای افکت‌های keyframe‌محور (jelly/pull) — فقط لحظه‌ی رهاشدن (نه حین درگ زنده) پخش می‌شه */
80
+ protected readonly playEffectClass: _angular_core.WritableSignal<boolean>;
81
+ private stopDrag?;
82
+ private dragStartX;
83
+ private dragStartRatio;
84
+ private prevOpen;
85
+ constructor();
86
+ protected onEscape(): void;
87
+ protected closeFromBackdrop(): void;
88
+ toggle(): void;
89
+ /** true یعنی این پنل فیزیکاً روی لبه‌ی چپِ صفحه‌ست (صرف‌نظر از start/end منطقی) */
90
+ private isPhysicalLeftEdge;
91
+ protected stripDelay(index: number): string;
92
+ protected onEdgeDragStart(ev: MouseEvent | TouchEvent): void;
93
+ protected onPanelDragStart(ev: MouseEvent | TouchEvent): void;
94
+ private beginDrag;
95
+ private clientXOf;
96
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgxDrawerMenuComponent, never>;
97
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NgxDrawerMenuComponent, "ngx-drawer-menu", never, { "side": { "alias": "side"; "required": false; "isSignal": true; }; "effect": { "alias": "effect"; "required": false; "isSignal": true; }; "contentBehavior": { "alias": "contentBehavior"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; "swipeEdgeSize": { "alias": "swipeEdgeSize"; "required": false; "isSignal": true; }; "curtainStrips": { "alias": "curtainStrips"; "required": false; "isSignal": true; }; "backdropClose": { "alias": "backdropClose"; "required": false; "isSignal": true; }; "swipeEnabled": { "alias": "swipeEnabled"; "required": false; "isSignal": true; }; "respondToViewport": { "alias": "respondToViewport"; "required": false; "isSignal": true; }; "openOnDesktop": { "alias": "openOnDesktop"; "required": false; "isSignal": true; }; "openOnMobile": { "alias": "openOnMobile"; "required": false; "isSignal": true; }; "mobileBreakpoint": { "alias": "mobileBreakpoint"; "required": false; "isSignal": true; }; "open": { "alias": "open"; "required": false; "isSignal": true; }; }, { "open": "openChange"; }, never, ["*", "[drawerContent]"], true, never>;
98
+ }
99
+
100
+ export { NgxDrawerMenuComponent };
101
+ export type { NgxDrawerContentBehavior, NgxDrawerEffect, NgxDrawerSide };
@@ -0,0 +1,84 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { OnDestroy } from '@angular/core';
3
+
4
+ interface NgxDropzoneFile {
5
+ /** شناسه‌ی یکتا برای track کردن توی @for و امکان حذف تکی */
6
+ id: string;
7
+ file: File;
8
+ /** فقط برای فایل‌های تصویری پر می‌شه (object URL) */
9
+ previewUrl?: string;
10
+ status: 'pending' | 'accepted' | 'rejected';
11
+ /** در صورت رد شدن، دلیلش */
12
+ rejectionReason?: NgxDropzoneRejectionReason;
13
+ }
14
+ type NgxDropzoneRejectionReason = 'type' | 'size' | 'count';
15
+ interface NgxDropzoneRejectedFile {
16
+ file: File;
17
+ reason: NgxDropzoneRejectionReason;
18
+ }
19
+
20
+ /**
21
+ * ناحیه‌ی درگ‌اند‌دراپِ فایل — کاملاً مستقل (بدون وابستگی به هیچ lib
22
+ * دیگه‌ای، حتی shared)، signal-based و OnPush.
23
+ *
24
+ * ویژگی‌های مهمی که معمولاً پیاده‌سازی‌های ساده‌ی dropzone ندارن:
25
+ * - شمارنده‌ی dragenter/dragleave: چون dragleave برای فرزندهای داخل
26
+ * dropzone هم شلیک می‌شه، پیاده‌سازی‌های ساده موقع درگ‌کردن روی متن/آیکون
27
+ * داخل ناحیه، حالت "درگ" رو اشتباهی خاموش می‌کنن (چشمک‌زدن). این‌جا با
28
+ * شمارنده حل شده.
29
+ * - پیمایش بازگشتیِ پوشه‌ها (وقتی کاربر یه پوشه رو درگ کنه، نه فقط فایل).
30
+ * - قابل‌دسترسی با کیبورد (focusable + Enter/Space).
31
+ * - پاک‌سازی object URL پیش‌نمایش‌ها روی حذف/destroy (وگرنه نشتی حافظه‌ست).
32
+ */
33
+ declare class NgxDropzoneComponent implements OnDestroy {
34
+ /** الگوی accept مثل input[type=file]: "image/*", ".pdf,.docx" و ... */
35
+ accept: _angular_core.InputSignal<string>;
36
+ multiple: _angular_core.InputSignal<boolean>;
37
+ /** حداکثر حجم هر فایل به بایت؛ undefined یعنی بدون محدودیت */
38
+ maxFileSize: _angular_core.InputSignal<number | undefined>;
39
+ /** حداکثر تعداد فایل مجاز؛ undefined یعنی بدون محدودیت */
40
+ maxFiles: _angular_core.InputSignal<number | undefined>;
41
+ disabled: _angular_core.InputSignal<boolean>;
42
+ /** نمایش لیست/پیش‌نمایش فایل‌های انتخاب‌شده داخل خودِ کامپوننت */
43
+ showFileList: _angular_core.InputSignal<boolean>;
44
+ filesAdded: _angular_core.OutputEmitterRef<File[]>;
45
+ filesRejected: _angular_core.OutputEmitterRef<NgxDropzoneRejectedFile[]>;
46
+ /** کل لیست فعلی (بعد از هر تغییر) — برای binding راحت‌تر */
47
+ filesChange: _angular_core.OutputEmitterRef<File[]>;
48
+ protected readonly files: _angular_core.WritableSignal<NgxDropzoneFile[]>;
49
+ protected readonly isDragging: _angular_core.WritableSignal<boolean>;
50
+ private dragCounter;
51
+ private readonly fileInput;
52
+ protected readonly hint: _angular_core.Signal<string>;
53
+ protected formatSize(bytes: number): string;
54
+ ngOnDestroy(): void;
55
+ protected onDragEnter(ev: DragEvent): void;
56
+ protected onDragOver(ev: DragEvent): void;
57
+ protected onDragLeave(ev: DragEvent): void;
58
+ protected onDrop(ev: DragEvent): Promise<void>;
59
+ protected onBrowseClick(): void;
60
+ protected onKeydown(ev: KeyboardEvent): void;
61
+ protected onFileInputChange(ev: Event): void;
62
+ protected removeFile(id: string): void;
63
+ private handleIncomingFiles;
64
+ private emitCurrentFiles;
65
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgxDropzoneComponent, never>;
66
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NgxDropzoneComponent, "ngx-dropzone", never, { "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "maxFileSize": { "alias": "maxFileSize"; "required": false; "isSignal": true; }; "maxFiles": { "alias": "maxFiles"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "showFileList": { "alias": "showFileList"; "required": false; "isSignal": true; }; }, { "filesAdded": "filesAdded"; "filesRejected": "filesRejected"; "filesChange": "filesChange"; }, never, ["[dropzone-icon]", "*"], true, never>;
67
+ }
68
+
69
+ /**
70
+ * چک می‌کنه یه فایل با pattern رشته‌ای accept (مثل input[type=file])
71
+ * مطابقت داره یا نه. پشتیبانی می‌شه از:
72
+ * - MIME کامل: "image/png"
73
+ * - MIME با wildcard: "image/*"
74
+ * - پسوند فایل: ".png", ".jpg"
75
+ * - لیست کاما-جدا از موارد بالا: "image/*,.pdf,.docx"
76
+ */
77
+ declare function matchesAccept(file: File, accept?: string): boolean;
78
+ /** تبدیل بایت به یه رشته‌ی خوانا (KB/MB/GB) */
79
+ declare function formatBytes(bytes: number): string;
80
+ /** استخراج فایل‌های واقعی از یک DataTransfer، شامل پیمایش بازگشتیِ پوشه‌ها (وقتی مرورگر پشتیبانی کنه) */
81
+ declare function extractFilesFromDataTransfer(dataTransfer: DataTransfer): Promise<File[]>;
82
+
83
+ export { NgxDropzoneComponent, extractFilesFromDataTransfer, formatBytes, matchesAccept };
84
+ export type { NgxDropzoneFile, NgxDropzoneRejectedFile, NgxDropzoneRejectionReason };
@@ -0,0 +1,31 @@
1
+ import * as _angular_core from '@angular/core';
2
+
3
+ type NgxFormFieldType = 'text' | 'password' | 'email' | 'number' | 'tel' | 'url' | 'search' | 'textarea';
4
+
5
+ declare class NgxFormField {
6
+ readonly value: _angular_core.ModelSignal<string | number>;
7
+ readonly label: _angular_core.InputSignal<string>;
8
+ readonly type: _angular_core.InputSignal<NgxFormFieldType>;
9
+ readonly placeholder: _angular_core.InputSignal<string>;
10
+ readonly required: _angular_core.InputSignal<boolean>;
11
+ readonly disabled: _angular_core.InputSignal<boolean>;
12
+ readonly readonly: _angular_core.InputSignal<boolean>;
13
+ readonly float: _angular_core.InputSignal<boolean>;
14
+ readonly name: _angular_core.InputSignal<string | null>;
15
+ readonly autocomplete: _angular_core.InputSignal<string | null>;
16
+ readonly rows: _angular_core.InputSignal<number>;
17
+ readonly hint: _angular_core.InputSignal<string>;
18
+ readonly errorMessages: _angular_core.InputSignal<string[]>;
19
+ readonly dir: _angular_core.InputSignal<"" | "ltr" | "rtl">;
20
+ readonly id: _angular_core.InputSignal<string>;
21
+ readonly focused: _angular_core.OutputEmitterRef<void>;
22
+ readonly blurred: _angular_core.OutputEmitterRef<void>;
23
+ readonly hasValue: _angular_core.Signal<boolean>;
24
+ onInput(event: Event): void;
25
+ onFocus(): void;
26
+ onBlur(): void;
27
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgxFormField, never>;
28
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NgxFormField, "ngx-form-field", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": true; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "float": { "alias": "float"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "autocomplete": { "alias": "autocomplete"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "errorMessages": { "alias": "errorMessages"; "required": false; "isSignal": true; }; "dir": { "alias": "dir"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "focused": "focused"; "blurred": "blurred"; }, never, never, true, never>;
29
+ }
30
+
31
+ export { NgxFormField };
@@ -0,0 +1,168 @@
1
+ import * as _angular_core from '@angular/core';
2
+
3
+ interface NgxImageViewerItem {
4
+ src: string;
5
+ alt?: string;
6
+ caption?: string;
7
+ /** نام فایل هنگام دانلود؛ نبود یعنی از روی src حدس زده می‌شه */
8
+ downloadFileName?: string;
9
+ }
10
+ /**
11
+ * هر دکمه‌ی نوار ابزار جدا فعال/غیرفعال می‌شه — دقیقاً طبق خواسته: «این
12
+ * دکمه‌های کانفیگی باشه که هر کدوم خواست فعال کنه».
13
+ */
14
+ interface NgxImageViewerToolbarConfig {
15
+ prevNext?: boolean;
16
+ counter?: boolean;
17
+ zoomIn?: boolean;
18
+ zoomOut?: boolean;
19
+ resetZoom?: boolean;
20
+ rotateLeft?: boolean;
21
+ rotateRight?: boolean;
22
+ download?: boolean;
23
+ print?: boolean;
24
+ fullscreen?: boolean;
25
+ close?: boolean;
26
+ }
27
+ declare const NGX_IMAGE_VIEWER_DEFAULT_TOOLBAR: Required<NgxImageViewerToolbarConfig>;
28
+
29
+ /**
30
+ * ویوئر حرفه‌ایِ تصویر: یه لیست تصویر می‌گیره، اولی رو نشون می‌ده، با
31
+ * دکمه‌های چپ/راست (مثل کاروسل) بین‌شون می‌ره، و یه نوار ابزار کاملاً
32
+ * قابل‌تنظیم (هر دکمه جدا فعال/غیرفعال می‌شه) داره: زوم این/اوت/ریست،
33
+ * چرخش، دانلود، پرینت، تمام‌صفحه.
34
+ *
35
+ * تعامل‌ها:
36
+ * - اسکرول موس روی تصویر = زوم (نسبت به همون نقطه‌ی زیر cursor، نه مرکز)
37
+ * - دو انگشتی روی تاچ = پینچ زوم
38
+ * - وقتی زوم‌شده، درگ با موس یا تک‌انگشتی = پن
39
+ * - کیبورد: ← → برای قبلی/بعدی، +/- برای زوم، Esc برای closed
40
+ *
41
+ * چون wheel/touchmove باید preventDefault بشن (وگرنه صفحه اسکرول/زوم
42
+ * می‌شه) و انگیولار این ایونت‌ها رو به‌صورت پیش‌فرض passive رجیستر می‌کنه
43
+ * (که توش preventDefault اثر نداره)، این‌ها با addEventListener دستی و
44
+ * {passive:false} وصل می‌شن، نه با بایندینگ تمپلیت.
45
+ *
46
+ * می‌تونه هم مستقیم توی صفحه جا بگیره، هم توسط مصرف‌کننده داخل
47
+ * ngx-kit/dialog (یا هر overlay دیگه) قرار بگیره — خودش به هیچ‌کدوم وابسته
48
+ * نیست، فقط با closed خروجی به بیرون خبر می‌ده که «ببندم».
49
+ */
50
+ declare class NgxImageViewerComponent {
51
+ images: _angular_core.InputSignal<NgxImageViewerItem[]>;
52
+ startIndex: _angular_core.InputSignal<number>;
53
+ toolbar: _angular_core.InputSignal<NgxImageViewerToolbarConfig>;
54
+ minZoom: _angular_core.InputSignal<number>;
55
+ maxZoom: _angular_core.InputSignal<number>;
56
+ zoomStep: _angular_core.InputSignal<number>;
57
+ indexChange: _angular_core.OutputEmitterRef<number>;
58
+ closed: _angular_core.OutputEmitterRef<void>;
59
+ protected readonly activeIndex: _angular_core.WritableSignal<number>;
60
+ protected readonly zoom: _angular_core.WritableSignal<number>;
61
+ protected readonly panX: _angular_core.WritableSignal<number>;
62
+ protected readonly panY: _angular_core.WritableSignal<number>;
63
+ protected readonly rotation: _angular_core.WritableSignal<number>;
64
+ protected readonly activeImage: _angular_core.Signal<NgxImageViewerItem | undefined>;
65
+ protected readonly toolbarConfig: _angular_core.Signal<{
66
+ prevNext: boolean;
67
+ counter: boolean;
68
+ zoomIn: boolean;
69
+ zoomOut: boolean;
70
+ resetZoom: boolean;
71
+ rotateLeft: boolean;
72
+ rotateRight: boolean;
73
+ download: boolean;
74
+ print: boolean;
75
+ fullscreen: boolean;
76
+ close: boolean;
77
+ }>;
78
+ protected readonly isZoomed: _angular_core.Signal<boolean>;
79
+ protected readonly stageTransform: _angular_core.Signal<string>;
80
+ private readonly stageEl;
81
+ private readonly hostElRef;
82
+ private readonly destroyRef;
83
+ private pinchStartDistance;
84
+ private pinchStartZoom;
85
+ private stopPanDrag?;
86
+ constructor();
87
+ protected onKeydown(ev: KeyboardEvent): void;
88
+ protected next(): void;
89
+ protected prev(): void;
90
+ protected goTo(index: number): void;
91
+ protected zoomIn(): void;
92
+ protected zoomOut(): void;
93
+ protected resetView(): void;
94
+ protected rotateLeft(): void;
95
+ protected rotateRight(): void;
96
+ protected download(): Promise<void>;
97
+ protected print(): void;
98
+ protected toggleFullscreen(): void;
99
+ protected close(): void;
100
+ protected onPanPointerDown(ev: MouseEvent): void;
101
+ private beginPanDrag;
102
+ private setZoomAtCenter;
103
+ private applyZoomAt;
104
+ private clientXOf;
105
+ private clientYOf;
106
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgxImageViewerComponent, never>;
107
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NgxImageViewerComponent, "ngx-image-viewer", never, { "images": { "alias": "images"; "required": true; "isSignal": true; }; "startIndex": { "alias": "startIndex"; "required": false; "isSignal": true; }; "toolbar": { "alias": "toolbar"; "required": false; "isSignal": true; }; "minZoom": { "alias": "minZoom"; "required": false; "isSignal": true; }; "maxZoom": { "alias": "maxZoom"; "required": false; "isSignal": true; }; "zoomStep": { "alias": "zoomStep"; "required": false; "isSignal": true; }; }, { "indexChange": "indexChange"; "closed": "closed"; }, never, never, true, never>;
108
+ }
109
+
110
+ interface NgxImageViewerOpenOptions {
111
+ startIndex?: number;
112
+ toolbar?: NgxImageViewerToolbarConfig;
113
+ minZoom?: number;
114
+ maxZoom?: number;
115
+ zoomStep?: number;
116
+ }
117
+ /**
118
+ * راه میان‌بر برای وقتی که کاربر می‌خواد ویوئر رو داخل یه دیالوگِ تمام‌صفحه
119
+ * باز کنه، بدون این‌که خودش دستی wire کنه. اگه کسی می‌خواد داخل دیالوگِ
120
+ * خودش (مثلاً ngx-kit/dialog) بذارتش، کافیه مستقیم از NgxImageViewerComponent
121
+ * استفاده کنه — این سرویس صرفاً یه میان‌بَره، وابستگی اجباری نیست.
122
+ *
123
+ * دقیقاً همون الگوی امن‌شده‌ی NgxMessageService: با Map<id, ComponentRef> و
124
+ * detachView قبل از destroy، تا اون نشتی حافظه‌ای که قبلاً توی message
125
+ * service پیدا و رفع شد، اینجا از اول تکرار نشه.
126
+ */
127
+ declare class NgxImageViewerService {
128
+ private readonly appRef;
129
+ private readonly envInjector;
130
+ private nextId;
131
+ private readonly openInstances;
132
+ open(images: NgxImageViewerItem[], options?: NgxImageViewerOpenOptions): {
133
+ close: () => void;
134
+ };
135
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgxImageViewerService, never>;
136
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<NgxImageViewerService>;
137
+ }
138
+
139
+ interface PanZoomState {
140
+ zoom: number;
141
+ panX: number;
142
+ panY: number;
143
+ }
144
+ /**
145
+ * با تغییر zoom، pan رو طوری تنظیم می‌کنه که نقطه‌ی زیر cursor/انگشت‌ها
146
+ * (نسبت به مرکز کانتینر) سرجاش بمونه — یعنی zoom-to-cursor به‌جای
147
+ * zoom-to-center (که تجربه‌ی خیلی بهتری داره، دقیقاً مثل هر ویوئر حرفه‌ای).
148
+ *
149
+ * ریاضیِ پشتش: با transform="translate(panX,panY) scale(zoom)"، موقعیتِ
150
+ * صفحه‌ایِ یه نقطه‌ی محلیِ p (نسبت به مرکز) برابره با
151
+ * center + pan + p*zoom. اول p رو از روی وضعیت فعلی حساب می‌کنیم، بعد pan
152
+ * جدید رو طوری می‌سازیم که با zoom تازه، همون p به همون مختصات صفحه برسه.
153
+ */
154
+ declare function zoomAroundPoint(current: PanZoomState, newZoom: number, cursorX: number, cursorY: number, containerWidth: number, containerHeight: number): PanZoomState;
155
+ declare function distanceBetweenTouches(a: Touch, b: Touch): number;
156
+ declare function midpointOfTouches(a: Touch, b: Touch): {
157
+ x: number;
158
+ y: number;
159
+ };
160
+ declare function clamp(value: number, min: number, max: number): number;
161
+
162
+ /** دانلود تصویر با fetch→blob (نام‌گذاریِ درست فایل رو تضمین می‌کنه)؛ اگه CORS اجازه نداد، در تب جدید باز می‌شه */
163
+ declare function downloadImage(src: string, filename?: string): Promise<void>;
164
+ /** یه پنجره‌ی جدید فقط با همون تصویر باز می‌کنه و بعد از لود، print می‌زنه؛ با DOM API (نه innerHTML) پس در برابر src مخرب امنه */
165
+ declare function printImage(src: string): void;
166
+
167
+ export { NGX_IMAGE_VIEWER_DEFAULT_TOOLBAR, NgxImageViewerComponent, NgxImageViewerService, clamp, distanceBetweenTouches, downloadImage, midpointOfTouches, printImage, zoomAroundPoint };
168
+ export type { NgxImageViewerItem, NgxImageViewerOpenOptions, NgxImageViewerToolbarConfig, PanZoomState };