@erplora/outfitkit 0.1.28 → 0.1.29

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 CHANGED
@@ -439,7 +439,7 @@ npm run build # vite (dist/*.js, outfitkit.js, theme.example.css) + tsc (
439
439
  npm run typecheck # comprobación de tipos sin emitir
440
440
  npm run verify:csp # rechaza eval / new Function en dist (CSP estricta)
441
441
  npm run dev # vite build --watch (showcase en local)
442
- npm run release # release-it: corta una versión (ver docs/RELEASING.md)
442
+ npm run release # release-it a mano (NO hace falta: la CI publica al mergear, ver docs/RELEASING.md)
443
443
  ```
444
444
 
445
445
  Publicación a npm: [`docs/RELEASING.md`](docs/RELEASING.md) (Trusted Publishing / OIDC).
@@ -52,6 +52,22 @@ export interface OkFmQuota {
52
52
  /** Modo de visualización del área de archivos. */
53
53
  export type OkFmView = 'grid' | 'list';
54
54
  /** Textos i18n del componente (defaults en español). */
55
+ /**
56
+ * Qué se puede hacer en la carpeta actual. La decide el HOST (en ERPlora, el módulo dueño de la
57
+ * carpeta — ADR-0172) y el componente solo la obedece al pintar: **no es una barrera de
58
+ * seguridad**, el servidor revalida siempre. Ver y descargar no están aquí porque son siempre
59
+ * posibles: "solo lectura" no significa "no puedes mirar".
60
+ *
61
+ * Ausente ⇒ todo disponible (los consumidores que no la pasan no cambian de comportamiento).
62
+ */
63
+ export interface OkFmPolicy {
64
+ /** Subir ficheros y crear subcarpetas. */
65
+ upload: boolean;
66
+ /** Renombrar ficheros y la propia carpeta. */
67
+ rename: boolean;
68
+ /** Borrar ficheros y la propia carpeta. */
69
+ delete: boolean;
70
+ }
55
71
  export interface OkFmLabels {
56
72
  /** Botón primario de subida. */
57
73
  upload: string;
@@ -73,6 +89,12 @@ export interface OkFmLabels {
73
89
  open: string;
74
90
  /** Botón de nueva carpeta. */
75
91
  newFolder: string;
92
+ /** Acción de renombrar (ficheros y carpetas). */
93
+ rename: string;
94
+ /** Renombrar la carpeta en la que se está. */
95
+ renameFolder: string;
96
+ /** Borrar la carpeta en la que se está (con su contenido). */
97
+ deleteFolder: string;
76
98
  /** Caption del medidor cuando no hay cuota dura. */
77
99
  noLimit: string;
78
100
  }
@@ -96,6 +118,9 @@ export declare class OkFileManager extends LitElement {
96
118
  searchable: boolean;
97
119
  /** Muestra el botón primario de subida y habilita drag&drop. */
98
120
  uploadable: boolean;
121
+ /** Acciones permitidas en la carpeta actual (ver `OkFmPolicy`). Ausente ⇒ todo permitido. */
122
+ policy?: OkFmPolicy;
123
+ private can;
99
124
  /** Muestra esqueletos de carga en lugar del contenido. */
100
125
  loading: boolean;
101
126
  /** Textos i18n (merge sobre los defaults en español). */
@@ -112,6 +137,12 @@ export declare class OkFileManager extends LitElement {
112
137
  private open;
113
138
  private download;
114
139
  private deleteFile;
140
+ /** Renombrar un fichero. Se manda el nombre actual para que el host lo proponga en su diálogo. */
141
+ private renameFile;
142
+ /** Etiqueta de la carpeta actual (para proponerla como nombre al renombrar). */
143
+ private get currentFolderLabel();
144
+ private renameCurrentFolder;
145
+ private deleteCurrentFolder;
115
146
  private createFolder;
116
147
  private changeView;
117
148
  private onSearch;
@@ -131,6 +162,7 @@ export declare class OkFileManager extends LitElement {
131
162
  private renderToolbar;
132
163
  private get iconOpen();
133
164
  private get iconDownload();
165
+ private get iconRename();
134
166
  private get iconDelete();
135
167
  private fileActions;
136
168
  private renderContent;
@@ -0,0 +1 @@
1
+ import './ok-file-manager';
@@ -22,6 +22,9 @@ const DEFAULT_LABELS = {
22
22
  delete: "Eliminar",
23
23
  open: "Abrir",
24
24
  newFolder: "Nueva carpeta",
25
+ rename: "Renombrar",
26
+ renameFolder: "Renombrar carpeta",
27
+ deleteFolder: "Eliminar carpeta",
25
28
  noLimit: "Sin límite"
26
29
  };
27
30
  class OkFileManager extends LitElement {
@@ -545,6 +548,11 @@ class OkFileManager extends LitElement {
545
548
  .action.danger:hover {
546
549
  color: var(--danger);
547
550
  }
551
+ /* Borrar la carpeta actual: se tiñe al pasar por encima, igual que el borrado de un fichero. */
552
+ .tbtn.danger:hover {
553
+ color: var(--danger);
554
+ border-color: var(--danger);
555
+ }
548
556
  .action svg {
549
557
  width: 15px;
550
558
  height: 15px;
@@ -644,6 +652,9 @@ class OkFileManager extends LitElement {
644
652
  }
645
653
  `;
