ngx-kit 6.0.1 → 6.0.2

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 (39) hide show
  1. package/angle-selector/README.md +11 -11
  2. package/box-shadow/README.md +10 -10
  3. package/color-picker/README.md +20 -23
  4. package/data-table/README.md +34 -41
  5. package/date-picker/README.md +21 -26
  6. package/dialog/README.md +31 -33
  7. package/drawer-menu/README.md +51 -50
  8. package/dropzone/README.md +27 -26
  9. package/fesm2022/ngx-kit-box-shadow.mjs +2 -2
  10. package/fesm2022/ngx-kit-box-shadow.mjs.map +1 -1
  11. package/fesm2022/ngx-kit-color-picker.mjs +2 -2
  12. package/fesm2022/ngx-kit-color-picker.mjs.map +1 -1
  13. package/fesm2022/ngx-kit-data-table.mjs +68 -26
  14. package/fesm2022/ngx-kit-data-table.mjs.map +1 -1
  15. package/fesm2022/ngx-kit-dropzone.mjs +3 -3
  16. package/fesm2022/ngx-kit-dropzone.mjs.map +1 -1
  17. package/fesm2022/ngx-kit-form-field.mjs +129 -64
  18. package/fesm2022/ngx-kit-form-field.mjs.map +1 -1
  19. package/fesm2022/ngx-kit-gallery.mjs +2 -2
  20. package/fesm2022/ngx-kit-gallery.mjs.map +1 -1
  21. package/fesm2022/ngx-kit-gradient-picker.mjs +2 -2
  22. package/fesm2022/ngx-kit-gradient-picker.mjs.map +1 -1
  23. package/fesm2022/ngx-kit-image-editor.mjs +5 -5
  24. package/fesm2022/ngx-kit-image-editor.mjs.map +1 -1
  25. package/fesm2022/ngx-kit-time-picker.mjs +17 -4
  26. package/fesm2022/ngx-kit-time-picker.mjs.map +1 -1
  27. package/gallery/README.md +29 -29
  28. package/gradient-picker/README.md +16 -16
  29. package/image-editor/README.md +19 -19
  30. package/menu/README.md +27 -27
  31. package/message/README.md +34 -34
  32. package/notify/README.md +25 -23
  33. package/package.json +1 -1
  34. package/shared/README.md +32 -32
  35. package/time-picker/README.md +95 -0
  36. package/types/ngx-kit-data-table.d.ts +25 -5
  37. package/types/ngx-kit-form-field.d.ts +65 -27
  38. package/types/ngx-kit-image-editor.d.ts +1 -1
  39. package/types/ngx-kit-time-picker.d.ts +19 -14
package/message/README.md CHANGED
@@ -1,70 +1,70 @@
1
1
  # ngx-kit/message
2
2
 
3
- دیالوگ‌های alert/confirm (شبیه SweetAlert)، با API استاتیک قابل‌فراخوانی از هرجای اپ.
3
+ Alert/confirm dialogs (SweetAlert-style), with a static API callable from anywhere in the app.
4
4
 
5
- ## نصب
5
+ ## Install
6
6
 
7
7
  ```bash
8
8
  npm install ngx-kit
9
9
  ```
10
10
 
11
- ## راه‌اندازی
11
+ ## Setup
12
12
 
13
- ``` typescript
13
+ ```ts
14
14
  // app.config.ts
15
15
  import { provideMessage } from 'ngx-kit/message';
16
16
 
17
17
  export const appConfig: ApplicationConfig = {
18
- providers: [provideMessage({ confirmButtonText: 'باشه' /* پیش‌فرض‌های سراسری */ })],
18
+ providers: [provideMessage({ confirmButtonText: 'OK' /* global defaults */ })],
19
19
  };
20
20
  ```
21
21
 
22
- ## استفاده
22
+ ## Usage
23
23
 
24
24
  ```ts
25
25
  import { MSG } from 'ngx-kit/message';
26
26
 
27
- MSG.success('ذخیره شد!', 'تغییرات با موفقیت ثبت شدن.');
28
- MSG.error('خطا', 'مشکلی پیش اومد.');
29
- MSG.warning('هشدار', 'مطمئنید؟');
30
- MSG.info('اطلاع', 'این یه پیامِ اطلاعاتیه.');
31
- MSG.question('سؤال', 'ادامه بدیم؟');
32
- MSG.loading('در حال پردازش…');
27
+ MSG.success('Saved!', 'Your changes were saved successfully.');
28
+ MSG.error('Error', 'Something went wrong.');
29
+ MSG.warning('Warning', 'Are you sure?');
30
+ MSG.info('Heads up', 'This is an informational message.');
31
+ MSG.question('Question', 'Continue?');
32
+ MSG.loading('Processing…');
33
33
 
