ngx-kit 7.3.2 → 7.4.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/fesm2022/ngx-kit-box-shadow.mjs +2 -2
- package/fesm2022/ngx-kit-box-shadow.mjs.map +1 -1
- package/fesm2022/ngx-kit-date-picker.mjs +27 -22
- package/fesm2022/ngx-kit-date-picker.mjs.map +1 -1
- package/fesm2022/ngx-kit-dialog.mjs +6 -5
- package/fesm2022/ngx-kit-dialog.mjs.map +1 -1
- package/fesm2022/ngx-kit-dropzone.mjs +5 -5
- package/fesm2022/ngx-kit-dropzone.mjs.map +1 -1
- package/fesm2022/ngx-kit-image-editor.mjs +14 -26
- package/fesm2022/ngx-kit-image-editor.mjs.map +1 -1
- package/fesm2022/ngx-kit-media-control-mse-media-engine-CtP97cb9.mjs +326 -0
- package/fesm2022/ngx-kit-media-control-mse-media-engine-CtP97cb9.mjs.map +1 -0
- package/fesm2022/ngx-kit-media-control.mjs +1847 -0
- package/fesm2022/ngx-kit-media-control.mjs.map +1 -0
- package/media-control/README.md +349 -0
- package/package.json +5 -1
- package/types/ngx-kit-date-picker.d.ts +1 -1
- package/types/ngx-kit-dialog.d.ts +1 -2
- package/types/ngx-kit-dropzone.d.ts +4 -4
- package/types/ngx-kit-image-editor.d.ts +10 -27
- package/types/ngx-kit-media-control.d.ts +671 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# ngx-kit/media-control
|
|
2
|
+
|
|
3
|
+
An Angular-native Audio/Video player: native `<audio>`/`<video>` fast path,
|
|
4
|
+
optional MSE and WASM decoder backends, DI-based decoder plugins, signals
|
|
5
|
+
throughout, SSR- and zoneless-safe.
|
|
6
|
+
|
|
7
|
+
> Migrating from `ngx-audio-control`? Nothing breaks — see
|
|
8
|
+
> [Migrating from `NgxAudioControl`](#migrating-from-ngxaudiocontrol).
|
|
9
|
+
|
|
10
|
+
## 1. Installation
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
npm install ngx-kit --save
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## 2. Basic audio usage
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { NgxMediaControl } from 'ngx-kit/media-control';
|
|
20
|
+
|
|
21
|
+
@Component({
|
|
22
|
+
imports: [NgxMediaControl],
|
|
23
|
+
template: `<ngx-media-control type="audio" [fileList]="files" [download]="true" />`,
|
|
24
|
+
})
|
|
25
|
+
export class PlayerComponent {
|
|
26
|
+
files = ['assets/a.mp3', 'assets/b.mp3'];
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 3. Basic video usage
|
|
31
|
+
|
|
32
|
+
```html
|
|
33
|
+
<ngx-media-control type="video" [sources]="[{ src: 'assets/clip.mp4', poster: 'assets/poster.jpg' }]" />
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 4. Audio + video configuration
|
|
37
|
+
|
|
38
|
+
`type` is `'audio' | 'video' | 'both'`:
|
|
39
|
+
|
|
40
|
+
- `'audio'` — no video frame is rendered even if a source has a video track.
|
|
41
|
+
- `'video'` — video frame, fullscreen/PiP controls (when the browser supports them).
|
|
42
|
+
- `'both'` — video frame is rendered; degrades to audio-style controls when the active source has no video track.
|
|
43
|
+
|
|
44
|
+
## 5. Playlist
|
|
45
|
+
|
|
46
|
+
Use `sources` (typed, supports metadata) instead of the legacy `fileList` (plain string URLs) when you need titles/artist/poster/codecs/download URLs:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
sources: NgxMediaSource[] = [
|
|
50
|
+
{ src: 'a.mp3', title: 'Track A', artist: 'Someone' },
|
|
51
|
+
{ src: 'b.mp3', title: 'Track B' },
|
|
52
|
+
];
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 6. Controls (inputs)
|
|
56
|
+
|
|
57
|
+
| Input | Type | Default | Notes |
|
|
58
|
+
|---|---|---|---|
|
|
59
|
+
| `type` | `'audio' \| 'video' \| 'both'` | `'audio'` | new |
|
|
60
|
+
| `poster` | `string` | — | new, video only |
|
|
61
|
+
| `showList` | `boolean` | `true` | unchanged |
|
|
62
|
+
| `download` | `boolean` | `false` | unchanged |
|
|
63
|
+
| `showFileName` | `boolean` | `true` | unchanged |
|
|
64
|
+
| `showSpeed` | `boolean` | `true` | unchanged |
|
|
65
|
+
| `showVolume` | `boolean` | `true` | unchanged |
|
|
66
|
+
| `linear` | `boolean` | `false` | unchanged |
|
|
67
|
+
| `preload` | `'none' \| 'metadata' \| 'auto'` | `'metadata'` | unchanged |
|
|
68
|
+
| `fetchHeaders` | `HeadersInit` | — | see note below — NOT sent on plain native playback |
|
|
69
|
+
| `fileList` | `string[]` | — | unchanged, still works |
|
|
70
|
+
| `sources` | `NgxMediaSource[]` | — | new, preferred |
|
|
71
|
+
|
|
72
|
+
Outputs: `trackChange` (fires with the active `NgxMediaSource`), `error` (fires with a human-readable message; inspect `NgxMediaError.category` if you're subscribing programmatically via the facade in your own wrapper).
|
|
73
|
+
|
|
74
|
+
> **`fetchHeaders` platform limitation.** A native `<audio src>`/`<video src>`
|
|
75
|
+
> fetch cannot carry arbitrary request headers — that's a browser limitation,
|
|
76
|
+
> not something this library papers over with a hidden `fetch()` + `Blob`
|
|
77
|
+
> step (which would break streaming/range-requests for anything but small
|
|
78
|
+
> clips). `fetchHeaders` is applied as the default `requestHeaders` for any
|
|
79
|
+
> resolved source that doesn't specify its own, and only actually takes
|
|
80
|
+
> effect for sources that end up on a decoder/MSE backend — both of which
|
|
81
|
+
> fetch through `NGX_MEDIA_REQUEST_HANDLER` and can carry headers. For a
|
|
82
|
+
> plain natively-playable URL, set headers via a signed/short-lived URL or a
|
|
83
|
+
> `NGX_MEDIA_REQUEST_HANDLER`-based backend instead.
|
|
84
|
+
|
|
85
|
+
## 7. Media sources
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
export interface NgxMediaSource {
|
|
89
|
+
src: string | Blob | File | MediaStream;
|
|
90
|
+
type?: string;
|
|
91
|
+
codecs?: string;
|
|
92
|
+
title?: string;
|
|
93
|
+
artist?: string;
|
|
94
|
+
album?: string;
|
|
95
|
+
poster?: string;
|
|
96
|
+
downloadUrl?: string;
|
|
97
|
+
downloadFileName?: string;
|
|
98
|
+
requestHeaders?: HeadersInit;
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Playback source and download source are independent (`downloadUrl`) — the
|
|
103
|
+
playback URL is not assumed to be publicly downloadable or vice versa.
|
|
104
|
+
|
|
105
|
+
## 8. Browser support
|
|
106
|
+
|
|
107
|
+
Chrome, Edge, Firefox, Safari (desktop + iOS), Android WebView. Every
|
|
108
|
+
optional API (`MediaSource`, `AudioContext`, `mediaSession`,
|
|
109
|
+
`requestPictureInPicture`, `requestFullscreen`) is feature-detected at the
|
|
110
|
+
call site (`utils/capabilities.ts`) before use; the UI hides the
|
|
111
|
+
corresponding control when unsupported instead of showing a broken button.
|
|
112
|
+
|
|
113
|
+
## 9. Native playback
|
|
114
|
+
|
|
115
|
+
The default `MediaEngineFactory` always tries a native `<audio>`/`<video>`
|
|
116
|
+
element first via `HTMLMediaElement.canPlayType()` combined with an explicit
|
|
117
|
+
`type`/`codecs` you supply (never trusting the file extension alone — see
|
|
118
|
+
`utils/capabilities.ts`). This is the fast path for MP3/AAC/WAV/OGG/Opus/WebM/MP4/etc.
|
|
119
|
+
whenever the browser can decode them itself.
|
|
120
|
+
|
|
121
|
+
## 10. Decoder architecture
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
Source
|
|
125
|
+
│
|
|
126
|
+
▼
|
|
127
|
+
Capability detection (canPlayType + type/codecs)
|
|
128
|
+
│
|
|
129
|
+
├─ native? ───────────► NativeMediaEngine (<audio>/<video>)
|
|
130
|
+
│
|
|
131
|
+
└─ not native ─► NgxMediaDecoderRegistry.findDecoder()
|
|
132
|
+
│
|
|
133
|
+
├─ found ─► decoder.createEngine() → WASM / MSE / custom engine
|
|
134
|
+
└─ none ─► NgxMediaError('UNSUPPORTED_FORMAT')
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The UI (`NgxMediaControl`) never touches an engine directly — it only calls
|
|
138
|
+
`NgxMediaFacade`, which asks `NgxMediaEngineFactory` for a native engine and
|
|
139
|
+
actually attempts `load()` before ever consulting the decoder registry.
|
|
140
|
+
`canPlayType()`/extension/mime are only ever a hint, not a guarantee — a
|
|
141
|
+
mislabeled or fake extension, or a container the browser opens but can't
|
|
142
|
+
actually decode, only shows up as a genuine failure once `load()` is
|
|
143
|
+
attempted, so the decoder registry is tried on a real failure, not on a
|
|
144
|
+
pessimistic upfront guess. Swapping the engine implementation never touches
|
|
145
|
+
the component.
|
|
146
|
+
|
|
147
|
+
## 11. WASM decoders
|
|
148
|
+
|
|
149
|
+
**Is there an npm package you can install today to try this?** Yes —
|
|
150
|
+
[`@ffmpeg/ffmpeg`](https://www.npmjs.com/package/@ffmpeg/ffmpeg) is the
|
|
151
|
+
general-purpose answer (handles 3GP, WMA, AMR, FLV, and effectively
|
|
152
|
+
anything FFmpeg reads). For narrower needs there are also small pure-WASM
|
|
153
|
+
decoders like `opus-decoder`/`mpg123-decoder` if you specifically only need
|
|
154
|
+
one codec and want a much smaller download than FFmpeg's ~25MB core.
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
npm install @ffmpeg/ffmpeg @ffmpeg/util @ffmpeg/core
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
A complete, copy-pasteable decoder built on it is in
|
|
161
|
+
`examples/ffmpeg-transcode-decoder.example.ts` (outside the library's own
|
|
162
|
+
source tree on purpose, so the library itself never depends on `@ffmpeg/*`
|
|
163
|
+
— see below). It transcodes the unsupported source into `wav`/`mp4`
|
|
164
|
+
in-memory and hands the result to `NativeMediaEngine`, reusing all of the
|
|
165
|
+
native engine's playback/seek/event handling instead of reimplementing it.
|
|
166
|
+
Copy that file into your app (e.g. `src/app/decoders/`) and register it:
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { provideNgxMediaDecoder } from 'ngx-kit/media-control';
|
|
170
|
+
import { FfmpegTranscodeDecoder } from './decoders/ffmpeg-transcode-decoder.example';
|
|
171
|
+
|
|
172
|
+
bootstrapApplication(AppComponent, {
|
|
173
|
+
providers: [provideNgxMediaDecoder(FfmpegTranscodeDecoder)],
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
`NgxWasmDecoderBase` (in `decoders/wasm-decoder.base.ts`) is the harness: it
|
|
180
|
+
lazily `import()`s your codec module (and optionally runs it in a `Worker`)
|
|
181
|
+
on first real use, so nothing WASM-related ever enters the default bundle.
|
|
182
|
+
**No real codec ships with this library** — bundling e.g. FFmpeg/WASM into
|
|
183
|
+
the core would defeat the "lightweight native fast path" requirement for
|
|
184
|
+
every consumer, including those who never need it. You extend the base class
|
|
185
|
+
with your own `loadModule()`/`buildEngine()`; `DecodedBufferEngine` is
|
|
186
|
+
provided as a ready-made `NgxMediaEngine` for decoders that decode a full
|
|
187
|
+
clip into an `AudioBuffer` and play it via Web Audio.
|
|
188
|
+
|
|
189
|
+
## 12. Custom decoder development
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
import { NgxMediaDecoder, NgxMediaSource, provideNgxMediaDecoder } from 'ngx-kit/media-control';
|
|
193
|
+
|
|
194
|
+
@Injectable()
|
|
195
|
+
export class My3gpDecoder implements NgxMediaDecoder {
|
|
196
|
+
readonly id = '3gp';
|
|
197
|
+
readonly formats = ['3gp'];
|
|
198
|
+
readonly priority = 0;
|
|
199
|
+
|
|
200
|
+
canDecode(source: NgxMediaSource) {
|
|
201
|
+
return source.type === 'video/3gpp';
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async createEngine(source: NgxMediaSource) {
|
|
205
|
+
// return any NgxMediaEngine — e.g. extend NgxWasmDecoderBase, or build
|
|
206
|
+
// one by hand around MSE/Web Audio.
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
destroy() {}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## 13. Angular DI registration
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
bootstrapApplication(AppComponent, {
|
|
217
|
+
providers: [
|
|
218
|
+
provideNgxMedia(), // optional global config
|
|
219
|
+
provideNgxMediaDecoder(My3gpDecoder),
|
|
220
|
+
// provideNgxMediaRequestHandler({ request: (source, signal) => myFetch(source, signal) }),
|
|
221
|
+
],
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
`provideNgxMediaDecoder` registers into the `NGX_MEDIA_DECODER` multi
|
|
226
|
+
token; register as many as you like, `priority` (higher first) breaks ties
|
|
227
|
+
when more than one decoder claims the same source.
|
|
228
|
+
|
|
229
|
+
## 14. Performance
|
|
230
|
+
|
|
231
|
+
- No polling: every state field is driven by a real media event (`timeupdate`, `progress`, `durationchange`, ...).
|
|
232
|
+
- All native listeners are attached inside `NgZone.runOutsideAngular` via the facade; the only thing that can trigger a render is a signal write, which OnPush + signals coalesce naturally — high-frequency events don't cause excess change detection.
|
|
233
|
+
- `AudioContext`/Web Audio graph is created lazily, only if a consumer calls into it.
|
|
234
|
+
- WASM/MSE code paths are behind dynamic `import()`.
|
|
235
|
+
|
|
236
|
+
## 15. SSR
|
|
237
|
+
|
|
238
|
+
Every browser API access is guarded by `isBrowser()`
|
|
239
|
+
(`utils/capabilities.ts`). `NgxMediaEngineFactory.create()` throws a typed
|
|
240
|
+
`NgxMediaError('BROWSER_UNSUPPORTED', ...)` rather than crashing if somehow
|
|
241
|
+
invoked outside a browser context.
|
|
242
|
+
|
|
243
|
+
## 16. Zoneless Angular
|
|
244
|
+
|
|
245
|
+
The facade and engines are 100% signal-driven; nothing relies on Zone.js
|
|
246
|
+
patches. `NgZone.runOutsideAngular` is used defensively for zone-based apps
|
|
247
|
+
but is a no-op wrapper under zoneless change detection.
|
|
248
|
+
|
|
249
|
+
## 17. Web Audio
|
|
250
|
+
|
|
251
|
+
Opt-in only, via `facade.getWebAudioGraph()` inside your own extension —
|
|
252
|
+
gain/analyser nodes are created lazily on first access. Never bypasses
|
|
253
|
+
autoplay policy; `resumeOnUserGesture()` must be called from a real user
|
|
254
|
+
gesture handler.
|
|
255
|
+
|
|
256
|
+
## 18. MSE
|
|
257
|
+
|
|
258
|
+
`engines/mse-media-engine.ts` is a real, working single-`SourceBuffer`
|
|
259
|
+
progressive-fetch engine, reached only via explicit opt-in
|
|
260
|
+
(`NgxMediaEngineFactory.createMse()`, typically from inside a decoder). It is
|
|
261
|
+
not an ABR/manifest (DASH/HLS) player — that's a decoder plugin's job, built
|
|
262
|
+
on top of this engine.
|
|
263
|
+
|
|
264
|
+
## 19. Media Session
|
|
265
|
+
|
|
266
|
+
Wired automatically (`facade/media-session.ts`) whenever `navigator.mediaSession`
|
|
267
|
+
exists: play/pause/prev/next/seek actions and `title`/`artist`/`album`/`poster`
|
|
268
|
+
metadata. No-ops everywhere the API is absent.
|
|
269
|
+
|
|
270
|
+
## 20. Fullscreen
|
|
271
|
+
|
|
272
|
+
Shown automatically for `type="video"`/`"both"` when `document.fullscreenEnabled`
|
|
273
|
+
is true. Double-clicking the video also toggles fullscreen.
|
|
274
|
+
|
|
275
|
+
## 21. Picture-in-Picture
|
|
276
|
+
|
|
277
|
+
Shown automatically when `document.pictureInPictureEnabled` /
|
|
278
|
+
`HTMLVideoElement.prototype.requestPictureInPicture` exist.
|
|
279
|
+
|
|
280
|
+
## 22. Error handling
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
export type NgxMediaErrorCategory =
|
|
284
|
+
| 'NETWORK' | 'UNSUPPORTED_FORMAT' | 'DECODER' | 'ABORTED'
|
|
285
|
+
| 'AUTOPLAY_BLOCKED' | 'MEDIA' | 'PERMISSION' | 'BROWSER_UNSUPPORTED' | 'UNKNOWN';
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
`NgxMediaError` carries a `category` and human-readable `message`; the
|
|
289
|
+
component's `error` output emits the message, and `NgxMediaError.cause`
|
|
290
|
+
keeps the original DOM/browser error for logging without leaking it into the
|
|
291
|
+
template.
|
|
292
|
+
|
|
293
|
+
## 23. Security limitations
|
|
294
|
+
|
|
295
|
+
Client-side code cannot prevent someone from downloading a file the browser
|
|
296
|
+
can already fetch and play. This library does not implement URL obfuscation
|
|
297
|
+
and call it security. For genuine protection, use short-lived signed URLs
|
|
298
|
+
and/or authenticated requests — `NGX_MEDIA_REQUEST_HANDLER` lets you plug in
|
|
299
|
+
your own authenticated fetcher without coupling the core to `HttpClient`.
|
|
300
|
+
|
|
301
|
+
## 24. Examples
|
|
302
|
+
|
|
303
|
+
See `demo/media-control/` for a working audio + video showcase, including
|
|
304
|
+
the exact custom-decoder registration snippet from §12.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Seeking support on your server
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
### IIS `web.config`
|
|
312
|
+
```xml
|
|
313
|
+
<system.webServer>
|
|
314
|
+
<httpProtocol>
|
|
315
|
+
<customHeaders>
|
|
316
|
+
<add name="Accept-Ranges" value="bytes" />
|
|
317
|
+
</customHeaders>
|
|
318
|
+
</httpProtocol>
|
|
319
|
+
</system.webServer>
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Apache `.htaccess`
|
|
323
|
+
```
|
|
324
|
+
<IfModule mod_headers.c>
|
|
325
|
+
Header set Accept-Ranges bytes
|
|
326
|
+
</IfModule>
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Nginx `nginx.conf`
|
|
330
|
+
```
|
|
331
|
+
http {
|
|
332
|
+
server {
|
|
333
|
+
location / {
|
|
334
|
+
add_header Accept-Ranges bytes;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Migrating from `NgxAudioControl`
|
|
343
|
+
|
|
344
|
+
Nothing is required. `<ngx-audio-control [fileList]="...">` keeps working —
|
|
345
|
+
it's now a thin wrapper around `<ngx-media-control type="audio">` with the
|
|
346
|
+
exact same inputs/defaults. When you're ready, switch the selector to
|
|
347
|
+
`ngx-media-control` and add `type="audio"` to opt into the richer `sources`
|
|
348
|
+
input, `trackChange`/`error` outputs, and future decoder support.
|
|
349
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ngx-kit",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.4.0",
|
|
4
4
|
"description": "Angular input components",
|
|
5
5
|
"author": "Mohammadreza Samani <mr.samani1368@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -97,6 +97,10 @@
|
|
|
97
97
|
"types": "./types/ngx-kit-infinite-scroll.d.ts",
|
|
98
98
|
"default": "./fesm2022/ngx-kit-infinite-scroll.mjs"
|
|
99
99
|
},
|
|
100
|
+
"./media-control": {
|
|
101
|
+
"types": "./types/ngx-kit-media-control.d.ts",
|
|
102
|
+
"default": "./fesm2022/ngx-kit-media-control.mjs"
|
|
103
|
+
},
|
|
100
104
|
"./menu": {
|
|
101
105
|
"types": "./types/ngx-kit-menu.d.ts",
|
|
102
106
|
"default": "./fesm2022/ngx-kit-menu.mjs"
|
|
@@ -330,7 +330,7 @@ declare class NgxCalendarComponent extends NgxDatePickerBase implements OnInit {
|
|
|
330
330
|
eventChange: EventEmitter<CalendarEventChange>;
|
|
331
331
|
eventsChange: EventEmitter<MsEvents<Date>[]>;
|
|
332
332
|
selected?: Date;
|
|
333
|
-
anchorDate: Date
|
|
333
|
+
anchorDate: _angular_core.WritableSignal<Date | undefined>;
|
|
334
334
|
eventViewItems: {
|
|
335
335
|
event: MsEventViewer;
|
|
336
336
|
start: Date;
|
|
@@ -232,10 +232,9 @@ declare class Dialog {
|
|
|
232
232
|
declare const DIALOG_DATA: InjectionToken<any>;
|
|
233
233
|
declare const DIALOG_REF: InjectionToken<NgxDialogRef<any>>;
|
|
234
234
|
/** The resolved config for the dialog currently being rendered. */
|
|
235
|
-
declare const NGX_DIALOG_DEFAULT_CONFIG: NgxDialogConfig<any>;
|
|
236
235
|
declare const NGX_DIALOG_CONFIG: InjectionToken<NgxDialogConfig<any>>;
|
|
237
236
|
/** The arbitrary content component passed to `open()`, projected via `*ngComponentOutlet`. */
|
|
238
237
|
declare const DIALOG_CONTENT: InjectionToken<Type<any>>;
|
|
239
238
|
|
|
240
|
-
export { DIALOG_CONTENT, DIALOG_DATA, DIALOG_REF, Dialog, NGX_DIALOG_CONFIG,
|
|
239
|
+
export { DIALOG_CONTENT, DIALOG_DATA, DIALOG_REF, Dialog, NGX_DIALOG_CONFIG, NgxDialogBody, NgxDialogComponent, NgxDialogConfig, NgxDialogFooter, NgxDialogHeader, NgxDialogModule, NgxDialogService, provideNgxDialog };
|
|
241
240
|
export type { NgxDialogFooterAlign, NgxDialogFooterConfig, NgxDialogHeaderConfig, NgxDialogSize };
|
|
@@ -77,7 +77,7 @@ interface NgxDropzoneFileLike {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
type NgxDropzoneUploadMode = 'all' | 'single';
|
|
80
|
-
declare class
|
|
80
|
+
declare class NgxDropzone implements OnDestroy {
|
|
81
81
|
/** الگوی accept مثل input[type=file]: "image/*", ".pdf,.docx" و ... */
|
|
82
82
|
accept: _angular_core.InputSignal<string>;
|
|
83
83
|
multiple: _angular_core.InputSignal<boolean>;
|
|
@@ -157,8 +157,8 @@ declare class NgxDropzoneComponent implements OnDestroy {
|
|
|
157
157
|
private finishUpload;
|
|
158
158
|
private updateFile;
|
|
159
159
|
private emitCurrentFiles;
|
|
160
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<
|
|
161
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<
|
|
160
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgxDropzone, never>;
|
|
161
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<NgxDropzone, "ngx-dropzone", never, { "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "maxFileSize": { "alias": "maxFileSize"; "required": false; "isSignal": true; }; "maxFiles": { "alias": "maxFiles"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "showFileList": { "alias": "showFileList"; "required": false; "isSignal": true; }; "uploadUrl": { "alias": "uploadUrl"; "required": false; "isSignal": true; }; "uploadAlias": { "alias": "uploadAlias"; "required": false; "isSignal": true; }; "autoUpload": { "alias": "autoUpload"; "required": false; "isSignal": true; }; "maxParallel": { "alias": "maxParallel"; "required": false; "isSignal": true; }; "uploadMode": { "alias": "uploadMode"; "required": false; "isSignal": true; }; "uploadData": { "alias": "uploadData"; "required": false; "isSignal": true; }; "uploadHeaders": { "alias": "uploadHeaders"; "required": false; "isSignal": true; }; "uploadWithCredentials": { "alias": "uploadWithCredentials"; "required": false; "isSignal": true; }; }, { "filesAdded": "filesAdded"; "filesRejected": "filesRejected"; "filesChange": "filesChange"; "uploadStarted": "uploadStarted"; "uploadProgress": "uploadProgress"; "uploadSuccess": "uploadSuccess"; "uploadError": "uploadError"; }, never, ["[dropzone-icon]", "*"], true, never>;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
declare class NgxDropzoneHttpUploadService implements NgxDropzoneUploadService {
|
|
@@ -191,5 +191,5 @@ declare function formatBytes(bytes: number): string;
|
|
|
191
191
|
/** استخراج فایلهای واقعی از یک DataTransfer، شامل پیمایش بازگشتیِ پوشهها (وقتی مرورگر پشتیبانی کنه) */
|
|
192
192
|
declare function extractFilesFromDataTransfer(dataTransfer: DataTransfer): Promise<File[]>;
|
|
193
193
|
|
|
194
|
-
export { NGX_DROPZONE_UPLOAD_SERVICE,
|
|
194
|
+
export { NGX_DROPZONE_UPLOAD_SERVICE, NgxDropzone, NgxDropzoneHttpUploadService, extractFilesFromDataTransfer, formatBytes, matchesAccept };
|
|
195
195
|
export type { NgxDropzoneFile, NgxDropzoneFileLike, NgxDropzoneFileStatus, NgxDropzoneRejectedFile, NgxDropzoneRejectionReason, NgxDropzoneUploadEvent, NgxDropzoneUploadMode, NgxDropzoneUploadProgressEvent, NgxDropzoneUploadRequest, NgxDropzoneUploadService };
|
|
@@ -9,6 +9,7 @@ interface NgxCropRect {
|
|
|
9
9
|
height: number;
|
|
10
10
|
}
|
|
11
11
|
type NgxImageFilterPreset = 'none' | 'grayscale' | 'sepia' | 'invert' | 'cartoon';
|
|
12
|
+
type NgxImageFileType = 'image/jpeg' | 'image/png' | 'image/webp';
|
|
12
13
|
interface NgxImageEditorAdjustments {
|
|
13
14
|
/** همه ۱۰۰ یعنی بدون تغییر؛ بازهی معقول ۰ تا ۲۰۰ */
|
|
14
15
|
brightness: number;
|
|
@@ -19,10 +20,12 @@ interface NgxImageEditorAdjustments {
|
|
|
19
20
|
filter: NgxImageFilterPreset;
|
|
20
21
|
}
|
|
21
22
|
interface NgxImageEditorResult {
|
|
23
|
+
file: File;
|
|
22
24
|
blob: Blob;
|
|
23
25
|
dataUrl: string;
|
|
24
26
|
width: number;
|
|
25
27
|
height: number;
|
|
28
|
+
type: NgxImageFileType;
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
interface NgxPointerDragDelta {
|
|
@@ -75,33 +78,13 @@ declare class NgxImageEditorLocalization {
|
|
|
75
78
|
}
|
|
76
79
|
declare const DEFAULT_NGX_IMAGE_EDITOR_LOCALIZATION: NgxImageEditorLocalization;
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
* (سیاهوسفید، سپیا، معکوس، کارتونی) + فشردهسازی خروجی. کاملاً روی Canvas
|
|
81
|
-
* خام پیاده شده، بدون هیچ وابستگی خارجیای.
|
|
82
|
-
*
|
|
83
|
-
* نکتهی مهمِ معماری: تمام تعامل زنده (چرخوندن، جابهجا/ریسایز کراپباکس،
|
|
84
|
-
* پیشنمایش فیلترها حتی کارتونی) روی یه کپیِ کوچیکشده از تصویر انجام میشه
|
|
85
|
-
* (createWorkingCopy)، نه روی تصویر اصلی که ممکنه چند مگاپیکسل باشه — وگرنه
|
|
86
|
-
* درگکردن اسلایدرها/گوشههای کراپ رو کاربر حس تاخیر میکرد. فقط لحظهی
|
|
87
|
-
* save()، رندر نهایی از روی تصویر اصلیِ کامل انجام میشه.
|
|
88
|
-
*
|
|
89
|
-
* اندازهی صحنه (stage) با panelSize کنترل میشه: عرض همیشه ۱۰۰٪ عرضِ
|
|
90
|
-
* والدِ کامپوننته (با ResizeObserver اندازهگیری میشه، پس با تغییر سایز
|
|
91
|
-
* صفحه/layout هم زنده هماهنگ میمونه)، ارتفاع دقیقاً همون چیزیه که کاربر با
|
|
92
|
-
* panelSize میده. تصویر همیشه با یک مقیاسِ «contain» واقعی (هم بر اساس
|
|
93
|
-
* عرض، هم بر اساس ارتفاع — هرکدوم تنگتره) جا داده میشه، پس کلِ تصویر
|
|
94
|
-
* همیشه در محدودهی همین باکس دیده میشه، صرفنظر از اندازهی واقعیِ فایل.
|
|
95
|
-
* سقفِ مقیاس هم ۱ هست، یعنی تصاویر کوچیک بزرگنمایی نمیشن (که باعثِ محو
|
|
96
|
-
* شدنشون میشد).
|
|
97
|
-
*/
|
|
98
|
-
declare class NgxImageEditorComponent {
|
|
99
|
-
source: _angular_core.InputSignal<string | Blob | File | null>;
|
|
81
|
+
declare class NgxImageEditor {
|
|
82
|
+
source: _angular_core.InputSignal<string | File | Blob | null>;
|
|
100
83
|
/** قفل نسبتِ کراپ (مثلاً ۱ برای آواتار مربعی)؛ undefined یعنی آزاد */
|
|
101
84
|
aspectRatio: _angular_core.InputSignal<number | undefined>;
|
|
102
85
|
outputMaxWidth: _angular_core.InputSignal<number | undefined>;
|
|
103
86
|
outputMaxHeight: _angular_core.InputSignal<number | undefined>;
|
|
104
|
-
outputType: _angular_core.InputSignal<
|
|
87
|
+
outputType: _angular_core.InputSignal<NgxImageFileType>;
|
|
105
88
|
/**
|
|
106
89
|
* کدوم فیلترها نشون داده بشن (و به چه ترتیبی). اگه ندید، هر ۵ تا نشون داده
|
|
107
90
|
* میشن. آرایهی خالی یعنی کلِ بخشِ فیلتر مخفی بشه.
|
|
@@ -161,8 +144,8 @@ declare class NgxImageEditorComponent {
|
|
|
161
144
|
protected onResizeDragMove(corner: Corner, delta: NgxPointerDragDelta): void;
|
|
162
145
|
protected cancel(): void;
|
|
163
146
|
save(): Promise<void>;
|
|
164
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<
|
|
165
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<
|
|
147
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgxImageEditor, never>;
|
|
148
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<NgxImageEditor, "ngx-image-editor", never, { "source": { "alias": "source"; "required": false; "isSignal": true; }; "aspectRatio": { "alias": "aspectRatio"; "required": false; "isSignal": true; }; "outputMaxWidth": { "alias": "outputMaxWidth"; "required": false; "isSignal": true; }; "outputMaxHeight": { "alias": "outputMaxHeight"; "required": false; "isSignal": true; }; "outputType": { "alias": "outputType"; "required": false; "isSignal": true; }; "filters": { "alias": "filters"; "required": false; "isSignal": true; }; "quality": { "alias": "quality"; "required": false; "isSignal": true; }; "localize": { "alias": "localize"; "required": false; "isSignal": true; }; }, { "saved": "saved"; "cancelled": "cancelled"; }, never, never, true, never>;
|
|
166
149
|
}
|
|
167
150
|
|
|
168
151
|
/** یه File/Blob/data-URL/URL رو به یک HTMLImageElement بارگذاریشده تبدیل میکنه */
|
|
@@ -216,5 +199,5 @@ declare function applyCartoonEffect(ctx: CanvasRenderingContext2D, width: number
|
|
|
216
199
|
edgeThreshold?: number;
|
|
217
200
|
}): void;
|
|
218
201
|
|
|
219
|
-
export { DEFAULT_NGX_IMAGE_EDITOR_LOCALIZATION, NGX_IMAGE_EDITOR_LOCALIZATION,
|
|
220
|
-
export type { NgxCropRect, NgxImageEditorAdjustments, NgxImageEditorResult, NgxImageFilterPreset, NgxPointerDragDelta };
|
|
202
|
+
export { DEFAULT_NGX_IMAGE_EDITOR_LOCALIZATION, NGX_IMAGE_EDITOR_LOCALIZATION, NgxImageEditor, NgxImageEditorLocalization, NgxPointerDragDirective, applyCartoonEffect, canvasToBlob, createWorkingCopy, fitWithin, loadImage, renderComposite, renderRotated };
|
|
203
|
+
export type { NgxCropRect, NgxImageEditorAdjustments, NgxImageEditorResult, NgxImageFileType, NgxImageFilterPreset, NgxPointerDragDelta };
|