@acorex/core 21.0.2-next.24 → 21.0.2-next.26

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 (62) hide show
  1. package/fesm2022/acorex-core-components.mjs +3 -3
  2. package/fesm2022/acorex-core-components.mjs.map +1 -1
  3. package/fesm2022/acorex-core-config.mjs +3 -3
  4. package/fesm2022/acorex-core-config.mjs.map +1 -1
  5. package/fesm2022/acorex-core-constants.mjs.map +1 -1
  6. package/fesm2022/acorex-core-date-time.mjs +25 -25
  7. package/fesm2022/acorex-core-date-time.mjs.map +1 -1
  8. package/fesm2022/acorex-core-events.mjs +3 -3
  9. package/fesm2022/acorex-core-events.mjs.map +1 -1
  10. package/fesm2022/acorex-core-file.mjs +92 -685
  11. package/fesm2022/acorex-core-file.mjs.map +1 -1
  12. package/fesm2022/acorex-core-format.mjs +19 -19
  13. package/fesm2022/acorex-core-format.mjs.map +1 -1
  14. package/fesm2022/acorex-core-full-screen.mjs +3 -3
  15. package/fesm2022/acorex-core-full-screen.mjs.map +1 -1
  16. package/fesm2022/acorex-core-icon.mjs +3 -3
  17. package/fesm2022/acorex-core-icon.mjs.map +1 -1
  18. package/fesm2022/acorex-core-image.mjs +3 -3
  19. package/fesm2022/acorex-core-image.mjs.map +1 -1
  20. package/fesm2022/acorex-core-locale.mjs +10 -10
  21. package/fesm2022/acorex-core-locale.mjs.map +1 -1
  22. package/fesm2022/acorex-core-memoize.mjs.map +1 -1
  23. package/fesm2022/acorex-core-network.mjs +3 -3
  24. package/fesm2022/acorex-core-network.mjs.map +1 -1
  25. package/fesm2022/acorex-core-pipes.mjs +3 -3
  26. package/fesm2022/acorex-core-pipes.mjs.map +1 -1
  27. package/fesm2022/acorex-core-platform.mjs +4 -4
  28. package/fesm2022/acorex-core-platform.mjs.map +1 -1
  29. package/fesm2022/acorex-core-storage.mjs +9 -9
  30. package/fesm2022/acorex-core-storage.mjs.map +1 -1
  31. package/fesm2022/acorex-core-translation.mjs +16 -16
  32. package/fesm2022/acorex-core-translation.mjs.map +1 -1
  33. package/fesm2022/acorex-core-utils.mjs +6 -4
  34. package/fesm2022/acorex-core-utils.mjs.map +1 -1
  35. package/fesm2022/acorex-core-validation.mjs +40 -40
  36. package/fesm2022/acorex-core-validation.mjs.map +1 -1
  37. package/fesm2022/acorex-core-z-index.mjs +3 -3
  38. package/fesm2022/acorex-core-z-index.mjs.map +1 -1
  39. package/fesm2022/acorex-core.mjs.map +1 -1
  40. package/package.json +23 -23
  41. package/types/acorex-core-file.d.ts +85 -0
  42. package/{format/index.d.ts → types/acorex-core-format.d.ts} +2 -2
  43. package/{utils/index.d.ts → types/acorex-core-utils.d.ts} +10 -2
  44. package/{validation/index.d.ts → types/acorex-core-validation.d.ts} +10 -10
  45. package/file/index.d.ts +0 -321
  46. /package/{components/index.d.ts → types/acorex-core-components.d.ts} +0 -0
  47. /package/{config/index.d.ts → types/acorex-core-config.d.ts} +0 -0
  48. /package/{constants/index.d.ts → types/acorex-core-constants.d.ts} +0 -0
  49. /package/{date-time/index.d.ts → types/acorex-core-date-time.d.ts} +0 -0
  50. /package/{events/index.d.ts → types/acorex-core-events.d.ts} +0 -0
  51. /package/{full-screen/index.d.ts → types/acorex-core-full-screen.d.ts} +0 -0
  52. /package/{icon/index.d.ts → types/acorex-core-icon.d.ts} +0 -0
  53. /package/{image/index.d.ts → types/acorex-core-image.d.ts} +0 -0
  54. /package/{locale/index.d.ts → types/acorex-core-locale.d.ts} +0 -0
  55. /package/{memoize/index.d.ts → types/acorex-core-memoize.d.ts} +0 -0
  56. /package/{network/index.d.ts → types/acorex-core-network.d.ts} +0 -0
  57. /package/{pipes/index.d.ts → types/acorex-core-pipes.d.ts} +0 -0
  58. /package/{platform/index.d.ts → types/acorex-core-platform.d.ts} +0 -0
  59. /package/{storage/index.d.ts → types/acorex-core-storage.d.ts} +0 -0
  60. /package/{translation/index.d.ts → types/acorex-core-translation.d.ts} +0 -0
  61. /package/{z-index/index.d.ts → types/acorex-core-z-index.d.ts} +0 -0
  62. /package/{index.d.ts → types/acorex-core.d.ts} +0 -0