34
- // کنترلِ کامل روی گزینه‌ها:
34
+ // full control over options:
35
35
  const result = MSG.show({
36
- title: 'حذف شود؟',
37
- text: 'این عمل قابل بازگشت نیست.',
36
+ title: 'Delete this?',
37
+ text: 'This action cannot be undone.',
38
38
  showCancelButton: true,
39
39
  showDenyButton: true,
40
- confirmButtonText: 'بله، حذف کن',
40
+ confirmButtonText: 'Yes, delete it',
41
41
  });
42
42
  result.afterClose.subscribe((r) => console.log(r));
43
43
  ```
44
44
 
45
45
  ## API
46
46
 
47
- ### `MSG` (و alias آن `Modal`)
47
+ ### `MSG` (and its alias `Modal`)
48
48
 
49
- | متد | امضا | توضیح |
50
- | ----------------------------------------------------------------- | -------------------------- | --------------- |
51
- | `show(options?)` | `IMessageOptions` | کنترلِ کامل |
52
- | `info` / `success` / `warning` / `error` / `question` / `loading` | `(title, text?, options?)` | میان‌برهای رایج |
49
+ | Method | Signature | Description |
50
+ | --- | --- | --- |
51
+ | `show(options?)` | `IMessageOptions` | Full control |
52
+ | `info` / `success` / `warning` / `error` / `question` / `loading` | `(title, text?, options?)` | Common shortcuts |
53
53
 
54
- ### `IMessageOptions` (مهم‌ترین فیلدها)
54
+ ### `IMessageOptions` (key fields)
55
55
 
56
- | فیلد | نوع | پیش‌فرض | توضیح |
57
- | ----------------------------------------------------------- | ------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------- |
58
- | `title` / `text` / `html` | `string` | | محتوا (`html` سنیتایز نمی‌شه — مسئولیتِ escape با خودتونه) |
59
- | `icon` | `MessageIcon` | | آیکونِ نمایشی |
60
- | `showConfirmButton` / `showDenyButton` / `showCancelButton` | `boolean` | `true` / `false` / `false` | |
61
- | `confirmButtonText` / `denyButtonText` / `cancelButtonText` | `string` | `'OK'` / `'No'` / `'Cancel'` | |
62
- | `allowOutsideClick` / `allowEscapeKey` / `allowEnterKey` | `boolean` | `true` | نحوه‌ی بستنِ پیام |
63
- | `showCloseButton` | `boolean` | `false` | دکمه‌ی ✕ |
64
- | `useOverlay` | `boolean` | | برای وقتی که داخل یه دیالوگِ دیگه (مثلاً Angular Material) استفاده می‌شه، لایه‌ی نمایشی رو به بالاترین سطح می‌بره |
56
+ | Field | Type | Default | Description |
57
+ | --- | --- | --- | --- |
58
+ | `title` / `text` / `html` | `string` | | Content (`html` is not sanitized — escaping is your responsibility) |
59
+ | `icon` | `MessageIcon` | | Icon shown |
60
+ | `showConfirmButton` / `showDenyButton` / `showCancelButton` | `boolean` | `true` / `false` / `false` | |
61
+ | `confirmButtonText` / `denyButtonText` / `cancelButtonText` | `string` | `'OK'` / `'No'` / `'Cancel'` | |
62
+ | `allowOutsideClick` / `allowEscapeKey` / `allowEnterKey` | `boolean` | `true` | How the message can be dismissed |
63
+ | `showCloseButton` | `boolean` | `false` | The ✕ button |
64
+ | `useOverlay` | `boolean` | | For when it's used inside another dialog (e.g. Angular Material), raises the display layer to the top |
65
65
 
66
- اگه چند پیام هم‌زمان باز باشن، Escape/Enter فقط روی **آخرین (بالاترین) پیام** اثر می‌کنه، نه همه‌شون.
66
+ If several messages are open at once, Escape/Enter only affect the **last (topmost) message**, not all of them.
67
67
 
68
- ## دارک‌مود و RTL
68
+ ## Dark mode and RTL
69
69
 
70
- خودکار پشتیبانی می‌شه.
70
+ Supported automatically.
package/notify/README.md CHANGED
@@ -1,56 +1,58 @@
1
1
  # ngx-kit/notify
2
2
 
3
- نوتیفیکیشن/toast گوشه‌ی صفحه، با API استاتیک، صف‌بندیِ خودکار (وقتی تعداد از حد مجاز بیشتر بشه)، و مکث‌کردنِ تایمر روی هاور.
3
+ Corner toast notifications, with a static API, automatic queueing (once the visible count exceeds the limit), and the timer pausing on hover.
4
4
 
5
- ## نصب
5
+ ## Install
6
6
 
7
7
  ```bash
8
8
  npm install ngx-kit
9
9
  ```
10
10
 
11
- ## راه‌اندازی
11
+ ## Setup
12
12
 
13
13
  ```ts
