@taiga-ui/kit
Version:
Taiga UI Angular main components kit
443 lines (428 loc) • 44.2 kB
JavaScript
import * as i0 from '@angular/core';
import { inject, LOCALE_ID, computed, input, output, ChangeDetectionStrategy, Component, contentChildren, TemplateRef, model, ViewEncapsulation, Directive, forwardRef, contentChild, Pipe } from '@angular/core';
import { WA_WINDOW } from '@ng-web-apis/common';
import { TuiButton } from '@taiga-ui/core/components/button';
import { TuiIcon } from '@taiga-ui/core/components/icon';
import { TuiLoader } from '@taiga-ui/core/components/loader';
import * as i1 from '@taiga-ui/core/directives/appearance';
import { tuiAppearanceOptionsProvider, TuiAppearance, tuiAppearanceMode, TuiWithAppearance } from '@taiga-ui/core/directives/appearance';
import { TuiHintOverflow } from '@taiga-ui/core/portals/hint';
import { TUI_COMMON_ICONS, TUI_BREAKPOINT } from '@taiga-ui/core/tokens';
import { TUI_DIGITAL_INFORMATION_UNITS, TUI_FILE_TEXTS, TUI_HIDE_TEXT, TUI_SHOW_ALL_TEXT, TUI_INPUT_FILE_TEXTS } from '@taiga-ui/kit/tokens';
import { PolymorpheusOutlet, injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus';
import { tuiCreateOptions, tuiProvide } from '@taiga-ui/cdk/utils/di';
import { coerceArray } from '@angular/cdk/coercion';
import { tuiRound } from '@taiga-ui/cdk/utils/math';
import { TuiItem } from '@taiga-ui/cdk/directives/item';
import { NgTemplateOutlet } from '@angular/common';
import { TUI_VERSION, CHAR_NO_BREAK_SPACE } from '@taiga-ui/cdk/constants';
import { TuiExpand } from '@taiga-ui/core/components/expand';
import * as i1$1 from '@taiga-ui/core/directives/group';
import { TuiGroup, tuiGroupOptionsProvider } from '@taiga-ui/core/directives/group';
import { TuiLink } from '@taiga-ui/core/components/link';
import { outputFromObservable, toObservable } from '@angular/core/rxjs-interop';
import { TuiControl, tuiAsControl } from '@taiga-ui/cdk/classes';
import * as i1$2 from '@taiga-ui/cdk/directives/native-validator';
import { TuiNativeValidator } from '@taiga-ui/cdk/directives/native-validator';
import { tuiZonefreeScheduler, tuiControlValue } from '@taiga-ui/cdk/observables';
import { tuiInjectElement } from '@taiga-ui/cdk/utils/dom';
import { timer, switchMap, map, filter, combineLatest } from 'rxjs';
import { Validators, NG_VALIDATORS, FormControl } from '@angular/forms';
import { TuiValidator } from '@taiga-ui/cdk/directives/validator';
const TUI_SIZE_ERROR = 'tuiSize';
const TUI_FORMAT_ERROR = 'tuiFormat';
function tuiCreateFileSizeValidator(size) {
return ({ value }) => {
const files = value && coerceArray(value);
const $implicit = value && files?.filter((file) => file.size > size);
return $implicit?.length ? { [TUI_SIZE_ERROR]: { $implicit, size } } : null;
};
}
function tuiCreateFileFormatValidator(accept) {
return ({ value }) => {
const files = value && coerceArray(value);
const formats = toArray$1(accept);
const $implicit = value && files?.filter((file) => !checkFormat(file, formats));
return $implicit?.length && accept ? { [TUI_FORMAT_ERROR]: { $implicit } } : null;
};
}
function checkFormat({ name, type }, formats) {
const extension = `.${(name.split('.').pop() || '').toLowerCase()}`;
const normalizedType = type?.toLowerCase() || '';
return formats.some((format) => format === extension ||
format === normalizedType ||
(format.split('/')[1] === '*' &&
normalizedType.split('/')[0] === format.split('/')[0]));
}
function toArray$1(accept) {
return accept
.split(',')
.map((format) => format.trim().toLowerCase())
.filter(Boolean);
}
const BYTES_PER_KIB = 1024;
const BYTES_PER_MIB = 1024 * BYTES_PER_KIB;
function tuiFilesRejected(control) {
const format = control?.getError(TUI_FORMAT_ERROR)?.$implicit || [];
const size = control?.getError(TUI_SIZE_ERROR)?.$implicit || [];
return Array.from(new Set([...format, ...size]));
}
function tuiFilesAccepted(control) {
const value = control?.value || [];
const files = coerceArray(value);
const size = control?.getError(TUI_SIZE_ERROR)?.$implicit || [];
const format = control?.getError(TUI_FORMAT_ERROR)?.$implicit || [];
return files.filter((file) => !size.includes(file) && !format.includes(file));
}
function tuiFormatSize(units, size, locale) {
if (size === undefined) {
return null;
}
if (size < BYTES_PER_KIB) {
return `${size} ${units[0]}`;
}
return size < BYTES_PER_MIB
? `${(size / BYTES_PER_KIB).toFixed(0)} ${units[1]}`
: `${tuiRound(size / BYTES_PER_MIB, 2).toLocaleString(locale)} ${units[2]}`;
}
const TUI_FILE_DEFAULT_OPTIONS = {
appearance: 'outline',
formatSize: tuiFormatSize,
icons: {
normal: ({ $implicit }) => ($implicit === 'l' ? '.file' : '.circle-check'),
error: '.circle-alert',
deleted: '.trash',
},
};
/**
* Default parameters for file component
*/
const [TUI_FILE_OPTIONS, tuiFileOptionsProvider] = tuiCreateOptions(TUI_FILE_DEFAULT_OPTIONS);
class TuiFile {
constructor() {
this.options = inject(TUI_FILE_OPTIONS);
this.locale = inject(LOCALE_ID);
this.units = inject(TUI_DIGITAL_INFORMATION_UNITS);
this.win = inject(WA_WINDOW);
this.icons = inject(TUI_COMMON_ICONS);
this.fileTexts = inject(TUI_FILE_TEXTS);
this.content = computed(() => this.state() === 'error' && !this.file().content
? this.fileTexts().loadingError
: this.file().content || '');
this.fileSize = computed(() => this.options.formatSize(this.units(), this.file().size, this.locale));
this.preview = computed(() => this.size() === 'l' ? this.createPreview(this.file()) : '');
this.name = computed(() => {
const dot = this.file().name.lastIndexOf('.');
// a dot at position 0 means a “hidden” file, not an extension
return dot > 0 ? this.file().name.slice(0, dot) : this.file().name;
});
this.type = computed(() => {
const dot = this.file().name.lastIndexOf('.');
// only return an extension when there is one
return dot > 0 ? this.file().name.slice(dot) : '';
});
this.icon = computed((state = this.state()) => state === 'loading' ? '' : this.options.icons[state]);
this.file = input({ name: '' });
this.state = input('normal');
this.size = input('m');
this.showDelete = input(true);
this.showSize = input(true);
this.leftContent = input();
this.remove = output();
}
get allowDelete() {
return this.showDelete() && !!this.remove['listeners']?.length;
}
createPreview(file) {
if (file.src) {
return file.src;
}
return this.win.File &&
file instanceof this.win.File &&
file.type?.startsWith('image/')
? URL.createObjectURL(file)
: '';
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiFile, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: TuiFile, isStandalone: true, selector: "tui-file,a[tuiFile],button[tuiFile]", inputs: { file: { classPropertyName: "file", publicName: "file", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showDelete: { classPropertyName: "showDelete", publicName: "showDelete", isSignal: true, isRequired: false, transformFunction: null }, showSize: { classPropertyName: "showSize", publicName: "showSize", isSignal: true, isRequired: false, transformFunction: null }, leftContent: { classPropertyName: "leftContent", publicName: "leftContent", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { remove: "remove" }, host: { properties: { "attr.data-delete": "showDelete()" } }, providers: [tuiAppearanceOptionsProvider(TUI_FILE_OPTIONS)], hostDirectives: [{ directive: i1.TuiAppearance }], ngImport: i0, template: "<div\n class=\"t-preview\"\n [class.t-preview_big]=\"size() === 'l'\"\n>\n <ng-container *polymorpheusOutlet=\"leftContent() || defaultLeftContent as text\">\n {{ text }}\n </ng-container>\n</div>\n<div class=\"t-wrapper\">\n <div class=\"t-text\">\n <div\n tuiHintOverflow\n class=\"t-name\"\n >\n {{ name() }}\n </div>\n <div class=\"t-type\">{{ type() }}</div>\n @if (showSize() && fileSize()) {\n <div class=\"t-size\">\n {{ fileSize() }}\n </div>\n }\n </div>\n @if (content(); as text) {\n <div class=\"t-content\">\n <ng-container *polymorpheusOutlet=\"text\">\n {{ text }}\n </ng-container>\n </div>\n }\n <ng-content />\n</div>\n@if (allowDelete) {\n @if (fileTexts(); as texts) {\n <button\n appearance=\"icon\"\n size=\"xs\"\n tuiIconButton\n type=\"button\"\n class=\"t-remove\"\n [iconStart]=\"icons.close\"\n (click.prevent)=\"remove.emit()\"\n (mousedown.prevent.zoneless)=\"(0)\"\n >\n {{ texts.remove }}\n </button>\n }\n}\n\n<ng-template #defaultLeftContent>\n @if (preview()) {\n <img\n alt=\"file preview\"\n class=\"t-image\"\n [src]=\"preview()\"\n />\n } @else {\n @if (state() === 'loading') {\n <tui-loader\n class=\"t-loader\"\n [inheritColor]=\"size() === 'l'\"\n />\n } @else {\n <tui-icon\n *polymorpheusOutlet=\"icon() as src; context: {$implicit: size()}\"\n class=\"t-icon\"\n [class.t-icon_blank]=\"size() === 'l' || state() === 'deleted'\"\n [class.t-icon_error]=\"state() === 'error'\"\n [icon]=\"src.toString()\"\n />\n }\n }\n</ng-template>\n", styles: [":host{position:relative;display:flex;align-items:center;font:var(--tui-typography-body-m);padding:.625rem;padding-inline-end:2.25rem;text-decoration:none;border-radius:var(--tui-radius-m)}:host:hover .t-remove,:host[data-delete=always] .t-remove{opacity:1}.t-preview{position:relative;display:flex;align-items:center;justify-content:center;flex-shrink:0;inline-size:1.5rem;block-size:1.5rem;margin-inline-end:.75rem;border-radius:var(--tui-radius-m);overflow:hidden;color:var(--tui-text-tertiary)}.t-preview_big{inline-size:4rem;block-size:4rem;margin-inline-end:1rem}.t-preview_big:before{position:absolute;inset-block-start:0;inset-inline-start:0;inline-size:100%;block-size:100%;content:\"\";background:var(--tui-background-neutral-1)}.t-image{max-inline-size:100%;max-block-size:100%}.t-loader{position:absolute;inset-block-start:0;inset-inline-start:0;inline-size:100%;block-size:100%}.t-icon{position:absolute;inset-block-start:0;inset-inline-start:0;inset-block-end:0;inset-inline-end:0;color:var(--tui-status-positive);margin:auto}.t-icon_blank{color:var(--tui-text-tertiary)}.t-icon_error{color:var(--tui-text-negative)}.t-remove{transition-property:opacity;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;position:absolute;inset-block-start:.625rem;inset-inline-end:.625rem}.t-remove:focus{opacity:1}.t-remove:focus-visible{box-shadow:inset 0 0 0 2px var(--tui-border-focus)}@media(hover:hover)and (pointer:fine){.t-remove{opacity:0}}.t-wrapper{display:flex;flex-direction:column;justify-content:center;align-items:flex-start;overflow:hidden;color:var(--tui-text-primary)}.t-text{display:flex;inline-size:100%}.t-size{flex-shrink:0;opacity:var(--tui-disabled-opacity);margin-inline-start:.5rem}.t-type{flex-shrink:0}.t-name{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.t-content{font:var(--tui-typography-body-s);color:var(--tui-text-negative)}\n"], dependencies: [{ kind: "directive", type: PolymorpheusOutlet, selector: "[polymorpheusOutlet]", inputs: ["polymorpheusOutlet", "polymorpheusOutletContext"] }, { kind: "directive", type: TuiButton, selector: "a[tuiButton],button[tuiButton],a[tuiIconButton],button[tuiIconButton]", inputs: ["size"] }, { kind: "directive", type: TuiHintOverflow, selector: "[tuiHintOverflow]", inputs: ["tuiHintOverflow"] }, { kind: "component", type: TuiIcon, selector: "tui-icon:not([tuiBadge])", inputs: ["background"] }, { kind: "component", type: TuiLoader, selector: "tui-loader", inputs: ["size", "inheritColor", "overlay", "textContent", "loading"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiFile, decorators: [{
type: Component,
args: [{ selector: 'tui-file,a[tuiFile],button[tuiFile]', imports: [PolymorpheusOutlet, TuiButton, TuiHintOverflow, TuiIcon, TuiLoader], changeDetection: ChangeDetectionStrategy.OnPush, providers: [tuiAppearanceOptionsProvider(TUI_FILE_OPTIONS)], hostDirectives: [TuiAppearance], host: { '[attr.data-delete]': 'showDelete()' }, template: "<div\n class=\"t-preview\"\n [class.t-preview_big]=\"size() === 'l'\"\n>\n <ng-container *polymorpheusOutlet=\"leftContent() || defaultLeftContent as text\">\n {{ text }}\n </ng-container>\n</div>\n<div class=\"t-wrapper\">\n <div class=\"t-text\">\n <div\n tuiHintOverflow\n class=\"t-name\"\n >\n {{ name() }}\n </div>\n <div class=\"t-type\">{{ type() }}</div>\n @if (showSize() && fileSize()) {\n <div class=\"t-size\">\n {{ fileSize() }}\n </div>\n }\n </div>\n @if (content(); as text) {\n <div class=\"t-content\">\n <ng-container *polymorpheusOutlet=\"text\">\n {{ text }}\n </ng-container>\n </div>\n }\n <ng-content />\n</div>\n@if (allowDelete) {\n @if (fileTexts(); as texts) {\n <button\n appearance=\"icon\"\n size=\"xs\"\n tuiIconButton\n type=\"button\"\n class=\"t-remove\"\n [iconStart]=\"icons.close\"\n (click.prevent)=\"remove.emit()\"\n (mousedown.prevent.zoneless)=\"(0)\"\n >\n {{ texts.remove }}\n </button>\n }\n}\n\n<ng-template #defaultLeftContent>\n @if (preview()) {\n <img\n alt=\"file preview\"\n class=\"t-image\"\n [src]=\"preview()\"\n />\n } @else {\n @if (state() === 'loading') {\n <tui-loader\n class=\"t-loader\"\n [inheritColor]=\"size() === 'l'\"\n />\n } @else {\n <tui-icon\n *polymorpheusOutlet=\"icon() as src; context: {$implicit: size()}\"\n class=\"t-icon\"\n [class.t-icon_blank]=\"size() === 'l' || state() === 'deleted'\"\n [class.t-icon_error]=\"state() === 'error'\"\n [icon]=\"src.toString()\"\n />\n }\n }\n</ng-template>\n", styles: [":host{position:relative;display:flex;align-items:center;font:var(--tui-typography-body-m);padding:.625rem;padding-inline-end:2.25rem;text-decoration:none;border-radius:var(--tui-radius-m)}:host:hover .t-remove,:host[data-delete=always] .t-remove{opacity:1}.t-preview{position:relative;display:flex;align-items:center;justify-content:center;flex-shrink:0;inline-size:1.5rem;block-size:1.5rem;margin-inline-end:.75rem;border-radius:var(--tui-radius-m);overflow:hidden;color:var(--tui-text-tertiary)}.t-preview_big{inline-size:4rem;block-size:4rem;margin-inline-end:1rem}.t-preview_big:before{position:absolute;inset-block-start:0;inset-inline-start:0;inline-size:100%;block-size:100%;content:\"\";background:var(--tui-background-neutral-1)}.t-image{max-inline-size:100%;max-block-size:100%}.t-loader{position:absolute;inset-block-start:0;inset-inline-start:0;inline-size:100%;block-size:100%}.t-icon{position:absolute;inset-block-start:0;inset-inline-start:0;inset-block-end:0;inset-inline-end:0;color:var(--tui-status-positive);margin:auto}.t-icon_blank{color:var(--tui-text-tertiary)}.t-icon_error{color:var(--tui-text-negative)}.t-remove{transition-property:opacity;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;position:absolute;inset-block-start:.625rem;inset-inline-end:.625rem}.t-remove:focus{opacity:1}.t-remove:focus-visible{box-shadow:inset 0 0 0 2px var(--tui-border-focus)}@media(hover:hover)and (pointer:fine){.t-remove{opacity:0}}.t-wrapper{display:flex;flex-direction:column;justify-content:center;align-items:flex-start;overflow:hidden;color:var(--tui-text-primary)}.t-text{display:flex;inline-size:100%}.t-size{flex-shrink:0;opacity:var(--tui-disabled-opacity);margin-inline-start:.5rem}.t-type{flex-shrink:0}.t-name{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.t-content{font:var(--tui-typography-body-s);color:var(--tui-text-negative)}\n"] }]
}] });
class TuiFilesComponent {
constructor() {
this.hideText = inject(TUI_HIDE_TEXT);
this.showAllText = inject(TUI_SHOW_ALL_TEXT);
this.items = contentChildren(TuiItem, { read: TemplateRef });
this.max = input(0);
this.expanded = model(false);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiFilesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: TuiFilesComponent, isStandalone: true, selector: "tui-files", inputs: { max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { expanded: "expandedChange" }, providers: [
tuiGroupOptionsProvider({ size: 'm', collapsed: true, orientation: 'vertical' }),
], queries: [{ propertyName: "items", predicate: TuiItem, read: TemplateRef, isSignal: true }], hostDirectives: [{ directive: i1$1.TuiGroup }], ngImport: i0, template: "<ng-content />\n@for (item of items(); track $index) {\n @if (!max() || $index < max()) {\n <ng-container [ngTemplateOutlet]=\"item\" />\n }\n}\n@if (max() && items().length > max()) {\n <tui-expand [expanded]=\"expanded()\">\n <div\n tuiGroup\n class=\"t-extra-items\"\n >\n @for (item of items(); track $index) {\n @if (max() && $index >= max()) {\n <ng-container [ngTemplateOutlet]=\"item\" />\n }\n }\n </div>\n </tui-expand>\n <div\n class=\"t-bottom\"\n [class.t-bottom_collapsed]=\"!expanded()\"\n >\n <button\n appearance=\"outline\"\n size=\"m\"\n tuiButton\n type=\"button\"\n class=\"t-button\"\n (click)=\"expanded.set(!expanded())\"\n >\n {{ expanded() ? hideText() : showAllText() }}\n </button>\n </div>\n}\n", styles: ["tui-files:where(*[data-tui-version=\"5.7.0\"]){inline-size:100%;overflow:hidden;border-radius:var(--tui-radius-m)}tui-files:where(*[data-tui-version=\"5.7.0\"]):empty:empty{display:none}tui-files:where(*[data-tui-version=\"5.7.0\"]) .t-files{position:relative;display:block;inline-size:100%;block-size:100%;border-radius:var(--tui-radius-m);overflow:hidden}tui-files:where(*[data-tui-version=\"5.7.0\"]) .t-button{inline-size:100%;border-radius:inherit}tui-files:where(*[data-tui-version=\"5.7.0\"]) .t-bottom{z-index:3;inline-size:100%;background:var(--tui-background-base);-webkit-mask-image:none!important;mask-image:none!important}tui-files:where(*[data-tui-version=\"5.7.0\"]) .t-bottom_collapsed{box-shadow:var(--tui-shadow-popup);margin-block-start:-1.5rem}tui-files:where(*[data-tui-version=\"5.7.0\"]) .t-extra-items{inline-size:100%}tui-files:where(*[data-tui-version=\"5.7.0\"]) .t-extra-items>*{border-radius:0!important}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: TuiButton, selector: "a[tuiButton],button[tuiButton],a[tuiIconButton],button[tuiIconButton]", inputs: ["size"] }, { kind: "component", type: TuiExpand, selector: "tui-expand", inputs: ["expanded"] }, { kind: "directive", type: TuiGroup, selector: "[tuiGroup]:not(ng-container)", inputs: ["orientation", "collapsed", "rounded", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiFilesComponent, decorators: [{
type: Component,
args: [{ selector: 'tui-files', imports: [NgTemplateOutlet, TuiButton, TuiExpand, TuiGroup], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
tuiGroupOptionsProvider({ size: 'm', collapsed: true, orientation: 'vertical' }),
], hostDirectives: [TuiGroup], template: "<ng-content />\n@for (item of items(); track $index) {\n @if (!max() || $index < max()) {\n <ng-container [ngTemplateOutlet]=\"item\" />\n }\n}\n@if (max() && items().length > max()) {\n <tui-expand [expanded]=\"expanded()\">\n <div\n tuiGroup\n class=\"t-extra-items\"\n >\n @for (item of items(); track $index) {\n @if (max() && $index >= max()) {\n <ng-container [ngTemplateOutlet]=\"item\" />\n }\n }\n </div>\n </tui-expand>\n <div\n class=\"t-bottom\"\n [class.t-bottom_collapsed]=\"!expanded()\"\n >\n <button\n appearance=\"outline\"\n size=\"m\"\n tuiButton\n type=\"button\"\n class=\"t-button\"\n (click)=\"expanded.set(!expanded())\"\n >\n {{ expanded() ? hideText() : showAllText() }}\n </button>\n </div>\n}\n", styles: ["tui-files:where(*[data-tui-version=\"5.7.0\"]){inline-size:100%;overflow:hidden;border-radius:var(--tui-radius-m)}tui-files:where(*[data-tui-version=\"5.7.0\"]):empty:empty{display:none}tui-files:where(*[data-tui-version=\"5.7.0\"]) .t-files{position:relative;display:block;inline-size:100%;block-size:100%;border-radius:var(--tui-radius-m);overflow:hidden}tui-files:where(*[data-tui-version=\"5.7.0\"]) .t-button{inline-size:100%;border-radius:inherit}tui-files:where(*[data-tui-version=\"5.7.0\"]) .t-bottom{z-index:3;inline-size:100%;background:var(--tui-background-base);-webkit-mask-image:none!important;mask-image:none!important}tui-files:where(*[data-tui-version=\"5.7.0\"]) .t-bottom_collapsed{box-shadow:var(--tui-shadow-popup);margin-block-start:-1.5rem}tui-files:where(*[data-tui-version=\"5.7.0\"]) .t-extra-items{inline-size:100%}tui-files:where(*[data-tui-version=\"5.7.0\"]) .t-extra-items>*{border-radius:0!important}\n"] }]
}] });
class TuiInputFilesContent {
constructor() {
this.texts = inject(TUI_INPUT_FILE_TEXTS);
this.component = inject(TuiInputFiles);
this.breakpoint = inject(TUI_BREAKPOINT);
this.context = injectContext();
this.link = computed(() => this.component.input()?.el.multiple
? this.texts().defaultLinkMultiple
: this.texts().defaultLinkSingle);
this.label = computed(() => this.component.input()?.el.multiple
? this.texts().defaultLabelMultiple
: this.texts().defaultLabelSingle);
this.dragged = computed(() => this.component.input()?.el.multiple
? this.texts().dropMultiple
: this.texts().drop);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiInputFilesContent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: TuiInputFilesContent, isStandalone: true, selector: "ng-component", ngImport: i0, template: `
<a tuiLink>{{ context.$implicit ? '' : link() }}</a>
(breakpoint() !== 'mobile') {
{{ context.$implicit ? dragged() : label() }}
}
`, isInline: true, dependencies: [{ kind: "directive", type: TuiLink, selector: "a[tuiLink], button[tuiLink]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiInputFilesContent, decorators: [{
type: Component,
args: [{
imports: [TuiLink],
template: `
<a tuiLink>{{ context.$implicit ? '' : link() }}</a>
(breakpoint() !== 'mobile') {
{{ context.$implicit ? dragged() : label() }}
}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
}]
}] });
const TUI_INPUT_FILES_DEFAULT_OPTIONS = {
appearance: 'file',
accept: '',
multiple: false,
size: 'l',
maxFileSize: 30 * 1024 * 1024, // 30 MiB
};
/**
* Default parameters for input files component
*/
const [TUI_INPUT_FILES_OPTIONS, tuiInputFilesOptionsProvider] = tuiCreateOptions(TUI_INPUT_FILES_DEFAULT_OPTIONS);
class TuiInputFilesValidator extends TuiValidator {
constructor() {
super(...arguments);
this.options = inject(TUI_INPUT_FILES_OPTIONS);
this.accept = this.options.accept;
this.maxFileSize = this.options.maxFileSize;
}
ngOnChanges() {
this.update();
}
ngOnInit() {
this.update();
}
update() {
this.validate =
Validators.compose([
tuiCreateFileFormatValidator(this.accept),
tuiCreateFileSizeValidator(this.maxFileSize),
]) || Validators.nullValidator;
this.onChange();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiInputFilesValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.21", type: TuiInputFilesValidator, isStandalone: true, inputs: { accept: "accept", maxFileSize: "maxFileSize" }, host: { properties: { "accept": "accept" } }, providers: [tuiProvide(NG_VALIDATORS, TuiInputFilesValidator, true)], exportAs: ["tuiInputFilesValidator"], usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiInputFilesValidator, decorators: [{
type: Directive,
args: [{
inputs: ['accept', 'maxFileSize'],
providers: [tuiProvide(NG_VALIDATORS, TuiInputFilesValidator, true)],
exportAs: 'tuiInputFilesValidator',
host: { '[accept]': 'accept' },
}]
}] });
class TuiInputFilesDirective extends TuiControl {
constructor() {
super(...arguments);
this.host = inject(forwardRef(() => TuiInputFiles));
this.m = tuiAppearanceMode(this.mode);
this.el = tuiInjectElement();
this.reject = outputFromObservable(timer(0, tuiZonefreeScheduler()).pipe(switchMap(() => tuiControlValue(this.control.control)), map(() => tuiFilesRejected(this.control.control)), filter(({ length }) => !!length)));
}
process(files) {
const fileOrFiles = this.el.multiple
? [...toArray(this.value()), ...Array.from(files)]
: files[0];
if (fileOrFiles) {
this.onChange(fileOrFiles);
}
}
onClick(event) {
if (this.el.readOnly) {
event.preventDefault();
}
}
onBlur() {
if (this.el !== this.el.ownerDocument.activeElement) {
this.onTouched();
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiInputFilesDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.21", type: TuiInputFilesDirective, isStandalone: true, selector: "input[tuiInputFiles]", outputs: { reject: "reject" }, host: { attributes: { "title": "", "type": "file" }, listeners: { "blur": "onBlur()", "click": "onClick($event)" }, properties: { "disabled": "disabled()" } }, providers: [
tuiAsControl(TuiInputFilesDirective),
tuiAppearanceOptionsProvider(TUI_INPUT_FILES_OPTIONS),
], usesInheritance: true, hostDirectives: [{ directive: i1$2.TuiNativeValidator }, { directive: i1.TuiWithAppearance }, { directive: TuiInputFilesValidator, inputs: ["accept", "accept", "maxFileSize", "maxFileSize"] }], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiInputFilesDirective, decorators: [{
type: Directive,
args: [{
selector: 'input[tuiInputFiles]',
providers: [
tuiAsControl(TuiInputFilesDirective),
tuiAppearanceOptionsProvider(TUI_INPUT_FILES_OPTIONS),
],
hostDirectives: [
TuiNativeValidator,
TuiWithAppearance,
{
directive: TuiInputFilesValidator,
inputs: ['accept', 'maxFileSize'],
},
],
host: {
title: '',
type: 'file',
'[disabled]': 'disabled()',
'(blur)': 'onBlur()',
'(click)': 'onClick($event)',
},
}]
}] });
function toArray(value) {
return value ? coerceArray(value) : [];
}
class TuiInputFiles {
constructor() {
this.options = inject(TUI_INPUT_FILES_OPTIONS);
this.content = new PolymorpheusComponent(TuiInputFilesContent);
this.template = contentChild(TemplateRef);
this.input = contentChild(TuiInputFilesDirective);
this.size = input(this.options.size, {
alias: 'tuiInputFiles',
});
}
get fileDragged() {
return !!this.files && !this.input()?.disabled();
}
onFilesSelected(input) {
if (!input?.files) {
return;
}
this.input()?.process(input.files);
input.value = '';
}
onDropped({ dataTransfer }) {
this.files = null;
const input = this.input();
if (dataTransfer?.files && !input?.disabled()) {
input?.process(dataTransfer.files);
}
}
onDrag(dataTransfer) {
this.files = dataTransfer?.files;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiInputFiles, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.21", type: TuiInputFiles, isStandalone: true, selector: "label[tuiInputFiles]", inputs: { size: { classPropertyName: "size", publicName: "tuiInputFiles", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-tui-version": "5.7.0", "tuiInputFiles": "" }, listeners: { "change": "onFilesSelected($event.target)", "dragenter": "onDrag($event.dataTransfer)", "dragleave": "onDrag(null)", "dragover.prevent.zoneless": "0", "drop.prevent": "onDropped($event)" }, properties: { "attr.data-size": "size() || options.size", "class._dragged": "fileDragged" } }, queries: [{ propertyName: "template", first: true, predicate: TemplateRef, descendants: true, isSignal: true }, { propertyName: "input", first: true, predicate: TuiInputFilesDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
<ng-content />
<span
*polymorpheusOutlet="
template() || content as text;
context: {$implicit: fileDragged}
"
>
{{ text }}
</span>
`, isInline: true, styles: ["label[tuiInputFiles]:where(*[data-tui-version=\"5.7.0\"]){position:relative;display:flex;box-sizing:border-box;flex-direction:column;min-block-size:var(--tui-height-m);justify-content:center;align-items:center;text-align:center;border-radius:var(--tui-radius-s);font:var(--tui-typography-body-s);overflow-wrap:break-word;padding:.75rem 1rem;gap:.5rem}label[tuiInputFiles]:where(*[data-tui-version=\"5.7.0\"])[data-size=l]{min-block-size:var(--tui-height-l);border-radius:var(--tui-radius-l);font:var(--tui-typography-body-m);padding:1rem}label[tuiInputFiles]:where(*[data-tui-version=\"5.7.0\"])>:not(input){position:relative;pointer-events:none}label[tuiInputFiles]:where(*[data-tui-version=\"5.7.0\"]) input{position:absolute;inset-block-start:0;inset-inline-start:0;inline-size:100%;block-size:100%;color:transparent;cursor:pointer}label[tuiInputFiles]:where(*[data-tui-version=\"5.7.0\"]) input:disabled~*{opacity:var(--tui-disabled-opacity)}label[tuiInputFiles]:where(*[data-tui-version=\"5.7.0\"]) input::-webkit-file-upload-button{display:none}label[tuiInputFiles]:where(*[data-tui-version=\"5.7.0\"]) input::file-selector-button{display:none}*:disabled label[tuiInputFiles]:where(*[data-tui-version=\"5.7.0\"]){pointer-events:none}[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]){transition-property:background;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;border-radius:inherit;box-sizing:border-box;border:1px dashed var(--tui-text-action);outline:none}tui-root._mobile [tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]){border-style:solid}[tuiInputFiles]._dragged [tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]){background:var(--tui-background-neutral-1);border-color:var(--tui-text-action-hover)}@media(hover:hover)and (pointer:fine){[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]):is(a,button,select,textarea,input,label,.tui-interactive):not(:disabled):hover:not([data-state]){background:var(--tui-background-neutral-1);border-color:var(--tui-text-action-hover)}}[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"])[data-state=hover]{background:var(--tui-background-neutral-1);border-color:var(--tui-text-action-hover)}[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]):is(a,button,select,textarea,input,label,.tui-interactive):not(:disabled):active:not([data-state]){background:var(--tui-background-neutral-1-hover)}[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"])[data-state=active]{background:var(--tui-background-neutral-1-hover)}[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]):disabled:not([data-state]),[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"])[data-state=disabled]{background:transparent;border-color:var(--tui-text-tertiary)}[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]):focus-visible:not([data-focus=false]){border:.125rem solid var(--tui-border-focus)}[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"])[data-focus=true]{border:.125rem solid var(--tui-border-focus)}[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]):not(:disabled)[data-mode~=invalid],[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]):invalid:not(:disabled):not([data-mode]){border-color:var(--tui-status-negative)!important}\n"], dependencies: [{ kind: "directive", type: PolymorpheusOutlet, selector: "[polymorpheusOutlet]", inputs: ["polymorpheusOutlet", "polymorpheusOutletContext"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiInputFiles, decorators: [{
type: Component,
args: [{ selector: 'label[tuiInputFiles]', imports: [PolymorpheusOutlet], template: `
<ng-content />
<span
*polymorpheusOutlet="
template() || content as text;
context: {$implicit: fileDragged}
"
>
{{ text }}
</span>
`, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
'data-tui-version': TUI_VERSION,
tuiInputFiles: '',
'[attr.data-size]': 'size() || options.size',
'[class._dragged]': 'fileDragged',
'(change)': 'onFilesSelected($event.target)',
'(dragenter)': 'onDrag($event.dataTransfer)',
'(dragleave)': 'onDrag(null)',
'(dragover.prevent.zoneless)': '0',
'(drop.prevent)': 'onDropped($event)',
}, styles: ["label[tuiInputFiles]:where(*[data-tui-version=\"5.7.0\"]){position:relative;display:flex;box-sizing:border-box;flex-direction:column;min-block-size:var(--tui-height-m);justify-content:center;align-items:center;text-align:center;border-radius:var(--tui-radius-s);font:var(--tui-typography-body-s);overflow-wrap:break-word;padding:.75rem 1rem;gap:.5rem}label[tuiInputFiles]:where(*[data-tui-version=\"5.7.0\"])[data-size=l]{min-block-size:var(--tui-height-l);border-radius:var(--tui-radius-l);font:var(--tui-typography-body-m);padding:1rem}label[tuiInputFiles]:where(*[data-tui-version=\"5.7.0\"])>:not(input){position:relative;pointer-events:none}label[tuiInputFiles]:where(*[data-tui-version=\"5.7.0\"]) input{position:absolute;inset-block-start:0;inset-inline-start:0;inline-size:100%;block-size:100%;color:transparent;cursor:pointer}label[tuiInputFiles]:where(*[data-tui-version=\"5.7.0\"]) input:disabled~*{opacity:var(--tui-disabled-opacity)}label[tuiInputFiles]:where(*[data-tui-version=\"5.7.0\"]) input::-webkit-file-upload-button{display:none}label[tuiInputFiles]:where(*[data-tui-version=\"5.7.0\"]) input::file-selector-button{display:none}*:disabled label[tuiInputFiles]:where(*[data-tui-version=\"5.7.0\"]){pointer-events:none}[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]){transition-property:background;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;border-radius:inherit;box-sizing:border-box;border:1px dashed var(--tui-text-action);outline:none}tui-root._mobile [tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]){border-style:solid}[tuiInputFiles]._dragged [tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]){background:var(--tui-background-neutral-1);border-color:var(--tui-text-action-hover)}@media(hover:hover)and (pointer:fine){[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]):is(a,button,select,textarea,input,label,.tui-interactive):not(:disabled):hover:not([data-state]){background:var(--tui-background-neutral-1);border-color:var(--tui-text-action-hover)}}[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"])[data-state=hover]{background:var(--tui-background-neutral-1);border-color:var(--tui-text-action-hover)}[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]):is(a,button,select,textarea,input,label,.tui-interactive):not(:disabled):active:not([data-state]){background:var(--tui-background-neutral-1-hover)}[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"])[data-state=active]{background:var(--tui-background-neutral-1-hover)}[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]):disabled:not([data-state]),[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"])[data-state=disabled]{background:transparent;border-color:var(--tui-text-tertiary)}[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]):focus-visible:not([data-focus=false]){border:.125rem solid var(--tui-border-focus)}[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"])[data-focus=true]{border:.125rem solid var(--tui-border-focus)}[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]):not(:disabled)[data-mode~=invalid],[tuiAppearance][data-appearance=file]:where(*[data-tui-version=\"5.7.0\"]):invalid:not(:disabled):not([data-mode]){border-color:var(--tui-status-negative)!important}\n"] }]
}] });
class TuiFileRejectedPipe {
constructor() {
this.options = inject(TUI_INPUT_FILES_OPTIONS);
this.formatSize = inject(TUI_FILE_OPTIONS).formatSize;
this.locale = inject(LOCALE_ID);
this.text$ = toObservable(inject(TUI_INPUT_FILE_TEXTS));
this.unit$ = toObservable(inject(TUI_DIGITAL_INFORMATION_UNITS));
}
transform(file, { accept = this.options.accept, maxFileSize = this.options.maxFileSize, } = this.options) {
const sizeValidator = tuiCreateFileSizeValidator(maxFileSize);
const formatValidator = tuiCreateFileFormatValidator(accept);
const control = new FormControl(file);
return combineLatest([this.text$, this.unit$]).pipe(map(([{ maxSizeRejectionReason, formatRejectionReason }, units]) => {
if (file && formatValidator(control)) {
return {
name: file.name,
size: file.size,
content: formatRejectionReason,
};
}
return file && sizeValidator(control)
? {
name: file.name,
size: file.size,
content: `${maxSizeRejectionReason}${CHAR_NO_BREAK_SPACE}${this.formatSize(units, maxFileSize, this.locale)}`,
}
: null;
}));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiFileRejectedPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.21", ngImport: i0, type: TuiFileRejectedPipe, isStandalone: true, name: "tuiFileRejected" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiFileRejectedPipe, decorators: [{
type: Pipe,
args: [{ name: 'tuiFileRejected' }]
}] });
const TuiFiles = [
TuiItem,
TuiFile,
TuiInputFiles,
TuiFilesComponent,
TuiFileRejectedPipe,
TuiInputFilesDirective,
];
/**
* Generated bundle index. Do not edit.
*/
export { TUI_FILE_DEFAULT_OPTIONS, TUI_FILE_OPTIONS, TUI_FORMAT_ERROR, TUI_INPUT_FILES_DEFAULT_OPTIONS, TUI_INPUT_FILES_OPTIONS, TUI_SIZE_ERROR, TuiFile, TuiFileRejectedPipe, TuiFiles, TuiFilesComponent, TuiInputFiles, TuiInputFilesContent, TuiInputFilesDirective, TuiInputFilesValidator, tuiCreateFileFormatValidator, tuiCreateFileSizeValidator, tuiFileOptionsProvider, tuiFilesAccepted, tuiFilesRejected, tuiFormatSize, tuiInputFilesOptionsProvider };
//# sourceMappingURL=taiga-ui-kit-components-files.mjs.map