ngx-kit 6.3.0 → 7.0.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.
Files changed (67) hide show
  1. package/README.md +3 -3
  2. package/angle-selector/README.md +34 -34
  3. package/box-shadow/README.md +33 -33
  4. package/color-picker/README.md +52 -49
  5. package/data-table/README.md +120 -113
  6. package/date-picker/README.md +74 -69
  7. package/dialog/README.md +92 -92
  8. package/drag-resize/README.md +55 -0
  9. package/dropzone/README.md +422 -422
  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 +2 -2
  13. package/fesm2022/ngx-kit-box-shadow.mjs.map +1 -1
  14. package/fesm2022/ngx-kit-color-picker.mjs +265 -73
  15. package/fesm2022/ngx-kit-color-picker.mjs.map +1 -1
  16. package/fesm2022/ngx-kit-data-table.mjs +2 -2
  17. package/fesm2022/ngx-kit-data-table.mjs.map +1 -1
  18. package/fesm2022/ngx-kit-date-picker.mjs +7 -9
  19. package/fesm2022/ngx-kit-date-picker.mjs.map +1 -1
  20. package/fesm2022/ngx-kit-dialog.mjs +3 -3
  21. package/fesm2022/ngx-kit-dialog.mjs.map +1 -1
  22. package/fesm2022/ngx-kit-drag-resize.mjs +1664 -0
  23. package/fesm2022/ngx-kit-drag-resize.mjs.map +1 -0
  24. package/fesm2022/ngx-kit-drawer-menu.mjs +389 -285
  25. package/fesm2022/ngx-kit-drawer-menu.mjs.map +1 -1
  26. package/fesm2022/ngx-kit-dropzone.mjs +2 -2
  27. package/fesm2022/ngx-kit-dropzone.mjs.map +1 -1
  28. package/fesm2022/ngx-kit-form-field.mjs +3 -5
  29. package/fesm2022/ngx-kit-form-field.mjs.map +1 -1
  30. package/fesm2022/ngx-kit-gallery.mjs +2 -2
  31. package/fesm2022/ngx-kit-gallery.mjs.map +1 -1
  32. package/fesm2022/ngx-kit-gradient-picker.mjs.map +1 -1
  33. package/fesm2022/ngx-kit-grid-layout.mjs +927 -0
  34. package/fesm2022/ngx-kit-grid-layout.mjs.map +1 -0
  35. package/fesm2022/ngx-kit-image-editor.mjs.map +1 -1
  36. package/fesm2022/ngx-kit-menu.mjs +8 -8
  37. package/fesm2022/ngx-kit-menu.mjs.map +1 -1
  38. package/fesm2022/ngx-kit-message.mjs.map +1 -1
  39. package/fesm2022/ngx-kit-notify.mjs +2 -2
  40. package/fesm2022/ngx-kit-notify.mjs.map +1 -1
  41. package/fesm2022/ngx-kit-shared.mjs +54 -3
  42. package/fesm2022/ngx-kit-shared.mjs.map +1 -1
  43. package/fesm2022/ngx-kit-time-picker.mjs +2 -2
  44. package/fesm2022/ngx-kit-time-picker.mjs.map +1 -1
  45. package/fesm2022/ngx-kit-virtual-scroll.mjs +392 -0
  46. package/fesm2022/ngx-kit-virtual-scroll.mjs.map +1 -0
  47. package/fesm2022/ngx-kit-webflow.mjs +709 -0
  48. package/fesm2022/ngx-kit-webflow.mjs.map +1 -0
  49. package/gallery/README.md +71 -71
  50. package/gradient-picker/README.md +41 -41
  51. package/grid-layout/README.md +64 -0
  52. package/image-editor/README.md +12 -12
  53. package/menu/README.md +85 -85
  54. package/message/README.md +70 -70
  55. package/notify/README.md +56 -58
  56. package/package.json +17 -1
  57. package/shared/README.md +117 -117
  58. package/time-picker/README.md +89 -95
  59. package/types/ngx-kit-color-picker.d.ts +72 -16
  60. package/types/ngx-kit-drag-resize.d.ts +368 -0
  61. package/types/ngx-kit-drawer-menu.d.ts +135 -86
  62. package/types/ngx-kit-grid-layout.d.ts +310 -0
  63. package/types/ngx-kit-image-editor.d.ts +1 -1
  64. package/types/ngx-kit-shared.d.ts +12 -1
  65. package/types/ngx-kit-virtual-scroll.d.ts +179 -0
  66. package/types/ngx-kit-webflow.d.ts +286 -0
  67. package/virtual-scroll/README.md +199 -0