14
14
  // app.config.ts
15
15
  import { provideNotify } from 'ngx-kit/notify';
16
16
 
17
17
  export const appConfig: ApplicationConfig = {
18
- providers: [provideNotify({ timeout: 4000, position: 'top-center', dismissible: true })],
18
+ providers: [
19
+ provideNotify({ timeout: 4000, position: 'top-center', dismissible: true }),
20
+ ],
19
21
  };
20
22
  ```
21
23
 
22
- ## استفاده
24
+ ## Usage
23
25
 
24
26
  ```ts
25
27
  import { Notify } from 'ngx-kit/notify';
26
28
 
27
- Notify.success('ذخیره شد');
28
- Notify.error('پیام رو نتونستیم ارسال کنیم', 'دوباره تلاش کنید');
29
- Notify.warning('اتصال ضعیف است');
30
- Notify.info('نسخه‌ی جدید موجوده', undefined, { timeout: 8000 });
29
+ Notify.success('Saved');
30
+ Notify.error('We couldn\'t send your message', 'Try again');
31
+ Notify.warning('Weak connection');
32
+ Notify.info('A new version is available', undefined, { timeout: 8000 });
31
33
  ```
32
34
 
33
35
  ## API
34
36
 
35
37
  ### `Notify`
36
38
 
37
- | متد | امضا |
38
- | --------------------------------------------- | --------------------------------------------------- |
39
+ | Method | Signature |
40
+ | --- | --- |
39
41
  | `show(type, message, description?, options?)` | `type: 'info' \| 'success' \| 'warning' \| 'error'` |
40
- | `info` / `success` / `warning` / `error` | `(message, description?, options?)` |
42
+ | `info` / `success` / `warning` / `error` | `(message, description?, options?)` |
41
43
 
42
44
  ### `NgxNotifyOptions`
43
45
 
44
- | فیلد | نوع | پیش‌فرض | توضیح |
45
- | -------------- | ----------------------- | -------------- | ---------------------------------------------------------- |
46
- | `timeout` | `number` (ms) | `3000` | مدتِ نمایش قبل از بسته‌شدنِ خودکار |
47
- | `position` | `NgxNotifyPositionType` | `'top-center'` | گوشه/مرکزِ نمایش |
48
- | `maxVisible` | `number` | `10` | بیشتر از این تعداد صف می‌شن، نه هم‌پوشانی |
49
- | `allowHtml` | `boolean` | `false` | اگه `true`، پیام به‌عنوان HTML رندر می‌شه (سنیتایز نمی‌شه) |
50
- | `pauseOnHover` | `boolean` | `true` | تایمر با هاور موس متوقف می‌شه |
51
- | `dismissible` | `boolean` | `true` | نمایشِ دکمه‌ی بستن |
52
- | `closeOnTap` | `boolean` | `true` | با کلیک روی خودِ نوتیفیکیشن بسته بشه |
46
+ | Field | Type | Default | Description |
47
+ | --- | --- | --- | --- |
48
+ | `timeout` | `number` (ms) | `3000` | How long it's shown before auto-dismissing |
49
+ | `position` | `NgxNotifyPositionType` | `'top-center'` | Corner/center to display in |
50
+ | `maxVisible` | `number` | `10` | Beyond this count, notifications queue instead of overlapping |
51
+ | `allowHtml` | `boolean` | `false` | If `true`, the message is rendered as HTML (not sanitized) |
52
+ | `pauseOnHover` | `boolean` | `true` | The timer pauses while the mouse hovers |
53
+ | `dismissible` | `boolean` | `true` | Show a close button |
54
+ | `closeOnTap` | `boolean` | `true` | Clicking the notification itself closes it |
53
55
 
54
- ## دارک‌مود و RTL
56
+ ## Dark mode and RTL
55
57
 
56
- خودکار پشتیبانی می‌شه.
58
+ Supported automatically.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ngx-kit",
3
- "version": "6.0.1",
3
+ "version": "6.0.2",
4
4
  "description": "Angular input components",
5
5
  "author": "Mohammadreza Samani <mr.samani1368@gmail.com>",
6
6
  "license": "MIT",
package/shared/README.md CHANGED
@@ -1,27 +1,27 @@
1
1
  # ngx-kit/shared
2
2
 
3
- ابزارها و سرویس‌های مشترکی که بقیه‌ی بسته‌های `ngx-kit` روشون بنا شدن: مدیریت اورلی/دیالوگ، تشخیص جهت صفحه (RTL/LTR)، تشخیص تنظیمات مرورگر، و چند کامپوننت پایه‌ی قابل‌استفاده‌ی مجدد (اسلایدر، رنج‌اسلایدر، صفحه‌ی اشباع رنگ).
3
+ Shared utilities and services that the rest of the `ngx-kit` packages are built on: overlay/dialog management, page-direction (RTL/LTR) detection, browser-preference detection, and a few reusable base components (slider, range slider, color-saturation panel).
4
4
 
5
- معمولاً مستقیم به این پکیج نیازی ندارید — بقیه‌ی بسته‌ها به‌صورت خودکار بهش وابسته‌ان. ولی اگه دارید یه کامپوننت سفارشی می‌سازید که باید با بقیه‌ی کتابخونه هم‌خونی داشته باشه (دارک‌مود، RTL، درگ‌وپرفورمنس)، از همین ابزارها استفاده کنید.
5
+ You usually won't need this package directly — the other packages depend on it automatically. But if you're building a custom component that should stay consistent with the rest of the library (dark mode, RTL, drag performance), use these same utilities.
6
6
 
7
- ## نصب
7
+ ## Install
8
8
 
9
9
  ```bash