646
654
  }
655
+ can(action) {
656
+ return this.policy ? this.policy[action] : true;
657
+ }
647
658
  // Textos efectivos.
648
659
  get t() {
649
660
  return { ...DEFAULT_LABELS, ...this.labels };
@@ -671,7 +682,21 @@ class OkFileManager extends LitElement {
671
682
  this.emit("ok-download", { id: file.id, url: file.url });
672
683
  }
673
684
  deleteFile(id) {
674
- this.emit("ok-delete", { id });
685
+ this.emit("ok-delete", { id, kind: "file" });
686
+ }
687
+ /** Renombrar un fichero. Se manda el nombre actual para que el host lo proponga en su diálogo. */
688
+ renameFile(file) {
689
+ this.emit("ok-rename", { id: file.id, name: file.name, kind: "file" });
690
+ }
691
+ /** Etiqueta de la carpeta actual (para proponerla como nombre al renombrar). */
692
+ get currentFolderLabel() {
693
+ return this.path[this.path.length - 1]?.label ?? this.selected.split("/").pop() ?? "";
694
+ }
695
+ renameCurrentFolder() {
696
+ this.emit("ok-rename", { id: this.selected, name: this.currentFolderLabel, kind: "folder" });
697
+ }
698
+ deleteCurrentFolder() {
699
+ this.emit("ok-delete", { id: this.selected, kind: "folder" });
675
700
  }
676
701
  createFolder() {
677
702
  this.emit("ok-create-folder", { parent: this.selected });
@@ -877,23 +902,47 @@ class OkFileManager extends LitElement {
877
902
  </button>
878
903
  </div>
879
904
 
880
- <button
881
- type="button"
882
- class="tbtn icon"
883
- aria-label=${this.t.newFolder}
884
- title=${this.t.newFolder}
885
- @click=${() => this.createFolder()}
886
- >
887
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
888
- stroke-linecap="round" stroke-linejoin="round">
889
- <path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
890
- <path d="M12 11v6M9 14h6" />
891
- </svg>
892
- </button>
905
+ ${this.selected && this.can("rename") ? html`<button
906
+ type="button"
907
+ class="tbtn icon"
908
+ data-act="rename-folder"
909
+ aria-label=${this.t.renameFolder}
910
+ title=${this.t.renameFolder}
911
+ @click=${() => this.renameCurrentFolder()}
912
+ >
913
+ ${this.iconRename}
914
+ </button>` : ""}
915
+
916
+ ${this.selected && this.can("delete") ? html`<button
917
+ type="button"
918
+ class="tbtn icon danger"
919
+ data-act="delete-folder"
920
+ aria-label=${this.t.deleteFolder}
921
+ title=${this.t.deleteFolder}
922
+ @click=${() => this.deleteCurrentFolder()}
923
+ >
924
+ ${this.iconDelete}
925
+ </button>` : ""}
926
+
927
+ ${this.can("upload") ? html`<button
928
+ type="button"
929
+ class="tbtn icon"
930
+ data-act="new-folder"
931
+ aria-label=${this.t.newFolder}
932
+ title=${this.t.newFolder}
933
+ @click=${() => this.createFolder()}
934
+ >
935
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
936
+ stroke-linecap="round" stroke-linejoin="round">
937
+ <path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
938
+ <path d="M12 11v6M9 14h6" />
939
+ </svg>
940
+ </button>` : ""}
893
941
 
894
- ${this.uploadable ? html`<button
942
+ ${this.uploadable && this.can("upload") ? html`<button
895
943
  type="button"
896
944
  class="tbtn primary icon"
945
+ data-act="upload"
897
946
  aria-label=${this.t.upload}
898
947
  title=${this.t.upload}
899
948
  @click=${() => this.openPicker()}
@@ -920,17 +969,25 @@ class OkFileManager extends LitElement {
920
969
  <polyline points="7 10 12 15 17 10" /><line x1="12" y1="15" x2="12" y2="3" />
921
970
  </svg>`;
922
971
  }
972
+ get iconRename() {
973
+ return html`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
974
+ stroke-linecap="round" stroke-linejoin="round">
975
+ <path d="M12 20h9" /><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z" />
976
+ </svg>`;
977
+ }
923
978
  get iconDelete() {
924
979
  return html`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
925
980
  stroke-linecap="round" stroke-linejoin="round">
926
981
  <path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
927
982
  </svg>`;
928
983
  }
929
- // Acciones de un archivo (abrir/descargar/eliminar), reutilizadas en grid y lista.
984
+ // Acciones de un archivo, reutilizadas en grid y lista. Abrir y descargar SIEMPRE se ofrecen;
985
+ // renombrar y borrar solo si la política de la carpeta los concede.
930
986
  fileActions(file) {
931
987
  return html`<button
932
988
  type="button"
933
989
  class="action"
990
+ data-act="open"
934
991
  aria-label=${this.t.open}
935
992
  title=${this.t.open}
936
993
  @click=${(e) => {
@@ -943,6 +1000,7 @@ class OkFileManager extends LitElement {
943
1000
  <button
944
1001
  type="button"
945
1002
  class="action"
1003
+ data-act="download"
946
1004
  aria-label=${this.t.download}
947
1005
  title=${this.t.download}
948
1006
  @click=${(e) => {
@@ -952,18 +1010,32 @@ class OkFileManager extends LitElement {
952
1010
  >
953
1011
  ${this.iconDownload}
954
1012
  </button>
955
- <button
956
- type="button"
957
- class="action danger"
958
- aria-label=${this.t.delete}
959
- title=${this.t.delete}
960
- @click=${(e) => {
1013
+ ${this.can("rename") ? html`<button
1014
+ type="button"
1015
+ class="action"
1016
+ data-act="rename-file"
1017
+ aria-label=${this.t.rename}
1018
+ title=${this.t.rename}
1019
+ @click=${(e) => {
1020
+ e.stopPropagation();
1021
+ this.renameFile(file);
1022
+ }}
1023
+ >
1024
+ ${this.iconRename}
1025
+ </button>` : ""}
1026
+ ${this.can("delete") ? html`<button
1027
+ type="button"
1028
+ class="action danger"
1029
+ data-act="delete-file"
1030
+ aria-label=${this.t.delete}
1031
+ title=${this.t.delete}
1032
+ @click=${(e) => {
961
1033
  e.stopPropagation();
962
1034
  this.deleteFile(file.id);
963
1035
  }}
964
- >
965
- ${this.iconDelete}
966
- </button>`;
1036
+ >
1037
+ ${this.iconDelete}
1038
+ </button>` : ""}`;
967
1039
  }
968
1040
  // ---- Render del contenido (grid/lista/vacío/loading) ----
969
1041
  renderContent() {
@@ -1096,6 +1168,9 @@ __decorateClass([
1096
1168
  __decorateClass([
1097
1169
  property({ type: Boolean })
1098
1170
  ], OkFileManager.prototype, "uploadable");
1171
+ __decorateClass([
1172
+ property({ attribute: false })
1173
+ ], OkFileManager.prototype, "policy");
1099
1174
  __decorateClass([
1100
1175
  property({ type: Boolean })
1101
1176
  ], OkFileManager.prototype, "loading");
@@ -585,7 +585,7 @@ const _i = (n, e, t) => (t.configurable = !0, t.enumerable = !0, Reflect.decorat
585
585
  * Copyright 2017 Google LLC
586
586
  * SPDX-License-Identifier: BSD-3-Clause
587
587
  */
588
- function T(n, e) {
588
+ function B(n, e) {
589
589
  return (t, o, r) => {
590
590
  const i = (a) => a.renderRoot?.querySelector(n) ?? null;
591
591
  if (e) {
@@ -6669,7 +6669,7 @@ ho([
6669
6669
  l({ attribute: !1 })
6670
6670
  ], Mr.prototype, "labels", 2);
6671
6671
  ho([
6672
- T("input")
6672
+ B("input")
6673
6673
  ], Mr.prototype, "firstInput", 2);
6674
6674
  k("ok-otp", Mr);
6675
6675
  var ll = Object.defineProperty, cl = Object.getOwnPropertyDescriptor, qe = (n, e, t, o) => {
@@ -7558,7 +7558,7 @@ ye([
7558
7558
  v()
7559
7559
  ], ie.prototype, "error", 2);
7560
7560
  ye([
7561
- T('input[type="file"]')
7561
+ B('input[type="file"]')
7562
7562
  ], ie.prototype, "input", 2);
7563
7563
  k("ok-dropzone", ie);
7564
7564
  var yl = Object.defineProperty, kl = Object.getOwnPropertyDescriptor, Yt = (n, e, t, o) => {
@@ -7957,10 +7957,10 @@ $t([
7957
7957
  l({ attribute: !1 })
7958
7958
  ], He.prototype, "labels", 2);
7959
7959
  $t([
7960
- T(".log")
7960
+ B(".log")
7961
7961
  ], He.prototype, "logEl", 2);
7962
7962
  $t([
7963
- T("ion-textarea")
7963
+ B("ion-textarea")
7964
7964
  ], He.prototype, "textareaEl", 2);
7965
7965
  k("ok-chat", He);
7966
7966
  var zl = Object.defineProperty, _l = Object.getOwnPropertyDescriptor, ke = (n, e, t, o) => {
@@ -9282,7 +9282,7 @@ Ct([
9282
9282
  v()
9283
9283
  ], Ye.prototype, "slottedCount", 2);
9284
9284
  Ct([
9285
- T(".track")
9285
+ B(".track")
9286
9286
  ], Ye.prototype, "trackEl", 2);
9287
9287
  k("ok-carousel", Ye);
9288
9288
  var jl = Object.defineProperty, Ll = Object.getOwnPropertyDescriptor, zt = (n, e, t, o) => {
@@ -9478,7 +9478,7 @@ zt([
9478
9478
  l({ attribute: !1 })
9479
9479
  ], We.prototype, "labels", 2);
9480
9480
  zt([
9481
- T("canvas")
9481
+ B("canvas")
9482
9482
  ], We.prototype, "canvas", 2);
9483
9483
  k("ok-signature", We);
9484
9484
  var Tl = Object.defineProperty, Bl = Object.getOwnPropertyDescriptor, Wt = (n, e, t, o) => {
@@ -10275,7 +10275,7 @@ $e([
10275
10275
  v()
10276
10276
  ], se.prototype, "muted", 2);
10277
10277
  $e([
10278
- T("audio")
10278
+ B("audio")
10279
10279
  ], se.prototype, "audioEl", 2);
10280
10280
  k("ok-audio", se);
10281
10281
  var oc = Object.defineProperty, ic = Object.getOwnPropertyDescriptor, ne = (n, e, t, o) => {
@@ -10594,10 +10594,10 @@ ne([
10594
10594
  v()
10595
10595
  ], G.prototype, "muted", 2);
10596
10596
  ne([
10597
- T("video")
10597
+ B("video")
10598
10598
  ], G.prototype, "videoEl", 2);
10599
10599
  ne([
10600
- T(".stage")
10600
+ B(".stage")
10601
10601
  ], G.prototype, "stageEl", 2);
10602
10602
  k("ok-video", G);
10603
10603
  var sc = Object.defineProperty, nc = Object.getOwnPropertyDescriptor, uo = (n, e, t, o) => {
@@ -11949,7 +11949,7 @@ Xe([
11949
11949
  v()
11950
11950
  ], Ce.prototype, "activeIndex", 2);
11951
11951
  Xe([
11952
- T(".search input")
11952
+ B(".search input")
11953
11953
  ], Ce.prototype, "searchInput", 2);
11954
11954
  k("ok-command-palette", Ce);
11955
11955
  var $c = Object.defineProperty, Cc = Object.getOwnPropertyDescriptor, Gt = (n, e, t, o) => {
@@ -12131,7 +12131,7 @@ Gt([
12131
12131
  l({ attribute: "trigger-label" })
12132
12132
  ], Et.prototype, "triggerLabel", 2);
12133
12133
  Gt([
12134
- T(".top input")
12134
+ B(".top input")
12135
12135
  ], Et.prototype, "input", 2);
12136
12136
  k("ok-spotlight-search", Et);
12137
12137
  var zc = Object.defineProperty, _c = Object.getOwnPropertyDescriptor, ze = (n, e, t, o) => {
@@ -18002,10 +18002,10 @@ I([
18002
18002
  v()
18003
18003
  ], L.prototype, "above", 2);
18004
18004
  I([
18005
- T(".card")
18005
+ B(".card")
18006
18006
  ], L.prototype, "cardEl", 2);
18007
18007
  I([
18008
- T(".trigger")
18008
+ B(".trigger")
18009
18009
  ], L.prototype, "triggerEl", 2);
18010
18010
  k("ok-hover-card", L);
18011
18011
  var qd = Object.defineProperty, Ud = Object.getOwnPropertyDescriptor, nr = (n, e, t, o) => {
@@ -19345,7 +19345,7 @@ var tp = Object.defineProperty, rp = Object.getOwnPropertyDescriptor, U = (n, e,
19345
19345
  (a = n[i]) && (r = (o ? a(e, t, r) : a(r)) || r);
19346
19346
  return o && r && tp(e, t, r), r;
19347
19347
  };
19348
- class F extends g {
19348
+ class R extends g {
19349
19349
  constructor() {
19350
19350
  super(...arguments), this.title = "", this.variant = "info", this.mode = "http", this.shortcuts = [], this.checks = [], this.detailsLabel = "Detalles técnicos", this.retryLabel = "Reintentando en", this.retrySeconds = 0, this.remaining = 0, this.initialSeconds = 0;
19351
19351
  }
@@ -19809,44 +19809,44 @@ class F extends g {
19809
19809
  }
19810
19810
  U([
19811
19811
  l()
19812
- ], F.prototype, "code", 2);
19812
+ ], R.prototype, "code", 2);
19813
19813
  U([
19814
19814
  l()
19815
- ], F.prototype, "title", 2);
19815
+ ], R.prototype, "title", 2);
19816
19816
  U([
19817
19817
  l()
19818
- ], F.prototype, "message", 2);
19818
+ ], R.prototype, "message", 2);
19819
19819
  U([
19820
19820
  l({ reflect: !0 })
19821
- ], F.prototype, "variant", 2);
19821
+ ], R.prototype, "variant", 2);
19822
19822
  U([
19823
19823
  l({ reflect: !0 })
19824
- ], F.prototype, "mode", 2);
19824
+ ], R.prototype, "mode", 2);
19825
19825
  U([
19826
19826
  l({ attribute: !1 })
19827
- ], F.prototype, "shortcuts", 2);
19827
+ ], R.prototype, "shortcuts", 2);
19828
19828
  U([
19829
19829
  l({ attribute: !1 })
19830
- ], F.prototype, "checks", 2);
19830
+ ], R.prototype, "checks", 2);
19831
19831
  U([
19832
19832
  l()
19833
- ], F.prototype, "trace", 2);
19833
+ ], R.prototype, "trace", 2);
19834
19834
  U([
19835
19835
  l({ attribute: "details-label" })
19836
- ], F.prototype, "detailsLabel", 2);
19836
+ ], R.prototype, "detailsLabel", 2);
19837
19837
  U([
19838
19838
  l()
19839
- ], F.prototype, "meta", 2);
19839
+ ], R.prototype, "meta", 2);
19840
19840
  U([
19841
19841
  l({ attribute: "retry-label" })
19842
- ], F.prototype, "retryLabel", 2);
19842
+ ], R.prototype, "retryLabel", 2);
19843
19843
  U([
19844
19844
  l({ type: Number, attribute: "retry-seconds" })
19845
- ], F.prototype, "retrySeconds", 2);
19845
+ ], R.prototype, "retrySeconds", 2);
19846
19846
  U([
19847
19847
  v()
19848
- ], F.prototype, "remaining", 2);
19849
- k("ok-error-page", F);
19848
+ ], R.prototype, "remaining", 2);
19849
+ k("ok-error-page", R);
19850
19850
  var op = Object.defineProperty, ip = Object.getOwnPropertyDescriptor, Lt = (n, e, t, o) => {
19851
19851
  for (var r = o > 1 ? void 0 : o ? ip(e, t) : e, i = n.length - 1, a; i >= 0; i--)
19852
19852
  (a = n[i]) && (r = (o ? a(e, t, r) : a(r)) || r);
@@ -20575,7 +20575,7 @@ ue([
20575
20575
  v()
20576
20576
  ], J.prototype, "words", 2);
20577
20577
  ue([
20578
- T(".content")
20578
+ B(".content")
20579
20579
  ], J.prototype, "contentEl", 2);
20580
20580
  let np = J;
20581
20581
  k("ok-rich-text", np);
@@ -21961,7 +21961,7 @@ var zp = Object.defineProperty, _p = Object.getOwnPropertyDescriptor, V = (n, e,
21961
21961
  (a = n[i]) && (r = (o ? a(e, t, r) : a(r)) || r);
21962
21962
  return o && r && zp(e, t, r), r;
21963
21963
  };
21964
- class R extends g {
21964
+ class N extends g {
21965
21965
  constructor() {
21966
21966
  super(...arguments), this.src = "", this.alt = "", this.ratio = "16:9", this.radius = "md", this.zoom = "none", this.placeholderText = "cargando…", this.loaded = !1, this.errored = !1, this.zooming = !1, this.lightboxOpen = !1, this.lensX = 50, this.lensY = 50, this.closeLightbox = () => {
21967
21967
  this.lightboxOpen = !1;
@@ -22348,44 +22348,44 @@ class R extends g {
22348
22348
  }
22349
22349
  V([
22350
22350
  l()
22351
- ], R.prototype, "src", 2);
22351
+ ], N.prototype, "src", 2);
22352
22352
  V([
22353
22353
  l()
22354
- ], R.prototype, "alt", 2);
22354
+ ], N.prototype, "alt", 2);
22355
22355
  V([
22356
22356
  l({ reflect: !0 })
22357
- ], R.prototype, "ratio", 2);
22357
+ ], N.prototype, "ratio", 2);
22358
22358
  V([
22359
22359
  l()
22360
- ], R.prototype, "caption", 2);
22360
+ ], N.prototype, "caption", 2);
22361
22361
  V([
22362
22362
  l({ reflect: !0 })
22363
- ], R.prototype, "radius", 2);
22363
+ ], N.prototype, "radius", 2);
22364
22364
  V([
22365
22365
  l({ reflect: !0 })
22366
- ], R.prototype, "zoom", 2);
22366
+ ], N.prototype, "zoom", 2);
22367
22367
  V([
22368
22368
  l({ attribute: "placeholder-text" })
22369
- ], R.prototype, "placeholderText", 2);
22369
+ ], N.prototype, "placeholderText", 2);
22370
22370
  V([
22371
22371
  v()
22372
- ], R.prototype, "loaded", 2);
22372
+ ], N.prototype, "loaded", 2);
22373
22373
  V([
22374
22374
  v()
22375
- ], R.prototype, "errored", 2);
22375
+ ], N.prototype, "errored", 2);
22376
22376
  V([
22377
22377
  v()
22378
- ], R.prototype, "zooming", 2);
22378
+ ], N.prototype, "zooming", 2);
22379
22379
  V([
22380
22380
  v()
22381
- ], R.prototype, "lightboxOpen", 2);
22381
+ ], N.prototype, "lightboxOpen", 2);
22382
22382
  V([
22383
22383
  v()
22384
- ], R.prototype, "lensX", 2);
22384
+ ], N.prototype, "lensX", 2);
22385
22385
  V([
22386
22386
  v()
22387
- ], R.prototype, "lensY", 2);
22388
- k("ok-image", R);
22387
+ ], N.prototype, "lensY", 2);
22388
+ k("ok-image", N);
22389
22389
  var Sp = Object.defineProperty, Ep = Object.getOwnPropertyDescriptor, Kr = (n, e, t, o) => {
22390
22390
  for (var r = o > 1 ? void 0 : o ? Ep(e, t) : e, i = n.length - 1, a; i >= 0; i--)
22391
22391
  (a = n[i]) && (r = (o ? a(e, t, r) : a(r)) || r);
@@ -24987,7 +24987,7 @@ it([
24987
24987
  v()
24988
24988
  ], De.prototype, "collapsed", 2);
24989
24989
  k("ok-org-chart", De);
24990
- var Wp = Object.defineProperty, Xp = Object.getOwnPropertyDescriptor, N = (n, e, t, o) => {
24990
+ var Wp = Object.defineProperty, Xp = Object.getOwnPropertyDescriptor, F = (n, e, t, o) => {
24991
24991
  for (var r = o > 1 ? void 0 : o ? Xp(e, t) : e, i = n.length - 1, a; i >= 0; i--)
24992
24992
  (a = n[i]) && (r = (o ? a(e, t, r) : a(r)) || r);
24993
24993
  return o && r && Wp(e, t, r), r;
@@ -25003,9 +25003,12 @@ const Gp = {
25003
25003
  delete: "Eliminar",
25004
25004
  open: "Abrir",
25005
25005
  newFolder: "Nueva carpeta",
25006
+ rename: "Renombrar",
25007
+ renameFolder: "Renombrar carpeta",
25008
+ deleteFolder: "Eliminar carpeta",
25006
25009
  noLimit: "Sin límite"
25007
25010
  };
25008
- class B extends g {
25011
+ class T extends g {
25009
25012
  constructor() {
25010
25013
  super(...arguments), this.folders = [], this.files = [], this.path = [], this.selected = "", this.view = "grid", this.title = "", this.searchable = !0, this.uploadable = !0, this.loading = !1, this.labels = {}, this.expandedIds = /* @__PURE__ */ new Set(), this.dragging = !1, this.seeded = !1;
25011
25014
  }
@@ -25513,6 +25516,11 @@ class B extends g {
25513
25516
  .action.danger:hover {
25514
25517
  color: var(--danger);
25515
25518
  }
25519
+ /* Borrar la carpeta actual: se tiñe al pasar por encima, igual que el borrado de un fichero. */
25520
+ .tbtn.danger:hover {
25521
+ color: var(--danger);
25522
+ border-color: var(--danger);
25523
+ }
25516
25524
  .action svg {
25517
25525
  width: 15px;
25518
25526
  height: 15px;
@@ -25612,6 +25620,9 @@ class B extends g {
25612
25620
  }
25613
25621
  `;
25614
25622
  }
25623
+ can(e) {
25624
+ return this.policy ? this.policy[e] : !0;
25625
+ }
25615
25626
  // Textos efectivos.
25616
25627
  get t() {
25617
25628
  return { ...Gp, ...this.labels };
@@ -25635,7 +25646,21 @@ class B extends g {
25635
25646
  this.emit("ok-download", { id: e.id, url: e.url });
25636
25647
  }
25637
25648
  deleteFile(e) {
25638
- this.emit("ok-delete", { id: e });
25649
+ this.emit("ok-delete", { id: e, kind: "file" });
25650
+ }
25651
+ /** Renombrar un fichero. Se manda el nombre actual para que el host lo proponga en su diálogo. */
25652
+ renameFile(e) {
25653
+ this.emit("ok-rename", { id: e.id, name: e.name, kind: "file" });
25654
+ }
25655
+ /** Etiqueta de la carpeta actual (para proponerla como nombre al renombrar). */
25656
+ get currentFolderLabel() {
25657
+ return this.path[this.path.length - 1]?.label ?? this.selected.split("/").pop() ?? "";
25658
+ }
25659
+ renameCurrentFolder() {
25660
+ this.emit("ok-rename", { id: this.selected, name: this.currentFolderLabel, kind: "folder" });
25661
+ }
25662
+ deleteCurrentFolder() {
25663
+ this.emit("ok-delete", { id: this.selected, kind: "folder" });
25639
25664
  }
25640
25665
  createFolder() {
25641
25666
  this.emit("ok-create-folder", { parent: this.selected });
@@ -25811,23 +25836,47 @@ class B extends g {
25811
25836
  </button>
25812
25837
  </div>
25813
25838
 
25814
- <button
25815
- type="button"
25816
- class="tbtn icon"
25817
- aria-label=${this.t.newFolder}
25818
- title=${this.t.newFolder}
25819
- @click=${() => this.createFolder()}
25820
- >
25821
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
25822
- stroke-linecap="round" stroke-linejoin="round">
25823
- <path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
25824
- <path d="M12 11v6M9 14h6" />
25825
- </svg>
25826
- </button>
25839
+ ${this.selected && this.can("rename") ? s`<button
25840
+ type="button"
25841
+ class="tbtn icon"
25842
+ data-act="rename-folder"
25843
+ aria-label=${this.t.renameFolder}
25844
+ title=${this.t.renameFolder}
25845
+ @click=${() => this.renameCurrentFolder()}
25846
+ >
25847
+ ${this.iconRename}
25848
+ </button>` : ""}
25849
+
25850
+ ${this.selected && this.can("delete") ? s`<button
25851
+ type="button"
25852
+ class="tbtn icon danger"
25853
+ data-act="delete-folder"
25854
+ aria-label=${this.t.deleteFolder}
25855
+ title=${this.t.deleteFolder}
25856
+ @click=${() => this.deleteCurrentFolder()}
25857
+ >
25858
+ ${this.iconDelete}
25859
+ </button>` : ""}
25827
25860
 
25828
- ${this.uploadable ? s`<button
25861
+ ${this.can("upload") ? s`<button
25862
+ type="button"
25863
+ class="tbtn icon"
25864
+ data-act="new-folder"
25865
+ aria-label=${this.t.newFolder}
25866
+ title=${this.t.newFolder}
25867
+ @click=${() => this.createFolder()}
25868
+ >
25869
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
25870
+ stroke-linecap="round" stroke-linejoin="round">
25871
+ <path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
25872
+ <path d="M12 11v6M9 14h6" />
25873
+ </svg>
25874
+ </button>` : ""}
25875
+
25876
+ ${this.uploadable && this.can("upload") ? s`<button
25829
25877
  type="button"
25830
25878
  class="tbtn primary icon"
25879
+ data-act="upload"
25831
25880
  aria-label=${this.t.upload}
25832
25881
  title=${this.t.upload}
25833
25882
  @click=${() => this.openPicker()}
@@ -25854,17 +25903,25 @@ class B extends g {
25854
25903
  <polyline points="7 10 12 15 17 10" /><line x1="12" y1="15" x2="12" y2="3" />
25855
25904
  </svg>`;
25856
25905
  }
25906
+ get iconRename() {
25907
+ return s`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
25908
+ stroke-linecap="round" stroke-linejoin="round">
25909
+ <path d="M12 20h9" /><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z" />
25910
+ </svg>`;
25911
+ }
25857
25912
  get iconDelete() {
25858
25913
  return s`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
25859
25914
  stroke-linecap="round" stroke-linejoin="round">
25860
25915
  <path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
25861
25916
  </svg>`;
25862
25917
  }
25863
- // Acciones de un archivo (abrir/descargar/eliminar), reutilizadas en grid y lista.
25918
+ // Acciones de un archivo, reutilizadas en grid y lista. Abrir y descargar SIEMPRE se ofrecen;
25919
+ // renombrar y borrar solo si la política de la carpeta los concede.
25864
25920
  fileActions(e) {
25865
25921
  return s`<button
25866
25922
  type="button"
25867
25923
  class="action"
25924
+ data-act="open"
25868
25925
  aria-label=${this.t.open}
25869
25926
  title=${this.t.open}
25870
25927
  @click=${(t) => {
@@ -25876,6 +25933,7 @@ class B extends g {
25876
25933
  <button
25877
25934
  type="button"
25878
25935
  class="action"
25936
+ data-act="download"
25879
25937
  aria-label=${this.t.download}
25880
25938
  title=${this.t.download}
25881
25939
  @click=${(t) => {
@@ -25884,17 +25942,30 @@ class B extends g {
25884
25942
  >
25885
25943
  ${this.iconDownload}
25886
25944
  </button>
25887
- <button
25888
- type="button"
25889
- class="action danger"
25890
- aria-label=${this.t.delete}
25891
- title=${this.t.delete}
25892
- @click=${(t) => {
25945
+ ${this.can("rename") ? s`<button
25946
+ type="button"
25947
+ class="action"
25948
+ data-act="rename-file"
25949
+ aria-label=${this.t.rename}
25950
+ title=${this.t.rename}
25951
+ @click=${(t) => {
25952
+ t.stopPropagation(), this.renameFile(e);
25953
+ }}
25954
+ >
25955
+ ${this.iconRename}
25956
+ </button>` : ""}
25957
+ ${this.can("delete") ? s`<button
25958
+ type="button"
25959
+ class="action danger"
25960
+ data-act="delete-file"
25961
+ aria-label=${this.t.delete}
25962
+ title=${this.t.delete}
25963
+ @click=${(t) => {
25893
25964
  t.stopPropagation(), this.deleteFile(e.id);
25894
25965
  }}
25895
- >
25896
- ${this.iconDelete}
25897
- </button>`;
25966
+ >
25967
+ ${this.iconDelete}
25968
+ </button>` : ""}`;
25898
25969
  }
25899
25970
  // ---- Render del contenido (grid/lista/vacío/loading) ----
25900
25971
  renderContent() {
@@ -25991,46 +26062,49 @@ class B extends g {
25991
26062
  <input type="file" multiple @change=${this.onPicked} />`;
25992
26063
  }
25993
26064
  }
25994
- N([
26065
+ F([
25995
26066
  l({ attribute: !1 })
25996
- ], B.prototype, "folders", 2);
25997
- N([
26067
+ ], T.prototype, "folders", 2);
26068
+ F([
25998
26069
  l({ attribute: !1 })
25999
- ], B.prototype, "files", 2);
26000
- N([
26070
+ ], T.prototype, "files", 2);
26071
+ F([
26001
26072
  l({ attribute: !1 })
26002
- ], B.prototype, "path", 2);
26003
- N([
26073
+ ], T.prototype, "path", 2);
26074
+ F([
26004
26075
  l()
26005
- ], B.prototype, "selected", 2);
26006
- N([
26076
+ ], T.prototype, "selected", 2);
26077
+ F([
26007
26078
  l()
26008
- ], B.prototype, "view", 2);
26009
- N([
26079
+ ], T.prototype, "view", 2);
26080
+ F([
26010
26081
  l({ attribute: !1 })
26011
- ], B.prototype, "quota", 2);
26012
- N([
26082
+ ], T.prototype, "quota", 2);
26083
+ F([
26013
26084
  l()
26014
- ], B.prototype, "title", 2);
26015
- N([
26085
+ ], T.prototype, "title", 2);
26086
+ F([
26016
26087
  l({ type: Boolean })
26017
- ], B.prototype, "searchable", 2);
26018
- N([
26088
+ ], T.prototype, "searchable", 2);
26089
+ F([
26019
26090
  l({ type: Boolean })
26020
- ], B.prototype, "uploadable", 2);
26021
- N([
26091
+ ], T.prototype, "uploadable", 2);
26092
+ F([
26093
+ l({ attribute: !1 })
26094
+ ], T.prototype, "policy", 2);
26095
+ F([
26022
26096
  l({ type: Boolean })
26023
- ], B.prototype, "loading", 2);
26024
- N([
26097
+ ], T.prototype, "loading", 2);
26098
+ F([
26025
26099
  l({ attribute: !1 })
26026
- ], B.prototype, "labels", 2);
26027
- N([
26100
+ ], T.prototype, "labels", 2);
26101
+ F([
26028
26102
  v()
26029
- ], B.prototype, "expandedIds", 2);
26030
- N([
26103
+ ], T.prototype, "expandedIds", 2);
26104
+ F([
26031
26105
  v()
26032
- ], B.prototype, "dragging", 2);
26033
- N([
26034
- T('input[type="file"]')
26035
- ], B.prototype, "fileInput", 2);
26036
- k("ok-file-manager", B);
26106
+ ], T.prototype, "dragging", 2);
26107
+ F([
26108
+ B('input[type="file"]')
26109
+ ], T.prototype, "fileInput", 2);
26110
+ k("ok-file-manager", T);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@erplora/outfitkit",
3
- "version": "0.1.28",
3
+ "version": "0.1.29",
4
4
  "description": "OutfitKit — librería de Web Components (Lit) que CONSTRUYE lo que Ionic no tiene (tree, data-table rica, inline-feedback, kpi/stat, stepper/wizard, calendar, kanban…) sobre primitivos de Ionic. Ionic es la base; OutfitKit cubre los huecos. npm + CDN, imports individuales, CSP-safe. Tema vía tokens --ok-* (fallback a --ion-*).",
5
5
  "type": "module",
6
6
  "license": "MIT",