ngx-kit 7.0.1 → 7.2.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 +7 -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 +76 -104
- package/fesm2022/ngx-kit-drag-resize.mjs.map +1 -1
- package/fesm2022/ngx-kit-drawer-menu.mjs +3 -3
- 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 +9 -3
- 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 +32 -30
- 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-message.mjs +1 -1
- package/fesm2022/ngx-kit-message.mjs.map +1 -1
- package/fesm2022/ngx-kit-shared.mjs +64 -1
- 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-date-picker.d.ts +14 -11
- package/types/ngx-kit-drag-resize.d.ts +44 -44
- package/types/ngx-kit-form-field.d.ts +26 -23
- package/types/ngx-kit-infinite-scroll.d.ts +86 -0
- package/types/ngx-kit-shared.d.ts +39 -1
- package/virtual-scroll/README.md +199 -199
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# ngx-kit Infinite Scroll
|
|
2
|
+
|
|
3
|
+
A performance-first infinite-scroll directive for Angular, designed as a small reusable primitive for `ngx-kit`.
|
|
4
|
+
|
|
5
|
+
It uses the browser's `IntersectionObserver` instead of a continuous `scroll` listener, stays outside Angular's zone until an actual boundary trigger occurs, and supports normal lists, browser-window scrolling, custom roots, reverse chat feeds, and bidirectional feeds.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- `IntersectionObserver` based; no continuous scroll polling.
|
|
10
|
+
- No RxJS dependency in the directive itself.
|
|
11
|
+
- Standalone Angular directive with signal-based inputs and outputs.
|
|
12
|
+
- Window, host element, external element, or selector-based scroll roots.
|
|
13
|
+
- Runtime root/configuration changes.
|
|
14
|
+
- `down`, `up`, and `both` directions.
|
|
15
|
+
- Prefetch distance in pixels.
|
|
16
|
+
- Immediate check for under-filled lists.
|
|
17
|
+
- Minimum trigger interval.
|
|
18
|
+
- Disabled state that automatically rearms the observer.
|
|
19
|
+
- Reverse/prepend support with automatic scroll-position preservation.
|
|
20
|
+
- `ResizeObserver` + `MutationObserver` assist slow and dynamic layout changes.
|
|
21
|
+
- Explicit `check()` and `completePrepend()` escape hatches.
|
|
22
|
+
- SSR-safe: browser-only APIs are guarded.
|
|
23
|
+
- `scrollStartReached` and `scrollEndReached` convenience outputs.
|
|
24
|
+
- Tiny API surface and zero third-party runtime dependencies.
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
From an existing Angular 22 application:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install @ngx-kit/infinite-scroll
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Then import the standalone directive where it is needed:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { NgxInfiniteScroll } from '@ngx-kit/infinite-scroll';
|
|
38
|
+
|
|
39
|
+
@Component({
|
|
40
|
+
standalone: true,
|
|
41
|
+
imports: [NgxInfiniteScroll],
|
|
42
|
+
// ...
|
|
43
|
+
})
|
|
44
|
+
export class MyComponent {}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Basic usage
|
|
48
|
+
|
|
49
|
+
```html
|
|
50
|
+
<div
|
|
51
|
+
class="list"
|
|
52
|
+
infiniteScroll
|
|
53
|
+
[scrollWindow]="false"
|
|
54
|
+
[infiniteScrollDistance]="300"
|
|
55
|
+
[infiniteScrollDisabled]="loading() || endOfList()"
|
|
56
|
+
(scrolled)="loadMore()">
|
|
57
|
+
@for (item of items(); track item.id) {
|
|
58
|
+
<article>{{ item.title }}</article>
|
|
59
|
+
}
|
|
60
|
+
</div>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The host itself is the scroll container when `scrollWindow` is `false` and no explicit container/root is supplied.
|
|
64
|
+
|
|
65
|
+
## Window scrolling
|
|
66
|
+
|
|
67
|
+
Leave `scrollWindow` at its default `true`:
|
|
68
|
+
|
|
69
|
+
```html
|
|
70
|
+
<div
|
|
71
|
+
infiniteScroll
|
|
72
|
+
[infiniteScrollDistance]="600"
|
|
73
|
+
[infiniteScrollDisabled]="loading() || endOfList()"
|
|
74
|
+
(scrolled)="loadMore()">
|
|
75
|
+
...
|
|
76
|
+
</div>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The observer root is `null`, so the browser viewport is used.
|
|
80
|
+
|
|
81
|
+
## External/custom root
|
|
82
|
+
|
|
83
|
+
Pass an element directly:
|
|
84
|
+
|
|
85
|
+
```html
|
|
86
|
+
<div
|
|
87
|
+
infiniteScroll
|
|
88
|
+
[scrollWindow]="false"
|
|
89
|
+
[infiniteScrollRoot]="listViewport"
|
|
90
|
+
(scrolled)="loadMore()">
|
|
91
|
+
...
|
|
92
|
+
</div>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Or use a selector:
|
|
96
|
+
|
|
97
|
+
```html
|
|
98
|
+
<div
|
|
99
|
+
infiniteScroll
|
|
100
|
+
[fromRoot]="true"
|
|
101
|
+
[infiniteScrollContainer]="'.questioner-infinit'"
|
|
102
|
+
[scrollWindow]="false"
|
|
103
|
+
(scrolled)="loadMore()">
|
|
104
|
+
...
|
|
105
|
+
</div>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
When a selector cannot be resolved, the directive falls back to the host element instead of silently switching to the browser window.
|
|
109
|
+
|
|
110
|
+
## Reverse / chat feeds
|
|
111
|
+
|
|
112
|
+
Use `up` and keep scroll anchoring enabled:
|
|
113
|
+
|
|
114
|
+
```html
|
|
115
|
+
<div
|
|
116
|
+
class="chat"
|
|
117
|
+
infiniteScroll
|
|
118
|
+
[scrollWindow]="false"
|
|
119
|
+
[infiniteScrollDirection]="'up'"
|
|
120
|
+
[infiniteScrollDistance]="180"
|
|
121
|
+
[infiniteScrollMaintainScrollPosition]="true"
|
|
122
|
+
[infiniteScrollDisabled]="loadingOlder() || reachedBeginning()"
|
|
123
|
+
(scrolled)="loadOlder()">
|
|
124
|
+
...
|
|
125
|
+
</div>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Before emitting the `up` event, the directive snapshots `scrollTop` and `scrollHeight`. When prepended content increases `scrollHeight`, it adds the exact height delta to the previous `scrollTop` so the user's visible messages stay anchored.
|
|
129
|
+
|
|
130
|
+
For custom rendering pipelines that know exactly when a batch has rendered:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
@ViewChild(NgxInfiniteScroll)
|
|
134
|
+
private infiniteScroll?: NgxInfiniteScroll;
|
|
135
|
+
|
|
136
|
+
loadOlder(): void {
|
|
137
|
+
// fetch + prepend data
|
|
138
|
+
// ...
|
|
139
|
+
this.infiniteScroll?.completePrepend();
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
In most Angular templates, automatic observation is enough and `completePrepend()` is not required.
|
|
144
|
+
|
|
145
|
+
## Bidirectional feeds
|
|
146
|
+
|
|
147
|
+
```html
|
|
148
|
+
<div
|
|
149
|
+
infiniteScroll
|
|
150
|
+
[scrollWindow]="false"
|
|
151
|
+
[infiniteScrollDirection]="'both'"
|
|
152
|
+
[infiniteScrollDistance]="200"
|
|
153
|
+
(scrolled)="loadFromEdge($event)">
|
|
154
|
+
...
|
|
155
|
+
</div>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The event tells you which edge triggered the load:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
loadFromEdge(event: NgxInfiniteScrollEvent): void {
|
|
162
|
+
if (event.direction === 'up') {
|
|
163
|
+
// prepend older records
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// append newer records
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Public API
|
|
172
|
+
|
|
173
|
+
| Input | Type | Default | Purpose |
|
|
174
|
+
| -------------------------------------- | ------------------------------- | -------: | ---------------------------------------------------------------------- |
|
|
175
|
+
| `infiniteScrollDistance` | `number` | `200` | Prefetch threshold in pixels. |
|
|
176
|
+
| `infiniteScrollDisabled` | `boolean` | `false` | Stops triggers while true. |
|
|
177
|
+
| `infiniteScrollImmediateCheck` | `boolean` | `true` | Performs a direct visibility check after setup/re-enable. |
|
|
178
|
+
| `infiniteScrollMinInterval` | `number` | `100` | Minimum time between trigger emissions. |
|
|
179
|
+
| `infiniteScrollUpDistance` | `number \| null` | `null` | Optional top-edge override; falls back to `infiniteScrollDistance`. |
|
|
180
|
+
| `infiniteScrollDownDistance` | `number \| null` | `null` | Optional bottom-edge override; falls back to `infiniteScrollDistance`. |
|
|
181
|
+
| `infiniteScrollDirection` | `'up' \| 'down' \| 'both'` | `'down'` | Active edge(s). |
|
|
182
|
+
| `infiniteScrollContainer` | `string \| HTMLElement \| null` | `null` | Selector or element root. |
|
|
183
|
+
| `infiniteScrollRoot` | `HTMLElement \| null` | `null` | Explicit observer root; highest precedence. |
|
|
184
|
+
| `scrollWindow` | `boolean` | `true` | Use browser viewport as root. |
|
|
185
|
+
| `fromRoot` | `boolean` | `false` | Resolve a selector from `document` instead of the host. |
|
|
186
|
+
| `infiniteScrollMaintainScrollPosition` | `boolean` | `true` | Preserve viewport on `up` triggers. |
|
|
187
|
+
| `infiniteScrollPreserveScrollBehavior` | `ScrollBehavior` | `'auto'` | Behavior used for scroll compensation. |
|
|
188
|
+
|
|
189
|
+
### Outputs
|
|
190
|
+
|
|
191
|
+
| Output | Payload | Purpose |
|
|
192
|
+
| -------------------- | ------------------------ | ---------------------------------------------------- |
|
|
193
|
+
| `scrolled` | `NgxInfiniteScrollEvent` | Main load trigger. |
|
|
194
|
+
| `scrolledUp` | `NgxInfiniteScrollEvent` | Compatibility/convenience output for an up trigger. |
|
|
195
|
+
| `scrolledDown` | `NgxInfiniteScrollEvent` | Compatibility/convenience output for a down trigger. |
|
|
196
|
+
| `scrollStartReached` | `NgxInfiniteScrollEvent` | Convenience output for the top edge. |
|
|
197
|
+
| `scrollEndReached` | `NgxInfiniteScrollEvent` | Convenience output for the bottom edge. |
|
|
198
|
+
|
|
199
|
+
### `NgxInfiniteScrollEvent`
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
export interface NgxInfiniteScrollEvent {
|
|
203
|
+
direction: 'up' | 'down';
|
|
204
|
+
distance: number;
|
|
205
|
+
target: HTMLElement;
|
|
206
|
+
root: HTMLElement | null;
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Performance model
|
|
211
|
+
|
|
212
|
+
The directive does **not** install a continuous `scroll` handler. Instead, it creates two tiny sentinels:
|
|
213
|
+
|
|
214
|
+
```text
|
|
215
|
+
┌──────────────────────────────┐
|
|
216
|
+
│ top sentinel │ ← up
|
|
217
|
+
│ │
|
|
218
|
+
│ application items │
|
|
219
|
+
│ application items │
|
|
220
|
+
│ application items │
|
|
221
|
+
│ │
|
|
222
|
+
│ bottom sentinel │ ← down
|
|
223
|
+
└──────────────────────────────┘
|
|
224
|
+
↑
|
|
225
|
+
IntersectionObserver
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
The observer is created outside Angular's zone. Angular is re-entered only for an actual `scrolled`/edge output. This keeps scrolling/layout work in the browser platform rather than turning every scroll movement into Angular work.
|
|
229
|
+
|
|
230
|
+
The directive also stays passive about data ownership: application state owns the items, loading state, pagination, retry logic, and end-of-list state. The directive only reports that an edge is close.
|
|
231
|
+
|
|
232
|
+
## Why not a scroll listener?
|
|
233
|
+
|
|
234
|
+
A classic implementation continuously evaluates:
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
scrollTop + clientHeight >= scrollHeight - threshold;
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
That can work, but it means the application needs to receive and process a high-frequency browser event. IntersectionObserver lets the browser manage the geometry observation and calls the application when the sentinel actually crosses the configured boundary.
|
|
241
|
+
|
|
242
|
+
## SSR
|
|
243
|
+
|
|
244
|
+
The package does not touch browser-only APIs until the directive is running in a browser. `IntersectionObserver`, `ResizeObserver`, `MutationObserver`, `window`, and `document` are all guarded by the browser platform check or accessed after view initialization.
|
|
245
|
+
|
|
246
|
+
This makes it safe to include in an Angular application that uses SSR.
|
|
247
|
+
|
|
248
|
+
## Package design notes
|
|
249
|
+
|
|
250
|
+
This primitive intentionally does not provide pagination state, API calls, retry policy, loaders, virtual scrolling, or item caching. Those concerns belong to the application/data layer.
|
|
251
|
+
|
|
252
|
+
For very large datasets, combine this directive with ngx-kit virtual scrolling rather than rendering tens of thousands of nodes into the DOM. Infinite scroll decides **when to fetch**; virtual scrolling decides **how much DOM to keep**.
|
package/menu/README.md
CHANGED
|
@@ -1,85 +1,85 @@
|
|
|
1
|
-
# ngx-kit/menu
|
|
2
|
-
|
|
3
|
-
Dropdown menu and context (right-click) menu, with smart positioning relative to an anchor (via `ngx-kit/shared`'s `OverlayService`).
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install ngx-kit
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Basic usage (dropdown menu)
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
import { NgxMenuModule } from 'ngx-kit/menu';
|
|
15
|
-
|
|
16
|
-
@Component({
|
|
17
|
-
standalone: true,
|
|
18
|
-
imports: [NgxMenuModule],
|
|
19
|
-
template: `
|
|
20
|
-
<button [ngxMenu]="userMenu">Open menu</button>
|
|
21
|
-
|
|
22
|
-
<ngx-menu #userMenu="ngxMenu">
|
|
23
|
-
<ngx-menu-item (click)="editProfile()">Edit profile</ngx-menu-item>
|
|
24
|
-
<ngx-menu-item (click)="logout()">Sign out</ngx-menu-item>
|
|
25
|
-
<ngx-menu-divider></ngx-menu-divider>
|
|
26
|
-
<ngx-menu-item [ngxMenu]="subMenu">More settings ›</ngx-menu-item>
|
|
27
|
-
</ngx-menu>
|
|
28
|
-
|
|
29
|
-
<ngx-menu #subMenu="ngxMenu">
|
|
30
|
-
<ngx-menu-item>Option A</ngx-menu-item>
|
|
31
|
-
<ngx-menu-item>Option B</ngx-menu-item>
|
|
32
|
-
</ngx-menu>
|
|
33
|
-
`,
|
|
34
|
-
})
|
|
35
|
-
export class MyComponent {}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
Important: `<ngx-menu>`'s content isn't rendered until it's triggered via `[ngxMenu]` (or `[ngxContextMenu]`) — so you can't use `<ngx-menu>` directly, without a trigger, as an always-visible list (like a sidebar). For that, use a regular list styled similarly.
|
|
39
|
-
|
|
40
|
-
Nested menus (submenus) work exactly as shown above, just by putting `[ngxMenu]` on the `<ngx-menu-item>` itself.
|
|
41
|
-
|
|
42
|
-
## Right-click (context) menu
|
|
43
|
-
|
|
44
|
-
```html
|
|
45
|
-
<div [ngxContextMenu]="rightClickMenu">Right-click me</div>
|
|
46
|
-
|
|
47
|
-
<ngx-menu #rightClickMenu="ngxMenu">
|
|
48
|
-
<ngx-menu-item>Copy</ngx-menu-item>
|
|
49
|
-
<ngx-menu-item>Paste</ngx-menu-item>
|
|
50
|
-
</ngx-menu>
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## API
|
|
54
|
-
|
|
55
|
-
### `[ngxMenu]` directive
|
|
56
|
-
|
|
57
|
-
| Input | Type | Description |
|
|
58
|
-
| ----------- | ----------------------------- | ----------------------------------------------------------------------------------------- |
|
|
59
|
-
| `ngxMenu` | `NgxMenu \| TemplateRef` | Reference to the menu to open |
|
|
60
|
-
| `placement` | `'top' \| 'bottom' \| 'auto'` | Opening direction; defaults to `'auto'` (picked automatically if there isn't enough room) |
|
|
61
|
-
|
|
62
|
-
### `<ngx-menu>`
|
|
63
|
-
|
|
64
|
-
| Input | Type | Description |
|
|
65
|
-
| ------- | -------- | ---------------------------- |
|
|
66
|
-
| `class` | `string` | Extra CSS class on the panel |
|
|
67
|
-
|
|
68
|
-
### Styling
|
|
69
|
-
|
|
70
|
-
Via CSS custom properties:
|
|
71
|
-
|
|
72
|
-
```css
|
|
73
|
-
ngx-menu {
|
|
74
|
-
--ngx-menu-bg: light-dark(#fff, #252425);
|
|
75
|
-
--ngx-menu-fg: light-dark(#000, #fff);
|
|
76
|
-
--ngx-menu-radius: 10px;
|
|
77
|
-
--ngx-menu-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
|
|
78
|
-
--ngx-menu-item-padding: 8px 14px;
|
|
79
|
-
--ngx-menu-item-hover-bg: #9bc6ff68;
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## Dark mode and RTL
|
|
84
|
-
|
|
85
|
-
Both are supported automatically (via `ngx-kit/shared`'s `OverlayService`/`DirectionService` and `light-dark()`); no extra work needed.
|
|
1
|
+
# ngx-kit/menu
|
|
2
|
+
|
|
3
|
+
Dropdown menu and context (right-click) menu, with smart positioning relative to an anchor (via `ngx-kit/shared`'s `OverlayService`).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install ngx-kit
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Basic usage (dropdown menu)
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { NgxMenuModule } from 'ngx-kit/menu';
|
|
15
|
+
|
|
16
|
+
@Component({
|
|
17
|
+
standalone: true,
|
|
18
|
+
imports: [NgxMenuModule],
|
|
19
|
+
template: `
|
|
20
|
+
<button [ngxMenu]="userMenu">Open menu</button>
|
|
21
|
+
|
|
22
|
+
<ngx-menu #userMenu="ngxMenu">
|
|
23
|
+
<ngx-menu-item (click)="editProfile()">Edit profile</ngx-menu-item>
|
|
24
|
+
<ngx-menu-item (click)="logout()">Sign out</ngx-menu-item>
|
|
25
|
+
<ngx-menu-divider></ngx-menu-divider>
|
|
26
|
+
<ngx-menu-item [ngxMenu]="subMenu">More settings ›</ngx-menu-item>
|
|
27
|
+
</ngx-menu>
|
|
28
|
+
|
|
29
|
+
<ngx-menu #subMenu="ngxMenu">
|
|
30
|
+
<ngx-menu-item>Option A</ngx-menu-item>
|
|
31
|
+
<ngx-menu-item>Option B</ngx-menu-item>
|
|
32
|
+
</ngx-menu>
|
|
33
|
+
`,
|
|
34
|
+
})
|
|
35
|
+
export class MyComponent {}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Important: `<ngx-menu>`'s content isn't rendered until it's triggered via `[ngxMenu]` (or `[ngxContextMenu]`) — so you can't use `<ngx-menu>` directly, without a trigger, as an always-visible list (like a sidebar). For that, use a regular list styled similarly.
|
|
39
|
+
|
|
40
|
+
Nested menus (submenus) work exactly as shown above, just by putting `[ngxMenu]` on the `<ngx-menu-item>` itself.
|
|
41
|
+
|
|
42
|
+
## Right-click (context) menu
|
|
43
|
+
|
|
44
|
+
```html
|
|
45
|
+
<div [ngxContextMenu]="rightClickMenu">Right-click me</div>
|
|
46
|
+
|
|
47
|
+
<ngx-menu #rightClickMenu="ngxMenu">
|
|
48
|
+
<ngx-menu-item>Copy</ngx-menu-item>
|
|
49
|
+
<ngx-menu-item>Paste</ngx-menu-item>
|
|
50
|
+
</ngx-menu>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## API
|
|
54
|
+
|
|
55
|
+
### `[ngxMenu]` directive
|
|
56
|
+
|
|
57
|
+
| Input | Type | Description |
|
|
58
|
+
| ----------- | ----------------------------- | ----------------------------------------------------------------------------------------- |
|
|
59
|
+
| `ngxMenu` | `NgxMenu \| TemplateRef` | Reference to the menu to open |
|
|
60
|
+
| `placement` | `'top' \| 'bottom' \| 'auto'` | Opening direction; defaults to `'auto'` (picked automatically if there isn't enough room) |
|
|
61
|
+
|
|
62
|
+
### `<ngx-menu>`
|
|
63
|
+
|
|
64
|
+
| Input | Type | Description |
|
|
65
|
+
| ------- | -------- | ---------------------------- |
|
|
66
|
+
| `class` | `string` | Extra CSS class on the panel |
|
|
67
|
+
|
|
68
|
+
### Styling
|
|
69
|
+
|
|
70
|
+
Via CSS custom properties:
|
|
71
|
+
|
|
72
|
+
```css
|
|
73
|
+
ngx-menu {
|
|
74
|
+
--ngx-menu-bg: light-dark(#fff, #252425);
|
|
75
|
+
--ngx-menu-fg: light-dark(#000, #fff);
|
|
76
|
+
--ngx-menu-radius: 10px;
|
|
77
|
+
--ngx-menu-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
|
|
78
|
+
--ngx-menu-item-padding: 8px 14px;
|
|
79
|
+
--ngx-menu-item-hover-bg: #9bc6ff68;
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Dark mode and RTL
|
|
84
|
+
|
|
85
|
+
Both are supported automatically (via `ngx-kit/shared`'s `OverlayService`/`DirectionService` and `light-dark()`); no extra work needed.
|
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.
|