10
10
  npm install ngx-kit
11
11
  ```
12
12
 
13
- سبک‌های پایه (شامل `color-scheme` که دارک‌مود رو فعال می‌کنه) رو یک‌بار در سراسر اپ ایمپورت کنید:
13
+ Import the base styles (which enable dark mode via `color-scheme`) once, app-wide:
14
14
 
15
15
  ```scss
16
16
  // styles.scss
17
17
  @import 'ngx-kit/styles/all.css';
18
18
  ```
19
19
 
20
- ## سرویس‌ها
20
+ ## Services
21
21
 
22
22
  ### `OverlayService`
23
23
 
24
- موتور اصلی پشتِ همه‌ی چیزهای شناور کتابخونه (منو، دیالوگ، پاپ‌آپ‌های رنگ/گرادیان/زاویه). یک المنت انگولاری رو داخل یک `<dialog>` بومیِ مرورگر (`showModal()`) نمایش می‌ده و نسبت به یک anchor موقعیت‌دهی می‌کنه.
24
+ The engine behind everything floating in the library (menus, dialogs, the color/gradient/angle picker popups). Renders an Angular component inside a native `<dialog>` (`showModal()`) and positions it relative to an anchor.
25
25
 
26
26
  ```ts
27
27
  import { OverlayService } from 'ngx-kit/shared';
@@ -38,20 +38,20 @@ const ref = overlay.open({
38
38
  margin: 8,
39
39
  });
40
40
 
41
- ref.close(); // OverlayRef.close() آرگومان یا afterClosed نداره؛ برای اون‌جور رفتار (نتیجه‌ی بازگشتی، افترکلوز) از ngx-kit/dialog استفاده کنید که روی همین سرویس بنا شده
41
+ ref.close(); // OverlayRef.close() takes no argument and has no afterClosed; for that (return value, afterClosed) use ngx-kit/dialog, which is built on top of this service
42
42
  ```
43
43
 
44
- چیزهایی که به‌صورت خودکار برات مدیریت می‌شه:
44
+ What's handled for you automatically:
45
45
 
46
- - **موقعیت‌دهی هوشمند**: اگه فضای کافی پایین anchor نباشه، خودکار بالا می‌ره (`placement:'auto'`).
47
- - **بستن با کلیک بیرون**: با تشخیص کلیک روی backdrop، نه با listener سراسری روی document.
48
- - **پشته‌بندی درست**: چند اورلیِ هم‌زمان (مثلاً یه منوی زیرمنو‌دار) درست کار می‌کنن؛ Escape فقط آخرین (بالاترین) اورلی رو می‌بنده.
49
- - **بازگشتِ فوکوس**: بعد از بسته‌شدن، فوکوس به همون المنتی که قبلش فوکوس داشت برمی‌گرده (دسترس‌پذیری).
50
- - **RTL خودکار**: alignment و placement بر اساس جهت واقعیِ صفحه (نه فقط یه فرض ثابت) حساب می‌شن.
46
+ - **Smart positioning**: if there isn't enough room below the anchor, it flips above (`placement: 'auto'`).
47
+ - **Click-outside dismissal**: detected via the backdrop click, not a global `document` listener.
48
+ - **Correct stacking**: multiple simultaneous overlays (e.g. a menu with a submenu) work correctly; Escape only closes the last (topmost) overlay.
49
+ - **Focus restoration**: after closing, focus returns to whatever had focus before the overlay opened (accessibility).
50
+ - **Automatic RTL**: alignment and placement are computed against the page's actual direction (not a fixed assumption).
51
51
 
52
52
  ### `DirectionService`
53
53
 
54
- یه سیگنال (`isRtl(): boolean`) که با `MutationObserver` روی attribute-ی `dir` عنصر `<html>` گوش می‌ده و به‌محض تغییرش، ری‌اکتیو آپدیت می‌شه — یعنی اگه اپ شما زبان رو runtime عوض کنه، همه‌چیز خودکار هماهنگ می‌مونه.
54
+ A signal (`isRtl(): boolean`) that watches the `<html>` element's `dir` attribute with a `MutationObserver` and updates reactively the moment it changes — so if your app switches languages at runtime, everything stays in sync automatically.
55
55
 
56
56
  ```ts
