codexly-ui 0.3.0 → 0.4.0
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/codexly-ui.mjs +199 -56
- package/fesm2022/codexly-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/codexly-ui.d.ts +41 -7
package/fesm2022/codexly-ui.mjs
CHANGED
|
@@ -4850,6 +4850,46 @@ const UPLOAD_SIZE_MAP = {
|
|
|
4850
4850
|
md: { zone: 'py-9 px-8 gap-3', icon: 'lg', title: 'text-sm', hint: 'text-xs' },
|
|
4851
4851
|
lg: { zone: 'py-12 px-10 gap-4', icon: 'xl', title: 'text-base', hint: 'text-sm' },
|
|
4852
4852
|
};
|
|
4853
|
+
const FILE_TYPE_BY_MIME = {
|
|
4854
|
+
'application/pdf': { icon: 'picture_as_pdf', color: 'red' },
|
|
4855
|
+
'application/msword': { icon: 'description', color: 'blue' },
|
|
4856
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': { icon: 'description', color: 'blue' },
|
|
4857
|
+
'application/vnd.ms-excel': { icon: 'table_chart', color: 'green' },
|
|
4858
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': { icon: 'table_chart', color: 'green' },
|
|
4859
|
+
'text/csv': { icon: 'table_chart', color: 'green' },
|
|
4860
|
+
'application/vnd.ms-powerpoint': { icon: 'slideshow', color: 'orange' },
|
|
4861
|
+
'application/vnd.openxmlformats-officedocument.presentationml.presentation': { icon: 'slideshow', color: 'orange' },
|
|
4862
|
+
'text/plain': { icon: 'article', color: 'slate' },
|
|
4863
|
+
'application/zip': { icon: 'folder_zip', color: 'amber' },
|
|
4864
|
+
'application/x-zip-compressed': { icon: 'folder_zip', color: 'amber' },
|
|
4865
|
+
'application/x-rar-compressed': { icon: 'folder_zip', color: 'amber' },
|
|
4866
|
+
'application/x-7z-compressed': { icon: 'folder_zip', color: 'amber' },
|
|
4867
|
+
};
|
|
4868
|
+
const FILE_TYPE_BY_EXTENSION = {
|
|
4869
|
+
pdf: { icon: 'picture_as_pdf', color: 'red' },
|
|
4870
|
+
doc: { icon: 'description', color: 'blue' },
|
|
4871
|
+
docx: { icon: 'description', color: 'blue' },
|
|
4872
|
+
xls: { icon: 'table_chart', color: 'green' },
|
|
4873
|
+
xlsx: { icon: 'table_chart', color: 'green' },
|
|
4874
|
+
csv: { icon: 'table_chart', color: 'green' },
|
|
4875
|
+
ppt: { icon: 'slideshow', color: 'orange' },
|
|
4876
|
+
pptx: { icon: 'slideshow', color: 'orange' },
|
|
4877
|
+
txt: { icon: 'article', color: 'slate' },
|
|
4878
|
+
zip: { icon: 'folder_zip', color: 'amber' },
|
|
4879
|
+
rar: { icon: 'folder_zip', color: 'amber' },
|
|
4880
|
+
'7z': { icon: 'folder_zip', color: 'amber' },
|
|
4881
|
+
};
|
|
4882
|
+
const FILE_TYPE_DEFAULT = { icon: 'draft', color: 'slate' };
|
|
4883
|
+
function resolveFileTypeVisual(name, mimeType) {
|
|
4884
|
+
if (mimeType?.startsWith('video/'))
|
|
4885
|
+
return { icon: 'movie', color: 'purple' };
|
|
4886
|
+
if (mimeType?.startsWith('audio/'))
|
|
4887
|
+
return { icon: 'audiotrack', color: 'pink' };
|
|
4888
|
+
if (mimeType && FILE_TYPE_BY_MIME[mimeType])
|
|
4889
|
+
return FILE_TYPE_BY_MIME[mimeType];
|
|
4890
|
+
const ext = name.split('.').pop()?.toLowerCase() ?? '';
|
|
4891
|
+
return FILE_TYPE_BY_EXTENSION[ext] ?? FILE_TYPE_DEFAULT;
|
|
4892
|
+
}
|
|
4853
4893
|
|
|
4854
4894
|
class ClxUploadComponent {
|
|
4855
4895
|
_themeSvc = inject(ClxThemeService);
|
|
@@ -4863,13 +4903,20 @@ class ClxUploadComponent {
|
|
|
4863
4903
|
size = input(undefined, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
4864
4904
|
_size = computed(() => (this.size() ?? this._themeSvc.config().defaultSize), ...(ngDevMode ? [{ debugName: "_size" }] : /* istanbul ignore next */ []));
|
|
4865
4905
|
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
4906
|
+
/** Already-persisted files (e.g. previously uploaded to the backend). Rendered in the same
|
|
4907
|
+
* preview grid as newly-selected local files. The component never deletes these itself —
|
|
4908
|
+
* removing one only emits `existingFileRemove`, letting the caller decide (e.g. call the API). */
|
|
4909
|
+
existingFiles = input([], ...(ngDevMode ? [{ debugName: "existingFiles" }] : /* istanbul ignore next */ []));
|
|
4866
4910
|
// ── Outputs ────────────────────────────────────────────────────────────────
|
|
4867
4911
|
onUploadError = output();
|
|
4868
4912
|
onUploadSuccess = output();
|
|
4913
|
+
existingFileRemove = output();
|
|
4869
4914
|
// ── Internal state ─────────────────────────────────────────────────────────
|
|
4870
4915
|
_files = signal([], ...(ngDevMode ? [{ debugName: "_files" }] : /* istanbul ignore next */ []));
|
|
4871
4916
|
_isDragging = signal(false, ...(ngDevMode ? [{ debugName: "_isDragging" }] : /* istanbul ignore next */ []));
|
|
4872
4917
|
_errorKey = signal(null, ...(ngDevMode ? [{ debugName: "_errorKey" }] : /* istanbul ignore next */ []));
|
|
4918
|
+
/** File → object URL cache, so we don't re-create (and leak) a new URL on every re-render. */
|
|
4919
|
+
_objectUrls = new Map();
|
|
4873
4920
|
// ── CVA ────────────────────────────────────────────────────────────────────
|
|
4874
4921
|
_ngControl = inject(NgControl, { optional: true, self: true });
|
|
4875
4922
|
_cvaDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_cvaDisabled" }] : /* istanbul ignore next */ []));
|
|
@@ -4886,11 +4933,37 @@ class ClxUploadComponent {
|
|
|
4886
4933
|
_disabled = computed(() => this._cvaDisabled() || this.disabled(), ...(ngDevMode ? [{ debugName: "_disabled" }] : /* istanbul ignore next */ []));
|
|
4887
4934
|
_sizeConfig = computed(() => UPLOAD_SIZE_MAP[this._size()], ...(ngDevMode ? [{ debugName: "_sizeConfig" }] : /* istanbul ignore next */ []));
|
|
4888
4935
|
_isError = computed(() => this._errorKey() !== null, ...(ngDevMode ? [{ debugName: "_isError" }] : /* istanbul ignore next */ []));
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4936
|
+
_thumbClass = computed(() => `relative group aspect-square ${resolveRadius(this._themeSvc.config().borderRadius)} overflow-hidden border border-clx-border bg-clx-surface-2`, ...(ngDevMode ? [{ debugName: "_thumbClass" }] : /* istanbul ignore next */ []));
|
|
4937
|
+
_fileCardClass = computed(() => `relative group aspect-square ${resolveRadius(this._themeSvc.config().borderRadius)} border border-clx-border bg-clx-surface-2 flex flex-col items-center justify-center gap-1 p-2`, ...(ngDevMode ? [{ debugName: "_fileCardClass" }] : /* istanbul ignore next */ []));
|
|
4938
|
+
_previewItems = computed(() => {
|
|
4939
|
+
const existing = this.existingFiles().map(f => ({
|
|
4940
|
+
kind: 'existing',
|
|
4941
|
+
key: `existing:${f.id}`,
|
|
4942
|
+
name: f.name ?? '',
|
|
4943
|
+
isImage: true,
|
|
4944
|
+
thumbUrl: f.url,
|
|
4945
|
+
fileIcon: '',
|
|
4946
|
+
fileColor: '',
|
|
4947
|
+
status: f.status,
|
|
4948
|
+
existing: f,
|
|
4949
|
+
}));
|
|
4950
|
+
const fresh = this._files().map(file => {
|
|
4951
|
+
const isImage = file.type.startsWith('image/');
|
|
4952
|
+
const visual = isImage ? null : resolveFileTypeVisual(file.name, file.type);
|
|
4953
|
+
return {
|
|
4954
|
+
kind: 'new',
|
|
4955
|
+
key: `new:${file.name}:${file.size}:${file.lastModified}`,
|
|
4956
|
+
name: file.name,
|
|
4957
|
+
size: file.size,
|
|
4958
|
+
isImage,
|
|
4959
|
+
thumbUrl: isImage ? this._getObjectUrl(file) : null,
|
|
4960
|
+
fileIcon: visual?.icon ?? '',
|
|
4961
|
+
fileColor: visual?.color ?? '',
|
|
4962
|
+
file,
|
|
4963
|
+
};
|
|
4964
|
+
});
|
|
4965
|
+
return [...existing, ...fresh];
|
|
4966
|
+
}, ...(ngDevMode ? [{ debugName: "_previewItems" }] : /* istanbul ignore next */ []));
|
|
4894
4967
|
_zoneClass = computed(() => {
|
|
4895
4968
|
const base = [
|
|
4896
4969
|
'flex flex-col items-center justify-center text-center',
|
|
@@ -4957,15 +5030,13 @@ class ClxUploadComponent {
|
|
|
4957
5030
|
// ── CVA implementation ─────────────────────────────────────────────────────
|
|
4958
5031
|
writeValue(value) {
|
|
4959
5032
|
this._cvaConnected = true;
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
}
|
|
4966
|
-
else {
|
|
4967
|
-
this._files.set([value]);
|
|
5033
|
+
const next = !value ? [] : Array.isArray(value) ? value : [value];
|
|
5034
|
+
const nextSet = new Set(next);
|
|
5035
|
+
for (const file of this._files()) {
|
|
5036
|
+
if (!nextSet.has(file))
|
|
5037
|
+
this._releaseObjectUrl(file);
|
|
4968
5038
|
}
|
|
5039
|
+
this._files.set(next);
|
|
4969
5040
|
}
|
|
4970
5041
|
registerOnChange(fn) {
|
|
4971
5042
|
this._onChange = fn;
|
|
@@ -5004,13 +5075,39 @@ class ClxUploadComponent {
|
|
|
5004
5075
|
if (files?.length)
|
|
5005
5076
|
this._addFiles(files);
|
|
5006
5077
|
}
|
|
5007
|
-
|
|
5078
|
+
_removeItem(item) {
|
|
5079
|
+
if (item.kind === 'existing') {
|
|
5080
|
+
this.existingFileRemove.emit(item.existing.id);
|
|
5081
|
+
return;
|
|
5082
|
+
}
|
|
5083
|
+
const file = item.file;
|
|
5008
5084
|
this._files.update(current => current.filter(f => f !== file));
|
|
5085
|
+
this._releaseObjectUrl(file);
|
|
5009
5086
|
this._errorKey.set(null);
|
|
5010
5087
|
this._ngControl?.control?.setErrors(null);
|
|
5011
5088
|
this._emit();
|
|
5012
5089
|
this._onTouched();
|
|
5013
5090
|
}
|
|
5091
|
+
_getObjectUrl(file) {
|
|
5092
|
+
let url = this._objectUrls.get(file);
|
|
5093
|
+
if (!url) {
|
|
5094
|
+
url = URL.createObjectURL(file);
|
|
5095
|
+
this._objectUrls.set(file, url);
|
|
5096
|
+
}
|
|
5097
|
+
return url;
|
|
5098
|
+
}
|
|
5099
|
+
_releaseObjectUrl(file) {
|
|
5100
|
+
const url = this._objectUrls.get(file);
|
|
5101
|
+
if (url) {
|
|
5102
|
+
URL.revokeObjectURL(url);
|
|
5103
|
+
this._objectUrls.delete(file);
|
|
5104
|
+
}
|
|
5105
|
+
}
|
|
5106
|
+
ngOnDestroy() {
|
|
5107
|
+
for (const url of this._objectUrls.values())
|
|
5108
|
+
URL.revokeObjectURL(url);
|
|
5109
|
+
this._objectUrls.clear();
|
|
5110
|
+
}
|
|
5014
5111
|
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
5015
5112
|
_addFiles(rawFiles) {
|
|
5016
5113
|
const files = Array.from(rawFiles);
|
|
@@ -5083,7 +5180,7 @@ class ClxUploadComponent {
|
|
|
5083
5180
|
return `${(bytes / 1_048_576).toFixed(1)} MB`;
|
|
5084
5181
|
}
|
|
5085
5182
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5086
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxUploadComponent, isStandalone: true, selector: "clx-upload", inputs: { multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onUploadError: "onUploadError", onUploadSuccess: "onUploadSuccess" }, host: { classAttribute: "block w-full" }, viewQueries: [{ propertyName: "_fileInput", first: true, predicate: ["fileInput"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
5183
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxUploadComponent, isStandalone: true, selector: "clx-upload", inputs: { multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, existingFiles: { classPropertyName: "existingFiles", publicName: "existingFiles", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onUploadError: "onUploadError", onUploadSuccess: "onUploadSuccess", existingFileRemove: "existingFileRemove" }, host: { classAttribute: "block w-full" }, viewQueries: [{ propertyName: "_fileInput", first: true, predicate: ["fileInput"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
5087
5184
|
<!-- Hidden file input -->
|
|
5088
5185
|
<input
|
|
5089
5186
|
#fileInput
|
|
@@ -5127,25 +5224,48 @@ class ClxUploadComponent {
|
|
|
5127
5224
|
</div>
|
|
5128
5225
|
</div>
|
|
5129
5226
|
|
|
5130
|
-
<!-- ──
|
|
5131
|
-
@if (
|
|
5132
|
-
<div class="mt-3
|
|
5133
|
-
@for (
|
|
5134
|
-
|
|
5135
|
-
<
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5227
|
+
<!-- ── Preview list (existing + new files, images get a real thumbnail) ───── -->
|
|
5228
|
+
@if (_previewItems().length) {
|
|
5229
|
+
<div class="mt-3 grid grid-cols-3 sm:grid-cols-4 gap-2">
|
|
5230
|
+
@for (item of _previewItems(); track item.key) {
|
|
5231
|
+
@if (item.isImage) {
|
|
5232
|
+
<div [class]="_thumbClass()">
|
|
5233
|
+
<img [src]="item.thumbUrl" [alt]="item.name" loading="lazy" class="w-full h-full object-cover" />
|
|
5234
|
+
|
|
5235
|
+
@if (item.status === 'PENDING' || item.status === 'PROCESSING') {
|
|
5236
|
+
<div class="absolute inset-0 bg-black/50 flex flex-col items-center justify-center gap-1">
|
|
5237
|
+
<span clx-icon name="progress_activity" size="md" class="text-white animate-spin"></span>
|
|
5238
|
+
</div>
|
|
5239
|
+
} @else if (item.status === 'FAILED') {
|
|
5240
|
+
<div class="absolute inset-0 bg-red-500/40 flex items-center justify-center">
|
|
5241
|
+
<span clx-icon name="error" size="md" class="text-white"></span>
|
|
5242
|
+
</div>
|
|
5243
|
+
}
|
|
5244
|
+
|
|
5245
|
+
<button
|
|
5246
|
+
type="button"
|
|
5247
|
+
class="absolute top-1 right-1 opacity-0 group-hover:opacity-100 hover:opacity-100 transition-opacity bg-black/60 hover:bg-red-600 text-white rounded-full w-6 h-6 flex items-center justify-center"
|
|
5248
|
+
[disabled]="_disabled()"
|
|
5249
|
+
(click)="_removeItem(item); $event.stopPropagation()">
|
|
5250
|
+
<span clx-icon name="close" size="xs"></span>
|
|
5251
|
+
</button>
|
|
5252
|
+
</div>
|
|
5253
|
+
} @else {
|
|
5254
|
+
<div [class]="_fileCardClass()">
|
|
5255
|
+
<span clx-icon [name]="item.fileIcon" size="lg" [class]="'text-' + item.fileColor + '-500'"></span>
|
|
5256
|
+
<span class="text-xs text-clx-text-label font-medium text-center truncate w-full px-1">{{ item.name }}</span>
|
|
5257
|
+
@if (item.size !== undefined) {
|
|
5258
|
+
<span class="text-[11px] text-clx-text-muted">{{ _formatSize(item.size) }}</span>
|
|
5259
|
+
}
|
|
5260
|
+
<button
|
|
5261
|
+
type="button"
|
|
5262
|
+
class="absolute top-1 right-1 opacity-0 group-hover:opacity-100 hover:opacity-100 transition-opacity bg-black/60 hover:bg-red-600 text-white rounded-full w-6 h-6 flex items-center justify-center"
|
|
5263
|
+
[disabled]="_disabled()"
|
|
5264
|
+
(click)="_removeItem(item); $event.stopPropagation()">
|
|
5265
|
+
<span clx-icon name="close" size="xs"></span>
|
|
5266
|
+
</button>
|
|
5267
|
+
</div>
|
|
5268
|
+
}
|
|
5149
5269
|
}
|
|
5150
5270
|
</div>
|
|
5151
5271
|
}
|
|
@@ -5157,14 +5277,14 @@ class ClxUploadComponent {
|
|
|
5157
5277
|
{{ _errorMessage() }}
|
|
5158
5278
|
</p>
|
|
5159
5279
|
}
|
|
5160
|
-
`, isInline: true, dependencies: [{ kind: "component", type:
|
|
5280
|
+
`, isInline: true, dependencies: [{ kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
5161
5281
|
}
|
|
5162
5282
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxUploadComponent, decorators: [{
|
|
5163
5283
|
type: Component,
|
|
5164
5284
|
args: [{
|
|
5165
5285
|
selector: 'clx-upload',
|
|
5166
5286
|
standalone: true,
|
|
5167
|
-
imports: [
|
|
5287
|
+
imports: [ClxIconComponent],
|
|
5168
5288
|
template: `
|
|
5169
5289
|
<!-- Hidden file input -->
|
|
5170
5290
|
<input
|
|
@@ -5209,25 +5329,48 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
|
|
|
5209
5329
|
</div>
|
|
5210
5330
|
</div>
|
|
5211
5331
|
|
|
5212
|
-
<!-- ──
|
|
5213
|
-
@if (
|
|
5214
|
-
<div class="mt-3
|
|
5215
|
-
@for (
|
|
5216
|
-
|
|
5217
|
-
<
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5332
|
+
<!-- ── Preview list (existing + new files, images get a real thumbnail) ───── -->
|
|
5333
|
+
@if (_previewItems().length) {
|
|
5334
|
+
<div class="mt-3 grid grid-cols-3 sm:grid-cols-4 gap-2">
|
|
5335
|
+
@for (item of _previewItems(); track item.key) {
|
|
5336
|
+
@if (item.isImage) {
|
|
5337
|
+
<div [class]="_thumbClass()">
|
|
5338
|
+
<img [src]="item.thumbUrl" [alt]="item.name" loading="lazy" class="w-full h-full object-cover" />
|
|
5339
|
+
|
|
5340
|
+
@if (item.status === 'PENDING' || item.status === 'PROCESSING') {
|
|
5341
|
+
<div class="absolute inset-0 bg-black/50 flex flex-col items-center justify-center gap-1">
|
|
5342
|
+
<span clx-icon name="progress_activity" size="md" class="text-white animate-spin"></span>
|
|
5343
|
+
</div>
|
|
5344
|
+
} @else if (item.status === 'FAILED') {
|
|
5345
|
+
<div class="absolute inset-0 bg-red-500/40 flex items-center justify-center">
|
|
5346
|
+
<span clx-icon name="error" size="md" class="text-white"></span>
|
|
5347
|
+
</div>
|
|
5348
|
+
}
|
|
5349
|
+
|
|
5350
|
+
<button
|
|
5351
|
+
type="button"
|
|
5352
|
+
class="absolute top-1 right-1 opacity-0 group-hover:opacity-100 hover:opacity-100 transition-opacity bg-black/60 hover:bg-red-600 text-white rounded-full w-6 h-6 flex items-center justify-center"
|
|
5353
|
+
[disabled]="_disabled()"
|
|
5354
|
+
(click)="_removeItem(item); $event.stopPropagation()">
|
|
5355
|
+
<span clx-icon name="close" size="xs"></span>
|
|
5356
|
+
</button>
|
|
5357
|
+
</div>
|
|
5358
|
+
} @else {
|
|
5359
|
+
<div [class]="_fileCardClass()">
|
|
5360
|
+
<span clx-icon [name]="item.fileIcon" size="lg" [class]="'text-' + item.fileColor + '-500'"></span>
|
|
5361
|
+
<span class="text-xs text-clx-text-label font-medium text-center truncate w-full px-1">{{ item.name }}</span>
|
|
5362
|
+
@if (item.size !== undefined) {
|
|
5363
|
+
<span class="text-[11px] text-clx-text-muted">{{ _formatSize(item.size) }}</span>
|
|
5364
|
+
}
|
|
5365
|
+
<button
|
|
5366
|
+
type="button"
|
|
5367
|
+
class="absolute top-1 right-1 opacity-0 group-hover:opacity-100 hover:opacity-100 transition-opacity bg-black/60 hover:bg-red-600 text-white rounded-full w-6 h-6 flex items-center justify-center"
|
|
5368
|
+
[disabled]="_disabled()"
|
|
5369
|
+
(click)="_removeItem(item); $event.stopPropagation()">
|
|
5370
|
+
<span clx-icon name="close" size="xs"></span>
|
|
5371
|
+
</button>
|
|
5372
|
+
</div>
|
|
5373
|
+
}
|
|
5231
5374
|
}
|
|
5232
5375
|
</div>
|
|
5233
5376
|
}
|
|
@@ -5246,7 +5389,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
|
|
|
5246
5389
|
class: 'block w-full',
|
|
5247
5390
|
},
|
|
5248
5391
|
}]
|
|
5249
|
-
}], ctorParameters: () => [], propDecorators: { multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], onUploadError: [{ type: i0.Output, args: ["onUploadError"] }], onUploadSuccess: [{ type: i0.Output, args: ["onUploadSuccess"] }], _fileInput: [{ type: i0.ViewChild, args: ['fileInput', { isSignal: true }] }] } });
|
|
5392
|
+
}], ctorParameters: () => [], propDecorators: { multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], existingFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "existingFiles", required: false }] }], onUploadError: [{ type: i0.Output, args: ["onUploadError"] }], onUploadSuccess: [{ type: i0.Output, args: ["onUploadSuccess"] }], existingFileRemove: [{ type: i0.Output, args: ["existingFileRemove"] }], _fileInput: [{ type: i0.ViewChild, args: ['fileInput', { isSignal: true }] }] } });
|
|
5250
5393
|
|
|
5251
5394
|
const COLOR_PICKER_SIZE_MAP = {
|
|
5252
5395
|
sm: { minH: 'min-h-8', text: 'text-sm', label: 'text-xs font-medium', hint: 'text-xs', px: 'px-2.5', swatchSz: 'w-4 h-4', btnSize: 'xs' },
|