@@ -1,7 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, InjectionToken, inject, NgModule, DOCUMENT, isDevMode } from '@angular/core';
3
- import * as i2 from '@acorex/core/validation';
4
- import { AXValidationService, AXValidationRegistryService, AXValidationModule } from '@acorex/core/validation';
2
+ import { Injectable, NgModule, inject, DOCUMENT, PLATFORM_ID } from '@angular/core';
5
3
  import * as i1 from '@acorex/core/format';
6
4
  import { AXFormatModule } from '@acorex/core/format';
7
5
 
@@ -31,603 +29,24 @@ class AXFileSizeFormatter {
31
29
  const i = Math.floor(Math.log(size) / Math.log(k));
32
30
  return parseFloat((size / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
33
31
  }
34
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileSizeFormatter, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
35
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileSizeFormatter }); }
32
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileSizeFormatter, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
33
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileSizeFormatter }); }
36
34
  }
37
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileSizeFormatter, decorators: [{
35
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileSizeFormatter, decorators: [{
38
36
  type: Injectable
39
37
  }] });
40
38
 
41
- /** Human-readable file size (binary units, e.g. `41.5 MB`). */
42
- function formatFileSizeBytes(bytes) {
43
- if (!Number.isFinite(bytes) || bytes < 0) {
44
- return '0 B';
45
- }
46
- if (bytes === 0) {
47
- return '0 B';
48
- }
49
- const k = 1024;
50
- const units = ['B', 'KB', 'MB', 'GB', 'TB'];
51
- const i = Math.min(Math.floor(Math.log(bytes) / Math.log(k)), units.length - 1);
52
- const value = bytes / Math.pow(k, i);
53
- if (i === 0) {
54
- return `${bytes} B`;
55
- }
56
- const digits = value >= 100 ? 0 : value >= 10 ? 1 : 2;
57
- return `${value.toFixed(digits)} ${units[i]}`;
58
- }
59
-
60
- /** Well-known utility keys (optional per {@link AXFileType}). */
61
- const AX_FILE_TYPE_UTILITY = {
62
- preview: 'preview',
63
- duration: 'duration',
64
- formatSize: 'formatSize',
65
- formatDuration: 'formatDuration',
66
- createLocalPreviewUrl: 'createLocalPreviewUrl',
67
- /** Resolves catalog name for mixed file-picker rows. */
68
- pickerCatalog: 'pickerCatalog',
69
- };
70
- function createFileTypeUtilitiesContext(readAsDataUrl, platformId) {
71
- return { readAsDataUrl, platformId };
72
- }
73
- function hasFileTypeUtility(fileType, name) {
74
- return typeof fileType?.utilities?.[name] === 'function';
75
- }
76
- async function runFileTypeUtility(fileType, name, ctx, ...args) {
77
- const fn = fileType?.utilities?.[name];
78
- if (!fn) {
79
- return undefined;
80
- }
81
- return (await fn(ctx, ...args));
82
- }
83
- function runFileTypeUtilitySync(fileType, name, ctx, ...args) {
84
- const fn = fileType?.utilities?.[name];
85
- if (!fn) {
86
- return undefined;
87
- }
88
- return fn(ctx, ...args);
89
- }
90
-
91
- /** Contributes {@link AXFileType} entries (multi provider). */
92
- class AXFileTypeInfoProvider {
93
- }
94
- const AX_FILE_TYPE_INFO_PROVIDER = new InjectionToken('AX_FILE_TYPE_INFO_PROVIDER');
95
- function provideFileTypeInfoProvider(provider) {
96
- return {
97
- provide: AX_FILE_TYPE_INFO_PROVIDER,
98
- useClass: provider,
99
- multi: true,
100
- };
101
- }
102
-
103
- /** Merges type-level validations with extension overrides (extension wins per field). */
104
- function mergeFileValidations(base, override) {
105
- if (!override) {
106
- return { ...base };
107
- }
108
- return {
109
- mimeTypes: override.mimeTypes ?? base.mimeTypes,
110
- minSize: override.minSize ?? base.minSize,
111
- maxSize: override.maxSize ?? base.maxSize,
112
- rules: override.rules ?? base.rules,
113
- };
114
- }
115
- /** Resolved validations for a type + optional extension. */
116
- function resolveFileValidations(type, extension) {
117
- return mergeFileValidations(type.validations ?? {}, extension?.validations);
118
- }
119
- /** True when no mime/size/rules are defined on the type. */
120
- function isEmptyFileValidations(validations) {
121
- if (!validations) {
122
- return true;
123
- }
124
- return ((validations.mimeTypes?.length ?? 0) === 0 &&
125
- validations.minSize == null &&
126
- validations.maxSize == null &&
127
- (validations.rules?.length ?? 0) === 0);
128
- }
129
- /**
130
- * Extension-only mode: empty type `validations` and a non-empty `extensions` list.
131
- * Files must match a listed extension; rules come from that extension entry.
132
- */
133
- function isExtensionsOnlyType(type) {
134
- return isEmptyFileValidations(type.validations) && (type.extensions?.length ?? 0) > 0;
135
- }
136
- /** File extension from name (lowercase, no dot). */
137
- function getFileExtension(fileName) {
138
- const parts = fileName.trim().split('.');
139
- return parts.length > 1 ? (parts.pop()?.toLowerCase() ?? '') : '';
140
- }
141
- /** Matching extension entry for a file within a type, if any. */
142
- function findFileTypeExtension(file, type) {
143
- const ext = getFileExtension(file.name);
144
- if (!ext || !type.extensions?.length) {
145
- return undefined;
146
- }
147
- return type.extensions.find((e) => e.name.toLowerCase() === ext);
148
- }
149
-
150
- /** Maps {@link AXFileValidations} to executable validation entries. */
151
- function fileValidationsToRules(validations) {
152
- const rules = [];
153
- if (validations.mimeTypes?.length) {
154
- rules.push({
155
- rule: 'fileMimeType',
156
- options: { allowed: validations.mimeTypes },
157
- });
158
- }
159
- if (validations.minSize != null) {
160
- rules.push({
161
- rule: 'fileMinSize',
162
- options: { minSize: validations.minSize },
163
- });
164
- }
165
- if (validations.maxSize != null) {
166
- rules.push({
167
- rule: 'fileMaxSize',
168
- options: { maxSize: validations.maxSize },
169
- });
170
- }
171
- if (validations.rules?.length) {
172
- rules.push(...validations.rules);
173
- }
174
- return rules;
175
- }
176
- /** Failed validation results; empty array means the file is valid. */
177
- async function validateFileWithValidations(validation, file, validations) {
178
- const entries = fileValidationsToRules(validations);
179
- const errors = [];
180
- for (const { rule, options } of entries) {
181
- const result = await validation.validate(rule, file, options);
182
- if (!result.result) {
183
- errors.push(result);
184
- }
185
- }
186
- return errors;
187
- }
188
- /** Validates a file against a type; extension rules override when the file name matches. */
189
- async function validateFileAgainstType(validation, file, type, extension) {
190
- const matchedExtension = extension ?? findFileTypeExtension(file, type);
191
- if (isExtensionsOnlyType(type) && !matchedExtension) {
192
- const ext = getFileExtension(file.name);
193
- return [
194
- {
195
- rule: 'fileExtension',
196
- result: false,
197
- message: ext ? `Extension ".${ext}" is not allowed.` : 'File must have an allowed extension.',
198
- value: ext,
199
- },
200
- ];
201
- }
202
- const resolved = resolveFileValidations(type, matchedExtension);
203
- return validateFileWithValidations(validation, file, resolved);
204
- }
205
-
206
- class AXFileTypeRegistryService {
207
- constructor() {
208
- this.validation = inject(AXValidationService);
209
- this.providers = inject(AX_FILE_TYPE_INFO_PROVIDER, { optional: true }) ?? [];
210
- this.registeredTypes = [];
211
- this.cache = null;
212
- }
213
- /** Registers or replaces catalog entries (e.g. from feature bootstrap). */
214
- registerTypes(types) {
215
- for (const type of types) {
216
- const index = this.registeredTypes.findIndex((t) => t.name === type.name);
217
- if (index >= 0) {
218
- this.registeredTypes[index] = type;
219
- }
220
- else {
221
- this.registeredTypes.push(type);
222
- }
223
- }
224
- this.invalidateCache();
225
- }
226
- invalidateCache() {
227
- this.cache = null;
228
- }
229
- async resolveTypes() {
230
- if (this.cache) {
231
- return this.cache;
232
- }
233
- const byName = new Map();
234
- if (this.providers.length) {
235
- const batches = await Promise.all(this.providers.map((p) => p.items()));
236
- for (const batch of batches) {
237
- for (const type of batch) {
238
- if (!byName.has(type.name)) {
239
- byName.set(type.name, type);
240
- }
241
- }
242
- }
243
- }
244
- for (const type of this.registeredTypes) {
245
- byName.set(type.name, type);
246
- }
247
- this.cache = [...byName.values()];
248
- return this.cache;
249
- }
250
- async getTypes() {
251
- return this.resolveTypes();
252
- }
253
- async get(name) {
254
- const types = await this.resolveTypes();
255
- return types.find((t) => t.name === name);
256
- }
257
- async accept(typeNames) {
258
- const names = typeNames ? (Array.isArray(typeNames) ? typeNames : [typeNames]) : undefined;
259
- const types = await this.resolveTypes();
260
- const selected = names?.length ? types.filter((t) => names.includes(t.name)) : types;
261
- if (names?.length && selected.length === 0) {
262
- return '';
263
- }
264
- const parts = new Set();
265
- for (const type of selected) {
266
- type.validations?.mimeTypes?.forEach((m) => parts.add(m));
267
- type.extensions?.forEach((ext) => {
268
- ext.validations?.mimeTypes?.forEach((m) => parts.add(m));
269
- parts.add(`.${ext.name.replace(/^\./, '')}`);
270
- });
271
- }
272
- return [...parts].join(',');
273
- }
274
- async matchType(file) {
275
- const types = await this.resolveTypes();
276
- const mime = file.type.trim().toLowerCase();
277
- return types.find((type) => {
278
- const patterns = [
279
- ...(type.validations?.mimeTypes ?? []),
280
- ...(type.extensions?.flatMap((e) => e.validations?.mimeTypes ?? []) ?? []),
281
- ];
282
- if (!patterns.length) {
283
- return false;
284
- }
285
- return patterns.some((pattern) => this.matchesMime(mime, pattern.trim().toLowerCase()));
286
- });
287
- }
288
- async validate(file, typeName) {
289
- const type = await this.get(typeName);
290
- if (!type) {
291
- return [
292
- {
293
- rule: 'fileType',
294
- result: false,
295
- message: `Unknown file type: ${typeName}`,
296
- value: typeName,
297
- },
298
- ];
299
- }
300
- const extension = findFileTypeExtension(file, type);
301
- return validateFileAgainstType(this.validation, file, type, extension);
302
- }
303
- async validateAgainstTypes(file, typeNames) {
304
- const names = Array.isArray(typeNames) ? typeNames : [typeNames];
305
- let lastErrors = [];
306
- for (const name of names) {
307
- const errors = await this.validate(file, name);
308
- if (errors.length === 0) {
309
- return [];
310
- }
311
- lastErrors = errors;
312
- }
313
- return lastErrors;
314
- }
315
- async validateMany(files, typeNames) {
316
- const accepted = [];
317
- const rejected = [];
318
- for (const file of files) {
319
- const errors = await this.validateAgainstTypes(file, typeNames);
320
- if (errors.length === 0) {
321
- accepted.push(file);
322
- }
323
- else {
324
- rejected.push({ file, errors });
325
- }
326
- }
327
- return { accepted, rejected };
328
- }
329
- matchesMime(mime, pattern) {
330
- if (!pattern || pattern === '*/*' || pattern === '*') {
331
- return true;
332
- }
333
- if (pattern.endsWith('/*')) {
334
- const category = pattern.slice(0, -2);
335
- return mime.startsWith(`${category}/`) || (mime === '' && category === 'application');
336
- }
337
- return mime === pattern;
338
- }
339
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileTypeRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
340
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileTypeRegistryService, providedIn: 'root' }); }
341
- }
342
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileTypeRegistryService, decorators: [{
343
- type: Injectable,
344
- args: [{ providedIn: 'root' }]
345
- }] });
346
-
347
- const MB$4 = 1024 * 1024;
348
- const AX_AUDIO_FILE_TYPE = {
349
- name: 'audio',
350
- title: 'Audio',
351
- icon: 'fa-light fa-music ax-text-amber-500',
352
- validations: {
353
- mimeTypes: ['audio/*'],
354
- minSize: 1,
355
- maxSize: 50 * MB$4,
356
- },
357
- extensions: [
358
- { name: 'mp3', title: 'MP3' },
359
- { name: 'wav', title: 'WAV', validations: { maxSize: 30 * MB$4 } },
360
- { name: 'ogg', title: 'OGG' },
361
- { name: 'm4a', title: 'M4A' },
362
- ],
363
- };
364
- class AXAudioFileTypeProvider extends AXFileTypeInfoProvider {
365
- items() {
366
- return Promise.resolve([AX_AUDIO_FILE_TYPE]);
367
- }
368
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXAudioFileTypeProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
369
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXAudioFileTypeProvider }); }
370
- }
371
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXAudioFileTypeProvider, decorators: [{
372
- type: Injectable
373
- }] });
374
-
375
- const MB$3 = 1024 * 1024;
376
- /** Extension-only: no type `validations` — only listed extensions are allowed. */
377
- const AX_DOCUMENT_FILE_TYPE = {
378
- name: 'document',
379
- title: 'Document',
380
- icon: 'fa-light fa-file-lines ax-text-red-500',
381
- extensions: [{ name: 'pdf', title: 'PDF', validations: { mimeTypes: ['application/pdf'], maxSize: 5 * MB$3 } }],
382
- };
383
- class AXDocumentFileTypeProvider extends AXFileTypeInfoProvider {
384
- items() {
385
- return Promise.resolve([AX_DOCUMENT_FILE_TYPE]);
386
- }
387
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXDocumentFileTypeProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
388
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXDocumentFileTypeProvider }); }
389
- }
390
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXDocumentFileTypeProvider, decorators: [{
391
- type: Injectable
392
- }] });
393
-
394
- const MB$2 = 1024 * 1024;
395
- const AX_FILE_FILE_TYPE = {
396
- name: 'file',
397
- title: 'File',
398
- icon: 'fa-light fa-file ax-text-neutral-500',
399
- validations: {
400
- mimeTypes: ['application/*', 'text/*'],
401
- minSize: 1,
402
- maxSize: 100 * MB$2,
403
- },
404
- extensions: [
405
- { name: 'pdf', title: 'PDF', validations: { mimeTypes: ['application/pdf'], maxSize: 25 * MB$2 } },
406
- { name: 'doc', title: 'Word' },
407
- { name: 'docx', title: 'Word' },
408
- { name: 'txt', title: 'Text', validations: { mimeTypes: ['text/plain'], maxSize: 5 * MB$2 } },
409
- { name: 'zip', title: 'ZIP', validations: { maxSize: 50 * MB$2 } },
410
- ],
411
- };
412
- class AXFileFileTypeProvider extends AXFileTypeInfoProvider {
413
- items() {
414
- return Promise.resolve([AX_FILE_FILE_TYPE]);
415
- }
416
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileFileTypeProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
417
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileFileTypeProvider }); }
418
- }
419
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileFileTypeProvider, decorators: [{
420
- type: Injectable
421
- }] });
422
-
423
- const MB$1 = 1024 * 1024;
424
- const AX_IMAGE_FILE_TYPE = {
425
- name: 'image',
426
- title: 'Image',
427
- icon: 'fa-light fa-image ax-text-purple-500',
428
- validations: {
429
- mimeTypes: ['image/*'],
430
- minSize: 1,
431
- maxSize: 100 * MB$1,
432
- },
433
- extensions: [
434
- { name: 'jpg', title: 'JPEG' },
435
- { name: 'jpeg', title: 'JPEG', validations: { maxSize: 5 * MB$1 } },
436
- { name: 'png', title: 'PNG' },
437
- { name: 'gif', title: 'GIF' },
438
- { name: 'webp', title: 'WebP' },
439
- { name: 'svg', title: 'SVG', validations: { maxSize: 2 * MB$1 } },
440
- ],
441
- };
442
- class AXImageFileTypeProvider extends AXFileTypeInfoProvider {
443
- items() {
444
- return Promise.resolve([AX_IMAGE_FILE_TYPE]);
445
- }
446
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXImageFileTypeProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
447
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXImageFileTypeProvider }); }
448
- }
449
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXImageFileTypeProvider, decorators: [{
450
- type: Injectable
451
- }] });
452
-
453
- const MB = 1024 * 1024;
454
- const AX_VIDEO_FILE_TYPE = {
455
- name: 'video',
456
- title: 'Video',
457
- icon: 'fa-light fa-video ax-text-blue-500',
458
- validations: {
459
- mimeTypes: ['video/*'],
460
- minSize: 1,
461
- maxSize: 500 * MB,
462
- },
463
- extensions: [
464
- { name: 'mp4', title: 'MP4' },
465
- { name: 'webm', title: 'WebM', validations: { maxSize: 200 * MB } },
466
- { name: 'ogg', title: 'OGG' },
467
- ],
468
- };
469
- class AXVideoFileTypeProvider extends AXFileTypeInfoProvider {
470
- items() {
471
- return Promise.resolve([AX_VIDEO_FILE_TYPE]);
472
- }
473
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXVideoFileTypeProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
474
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXVideoFileTypeProvider }); }
475
- }
476
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXVideoFileTypeProvider, decorators: [{
477
- type: Injectable
478
- }] });
479
-
480
- /** Built-in file type provider classes (one logical type per provider). */
481
- const AX_BUILTIN_FILE_TYPE_PROVIDERS = [
482
- AXImageFileTypeProvider,
483
- AXVideoFileTypeProvider,
484
- AXAudioFileTypeProvider,
485
- AXFileFileTypeProvider,
486
- AXDocumentFileTypeProvider,
487
- ];
488
- /** Registers all built-in file type providers (image, video, audio, file, document). */
489
- function provideBuiltinFileTypeProviders() {
490
- return AX_BUILTIN_FILE_TYPE_PROVIDERS.map((provider) => provideFileTypeInfoProvider(provider));
491
- }
492
- /** @deprecated Use {@link provideBuiltinFileTypeProviders}. */
493
- const provideDefaultFileTypeProviders = provideBuiltinFileTypeProviders;
494
-
495
- class AXFileMimeTypeValidationRule {
496
- get name() {
497
- return 'fileMimeType';
498
- }
499
- async validate(value, options) {
500
- const mime = (value instanceof File || value instanceof Blob ? value.type : '').trim().toLowerCase();
501
- const allowed = options.allowed ?? [];
502
- const valid = allowed.length === 0 ||
503
- allowed.some((pattern) => this.matchesMime(mime, pattern.trim().toLowerCase()));
504
- return {
505
- rule: this.name,
506
- result: valid,
507
- message: valid ? '' : (options.message ?? 'File type is not allowed.'),
508
- value: mime,
509
- };
510
- }
511
- matchesMime(mime, pattern) {
512
- if (!pattern || pattern === '*/*' || pattern === '*') {
513
- return true;
514
- }
515
- if (pattern.endsWith('/*')) {
516
- const category = pattern.slice(0, -2);
517
- return mime.startsWith(`${category}/`) || (mime === '' && category === 'application');
518
- }
519
- return mime === pattern;
520
- }
521
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMimeTypeValidationRule, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
522
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMimeTypeValidationRule }); }
523
- }
524
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMimeTypeValidationRule, decorators: [{
525
- type: Injectable
526
- }] });
527
-
528
- class AXFileMinSizeValidationRule {
529
- get name() {
530
- return 'fileMinSize';
531
- }
532
- async validate(value, options) {
533
- const size = value instanceof File || value instanceof Blob ? value.size : 0;
534
- const valid = size >= options.minSize;
535
- const limitLabel = formatFileSizeBytes(options.minSize);
536
- return {
537
- rule: this.name,
538
- result: valid,
539
- message: valid
540
- ? ''
541
- : (options.message ?? `File is too small. Minimum size is ${limitLabel}.`),
542
- value: size,
543
- minSize: options.minSize,
544
- };
545
- }
546
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMinSizeValidationRule, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
547
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMinSizeValidationRule }); }
548
- }
549
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMinSizeValidationRule, decorators: [{
550
- type: Injectable
551
- }] });
552
-
553
- class AXFileMaxSizeValidationRule {
554
- get name() {
555
- return 'fileMaxSize';
556
- }
557
- async validate(value, options) {
558
- const size = value instanceof File || value instanceof Blob ? value.size : 0;
559
- const valid = size <= options.maxSize;
560
- const limitLabel = formatFileSizeBytes(options.maxSize);
561
- return {
562
- rule: this.name,
563
- result: valid,
564
- message: valid
565
- ? ''
566
- : (options.message ??
567
- `File is too large. Maximum size is ${limitLabel}.`),
568
- value: size,
569
- maxSize: options.maxSize,
570
- };
571
- }
572
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMaxSizeValidationRule, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
573
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMaxSizeValidationRule }); }
574
- }
575
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMaxSizeValidationRule, decorators: [{
576
- type: Injectable
577
- }] });
578
-
579
- /** Validation rule classes to register with {@link AXValidationModule}. */
580
- const AX_FILE_VALIDATION_RULES = [
581
- AXFileMimeTypeValidationRule,
582
- AXFileMinSizeValidationRule,
583
- AXFileMaxSizeValidationRule,
584
- ];
585
- /** Registers file validation rules with {@link AXValidationRegistryService}. */
586
- function provideFileValidationRules() {
587
- return {
588
- provide: 'AXValidationModuleFactory',
589
- useFactory: (registry) => () => {
590
- registry.register(...AX_FILE_VALIDATION_RULES);
591
- },
592
- deps: [AXValidationRegistryService],
593
- multi: true,
594
- };
595
- }
596
- /**
597
- * Registers validation rules and optional built-in file type providers.
598
- * {@link AXFileTypeRegistryService} and {@link AXFileService} are `providedIn: 'root'`.
599
- */
600
- function provideFileTypeSystem() {
601
- return [provideFileValidationRules(), ...provideBuiltinFileTypeProviders()];
602
- }
603
-
604
39
  class AXFileModule {
605
- static forRoot(config) {
606
- const includeDefaults = config?.includeDefaultFileTypes !== false;
607
- return {
608
- ngModule: AXFileModule,
609
- providers: [
610
- provideFileValidationRules(),
611
- ...(includeDefaults ? provideDefaultFileTypeProviders() : []),
612
- ...(config?.fileTypeProviders ?? []),
613
- ],
614
- };
615
- }
616
- static forChild(config) {
617
- return AXFileModule.forRoot(config);
618
- }
619
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
620
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.3", ngImport: i0, type: AXFileModule, imports: [i1.AXFormatModule, i2.AXValidationModule] }); }
621
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileModule, providers: [AXFileSizeFormatter], imports: [AXFormatModule.forChild({ formatters: [AXFileSizeFormatter] }),
622
- AXValidationModule.forChild({ rules: [...AX_FILE_VALIDATION_RULES] })] }); }
40
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
41
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: AXFileModule, imports: [i1.AXFormatModule] }); }
42
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileModule, providers: [AXFileSizeFormatter], imports: [AXFormatModule.forChild({ formatters: [AXFileSizeFormatter] })] }); }
623
43
  }
