codexly-ui 0.4.9 → 0.5.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/codexly-ui.mjs +102 -30
- package/fesm2022/codexly-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/codexly-ui.d.ts +33 -7
package/fesm2022/codexly-ui.mjs
CHANGED
|
@@ -2321,6 +2321,11 @@ class ClxTooltipDirective {
|
|
|
2321
2321
|
host.addEventListener('mouseleave', () => this._scheduleHide(), { signal });
|
|
2322
2322
|
host.addEventListener('focus', () => this._scheduleShow(), { signal });
|
|
2323
2323
|
host.addEventListener('blur', () => this._scheduleHide(), { signal });
|
|
2324
|
+
// Touch devices fire 'mouseenter'/'focus' on tap but never a real
|
|
2325
|
+
// 'mouseleave' — hide immediately once the tap completes instead of
|
|
2326
|
+
// leaving the bubble stuck until the next unrelated touch.
|
|
2327
|
+
host.addEventListener('touchend', () => this._hide(), { signal });
|
|
2328
|
+
host.addEventListener('touchcancel', () => this._hide(), { signal });
|
|
2324
2329
|
this._destroyRef.onDestroy(() => {
|
|
2325
2330
|
this._destroyed = true;
|
|
2326
2331
|
this._abort.abort();
|
|
@@ -4920,6 +4925,9 @@ function resolveFileTypeVisual(name, mimeType) {
|
|
|
4920
4925
|
return FILE_TYPE_BY_EXTENSION[ext] ?? FILE_TYPE_DEFAULT;
|
|
4921
4926
|
}
|
|
4922
4927
|
|
|
4928
|
+
const DEFAULT_PRIMARY_ACTION = () => ({
|
|
4929
|
+
icon: 'close', color: 'red', tooltip: 'Eliminar',
|
|
4930
|
+
});
|
|
4923
4931
|
class ClxUploadComponent {
|
|
4924
4932
|
_themeSvc = inject(ClxThemeService);
|
|
4925
4933
|
// ── Inputs ─────────────────────────────────────────────────────────────────
|
|
@@ -4936,10 +4944,18 @@ class ClxUploadComponent {
|
|
|
4936
4944
|
* preview grid as newly-selected local files. The component never deletes these itself —
|
|
4937
4945
|
* removing one only emits `existingFileRemove`, letting the caller decide (e.g. call the API). */
|
|
4938
4946
|
existingFiles = input([], ...(ngDevMode ? [{ debugName: "existingFiles" }] : /* istanbul ignore next */ []));
|
|
4947
|
+
/** Resolves the badge button shown top-right on each thumbnail. Defaults to a red "Eliminar"
|
|
4948
|
+
* button wired to the built-in remove behavior. Return `null` for an item to hide it. */
|
|
4949
|
+
primaryAction = input(DEFAULT_PRIMARY_ACTION, ...(ngDevMode ? [{ debugName: "primaryAction" }] : /* istanbul ignore next */ []));
|
|
4950
|
+
/** Resolves an optional second badge button (bottom-right on each thumbnail). Hidden by
|
|
4951
|
+
* default — the caller owns what clicking it means (e.g. opening a settings modal); this
|
|
4952
|
+
* component only reports which item was clicked via `secondaryActionClick`. */
|
|
4953
|
+
secondaryAction = input(null, ...(ngDevMode ? [{ debugName: "secondaryAction" }] : /* istanbul ignore next */ []));
|
|
4939
4954
|
// ── Outputs ────────────────────────────────────────────────────────────────
|
|
4940
4955
|
onUploadError = output();
|
|
4941
4956
|
onUploadSuccess = output();
|
|
4942
4957
|
existingFileRemove = output();
|
|
4958
|
+
secondaryActionClick = output();
|
|
4943
4959
|
// ── Internal state ─────────────────────────────────────────────────────────
|
|
4944
4960
|
_files = signal([], ...(ngDevMode ? [{ debugName: "_files" }] : /* istanbul ignore next */ []));
|
|
4945
4961
|
_isDragging = signal(false, ...(ngDevMode ? [{ debugName: "_isDragging" }] : /* istanbul ignore next */ []));
|
|
@@ -5104,6 +5120,18 @@ class ClxUploadComponent {
|
|
|
5104
5120
|
if (files?.length)
|
|
5105
5121
|
this._addFiles(files);
|
|
5106
5122
|
}
|
|
5123
|
+
_resolvePrimaryAction(item) {
|
|
5124
|
+
return this.primaryAction()(item) ?? null;
|
|
5125
|
+
}
|
|
5126
|
+
_resolveSecondaryAction(item) {
|
|
5127
|
+
const resolver = this.secondaryAction();
|
|
5128
|
+
return resolver ? (resolver(item) ?? null) : null;
|
|
5129
|
+
}
|
|
5130
|
+
/** Built-in behavior for the default primary action (remove). Callers who override
|
|
5131
|
+
* `primaryAction` only for its visuals still get this same removal behavior. */
|
|
5132
|
+
_onPrimaryAction(item) {
|
|
5133
|
+
this._removeItem(item);
|
|
5134
|
+
}
|
|
5107
5135
|
_removeItem(item) {
|
|
5108
5136
|
if (item.kind === 'existing') {
|
|
5109
5137
|
this.existingFileRemove.emit(item.existing.id);
|
|
@@ -5217,7 +5245,7 @@ class ClxUploadComponent {
|
|
|
5217
5245
|
return `${(bytes / 1_048_576).toFixed(1)} MB`;
|
|
5218
5246
|
}
|
|
5219
5247
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5220
|
-
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: `
|
|
5248
|
+
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 }, primaryAction: { classPropertyName: "primaryAction", publicName: "primaryAction", isSignal: true, isRequired: false, transformFunction: null }, secondaryAction: { classPropertyName: "secondaryAction", publicName: "secondaryAction", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onUploadError: "onUploadError", onUploadSuccess: "onUploadSuccess", existingFileRemove: "existingFileRemove", secondaryActionClick: "secondaryActionClick" }, host: { classAttribute: "block w-full" }, viewQueries: [{ propertyName: "_fileInput", first: true, predicate: ["fileInput"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
5221
5249
|
<!-- Hidden file input -->
|
|
5222
5250
|
<input
|
|
5223
5251
|
#fileInput
|
|
@@ -5286,19 +5314,41 @@ class ClxUploadComponent {
|
|
|
5286
5314
|
}
|
|
5287
5315
|
</div>
|
|
5288
5316
|
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5317
|
+
@let primaryAction = _resolvePrimaryAction(item);
|
|
5318
|
+
@if (primaryAction) {
|
|
5319
|
+
<button
|
|
5320
|
+
clx-button
|
|
5321
|
+
type="button"
|
|
5322
|
+
variant="solid"
|
|
5323
|
+
[color]="primaryAction.color ?? 'red'"
|
|
5324
|
+
shape="circle"
|
|
5325
|
+
size="xxs"
|
|
5326
|
+
[icon]="primaryAction.icon"
|
|
5327
|
+
[iconOnly]="true"
|
|
5328
|
+
[clxTooltip]="primaryAction.tooltip ?? ''"
|
|
5329
|
+
class="absolute top-0 right-0 -translate-y-1/2 translate-x-1/2 shadow-md z-10"
|
|
5330
|
+
[disabled]="_disabled()"
|
|
5331
|
+
(click)="_onPrimaryAction(item); $event.stopPropagation()">
|
|
5332
|
+
</button>
|
|
5333
|
+
}
|
|
5334
|
+
|
|
5335
|
+
@let secondaryAction = _resolveSecondaryAction(item);
|
|
5336
|
+
@if (secondaryAction) {
|
|
5337
|
+
<button
|
|
5338
|
+
clx-button
|
|
5339
|
+
type="button"
|
|
5340
|
+
variant="solid"
|
|
5341
|
+
[color]="secondaryAction.color ?? 'slate'"
|
|
5342
|
+
shape="circle"
|
|
5343
|
+
size="xxs"
|
|
5344
|
+
[icon]="secondaryAction.icon"
|
|
5345
|
+
[iconOnly]="true"
|
|
5346
|
+
[clxTooltip]="secondaryAction.tooltip ?? ''"
|
|
5347
|
+
class="absolute bottom-0 right-0 translate-y-1/2 translate-x-1/2 shadow-md z-10"
|
|
5348
|
+
[disabled]="_disabled()"
|
|
5349
|
+
(click)="secondaryActionClick.emit(item); $event.stopPropagation()">
|
|
5350
|
+
</button>
|
|
5351
|
+
}
|
|
5302
5352
|
|
|
5303
5353
|
<div class="px-1.5 py-1 w-full min-w-0">
|
|
5304
5354
|
<p class="text-[11px] leading-tight text-clx-text-label font-medium truncate" [title]="item.name">{{ item.name }}</p>
|
|
@@ -5318,14 +5368,14 @@ class ClxUploadComponent {
|
|
|
5318
5368
|
{{ _errorMessage() }}
|
|
5319
5369
|
</p>
|
|
5320
5370
|
}
|
|
5321
|
-
`, isInline: true, dependencies: [{ kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxButtonComponent, selector: "button[clx-button], a[clx-button]", inputs: ["variant", "color", "size", "shape", "loading", "disabled", "block", "icon", "iconPosition", "iconOnly", "badge", "badgeColor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
5371
|
+
`, isInline: true, dependencies: [{ kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxButtonComponent, selector: "button[clx-button], a[clx-button]", inputs: ["variant", "color", "size", "shape", "loading", "disabled", "block", "icon", "iconPosition", "iconOnly", "badge", "badgeColor"] }, { kind: "directive", type: ClxTooltipDirective, selector: "[clxTooltip]", inputs: ["clxTooltip", "clxTooltipPosition", "clxTooltipColor", "clxTooltipSize", "clxTooltipDelay"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
5322
5372
|
}
|
|
5323
5373
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxUploadComponent, decorators: [{
|
|
5324
5374
|
type: Component,
|
|
5325
5375
|
args: [{
|
|
5326
5376
|
selector: 'clx-upload',
|
|
5327
5377
|
standalone: true,
|
|
5328
|
-
imports: [ClxIconComponent, ClxButtonComponent],
|
|
5378
|
+
imports: [ClxIconComponent, ClxButtonComponent, ClxTooltipDirective],
|
|
5329
5379
|
template: `
|
|
5330
5380
|
<!-- Hidden file input -->
|
|
5331
5381
|
<input
|
|
@@ -5395,19 +5445,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
|
|
|
5395
5445
|
}
|
|
5396
5446
|
</div>
|
|
5397
5447
|
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5448
|
+
@let primaryAction = _resolvePrimaryAction(item);
|
|
5449
|
+
@if (primaryAction) {
|
|
5450
|
+
<button
|
|
5451
|
+
clx-button
|
|
5452
|
+
type="button"
|
|
5453
|
+
variant="solid"
|
|
5454
|
+
[color]="primaryAction.color ?? 'red'"
|
|
5455
|
+
shape="circle"
|
|
5456
|
+
size="xxs"
|
|
5457
|
+
[icon]="primaryAction.icon"
|
|
5458
|
+
[iconOnly]="true"
|
|
5459
|
+
[clxTooltip]="primaryAction.tooltip ?? ''"
|
|
5460
|
+
class="absolute top-0 right-0 -translate-y-1/2 translate-x-1/2 shadow-md z-10"
|
|
5461
|
+
[disabled]="_disabled()"
|
|
5462
|
+
(click)="_onPrimaryAction(item); $event.stopPropagation()">
|
|
5463
|
+
</button>
|
|
5464
|
+
}
|
|
5465
|
+
|
|
5466
|
+
@let secondaryAction = _resolveSecondaryAction(item);
|
|
5467
|
+
@if (secondaryAction) {
|
|
5468
|
+
<button
|
|
5469
|
+
clx-button
|
|
5470
|
+
type="button"
|
|
5471
|
+
variant="solid"
|
|
5472
|
+
[color]="secondaryAction.color ?? 'slate'"
|
|
5473
|
+
shape="circle"
|
|
5474
|
+
size="xxs"
|
|
5475
|
+
[icon]="secondaryAction.icon"
|
|
5476
|
+
[iconOnly]="true"
|
|
5477
|
+
[clxTooltip]="secondaryAction.tooltip ?? ''"
|
|
5478
|
+
class="absolute bottom-0 right-0 translate-y-1/2 translate-x-1/2 shadow-md z-10"
|
|
5479
|
+
[disabled]="_disabled()"
|
|
5480
|
+
(click)="secondaryActionClick.emit(item); $event.stopPropagation()">
|
|
5481
|
+
</button>
|
|
5482
|
+
}
|
|
5411
5483
|
|
|
5412
5484
|
<div class="px-1.5 py-1 w-full min-w-0">
|
|
5413
5485
|
<p class="text-[11px] leading-tight text-clx-text-label font-medium truncate" [title]="item.name">{{ item.name }}</p>
|
|
@@ -5434,7 +5506,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
|
|
|
5434
5506
|
class: 'block w-full',
|
|
5435
5507
|
},
|
|
5436
5508
|
}]
|
|
5437
|
-
}], 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 }] }] } });
|
|
5509
|
+
}], 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 }] }], primaryAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "primaryAction", required: false }] }], secondaryAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "secondaryAction", required: false }] }], onUploadError: [{ type: i0.Output, args: ["onUploadError"] }], onUploadSuccess: [{ type: i0.Output, args: ["onUploadSuccess"] }], existingFileRemove: [{ type: i0.Output, args: ["existingFileRemove"] }], secondaryActionClick: [{ type: i0.Output, args: ["secondaryActionClick"] }], _fileInput: [{ type: i0.ViewChild, args: ['fileInput', { isSignal: true }] }] } });
|
|
5438
5510
|
|
|
5439
5511
|
const COLOR_PICKER_SIZE_MAP = {
|
|
5440
5512
|
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' },
|