@rossigee/clarity-angular 18.2.1-fixed.1 → 18.2.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/clr-angular-accordion.mjs +355 -0
- package/fesm2022/clr-angular-accordion.mjs.map +1 -0
- package/fesm2022/clr-angular-button.mjs +713 -0
- package/fesm2022/clr-angular-button.mjs.map +1 -0
- package/fesm2022/clr-angular-collapsible-panel.mjs +201 -0
- package/fesm2022/clr-angular-collapsible-panel.mjs.map +1 -0
- package/fesm2022/clr-angular-data-datagrid.mjs +7635 -0
- package/fesm2022/clr-angular-data-datagrid.mjs.map +1 -0
- package/fesm2022/clr-angular-data-stack-view.mjs +442 -0
- package/fesm2022/clr-angular-data-stack-view.mjs.map +1 -0
- package/fesm2022/clr-angular-data-tree-view.mjs +1106 -0
- package/fesm2022/clr-angular-data-tree-view.mjs.map +1 -0
- package/fesm2022/clr-angular-data.mjs +40 -0
- package/fesm2022/clr-angular-data.mjs.map +1 -0
- package/fesm2022/clr-angular-emphasis-alert.mjs +624 -0
- package/fesm2022/clr-angular-emphasis-alert.mjs.map +1 -0
- package/fesm2022/clr-angular-emphasis-badge.mjs +69 -0
- package/fesm2022/clr-angular-emphasis-badge.mjs.map +1 -0
- package/fesm2022/clr-angular-emphasis-common.mjs +25 -0
- package/fesm2022/clr-angular-emphasis-common.mjs.map +1 -0
- package/fesm2022/clr-angular-emphasis-label.mjs +105 -0
- package/fesm2022/clr-angular-emphasis-label.mjs.map +1 -0
- package/fesm2022/clr-angular-emphasis.mjs +41 -0
- package/fesm2022/clr-angular-emphasis.mjs.map +1 -0
- package/fesm2022/clr-angular-forms-checkbox.mjs +270 -0
- package/fesm2022/clr-angular-forms-checkbox.mjs.map +1 -0
- package/fesm2022/clr-angular-forms-combobox.mjs +1775 -0
- package/fesm2022/clr-angular-forms-combobox.mjs.map +1 -0
- package/fesm2022/clr-angular-forms-common.mjs +1251 -0
- package/fesm2022/clr-angular-forms-common.mjs.map +1 -0
- package/fesm2022/clr-angular-forms-datalist.mjs +263 -0
- package/fesm2022/clr-angular-forms-datalist.mjs.map +1 -0
- package/fesm2022/clr-angular-forms-datepicker.mjs +3274 -0
- package/fesm2022/clr-angular-forms-datepicker.mjs.map +1 -0
- package/fesm2022/clr-angular-forms-file-input.mjs +826 -0
- package/fesm2022/clr-angular-forms-file-input.mjs.map +1 -0
- package/fesm2022/clr-angular-forms-input.mjs +153 -0
- package/fesm2022/clr-angular-forms-input.mjs.map +1 -0
- package/fesm2022/clr-angular-forms-number-input.mjs +236 -0
- package/fesm2022/clr-angular-forms-number-input.mjs.map +1 -0
- package/fesm2022/clr-angular-forms-password.mjs +233 -0
- package/fesm2022/clr-angular-forms-password.mjs.map +1 -0
- package/fesm2022/clr-angular-forms-radio.mjs +231 -0
- package/fesm2022/clr-angular-forms-radio.mjs.map +1 -0
- package/fesm2022/clr-angular-forms-range.mjs +186 -0
- package/fesm2022/clr-angular-forms-range.mjs.map +1 -0
- package/fesm2022/clr-angular-forms-select.mjs +153 -0
- package/fesm2022/clr-angular-forms-select.mjs.map +1 -0
- package/fesm2022/clr-angular-forms-textarea.mjs +136 -0
- package/fesm2022/clr-angular-forms-textarea.mjs.map +1 -0
- package/fesm2022/clr-angular-forms.mjs +100 -0
- package/fesm2022/clr-angular-forms.mjs.map +1 -0
- package/fesm2022/clr-angular-icon.mjs +7397 -0
- package/fesm2022/clr-angular-icon.mjs.map +1 -0
- package/fesm2022/clr-angular-layout-breadcrumbs.mjs +120 -0
- package/fesm2022/clr-angular-layout-breadcrumbs.mjs.map +1 -0
- package/fesm2022/clr-angular-layout-main-container.mjs +100 -0
- package/fesm2022/clr-angular-layout-main-container.mjs.map +1 -0
- package/fesm2022/clr-angular-layout-nav.mjs +582 -0
- package/fesm2022/clr-angular-layout-nav.mjs.map +1 -0
- package/fesm2022/clr-angular-layout-tabs.mjs +807 -0
- package/fesm2022/clr-angular-layout-tabs.mjs.map +1 -0
- package/fesm2022/clr-angular-layout-vertical-nav.mjs +507 -0
- package/fesm2022/clr-angular-layout-vertical-nav.mjs.map +1 -0
- package/fesm2022/clr-angular-layout.mjs +44 -0
- package/fesm2022/clr-angular-layout.mjs.map +1 -0
- package/fesm2022/clr-angular-modal.mjs +617 -0
- package/fesm2022/clr-angular-modal.mjs.map +1 -0
- package/fesm2022/clr-angular-popover-common.mjs +1082 -0
- package/fesm2022/clr-angular-popover-common.mjs.map +1 -0
- package/fesm2022/clr-angular-popover-dropdown.mjs +492 -0
- package/fesm2022/clr-angular-popover-dropdown.mjs.map +1 -0
- package/fesm2022/clr-angular-popover-signpost.mjs +494 -0
- package/fesm2022/clr-angular-popover-signpost.mjs.map +1 -0
- package/fesm2022/clr-angular-popover-tooltip.mjs +293 -0
- package/fesm2022/clr-angular-popover-tooltip.mjs.map +1 -0
- package/fesm2022/clr-angular-popover.mjs +41 -0
- package/fesm2022/clr-angular-popover.mjs.map +1 -0
- package/fesm2022/clr-angular-progress-progress-bars.mjs +217 -0
- package/fesm2022/clr-angular-progress-progress-bars.mjs.map +1 -0
- package/fesm2022/clr-angular-progress-spinner.mjs +132 -0
- package/fesm2022/clr-angular-progress-spinner.mjs.map +1 -0
- package/fesm2022/clr-angular-stepper.mjs +694 -0
- package/fesm2022/clr-angular-stepper.mjs.map +1 -0
- package/fesm2022/clr-angular-timeline.mjs +316 -0
- package/fesm2022/clr-angular-timeline.mjs.map +1 -0
- package/fesm2022/clr-angular-utils-conditional.mjs +351 -0
- package/fesm2022/clr-angular-utils-conditional.mjs.map +1 -0
- package/fesm2022/clr-angular-utils-loading.mjs +107 -0
- package/fesm2022/clr-angular-utils-loading.mjs.map +1 -0
- package/fesm2022/clr-angular-utils.mjs +2079 -0
- package/fesm2022/clr-angular-utils.mjs.map +1 -0
- package/fesm2022/clr-angular-wizard.mjs +3074 -0
- package/fesm2022/clr-angular-wizard.mjs.map +1 -0
- package/fesm2022/clr-angular.mjs +2 -2
- package/fesm2022/clr-angular.mjs.map +1 -1
- package/package.json +7 -5
- package/schematics/ng-update/index.d.ts +2 -0
- package/schematics/ng-update/index.js +69 -0
- package/schematics/ng-update/index.js.map +1 -0
- package/schematics/ng-update/migrations/css-migration.d.ts +6 -0
- package/schematics/ng-update/migrations/css-migration.js +177 -0
- package/schematics/ng-update/migrations/css-migration.js.map +1 -0
- package/schematics/ng-update/migrations/import-migration.d.ts +4 -0
- package/schematics/ng-update/migrations/import-migration.js +187 -0
- package/schematics/ng-update/migrations/import-migration.js.map +1 -0
- package/schematics/ng-update/migrations/template-migration.d.ts +6 -0
- package/schematics/ng-update/migrations/template-migration.js +261 -0
- package/schematics/ng-update/migrations/template-migration.js.map +1 -0
- package/schematics/ng-update/replacements/css-replacements.d.ts +17 -0
- package/schematics/ng-update/replacements/css-replacements.js +74 -0
- package/schematics/ng-update/replacements/css-replacements.js.map +1 -0
- package/schematics/ng-update/replacements/import-replacements.d.ts +13 -0
- package/schematics/ng-update/replacements/import-replacements.js +108 -0
- package/schematics/ng-update/replacements/import-replacements.js.map +1 -0
- package/schematics/ng-update/replacements/symbol-replacements.d.ts +12 -0
- package/schematics/ng-update/replacements/symbol-replacements.js +67 -0
- package/schematics/ng-update/replacements/symbol-replacements.js.map +1 -0
- package/schematics/ng-update/replacements/template-replacements.d.ts +19 -0
- package/schematics/ng-update/replacements/template-replacements.js +57 -0
- package/schematics/ng-update/replacements/template-replacements.js.map +1 -0
- package/schematics/ng-update/tests/test-helpers.d.ts +6 -0
- package/schematics/ng-update/tests/test-helpers.js +34 -0
- package/schematics/ng-update/tests/test-helpers.js.map +1 -0
- package/schematics/ng-update/utils/file-visitor.d.ts +8 -0
- package/schematics/ng-update/utils/file-visitor.js +44 -0
- package/schematics/ng-update/utils/file-visitor.js.map +1 -0
- package/schematics/ng-update/utils/regexp-utils.d.ts +16 -0
- package/schematics/ng-update/utils/regexp-utils.js +34 -0
- package/schematics/ng-update/utils/regexp-utils.js.map +1 -0
- package/schematics/vitest.config.d.ts +2 -0
- package/schematics/vitest.config.js +17 -0
- package/schematics/vitest.config.js.map +1 -0
- package/types/clr-angular-accordion.d.ts +100 -0
- package/types/clr-angular-button.d.ts +169 -0
- package/types/clr-angular-collapsible-panel.d.ts +73 -0
- package/types/clr-angular-data-datagrid.d.ts +1843 -0
- package/types/clr-angular-data-stack-view.d.ts +87 -0
- package/types/clr-angular-data-tree-view.d.ts +229 -0
- package/types/clr-angular-data.d.ts +15 -0
- package/types/clr-angular-emphasis-alert.d.ts +175 -0
- package/types/clr-angular-emphasis-badge.d.ts +25 -0
- package/types/clr-angular-emphasis-common.d.ts +6 -0
- package/types/clr-angular-emphasis-label.d.ts +29 -0
- package/types/clr-angular-emphasis.d.ts +15 -0
- package/types/clr-angular-forms-checkbox.d.ts +69 -0
- package/types/clr-angular-forms-combobox.d.ts +353 -0
- package/types/clr-angular-forms-common.d.ts +339 -0
- package/types/clr-angular-forms-datalist.d.ts +59 -0
- package/types/clr-angular-forms-datepicker.d.ts +986 -0
- package/types/clr-angular-forms-file-input.d.ts +193 -0
- package/types/clr-angular-forms-input.d.ts +29 -0
- package/types/clr-angular-forms-number-input.d.ts +43 -0
- package/types/clr-angular-forms-password.d.ts +52 -0
- package/types/clr-angular-forms-radio.d.ts +50 -0
- package/types/clr-angular-forms-range.d.ts +37 -0
- package/types/clr-angular-forms-select.d.ts +36 -0
- package/types/clr-angular-forms-textarea.d.ts +29 -0
- package/types/clr-angular-forms.d.ts +36 -0
- package/types/clr-angular-icon.d.ts +1498 -0
- package/types/clr-angular-layout-breadcrumbs.d.ts +45 -0
- package/types/clr-angular-layout-main-container.d.ts +28 -0
- package/types/clr-angular-layout-nav.d.ts +142 -0
- package/types/clr-angular-layout-tabs.d.ts +158 -0
- package/types/clr-angular-layout-vertical-nav.d.ts +128 -0
- package/types/clr-angular-layout.d.ts +19 -0
- package/types/clr-angular-modal.d.ts +160 -0
- package/types/clr-angular-popover-common.d.ts +254 -0
- package/types/clr-angular-popover-dropdown.d.ts +123 -0
- package/types/clr-angular-popover-signpost.d.ts +157 -0
- package/types/clr-angular-popover-tooltip.d.ts +83 -0
- package/types/clr-angular-popover.d.ts +16 -0
- package/types/clr-angular-progress-progress-bars.d.ts +57 -0
- package/types/clr-angular-progress-spinner.d.ts +44 -0
- package/types/clr-angular-stepper.d.ts +179 -0
- package/types/clr-angular-timeline.d.ts +86 -0
- package/types/clr-angular-utils-conditional.d.ts +132 -0
- package/types/clr-angular-utils-loading.d.ts +38 -0
- package/types/clr-angular-utils.d.ts +913 -0
- package/types/clr-angular-wizard.d.ts +1508 -0
|
@@ -0,0 +1,826 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, Component, inject, TemplateRef, Directive, Injector, ContentChild, ViewChild, forwardRef, Input, HostListener, Self, Optional, NgModule } from '@angular/core';
|
|
3
|
+
import * as i3 from '@clr/angular/forms/common';
|
|
4
|
+
import { NgControlService, ClrAbstractContainer, ControlIdService, ControlClassService, WrappedFormControl, ClrCommonFormsModule } from '@clr/angular/forms/common';
|
|
5
|
+
import * as i2 from '@clr/angular/utils';
|
|
6
|
+
import { ClrCommonStringsService } from '@clr/angular/utils';
|
|
7
|
+
import * as i1 from '@clr/angular/icon';
|
|
8
|
+
import { ClarityIcons, folderOpenIcon, successStandardIcon, errorStandardIcon, ClrIcon } from '@clr/angular/icon';
|
|
9
|
+
import * as i1$1 from '@angular/common';
|
|
10
|
+
import { CommonModule } from '@angular/common';
|
|
11
|
+
import * as i1$2 from '@angular/forms';
|
|
12
|
+
import { NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
|
|
16
|
+
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
|
17
|
+
* This software is released under MIT license.
|
|
18
|
+
* The full license information can be found in LICENSE in the root directory of this project.
|
|
19
|
+
*/
|
|
20
|
+
function buildFileList(files) {
|
|
21
|
+
const dataTransfer = new DataTransfer();
|
|
22
|
+
for (const file of files) {
|
|
23
|
+
dataTransfer.items.add(file);
|
|
24
|
+
}
|
|
25
|
+
return dataTransfer.files;
|
|
26
|
+
}
|
|
27
|
+
function selectFiles(fileInputElement, files) {
|
|
28
|
+
fileInputElement.files = files instanceof FileList ? files : buildFileList(files);
|
|
29
|
+
fileInputElement.dispatchEvent(new Event('change', { bubbles: true, cancelable: true }));
|
|
30
|
+
}
|
|
31
|
+
function clearFiles(fileInputElement) {
|
|
32
|
+
fileInputElement.value = '';
|
|
33
|
+
fileInputElement.dispatchEvent(new Event('change', { bubbles: true, cancelable: true }));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/*
|
|
37
|
+
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
|
|
38
|
+
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
|
39
|
+
* This software is released under MIT license.
|
|
40
|
+
* The full license information can be found in LICENSE in the root directory of this project.
|
|
41
|
+
*/
|
|
42
|
+
const CLR_FILE_MESSAGES_TEMPLATE_CONTEXT = new InjectionToken('ClrFileMessagesTemplateContext');
|
|
43
|
+
class ClrFileInfo {
|
|
44
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileInfo, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
45
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.3", type: ClrFileInfo, isStandalone: false, selector: "clr-file-info", host: { properties: { "class.clr-subtext-wrapper": "true" } }, ngImport: i0, template: `
|
|
46
|
+
<span class="clr-subtext">
|
|
47
|
+
<ng-content></ng-content>
|
|
48
|
+
</span>
|
|
49
|
+
`, isInline: true }); }
|
|
50
|
+
}
|
|
51
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileInfo, decorators: [{
|
|
52
|
+
type: Component,
|
|
53
|
+
args: [{
|
|
54
|
+
selector: 'clr-file-info',
|
|
55
|
+
template: `
|
|
56
|
+
<span class="clr-subtext">
|
|
57
|
+
<ng-content></ng-content>
|
|
58
|
+
</span>
|
|
59
|
+
`,
|
|
60
|
+
host: {
|
|
61
|
+
'[class.clr-subtext-wrapper]': 'true',
|
|
62
|
+
},
|
|
63
|
+
standalone: false,
|
|
64
|
+
}]
|
|
65
|
+
}] });
|
|
66
|
+
class ClrFileSuccess {
|
|
67
|
+
constructor() {
|
|
68
|
+
this.context = inject(CLR_FILE_MESSAGES_TEMPLATE_CONTEXT);
|
|
69
|
+
}
|
|
70
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileSuccess, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
71
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ClrFileSuccess, isStandalone: false, selector: "clr-file-success", host: { properties: { "style.display": "context.success ? \"flex\" : \"none\"", "class.clr-subtext-wrapper": "true", "class.success": "true" } }, ngImport: i0, template: `
|
|
72
|
+
@if (context.success) {
|
|
73
|
+
<cds-icon class="clr-validate-icon" shape="success-standard" status="success" aria-hidden="true"></cds-icon>
|
|
74
|
+
<span class="clr-subtext">
|
|
75
|
+
<ng-content></ng-content>
|
|
76
|
+
</span>
|
|
77
|
+
}
|
|
78
|
+
`, isInline: true, dependencies: [{ kind: "component", type: i1.ClrIcon, selector: "clr-icon, cds-icon", inputs: ["shape", "size", "direction", "flip", "solid", "status", "inverse", "badge"] }] }); }
|
|
79
|
+
}
|
|
80
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileSuccess, decorators: [{
|
|
81
|
+
type: Component,
|
|
82
|
+
args: [{
|
|
83
|
+
selector: 'clr-file-success',
|
|
84
|
+
// We check for success here so that consumers don't have to.
|
|
85
|
+
template: `
|
|
86
|
+
@if (context.success) {
|
|
87
|
+
<cds-icon class="clr-validate-icon" shape="success-standard" status="success" aria-hidden="true"></cds-icon>
|
|
88
|
+
<span class="clr-subtext">
|
|
89
|
+
<ng-content></ng-content>
|
|
90
|
+
</span>
|
|
91
|
+
}
|
|
92
|
+
`,
|
|
93
|
+
host: {
|
|
94
|
+
'[style.display]': 'context.success ? "flex" : "none"',
|
|
95
|
+
'[class.clr-subtext-wrapper]': 'true',
|
|
96
|
+
'[class.success]': 'true',
|
|
97
|
+
},
|
|
98
|
+
standalone: false,
|
|
99
|
+
}]
|
|
100
|
+
}] });
|
|
101
|
+
class ClrFileError {
|
|
102
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileError, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
103
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.3", type: ClrFileError, isStandalone: false, selector: "clr-file-error", host: { properties: { "class.clr-subtext-wrapper": "true", "class.error": "true" } }, ngImport: i0, template: `
|
|
104
|
+
<cds-icon class="clr-validate-icon" shape="error-standard" status="danger" aria-hidden="true"></cds-icon>
|
|
105
|
+
<span class="clr-subtext">
|
|
106
|
+
<ng-content></ng-content>
|
|
107
|
+
</span>
|
|
108
|
+
`, isInline: true, dependencies: [{ kind: "component", type: i1.ClrIcon, selector: "clr-icon, cds-icon", inputs: ["shape", "size", "direction", "flip", "solid", "status", "inverse", "badge"] }] }); }
|
|
109
|
+
}
|
|
110
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileError, decorators: [{
|
|
111
|
+
type: Component,
|
|
112
|
+
args: [{
|
|
113
|
+
selector: 'clr-file-error',
|
|
114
|
+
// The host should have an `*ngIf` or `@if` that checks for the relevant error.
|
|
115
|
+
template: `
|
|
116
|
+
<cds-icon class="clr-validate-icon" shape="error-standard" status="danger" aria-hidden="true"></cds-icon>
|
|
117
|
+
<span class="clr-subtext">
|
|
118
|
+
<ng-content></ng-content>
|
|
119
|
+
</span>
|
|
120
|
+
`,
|
|
121
|
+
host: {
|
|
122
|
+
'[class.clr-subtext-wrapper]': 'true',
|
|
123
|
+
'[class.error]': 'true',
|
|
124
|
+
},
|
|
125
|
+
standalone: false,
|
|
126
|
+
}]
|
|
127
|
+
}] });
|
|
128
|
+
|
|
129
|
+
/*
|
|
130
|
+
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
|
|
131
|
+
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
|
132
|
+
* This software is released under MIT license.
|
|
133
|
+
* The full license information can be found in LICENSE in the root directory of this project.
|
|
134
|
+
*/
|
|
135
|
+
class ClrFileMessagesTemplate {
|
|
136
|
+
constructor() {
|
|
137
|
+
this.templateRef = inject(TemplateRef);
|
|
138
|
+
}
|
|
139
|
+
static ngTemplateContextGuard(directive, context) {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileMessagesTemplate, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
143
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.3", type: ClrFileMessagesTemplate, isStandalone: false, selector: "ng-template[clr-file-messages]", ngImport: i0 }); }
|
|
144
|
+
}
|
|
145
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileMessagesTemplate, decorators: [{
|
|
146
|
+
type: Directive,
|
|
147
|
+
args: [{
|
|
148
|
+
selector: 'ng-template[clr-file-messages]',
|
|
149
|
+
standalone: false,
|
|
150
|
+
}]
|
|
151
|
+
}] });
|
|
152
|
+
|
|
153
|
+
/*
|
|
154
|
+
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
|
|
155
|
+
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
|
156
|
+
* This software is released under MIT license.
|
|
157
|
+
* The full license information can be found in LICENSE in the root directory of this project.
|
|
158
|
+
*/
|
|
159
|
+
class ClrFileList {
|
|
160
|
+
constructor() {
|
|
161
|
+
this.injectorCache = new Map();
|
|
162
|
+
this.contextCache = new Map();
|
|
163
|
+
this.injector = inject(Injector);
|
|
164
|
+
this.commonStrings = inject(ClrCommonStringsService);
|
|
165
|
+
this.ngControlService = inject(NgControlService, { optional: true });
|
|
166
|
+
this.fileInputContainer = inject(ClrFileInputContainer, { optional: true });
|
|
167
|
+
if (!this.ngControlService || !this.fileInputContainer) {
|
|
168
|
+
throw new Error('The clr-file-list component can only be used within a clr-file-input-container.');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
get files() {
|
|
172
|
+
if (!this.fileInputContainer.fileInput) {
|
|
173
|
+
return [];
|
|
174
|
+
}
|
|
175
|
+
const fileInputElement = this.fileInputContainer.fileInput.elementRef.nativeElement;
|
|
176
|
+
return Array.from(fileInputElement.files).sort((a, b) => a.name.localeCompare(b.name));
|
|
177
|
+
}
|
|
178
|
+
getClearFileLabel(filename) {
|
|
179
|
+
return this.commonStrings.parse(this.commonStrings.keys.clearFile, {
|
|
180
|
+
FILE: filename,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
clearFile(fileToRemove) {
|
|
184
|
+
if (!this.fileInputContainer.fileInput) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const fileInputElement = this.fileInputContainer.fileInput.elementRef.nativeElement;
|
|
188
|
+
const files = Array.from(fileInputElement.files);
|
|
189
|
+
const newFiles = files.filter(file => file !== fileToRemove);
|
|
190
|
+
selectFiles(fileInputElement, newFiles);
|
|
191
|
+
this.fileInputContainer.focusBrowseButton();
|
|
192
|
+
}
|
|
193
|
+
createFileMessagesTemplateContext(file) {
|
|
194
|
+
const fileInputErrors = this.ngControlService.controls[0].errors || {};
|
|
195
|
+
const errors = {
|
|
196
|
+
accept: fileInputErrors.accept?.find(error => error.name === file.name),
|
|
197
|
+
minFileSize: fileInputErrors.minFileSize?.find(error => error.name === file.name),
|
|
198
|
+
maxFileSize: fileInputErrors.maxFileSize?.find(error => error.name === file.name),
|
|
199
|
+
};
|
|
200
|
+
const success = Object.values(errors).every(error => !error);
|
|
201
|
+
const cached = this.contextCache.get(file);
|
|
202
|
+
if (cached && cached.success === success && this.errorsEqual(cached.errors, errors)) {
|
|
203
|
+
return cached;
|
|
204
|
+
}
|
|
205
|
+
// new context is made and old reference replaced
|
|
206
|
+
const context = { $implicit: file, success, errors };
|
|
207
|
+
this.contextCache.set(file, context);
|
|
208
|
+
// new injector is made and old reference replaced
|
|
209
|
+
const injector = this.createFileMessagesTemplateInjector(context);
|
|
210
|
+
this.injectorCache.set(file, injector);
|
|
211
|
+
return context;
|
|
212
|
+
}
|
|
213
|
+
createFileMessagesTemplateInjector(fileMessagesTemplateContext) {
|
|
214
|
+
return Injector.create({
|
|
215
|
+
parent: this.injector,
|
|
216
|
+
providers: [{ provide: CLR_FILE_MESSAGES_TEMPLATE_CONTEXT, useValue: fileMessagesTemplateContext }],
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
errorsEqual(a, b) {
|
|
220
|
+
return a.accept === b.accept && a.minFileSize === b.minFileSize && a.maxFileSize === b.maxFileSize;
|
|
221
|
+
}
|
|
222
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileList, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
223
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ClrFileList, isStandalone: false, selector: "clr-file-list", host: { properties: { "attr.role": "\"list\"", "class.clr-file-list": "true" } }, queries: [{ propertyName: "fileMessagesTemplate", first: true, predicate: ClrFileMessagesTemplate, descendants: true }], ngImport: i0, template: `
|
|
224
|
+
@for (file of files; track file) {
|
|
225
|
+
@if (createFileMessagesTemplateContext(file); as fileMessagesTemplateContext) {
|
|
226
|
+
<div
|
|
227
|
+
role="listitem"
|
|
228
|
+
class="clr-file-list-item"
|
|
229
|
+
[ngClass]="{
|
|
230
|
+
'clr-error': !fileMessagesTemplateContext.success,
|
|
231
|
+
'clr-success': fileMessagesTemplateContext.success,
|
|
232
|
+
}"
|
|
233
|
+
>
|
|
234
|
+
<div class="clr-file-label-and-status-icon">
|
|
235
|
+
<span class="label clr-file-label">
|
|
236
|
+
{{ file.name }}
|
|
237
|
+
<button
|
|
238
|
+
class="btn btn-sm btn-link-neutral btn-icon clr-file-clear-button"
|
|
239
|
+
[attr.aria-label]="getClearFileLabel(file.name)"
|
|
240
|
+
(click)="clearFile(file)"
|
|
241
|
+
>
|
|
242
|
+
<cds-icon shape="times"></cds-icon>
|
|
243
|
+
</button>
|
|
244
|
+
</span>
|
|
245
|
+
</div>
|
|
246
|
+
@if (fileMessagesTemplate) {
|
|
247
|
+
<ng-container
|
|
248
|
+
[ngTemplateOutlet]="fileMessagesTemplate.templateRef"
|
|
249
|
+
[ngTemplateOutletContext]="fileMessagesTemplateContext"
|
|
250
|
+
[ngTemplateOutletInjector]="injectorCache.get(file)"
|
|
251
|
+
></ng-container>
|
|
252
|
+
}
|
|
253
|
+
</div>
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i1.ClrIcon, selector: "clr-icon, cds-icon", inputs: ["shape", "size", "direction", "flip", "solid", "status", "inverse", "badge"] }] }); }
|
|
257
|
+
}
|
|
258
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileList, decorators: [{
|
|
259
|
+
type: Component,
|
|
260
|
+
args: [{
|
|
261
|
+
selector: 'clr-file-list',
|
|
262
|
+
template: `
|
|
263
|
+
@for (file of files; track file) {
|
|
264
|
+
@if (createFileMessagesTemplateContext(file); as fileMessagesTemplateContext) {
|
|
265
|
+
<div
|
|
266
|
+
role="listitem"
|
|
267
|
+
class="clr-file-list-item"
|
|
268
|
+
[ngClass]="{
|
|
269
|
+
'clr-error': !fileMessagesTemplateContext.success,
|
|
270
|
+
'clr-success': fileMessagesTemplateContext.success,
|
|
271
|
+
}"
|
|
272
|
+
>
|
|
273
|
+
<div class="clr-file-label-and-status-icon">
|
|
274
|
+
<span class="label clr-file-label">
|
|
275
|
+
{{ file.name }}
|
|
276
|
+
<button
|
|
277
|
+
class="btn btn-sm btn-link-neutral btn-icon clr-file-clear-button"
|
|
278
|
+
[attr.aria-label]="getClearFileLabel(file.name)"
|
|
279
|
+
(click)="clearFile(file)"
|
|
280
|
+
>
|
|
281
|
+
<cds-icon shape="times"></cds-icon>
|
|
282
|
+
</button>
|
|
283
|
+
</span>
|
|
284
|
+
</div>
|
|
285
|
+
@if (fileMessagesTemplate) {
|
|
286
|
+
<ng-container
|
|
287
|
+
[ngTemplateOutlet]="fileMessagesTemplate.templateRef"
|
|
288
|
+
[ngTemplateOutletContext]="fileMessagesTemplateContext"
|
|
289
|
+
[ngTemplateOutletInjector]="injectorCache.get(file)"
|
|
290
|
+
></ng-container>
|
|
291
|
+
}
|
|
292
|
+
</div>
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
`,
|
|
296
|
+
host: {
|
|
297
|
+
'[attr.role]': '"list"',
|
|
298
|
+
'[class.clr-file-list]': 'true',
|
|
299
|
+
},
|
|
300
|
+
standalone: false,
|
|
301
|
+
}]
|
|
302
|
+
}], ctorParameters: () => [], propDecorators: { fileMessagesTemplate: [{
|
|
303
|
+
type: ContentChild,
|
|
304
|
+
args: [ClrFileMessagesTemplate]
|
|
305
|
+
}] } });
|
|
306
|
+
|
|
307
|
+
/*
|
|
308
|
+
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
|
|
309
|
+
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
|
310
|
+
* This software is released under MIT license.
|
|
311
|
+
* The full license information can be found in LICENSE in the root directory of this project.
|
|
312
|
+
*/
|
|
313
|
+
class ClrFileInputContainer extends ClrAbstractContainer {
|
|
314
|
+
constructor() {
|
|
315
|
+
super(...arguments);
|
|
316
|
+
this.commonStrings = inject(ClrCommonStringsService);
|
|
317
|
+
}
|
|
318
|
+
get accept() {
|
|
319
|
+
return this.fileInput.elementRef.nativeElement.accept;
|
|
320
|
+
}
|
|
321
|
+
get multiple() {
|
|
322
|
+
return this.fileInput.elementRef.nativeElement.multiple;
|
|
323
|
+
}
|
|
324
|
+
get disabled() {
|
|
325
|
+
return this.control ? this.control.disabled : this.fileInput.elementRef.nativeElement.disabled;
|
|
326
|
+
}
|
|
327
|
+
get browseButtonText() {
|
|
328
|
+
const selectionButtonLabel = this.fileList ? undefined : this.fileInput?.selection?.buttonLabel;
|
|
329
|
+
return selectionButtonLabel || this.customButtonLabel || this.commonStrings.keys.browse;
|
|
330
|
+
}
|
|
331
|
+
get browseButtonDescribedBy() {
|
|
332
|
+
return `${this.label?.forAttr} ${this.fileInput.elementRef.nativeElement.getAttribute('aria-describedby')}`;
|
|
333
|
+
}
|
|
334
|
+
get successMessagePresent() {
|
|
335
|
+
return super.successMessagePresent || !!this.fileSuccessComponent;
|
|
336
|
+
}
|
|
337
|
+
get errorMessagePresent() {
|
|
338
|
+
return super.errorMessagePresent || !!this.fileErrorComponent;
|
|
339
|
+
}
|
|
340
|
+
focusBrowseButton() {
|
|
341
|
+
this.browseButtonElementRef.nativeElement.focus();
|
|
342
|
+
}
|
|
343
|
+
browse() {
|
|
344
|
+
const fileInputElementRef = this.fileList && this.multiple ? this.fileListFileInputElementRef : this.fileInput.elementRef;
|
|
345
|
+
fileInputElementRef.nativeElement.click();
|
|
346
|
+
}
|
|
347
|
+
clearSelectedFiles() {
|
|
348
|
+
this.fileInput.elementRef.nativeElement.value = '';
|
|
349
|
+
this.fileInput.elementRef.nativeElement.dispatchEvent(new Event('change', { bubbles: true, cancelable: true }));
|
|
350
|
+
this.focusBrowseButton();
|
|
351
|
+
}
|
|
352
|
+
addFilesToSelection(newFiles) {
|
|
353
|
+
if (!newFiles.length) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
// start with new files
|
|
357
|
+
const mergedFiles = [...newFiles];
|
|
358
|
+
// add existing files if a new file doesn't have the same name
|
|
359
|
+
for (const existingFile of this.fileInput.elementRef.nativeElement.files) {
|
|
360
|
+
if (!mergedFiles.some(file => file.name === existingFile.name)) {
|
|
361
|
+
mergedFiles.push(existingFile);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
// update file selection
|
|
365
|
+
selectFiles(this.fileInput.elementRef.nativeElement, mergedFiles);
|
|
366
|
+
}
|
|
367
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileInputContainer, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
368
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ClrFileInputContainer, isStandalone: false, selector: "clr-file-input-container", inputs: { customButtonLabel: ["clrButtonLabel", "customButtonLabel"] }, host: { properties: { "class.clr-form-control": "true", "class.clr-form-control-disabled": "disabled", "class.clr-row": "addGrid()" } }, providers: [NgControlService, ControlIdService, ControlClassService], queries: [{ propertyName: "fileInput", first: true, predicate: i0.forwardRef(() => ClrFileInput), descendants: true }, { propertyName: "fileList", first: true, predicate: i0.forwardRef(() => ClrFileList), descendants: true }, { propertyName: "fileSuccessComponent", first: true, predicate: ClrFileSuccess, descendants: true }, { propertyName: "fileErrorComponent", first: true, predicate: ClrFileError, descendants: true }], viewQueries: [{ propertyName: "browseButtonElementRef", first: true, predicate: ["browseButton"], descendants: true }, { propertyName: "fileListFileInputElementRef", first: true, predicate: ["fileListFileInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: `
|
|
369
|
+
<ng-content select="label"></ng-content>
|
|
370
|
+
@if (!label && addGrid()) {
|
|
371
|
+
<label></label>
|
|
372
|
+
}
|
|
373
|
+
<div class="clr-control-container" [ngClass]="controlClass()">
|
|
374
|
+
<div class="clr-file-input-wrapper">
|
|
375
|
+
<ng-content select="[clrFileInput]"></ng-content>
|
|
376
|
+
|
|
377
|
+
<!-- file input to handle adding new files to selection when file list is present (prevent replacing selected files on the main file input) -->
|
|
378
|
+
@if (fileList) {
|
|
379
|
+
<input
|
|
380
|
+
#fileListFileInput
|
|
381
|
+
type="file"
|
|
382
|
+
class="clr-file-input"
|
|
383
|
+
tabindex="-1"
|
|
384
|
+
aria-hidden="true"
|
|
385
|
+
[accept]="accept"
|
|
386
|
+
[multiple]="multiple"
|
|
387
|
+
[disabled]="disabled"
|
|
388
|
+
(change)="addFilesToSelection(fileListFileInput.files)"
|
|
389
|
+
/>
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
<button
|
|
393
|
+
#browseButton
|
|
394
|
+
type="button"
|
|
395
|
+
class="btn btn-sm clr-file-input-browse-button"
|
|
396
|
+
[attr.aria-describedby]="browseButtonDescribedBy"
|
|
397
|
+
[disabled]="disabled"
|
|
398
|
+
(click)="browse()"
|
|
399
|
+
>
|
|
400
|
+
<cds-icon shape="folder-open"></cds-icon>
|
|
401
|
+
<span class="clr-file-input-browse-button-text">{{ browseButtonText }}</span>
|
|
402
|
+
</button>
|
|
403
|
+
@if (!fileList && fileInput?.selection?.fileCount) {
|
|
404
|
+
<button
|
|
405
|
+
type="button"
|
|
406
|
+
class="btn btn-sm clr-file-input-clear-button"
|
|
407
|
+
[attr.aria-label]="fileInput?.selection?.clearFilesButtonLabel"
|
|
408
|
+
(click)="clearSelectedFiles()"
|
|
409
|
+
>
|
|
410
|
+
<cds-icon shape="times" status="neutral"></cds-icon>
|
|
411
|
+
</button>
|
|
412
|
+
}
|
|
413
|
+
</div>
|
|
414
|
+
@if (showHelper) {
|
|
415
|
+
<ng-content select="clr-control-helper"></ng-content>
|
|
416
|
+
}
|
|
417
|
+
@if (showInvalid) {
|
|
418
|
+
<ng-content select="clr-control-error"></ng-content>
|
|
419
|
+
}
|
|
420
|
+
@if (showValid) {
|
|
421
|
+
<ng-content select="clr-control-success"></ng-content>
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
<!-- If this is present, this file input becomes an "advanced" file input. -->
|
|
425
|
+
<ng-container>
|
|
426
|
+
<div class="clr-file-list-break"></div>
|
|
427
|
+
<ng-content select="clr-file-list"></ng-content>
|
|
428
|
+
</ng-container>
|
|
429
|
+
</div>
|
|
430
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i1.ClrIcon, selector: "clr-icon, cds-icon", inputs: ["shape", "size", "direction", "flip", "solid", "status", "inverse", "badge"] }, { kind: "directive", type: i3.ClrControlLabel, selector: "label", inputs: ["id", "for"] }] }); }
|
|
431
|
+
}
|
|
432
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileInputContainer, decorators: [{
|
|
433
|
+
type: Component,
|
|
434
|
+
args: [{
|
|
435
|
+
selector: 'clr-file-input-container',
|
|
436
|
+
template: `
|
|
437
|
+
<ng-content select="label"></ng-content>
|
|
438
|
+
@if (!label && addGrid()) {
|
|
439
|
+
<label></label>
|
|
440
|
+
}
|
|
441
|
+
<div class="clr-control-container" [ngClass]="controlClass()">
|
|
442
|
+
<div class="clr-file-input-wrapper">
|
|
443
|
+
<ng-content select="[clrFileInput]"></ng-content>
|
|
444
|
+
|
|
445
|
+
<!-- file input to handle adding new files to selection when file list is present (prevent replacing selected files on the main file input) -->
|
|
446
|
+
@if (fileList) {
|
|
447
|
+
<input
|
|
448
|
+
#fileListFileInput
|
|
449
|
+
type="file"
|
|
450
|
+
class="clr-file-input"
|
|
451
|
+
tabindex="-1"
|
|
452
|
+
aria-hidden="true"
|
|
453
|
+
[accept]="accept"
|
|
454
|
+
[multiple]="multiple"
|
|
455
|
+
[disabled]="disabled"
|
|
456
|
+
(change)="addFilesToSelection(fileListFileInput.files)"
|
|
457
|
+
/>
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
<button
|
|
461
|
+
#browseButton
|
|
462
|
+
type="button"
|
|
463
|
+
class="btn btn-sm clr-file-input-browse-button"
|
|
464
|
+
[attr.aria-describedby]="browseButtonDescribedBy"
|
|
465
|
+
[disabled]="disabled"
|
|
466
|
+
(click)="browse()"
|
|
467
|
+
>
|
|
468
|
+
<cds-icon shape="folder-open"></cds-icon>
|
|
469
|
+
<span class="clr-file-input-browse-button-text">{{ browseButtonText }}</span>
|
|
470
|
+
</button>
|
|
471
|
+
@if (!fileList && fileInput?.selection?.fileCount) {
|
|
472
|
+
<button
|
|
473
|
+
type="button"
|
|
474
|
+
class="btn btn-sm clr-file-input-clear-button"
|
|
475
|
+
[attr.aria-label]="fileInput?.selection?.clearFilesButtonLabel"
|
|
476
|
+
(click)="clearSelectedFiles()"
|
|
477
|
+
>
|
|
478
|
+
<cds-icon shape="times" status="neutral"></cds-icon>
|
|
479
|
+
</button>
|
|
480
|
+
}
|
|
481
|
+
</div>
|
|
482
|
+
@if (showHelper) {
|
|
483
|
+
<ng-content select="clr-control-helper"></ng-content>
|
|
484
|
+
}
|
|
485
|
+
@if (showInvalid) {
|
|
486
|
+
<ng-content select="clr-control-error"></ng-content>
|
|
487
|
+
}
|
|
488
|
+
@if (showValid) {
|
|
489
|
+
<ng-content select="clr-control-success"></ng-content>
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
<!-- If this is present, this file input becomes an "advanced" file input. -->
|
|
493
|
+
<ng-container>
|
|
494
|
+
<div class="clr-file-list-break"></div>
|
|
495
|
+
<ng-content select="clr-file-list"></ng-content>
|
|
496
|
+
</ng-container>
|
|
497
|
+
</div>
|
|
498
|
+
`,
|
|
499
|
+
host: {
|
|
500
|
+
'[class.clr-form-control]': 'true',
|
|
501
|
+
'[class.clr-form-control-disabled]': 'disabled',
|
|
502
|
+
'[class.clr-row]': 'addGrid()',
|
|
503
|
+
},
|
|
504
|
+
providers: [NgControlService, ControlIdService, ControlClassService],
|
|
505
|
+
standalone: false,
|
|
506
|
+
}]
|
|
507
|
+
}], propDecorators: { customButtonLabel: [{
|
|
508
|
+
type: Input,
|
|
509
|
+
args: ['clrButtonLabel']
|
|
510
|
+
}], fileInput: [{
|
|
511
|
+
type: ContentChild,
|
|
512
|
+
args: [forwardRef(() => ClrFileInput)]
|
|
513
|
+
}], fileList: [{
|
|
514
|
+
type: ContentChild,
|
|
515
|
+
args: [forwardRef(() => ClrFileList)]
|
|
516
|
+
}], browseButtonElementRef: [{
|
|
517
|
+
type: ViewChild,
|
|
518
|
+
args: ['browseButton']
|
|
519
|
+
}], fileListFileInputElementRef: [{
|
|
520
|
+
type: ViewChild,
|
|
521
|
+
args: ['fileListFileInput']
|
|
522
|
+
}], fileSuccessComponent: [{
|
|
523
|
+
type: ContentChild,
|
|
524
|
+
args: [ClrFileSuccess]
|
|
525
|
+
}], fileErrorComponent: [{
|
|
526
|
+
type: ContentChild,
|
|
527
|
+
args: [ClrFileError]
|
|
528
|
+
}] } });
|
|
529
|
+
|
|
530
|
+
/*
|
|
531
|
+
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
|
|
532
|
+
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
|
533
|
+
* This software is released under MIT license.
|
|
534
|
+
* The full license information can be found in LICENSE in the root directory of this project.
|
|
535
|
+
*/
|
|
536
|
+
class ClrFileInput extends WrappedFormControl {
|
|
537
|
+
constructor(injector, renderer, viewContainerRef, elementRef, control, commonStrings) {
|
|
538
|
+
super(viewContainerRef, ClrFileInputContainer, injector, control, renderer, elementRef);
|
|
539
|
+
this.elementRef = elementRef;
|
|
540
|
+
this.control = control;
|
|
541
|
+
this.commonStrings = commonStrings;
|
|
542
|
+
this.selection = undefined;
|
|
543
|
+
}
|
|
544
|
+
handleChange() {
|
|
545
|
+
this.updateSelection();
|
|
546
|
+
}
|
|
547
|
+
updateSelection() {
|
|
548
|
+
const files = this.elementRef.nativeElement.files;
|
|
549
|
+
let selectionButtonLabel;
|
|
550
|
+
let clearFilesButtonLabel;
|
|
551
|
+
if (files?.length === 1) {
|
|
552
|
+
const filename = files[0].name;
|
|
553
|
+
selectionButtonLabel = filename;
|
|
554
|
+
clearFilesButtonLabel = this.commonStrings.parse(this.commonStrings.keys.clearFile, {
|
|
555
|
+
FILE: filename,
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
else if (files?.length > 1) {
|
|
559
|
+
const fileCount = files.length.toString();
|
|
560
|
+
selectionButtonLabel = this.commonStrings.parse(this.commonStrings.keys.fileCount, {
|
|
561
|
+
COUNT: fileCount,
|
|
562
|
+
});
|
|
563
|
+
clearFilesButtonLabel = this.commonStrings.parse(this.commonStrings.keys.clearFiles, {
|
|
564
|
+
COUNT: fileCount,
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
this.selection = {
|
|
568
|
+
fileCount: files.length,
|
|
569
|
+
buttonLabel: selectionButtonLabel,
|
|
570
|
+
clearFilesButtonLabel,
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileInput, deps: [{ token: i0.Injector }, { token: i0.Renderer2 }, { token: i0.ViewContainerRef }, { token: i0.ElementRef }, { token: i1$2.NgControl, optional: true, self: true }, { token: i2.ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
574
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.3", type: ClrFileInput, isStandalone: false, selector: "input[type=\"file\"][clrFileInput]", host: { attributes: { "tabindex": "-1", "aria-hidden": "true" }, listeners: { "change": "handleChange()" }, properties: { "class.clr-file-input": "true" } }, usesInheritance: true, ngImport: i0 }); }
|
|
575
|
+
}
|
|
576
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileInput, decorators: [{
|
|
577
|
+
type: Directive,
|
|
578
|
+
args: [{
|
|
579
|
+
selector: 'input[type="file"][clrFileInput]',
|
|
580
|
+
host: {
|
|
581
|
+
tabindex: '-1', // Remove the hidden file `input` element from the tab order because the browse `button` replaces it.
|
|
582
|
+
'aria-hidden': 'true', // Remove the hidden file `input` element from the accessibility tree because the browse `button` replaces it.
|
|
583
|
+
'[class.clr-file-input]': 'true',
|
|
584
|
+
},
|
|
585
|
+
standalone: false,
|
|
586
|
+
}]
|
|
587
|
+
}], ctorParameters: () => [{ type: i0.Injector }, { type: i0.Renderer2 }, { type: i0.ViewContainerRef }, { type: i0.ElementRef }, { type: i1$2.NgControl, decorators: [{
|
|
588
|
+
type: Self
|
|
589
|
+
}, {
|
|
590
|
+
type: Optional
|
|
591
|
+
}] }, { type: i2.ClrCommonStringsService }], propDecorators: { handleChange: [{
|
|
592
|
+
type: HostListener,
|
|
593
|
+
args: ['change']
|
|
594
|
+
}] } });
|
|
595
|
+
|
|
596
|
+
/*
|
|
597
|
+
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
|
|
598
|
+
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
|
599
|
+
* This software is released under MIT license.
|
|
600
|
+
* The full license information can be found in LICENSE in the root directory of this project.
|
|
601
|
+
*/
|
|
602
|
+
class ClrFileInputValidator {
|
|
603
|
+
constructor(elementRef) {
|
|
604
|
+
this.elementRef = elementRef;
|
|
605
|
+
}
|
|
606
|
+
validate(control) {
|
|
607
|
+
const files = control.value;
|
|
608
|
+
const fileInputElement = this.elementRef.nativeElement;
|
|
609
|
+
const errors = {};
|
|
610
|
+
// required validation (native attribute)
|
|
611
|
+
if (fileInputElement.required && files?.length === 0) {
|
|
612
|
+
errors.required = true;
|
|
613
|
+
}
|
|
614
|
+
const accept = fileInputElement.accept ? fileInputElement.accept.split(',').map(type => type.trim()) : null;
|
|
615
|
+
if (files?.length > 0 && (accept || this.minFileSize || this.maxFileSize)) {
|
|
616
|
+
for (let i = 0; i < files.length; i++) {
|
|
617
|
+
const file = files.item(i);
|
|
618
|
+
// accept validation (native attribute)
|
|
619
|
+
if (accept && accept.length) {
|
|
620
|
+
if (!this.validateAccept(file, accept)) {
|
|
621
|
+
errors.accept = errors.accept || [];
|
|
622
|
+
errors.accept.push({
|
|
623
|
+
name: file.name,
|
|
624
|
+
accept,
|
|
625
|
+
type: file.type || '',
|
|
626
|
+
extension: this.getSuffixByDepth(file.name, 2), // last up to 2 parts for reporting
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
// min file validation (custom input)
|
|
631
|
+
if (this.minFileSize && file.size < this.minFileSize) {
|
|
632
|
+
errors.minFileSize = errors.minFileSize || [];
|
|
633
|
+
errors.minFileSize.push({ name: file.name, minFileSize: this.minFileSize, actualFileSize: file.size });
|
|
634
|
+
}
|
|
635
|
+
// max file validation (custom input)
|
|
636
|
+
if (this.maxFileSize && file.size > this.maxFileSize) {
|
|
637
|
+
errors.maxFileSize = errors.maxFileSize || [];
|
|
638
|
+
errors.maxFileSize.push({ name: file.name, maxFileSize: this.maxFileSize, actualFileSize: file.size });
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
return Object.keys(errors).length ? errors : null;
|
|
643
|
+
}
|
|
644
|
+
getSuffixByDepth(filename, depth) {
|
|
645
|
+
const match = filename.toLowerCase().match(new RegExp(`(\\.[^.]+){1,${depth}}$`, 'i'));
|
|
646
|
+
return match ? match[0] : '';
|
|
647
|
+
}
|
|
648
|
+
validateAccept(file, acceptList) {
|
|
649
|
+
const name = file.name.toLowerCase();
|
|
650
|
+
const type = (file.type || '').toLowerCase();
|
|
651
|
+
for (const entryRaw of acceptList) {
|
|
652
|
+
const entry = entryRaw.trim().toLowerCase();
|
|
653
|
+
if (!entry) {
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
// Extension check
|
|
657
|
+
if (entry.startsWith('.')) {
|
|
658
|
+
const depth = (entry.match(/\./g) || []).length;
|
|
659
|
+
if (this.getSuffixByDepth(name, depth) === entry) {
|
|
660
|
+
return true;
|
|
661
|
+
}
|
|
662
|
+
continue;
|
|
663
|
+
}
|
|
664
|
+
// MIME check
|
|
665
|
+
if (entry.endsWith('/*')) {
|
|
666
|
+
const prefix = entry.slice(0, entry.length - 1); // keep trailing slash
|
|
667
|
+
if (type.startsWith(prefix)) {
|
|
668
|
+
return true;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
else if (entry.includes('/') && type === entry) {
|
|
672
|
+
return true;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return false;
|
|
676
|
+
}
|
|
677
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileInputValidator, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
678
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.3", type: ClrFileInputValidator, isStandalone: false, selector: "input[type=\"file\"][clrFileInput]", inputs: { minFileSize: ["clrMinFileSize", "minFileSize"], maxFileSize: ["clrMaxFileSize", "maxFileSize"] }, providers: [{ provide: NG_VALIDATORS, useExisting: ClrFileInputValidator, multi: true }], ngImport: i0 }); }
|
|
679
|
+
}
|
|
680
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileInputValidator, decorators: [{
|
|
681
|
+
type: Directive,
|
|
682
|
+
args: [{
|
|
683
|
+
selector: 'input[type="file"][clrFileInput]',
|
|
684
|
+
providers: [{ provide: NG_VALIDATORS, useExisting: ClrFileInputValidator, multi: true }],
|
|
685
|
+
standalone: false,
|
|
686
|
+
}]
|
|
687
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { minFileSize: [{
|
|
688
|
+
type: Input,
|
|
689
|
+
args: ['clrMinFileSize']
|
|
690
|
+
}], maxFileSize: [{
|
|
691
|
+
type: Input,
|
|
692
|
+
args: ['clrMaxFileSize']
|
|
693
|
+
}] } });
|
|
694
|
+
|
|
695
|
+
/*
|
|
696
|
+
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
|
|
697
|
+
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
|
698
|
+
* This software is released under MIT license.
|
|
699
|
+
* The full license information can be found in LICENSE in the root directory of this project.
|
|
700
|
+
*/
|
|
701
|
+
|
|
702
|
+
/*
|
|
703
|
+
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
|
|
704
|
+
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
|
705
|
+
* This software is released under MIT license.
|
|
706
|
+
* The full license information can be found in LICENSE in the root directory of this project.
|
|
707
|
+
*/
|
|
708
|
+
class ClrFileInputValueAccessor {
|
|
709
|
+
constructor(elementRef) {
|
|
710
|
+
this.elementRef = elementRef;
|
|
711
|
+
this.onChange = (_value) => { };
|
|
712
|
+
this.onTouched = () => { };
|
|
713
|
+
}
|
|
714
|
+
writeValue(value) {
|
|
715
|
+
if (value !== undefined && value !== null && !(value instanceof FileList)) {
|
|
716
|
+
throw new Error('The value of a file input control must be a FileList.');
|
|
717
|
+
}
|
|
718
|
+
if (value) {
|
|
719
|
+
selectFiles(this.elementRef.nativeElement, value);
|
|
720
|
+
}
|
|
721
|
+
else if (this.elementRef.nativeElement.files.length) {
|
|
722
|
+
clearFiles(this.elementRef.nativeElement);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
registerOnChange(fn) {
|
|
726
|
+
this.onChange = fn;
|
|
727
|
+
}
|
|
728
|
+
registerOnTouched(fn) {
|
|
729
|
+
this.onTouched = fn;
|
|
730
|
+
}
|
|
731
|
+
setDisabledState(isDisabled) {
|
|
732
|
+
this.elementRef.nativeElement.disabled = isDisabled;
|
|
733
|
+
}
|
|
734
|
+
handleChange() {
|
|
735
|
+
this.onTouched();
|
|
736
|
+
this.onChange(this.elementRef.nativeElement.files);
|
|
737
|
+
}
|
|
738
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileInputValueAccessor, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
739
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.3", type: ClrFileInputValueAccessor, isStandalone: false, selector: "input[type=\"file\"][clrFileInput]", host: { listeners: { "change": "handleChange()" } }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: ClrFileInputValueAccessor, multi: true }], ngImport: i0 }); }
|
|
740
|
+
}
|
|
741
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileInputValueAccessor, decorators: [{
|
|
742
|
+
type: Directive,
|
|
743
|
+
args: [{
|
|
744
|
+
selector: 'input[type="file"][clrFileInput]',
|
|
745
|
+
providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: ClrFileInputValueAccessor, multi: true }],
|
|
746
|
+
standalone: false,
|
|
747
|
+
}]
|
|
748
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { handleChange: [{
|
|
749
|
+
type: HostListener,
|
|
750
|
+
args: ['change']
|
|
751
|
+
}] } });
|
|
752
|
+
|
|
753
|
+
/*
|
|
754
|
+
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
|
|
755
|
+
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
|
756
|
+
* This software is released under MIT license.
|
|
757
|
+
* The full license information can be found in LICENSE in the root directory of this project.
|
|
758
|
+
*/
|
|
759
|
+
class ClrFileInputModule {
|
|
760
|
+
constructor() {
|
|
761
|
+
ClarityIcons.addIcons(folderOpenIcon, successStandardIcon, errorStandardIcon);
|
|
762
|
+
}
|
|
763
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileInputModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
764
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: ClrFileInputModule, declarations: [ClrFileInput,
|
|
765
|
+
ClrFileInputContainer,
|
|
766
|
+
ClrFileInputValidator,
|
|
767
|
+
ClrFileInputValueAccessor,
|
|
768
|
+
ClrFileList,
|
|
769
|
+
ClrFileMessagesTemplate,
|
|
770
|
+
ClrFileInfo,
|
|
771
|
+
ClrFileSuccess,
|
|
772
|
+
ClrFileError], imports: [CommonModule, ClrIcon, ClrCommonFormsModule], exports: [ClrCommonFormsModule,
|
|
773
|
+
ClrFileInput,
|
|
774
|
+
ClrFileInputContainer,
|
|
775
|
+
ClrFileInputValidator,
|
|
776
|
+
ClrFileInputValueAccessor,
|
|
777
|
+
ClrFileList,
|
|
778
|
+
ClrFileMessagesTemplate,
|
|
779
|
+
ClrFileInfo,
|
|
780
|
+
ClrFileSuccess,
|
|
781
|
+
ClrFileError] }); }
|
|
782
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileInputModule, imports: [CommonModule, ClrIcon, ClrCommonFormsModule, ClrCommonFormsModule] }); }
|
|
783
|
+
}
|
|
784
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrFileInputModule, decorators: [{
|
|
785
|
+
type: NgModule,
|
|
786
|
+
args: [{
|
|
787
|
+
imports: [CommonModule, ClrIcon, ClrCommonFormsModule],
|
|
788
|
+
declarations: [
|
|
789
|
+
ClrFileInput,
|
|
790
|
+
ClrFileInputContainer,
|
|
791
|
+
ClrFileInputValidator,
|
|
792
|
+
ClrFileInputValueAccessor,
|
|
793
|
+
ClrFileList,
|
|
794
|
+
ClrFileMessagesTemplate,
|
|
795
|
+
ClrFileInfo,
|
|
796
|
+
ClrFileSuccess,
|
|
797
|
+
ClrFileError,
|
|
798
|
+
],
|
|
799
|
+
exports: [
|
|
800
|
+
ClrCommonFormsModule,
|
|
801
|
+
ClrFileInput,
|
|
802
|
+
ClrFileInputContainer,
|
|
803
|
+
ClrFileInputValidator,
|
|
804
|
+
ClrFileInputValueAccessor,
|
|
805
|
+
ClrFileList,
|
|
806
|
+
ClrFileMessagesTemplate,
|
|
807
|
+
ClrFileInfo,
|
|
808
|
+
ClrFileSuccess,
|
|
809
|
+
ClrFileError,
|
|
810
|
+
],
|
|
811
|
+
}]
|
|
812
|
+
}], ctorParameters: () => [] });
|
|
813
|
+
|
|
814
|
+
/*
|
|
815
|
+
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
|
|
816
|
+
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
|
817
|
+
* This software is released under MIT license.
|
|
818
|
+
* The full license information can be found in LICENSE in the root directory of this project.
|
|
819
|
+
*/
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Generated bundle index. Do not edit.
|
|
823
|
+
*/
|
|
824
|
+
|
|
825
|
+
export { CLR_FILE_MESSAGES_TEMPLATE_CONTEXT, ClrFileError, ClrFileInfo, ClrFileInput, ClrFileInputContainer, ClrFileInputModule, ClrFileInputValidator, ClrFileInputValueAccessor, ClrFileList, ClrFileMessagesTemplate, ClrFileSuccess, buildFileList, clearFiles, selectFiles };
|
|
826
|
+
//# sourceMappingURL=clr-angular-forms-file-input.mjs.map
|