@nexterajs/ui 0.0.1 → 0.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.
Files changed (63) hide show
  1. package/README.md +279 -34
  2. package/fesm2022/nexterajs-ui-charts.mjs +1096 -0
  3. package/fesm2022/nexterajs-ui-charts.mjs.map +1 -0
  4. package/fesm2022/nexterajs-ui-core.mjs +835 -11
  5. package/fesm2022/nexterajs-ui-core.mjs.map +1 -1
  6. package/fesm2022/nexterajs-ui-display.mjs +1142 -0
  7. package/fesm2022/nexterajs-ui-display.mjs.map +1 -0
  8. package/fesm2022/nexterajs-ui-dropdowns.mjs +621 -69
  9. package/fesm2022/nexterajs-ui-dropdowns.mjs.map +1 -1
  10. package/fesm2022/nexterajs-ui-file-uploader.mjs +576 -11
  11. package/fesm2022/nexterajs-ui-file-uploader.mjs.map +1 -1
  12. package/fesm2022/nexterajs-ui-forms.mjs +2702 -452
  13. package/fesm2022/nexterajs-ui-forms.mjs.map +1 -1
  14. package/fesm2022/nexterajs-ui-grid.mjs +2350 -336
  15. package/fesm2022/nexterajs-ui-grid.mjs.map +1 -1
  16. package/fesm2022/nexterajs-ui-intl.mjs +117 -15
  17. package/fesm2022/nexterajs-ui-intl.mjs.map +1 -1
  18. package/fesm2022/nexterajs-ui-navigation.mjs +1054 -0
  19. package/fesm2022/nexterajs-ui-navigation.mjs.map +1 -0
  20. package/fesm2022/nexterajs-ui-notify.mjs +353 -0
  21. package/fesm2022/nexterajs-ui-notify.mjs.map +1 -0
  22. package/fesm2022/nexterajs-ui-overlay.mjs +1671 -0
  23. package/fesm2022/nexterajs-ui-overlay.mjs.map +1 -0
  24. package/fesm2022/nexterajs-ui-pivot.mjs +191 -136
  25. package/fesm2022/nexterajs-ui-pivot.mjs.map +1 -1
  26. package/fesm2022/nexterajs-ui-shell.mjs +542 -0
  27. package/fesm2022/nexterajs-ui-shell.mjs.map +1 -0
  28. package/fesm2022/nexterajs-ui-styling.mjs +568 -3
  29. package/fesm2022/nexterajs-ui-styling.mjs.map +1 -1
  30. package/fesm2022/nexterajs-ui-tree-view.mjs +150 -18
  31. package/fesm2022/nexterajs-ui-tree-view.mjs.map +1 -1
  32. package/fesm2022/nexterajs-ui-validation.mjs +283 -97
  33. package/fesm2022/nexterajs-ui-validation.mjs.map +1 -1
  34. package/fesm2022/nexterajs-ui.mjs +6 -0
  35. package/fesm2022/nexterajs-ui.mjs.map +1 -1
  36. package/package.json +37 -2
  37. package/styles/_dropdown.scss +150 -1
  38. package/styles/_editor.scss +75 -21
  39. package/styles/_icons.scss +92 -0
  40. package/styles/_mixins.scss +104 -1
  41. package/styles/_scrollbar.scss +134 -0
  42. package/styles/_status.scss +21 -0
  43. package/styles/_toast.scss +243 -0
  44. package/styles/_tokens.scss +467 -2
  45. package/styles/_widget.scss +14 -3
  46. package/styles/index.scss +10 -4
  47. package/types/nexterajs-ui-charts.d.ts +446 -0
  48. package/types/nexterajs-ui-core.d.ts +515 -30
  49. package/types/nexterajs-ui-display.d.ts +720 -0
  50. package/types/nexterajs-ui-dropdowns.d.ts +318 -57
  51. package/types/nexterajs-ui-file-uploader.d.ts +240 -8
  52. package/types/nexterajs-ui-forms.d.ts +772 -43
  53. package/types/nexterajs-ui-grid.d.ts +878 -135
  54. package/types/nexterajs-ui-intl.d.ts +39 -4
  55. package/types/nexterajs-ui-navigation.d.ts +531 -0
  56. package/types/nexterajs-ui-notify.d.ts +149 -0
  57. package/types/nexterajs-ui-overlay.d.ts +703 -0
  58. package/types/nexterajs-ui-pivot.d.ts +91 -70
  59. package/types/nexterajs-ui-shell.d.ts +294 -0
  60. package/types/nexterajs-ui-styling.d.ts +163 -3
  61. package/types/nexterajs-ui-tree-view.d.ts +56 -4
  62. package/types/nexterajs-ui-validation.d.ts +110 -22
  63. package/types/nexterajs-ui.d.ts +6 -0
