ngx-kit 7.0.0 → 7.1.0
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.
- package/angle-selector/README.md +34 -34
- package/box-shadow/README.md +33 -33
- package/color-picker/README.md +52 -52
- package/data-table/README.md +120 -120
- package/date-picker/README.md +74 -74
- package/dialog/README.md +92 -92
- package/drag-resize/README.md +55 -55
- package/fesm2022/ngx-kit-color-picker.mjs.map +1 -1
- package/fesm2022/ngx-kit-date-picker.mjs.map +1 -1
- package/fesm2022/ngx-kit-dialog.mjs.map +1 -1
- package/fesm2022/ngx-kit-drag-resize.mjs.map +1 -1
- package/fesm2022/ngx-kit-drawer-menu.mjs +2 -2
- package/fesm2022/ngx-kit-drawer-menu.mjs.map +1 -1
- package/fesm2022/ngx-kit-dropzone.mjs.map +1 -1
- package/fesm2022/ngx-kit-form-field.mjs.map +1 -1
- package/fesm2022/ngx-kit-gallery.mjs +2 -2
- package/fesm2022/ngx-kit-gallery.mjs.map +1 -1
- package/fesm2022/ngx-kit-grid-layout.mjs +108 -41
- package/fesm2022/ngx-kit-grid-layout.mjs.map +1 -1
- package/fesm2022/ngx-kit-infinite-scroll.mjs +467 -0
- package/fesm2022/ngx-kit-infinite-scroll.mjs.map +1 -0
- package/fesm2022/ngx-kit-shared.mjs.map +1 -1
- package/fesm2022/ngx-kit-virtual-scroll.mjs +2 -2
- package/fesm2022/ngx-kit-virtual-scroll.mjs.map +1 -1
- package/fesm2022/ngx-kit-webflow.mjs +38 -38
- package/fesm2022/ngx-kit-webflow.mjs.map +1 -1
- package/gallery/README.md +71 -71
- package/gradient-picker/README.md +41 -41
- package/grid-layout/README.md +64 -64
- package/image-editor/README.md +44 -44
- package/infinite-scroll/README.md +252 -0
- package/menu/README.md +85 -85
- package/message/README.md +70 -70
- package/notify/README.md +56 -56
- package/package.json +5 -1
- package/shared/README.md +117 -117
- package/time-picker/README.md +89 -89
- package/types/ngx-kit-grid-layout.d.ts +21 -20
- package/types/ngx-kit-infinite-scroll.d.ts +86 -0
- package/virtual-scroll/README.md +199 -199
package/notify/README.md
CHANGED
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
# ngx-kit/notify
|
|
2
|
-
|
|
3
|
-
Corner toast notifications, with a static API, automatic queueing (once the visible count exceeds the limit), and the timer pausing on hover.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install ngx-kit
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Setup
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
// app.config.ts
|
|
15
|
-
import { provideNotify } from 'ngx-kit/notify';
|
|
16
|
-
|
|
17
|
-
export const appConfig: ApplicationConfig = {
|
|
18
|
-
providers: [provideNotify({ timeout: 4000, position: 'top-center', dismissible: true })],
|
|
19
|
-
};
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Usage
|
|
23
|
-
|
|
24
|
-
```ts
|
|
25
|
-
import { Notify } from 'ngx-kit/notify';
|
|
26
|
-
|
|
27
|
-
Notify.success('Saved');
|
|
28
|
-
Notify.error("We couldn't send your message", 'Try again');
|
|
29
|
-
Notify.warning('Weak connection');
|
|
30
|
-
Notify.info('A new version is available', undefined, { timeout: 8000 });
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## API
|
|
34
|
-
|
|
35
|
-
### `Notify`
|
|
36
|
-
|
|
37
|
-
| Method | Signature |
|
|
38
|
-
| --------------------------------------------- | --------------------------------------------------- |
|
|
39
|
-
| `show(type, message, description?, options?)` | `type: 'info' \| 'success' \| 'warning' \| 'error'` |
|
|
40
|
-
| `info` / `success` / `warning` / `error` | `(message, description?, options?)` |
|
|
41
|
-
|
|
42
|
-
### `NgxNotifyOptions`
|
|
43
|
-
|
|
44
|
-
| Field | Type | Default | Description |
|
|
45
|
-
| -------------- | ----------------------- | -------------- | ------------------------------------------------------------- |
|
|
46
|
-
| `timeout` | `number` (ms) | `3000` | How long it's shown before auto-dismissing |
|
|
47
|
-
| `position` | `NgxNotifyPositionType` | `'top-center'` | Corner/center to display in |
|
|
48
|
-
| `maxVisible` | `number` | `10` | Beyond this count, notifications queue instead of overlapping |
|
|
49
|
-
| `allowHtml` | `boolean` | `false` | If `true`, the message is rendered as HTML (not sanitized) |
|
|
50
|
-
| `pauseOnHover` | `boolean` | `true` | The timer pauses while the mouse hovers |
|
|
51
|
-
| `dismissible` | `boolean` | `true` | Show a close button |
|
|
52
|
-
| `closeOnTap` | `boolean` | `true` | Clicking the notification itself closes it |
|
|
53
|
-
|
|
54
|
-
## Dark mode and RTL
|
|
55
|
-
|
|
56
|
-
Supported automatically.
|
|
1
|
+
# ngx-kit/notify
|
|
2
|
+
|
|
3
|
+
Corner toast notifications, with a static API, automatic queueing (once the visible count exceeds the limit), and the timer pausing on hover.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install ngx-kit
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
// app.config.ts
|
|
15
|
+
import { provideNotify } from 'ngx-kit/notify';
|
|
16
|
+
|
|
17
|
+
export const appConfig: ApplicationConfig = {
|
|
18
|
+
providers: [provideNotify({ timeout: 4000, position: 'top-center', dismissible: true })],
|
|
19
|
+
};
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { Notify } from 'ngx-kit/notify';
|
|
26
|
+
|
|
27
|
+
Notify.success('Saved');
|
|
28
|
+
Notify.error("We couldn't send your message", 'Try again');
|
|
29
|
+
Notify.warning('Weak connection');
|
|
30
|
+
Notify.info('A new version is available', undefined, { timeout: 8000 });
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## API
|
|
34
|
+
|
|
35
|
+
### `Notify`
|
|
36
|
+
|
|
37
|
+
| Method | Signature |
|
|
38
|
+
| --------------------------------------------- | --------------------------------------------------- |
|
|
39
|
+
| `show(type, message, description?, options?)` | `type: 'info' \| 'success' \| 'warning' \| 'error'` |
|
|
40
|
+
| `info` / `success` / `warning` / `error` | `(message, description?, options?)` |
|
|
41
|
+
|
|
42
|
+
### `NgxNotifyOptions`
|
|
43
|
+
|
|
44
|
+
| Field | Type | Default | Description |
|
|
45
|
+
| -------------- | ----------------------- | -------------- | ------------------------------------------------------------- |
|
|
46
|
+
| `timeout` | `number` (ms) | `3000` | How long it's shown before auto-dismissing |
|
|
47
|
+
| `position` | `NgxNotifyPositionType` | `'top-center'` | Corner/center to display in |
|
|
48
|
+
| `maxVisible` | `number` | `10` | Beyond this count, notifications queue instead of overlapping |
|
|
49
|
+
| `allowHtml` | `boolean` | `false` | If `true`, the message is rendered as HTML (not sanitized) |
|
|
50
|
+
| `pauseOnHover` | `boolean` | `true` | The timer pauses while the mouse hovers |
|
|
51
|
+
| `dismissible` | `boolean` | `true` | Show a close button |
|
|
52
|
+
| `closeOnTap` | `boolean` | `true` | Clicking the notification itself closes it |
|
|
53
|
+
|
|
54
|
+
## Dark mode and RTL
|
|
55
|
+
|
|
56
|
+
Supported automatically.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ngx-kit",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.1.0",
|
|
4
4
|
"description": "Angular input components",
|
|
5
5
|
"author": "Mohammadreza Samani <mr.samani1368@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -89,6 +89,10 @@
|
|
|
89
89
|
"types": "./types/ngx-kit-image-editor.d.ts",
|
|
90
90
|
"default": "./fesm2022/ngx-kit-image-editor.mjs"
|
|
91
91
|
},
|
|
92
|
+
"./infinite-scroll": {
|
|
93
|
+
"types": "./types/ngx-kit-infinite-scroll.d.ts",
|
|
94
|
+
"default": "./fesm2022/ngx-kit-infinite-scroll.mjs"
|
|
95
|
+
},
|
|
92
96
|
"./menu": {
|
|
93
97
|
"types": "./types/ngx-kit-menu.d.ts",
|
|
94
98
|
"default": "./fesm2022/ngx-kit-menu.mjs"
|
package/shared/README.md
CHANGED
|
@@ -1,117 +1,117 @@
|
|
|
1
|
-
# ngx-kit/shared
|
|
2
|
-
|
|
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
|
-
|
|
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
|
-
|
|
7
|
-
## Install
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install ngx-kit
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
Import the base styles (which enable dark mode via `color-scheme`) once, app-wide:
|
|
14
|
-
|
|
15
|
-
```scss
|
|
16
|
-
// styles.scss
|
|
17
|
-
@import 'ngx-kit/styles/all.css';
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## Services
|
|
21
|
-
|
|
22
|
-
### `OverlayService`
|
|
23
|
-
|
|
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
|
-
|
|
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() 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
|
-
```
|
|
43
|
-
|
|
44
|
-
What's handled for you automatically:
|
|
45
|
-
|
|
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
|
-
|
|
52
|
-
### `DirectionService`
|
|
53
|
-
|
|
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
|
-
|
|
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 — read once at service construction time
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Utilities
|
|
69
|
-
|
|
70
|
-
### `startDragSession(callbacks)`
|
|
71
|
-
|
|
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
|
-
|
|
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
|
-
/* update position */
|
|
84
|
-
},
|
|
85
|
-
onEnd: () => {
|
|
86
|
-
stop = undefined;
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
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
|
-
|
|
94
|
-
### `getOffsetPosition(event, element)`
|
|
95
|
-
|
|
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
|
-
|
|
98
|
-
### `mergeConfig(base, override)`
|
|
99
|
-
|
|
100
|
-
Deep-merges two config objects (for the `provideXxx({...})` pattern used throughout the library).
|
|
101
|
-
|
|
102
|
-
## Base components
|
|
103
|
-
|
|
104
|
-
These can be used directly, but they're mostly designed as building blocks for other components (like `color-picker`, `box-shadow`):
|
|
105
|
-
|
|
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
|
-
|
|
112
|
-
## Dark mode and RTL
|
|
113
|
-
|
|
114
|
-
Both rely directly on `ngx-kit/shared`:
|
|
115
|
-
|
|
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.
|
|
1
|
+
# ngx-kit/shared
|
|
2
|
+
|
|
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
|
+
|
|
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
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install ngx-kit
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Import the base styles (which enable dark mode via `color-scheme`) once, app-wide:
|
|
14
|
+
|
|
15
|
+
```scss
|
|
16
|
+
// styles.scss
|
|
17
|
+
@import 'ngx-kit/styles/all.css';
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Services
|
|
21
|
+
|
|
22
|
+
### `OverlayService`
|
|
23
|
+
|
|
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
|
+
|
|
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() 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
|
+
```
|
|
43
|
+
|
|
44
|
+
What's handled for you automatically:
|
|
45
|
+
|
|
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
|
+
|
|
52
|
+
### `DirectionService`
|
|
53
|
+
|
|
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
|
+
|
|
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 — read once at service construction time
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Utilities
|
|
69
|
+
|
|
70
|
+
### `startDragSession(callbacks)`
|
|
71
|
+
|
|
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
|
+
|
|
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
|
+
/* update position */
|
|
84
|
+
},
|
|
85
|
+
onEnd: () => {
|
|
86
|
+
stop = undefined;
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
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
|
+
|
|
94
|
+
### `getOffsetPosition(event, element)`
|
|
95
|
+
|
|
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
|
+
|
|
98
|
+
### `mergeConfig(base, override)`
|
|
99
|
+
|
|
100
|
+
Deep-merges two config objects (for the `provideXxx({...})` pattern used throughout the library).
|
|
101
|
+
|
|
102
|
+
## Base components
|
|
103
|
+
|
|
104
|
+
These can be used directly, but they're mostly designed as building blocks for other components (like `color-picker`, `box-shadow`):
|
|
105
|
+
|
|
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
|
+
|
|
112
|
+
## Dark mode and RTL
|
|
113
|
+
|
|
114
|
+
Both rely directly on `ngx-kit/shared`:
|
|
115
|
+
|
|
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.
|
package/time-picker/README.md
CHANGED
|
@@ -1,89 +1,89 @@
|
|
|
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 type="text" formControlName="time" ngxInputTimePicker #dp="ngxInputTimePicker" />
|
|
34
|
-
<button (click)="dp.toggle()">Open</button>
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
`[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'`.
|
|
38
|
-
|
|
39
|
-
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):
|
|
40
|
-
|
|
41
|
-
```html
|
|
42
|
-
@if (form.get('time')?.hasError('invalid')) {
|
|
43
|
-
<div class="text-danger">Invalid time</div>
|
|
44
|
-
} @if (form.get('time')?.hasError('required')) {
|
|
45
|
-
<div class="text-danger">Time is required</div>
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Usage — inline (always visible)
|
|
50
|
-
|
|
51
|
-
```html
|
|
52
|
-
<ngx-time-picker format="24" [(value)]="time" (change)="onTimeChange($event)"></ngx-time-picker>
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## API
|
|
56
|
-
|
|
57
|
-
### `[ngxInputTimePicker]`
|
|
58
|
-
|
|
59
|
-
| Input | Type | Default | Description |
|
|
60
|
-
| ------------- | -------------- | ----------- | ----------------------------------------------- |
|
|
61
|
-
| `openOnCLick` | `boolean` | `true` | Open the popup when the input itself is clicked |
|
|
62
|
-
| `format` | `'12' \| '24'` | from config | |
|
|
63
|
-
|
|
64
|
-
| Output | Type | Description |
|
|
65
|
-
| -------- | ------------------------------ | ------------------------------------- |
|
|
66
|
-
| `change` | `EventEmitter<string \| null>` | Emitted when the user confirms a time |
|
|
67
|
-
|
|
68
|
-
| Member | Description |
|
|
69
|
-
| ---------- | -------------------------------------------- |
|
|
70
|
-
| `toggle()` | Opens the popup if closed, closes it if open |
|
|
71
|
-
|
|
72
|
-
### `<ngx-time-picker>`
|
|
73
|
-
|
|
74
|
-
| Input | Type | Default | Description |
|
|
75
|
-
| ------------------------ | -------------- | ----------- | ------------------------------------------------------------ |
|
|
76
|
-
| `value` (model, two-way) | `string` | `'12:00'` | Bind with `[(value)]` |
|
|
77
|
-
| `format` | `'12' \| '24'` | from config | |
|
|
78
|
-
| `minuteStep` | `number` | from config | |
|
|
79
|
-
| `disabled` | `boolean` | `false` | |
|
|
80
|
-
| `autoSwitchToMinute` | `boolean` | from config | Switch to minute-selection mode right after picking the hour |
|
|
81
|
-
|
|
82
|
-
| Output | Type | Description |
|
|
83
|
-
| -------- | ------------------------------ | -------------------------------- |
|
|
84
|
-
| `change` | `EventEmitter<string \| null>` | Emitted when "OK" is pressed |
|
|
85
|
-
| `cancel` | `EventEmitter<void>` | Emitted when "Cancel" is pressed |
|
|
86
|
-
|
|
87
|
-
## Dark mode and RTL
|
|
88
|
-
|
|
89
|
-
Supported automatically.
|
|
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 type="text" formControlName="time" ngxInputTimePicker #dp="ngxInputTimePicker" />
|
|
34
|
+
<button (click)="dp.toggle()">Open</button>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`[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'`.
|
|
38
|
+
|
|
39
|
+
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):
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
@if (form.get('time')?.hasError('invalid')) {
|
|
43
|
+
<div class="text-danger">Invalid time</div>
|
|
44
|
+
} @if (form.get('time')?.hasError('required')) {
|
|
45
|
+
<div class="text-danger">Time is required</div>
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Usage — inline (always visible)
|
|
50
|
+
|
|
51
|
+
```html
|
|
52
|
+
<ngx-time-picker format="24" [(value)]="time" (change)="onTimeChange($event)"></ngx-time-picker>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## API
|
|
56
|
+
|
|
57
|
+
### `[ngxInputTimePicker]`
|
|
58
|
+
|
|
59
|
+
| Input | Type | Default | Description |
|
|
60
|
+
| ------------- | -------------- | ----------- | ----------------------------------------------- |
|
|
61
|
+
| `openOnCLick` | `boolean` | `true` | Open the popup when the input itself is clicked |
|
|
62
|
+
| `format` | `'12' \| '24'` | from config | |
|
|
63
|
+
|
|
64
|
+
| Output | Type | Description |
|
|
65
|
+
| -------- | ------------------------------ | ------------------------------------- |
|
|
66
|
+
| `change` | `EventEmitter<string \| null>` | Emitted when the user confirms a time |
|
|
67
|
+
|
|
68
|
+
| Member | Description |
|
|
69
|
+
| ---------- | -------------------------------------------- |
|
|
70
|
+
| `toggle()` | Opens the popup if closed, closes it if open |
|
|
71
|
+
|
|
72
|
+
### `<ngx-time-picker>`
|
|
73
|
+
|
|
74
|
+
| Input | Type | Default | Description |
|
|
75
|
+
| ------------------------ | -------------- | ----------- | ------------------------------------------------------------ |
|
|
76
|
+
| `value` (model, two-way) | `string` | `'12:00'` | Bind with `[(value)]` |
|
|
77
|
+
| `format` | `'12' \| '24'` | from config | |
|
|
78
|
+
| `minuteStep` | `number` | from config | |
|
|
79
|
+
| `disabled` | `boolean` | `false` | |
|
|
80
|
+
| `autoSwitchToMinute` | `boolean` | from config | Switch to minute-selection mode right after picking the hour |
|
|
81
|
+
|
|
82
|
+
| Output | Type | Description |
|
|
83
|
+
| -------- | ------------------------------ | -------------------------------- |
|
|
84
|
+
| `change` | `EventEmitter<string \| null>` | Emitted when "OK" is pressed |
|
|
85
|
+
| `cancel` | `EventEmitter<void>` | Emitted when "Cancel" is pressed |
|
|
86
|
+
|
|
87
|
+
## Dark mode and RTL
|
|
88
|
+
|
|
89
|
+
Supported automatically.
|
|
@@ -123,6 +123,24 @@ declare function trySwap<T extends LayoutNode>(items: readonly T[], id: string,
|
|
|
123
123
|
declare function compact<T extends LayoutNode>(items: readonly T[], mode: CompactMode): T[];
|
|
124
124
|
/** Highest occupied row (0-based, exclusive) across all items — drives the grid's auto-height. */
|
|
125
125
|
declare function maxOccupiedRow(items: readonly LayoutNode[]): number;
|
|
126
|
+
/**
|
|
127
|
+
* Finds a cell for `config` that doesn't collide with any existing item.
|
|
128
|
+
* Tries the requested (x, y) first; if that's already occupied, scans
|
|
129
|
+
* forward in reading order (row by row, top to bottom, left to right — the
|
|
130
|
+
* caller is responsible for any RTL flipping when it turns this back into
|
|
131
|
+
* pixels) for the first gap large enough to fit it.
|
|
132
|
+
*
|
|
133
|
+
* This is what a newly-registered item (or one whose config changes to a
|
|
134
|
+
* position that's no longer free) should go through instead of silently
|
|
135
|
+
* overlapping whatever's already there: unlike a drag/resize, registering an
|
|
136
|
+
* item isn't a deliberate "make room for me" gesture, so relocating the new
|
|
137
|
+
* item to open space reads far better than shoving already-placed items
|
|
138
|
+
* around to accommodate it.
|
|
139
|
+
*/
|
|
140
|
+
declare function findFreeSpot<T extends LayoutNode>(items: readonly T[], config: GridItemConfig, cols: number, excludeId?: string): {
|
|
141
|
+
x: number;
|
|
142
|
+
y: number;
|
|
143
|
+
};
|
|
126
144
|
|
|
127
145
|
/**
|
|
128
146
|
* All pixel <-> grid-cell math lives here, in one RTL-aware place.
|
|
@@ -173,7 +191,6 @@ declare class GridLayoutService {
|
|
|
173
191
|
readonly height: _angular_core.Signal<number>;
|
|
174
192
|
readonly layout: _angular_core.Signal<LayoutOutput[]>;
|
|
175
193
|
readonly columns: _angular_core.Signal<number>;
|
|
176
|
-
/** Resolves `rtl: 'auto'` against the attached element's *actual* computed direction. */
|
|
177
194
|
readonly rtl: _angular_core.Signal<boolean>;
|
|
178
195
|
private rtlTick;
|
|
179
196
|
private layoutListener?;
|
|
@@ -187,23 +204,7 @@ declare class GridLayoutService {
|
|
|
187
204
|
setOptions(value: Partial<IGridLayoutOptions>): void;
|
|
188
205
|
setEditMode(value: boolean): void;
|
|
189
206
|
setItems(items: GridItemState[]): void;
|
|
190
|
-
/**
|
|
191
|
-
* Registers a new item, or refreshes the DOM element reference of one that's
|
|
192
|
-
* already tracked. Adding an item can shift the whole layout (compaction /
|
|
193
|
-
* push), so that path settles. Merely re-supplying the same element on an
|
|
194
|
-
* already-known id has no geometric effect, so it is a deliberate no-op —
|
|
195
|
-
* skipping it is what keeps a per-item `effect()` that calls this on every
|
|
196
|
-
* change-detection pass from re-triggering `settle()` indefinitely.
|
|
197
|
-
*/
|
|
198
207
|
registerItem(item: GridItemState): void;
|
|
199
|
-
/**
|
|
200
|
-
* Updates an item's config. Only writes the signal and re-settles the layout
|
|
201
|
-
* when the *value* actually changed. Without this guard, any caller that
|
|
202
|
-
* supplies a structurally-equal but referentially-new config object (e.g. a
|
|
203
|
-
* template bound to a `computed()` layout) would cause an unconditional
|
|
204
|
-
* `items.set()` on every run — which produces new output objects, which
|
|
205
|
-
* feed back into that same new config reference, forever.
|
|
206
|
-
*/
|
|
207
208
|
updateItemConfig(id: string, config: GridItemConfig): void;
|
|
208
209
|
unregisterItem(id: string): void;
|
|
209
210
|
/** Called once the grid surface element exists (e.g. from `ngAfterViewInit`). */
|
|
@@ -246,8 +247,8 @@ declare class NgxGridLayoutComponent implements AfterViewInit, OnDestroy {
|
|
|
246
247
|
readonly editMode: _angular_core.InputSignal<boolean>;
|
|
247
248
|
readonly layoutChange: _angular_core.OutputEmitterRef<LayoutOutput[]>;
|
|
248
249
|
/** Explicit direction override. Leave unset to inherit the page/host direction automatically. */
|
|
249
|
-
readonly dir: _angular_core.InputSignal<"
|
|
250
|
-
readonly dirOverride: _angular_core.InputSignal<"
|
|
250
|
+
readonly dir: _angular_core.InputSignal<"rtl" | "ltr" | undefined>;
|
|
251
|
+
readonly dirOverride: _angular_core.InputSignal<"rtl" | "ltr" | undefined>;
|
|
251
252
|
readonly service: GridLayoutService;
|
|
252
253
|
private readonly el;
|
|
253
254
|
private surface?;
|
|
@@ -306,5 +307,5 @@ declare class NgxGridLayoutModule {
|
|
|
306
307
|
static ɵinj: _angular_core.ɵɵInjectorDeclaration<NgxGridLayoutModule>;
|
|
307
308
|
}
|
|
308
309
|
|
|
309
|
-
export { GridItemConfig, GridLayoutOptions, GridLayoutService, NgxGridItemComponent, NgxGridLayoutComponent, NgxGridLayoutModule, colToLeft, collides, compact, computeMetrics, getAllCollisions, getFirstCollision, gridItemConfigsEqual, leftToCol, maxOccupiedRow, moveItem, normalizeGridItem, placeItem, rowToTop, spanToHeightPx, spanToWidthPx, topToRow, trySwap };
|
|
310
|
+
export { GridItemConfig, GridLayoutOptions, GridLayoutService, NgxGridItemComponent, NgxGridLayoutComponent, NgxGridLayoutModule, colToLeft, collides, compact, computeMetrics, findFreeSpot, getAllCollisions, getFirstCollision, gridItemConfigsEqual, leftToCol, maxOccupiedRow, moveItem, normalizeGridItem, placeItem, rowToTop, spanToHeightPx, spanToWidthPx, topToRow, trySwap };
|
|
310
311
|
export type { CompactMode, GridFlow, GridItemState, GridMetrics, IGridBackgroundCfg, IGridLayoutOptions, LayoutNode, LayoutOutput, MoveOptions };
|