57
57
  const direction = inject(DirectionService);
@@ -62,14 +62,14 @@ direction.isRtl(); // signal<boolean>
62
62
 
63
63
  ```ts
64
64
  const browser = inject(BrowserService);
65
- browser.prefersDarkMode; // boolean — یه‌بار در لحظه‌ی ساخت سرویس خونده می‌شه
65
+ browser.prefersDarkMode; // boolean — read once at service construction time
66
66
  ```
67
67
 
68
- ## ابزارهای Utility
68
+ ## Utilities
69
69
 
70
70
  ### `startDragSession(callbacks)`
71
71
 
72
- جایگزینِ الگوی مشکل‌دارِ `@HostListener('document:mousemove', ...)` که listener رو برای کل عمر کامپوننت روی `document` نگه می‌داره (حتی وقتی دراگی در جریان نیست — یه مشکل واقعیِ پرفورمنس روی صفحاتی با چند نمونه‌ی هم‌زمان). این تابع فقط در طول یک درگِ واقعی، listener اضافه می‌کنه و خودش پاک می‌کنه؛ `touchmove` هم با `{passive:false}` مدیریت می‌شه، پس درگ‌کردن روی موبایل صفحه رو اسکرول نمی‌کنه.
72
+ Replaces the problematic `@HostListener('document:mousemove', ...)` pattern, which keeps a listener attached to `document` for the entire lifetime of the component — even when nothing is being dragged (a real performance issue on pages with many simultaneous instances). This function only adds a listener for the duration of an actual drag and removes it itself; `touchmove` is handled with `{passive: false}`, so dragging on mobile doesn't also scroll the page.
73
73
 
74
74
  ```ts
75
75
  import { startDragSession } from 'ngx-kit/shared';
@@ -80,7 +80,7 @@ function onPointerDown(ev: MouseEvent | TouchEvent) {
80
80
  stop?.();
81
81
  stop = startDragSession({
82
82
  onMove: (ev) => {
83
- /* آپدیت موقعیت */
83
+ /* update position */
84
84
  },
85
85
  onEnd: () => {
86
86
  stop = undefined;
@@ -89,29 +89,29 @@ function onPointerDown(ev: MouseEvent | TouchEvent) {
89
89
  }
90
90
  ```
91
91
 
92
- > اگه کامپوننت‌تون `OnPush` هست و از `startDragSession` (به‌جای `@HostListener`) استفاده می‌کنید، حتماً داخل `onMove`/`onEnd` خودتون `ChangeDetectorRef.markForCheck()` رو صدا بزنید — برخلاف `@HostListener` که خودکار view رو dirty می‌کنه، `addEventListener` دستی این کار رو نمی‌کنه.
92
+ > If your component is `OnPush` and uses `startDragSession` (instead of `@HostListener`), make sure to call `ChangeDetectorRef.markForCheck()` inside `onMove`/`onEnd` yourself — unlike `@HostListener`, which automatically marks the view dirty, a manual `addEventListener` does not.
93
93
 
94
94
  ### `getOffsetPosition(event, element)`
95
95
 
96
- موقعیت pointer/touch رو نسبت به گوشه‌ی بالا-چپِ یه المنت مشخص برمی‌گردونه؛ برای پیاده‌سازیِ کامپوننت‌های درگ‌محور (اسلایدر، انتخاب‌گر رنگ و ...) استفاده می‌شه.
96
+ Returns the pointer/touch position relative to an element's top-left corner; used to implement drag-based components (sliders, color pickers, etc.).
97
97
 
98
98
  ### `mergeConfig(base, override)`
99
99
 
100
- ادغام عمیقِ دو آبجکت کانفیگ (برای الگوی `provideXxx({...})` که همه‌ی کتابخونه ازش استفاده می‌کنه).
100
+ Deep-merges two config objects (for the `provideXxx({...})` pattern used throughout the library).
101
101
 
102
- ## کامپوننت‌های پایه
102
+ ## Base components
103
103
 
104
- اینا رو مستقیم هم می‌شه استفاده کرد، ولی بیشتر به‌عنوان بلوک‌های سازنده‌ی کامپوننت‌های دیگه (مثل `color-picker`, `box-shadow`) طراحی شدن:
104
+ These can be used directly, but they're mostly designed as building blocks for other components (like `color-picker`, `box-shadow`):
105
105
 