package/message/README.md CHANGED
@@ -1,70 +1,70 @@
1
- # ngx-kit/message
2
-
3
- Alert/confirm dialogs (SweetAlert-style), with a static API callable from anywhere in the app.
4
-
5
- ## Install
6
-
7
- ```bash
8
- npm install ngx-kit
9
- ```
10
-
11
- ## Setup
12
-
13
- ```ts
14
- // app.config.ts
15
- import { provideMessage } from 'ngx-kit/message';
16
-
17
- export const appConfig: ApplicationConfig = {
18
- providers: [provideMessage({ confirmButtonText: 'OK' /* global defaults */ })],
19
- };
20
- ```
21
-
22
- ## Usage
23
-
24
- ```ts
25
- import { MSG } from 'ngx-kit/message';
26
-
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
-
34
- // full control over options:
35
- const result = MSG.show({
36
- title: 'Delete this?',
37
- text: 'This action cannot be undone.',
38
- showCancelButton: true,
39
- showDenyButton: true,
40
- confirmButtonText: 'Yes, delete it',
41
- });
42
- result.afterClose.subscribe((r) => console.log(r));
43
- ```
44
-
45
- ## API
46
-
47
- ### `MSG` (and its alias `Modal`)
48
-
49
- | Method | Signature | Description |
50
- | --- | --- | --- |
51
- | `show(options?)` | `IMessageOptions` | Full control |
52
- | `info` / `success` / `warning` / `error` / `question` / `loading` | `(title, text?, options?)` | Common shortcuts |
53
-
54
- ### `IMessageOptions` (key fields)
55
-
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
-
66
- If several messages are open at once, Escape/Enter only affect the **last (topmost) message**, not all of them.
67
-
68
- ## Dark mode and RTL
69
-
70
- Supported automatically.
1
+ # ngx-kit/message
2
+
3
+ Alert/confirm dialogs (SweetAlert-style), with a static API callable from anywhere in the app.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install ngx-kit
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ ```ts
14
+ // app.config.ts
15
+ import { provideMessage } from 'ngx-kit/message';
16
+
17
+ export const appConfig: ApplicationConfig = {
18
+ providers: [provideMessage({ confirmButtonText: 'OK' /* global defaults */ })],
19
+ };
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```ts
25
+ import { MSG } from 'ngx-kit/message';
26
+
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
+
34
+ // full control over options:
35
+ const result = MSG.show({
36
+ title: 'Delete this?',
37
+ text: 'This action cannot be undone.',
38
+ showCancelButton: true,
39
+ showDenyButton: true,
40
+ confirmButtonText: 'Yes, delete it',
41
+ });
42
+ result.afterClose.subscribe((r) => console.log(r));
43
+ ```
44
+
45
+ ## API
46
+
47
+ ### `MSG` (and its alias `Modal`)
48
+
49
+ | Method | Signature | Description |
50
+ | ----------------------------------------------------------------- | -------------------------- | ---------------- |
51
+ | `show(options?)` | `IMessageOptions` | Full control |
52
+ | `info` / `success` / `warning` / `error` / `question` / `loading` | `(title, text?, options?)` | Common shortcuts |
53
+
54
+ ### `IMessageOptions` (key fields)
55
+
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
+
66
+ If several messages are open at once, Escape/Enter only affect the **last (topmost) message**, not all of them.
67
+
68
+ ## Dark mode and RTL
69
+
70
+ Supported automatically.
package/notify/README.md CHANGED
@@ -1,58 +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: [
19
- provideNotify({ timeout: 4000, position: 'top-center', dismissible: true }),
20
- ],
21
- };
22
- ```
23
-
24
- ## Usage
25
-
26
- ```ts
27
- import { Notify } from 'ngx-kit/notify';
28
-
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 });
33
- ```
34
-
35
- ## API
36
-
37
- ### `Notify`
38
-
39
- | Method | Signature |
40
- | --- | --- |
41
- | `show(type, message, description?, options?)` | `type: 'info' \| 'success' \| 'warning' \| 'error'` |
42
- | `info` / `success` / `warning` / `error` | `(message, description?, options?)` |
43
-
44
- ### `NgxNotifyOptions`
45
-
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 |
55
-
56
- ## Dark mode and RTL
57
-
58
- 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": "6.3.0",
3
+ "version": "7.0.0",
4
4
  "description": "Angular input components",
5
5
  "author": "Mohammadreza Samani <mr.samani1368@gmail.com>",
6
6
  "license": "MIT",
@@ -57,6 +57,10 @@
57
57
  "types": "./types/ngx-kit-dialog.d.ts",
58
58
  "default": "./fesm2022/ngx-kit-dialog.mjs"
59
59
  },
60
+ "./drag-resize": {
61
+ "types": "./types/ngx-kit-drag-resize.d.ts",
62
+ "default": "./fesm2022/ngx-kit-drag-resize.mjs"
63
+ },
60
64
  "./drawer-menu": {
61
65
  "types": "./types/ngx-kit-drawer-menu.d.ts",
62
66
  "default": "./fesm2022/ngx-kit-drawer-menu.mjs"
@@ -77,6 +81,10 @@
77
81
  "types": "./types/ngx-kit-gradient-picker.d.ts",
78
82
  "default": "./fesm2022/ngx-kit-gradient-picker.mjs"
79
83
  },
84
+ "./grid-layout": {
85
+ "types": "./types/ngx-kit-grid-layout.d.ts",
86
+ "default": "./fesm2022/ngx-kit-grid-layout.mjs"
87
+ },
80
88
  "./image-editor": {
81
89
  "types": "./types/ngx-kit-image-editor.d.ts",
82
90
  "default": "./fesm2022/ngx-kit-image-editor.mjs"
@@ -100,6 +108,14 @@
100
108
  "./time-picker": {
101
109
  "types": "./types/ngx-kit-time-picker.d.ts",
102
110
  "default": "./fesm2022/ngx-kit-time-picker.mjs"
111
+ },
112
+ "./virtual-scroll": {
113
+ "types": "./types/ngx-kit-virtual-scroll.d.ts",
114
+ "default": "./fesm2022/ngx-kit-virtual-scroll.mjs"
115
+ },
116
+ "./webflow": {
117
+ "types": "./types/ngx-kit-webflow.d.ts",
118
+ "default": "./fesm2022/ngx-kit-webflow.mjs"
103
119
  }
104
120
  },
105
121
  "type": "module"
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.