UNPKG

@taiga-ui/kit

Version:

Taiga UI Angular main components kit

443 lines (428 loc) 44.2 kB
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' ? '@tui.file' : '@tui.circle-check'), error: '@tui.circle-alert', deleted: '@tui.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> @if (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> @if (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