624
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileModule, decorators: [{
44
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileModule, decorators: [{
625
45
  type: NgModule,
626
46
  args: [{
627
- imports: [
628
- AXFormatModule.forChild({ formatters: [AXFileSizeFormatter] }),
629
- AXValidationModule.forChild({ rules: [...AX_FILE_VALIDATION_RULES] }),
630
- ],
47
+ imports: [AXFormatModule.forChild({ formatters: [AXFileSizeFormatter] })],
48
+ exports: [],
49
+ declarations: [],
631
50
  providers: [AXFileSizeFormatter],
632
51
  }]
633
52
  }] });
@@ -635,124 +54,112 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImpor
635
54
  class AXFileService {
636
55
  constructor() {
637
56
  this.document = inject(DOCUMENT);
638
- this.fileTypes = inject(AXFileTypeRegistryService);
639
- }
640
- async getFileTypes() {
641
- return this.fileTypes.getTypes();
642
- }
643
- async getFileType(name) {
644
- return this.fileTypes.get(name);
645
- }
646
- async getAcceptAttribute(fileType) {
647
- return this.fileTypes.accept(fileType);
648
- }
649
- async matchFileType(file) {
650
- return this.fileTypes.matchType(file);
651
- }
652
- validate(file, fileType) {
653
- return this.fileTypes.validateAgainstTypes(file, fileType);
654
- }
655
- validateMany(files, fileType) {
656
- return this.fileTypes.validateMany(files, fileType);
57
+ this.platformID = inject(PLATFORM_ID);
58
+ /**
59
+ * Gets the size of a file, blob, or base64 string.
60
+ *
61
+ * @param file - The file, blob, or base64 string to get size for
62
+ * @returns number | false - The size in bytes or false if not a base64 string
63
+ */
64
+ this.blobToBase64 = (blob) => {
65
+ if (blob instanceof Blob) {
66
+ return new Promise((resolve, reject) => {
67
+ const reader = new FileReader();
68
+ reader.onerror = reject;
69
+ reader.onload = () => {
70
+ resolve(reader.result);
71
+ };
72
+ reader.readAsDataURL(blob);
73
+ });
74
+ }
75
+ else {
76
+ return Promise.reject('input is not blob');
77
+ }
78
+ };
657
79
  }
658
80
  /**
659
- * Opens a file selection dialog.
660
- * With `fileType`, returns files that pass catalog validation (`accept` defaults from the catalog).
661
- * Without `fileType`, returns all selected files (legacy `accept` / `multiple` only).
81
+ * Opens a file selection dialog and returns the selected files.
82
+ *
83
+ * @param options - Optional configuration for file selection
84
+ * @param options.accept - File types to accept (e.g., 'image/*', '.pdf')
85
+ * @param options.multiple - Whether to allow multiple file selection
86
+ * @returns Promise<File[]> - Promise that resolves with the selected files
662
87
  */
663
- async chooseValidated(options) {
664
- const resolved = await this.resolveChooseOptions(options);
665
- const files = await this.openFileDialog(resolved);
666
- if (files.length === 0) {
667
- return { accepted: [], rejected: [] };
668
- }
669
- if (options.fileType) {
670
- return this.validateMany(files, options.fileType);
671
- }
672
- return { accepted: files, rejected: [] };
673
- }
674
- async choose(options) {
675
- const { accepted } = await this.chooseValidated(options);
676
- return accepted;
677
- }
678
- blobToBase64(blob) {
679
- if (!(blob instanceof Blob)) {
680
- return Promise.reject(new Error('input is not blob'));
681
- }
88
+ choose(options) {
682
89
  return new Promise((resolve, reject) => {
683
- const reader = new FileReader();
684
- reader.onerror = () => reject(reader.error);
685
- reader.onload = () => resolve(reader.result);
686
- reader.readAsDataURL(blob);
90
+ options = Object.assign({ multiple: false }, options);
91
+ const input = this.document.createElement('input');
92
+ input.style.display = 'none';
93
+ this.document.body.appendChild(input);
94
+ input.type = 'file';
95
+ input.accept = options.accept || '';
96
+ input.multiple = options.multiple || false;
97
+ //
98
+ const onError = (e) => {
99
+ reject(e);
100
+ this.document.body.removeChild(input);
101
+ input.remove();
102
+ input.removeEventListener('change', onChange);
103
+ input.removeEventListener('error', onError);
104
+ };
105
+ //
106
+ const onChange = () => {
107
+ resolve(Array.from(input.files || []));
108
+ this.document.body.removeChild(input);
109
+ input.remove();
110
+ input.removeEventListener('change', onChange);
111
+ input.removeEventListener('error', onError);
112
+ };
113
+ //
114
+ input.addEventListener('change', onChange);
115
+ input.addEventListener('error', onError);
116
+ input.click();
687
117
  });
688
118
  }
119
+ /**
120
+ * Gets the size of a file, blob, or base64 string.
121
+ *
122
+ * @param file - The file, blob, or base64 string to get size for
123
+ * @returns number | false - The size in bytes or false if not a base64 string
124
+ */
689
125
  getSize(file) {
690
126
  if (this.isBase64(file)) {
691
127
  return this.getBase64Size(file);
692
128
  }
693
129
  return false;
694
130
  }
131
+ /**
132
+ * Checks if a string is a valid base64 string.
133
+ *
134
+ * @param base64 - The string to check
135
+ * @returns boolean - True if the string is a valid base64 string
136
+ */
695
137
  isBase64(base64) {
696
138
  const regx = /[^:]\w+\/[\w-+\d.]+(?=;|,)/;
697
139
  return regx.test(base64);
698
140
  }
141
+ /**
142
+ * Gets the size of a base64 string in bytes.
143
+ *
144
+ * @param base64 - The base64 string to get size for
145
+ * @returns number - The size in bytes
146
+ */
699
147
  getBase64Size(base64) {
700
148
  return atob(base64.substring(base64.indexOf(',') + 1)).length;
701
149
  }
702
- async resolveChooseOptions(options) {
703
- const multiple = options.multiple ?? false;
704
- if (options.fileType) {
705
- const accept = options.accept ?? (await this.getAcceptAttribute(options.fileType));
706
- if (isDevMode() && !accept) {
707
- const name = Array.isArray(options.fileType) ? options.fileType.join(', ') : options.fileType;
708
- console.warn(`[AXFileService] No accept filter for file type "${name}". ` +
709
- 'Register a file type provider (e.g. provideConversationFileCatalog).');
710
- }
711
- return { accept, multiple };
712
- }
713
- return { accept: options.accept ?? '', multiple };
714
- }
715
- openFileDialog(options) {
716
- return new Promise((resolve, reject) => {
717
- const input = this.document.createElement('input');
718
- input.style.display = 'none';
719
- this.document.body.appendChild(input);
720
- input.type = 'file';
721
- input.accept = options.accept;
722
- input.multiple = options.multiple;
723
- const cleanup = () => {
724
- input.removeEventListener('change', onChange);
725
- input.removeEventListener('error', onError);
726
- if (input.parentNode) {
727
- this.document.body.removeChild(input);
728
- }
729
- input.remove();
730
- };
731
- const onError = (e) => {
732
- cleanup();
733
- reject(e);
734
- };
735
- const onChange = () => {
736
- const files = Array.from(input.files ?? []);
737
- cleanup();
738
- resolve(files);
739
- };
740
- input.addEventListener('change', onChange);
741
- input.addEventListener('error', onError);
742
- input.click();
743
- });
744
- }
745
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
746
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileService, providedIn: 'root' }); }
150
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
151
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileService, providedIn: 'root' }); }
747
152
  }
