@erplora/outfitkit 0.1.27 → 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).
@@ -0,0 +1 @@
1
+ import './ok-cta-band.js';
@@ -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';
@@ -20,12 +20,29 @@ class OkCtaBand extends LitElement {
20
20
  :host {
21
21
  display: block;
22
22
  width: 100%;
23
- --primary: var(--ion-color-primary, #1496d6);
24
- --primary-contrast: var(--ion-color-primary-contrast, #ffffff);
23
+ --primary: var(--ok-primary, var(--ion-color-primary, #1496d6));
24
+ --primary-contrast: var(--ok-primary-contrast, var(--ion-color-primary-contrast, #ffffff));
25
25
  --color: var(--ok-text, var(--ion-text-color, #18181b));
26
26
  --muted: var(--ok-muted, rgba(var(--ion-text-color-rgb, 24, 24, 27), 0.62));
27
27
  --surface: var(--ok-surface, var(--ion-card-background, var(--ion-background-color, #fff)));
28
28
  --radius: var(--ok-radius-lg, 28px);
29
+ --action-outline-color: var(--ok-cta-action-outline-color, var(--primary-contrast));
30
+ --action-outline-border-color: var(
31
+ --ok-cta-action-outline-border-color,
32
+ color-mix(in oklab, var(--action-outline-color) 62%, transparent)
33
+ );
34
+ --action-outline-background-hover: var(
35
+ --ok-cta-action-outline-background-hover,
36
+ color-mix(in oklab, var(--action-outline-color) 12%, transparent)
37
+ );
38
+ --action-outline-background-focused: var(
39
+ --ok-cta-action-outline-background-focused,
40
+ color-mix(in oklab, var(--action-outline-color) 16%, transparent)
41
+ );
42
+ --action-outline-background-activated: var(
43
+ --ok-cta-action-outline-background-activated,
44
+ color-mix(in oklab, var(--action-outline-color) 20%, transparent)
45
+ );
29
46
  font-family: var(--ok-font, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif);
30
47
  }
31
48
  .band {
@@ -106,6 +123,18 @@ class OkCtaBand extends LitElement {
106
123
  justify-content: center;
107
124
  margin-top: 0.6rem;
108
125
  }
126
+ :host(:not([variant])) ::slotted(ion-button[fill='outline']),
127
+ :host([variant='solid']) ::slotted(ion-button[fill='outline']) {
128
+ --color: var(--action-outline-color);
129
+ --color-hover: var(--action-outline-color);
130
+ --color-focused: var(--action-outline-color);
131
+ --color-activated: var(--action-outline-color);
132
+ --border-color: var(--action-outline-border-color);
133
+ --background-hover: var(--action-outline-background-hover);
134
+ --background-focused: var(--action-outline-background-focused);
135
+ --background-activated: var(--action-outline-background-activated);
136
+ --ripple-color: var(--action-outline-color);
137
+ }
109
138
  `;
110
139
  }
111
140
  render() {
@@ -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) => {
@@ -14023,12 +14023,29 @@ class Ir extends g {
14023
14023
  :host {
14024
14024
  display: block;
14025
14025
  width: 100%;
14026
- --primary: var(--ion-color-primary, #1496d6);
14027
- --primary-contrast: var(--ion-color-primary-contrast, #ffffff);
14026
+ --primary: var(--ok-primary, var(--ion-color-primary, #1496d6));
14027
+ --primary-contrast: var(--ok-primary-contrast, var(--ion-color-primary-contrast, #ffffff));
14028
14028
  --color: var(--ok-text, var(--ion-text-color, #18181b));
14029
14029
  --muted: var(--ok-muted, rgba(var(--ion-text-color-rgb, 24, 24, 27), 0.62));
14030
14030
  --surface: var(--ok-surface, var(--ion-card-background, var(--ion-background-color, #fff)));
14031
14031
  --radius: var(--ok-radius-lg, 28px);
14032
+ --action-outline-color: var(--ok-cta-action-outline-color, var(--primary-contrast));
14033
+ --action-outline-border-color: var(
14034
+ --ok-cta-action-outline-border-color,
14035
+ color-mix(in oklab, var(--action-outline-color) 62%, transparent)
14036
+ );
14037
+ --action-outline-background-hover: var(
14038
+ --ok-cta-action-outline-background-hover,
14039
+ color-mix(in oklab, var(--action-outline-color) 12%, transparent)
14040
+ );
14041
+ --action-outline-background-focused: var(
14042
+ --ok-cta-action-outline-background-focused,
14043
+ color-mix(in oklab, var(--action-outline-color) 16%, transparent)
14044
+ );
14045
+ --action-outline-background-activated: var(
14046
+ --ok-cta-action-outline-background-activated,
14047
+ color-mix(in oklab, var(--action-outline-color) 20%, transparent)
14048
+ );
14032
14049
  font-family: var(--ok-font, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif);
14033
14050
  }
14034
14051
  .band {
@@ -14109,6 +14126,18 @@ class Ir extends g {
14109
14126
  justify-content: center;
14110
14127
  margin-top: 0.6rem;
14111
14128
  }
14129
+ :host(:not([variant])) ::slotted(ion-button[fill='outline']),
14130
+ :host([variant='solid']) ::slotted(ion-button[fill='outline']) {
14131
+ --color: var(--action-outline-color);
14132
+ --color-hover: var(--action-outline-color);
14133
+ --color-focused: var(--action-outline-color);
14134
+ --color-activated: var(--action-outline-color);
14135
+ --border-color: var(--action-outline-border-color);
14136
+ --background-hover: var(--action-outline-background-hover);
14137
+ --background-focused: var(--action-outline-background-focused);
14138
+ --background-activated: var(--action-outline-background-activated);
14139
+ --ripple-color: var(--action-outline-color);
14140
+ }
14112
14141
  `;
14113
14142
  }
14114
14143
  render() {
@@ -17973,10 +18002,10 @@ I([
17973
18002
  v()
17974
18003
  ], L.prototype, "above", 2);
17975
18004
  I([
17976
- T(".card")
18005
+ B(".card")
17977
18006
  ], L.prototype, "cardEl", 2);
17978
18007
  I([
17979
- T(".trigger")
18008
+ B(".trigger")
17980
18009
  ], L.prototype, "triggerEl", 2);
17981
18010
  k("ok-hover-card", L);
17982
18011
  var qd = Object.defineProperty, Ud = Object.getOwnPropertyDescriptor, nr = (n, e, t, o) => {
@@ -19316,7 +19345,7 @@ var tp = Object.defineProperty, rp = Object.getOwnPropertyDescriptor, U = (n, e,
19316
19345
  (a = n[i]) && (r = (o ? a(e, t, r) : a(r)) || r);
19317
19346
  return o && r && tp(e, t, r), r;
19318
19347
  };
19319
- class F extends g {
19348
+ class R extends g {
19320
19349
  constructor() {
19321
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;
19322
19351
  }
@@ -19780,44 +19809,44 @@ class F extends g {
19780
19809
  }
19781
19810
  U([
19782
19811
  l()
19783
- ], F.prototype, "code", 2);
19812
+ ], R.prototype, "code", 2);
19784
19813
  U([
19785
19814
  l()
19786
- ], F.prototype, "title", 2);
19815
+ ], R.prototype, "title", 2);
19787
19816
  U([
19788
19817
  l()
19789
- ], F.prototype, "message", 2);
19818
+ ], R.prototype, "message", 2);
19790
19819
  U([
19791
19820
  l({ reflect: !0 })
19792
- ], F.prototype, "variant", 2);
19821
+ ], R.prototype, "variant", 2);
19793
19822
  U([
19794
19823
  l({ reflect: !0 })
19795
- ], F.prototype, "mode", 2);
19824
+ ], R.prototype, "mode", 2);
19796
19825
  U([
19797
19826
  l({ attribute: !1 })
19798
- ], F.prototype, "shortcuts", 2);
19827
+ ], R.prototype, "shortcuts", 2);
19799
19828
  U([
19800
19829
  l({ attribute: !1 })
19801
- ], F.prototype, "checks", 2);
19830
+ ], R.prototype, "checks", 2);
19802
19831
  U([
19803
19832
  l()
19804
- ], F.prototype, "trace", 2);
19833
+ ], R.prototype, "trace", 2);
19805
19834
  U([
19806
19835
  l({ attribute: "details-label" })
19807
- ], F.prototype, "detailsLabel", 2);
19836
+ ], R.prototype, "detailsLabel", 2);
19808
19837
  U([
19809
19838
  l()
19810
- ], F.prototype, "meta", 2);
19839
+ ], R.prototype, "meta", 2);
19811
19840
  U([
19812
19841
  l({ attribute: "retry-label" })
19813
- ], F.prototype, "retryLabel", 2);
19842
+ ], R.prototype, "retryLabel", 2);
19814
19843
  U([
19815
19844
  l({ type: Number, attribute: "retry-seconds" })
19816
- ], F.prototype, "retrySeconds", 2);
19845
+ ], R.prototype, "retrySeconds", 2);
19817
19846
  U([
19818
19847
  v()
19819
- ], F.prototype, "remaining", 2);
19820
- k("ok-error-page", F);
19848
+ ], R.prototype, "remaining", 2);
19849
+ k("ok-error-page", R);
19821
19850
  var op = Object.defineProperty, ip = Object.getOwnPropertyDescriptor, Lt = (n, e, t, o) => {
19822
19851
  for (var r = o > 1 ? void 0 : o ? ip(e, t) : e, i = n.length - 1, a; i >= 0; i--)
19823
19852
  (a = n[i]) && (r = (o ? a(e, t, r) : a(r)) || r);
@@ -20546,7 +20575,7 @@ ue([
20546
20575
  v()
20547
20576
  ], J.prototype, "words", 2);
20548
20577
  ue([
20549
- T(".content")
20578
+ B(".content")
20550
20579
  ], J.prototype, "contentEl", 2);
20551
20580
  let np = J;
20552
20581
  k("ok-rich-text", np);
@@ -21932,7 +21961,7 @@ var zp = Object.defineProperty, _p = Object.getOwnPropertyDescriptor, V = (n, e,
21932
21961
  (a = n[i]) && (r = (o ? a(e, t, r) : a(r)) || r);
21933
21962
  return o && r && zp(e, t, r), r;
21934
21963
  };
21935
- class R extends g {
21964
+ class N extends g {
21936
21965
  constructor() {
21937
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 = () => {
21938
21967
  this.lightboxOpen = !1;
@@ -22319,44 +22348,44 @@ class R extends g {
22319
22348
  }
22320
22349
  V([
22321
22350
  l()
22322
- ], R.prototype, "src", 2);
22351
+ ], N.prototype, "src", 2);
22323
22352
  V([
22324
22353
  l()
22325
- ], R.prototype, "alt", 2);
22354
+ ], N.prototype, "alt", 2);
22326
22355
  V([
22327
22356
  l({ reflect: !0 })
22328
- ], R.prototype, "ratio", 2);
22357
+ ], N.prototype, "ratio", 2);
22329
22358
  V([
22330
22359
  l()
22331
- ], R.prototype, "caption", 2);
22360
+ ], N.prototype, "caption", 2);
22332
22361
  V([
22333
22362
  l({ reflect: !0 })
22334
- ], R.prototype, "radius", 2);
22363
+ ], N.prototype, "radius", 2);
22335
22364
  V([
22336
22365
  l({ reflect: !0 })
22337
- ], R.prototype, "zoom", 2);
22366
+ ], N.prototype, "zoom", 2);
22338
22367
  V([
22339
22368
  l({ attribute: "placeholder-text" })
22340
- ], R.prototype, "placeholderText", 2);
22369
+ ], N.prototype, "placeholderText", 2);
22341
22370
  V([
22342
22371
  v()
22343
- ], R.prototype, "loaded", 2);
22372
+ ], N.prototype, "loaded", 2);
22344
22373
  V([
22345
22374
  v()
22346
- ], R.prototype, "errored", 2);
22375
+ ], N.prototype, "errored", 2);
22347
22376
  V([
22348
22377
  v()
22349
- ], R.prototype, "zooming", 2);
22378
+ ], N.prototype, "zooming", 2);
22350
22379
  V([
22351
22380
  v()
22352
- ], R.prototype, "lightboxOpen", 2);
22381
+ ], N.prototype, "lightboxOpen", 2);
22353
22382
  V([
22354
22383
  v()
22355
- ], R.prototype, "lensX", 2);
22384
+ ], N.prototype, "lensX", 2);
22356
22385
  V([
22357
22386
  v()
22358
- ], R.prototype, "lensY", 2);
22359
- k("ok-image", R);
22387
+ ], N.prototype, "lensY", 2);
22388
+ k("ok-image", N);
22360
22389
  var Sp = Object.defineProperty, Ep = Object.getOwnPropertyDescriptor, Kr = (n, e, t, o) => {
22361
22390
  for (var r = o > 1 ? void 0 : o ? Ep(e, t) : e, i = n.length - 1, a; i >= 0; i--)
22362
22391
  (a = n[i]) && (r = (o ? a(e, t, r) : a(r)) || r);
@@ -24958,7 +24987,7 @@ it([
24958
24987
  v()
24959
24988
  ], De.prototype, "collapsed", 2);
24960
24989
  k("ok-org-chart", De);
24961
- 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) => {
24962
24991
  for (var r = o > 1 ? void 0 : o ? Xp(e, t) : e, i = n.length - 1, a; i >= 0; i--)
24963
24992
  (a = n[i]) && (r = (o ? a(e, t, r) : a(r)) || r);
24964
24993
  return o && r && Wp(e, t, r), r;
@@ -24974,9 +25003,12 @@ const Gp = {
24974
25003
  delete: "Eliminar",
24975
25004
  open: "Abrir",
24976
25005
  newFolder: "Nueva carpeta",
25006
+ rename: "Renombrar",
25007
+ renameFolder: "Renombrar carpeta",
25008
+ deleteFolder: "Eliminar carpeta",
24977
25009
  noLimit: "Sin límite"
24978
25010
  };
24979
- class B extends g {
25011
+ class T extends g {
24980
25012
  constructor() {
24981
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;
24982
25014
  }
@@ -25484,6 +25516,11 @@ class B extends g {
25484
25516
  .action.danger:hover {
25485
25517
  color: var(--danger);
25486
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
+ }
25487
25524
  .action svg {
25488
25525
  width: 15px;
25489
25526
  height: 15px;
@@ -25583,6 +25620,9 @@ class B extends g {
25583
25620
  }
25584
25621
  `;
25585
25622
  }
25623
+ can(e) {
25624
+ return this.policy ? this.policy[e] : !0;
25625
+ }
25586
25626
  // Textos efectivos.
25587
25627
  get t() {
25588
25628
  return { ...Gp, ...this.labels };
@@ -25606,7 +25646,21 @@ class B extends g {
25606
25646
  this.emit("ok-download", { id: e.id, url: e.url });
25607
25647
  }
25608
25648
  deleteFile(e) {
25609
- 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" });
25610
25664
  }
25611
25665
  createFolder() {
25612
25666
  this.emit("ok-create-folder", { parent: this.selected });
@@ -25782,23 +25836,47 @@ class B extends g {
25782
25836
  </button>
25783
25837
  </div>
25784
25838
 
25785
- <button
25786
- type="button"
25787
- class="tbtn icon"
25788
- aria-label=${this.t.newFolder}
25789
- title=${this.t.newFolder}
25790
- @click=${() => this.createFolder()}
25791
- >
25792
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
25793
- stroke-linecap="round" stroke-linejoin="round">
25794
- <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" />
25795
- <path d="M12 11v6M9 14h6" />
25796
- </svg>
25797
- </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>` : ""}
25798
25849
 
25799
- ${this.uploadable ? s`<button
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>` : ""}
25860
+
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
25800
25877
  type="button"
25801
25878
  class="tbtn primary icon"
25879
+ data-act="upload"
25802
25880
  aria-label=${this.t.upload}
25803
25881
  title=${this.t.upload}
25804
25882
  @click=${() => this.openPicker()}
@@ -25825,17 +25903,25 @@ class B extends g {
25825
25903
  <polyline points="7 10 12 15 17 10" /><line x1="12" y1="15" x2="12" y2="3" />
25826
25904
  </svg>`;
25827
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
+ }
25828
25912
  get iconDelete() {
25829
25913
  return s`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
25830
25914
  stroke-linecap="round" stroke-linejoin="round">
25831
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" />
25832
25916
  </svg>`;
25833
25917
  }
25834
- // 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.
25835
25920
  fileActions(e) {
25836
25921
  return s`<button
25837
25922
  type="button"
25838
25923
  class="action"
25924
+ data-act="open"
25839
25925
  aria-label=${this.t.open}
25840
25926
  title=${this.t.open}
25841
25927
  @click=${(t) => {
@@ -25847,6 +25933,7 @@ class B extends g {
25847
25933
  <button
25848
25934
  type="button"
25849
25935
  class="action"
25936
+ data-act="download"
25850
25937
  aria-label=${this.t.download}
25851
25938
  title=${this.t.download}
25852
25939
  @click=${(t) => {
@@ -25855,17 +25942,30 @@ class B extends g {
25855
25942
  >
25856
25943
  ${this.iconDownload}
25857
25944
  </button>
25858
- <button
25859
- type="button"
25860
- class="action danger"
25861
- aria-label=${this.t.delete}
25862
- title=${this.t.delete}
25863
- @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) => {
25864
25964
  t.stopPropagation(), this.deleteFile(e.id);
25865
25965
  }}
25866
- >
25867
- ${this.iconDelete}
25868
- </button>`;
25966
+ >
25967
+ ${this.iconDelete}
25968
+ </button>` : ""}`;
25869
25969
  }
25870
25970
  // ---- Render del contenido (grid/lista/vacío/loading) ----
25871
25971
  renderContent() {
@@ -25962,46 +26062,49 @@ class B extends g {
25962
26062
  <input type="file" multiple @change=${this.onPicked} />`;
25963
26063
  }
25964
26064
  }
25965
- N([
26065
+ F([
25966
26066
  l({ attribute: !1 })
25967
- ], B.prototype, "folders", 2);
25968
- N([
26067
+ ], T.prototype, "folders", 2);
26068
+ F([
25969
26069
  l({ attribute: !1 })
25970
- ], B.prototype, "files", 2);
25971
- N([
26070
+ ], T.prototype, "files", 2);
26071
+ F([
25972
26072
  l({ attribute: !1 })
25973
- ], B.prototype, "path", 2);
25974
- N([
26073
+ ], T.prototype, "path", 2);
26074
+ F([
25975
26075
  l()
25976
- ], B.prototype, "selected", 2);
25977
- N([
26076
+ ], T.prototype, "selected", 2);
26077
+ F([
25978
26078
  l()
25979
- ], B.prototype, "view", 2);
25980
- N([
26079
+ ], T.prototype, "view", 2);
26080
+ F([
25981
26081
  l({ attribute: !1 })
25982
- ], B.prototype, "quota", 2);
25983
- N([
26082
+ ], T.prototype, "quota", 2);
26083
+ F([
25984
26084
  l()
25985
- ], B.prototype, "title", 2);
25986
- N([
26085
+ ], T.prototype, "title", 2);
26086
+ F([
25987
26087
  l({ type: Boolean })
25988
- ], B.prototype, "searchable", 2);
25989
- N([
26088
+ ], T.prototype, "searchable", 2);
26089
+ F([
25990
26090
  l({ type: Boolean })
25991
- ], B.prototype, "uploadable", 2);
25992
- N([
26091
+ ], T.prototype, "uploadable", 2);
26092
+ F([
26093
+ l({ attribute: !1 })
26094
+ ], T.prototype, "policy", 2);
26095
+ F([
25993
26096
  l({ type: Boolean })
25994
- ], B.prototype, "loading", 2);
25995
- N([
26097
+ ], T.prototype, "loading", 2);
26098
+ F([
25996
26099
  l({ attribute: !1 })
25997
- ], B.prototype, "labels", 2);
25998
- N([
26100
+ ], T.prototype, "labels", 2);
26101
+ F([
25999
26102
  v()
26000
- ], B.prototype, "expandedIds", 2);
26001
- N([
26103
+ ], T.prototype, "expandedIds", 2);
26104
+ F([
26002
26105
  v()
26003
- ], B.prototype, "dragging", 2);
26004
- N([
26005
- T('input[type="file"]')
26006
- ], B.prototype, "fileInput", 2);
26007
- 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.27",
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",