@tinya-code/gas-admin-ui 0.0.0-stage → 0.1.0-alpha.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/README.md +63 -2
- package/fesm2022/tinya-code-gas-admin-ui-api.service-CZrUeclM.mjs +281 -0
- package/fesm2022/tinya-code-gas-admin-ui-api.service-CZrUeclM.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs +84 -0
- package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs +140 -0
- package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs +113 -0
- package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs +163 -0
- package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-calendar-view-r-RXDE37.mjs +1022 -0
- package/fesm2022/tinya-code-gas-admin-ui-calendar-view-r-RXDE37.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs +278 -0
- package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-BBzWUuHl.mjs +101 -0
- package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-BBzWUuHl.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs +141 -0
- package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-data-source.service-LD8AM3Rn.mjs +89 -0
- package/fesm2022/tinya-code-gas-admin-ui-data-source.service-LD8AM3Rn.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs +107 -0
- package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs +140 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs +119 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs +125 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs +152 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs +211 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs +116 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs +111 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs +107 -0
- package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs +109 -0
- package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-Ci0UpXtV.mjs +45 -0
- package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-Ci0UpXtV.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs +50 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs +24 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs +27 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-file-Dg2N3XQ2.mjs +408 -0
- package/fesm2022/tinya-code-gas-admin-ui-file-Dg2N3XQ2.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-form-view-BwGupSbi.mjs +4514 -0
- package/fesm2022/tinya-code-gas-admin-ui-form-view-BwGupSbi.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs +82 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs +105 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs +65 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs +65 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs +65 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs +59 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs +94 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs +72 -0
- package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs +238 -0
- package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-image-Bjw9ImlS.mjs +416 -0
- package/fesm2022/tinya-code-gas-admin-ui-image-Bjw9ImlS.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-kanban-view-CeGueI57.mjs +439 -0
- package/fesm2022/tinya-code-gas-admin-ui-kanban-view-CeGueI57.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs +513 -0
- package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-list-CMzl9MkX.mjs +637 -0
- package/fesm2022/tinya-code-gas-admin-ui-list-CMzl9MkX.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs +127 -0
- package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-multiselect-CuWwAfdY.mjs +251 -0
- package/fesm2022/tinya-code-gas-admin-ui-multiselect-CuWwAfdY.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs +66 -0
- package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs +114 -0
- package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs +116 -0
- package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs +235 -0
- package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs +8 -0
- package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs +124 -0
- package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs +249 -0
- package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-relation-B3W3Ynsp.mjs +309 -0
- package/fesm2022/tinya-code-gas-admin-ui-relation-B3W3Ynsp.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs +39 -0
- package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-render-registry-B_D5Jhp9.mjs +546 -0
- package/fesm2022/tinya-code-gas-admin-ui-render-registry-B_D5Jhp9.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-rolldown-runtime-DpJrqANO.mjs +11 -0
- package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-CDrz9pVN.mjs +131 -0
- package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-CDrz9pVN.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-seed-CNbQtREA.mjs +80 -0
- package/fesm2022/tinya-code-gas-admin-ui-seed-CNbQtREA.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-select-DzaRfHXO.mjs +292 -0
- package/fesm2022/tinya-code-gas-admin-ui-select-DzaRfHXO.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs +119 -0
- package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs +158 -0
- package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs +26 -0
- package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs +205 -0
- package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs +432 -0
- package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs +36 -0
- package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs +107 -0
- package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs +223 -0
- package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs +107 -0
- package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-upload.service-C1g545w5.mjs +60 -0
- package/fesm2022/tinya-code-gas-admin-ui-upload.service-C1g545w5.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs +141 -0
- package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui.mjs +4400 -0
- package/fesm2022/tinya-code-gas-admin-ui.mjs.map +1 -0
- package/package.json +31 -3
- package/types/tinya-code-gas-admin-ui.d.ts +3091 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import { t as __exportAll } from "./tinya-code-gas-admin-ui-rolldown-runtime-DpJrqANO.mjs";
|
|
2
|
+
import { s as ApiError } from "./tinya-code-gas-admin-ui-api.service-CZrUeclM.mjs";
|
|
3
|
+
import { t as Button } from "./tinya-code-gas-admin-ui-button-BQjNW8KB.mjs";
|
|
4
|
+
import { t as NotificationService } from "./tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs";
|
|
5
|
+
import { t as UploadService } from "./tinya-code-gas-admin-ui-upload.service-C1g545w5.mjs";
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
import { Component, DestroyRef, computed, inject, input, model, output, signal, viewChild } from "@angular/core";
|
|
8
|
+
import { HttpEventType } from "@angular/common/http";
|
|
9
|
+
var file_exports = /* @__PURE__ */ __exportAll({ FieldFile: () => FieldFile });
|
|
10
|
+
var FieldFile = class FieldFile {
|
|
11
|
+
field = input.required(...ngDevMode ? [{ debugName: "field" }] : /* istanbul ignore next */ []);
|
|
12
|
+
resource = input("", ...ngDevMode ? [{ debugName: "resource" }] : /* istanbul ignore next */ []);
|
|
13
|
+
value = model.required(...ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []);
|
|
14
|
+
disabled = input(false, ...ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []);
|
|
15
|
+
touch = output();
|
|
16
|
+
upload = inject(UploadService);
|
|
17
|
+
notifications = inject(NotificationService);
|
|
18
|
+
destroyRef = inject(DestroyRef);
|
|
19
|
+
uploading = signal(false, ...ngDevMode ? [{ debugName: "uploading" }] : /* istanbul ignore next */ []);
|
|
20
|
+
progress = signal(0, ...ngDevMode ? [{ debugName: "progress" }] : /* istanbul ignore next */ []);
|
|
21
|
+
error = signal(null, ...ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []);
|
|
22
|
+
fileName = computed(() => {
|
|
23
|
+
const url = this.value();
|
|
24
|
+
const segment = url.split("/").pop() ?? url;
|
|
25
|
+
return decodeURIComponent(segment);
|
|
26
|
+
}, ...ngDevMode ? [{ debugName: "fileName" }] : /* istanbul ignore next */ []);
|
|
27
|
+
acceptAttr = computed(() => this.field().accept ?? "", ...ngDevMode ? [{ debugName: "acceptAttr" }] : /* istanbul ignore next */ []);
|
|
28
|
+
fileInput = viewChild.required("fileInput", ...ngDevMode ? [{ debugName: "fileInput" }] : /* istanbul ignore next */ []);
|
|
29
|
+
uploadSub;
|
|
30
|
+
pickFile() {
|
|
31
|
+
this.fileInput().nativeElement.click();
|
|
32
|
+
}
|
|
33
|
+
clear() {
|
|
34
|
+
this.value.set("");
|
|
35
|
+
this.error.set(null);
|
|
36
|
+
this.touch.emit();
|
|
37
|
+
}
|
|
38
|
+
onFileSelected(event) {
|
|
39
|
+
const input = event.target;
|
|
40
|
+
const file = input.files?.[0];
|
|
41
|
+
input.value = "";
|
|
42
|
+
if (file) this.startUpload(file);
|
|
43
|
+
}
|
|
44
|
+
onDrop(event) {
|
|
45
|
+
event.preventDefault();
|
|
46
|
+
const file = event.dataTransfer?.files?.[0];
|
|
47
|
+
if (file) this.startUpload(file);
|
|
48
|
+
}
|
|
49
|
+
startUpload(file) {
|
|
50
|
+
if (this.disabled()) return;
|
|
51
|
+
const problem = this.validate(file);
|
|
52
|
+
if (problem !== null) {
|
|
53
|
+
this.error.set(problem);
|
|
54
|
+
this.touch.emit();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
this.error.set(null);
|
|
58
|
+
this.uploading.set(true);
|
|
59
|
+
this.progress.set(0);
|
|
60
|
+
this.touch.emit();
|
|
61
|
+
this.uploadSub?.unsubscribe();
|
|
62
|
+
this.uploadSub = this.upload.uploadWithProgress(file, this.resource(), this.field().key).subscribe({
|
|
63
|
+
next: (event) => {
|
|
64
|
+
if (event.type === HttpEventType.UploadProgress) {
|
|
65
|
+
if (event.total) this.progress.set(Math.round(event.loaded / event.total * 100));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (event.type === HttpEventType.Response) {
|
|
69
|
+
const url = event.body ?? "";
|
|
70
|
+
this.uploading.set(false);
|
|
71
|
+
if (url === "") {
|
|
72
|
+
this.error.set("No se pudo subir el archivo.");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
this.value.set(url);
|
|
76
|
+
this.notifications.success("Archivo subido.");
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
error: (err) => {
|
|
80
|
+
this.uploading.set(false);
|
|
81
|
+
this.error.set(err instanceof ApiError ? err.message : "No se pudo subir el archivo. Revisa la conexión e inténtalo de nuevo.");
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
this.destroyRef.onDestroy(() => this.uploadSub?.unsubscribe());
|
|
85
|
+
}
|
|
86
|
+
validate(file) {
|
|
87
|
+
const accept = this.field().accept;
|
|
88
|
+
if (accept !== void 0 && accept !== "" && !acceptMatches(accept, file)) return "Formato no permitido para este campo.";
|
|
89
|
+
const maxSizeMB = this.field().maxSizeMB;
|
|
90
|
+
if (maxSizeMB !== void 0 && file.size > maxSizeMB * 1024 * 1024) return `El archivo supera ${maxSizeMB} MB.`;
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
94
|
+
minVersion: "12.0.0",
|
|
95
|
+
version: "22.2.3",
|
|
96
|
+
ngImport: i0,
|
|
97
|
+
type: FieldFile,
|
|
98
|
+
deps: [],
|
|
99
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
100
|
+
});
|
|
101
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
102
|
+
minVersion: "17.0.0",
|
|
103
|
+
version: "22.2.3",
|
|
104
|
+
type: FieldFile,
|
|
105
|
+
isStandalone: true,
|
|
106
|
+
selector: "app-field-file",
|
|
107
|
+
inputs: {
|
|
108
|
+
field: {
|
|
109
|
+
classPropertyName: "field",
|
|
110
|
+
publicName: "field",
|
|
111
|
+
isSignal: true,
|
|
112
|
+
isRequired: true,
|
|
113
|
+
transformFunction: null
|
|
114
|
+
},
|
|
115
|
+
resource: {
|
|
116
|
+
classPropertyName: "resource",
|
|
117
|
+
publicName: "resource",
|
|
118
|
+
isSignal: true,
|
|
119
|
+
isRequired: false,
|
|
120
|
+
transformFunction: null
|
|
121
|
+
},
|
|
122
|
+
value: {
|
|
123
|
+
classPropertyName: "value",
|
|
124
|
+
publicName: "value",
|
|
125
|
+
isSignal: true,
|
|
126
|
+
isRequired: true,
|
|
127
|
+
transformFunction: null
|
|
128
|
+
},
|
|
129
|
+
disabled: {
|
|
130
|
+
classPropertyName: "disabled",
|
|
131
|
+
publicName: "disabled",
|
|
132
|
+
isSignal: true,
|
|
133
|
+
isRequired: false,
|
|
134
|
+
transformFunction: null
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
outputs: {
|
|
138
|
+
value: "valueChange",
|
|
139
|
+
touch: "touch"
|
|
140
|
+
},
|
|
141
|
+
viewQueries: [{
|
|
142
|
+
propertyName: "fileInput",
|
|
143
|
+
first: true,
|
|
144
|
+
predicate: ["fileInput"],
|
|
145
|
+
descendants: true,
|
|
146
|
+
isSignal: true
|
|
147
|
+
}],
|
|
148
|
+
ngImport: i0,
|
|
149
|
+
template: ` @if (error(); as message) {
|
|
150
|
+
<p
|
|
151
|
+
class="mb-2 rounded-lg border border-danger/30 bg-danger/10 px-3 py-2 text-xs text-danger"
|
|
152
|
+
role="alert"
|
|
153
|
+
>
|
|
154
|
+
{{ message }}
|
|
155
|
+
</p>
|
|
156
|
+
}
|
|
157
|
+
@if (uploading()) {
|
|
158
|
+
<div class="rounded-xl border border-neutral/20 bg-surface p-3" data-testid="file-uploading">
|
|
159
|
+
<div class="h-1.5 w-full overflow-hidden rounded-full bg-neutral/20">
|
|
160
|
+
<div
|
|
161
|
+
class="h-full rounded-full bg-primary transition-all"
|
|
162
|
+
[style.width.%]="progress()"
|
|
163
|
+
></div>
|
|
164
|
+
</div>
|
|
165
|
+
<p class="mt-1 text-xs text-neutral">Subiendo… {{ progress() }}%</p>
|
|
166
|
+
</div>
|
|
167
|
+
} @else if (value()) {
|
|
168
|
+
<div
|
|
169
|
+
class="rounded-xl border border-neutral/20 bg-surface p-3"
|
|
170
|
+
data-testid="file-preview"
|
|
171
|
+
(dragover)="$event.preventDefault()"
|
|
172
|
+
(drop)="onDrop($event)"
|
|
173
|
+
>
|
|
174
|
+
<p class="truncate text-sm font-medium" [title]="value()">{{ fileName() }}</p>
|
|
175
|
+
<div class="mt-2 flex flex-wrap items-center gap-2">
|
|
176
|
+
<button
|
|
177
|
+
type="button"
|
|
178
|
+
app-button
|
|
179
|
+
variant="outline"
|
|
180
|
+
[disabled]="disabled()"
|
|
181
|
+
(click)="pickFile()"
|
|
182
|
+
>
|
|
183
|
+
Reemplazar
|
|
184
|
+
</button>
|
|
185
|
+
@if (!field().required) {
|
|
186
|
+
<button
|
|
187
|
+
type="button"
|
|
188
|
+
app-button
|
|
189
|
+
variant="outline"
|
|
190
|
+
[disabled]="disabled()"
|
|
191
|
+
(click)="clear()"
|
|
192
|
+
>
|
|
193
|
+
Quitar
|
|
194
|
+
</button>
|
|
195
|
+
}
|
|
196
|
+
<a
|
|
197
|
+
class="text-sm font-medium text-primary hover:underline"
|
|
198
|
+
[href]="value()"
|
|
199
|
+
target="_blank"
|
|
200
|
+
rel="noopener noreferrer"
|
|
201
|
+
>
|
|
202
|
+
Abrir
|
|
203
|
+
</a>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
} @else {
|
|
207
|
+
<div
|
|
208
|
+
class="rounded-xl border-2 border-dashed border-neutral/30 p-6 text-center"
|
|
209
|
+
data-testid="file-dropzone"
|
|
210
|
+
(dragover)="$event.preventDefault()"
|
|
211
|
+
(drop)="onDrop($event)"
|
|
212
|
+
>
|
|
213
|
+
<p class="text-sm text-neutral">Arrastrá un archivo acá</p>
|
|
214
|
+
<button
|
|
215
|
+
type="button"
|
|
216
|
+
app-button
|
|
217
|
+
variant="outline"
|
|
218
|
+
class="mt-2"
|
|
219
|
+
[disabled]="disabled()"
|
|
220
|
+
(click)="pickFile()"
|
|
221
|
+
>
|
|
222
|
+
Subir archivo
|
|
223
|
+
</button>
|
|
224
|
+
</div>
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
<input
|
|
228
|
+
#fileInput
|
|
229
|
+
type="file"
|
|
230
|
+
class="sr-only"
|
|
231
|
+
[accept]="acceptAttr()"
|
|
232
|
+
[disabled]="disabled()"
|
|
233
|
+
(change)="onFileSelected($event)"
|
|
234
|
+
/>`,
|
|
235
|
+
isInline: true,
|
|
236
|
+
dependencies: [{
|
|
237
|
+
kind: "component",
|
|
238
|
+
type: Button,
|
|
239
|
+
selector: "button[app-button]",
|
|
240
|
+
inputs: [
|
|
241
|
+
"variant",
|
|
242
|
+
"size",
|
|
243
|
+
"type",
|
|
244
|
+
"disabled",
|
|
245
|
+
"loading"
|
|
246
|
+
]
|
|
247
|
+
}]
|
|
248
|
+
});
|
|
249
|
+
};
|
|
250
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
251
|
+
minVersion: "12.0.0",
|
|
252
|
+
version: "22.2.3",
|
|
253
|
+
ngImport: i0,
|
|
254
|
+
type: FieldFile,
|
|
255
|
+
decorators: [{
|
|
256
|
+
type: Component,
|
|
257
|
+
args: [{
|
|
258
|
+
selector: "app-field-file",
|
|
259
|
+
imports: [Button],
|
|
260
|
+
template: ` @if (error(); as message) {
|
|
261
|
+
<p
|
|
262
|
+
class="mb-2 rounded-lg border border-danger/30 bg-danger/10 px-3 py-2 text-xs text-danger"
|
|
263
|
+
role="alert"
|
|
264
|
+
>
|
|
265
|
+
{{ message }}
|
|
266
|
+
</p>
|
|
267
|
+
}
|
|
268
|
+
@if (uploading()) {
|
|
269
|
+
<div class="rounded-xl border border-neutral/20 bg-surface p-3" data-testid="file-uploading">
|
|
270
|
+
<div class="h-1.5 w-full overflow-hidden rounded-full bg-neutral/20">
|
|
271
|
+
<div
|
|
272
|
+
class="h-full rounded-full bg-primary transition-all"
|
|
273
|
+
[style.width.%]="progress()"
|
|
274
|
+
></div>
|
|
275
|
+
</div>
|
|
276
|
+
<p class="mt-1 text-xs text-neutral">Subiendo… {{ progress() }}%</p>
|
|
277
|
+
</div>
|
|
278
|
+
} @else if (value()) {
|
|
279
|
+
<div
|
|
280
|
+
class="rounded-xl border border-neutral/20 bg-surface p-3"
|
|
281
|
+
data-testid="file-preview"
|
|
282
|
+
(dragover)="$event.preventDefault()"
|
|
283
|
+
(drop)="onDrop($event)"
|
|
284
|
+
>
|
|
285
|
+
<p class="truncate text-sm font-medium" [title]="value()">{{ fileName() }}</p>
|
|
286
|
+
<div class="mt-2 flex flex-wrap items-center gap-2">
|
|
287
|
+
<button
|
|
288
|
+
type="button"
|
|
289
|
+
app-button
|
|
290
|
+
variant="outline"
|
|
291
|
+
[disabled]="disabled()"
|
|
292
|
+
(click)="pickFile()"
|
|
293
|
+
>
|
|
294
|
+
Reemplazar
|
|
295
|
+
</button>
|
|
296
|
+
@if (!field().required) {
|
|
297
|
+
<button
|
|
298
|
+
type="button"
|
|
299
|
+
app-button
|
|
300
|
+
variant="outline"
|
|
301
|
+
[disabled]="disabled()"
|
|
302
|
+
(click)="clear()"
|
|
303
|
+
>
|
|
304
|
+
Quitar
|
|
305
|
+
</button>
|
|
306
|
+
}
|
|
307
|
+
<a
|
|
308
|
+
class="text-sm font-medium text-primary hover:underline"
|
|
309
|
+
[href]="value()"
|
|
310
|
+
target="_blank"
|
|
311
|
+
rel="noopener noreferrer"
|
|
312
|
+
>
|
|
313
|
+
Abrir
|
|
314
|
+
</a>
|
|
315
|
+
</div>
|
|
316
|
+
</div>
|
|
317
|
+
} @else {
|
|
318
|
+
<div
|
|
319
|
+
class="rounded-xl border-2 border-dashed border-neutral/30 p-6 text-center"
|
|
320
|
+
data-testid="file-dropzone"
|
|
321
|
+
(dragover)="$event.preventDefault()"
|
|
322
|
+
(drop)="onDrop($event)"
|
|
323
|
+
>
|
|
324
|
+
<p class="text-sm text-neutral">Arrastrá un archivo acá</p>
|
|
325
|
+
<button
|
|
326
|
+
type="button"
|
|
327
|
+
app-button
|
|
328
|
+
variant="outline"
|
|
329
|
+
class="mt-2"
|
|
330
|
+
[disabled]="disabled()"
|
|
331
|
+
(click)="pickFile()"
|
|
332
|
+
>
|
|
333
|
+
Subir archivo
|
|
334
|
+
</button>
|
|
335
|
+
</div>
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
<input
|
|
339
|
+
#fileInput
|
|
340
|
+
type="file"
|
|
341
|
+
class="sr-only"
|
|
342
|
+
[accept]="acceptAttr()"
|
|
343
|
+
[disabled]="disabled()"
|
|
344
|
+
(change)="onFileSelected($event)"
|
|
345
|
+
/>`
|
|
346
|
+
}]
|
|
347
|
+
}],
|
|
348
|
+
propDecorators: {
|
|
349
|
+
field: [{
|
|
350
|
+
type: i0.Input,
|
|
351
|
+
args: [{
|
|
352
|
+
isSignal: true,
|
|
353
|
+
alias: "field",
|
|
354
|
+
required: true
|
|
355
|
+
}]
|
|
356
|
+
}],
|
|
357
|
+
resource: [{
|
|
358
|
+
type: i0.Input,
|
|
359
|
+
args: [{
|
|
360
|
+
isSignal: true,
|
|
361
|
+
alias: "resource",
|
|
362
|
+
required: false
|
|
363
|
+
}]
|
|
364
|
+
}],
|
|
365
|
+
value: [{
|
|
366
|
+
type: i0.Input,
|
|
367
|
+
args: [{
|
|
368
|
+
isSignal: true,
|
|
369
|
+
alias: "value",
|
|
370
|
+
required: true
|
|
371
|
+
}]
|
|
372
|
+
}, {
|
|
373
|
+
type: i0.Output,
|
|
374
|
+
args: ["valueChange"]
|
|
375
|
+
}],
|
|
376
|
+
disabled: [{
|
|
377
|
+
type: i0.Input,
|
|
378
|
+
args: [{
|
|
379
|
+
isSignal: true,
|
|
380
|
+
alias: "disabled",
|
|
381
|
+
required: false
|
|
382
|
+
}]
|
|
383
|
+
}],
|
|
384
|
+
touch: [{
|
|
385
|
+
type: i0.Output,
|
|
386
|
+
args: ["touch"]
|
|
387
|
+
}],
|
|
388
|
+
fileInput: [{
|
|
389
|
+
type: i0.ViewChild,
|
|
390
|
+
args: ["fileInput", { isSignal: true }]
|
|
391
|
+
}]
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
function acceptMatches(accept, file) {
|
|
395
|
+
for (const raw of accept.split(",")) {
|
|
396
|
+
const entry = raw.trim().toLowerCase();
|
|
397
|
+
if (entry === "") continue;
|
|
398
|
+
if (entry.startsWith(".")) {
|
|
399
|
+
if (file.name.toLowerCase().endsWith(entry)) return true;
|
|
400
|
+
} else if (entry.endsWith("/*")) {
|
|
401
|
+
if (file.type.startsWith(entry.slice(0, -1))) return true;
|
|
402
|
+
} else if (file.type === entry) return true;
|
|
403
|
+
}
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
export { file_exports as n, FieldFile as t };
|
|
407
|
+
|
|
408
|
+
//# sourceMappingURL=tinya-code-gas-admin-ui-file-Dg2N3XQ2.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tinya-code-gas-admin-ui-file-Dg2N3XQ2.mjs","names":[],"sources":["../../../projects/gas-admin-ui/src/lib/fields/file/file.ts"],"sourcesContent":["import { HttpEventType } from '@angular/common/http';\nimport {\n Component,\n computed,\n DestroyRef,\n ElementRef,\n inject,\n input,\n model,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport type { FileField } from '../../core/models/schema.model';\nimport { ApiError } from '../../core/models/api.model';\nimport { NotificationService } from '../../core/services/notification.service';\nimport { Button } from '../../shared/components/button/button';\nimport { UploadService } from '../../core/services/upload.service';\n\n/**\n * Carga de archivo (base.md §7 · R9.5.3): el valor es SOLO la URL pública,\n * igual que `image`, pero para cualquier tipo de archivo (pdf, xlsx, zip…).\n *\n * Espejo de `FieldImage` (D27: es un control propio que no pasa por\n * `NgComponentOutlet`, porque su `value` es un `model()` que el host\n * sincroniza por `[formField]`). La ÚNICA diferencia de comportamiento: no\n * fuerza el prefijo `image/` — el catálogo de formatos lo define el backend\n * por campo (`formats` declarado) o la lista global, y el cliente sólo\n * respeta `accept`/`maxSizeMB` como validación de comodidad.\n *\n * Estados: vacío (zona punteada + arrastrar-soltar), subiendo (progreso; el\n * valor no cambia hasta la respuesta), con archivo (nombre + Quitar / Ver) y\n * error (conserva el archivo anterior).\n */\n@Component({\n selector: 'app-field-file',\n imports: [Button],\n template: ` @if (error(); as message) {\n <p\n class=\"mb-2 rounded-lg border border-danger/30 bg-danger/10 px-3 py-2 text-xs text-danger\"\n role=\"alert\"\n >\n {{ message }}\n </p>\n }\n @if (uploading()) {\n <div class=\"rounded-xl border border-neutral/20 bg-surface p-3\" data-testid=\"file-uploading\">\n <div class=\"h-1.5 w-full overflow-hidden rounded-full bg-neutral/20\">\n <div\n class=\"h-full rounded-full bg-primary transition-all\"\n [style.width.%]=\"progress()\"\n ></div>\n </div>\n <p class=\"mt-1 text-xs text-neutral\">Subiendo… {{ progress() }}%</p>\n </div>\n } @else if (value()) {\n <div\n class=\"rounded-xl border border-neutral/20 bg-surface p-3\"\n data-testid=\"file-preview\"\n (dragover)=\"$event.preventDefault()\"\n (drop)=\"onDrop($event)\"\n >\n <p class=\"truncate text-sm font-medium\" [title]=\"value()\">{{ fileName() }}</p>\n <div class=\"mt-2 flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n app-button\n variant=\"outline\"\n [disabled]=\"disabled()\"\n (click)=\"pickFile()\"\n >\n Reemplazar\n </button>\n @if (!field().required) {\n <button\n type=\"button\"\n app-button\n variant=\"outline\"\n [disabled]=\"disabled()\"\n (click)=\"clear()\"\n >\n Quitar\n </button>\n }\n <a\n class=\"text-sm font-medium text-primary hover:underline\"\n [href]=\"value()\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Abrir\n </a>\n </div>\n </div>\n } @else {\n <div\n class=\"rounded-xl border-2 border-dashed border-neutral/30 p-6 text-center\"\n data-testid=\"file-dropzone\"\n (dragover)=\"$event.preventDefault()\"\n (drop)=\"onDrop($event)\"\n >\n <p class=\"text-sm text-neutral\">Arrastrá un archivo acá</p>\n <button\n type=\"button\"\n app-button\n variant=\"outline\"\n class=\"mt-2\"\n [disabled]=\"disabled()\"\n (click)=\"pickFile()\"\n >\n Subir archivo\n </button>\n </div>\n }\n\n <input\n #fileInput\n type=\"file\"\n class=\"sr-only\"\n [accept]=\"acceptAttr()\"\n [disabled]=\"disabled()\"\n (change)=\"onFileSelected($event)\"\n />`,\n})\nexport class FieldFile implements FormValueControl<string> {\n readonly field = input.required<FileField>();\n /** Recurso dueño del archivo (firma de subida: carpeta de Cloudinary, §11.2). */\n readonly resource = input('');\n\n /** Sincronizado por el directive `FormField` del host. */\n readonly value = model.required<string>();\n readonly disabled = input(false);\n /** Marca el campo como tocado (upload/clear/error), como el `blur` nativo. */\n readonly touch = output<void>();\n\n private readonly upload = inject(UploadService);\n private readonly notifications = inject(NotificationService);\n private readonly destroyRef = inject(DestroyRef);\n\n protected readonly uploading = signal(false);\n protected readonly progress = signal(0);\n protected readonly error = signal<string | null>(null);\n\n /**\n * Nombre derivado de la URL para el preview. Cloudinary guarda el\n * `public_id` al final del path (…/v123/produccion/adjuntos/archivo_xyz):\n * lo presentable es el sufijo tras el último `/`, sin extensión ruidosa.\n */\n protected readonly fileName = computed(() => {\n const url = this.value();\n const segment = url.split('/').pop() ?? url;\n return decodeURIComponent(segment);\n });\n\n /** `accept` de `<input type=file>`: el declarado o `''` (sin forzar `image/*`). */\n protected readonly acceptAttr = computed(() => this.field().accept ?? '');\n\n /**\n * Template ref `#fileInput`: Angular NO auto-asigna las template refs a\n * propiedades de clase (mismo motivo que en `FieldImage`).\n */\n private readonly fileInput = viewChild.required<ElementRef<HTMLInputElement>>('fileInput');\n private uploadSub?: { unsubscribe(): void };\n\n protected pickFile(): void {\n this.fileInput().nativeElement.click();\n }\n\n protected clear(): void {\n this.value.set('');\n this.error.set(null);\n this.touch.emit();\n }\n\n protected onFileSelected(event: Event): void {\n const input = event.target as HTMLInputElement;\n const file = input.files?.[0];\n // Permite volver a elegir el mismo archivo tras un error.\n input.value = '';\n if (file) {\n this.startUpload(file);\n }\n }\n\n protected onDrop(event: Event): void {\n event.preventDefault();\n const file = (event as DragEvent).dataTransfer?.files?.[0];\n if (file) {\n this.startUpload(file);\n }\n }\n\n /** Valida en cliente (accept + maxSizeMB) y sube con progreso. */\n private startUpload(file: File): void {\n if (this.disabled()) {\n return;\n }\n const problem = this.validate(file);\n if (problem !== null) {\n this.error.set(problem);\n this.touch.emit();\n return;\n }\n this.error.set(null);\n this.uploading.set(true);\n this.progress.set(0);\n this.touch.emit();\n\n this.uploadSub?.unsubscribe();\n // El nombre del campo viaja siempre: si declara `formats`, el backend\n // firma ESA lista; sin formatos firma la lista global (R9.5.3).\n this.uploadSub = this.upload\n .uploadWithProgress(file, this.resource(), this.field().key)\n .subscribe({\n next: (event) => {\n if (event.type === HttpEventType.UploadProgress) {\n if (event.total) {\n this.progress.set(Math.round((event.loaded / event.total) * 100));\n }\n return;\n }\n if (event.type === HttpEventType.Response) {\n const url = event.body ?? '';\n this.uploading.set(false);\n if (url === '') {\n this.error.set('No se pudo subir el archivo.');\n return;\n }\n this.value.set(url);\n this.notifications.success('Archivo subido.');\n }\n },\n error: (err: unknown) => {\n this.uploading.set(false);\n // El backend explica el motivo (firma inválida, 429 rate-limit…).\n this.error.set(\n err instanceof ApiError\n ? err.message\n : 'No se pudo subir el archivo. Revisa la conexión e inténtalo de nuevo.',\n );\n },\n });\n this.destroyRef.onDestroy(() => this.uploadSub?.unsubscribe());\n }\n\n private validate(file: File): string | null {\n const accept = this.field().accept;\n if (accept !== undefined && accept !== '' && !acceptMatches(accept, file)) {\n return 'Formato no permitido para este campo.';\n }\n const maxSizeMB = this.field().maxSizeMB;\n if (maxSizeMB !== undefined && file.size > maxSizeMB * 1024 * 1024) {\n return `El archivo supera ${maxSizeMB} MB.`;\n }\n return null;\n }\n}\n\n/** `accept` de `<input type=file>`: lista, `tipo/*` o extensión `.png`. */\nfunction acceptMatches(accept: string, file: File): boolean {\n for (const raw of accept.split(',')) {\n const entry = raw.trim().toLowerCase();\n if (entry === '') {\n continue;\n }\n if (entry.startsWith('.')) {\n if (file.name.toLowerCase().endsWith(entry)) {\n return true;\n }\n } else if (entry.endsWith('/*')) {\n if (file.type.startsWith(entry.slice(0, -1))) {\n return true;\n }\n } else if (file.type === entry) {\n return true;\n }\n }\n return false;\n}\n"],"mappings":";;;;;;;;;AA8HA,IAAa,YAAb,MAAa,UAAS;CACX,QAAQ,MAAM,SAAqB,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAEnC,WAAW,MAAM,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAGpB,QAAQ,MAAM,SAAkB,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAChC,WAAW,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAEvB,QAAQ,OAAM;CAEN,SAAS,OAAO,aAAa;CAC7B,gBAAgB,OAAO,mBAAmB;CAC1C,aAAa,OAAO,UAAU;CAE5B,YAAY,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CACzB,WAAW,OAAO,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CACpB,QAAQ,OAAsB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAOnC,WAAW,eAAc;EAC1C,MAAM,MAAM,KAAK,MAAK;EACtB,MAAM,UAAU,IAAI,MAAM,GAAG,CAAC,CAAC,IAAG,KAAM;EACxC,OAAO,mBAAmB,OAAO;CACnC,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAGiB,aAAa,eAAe,KAAK,MAAK,CAAE,CAAC,UAAU,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CAMxD,YAAY,UAAU,SAAuC,aAAY,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAClF;CAEE,WAAQ;EAChB,KAAK,UAAS,CAAE,CAAC,cAAc,MAAK;CACtC;CAEU,QAAK;EACb,KAAK,MAAM,IAAI,EAAE;EACjB,KAAK,MAAM,IAAI,IAAI;EACnB,KAAK,MAAM,KAAI;CACjB;CAEU,eAAe,OAAY;EACnC,MAAM,QAAQ,MAAM;EACpB,MAAM,OAAO,MAAM,QAAQ;EAE3B,MAAM,QAAQ;EACd,IAAI,MACF,KAAK,YAAY,IAAI;CAEzB;CAEU,OAAO,OAAY;EAC3B,MAAM,eAAc;EACpB,MAAM,OAAQ,MAAoB,cAAc,QAAQ;EACxD,IAAI,MACF,KAAK,YAAY,IAAI;CAEzB;CAGQ,YAAY,MAAU;EAC5B,IAAI,KAAK,SAAQ,GACf;EAEF,MAAM,UAAU,KAAK,SAAS,IAAI;EAClC,IAAI,YAAY,MAAM;GACpB,KAAK,MAAM,IAAI,OAAO;GACtB,KAAK,MAAM,KAAI;GACf;EACF;EACA,KAAK,MAAM,IAAI,IAAI;EACnB,KAAK,UAAU,IAAI,IAAI;EACvB,KAAK,SAAS,IAAI,CAAC;EACnB,KAAK,MAAM,KAAI;EAEf,KAAK,WAAW,YAAW;EAG3B,KAAK,YAAY,KAAK,OACnB,mBAAmB,MAAM,KAAK,SAAQ,GAAI,KAAK,MAAK,CAAE,CAAC,GAAG,CAAC,CAC3D,UAAU;GACT,OAAO,UAAS;IACd,IAAI,MAAM,SAAS,cAAc,gBAAgB;KAC/C,IAAI,MAAM,OACR,KAAK,SAAS,IAAI,KAAK,MAAO,MAAM,SAAS,MAAM,QAAS,GAAG,CAAC;KAElE;IACF;IACA,IAAI,MAAM,SAAS,cAAc,UAAU;KACzC,MAAM,MAAM,MAAM,QAAQ;KAC1B,KAAK,UAAU,IAAI,KAAK;KACxB,IAAI,QAAQ,IAAI;MACd,KAAK,MAAM,IAAI,8BAA8B;MAC7C;KACF;KACA,KAAK,MAAM,IAAI,GAAG;KAClB,KAAK,cAAc,QAAQ,iBAAiB;IAC9C;GACF;GACA,QAAQ,QAAgB;IACtB,KAAK,UAAU,IAAI,KAAK;IAExB,KAAK,MAAM,IACT,eAAe,WACX,IAAI,UACJ,uEAAuE;GAE/E;EACD,CAAA;EACH,KAAK,WAAW,gBAAgB,KAAK,WAAW,YAAW,CAAE;CAC/D;CAEQ,SAAS,MAAU;EACzB,MAAM,SAAS,KAAK,MAAK,CAAE,CAAC;EAC5B,IAAI,WAAW,UAAa,WAAW,MAAM,CAAC,cAAc,QAAQ,IAAI,GACtE,OAAO;EAET,MAAM,YAAY,KAAK,MAAK,CAAE,CAAC;EAC/B,IAAI,cAAc,UAAa,KAAK,OAAO,YAAY,OAAO,MAC5D,OAAO,qBAAqB,UAAS;EAEvC,OAAO;CACT;CAnIW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAS,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAT,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAS,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,SAAA;GAAA,OAAA;GAAA,OAAA;EAAA;EAAA,aAAA,CAAA;GAAA,cAAA;GAAA,OAAA;GAAA,WAAA,CAAA,WAAA;GAAA,aAAA;GAAA,UAAA;EAAA,CAAA;EAAA,UAAA;EAAA,UAvFV;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqFL,UAAA;EAAA,cAAA,CAAA;GAAA,MAAA;GAAA,MAtFK;GAAM,UAAA;GAAA,QAAA;IAAA;IAAA;IAAA;IAAA;IAAA;GAAA;EAAA,CAAA;CAAA,CAAA;;AAwFL,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAS,YAAA,CAAA;EA1FrB,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,SAAS,CAAC,MAAM;GAChB,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsFX,CAAA;CAsC+E,CAAA;CAAA,gBAAA;EAAA,OAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,UAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,OAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,GAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,aAAA;EAAA,CAAA;EAAA,UAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,OAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,OAAA;EAAA,CAAA;EAAA,WAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,aAAW,EAAA,UAAA,KAAA,CAAA;EAAA,CAAA;CAAA;AAAA,CAAA;AAkG3F,SAAS,cAAc,QAAgB,MAAU;CAC/C,KAAK,MAAM,OAAO,OAAO,MAAM,GAAG,GAAG;EACnC,MAAM,QAAQ,IAAI,KAAI,CAAE,CAAC,YAAW;EACpC,IAAI,UAAU,IACZ;EAEF,IAAI,MAAM,WAAW,GAAG,GACtB;OAAI,KAAK,KAAK,YAAW,CAAE,CAAC,SAAS,KAAK,GACxC,OAAO;EACT,OACK,IAAI,MAAM,SAAS,IAAI,GAC5B;OAAI,KAAK,KAAK,WAAW,MAAM,MAAM,GAAG,EAAE,CAAC,GACzC,OAAO;EACT,OACK,IAAI,KAAK,SAAS,OACvB,OAAO;CAEX;CACA,OAAO;AACT"}
|