748
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileService, decorators: [{
153
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileService, decorators: [{
749
154
  type: Injectable,
750
- args: [{ providedIn: 'root' }]
155
+ args: [{
156
+ providedIn: 'root',
157
+ }]
751
158
  }] });
752
159
 
753
160
  /**
754
161
  * Generated bundle index. Do not edit.
755
162
  */
756
163
 
757
- export { AXAudioFileTypeProvider, AXDocumentFileTypeProvider, AXFileFileTypeProvider, AXFileMaxSizeValidationRule, AXFileMimeTypeValidationRule, AXFileMinSizeValidationRule, AXFileModule, AXFileService, AXFileSizeFormatter, AXFileTypeInfoProvider, AXFileTypeRegistryService, AXImageFileTypeProvider, AXVideoFileTypeProvider, AX_AUDIO_FILE_TYPE, AX_BUILTIN_FILE_TYPE_PROVIDERS, AX_DOCUMENT_FILE_TYPE, AX_FILE_FILE_TYPE, AX_FILE_TYPE_INFO_PROVIDER, AX_FILE_TYPE_UTILITY, AX_FILE_VALIDATION_RULES, AX_IMAGE_FILE_TYPE, AX_VIDEO_FILE_TYPE, createFileTypeUtilitiesContext, fileValidationsToRules, findFileTypeExtension, formatFileSizeBytes, getFileExtension, hasFileTypeUtility, isEmptyFileValidations, isExtensionsOnlyType, mergeFileValidations, provideBuiltinFileTypeProviders, provideDefaultFileTypeProviders, provideFileTypeInfoProvider, provideFileTypeSystem, provideFileValidationRules, resolveFileValidations, runFileTypeUtility, runFileTypeUtilitySync, validateFileAgainstType, validateFileWithValidations };
164
+ export { AXFileModule, AXFileService, AXFileSizeFormatter };
758
165
  //# sourceMappingURL=acorex-core-file.mjs.map