106
- | کامپوننت | Selector | توضیح |
107
- | ---------------------- | -------------------- | ------------------------------------------------------------------- |
108
- | `SliderComponent` | `slider` | اسلایدر تک‌مقداره، `ControlValueAccessor`، `[min]`/`[max]`/`[step]` |
109
- | `RangeSliderComponent` | `range-slider` | اسلایدر بازه‌ای (دو thumb) |
110
- | `SaturationComponent` | داخلی (color-picker) | صفحه‌ی دوبعدیِ انتخاب اشباع/روشنایی رنگ |
106
+ | Component | Selector | Description |
107
+ | --- | --- | --- |
108
+ | `SliderComponent` | `slider` | Single-value slider, `ControlValueAccessor`, `[min]`/`[max]`/`[step]` |
109
+ | `RangeSliderComponent` | `range-slider` | Range slider (two thumbs) |
110
+ | `SaturationComponent` | internal (color-picker) | 2D saturation/lightness picker panel |
111
111
 
112
- ## دارک‌مود و RTL
112
+ ## Dark mode and RTL
113
113
 
114
- هر دو مستقیماً روی `ngx-kit/shared` تکیه دارن:
114
+ Both rely directly on `ngx-kit/shared`:
115
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` و ...) استفاده شده، پس نیازی به استایل جداگانه نیست.
116
+ - **Dark mode**: uses the native CSS `light-dark()` function. For it to work, `color-scheme: light dark` (or `only light`/`only dark` to force it manually) must be set on `:root` — this happens automatically when you import `ngx-kit/styles/all.css`. To force a theme manually (independent of the OS's `prefers-color-scheme`), set `data-ngx-theme="dark"` or `"light"` on `<html>`/`<body>`.
117
+ - **RTL**: enabled via `dir="rtl"` on `<html>`; the whole library uses CSS logical properties (`inset-inline-start`, etc.), so no separate styling is needed.
@@ -0,0 +1,95 @@
1
+ # ngx-kit/time-picker
2
+
3
+ An analog clock time picker (MUI-style), usable either inline or as a popup attached to a text input, with 12h/24h format support and a configurable minute step.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install ngx-kit
9
+ ```
10
+
11
+ ## Setup (optional)
12
+
13
+ ```ts
14
+ // app.config.ts
15
+ import { provideTimePicker } from 'ngx-kit/time-picker';
16
+
17
+ export const appConfig: ApplicationConfig = {
18
+ providers: [
19
+ provideTimePicker({
20
+ format: '24',
21
+ minuteStep: 5,
22
+ confirmButtonText: 'Done',
23
+ }),
24
+ ],
25
+ };
26
+ ```
27
+
28
+ `provideTimePicker` only needs the fields you want to override — everything else falls back to the defaults (`confirmButtonText: 'Ok'`, `cancelButtonText: 'Cancel'`, `amText: 'AM'`, `pmText: 'PM'`, `format: '12'`, `minuteStep: 1`, `autoSwitchToMinute: true`).
29
+
30
+ ## Usage — popup attached to an input
31
+
32
+ ```html
33
+ <input
34
+ type="text"
35
+ formControlName="time"
36
+ ngxInputTimePicker
37
+ #dp="ngxInputTimePicker"
38
+ />
39
+ <button (click)="dp.toggle()">Open</button>
40
+ ```
41
+
42
+ `[ngxInputTimePicker]` is a full `ControlValueAccessor` + `Validator`, so it works with `ngModel`/`formControl`/`formControlName`. The value is always a string in `HH:MM` (24h) form, e.g. `'14:35'`.
43
+
44
+ If the typed text isn't a valid time, the control gets a `{ invalid: true }` error (in addition to whatever built-in validators like `Validators.required` you add yourself):
45
+
46
+ ```html
47
+ @if (form.get('time')?.hasError('invalid')) {
48
+ <div class="text-danger">Invalid time</div>
49
+ }
50
+ @if (form.get('time')?.hasError('required')) {
51
+ <div class="text-danger">Time is required</div>
52
+ }
53
+ ```
54
+
55
+ ## Usage — inline (always visible)
56
+
57
+ ```html
58
+ <ngx-time-picker format="24" [(value)]="time" (change)="onTimeChange($event)"></ngx-time-picker>
59
+ ```
60
+
61
+ ## API
62
+
63
+ ### `[ngxInputTimePicker]`
64
+
65
+ | Input | Type | Default | Description |
66
+ | --- | --- | --- | --- |
67
+ | `openOnCLick` | `boolean` | `true` | Open the popup when the input itself is clicked |
68
+ | `format` | `'12' \| '24'` | from config | |
69
+
70
+ | Output | Type | Description |
71
+ | --- | --- | --- |
72
+ | `change` | `EventEmitter<string \| null>` | Emitted when the user confirms a time |
73
+
74
+ | Member | Description |
75
+ | --- | --- |
76
+ | `toggle()` | Opens the popup if closed, closes it if open |
77
+
78
+ ### `<ngx-time-picker>`
79
+
80
+ | Input | Type | Default | Description |
81
+ | --- | --- | --- | --- |
82
+ | `value` (model, two-way) | `string` | `'12:00'` | Bind with `[(value)]` |
83
+ | `format` | `'12' \| '24'` | from config | |
84
+ | `minuteStep` | `number` | from config | |
85
+ | `disabled` | `boolean` | `false` | |
86
+ | `autoSwitchToMinute` | `boolean` | from config | Switch to minute-selection mode right after picking the hour |
87
+
88
+ | Output | Type | Description |
89
+ | --- | --- | --- |
90
+ | `change` | `EventEmitter<string \| null>` | Emitted when "OK" is pressed |
91
+ | `cancel` | `EventEmitter<void>` | Emitted when "Cancel" is pressed |
92
+
93
+ ## Dark mode and RTL
94
+
95
+ Supported automatically.
@@ -21,7 +21,8 @@ interface PageState {
21
21
  }
