@acorex/core 20.9.0 → 20.9.1
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/acorex-core-file.mjs +140 -2
- package/fesm2022/acorex-core-file.mjs.map +1 -1
- package/file/index.d.ts +102 -6
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, runInInjectionContext, InjectionToken, inject, NgModule, DOCUMENT, isDevMode } from '@angular/core';
|
|
2
|
+
import { Injectable, runInInjectionContext, InjectionToken, inject, input, signal, effect, ChangeDetectionStrategy, Component, NgModule, DOCUMENT, isDevMode } from '@angular/core';
|
|
3
|
+
import { NgComponentOutlet } from '@angular/common';
|
|
3
4
|
import * as i2 from '@acorex/core/validation';
|
|
4
5
|
import { AXValidationService, AXValidationRegistryService, AXValidationModule } from '@acorex/core/validation';
|
|
5
6
|
import * as i1 from '@acorex/core/format';
|
|
@@ -141,6 +142,18 @@ function getFileExtension(fileName) {
|
|
|
141
142
|
return parts.length > 1 ? (parts.pop()?.toLowerCase() ?? '') : '';
|
|
142
143
|
}
|
|
143
144
|
|
|
145
|
+
/** Resolves a {@link AXFileTypeComponent} to an Angular component type. */
|
|
146
|
+
async function resolveFileTypeComponentType(component) {
|
|
147
|
+
if (isLazyFileTypeComponentLoader(component)) {
|
|
148
|
+
return component();
|
|
149
|
+
}
|
|
150
|
+
return component;
|
|
151
|
+
}
|
|
152
|
+
/** Whether `value` is a lazy loader rather than an Angular component class. */
|
|
153
|
+
function isLazyFileTypeComponentLoader(value) {
|
|
154
|
+
return typeof value === 'function' && !('ɵcmp' in value);
|
|
155
|
+
}
|
|
156
|
+
|
|
144
157
|
/** Matches a MIME type against a catalog pattern (`image/*`, exact type, …). */
|
|
145
158
|
function matchesFileMime(mime, pattern) {
|
|
146
159
|
const normalizedMime = mime.trim().toLowerCase();
|
|
@@ -208,6 +221,17 @@ function resolveFileTypeCopy(type, extension) {
|
|
|
208
221
|
function resolveFileTypeOpen(type, extension) {
|
|
209
222
|
return extension?.open ?? type.open;
|
|
210
223
|
}
|
|
224
|
+
function resolveFileTypeComponent(type, extension) {
|
|
225
|
+
return extension?.component ?? type.component;
|
|
226
|
+
}
|
|
227
|
+
/** Loads the resolved view component (extension override first). */
|
|
228
|
+
async function loadFileTypeComponent(type, extension) {
|
|
229
|
+
const component = resolveFileTypeComponent(type, extension);
|
|
230
|
+
if (!component) {
|
|
231
|
+
return undefined;
|
|
232
|
+
}
|
|
233
|
+
return resolveFileTypeComponentType(component);
|
|
234
|
+
}
|
|
211
235
|
function resolveFileTypePaste(type, extension) {
|
|
212
236
|
return extension?.paste ?? type.paste;
|
|
213
237
|
}
|
|
@@ -249,6 +273,38 @@ function runFileTypeOpen(type, ctx, payload, extension) {
|
|
|
249
273
|
return runInInjectionContext(ctx.injector, () => open(ctx, payload));
|
|
250
274
|
}
|
|
251
275
|
|
|
276
|
+
/**
|
|
277
|
+
|
|
278
|
+
* Builds an {@link AXFileType} with optional typed handlers and view component.
|
|
279
|
+
|
|
280
|
+
*
|
|
281
|
+
|
|
282
|
+
* @example
|
|
283
|
+
|
|
284
|
+
* ```ts
|
|
285
|
+
|
|
286
|
+
* export const imageFileType = defineFileType<ImagePayload>({
|
|
287
|
+
|
|
288
|
+
* name: 'image',
|
|
289
|
+
|
|
290
|
+
* copy: (p) => p.caption ?? p.url,
|
|
291
|
+
|
|
292
|
+
* component: () => import('./image-viewer.component').then(m => m.ImageViewerComponent),
|
|
293
|
+
|
|
294
|
+
* });
|
|
295
|
+
|
|
296
|
+
* ```
|
|
297
|
+
|
|
298
|
+
*/
|
|
299
|
+
function defineFileType(config) {
|
|
300
|
+
const { copy, open, ...rest } = config;
|
|
301
|
+
return {
|
|
302
|
+
...rest,
|
|
303
|
+
...(copy ? { copy: copy } : {}),
|
|
304
|
+
...(open ? { open: open } : {}),
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
252
308
|
/** Contributes {@link AXFileType} entries (multi provider). */
|
|
253
309
|
class AXFileTypeInfoProvider {
|
|
254
310
|
}
|
|
@@ -261,6 +317,22 @@ function provideFileTypeInfoProvider(provider) {
|
|
|
261
317
|
};
|
|
262
318
|
}
|
|
263
319
|
|
|
320
|
+
/** Registers static file types via the existing {@link AXFileTypeInfoProvider} multi-token. */
|
|
321
|
+
function provideFileTypes(types) {
|
|
322
|
+
class AXStaticFileTypeProvider extends AXFileTypeInfoProvider {
|
|
323
|
+
items() {
|
|
324
|
+
const value = typeof types === 'function' ? types() : types;
|
|
325
|
+
return Promise.resolve(value);
|
|
326
|
+
}
|
|
327
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXStaticFileTypeProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
328
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXStaticFileTypeProvider }); }
|
|
329
|
+
}
|
|
330
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXStaticFileTypeProvider, decorators: [{
|
|
331
|
+
type: Injectable
|
|
332
|
+
}] });
|
|
333
|
+
return provideFileTypeInfoProvider(AXStaticFileTypeProvider);
|
|
334
|
+
}
|
|
335
|
+
|
|
264
336
|
/** Maps {@link AXFileValidations} to executable validation entries. */
|
|
265
337
|
function fileValidationsToRules(validations) {
|
|
266
338
|
const rules = [];
|
|
@@ -369,6 +441,24 @@ class AXFileTypeRegistryService {
|
|
|
369
441
|
const types = await this.resolveTypes();
|
|
370
442
|
return types.find((t) => t.name === name);
|
|
371
443
|
}
|
|
444
|
+
/** Resolved view component ref for a catalog entry (optional extension hint). */
|
|
445
|
+
async getComponent(name, hint) {
|
|
446
|
+
const type = await this.get(name);
|
|
447
|
+
if (!type) {
|
|
448
|
+
return undefined;
|
|
449
|
+
}
|
|
450
|
+
const extension = hint ? resolveFileTypeExtension(type, hint) : undefined;
|
|
451
|
+
return resolveFileTypeComponent(type, extension);
|
|
452
|
+
}
|
|
453
|
+
/** Loads the view component for a catalog entry. */
|
|
454
|
+
async loadComponent(name, hint) {
|
|
455
|
+
const type = await this.get(name);
|
|
456
|
+
if (!type) {
|
|
457
|
+
return undefined;
|
|
458
|
+
}
|
|
459
|
+
const extension = hint ? resolveFileTypeExtension(type, hint) : undefined;
|
|
460
|
+
return loadFileTypeComponent(type, extension);
|
|
461
|
+
}
|
|
372
462
|
async accept(typeNames) {
|
|
373
463
|
const names = typeNames ? (Array.isArray(typeNames) ? typeNames : [typeNames]) : undefined;
|
|
374
464
|
const types = await this.resolveTypes();
|
|
@@ -449,6 +539,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImpor
|
|
|
449
539
|
args: [{ providedIn: 'root' }]
|
|
450
540
|
}] });
|
|
451
541
|
|
|
542
|
+
class AXFileTypeRendererOutletComponent {
|
|
543
|
+
constructor() {
|
|
544
|
+
this.registry = inject(AXFileTypeRegistryService);
|
|
545
|
+
/** Catalog name (e.g. `image`, `conversation-image`). */
|
|
546
|
+
this.fileType = input.required(...(ngDevMode ? [{ debugName: "fileType" }] : []));
|
|
547
|
+
/** Payload passed to the file-type view component. */
|
|
548
|
+
this.payload = input.required(...(ngDevMode ? [{ debugName: "payload" }] : []));
|
|
549
|
+
/** Optional extension / MIME hint for extension-level renderer overrides. */
|
|
550
|
+
this.extensionHint = input(...(ngDevMode ? [undefined, { debugName: "extensionHint" }] : []));
|
|
551
|
+
/** Extra inputs merged with `payload` (e.g. `message` in conversation). */
|
|
552
|
+
this.inputs = input({}, ...(ngDevMode ? [{ debugName: "inputs" }] : []));
|
|
553
|
+
this.resolvedComponent = signal(null, ...(ngDevMode ? [{ debugName: "resolvedComponent" }] : []));
|
|
554
|
+
this.loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
555
|
+
this.mergedInputs = signal({}, ...(ngDevMode ? [{ debugName: "mergedInputs" }] : []));
|
|
556
|
+
effect(() => {
|
|
557
|
+
const name = this.fileType();
|
|
558
|
+
const payload = this.payload();
|
|
559
|
+
const hint = this.extensionHint();
|
|
560
|
+
const extra = this.inputs();
|
|
561
|
+
this.mergedInputs.set({ payload, ...extra });
|
|
562
|
+
this.loading.set(true);
|
|
563
|
+
this.resolvedComponent.set(null);
|
|
564
|
+
void this.registry.loadComponent(name, hint).then((component) => {
|
|
565
|
+
this.resolvedComponent.set(component ?? null);
|
|
566
|
+
this.loading.set(false);
|
|
567
|
+
});
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileTypeRendererOutletComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
571
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.3", type: AXFileTypeRendererOutletComponent, isStandalone: true, selector: "ax-file-type-renderer", inputs: { fileType: { classPropertyName: "fileType", publicName: "fileType", isSignal: true, isRequired: true, transformFunction: null }, payload: { classPropertyName: "payload", publicName: "payload", isSignal: true, isRequired: true, transformFunction: null }, extensionHint: { classPropertyName: "extensionHint", publicName: "extensionHint", isSignal: true, isRequired: false, transformFunction: null }, inputs: { classPropertyName: "inputs", publicName: "inputs", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
572
|
+
@if (resolvedComponent(); as component) {
|
|
573
|
+
<ng-container *ngComponentOutlet="component; inputs: mergedInputs()" />
|
|
574
|
+
} @else if (loading()) {
|
|
575
|
+
<span class="ax-file-type-renderer__loading" aria-hidden="true"></span>
|
|
576
|
+
}
|
|
577
|
+
`, isInline: true, styles: [":host{display:contents}.ax-file-type-renderer__loading{display:inline-block;min-height:1rem;min-width:1rem}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
578
|
+
}
|
|
579
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileTypeRendererOutletComponent, decorators: [{
|
|
580
|
+
type: Component,
|
|
581
|
+
args: [{ selector: 'ax-file-type-renderer', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgComponentOutlet], template: `
|
|
582
|
+
@if (resolvedComponent(); as component) {
|
|
583
|
+
<ng-container *ngComponentOutlet="component; inputs: mergedInputs()" />
|
|
584
|
+
} @else if (loading()) {
|
|
585
|
+
<span class="ax-file-type-renderer__loading" aria-hidden="true"></span>
|
|
586
|
+
}
|
|
587
|
+
`, styles: [":host{display:contents}.ax-file-type-renderer__loading{display:inline-block;min-height:1rem;min-width:1rem}\n"] }]
|
|
588
|
+
}], ctorParameters: () => [] });
|
|
589
|
+
|
|
452
590
|
const MB$4 = 1024 * 1024;
|
|
453
591
|
const AX_AUDIO_FILE_TYPE = {
|
|
454
592
|
name: 'audio',
|
|
@@ -864,5 +1002,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImpor
|
|
|
864
1002
|
* Generated bundle index. Do not edit.
|
|
865
1003
|
*/
|
|
866
1004
|
|
|
867
|
-
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_METADATA_PURPOSE, AX_FILE_VALIDATION_RULES, AX_IMAGE_FILE_TYPE, AX_VIDEO_FILE_TYPE, createFileTypeMetadata, fileTypeMatchesPurpose, fileValidationsToRules, filterFileTypesByPurpose, findFileTypeExtension, findFileTypeExtensionByName, findFileTypeExtensionForMime, formatFileSizeBytes, getFileExtension, getFileTypePurposes, isEmptyFileValidations, isExtensionsOnlyType, matchesFileMime, mergeFileValidations, provideBuiltinFileTypeProviders, provideDefaultFileTypeProviders, provideFileTypeInfoProvider, provideFileTypeSystem, provideFileValidationRules, resolveFileCopyText, resolveFileTypeCopy, resolveFileTypeExtension, resolveFileTypeOpen, resolveFileTypePaste, resolveFileTypeUtility, resolveFileValidations, runFileTypeCopy, runFileTypeOpen, runFileTypeUtility, runFileTypeUtilityForFile, validateFileAgainstType, validateFileWithValidations };
|
|
1005
|
+
export { AXAudioFileTypeProvider, AXDocumentFileTypeProvider, AXFileFileTypeProvider, AXFileMaxSizeValidationRule, AXFileMimeTypeValidationRule, AXFileMinSizeValidationRule, AXFileModule, AXFileService, AXFileSizeFormatter, AXFileTypeInfoProvider, AXFileTypeRegistryService, AXFileTypeRendererOutletComponent, 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_METADATA_PURPOSE, AX_FILE_VALIDATION_RULES, AX_IMAGE_FILE_TYPE, AX_VIDEO_FILE_TYPE, createFileTypeMetadata, defineFileType, fileTypeMatchesPurpose, fileValidationsToRules, filterFileTypesByPurpose, findFileTypeExtension, findFileTypeExtensionByName, findFileTypeExtensionForMime, formatFileSizeBytes, getFileExtension, getFileTypePurposes, isEmptyFileValidations, isExtensionsOnlyType, isLazyFileTypeComponentLoader, loadFileTypeComponent, matchesFileMime, mergeFileValidations, provideBuiltinFileTypeProviders, provideDefaultFileTypeProviders, provideFileTypeInfoProvider, provideFileTypeSystem, provideFileTypes, provideFileValidationRules, resolveFileCopyText, resolveFileTypeComponent, resolveFileTypeComponentType, resolveFileTypeCopy, resolveFileTypeExtension, resolveFileTypeOpen, resolveFileTypePaste, resolveFileTypeUtility, resolveFileValidations, runFileTypeCopy, runFileTypeOpen, runFileTypeUtility, runFileTypeUtilityForFile, validateFileAgainstType, validateFileWithValidations };
|
|
868
1006
|
//# sourceMappingURL=acorex-core-file.mjs.map
|