@@ -1,5 +1,8 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { NxeValidationTarget } from '@nexterajs/ui/core';
2
+ import { NxeValidationTarget, NxeMessageService, NxeFormControlBase, NxeMessageKey } from '@nexterajs/ui/core';
3
+ import { HttpEvent } from '@angular/common/http';
4
+ import { Observable } from 'rxjs';
5
+ import { Validator, AbstractControl, ValidationErrors } from '@angular/forms';
3
6
 
4
7
  /**
5
8
  * `nxe-file-uploader` — drop-in replacement for DevExtreme `dx-file-uploader`.
@@ -13,23 +16,30 @@ import { NxeValidationTarget } from '@nexterajs/ui/core';
13
16
  * `required` rule works — invalid while no file is chosen.
14
17
  */
15
18
  declare class NxeFileUploaderComponent implements NxeValidationTarget {
19
+ /** Shows the per-file cancel button — except in `useForm` mode, where dx never renders one
20
+ * (m_file_uploader.js `_getCancelButton` returns null for useForm before it reads this). */
16
21
  readonly allowCanceling: _angular_core.InputSignal<boolean>;
17
22
  readonly accept: _angular_core.InputSignal<string>;
18
- readonly labelText: _angular_core.InputSignal<string>;
19
- readonly selectButtonText: _angular_core.InputSignal<string>;
20
- /** Accepted for parity; only `useForm` is used (no server upload by the widget). */
23
+ /** Text beside the button; the active language's "or Drop here" when unset. */
24
+ readonly labelText: _angular_core.InputSignal<string | undefined>;
25
+ /** The button's text; the active language's "Select File" when unset. */
26
+ readonly selectButtonText: _angular_core.InputSignal<string | undefined>;
27
+ /** Accepted for parity; only `useForm` is used (no server upload by the widget). It also
28
+ * gates the cancel button, which dx omits in `useForm` mode. */
21
29
  readonly uploadMode: _angular_core.InputSignal<"instantly" | "useButtons" | "useForm">;
22
30
  readonly multiple: _angular_core.InputSignal<boolean>;
23
31
  readonly name: _angular_core.InputSignal<string>;
24
32
  /** Group for a nested nxe-validator (none used today → bare default group). */
25
- readonly validationGroupInput: _angular_core.InputSignal<string>;
33
+ readonly validationGroupInput: _angular_core.InputSignal<string | undefined>;
26
34
  /** Re-emits the native `<input type=file>` change so `$event.target.files[0]` keeps working. */
27
35
  readonly change: _angular_core.OutputEmitterRef<Event>;
28
36
  private readonly fileInput;
29
- readonly file: _angular_core.WritableSignal<File>;
37
+ /** The library's runtime-switchable messages. */
38
+ protected readonly messages: NxeMessageService;
39
+ readonly file: _angular_core.WritableSignal<File | null>;
30
40
  readonly dragOver: _angular_core.WritableSignal<boolean>;
31
41
  readonly focused: _angular_core.WritableSignal<boolean>;
32
- readonly validationError: _angular_core.WritableSignal<string>;
42
+ readonly validationError: _angular_core.WritableSignal<string | null>;
33
43
  getValue(): unknown;
34
44
  validationGroup(): string | undefined;
35
45
  setValidationError(message: string | null): void;
@@ -44,4 +54,226 @@ declare class NxeFileUploaderComponent implements NxeValidationTarget {
44
54
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<NxeFileUploaderComponent, "nxe-file-uploader", never, { "allowCanceling": { "alias": "allowCanceling"; "required": false; "isSignal": true; }; "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "labelText": { "alias": "labelText"; "required": false; "isSignal": true; }; "selectButtonText": { "alias": "selectButtonText"; "required": false; "isSignal": true; }; "uploadMode": { "alias": "uploadMode"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "validationGroupInput": { "alias": "validationGroup"; "required": false; "isSignal": true; }; }, { "change": "change"; }, never, ["*"], true, never>;
45
55
  }
46
56
 
47
- export { NxeFileUploaderComponent };
57
+ /** Where a file is in its life: chosen, on its way to the server, there, or failed. */
58
+ type NxeFileStatus = 'pending' | 'uploading' | 'uploaded' | 'error';
59
+ /**
60
+ * One entry of the value of `nxe-file-input`: the file chosen, and what became of it.
61
+ *
62
+ * Descriptors are immutable; every change produces a new array of new objects. `file` is there while
63
+ * the browser still holds the `File` (a descriptor the server handed back has `serverId` and `url`
64
+ * instead), so a form without an upload can read the files straight from the value.
65
+ */
66
+ interface NxeFileDescriptor {
67
+ /** Stable for the life of the entry; what `track` and the remove/retry/cancel calls use. */
68
+ readonly id: string;
69
+ readonly name: string;
70
+ /** Bytes. */
71
+ readonly size: number;
72
+ /** MIME type as the browser reported it; may be empty. */
73
+ readonly type: string;
74
+ readonly status: NxeFileStatus;
75
+ /** 0 to 100. Live while `uploading`; the value in the form is refreshed at each status change. */
76
+ readonly progress: number;
77
+ /** Why the upload failed or was cancelled. */
78
+ readonly error?: string;
79
+ readonly file?: File;
80
+ /** The server's id for the stored file, once uploaded. */
81
+ readonly serverId?: string;
82
+ /** Where the stored file can be fetched, once uploaded. */
83
+ readonly url?: string;
84
+ }
85
+ /** What an `uploadFn` may emit besides an `HttpEvent`: progress, and optionally the stored file's id and url. */
86
+ interface NxeUploadProgress {
87
+ /** 0 to 100. */
88
+ readonly progress: number;
89
+ readonly serverId?: string;
90
+ readonly url?: string;
91
+ }
92
+ /** An event of an upload: an Angular `HttpEvent` (with `reportProgress`), `{ progress }`, or a bare percentage. */
93
+ type NxeUploadEvent = HttpEvent<unknown> | NxeUploadProgress | number;
94
+ /** What `uploadFn` receives besides the file. */
95
+ interface NxeUploadContext {
96
+ /** Aborted when the user cancels or removes the file; pass it to `fetch`, or ignore it and unsubscribe. */
97
+ readonly signal: AbortSignal;
98
+ readonly descriptor: NxeFileDescriptor;
99
+ }
100
+ /**
101
+ * Uploads one file. Emit progress as it happens and complete when the file is stored; an error is a failed
102
+ * upload. Unsubscribing is how a cancel reaches you, as it is for `HttpClient`.
103
+ */
104
+ type NxeUploadFn = (file: File, context: NxeUploadContext) => Observable<NxeUploadEvent>;
105
+ /** What the server's response body says about the stored file. */
106
+ interface NxeUploadResult {
107
+ readonly serverId?: string;
108
+ readonly url?: string;
109
+ }
110
+ /** Why a file cannot be kept, in the order the rules are checked. */
111
+ type NxeFileIssueKind = 'fileType' | 'fileSize' | 'maxFiles';
112
+ /** Whether `file` matches an `accept` list: `.pdf`, `application/pdf`, `image/*`, comma separated. Empty or `*` accepts all. */
113
+ declare function nxeFileAccepted(file: {
114
+ readonly name: string;
115
+ readonly type: string;
116
+ }, accept: string): boolean;
117
+
118
+ /** One row of the list, with everything the template shows already worked out. */
119
+ interface FileRow {
120
+ readonly file: NxeFileDescriptor;
121
+ /** Why this file cannot be kept (wrong type, too big, over the count), or `null`. */
122
+ readonly issue: {
123
+ readonly kind: NxeFileIssueKind;
124
+ readonly message: string;
125
+ } | null;
126
+ readonly sizeText: string;
127
+ readonly statusText: string;
128
+ readonly failed: boolean;
129
+ readonly canRetry: boolean;
130
+ }
131
+ /**
132
+ * `nxe-file-input` is a file field for forms: the value is the list of files, `NxeFileDescriptor[]`, and it
133
+ * works with `formControlName`, `[formControl]`, `ngModel` and `nxe-form-field`.
134
+ *
135
+ * ```html
136
+ * <nxe-form-field label="Invoice and supporting documents">
137
+ * <nxe-file-input
138
+ * formControlName="attachments"
139
+ * accept=".pdf,image/*"
140
+ * [maxSize]="5 * 1024 * 1024"
141
+ * [maxFiles]="3"
142
+ * uploadUrl="/api/files/upload" />
143
+ * </nxe-form-field>
144
+ * ```
145
+ *
146
+ * **Value.** A file the user picks or drops becomes `{ id, name, size, type, status, progress, file }`. With no
147
+ * upload configured it stays `pending` and the form reads the `File` from the value (to put in a `FormData`
148
+ * itself). With one, it is uploaded as soon as it is added (`autoUpload`, default) and moves through
149
+ * `uploading` to `uploaded` with the server's `serverId` and `url`, or to `error`. A descriptor that came from the
150
+ * server (`writeValue` with `status: 'uploaded'`) shows as an existing attachment, a link when it has a `url`.
151
+ * The form is told at each status change; the progress bar between them is live without churning the form.
152
+ *
153
+ * **Validation.** The control is invalid, with these error keys (which `nxe-form-field` words in the active
154
+ * language), until the problem is removed:
155
+ *
156
+ * | key | when | error value |
157
+ * |---|---|---|
158
+ * | `fileType` | a file does not match `accept` | `{ accept, files }` |
159
+ * | `fileSize` | a file is over `maxSize` bytes | `{ maxSize, files }` |
160
+ * | `maxFiles` | more files than `maxFiles` (1 when not `multiple`) | `{ maxFiles, actual }` |
161
+ * | `uploading` | an upload is running, or a file is waiting for one | `{ count }` |
162
+ * | `uploadFailed` | an upload failed or was cancelled | `{ files }` |
163
+ *
164
+ * A file that breaks a rule is kept in the list, marked, so the user sees which one and can remove it; it is never
165
+ * uploaded. `required` needs a file in the list.
166
+ *
167
+ * **Uploading.** `uploadUrl` posts a `FormData` (field `uploadField`) with `HttpClient` and `reportProgress`, so the
168
+ * app needs `provideHttpClient()` (and its interceptors apply). `uploadFn` is the same job in your hands:
169
+ * `(file, { signal }) => Observable` of `HttpEvent`s, `{ progress, serverId?, url? }` or percentages, completing
170
+ * on success. Cancel and remove unsubscribe, and abort `signal`. `uploadResult` maps the response body to
171
+ * `{ serverId, url }` (default: `serverId` or `id`, and `url`).
172
+ */
173
+ declare class NxeFileInputComponent extends NxeFormControlBase<NxeFileDescriptor[]> implements Validator {
174
+ /** Accepted files, as in `<input accept>`: `.pdf`, `application/pdf`, `image/*`, comma separated. Empty accepts all. */
175
+ readonly accept: _angular_core.InputSignal<string>;
176
+ /** Largest file, in bytes. */
177
+ readonly maxSize: _angular_core.InputSignalWithTransform<number | undefined, unknown>;
178
+ /** Most files the control may hold. */
179
+ readonly maxFiles: _angular_core.InputSignalWithTransform<number | undefined, unknown>;
180
+ /** More than one file. When off, choosing a file replaces the current one. */
181
+ readonly multiple: _angular_core.InputSignalWithTransform<boolean, unknown>;
182
+ /** Uploads a file; see {@link NxeUploadFn}. Wins over `uploadUrl`. */
183
+ readonly uploadFn: _angular_core.InputSignal<NxeUploadFn | undefined>;
184
+ /** Where to POST each file, with `HttpClient`. */
185
+ readonly uploadUrl: _angular_core.InputSignal<string | undefined>;
186
+ /** Name of the form field the file is sent as. */
187
+ readonly uploadField: _angular_core.InputSignal<string>;
188
+ /** Headers for the `uploadUrl` request. */
189
+ readonly uploadHeaders: _angular_core.InputSignal<Record<string, string | string[]> | undefined>;
190
+ /** Send cookies with the `uploadUrl` request. */
191
+ readonly withCredentials: _angular_core.InputSignalWithTransform<boolean, unknown>;
192
+ /** Reads `{ serverId, url }` from the response body. */
193
+ readonly uploadResult: _angular_core.InputSignal<((body: unknown) => NxeUploadResult) | undefined>;
194
+ /** Start uploading as soon as a file is added. Off, call {@link upload}. */
195
+ readonly autoUpload: _angular_core.InputSignalWithTransform<boolean, unknown>;
196
+ /** The button's text; the active language's "Select files" when unset. */
197
+ readonly selectButtonText: _angular_core.InputSignal<string | undefined>;
198
+ /** Text beside the button; the active language's "or drop files here" when unset. */
199
+ readonly labelText: _angular_core.InputSignal<string | undefined>;
200
+ /** Show the accepted types, size and count under the button. */
201
+ readonly showHints: _angular_core.InputSignalWithTransform<boolean, unknown>;
202
+ /** Files were added, with their descriptors. */
203
+ readonly filesAdded: _angular_core.OutputEmitterRef<readonly NxeFileDescriptor[]>;
204
+ /** A file was removed (or replaced). Delete it from the server here, if it was stored. */
205
+ readonly fileRemoved: _angular_core.OutputEmitterRef<NxeFileDescriptor>;
206
+ /** An upload finished. */
207
+ readonly fileUploaded: _angular_core.OutputEmitterRef<NxeFileDescriptor>;
208
+ /** An upload failed or was cancelled. */
209
+ readonly fileFailed: _angular_core.OutputEmitterRef<NxeFileDescriptor>;
210
+ private readonly picker;
211
+ private readonly http;
212
+ private readonly injector;
213
+ private readonly destroyRef;
214
+ private readonly running;
215
+ private readonly results;
216
+ private validatorChange;
217
+ private announceToggle;
218
+ protected readonly dragOver: _angular_core.WritableSignal<boolean>;
219
+ protected readonly announcement: _angular_core.WritableSignal<string>;
220
+ /** The files in the control. */
221
+ readonly files: _angular_core.Signal<NxeFileDescriptor[]>;
222
+ /** An upload is configured. */
223
+ readonly uploads: _angular_core.Signal<boolean>;
224
+ /** Most files the control accepts: `maxFiles`, or one when not `multiple`. */
225
+ readonly limit: _angular_core.Signal<number>;
226
+ protected readonly canAdd: _angular_core.Signal<boolean>;
227
+ protected readonly rows: _angular_core.Signal<readonly FileRow[]>;
228
+ protected readonly hints: _angular_core.Signal<string[]>;
229
+ constructor();
230
+ validate(control: AbstractControl): ValidationErrors | null;
231
+ registerOnValidatorChange(fn: () => void): void;
232
+ /** Opens the browser's file picker. */
233
+ open(): void;
234
+ /** Adds files as if the user had chosen them. */
235
+ addFiles(list: readonly File[], event?: Event | null): void;
236
+ /** Removes a file, cancelling its upload if it is running. */
237
+ remove(id: string): void;
238
+ /** Stops a running upload. The file stays, as an error, so it can be retried or removed. */
239
+ cancel(id: string): void;
240
+ /** Uploads a failed or cancelled file again. */
241
+ retry(id: string): void;
242
+ /** Uploads every file that is waiting, for `autoUpload` off. */
243
+ upload(): void;
244
+ protected onPicked(event: Event): void;
245
+ protected onDragOver(event: DragEvent): void;
246
+ protected onDragLeave(event: DragEvent): void;
247
+ protected onDrop(event: DragEvent): void;
248
+ protected onZoneFocusOut(event: FocusEvent): void;
249
+ protected progressLabel(file: NxeFileDescriptor): string;
250
+ protected round(value: number): number;
251
+ protected t(key: NxeMessageKey, ...args: readonly unknown[]): string;
252
+ /** Why `file` at `index` cannot be kept; checked in the order type, size, count. */
253
+ private issueOf;
254
+ private statusText;
255
+ private describe;
256
+ private afterAdd;
257
+ /** Starts every pending file that breaks no rule, when uploads are on (`force` ignores `autoUpload`). */
258
+ private startEligible;
259
+ /** Marks `ids` as uploading in one change, then starts each request. */
260
+ private begin;
261
+ private request;
262
+ private onEvent;
263
+ private succeed;
264
+ private fail;
265
+ private messageOf;
266
+ private stopById;
267
+ private stop;
268
+ /** Applies changes to descriptors; `notify` tells the form, otherwise only the component's own value moves. */
269
+ private patch;
270
+ private say;
271
+ /** After a removal the focused button is gone: move to the neighbouring file, or to the picker button. */
272
+ private focusAfterRemove;
273
+ writeValue(value: NxeFileDescriptor[] | null): void;
274
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<NxeFileInputComponent, never>;
275
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NxeFileInputComponent, "nxe-file-input", never, { "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "maxSize": { "alias": "maxSize"; "required": false; "isSignal": true; }; "maxFiles": { "alias": "maxFiles"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "uploadFn": { "alias": "uploadFn"; "required": false; "isSignal": true; }; "uploadUrl": { "alias": "uploadUrl"; "required": false; "isSignal": true; }; "uploadField": { "alias": "uploadField"; "required": false; "isSignal": true; }; "uploadHeaders": { "alias": "uploadHeaders"; "required": false; "isSignal": true; }; "withCredentials": { "alias": "withCredentials"; "required": false; "isSignal": true; }; "uploadResult": { "alias": "uploadResult"; "required": false; "isSignal": true; }; "autoUpload": { "alias": "autoUpload"; "required": false; "isSignal": true; }; "selectButtonText": { "alias": "selectButtonText"; "required": false; "isSignal": true; }; "labelText": { "alias": "labelText"; "required": false; "isSignal": true; }; "showHints": { "alias": "showHints"; "required": false; "isSignal": true; }; }, { "filesAdded": "filesAdded"; "fileRemoved": "fileRemoved"; "fileUploaded": "fileUploaded"; "fileFailed": "fileFailed"; }, never, never, true, never>;
276
+ }
277
+
278
+ export { NxeFileInputComponent, NxeFileUploaderComponent, nxeFileAccepted };
279
+ export type { NxeFileDescriptor, NxeFileIssueKind, NxeFileStatus, NxeUploadContext, NxeUploadEvent, NxeUploadFn, NxeUploadProgress, NxeUploadResult };