22
22
  /** هر بار سرور باید صفحه‌ی جدید را (در حالت lazy) واکشی کند، امیت می‌شود. */
23
23
  interface LazyLoadEvent<T> extends PageState {
24
- sorts: SortMeta<T>[];
24
+ sorts?: SortMeta<T>[];
25
+ sorting?: string;
25
26
  }
26
27
 
27
28
  interface PaginationLabel {
@@ -59,7 +60,7 @@ type RendererExtraInputs<C extends Type<any>> = {
59
60
  [K in keyof InstanceOf<C> as K extends 'value' | 'row' | 'field' ? never : InstanceOf<C>[K] extends () => any ? K : never]?: UnwrapSignal<InstanceOf<C>[K]>;
60
61
  };
61
62
  type ColumnAlign = 'start' | 'center' | 'end';
62
- type TableCellFormatter<T extends object = object> = (value: unknown, row: T, field: TableFieldBase<T>) => unknown;
63
+ type TableCellFormatter<T extends object = object> = (value: any, row: T, field: TableFieldBase<T>) => any;
63
64
  interface CellTemplateContext<T extends object> {
64
65
  $implicit: T;
65
66
  row: T;
@@ -71,7 +72,14 @@ interface CellTemplateContext<T extends object> {
71
72
  interface TableFieldBase<T extends object> {
72
73
  column: Extract<keyof T, string>;
73
74
  title: string;
74
- width?: number;
75
+ /**
76
+ * عرضِ این ستون. عدد یعنی پیکسل (`160` = `160px`)؛ رشته یعنی هر مقدار
77
+ * معتبرِ CSS length برای flex-basis (`'20%'`, `'12rem'`, ...). اگه اصلاً
78
+ * ندید، این ستون flex می‌شه (`flex: 1 1 0`) و فضای باقی‌مونده‌ی جدول رو پر
79
+ * می‌کنه — دقیقاً برخلافِ ستون‌هایی که width دارن (که `flex: 0 0 <width>`
80
+ * می‌گیرن و ثابت می‌مونن).
81
+ */
82
+ width?: number | string;
75
83
  minWidth?: number;
76
84
  maxWidth?: number;
77
85
  resizable?: boolean;
@@ -144,6 +152,7 @@ type ResolvedTableOptions = Required<Omit<NgxTableOptions, 'labels' | 'renderers
144
152
  labels: Required<TableLabels>;
145
153
  renderers: RendererRegistry;
146
154
  formatters: Readonly<Record<string, TableCellFormatter<any>>>;
155
+ lazy: boolean;
147
156
  };
148
157
 
149
158
  declare const NGX_TABLE_CONFIG_DEFAULT: ResolvedTableOptions;
@@ -210,6 +219,7 @@ declare class ColumnResize {
210
219
  readonly direction: _angular_core.InputSignal<"ltr" | "rtl">;
211
220
  readonly resizing: _angular_core.OutputEmitterRef<number>;
212
221
  readonly resizeEnd: _angular_core.OutputEmitterRef<number>;
222
+ private readonly elementRef;
213
223
  private dragging;
214
224
  private startX;
215
225
  private baseWidth;
@@ -248,9 +258,12 @@ declare class NgxTable<T extends object> implements OnInit, AfterContentInit {
248
258
  readonly operationWidth: _angular_core.InputSignal<number>;
249
259
  readonly numWidth: _angular_core.InputSignal<number>;
250
260
  readonly pageSize: _angular_core.InputSignal<number>;
261
+ readonly page: _angular_core.InputSignal<number>;
262
+ readonly pageChange: _angular_core.OutputEmitterRef<number>;
251
263
  readonly loading: _angular_core.InputSignal<boolean>;
252
264
  readonly multiSort: _angular_core.InputSignal<boolean | undefined>;
253
265
  readonly lazy: _angular_core.InputSignal<boolean>;
266
+ readonly resizable: _angular_core.InputSignal<boolean>;
254
267
  /** پیش‌فرض بر اساس ایندکس؛ برای جلوگیری از گم‌شدن state سطرها هنگام سورت،
255
268
  * یک شناسه‌ی یکتا بدهید: [trackBy]="(i, row) => row.id" */
256
269
  readonly trackBy: _angular_core.InputSignal<(index: number, row: T) => unknown>;
@@ -260,7 +273,7 @@ declare class NgxTable<T extends object> implements OnInit, AfterContentInit {
260
273
  field: string;
261
274
  width: number;
262
275
  }>;
263
- protected readonly page: _angular_core.WritableSignal<number>;
276
+ protected readonly pageIndex: _angular_core.WritableSignal<number>;
264
277
  protected readonly pageSizeS: _angular_core.WritableSignal<number>;
265
278
  protected readonly sorts: _angular_core.WritableSignal<SortMeta<T>[]>;
266
279
  protected readonly widths: _angular_core.WritableSignal<Record<string, number>>;
@@ -287,6 +300,13 @@ declare class NgxTable<T extends object> implements OnInit, AfterContentInit {
287
300
  protected onPaginate(event: PageEvent): void;
288
301
  private emitLazyIfNeeded;
289
302
  protected columnWidth(column: string): number;
303
+ /**
304
+ * مقدار CSS `flex` واقعیِ این ستون:
305
+ * - اگه دستی ریسایز شده یا width عددی داره → `0 0 <px>` (ثابت، بدون رشد/کوچک‌شدن)
306
+ * - اگه width رشته‌ای داره (مثلاً '20%') → `0 0 <رشته>` (ثابت، هر واحد CSS معتبری)
307
+ * - اگه اصلاً width نداره → `1 1 0` (رشد می‌کنه تا فضای باقی‌مونده‌ی جدول رو پر کنه)
308
+ */
309
+ protected columnFlex(field: TableField<T, any>): string;
290
310
  protected columnMin(field: TableField<T, any>): number;
291
311
  protected columnMax(field: TableField<T, any>): number;
292
312
  protected isResizable(field: TableField<T, any>): boolean;
@@ -302,7 +322,7 @@ declare class NgxTable<T extends object> implements OnInit, AfterContentInit {
302
322
  * شود (مثلاً بعد از عوض‌شدن صفحه)، entry آن هم خودکار پاک می‌شود. */
303
323
  protected getRendererInputs(row: T, field: TableField<T, any>): Record<string, unknown>;
304
324
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgxTable<any>, never>;
305
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<NgxTable<any>, "ngx-table", never, { "fields": { "alias": "fields"; "required": true; "isSignal": true; }; "data": { "alias": "data"; "required": true; "isSignal": true; }; "totalRecords": { "alias": "totalRecords"; "required": true; "isSignal": true; }; "showRecordNumber": { "alias": "showRecordNumber"; "required": false; "isSignal": true; }; "operations": { "alias": "operations"; "required": false; "isSignal": true; }; "operationWidth": { "alias": "operationWidth"; "required": false; "isSignal": true; }; "numWidth": { "alias": "numWidth"; "required": false; "isSignal": true; }; "pageSize": { "alias": "pageSize"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "multiSort": { "alias": "multiSort"; "required": false; "isSignal": true; }; "lazy": { "alias": "lazy"; "required": false; "isSignal": true; }; "trackBy": { "alias": "trackBy"; "required": false; "isSignal": true; }; }, { "lazyLoad": "lazyLoad"; "sortChange": "sortChange"; "columnResize": "columnResize"; }, ["cellTemplates"], never, true, never>;
325
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NgxTable<any>, "ngx-table", never, { "fields": { "alias": "fields"; "required": true; "isSignal": true; }; "data": { "alias": "data"; "required": true; "isSignal": true; }; "totalRecords": { "alias": "totalRecords"; "required": true; "isSignal": true; }; "showRecordNumber": { "alias": "showRecordNumber"; "required": false; "isSignal": true; }; "operations": { "alias": "operations"; "required": false; "isSignal": true; }; "operationWidth": { "alias": "operationWidth"; "required": false; "isSignal": true; }; "numWidth": { "alias": "numWidth"; "required": false; "isSignal": true; }; "pageSize": { "alias": "pageSize"; "required": false; "isSignal": true; }; "page": { "alias": "page"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "multiSort": { "alias": "multiSort"; "required": false; "isSignal": true; }; "lazy": { "alias": "lazy"; "required": false; "isSignal": true; }; "resizable": { "alias": "resizable"; "required": false; "isSignal": true; }; "trackBy": { "alias": "trackBy"; "required": false; "isSignal": true; }; }, { "pageChange": "pageChange"; "lazyLoad": "lazyLoad"; "sortChange": "sortChange"; "columnResize": "columnResize"; }, ["cellTemplates"], never, true, never>;
306
326
  }
307
327
 
308
328
  declare class NgxPagination {