@dev-tcloud/tcloud-ui 7.0.2 → 7.0.4

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.
@@ -18,7 +18,7 @@ Componente de área de upload com suporte a drag-and-drop, pré-visualização d
18
18
  |------|------|---------|-----------|
19
19
  | `maxFiles` | `number \| undefined` | `undefined` | Número máximo de arquivos permitidos. Se `undefined`, não há limite. |
20
20
  | `acceptedFileTypes` | `AcceptedFileType[] \| undefined` | `undefined` | Lista de tipos MIME aceitos. Se `undefined`, todos os tipos são aceitos. Utiliza o enum `AcceptedFileType`. |
21
- | `acceptedExtensions` | `string[] \| undefined` | `undefined` | Lista de extensões de arquivo aceitas, ex: `['.doc', '.pdf']`. O ponto inicial é opcional. Validado com lógica **OU** em relação a `acceptedFileTypes`. |
21
+ | `acceptedExtensions` | `string[] \| undefined` | `undefined` | Lista de extensões de arquivo aceitas, ex: `['.doc', '.pdf', '.tar.gz']`. O ponto inicial é opcional. Suporta extensões compostas (ex.: `.tar.gz`, `.tar.bz2`), validadas por sufixo do nome do arquivo. Validado com lógica **OU** em relação a `acceptedFileTypes`. |
22
22
  | `imageDimensions` | `ImageDimensions \| undefined` | `undefined` | Dimensões permitidas para imagens (largura x altura em pixels). Se `strict: true`, valida exatamente; caso contrário, aceita até as dimensões informadas. |
23
23
  | `showProgress` | `boolean` | `false` | Exibe barra de progresso animada durante o carregamento dos arquivos. |
24
24
  | `preloadedImages` | `PreloadedImage[] \| string[]` | — | Imagens pré-carregadas para modo de edição. Aceita array de URLs (strings) ou objetos `PreloadedImage` com `url`, `key` e `order`. As imagens são baixadas e convertidas em `File`. |
@@ -180,7 +180,7 @@ existingImages: PreloadedImage[] = [
180
180
  - **Pré-visualização**: Exibe thumbnails das imagens selecionadas.
181
181
  - **Reordenação**: Arraste e solte as imagens para alterar a ordem.
182
182
  - **Remoção**: Botão "×" para remover imagens individualmente.
183
- - **Validação de tipos**: Filtra arquivos por tipo MIME usando o enum `AcceptedFileType`.
183
+ - **Validação de tipos**: Filtra arquivos por tipo MIME usando o enum `AcceptedFileType` ou por extensão (`acceptedExtensions`), incluindo extensões compostas como `.tar.gz` (validação por sufixo, aceita qualquer extensão composta configurada). A renomeação interna (`new_name`) e a exibição da extensão reconhecem nativamente `.tar.gz`, `.tar.bz2`, `.tar.xz`, `.tar.zst`, `.tar.lz` e `.tar.lzma`; outras extensões compostas fora dessa lista são validadas normalmente, mas exibidas/renomeadas usando apenas o último segmento.
184
184
  - **Validação de dimensões**: Valida largura e altura das imagens (exata ou máxima).
185
185
  - **Limite de arquivos**: Controla o número máximo de arquivos.
186
186
  - **Barra de progresso**: Exibe progresso animado durante o carregamento com efeito shimmer.
@@ -3773,7 +3773,7 @@ class TCloudUiModalComponent {
3773
3773
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: TCloudUiModalComponent, isStandalone: true, selector: "tcloud-ui-modal", inputs: { confirm: "confirm", confirmText: "confirmText", confirmInput: "confirmInput", autoClose: "autoClose", title: "title", maxWidth: "maxWidth", position: "position", sticky: "sticky", window: "window", open: "open", loading: "loading" }, outputs: { openChange: "openChange", toConfirm: "toConfirm", toCancel: "toCancel", toAction: "toAction" }, providers: [
3774
3774
  TcloudModalService,
3775
3775
  TCloudUiLayoutService
3776
- ], ngImport: i0, template: "@if (control_open) {\n <div class=\"tc-background-modal\" >{{ checkIsOpen() }}</div>\n}\n\n@if (open) {\n <div class=\"tcloud-ui-modal base-modal tcloud-ui-modal-layout-{{ layout }} tcloud-ui-modal-postition-{{ position }}\" [attr.data-layout]=\"layout\">\n <div class=\"sub-modal\" [ngClass]=\"['position-' + position, sticky ? 'is-sticky' : '']\" [@fade]=\"animationParams\">\n <div class=\"tc-modal tc-modal-shadow\" [style.max-width.px]=\"maxWidth\" [class.tcloud-ui-modal-sticky]=\"sticky\">\n <div class=\"area-top-actions tc-ui-modal-{{mode}}\">\n @if( layout === 'classic'){\n <button type=\"button\" class=\"tc-btn-action-close-ui-modal\" [class.no-use-header]=\"title\" (click)=\"toClose()\" [disabled]=\"loading\">\n @if (!loading) {\n <i class=\"fas fa-times\"></i>\n }\n @if (loading) {\n <i class=\"fas fa-spinner fa-spin\"></i>\n }\n </button>\n }@else{\n <button type=\"button\" class=\"tc-rev-btn-square tc-btn-x\" [class.no-use-header]=\"title\" (click)=\"toClose()\" [disabled]=\"loading\">\n @if (!loading) {\n <i class=\"fas fa-times\"></i>\n }\n @if (loading) {\n <i class=\"fas fa-spinner fa-spin\"></i>\n }\n </button>\n }\n </div>\n @if (title) {\n <h4 [innerHTML]=\"title\"></h4>\n }\n <ng-content></ng-content>\n </div>\n </div>\n </div>\n}\n\n<!-- Ex: Modal -->\n<!--\n<tcloud-ui-modal [(open)]=\"open\">\n\n <tcloud-ui-modal-header title=\"T\u00EDtulo do Modal\" ></tcloud-ui-modal-header>\n\n <tcloud-ui-modal-body>\n Conte\u00FAdo do modal aqui\n </tcloud-ui-modal-body>\n\n <tcloud-ui-modal-footer></tcloud-ui-modal-footer>\n\n</tcloud-ui-modal>\n\n<button type=\"button\" (click)=\"open = !open\">open modal {{ open }}</button>\n-->\n\n<!-- ****** -->\n<!-- ****** -->\n<!-- ****** -->\n<!-- ****** -->\n\n<!-- Ex: Confirm Modal -->\n<!--\n<tcloud-ui-modal [(open)]=\"open_confirm\" [title]=\"'Aten\u00E7\u00E3o'\" [confirmText]=\"'Aceito'\" [confirm]=\"true\" (toAction)=\"$event\" >\n\n <tcloud-ui-modal-body>Deseja realmente executar esta a\u00E7\u00E3o?</tcloud-ui-modal-body>\n\n <tcloud-ui-modal-footer></tcloud-ui-modal-footer>\n\n</tcloud-ui-modal>\n\n<button type=\"button\" (click)=\"open_confirm = !open_confirm\">open_confirm modal {{ open_confirm }}</button>\n-->", styles: [".tc-background-modal{border:1px solid var(--c-neutral-300);position:fixed;width:100%;left:0;top:0;background-color:#000;z-index:4005;height:100%;opacity:.3}.base-modal{height:100%;overflow:scroll;position:fixed;width:100%;z-index:4005;left:0;top:0;text-align:left!important}.sub-modal{padding:30px;position:absolute;width:100%;display:flex;justify-content:center;align-items:flex-start}.sub-modal.position-left{justify-content:flex-start}.sub-modal.position-right{justify-content:flex-end}.sub-modal.position-bottom{align-items:flex-end}.tc-modal{position:relative;background-color:var(--c-neutral-50);border:1px solid var(--c-neutral-200);padding:12px;border-radius:8px;margin:auto;width:100%;transition:max-width .3s ease-out}@media(prefers-reduced-motion:reduce){.tc-modal{transition:none}}.sub-modal.is-sticky{padding:0}.sub-modal.is-sticky .tc-modal{border-radius:0}.sub-modal.is-sticky.position-left .tc-modal{margin:0 auto 0 0}.sub-modal.is-sticky.position-right .tc-modal{margin:0 0 0 auto}.sub-modal.is-sticky.position-bottom .tc-modal{margin:auto 0 0}.sub-modal.is-sticky.position-center .tc-modal,.sub-modal.is-sticky.position-bottom .tc-modal{max-width:100%!important;width:100%!important}.tc-modal-shadow{-webkit-box-shadow:2px 2px 10px 0px rgba(0,0,0,.368627451);box-shadow:2px 2px 10px #0000005e}.tc-btn-x{min-height:25px!important;min-width:25px!important;height:25px;width:25px;margin-top:8px}.area-top-actions{position:absolute;top:2px;right:5px;z-index:1}.area-top-actions.tc-ui-modal-colorless button.tc-btn-action-close-ui-modal i{color:var(--c-neutral-600)!important}.area-top-actions button.tc-btn-action-close-ui-modal{cursor:pointer;background-color:transparent;border:none;font-size:15px;padding:5px 7px}.area-top-actions button.tc-btn-action-close-ui-modal i{font-size:17px;color:#fff;transition:all .25s;opacity:.7}.area-top-actions button.tc-btn-action-close-ui-modal i:hover{opacity:1!important}h4{font-size:16px;margin:5px 30px 10px 0;font-weight:700}.no-use-header i{color:var(--c-neutral-500)!important}.tcloud-ui-modal-sticky{height:100vh;overflow:hidden}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], animations: [
3776
+ ], ngImport: i0, template: "@if (control_open) {\n <div class=\"tc-background-modal\" >{{ checkIsOpen() }}</div>\n}\n\n@if (open) {\n <div class=\"tcloud-ui-modal base-modal tcloud-ui-modal-layout-{{ layout }} tcloud-ui-modal-postition-{{ position }}\" [attr.data-layout]=\"layout\">\n <div class=\"sub-modal\" [ngClass]=\"['position-' + position, sticky ? 'is-sticky' : '']\" [@fade]=\"animationParams\">\n <div class=\"tc-modal tc-modal-shadow\" [style.max-width.px]=\"maxWidth\" [class.tcloud-ui-modal-sticky]=\"sticky\">\n <div class=\"area-top-actions tc-ui-modal-{{mode}}\">\n @if( layout === 'classic'){\n <button type=\"button\" class=\"tc-btn-action-close-ui-modal\" [class.no-use-header]=\"title\" (click)=\"toClose()\" [disabled]=\"loading\">\n @if (!loading) {\n <i class=\"fas fa-times\"></i>\n }\n @if (loading) {\n <i class=\"fas fa-spinner fa-spin\"></i>\n }\n </button>\n }@else{\n <button type=\"button\" class=\"tc-rev-btn-square tc-btn-x\" [class.no-use-header]=\"title\" (click)=\"toClose()\" [disabled]=\"loading\">\n @if (!loading) {\n <i class=\"fas fa-times\"></i>\n }\n @if (loading) {\n <i class=\"fas fa-spinner fa-spin\"></i>\n }\n </button>\n }\n </div>\n @if (title) {\n <h4 [innerHTML]=\"title\"></h4>\n }\n <ng-content></ng-content>\n </div>\n </div>\n </div>\n}\n\n<!-- Ex: Modal -->\n<!--\n<tcloud-ui-modal [(open)]=\"open\">\n\n <tcloud-ui-modal-header title=\"T\u00EDtulo do Modal\" ></tcloud-ui-modal-header>\n\n <tcloud-ui-modal-body>\n Conte\u00FAdo do modal aqui\n </tcloud-ui-modal-body>\n\n <tcloud-ui-modal-footer></tcloud-ui-modal-footer>\n\n</tcloud-ui-modal>\n\n<button type=\"button\" (click)=\"open = !open\">open modal {{ open }}</button>\n-->\n\n<!-- ****** -->\n<!-- ****** -->\n<!-- ****** -->\n<!-- ****** -->\n\n<!-- Ex: Confirm Modal -->\n<!--\n<tcloud-ui-modal [(open)]=\"open_confirm\" [title]=\"'Aten\u00E7\u00E3o'\" [confirmText]=\"'Aceito'\" [confirm]=\"true\" (toAction)=\"$event\" >\n\n <tcloud-ui-modal-body>Deseja realmente executar esta a\u00E7\u00E3o?</tcloud-ui-modal-body>\n\n <tcloud-ui-modal-footer></tcloud-ui-modal-footer>\n\n</tcloud-ui-modal>\n\n<button type=\"button\" (click)=\"open_confirm = !open_confirm\">open_confirm modal {{ open_confirm }}</button>\n-->", styles: [".tc-background-modal{border:1px solid var(--c-neutral-300);position:fixed;width:100%;left:0;top:0;background-color:#000;z-index:4005;height:100%;opacity:.3}.base-modal{height:100%;overflow:scroll;position:fixed;width:100%;z-index:4005;left:0;top:0;text-align:left!important}.sub-modal{padding:30px;position:absolute;width:100%;display:flex;justify-content:center;align-items:flex-start}.sub-modal.position-left{justify-content:flex-start}.sub-modal.position-right{justify-content:flex-end}.sub-modal.position-bottom{align-items:flex-end}.tc-modal{position:relative;background-color:var(--c-neutral-50);border:1px solid var(--c-neutral-200);padding:12px;border-radius:8px;margin:auto;width:100%;transition:max-width .3s ease-out}@media(prefers-reduced-motion:reduce){.tc-modal{transition:none}}.sub-modal.is-sticky{padding:0}.sub-modal.is-sticky>.tc-modal{border-radius:0}.sub-modal.is-sticky.position-left>.tc-modal{margin:0 auto 0 0}.sub-modal.is-sticky.position-right>.tc-modal{margin:0 0 0 auto}.sub-modal.is-sticky.position-bottom>.tc-modal{margin:auto 0 0}.sub-modal.is-sticky.position-center>.tc-modal,.sub-modal.is-sticky.position-bottom>.tc-modal{max-width:100%!important;width:100%!important}.tc-modal-shadow{-webkit-box-shadow:2px 2px 10px 0px rgba(0,0,0,.368627451);box-shadow:2px 2px 10px #0000005e}.tc-btn-x{min-height:25px!important;min-width:25px!important;height:25px;width:25px;margin-top:8px}.area-top-actions{position:absolute;top:2px;right:5px;z-index:1}.area-top-actions.tc-ui-modal-colorless button.tc-btn-action-close-ui-modal i{color:var(--c-neutral-600)!important}.area-top-actions button.tc-btn-action-close-ui-modal{cursor:pointer;background-color:transparent;border:none;font-size:15px;padding:5px 7px}.area-top-actions button.tc-btn-action-close-ui-modal i{font-size:17px;color:#fff;transition:all .25s;opacity:.7}.area-top-actions button.tc-btn-action-close-ui-modal i:hover{opacity:1!important}h4{font-size:16px;margin:5px 30px 10px 0;font-weight:700}.no-use-header i{color:var(--c-neutral-500)!important}.tcloud-ui-modal-sticky{height:100vh;overflow:hidden}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], animations: [
3777
3777
  trigger('fade', [
3778
3778
  transition('void => *', [
3779
3779
  style({ opacity: 0, transform: '{{enterTransform}}' }),
@@ -3800,7 +3800,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
3800
3800
  animate('0.3s ease-out', style({ opacity: 0, transform: '{{leaveTransform}}' }))
3801
3801
  ], { params: { leaveTransform: 'translateY(-38%)' } })
3802
3802
  ])
3803
- ], standalone: true, imports: [CommonModule], template: "@if (control_open) {\n <div class=\"tc-background-modal\" >{{ checkIsOpen() }}</div>\n}\n\n@if (open) {\n <div class=\"tcloud-ui-modal base-modal tcloud-ui-modal-layout-{{ layout }} tcloud-ui-modal-postition-{{ position }}\" [attr.data-layout]=\"layout\">\n <div class=\"sub-modal\" [ngClass]=\"['position-' + position, sticky ? 'is-sticky' : '']\" [@fade]=\"animationParams\">\n <div class=\"tc-modal tc-modal-shadow\" [style.max-width.px]=\"maxWidth\" [class.tcloud-ui-modal-sticky]=\"sticky\">\n <div class=\"area-top-actions tc-ui-modal-{{mode}}\">\n @if( layout === 'classic'){\n <button type=\"button\" class=\"tc-btn-action-close-ui-modal\" [class.no-use-header]=\"title\" (click)=\"toClose()\" [disabled]=\"loading\">\n @if (!loading) {\n <i class=\"fas fa-times\"></i>\n }\n @if (loading) {\n <i class=\"fas fa-spinner fa-spin\"></i>\n }\n </button>\n }@else{\n <button type=\"button\" class=\"tc-rev-btn-square tc-btn-x\" [class.no-use-header]=\"title\" (click)=\"toClose()\" [disabled]=\"loading\">\n @if (!loading) {\n <i class=\"fas fa-times\"></i>\n }\n @if (loading) {\n <i class=\"fas fa-spinner fa-spin\"></i>\n }\n </button>\n }\n </div>\n @if (title) {\n <h4 [innerHTML]=\"title\"></h4>\n }\n <ng-content></ng-content>\n </div>\n </div>\n </div>\n}\n\n<!-- Ex: Modal -->\n<!--\n<tcloud-ui-modal [(open)]=\"open\">\n\n <tcloud-ui-modal-header title=\"T\u00EDtulo do Modal\" ></tcloud-ui-modal-header>\n\n <tcloud-ui-modal-body>\n Conte\u00FAdo do modal aqui\n </tcloud-ui-modal-body>\n\n <tcloud-ui-modal-footer></tcloud-ui-modal-footer>\n\n</tcloud-ui-modal>\n\n<button type=\"button\" (click)=\"open = !open\">open modal {{ open }}</button>\n-->\n\n<!-- ****** -->\n<!-- ****** -->\n<!-- ****** -->\n<!-- ****** -->\n\n<!-- Ex: Confirm Modal -->\n<!--\n<tcloud-ui-modal [(open)]=\"open_confirm\" [title]=\"'Aten\u00E7\u00E3o'\" [confirmText]=\"'Aceito'\" [confirm]=\"true\" (toAction)=\"$event\" >\n\n <tcloud-ui-modal-body>Deseja realmente executar esta a\u00E7\u00E3o?</tcloud-ui-modal-body>\n\n <tcloud-ui-modal-footer></tcloud-ui-modal-footer>\n\n</tcloud-ui-modal>\n\n<button type=\"button\" (click)=\"open_confirm = !open_confirm\">open_confirm modal {{ open_confirm }}</button>\n-->", styles: [".tc-background-modal{border:1px solid var(--c-neutral-300);position:fixed;width:100%;left:0;top:0;background-color:#000;z-index:4005;height:100%;opacity:.3}.base-modal{height:100%;overflow:scroll;position:fixed;width:100%;z-index:4005;left:0;top:0;text-align:left!important}.sub-modal{padding:30px;position:absolute;width:100%;display:flex;justify-content:center;align-items:flex-start}.sub-modal.position-left{justify-content:flex-start}.sub-modal.position-right{justify-content:flex-end}.sub-modal.position-bottom{align-items:flex-end}.tc-modal{position:relative;background-color:var(--c-neutral-50);border:1px solid var(--c-neutral-200);padding:12px;border-radius:8px;margin:auto;width:100%;transition:max-width .3s ease-out}@media(prefers-reduced-motion:reduce){.tc-modal{transition:none}}.sub-modal.is-sticky{padding:0}.sub-modal.is-sticky .tc-modal{border-radius:0}.sub-modal.is-sticky.position-left .tc-modal{margin:0 auto 0 0}.sub-modal.is-sticky.position-right .tc-modal{margin:0 0 0 auto}.sub-modal.is-sticky.position-bottom .tc-modal{margin:auto 0 0}.sub-modal.is-sticky.position-center .tc-modal,.sub-modal.is-sticky.position-bottom .tc-modal{max-width:100%!important;width:100%!important}.tc-modal-shadow{-webkit-box-shadow:2px 2px 10px 0px rgba(0,0,0,.368627451);box-shadow:2px 2px 10px #0000005e}.tc-btn-x{min-height:25px!important;min-width:25px!important;height:25px;width:25px;margin-top:8px}.area-top-actions{position:absolute;top:2px;right:5px;z-index:1}.area-top-actions.tc-ui-modal-colorless button.tc-btn-action-close-ui-modal i{color:var(--c-neutral-600)!important}.area-top-actions button.tc-btn-action-close-ui-modal{cursor:pointer;background-color:transparent;border:none;font-size:15px;padding:5px 7px}.area-top-actions button.tc-btn-action-close-ui-modal i{font-size:17px;color:#fff;transition:all .25s;opacity:.7}.area-top-actions button.tc-btn-action-close-ui-modal i:hover{opacity:1!important}h4{font-size:16px;margin:5px 30px 10px 0;font-weight:700}.no-use-header i{color:var(--c-neutral-500)!important}.tcloud-ui-modal-sticky{height:100vh;overflow:hidden}\n"] }]
3803
+ ], standalone: true, imports: [CommonModule], template: "@if (control_open) {\n <div class=\"tc-background-modal\" >{{ checkIsOpen() }}</div>\n}\n\n@if (open) {\n <div class=\"tcloud-ui-modal base-modal tcloud-ui-modal-layout-{{ layout }} tcloud-ui-modal-postition-{{ position }}\" [attr.data-layout]=\"layout\">\n <div class=\"sub-modal\" [ngClass]=\"['position-' + position, sticky ? 'is-sticky' : '']\" [@fade]=\"animationParams\">\n <div class=\"tc-modal tc-modal-shadow\" [style.max-width.px]=\"maxWidth\" [class.tcloud-ui-modal-sticky]=\"sticky\">\n <div class=\"area-top-actions tc-ui-modal-{{mode}}\">\n @if( layout === 'classic'){\n <button type=\"button\" class=\"tc-btn-action-close-ui-modal\" [class.no-use-header]=\"title\" (click)=\"toClose()\" [disabled]=\"loading\">\n @if (!loading) {\n <i class=\"fas fa-times\"></i>\n }\n @if (loading) {\n <i class=\"fas fa-spinner fa-spin\"></i>\n }\n </button>\n }@else{\n <button type=\"button\" class=\"tc-rev-btn-square tc-btn-x\" [class.no-use-header]=\"title\" (click)=\"toClose()\" [disabled]=\"loading\">\n @if (!loading) {\n <i class=\"fas fa-times\"></i>\n }\n @if (loading) {\n <i class=\"fas fa-spinner fa-spin\"></i>\n }\n </button>\n }\n </div>\n @if (title) {\n <h4 [innerHTML]=\"title\"></h4>\n }\n <ng-content></ng-content>\n </div>\n </div>\n </div>\n}\n\n<!-- Ex: Modal -->\n<!--\n<tcloud-ui-modal [(open)]=\"open\">\n\n <tcloud-ui-modal-header title=\"T\u00EDtulo do Modal\" ></tcloud-ui-modal-header>\n\n <tcloud-ui-modal-body>\n Conte\u00FAdo do modal aqui\n </tcloud-ui-modal-body>\n\n <tcloud-ui-modal-footer></tcloud-ui-modal-footer>\n\n</tcloud-ui-modal>\n\n<button type=\"button\" (click)=\"open = !open\">open modal {{ open }}</button>\n-->\n\n<!-- ****** -->\n<!-- ****** -->\n<!-- ****** -->\n<!-- ****** -->\n\n<!-- Ex: Confirm Modal -->\n<!--\n<tcloud-ui-modal [(open)]=\"open_confirm\" [title]=\"'Aten\u00E7\u00E3o'\" [confirmText]=\"'Aceito'\" [confirm]=\"true\" (toAction)=\"$event\" >\n\n <tcloud-ui-modal-body>Deseja realmente executar esta a\u00E7\u00E3o?</tcloud-ui-modal-body>\n\n <tcloud-ui-modal-footer></tcloud-ui-modal-footer>\n\n</tcloud-ui-modal>\n\n<button type=\"button\" (click)=\"open_confirm = !open_confirm\">open_confirm modal {{ open_confirm }}</button>\n-->", styles: [".tc-background-modal{border:1px solid var(--c-neutral-300);position:fixed;width:100%;left:0;top:0;background-color:#000;z-index:4005;height:100%;opacity:.3}.base-modal{height:100%;overflow:scroll;position:fixed;width:100%;z-index:4005;left:0;top:0;text-align:left!important}.sub-modal{padding:30px;position:absolute;width:100%;display:flex;justify-content:center;align-items:flex-start}.sub-modal.position-left{justify-content:flex-start}.sub-modal.position-right{justify-content:flex-end}.sub-modal.position-bottom{align-items:flex-end}.tc-modal{position:relative;background-color:var(--c-neutral-50);border:1px solid var(--c-neutral-200);padding:12px;border-radius:8px;margin:auto;width:100%;transition:max-width .3s ease-out}@media(prefers-reduced-motion:reduce){.tc-modal{transition:none}}.sub-modal.is-sticky{padding:0}.sub-modal.is-sticky>.tc-modal{border-radius:0}.sub-modal.is-sticky.position-left>.tc-modal{margin:0 auto 0 0}.sub-modal.is-sticky.position-right>.tc-modal{margin:0 0 0 auto}.sub-modal.is-sticky.position-bottom>.tc-modal{margin:auto 0 0}.sub-modal.is-sticky.position-center>.tc-modal,.sub-modal.is-sticky.position-bottom>.tc-modal{max-width:100%!important;width:100%!important}.tc-modal-shadow{-webkit-box-shadow:2px 2px 10px 0px rgba(0,0,0,.368627451);box-shadow:2px 2px 10px #0000005e}.tc-btn-x{min-height:25px!important;min-width:25px!important;height:25px;width:25px;margin-top:8px}.area-top-actions{position:absolute;top:2px;right:5px;z-index:1}.area-top-actions.tc-ui-modal-colorless button.tc-btn-action-close-ui-modal i{color:var(--c-neutral-600)!important}.area-top-actions button.tc-btn-action-close-ui-modal{cursor:pointer;background-color:transparent;border:none;font-size:15px;padding:5px 7px}.area-top-actions button.tc-btn-action-close-ui-modal i{font-size:17px;color:#fff;transition:all .25s;opacity:.7}.area-top-actions button.tc-btn-action-close-ui-modal i:hover{opacity:1!important}h4{font-size:16px;margin:5px 30px 10px 0;font-weight:700}.no-use-header i{color:var(--c-neutral-500)!important}.tcloud-ui-modal-sticky{height:100vh;overflow:hidden}\n"] }]
3804
3804
  }], ctorParameters: () => [{ type: TCloudUiLayoutService }, { type: TcloudModalService }], propDecorators: { confirm: [{
3805
3805
  type: Input
3806
3806
  }], confirmText: [{
@@ -6301,15 +6301,26 @@ class TCloudUiUploadAreaComponent {
6301
6301
  this.onImagesSelected(files);
6302
6302
  }
6303
6303
  generateNameFile(fileName) {
6304
- // Extrai a extensão do arquivo
6305
- const lastDotIndex = fileName.lastIndexOf('.');
6306
- const extension = lastDotIndex !== -1 ? fileName.substring(lastDotIndex) : '';
6304
+ const extension = this.getFullExtension(fileName);
6307
6305
  // Gera um nome aleatório (16 caracteres)
6308
6306
  const randomName = Math.random().toString(36).substring(2, 15) +
6309
6307
  Math.random().toString(36).substring(2, 15);
6310
6308
  // Retorna o nome aleatório + extensão, tudo em minúsculo
6311
6309
  return (randomName + extension).toLowerCase();
6312
6310
  }
6311
+ // Extensões compostas conhecidas (ex.: pacotes Linux) que não podem ser cortadas pelo último ponto
6312
+ static { this.COMPOUND_EXTENSIONS = [
6313
+ '.tar.gz', '.tar.bz2', '.tar.xz', '.tar.zst', '.tar.lz', '.tar.lzma'
6314
+ ]; }
6315
+ // Extrai a extensão do arquivo, reconhecendo extensões compostas (.tar.gz, etc.)
6316
+ getFullExtension(fileName) {
6317
+ const lower = fileName.toLowerCase();
6318
+ const compound = TCloudUiUploadAreaComponent.COMPOUND_EXTENSIONS.find(ext => lower.endsWith(ext));
6319
+ if (compound)
6320
+ return compound;
6321
+ const lastDot = fileName.lastIndexOf('.');
6322
+ return lastDot !== -1 ? fileName.substring(lastDot).toLowerCase() : '';
6323
+ }
6313
6324
  onImagesSelected(files) {
6314
6325
  // Não limpa o array, apenas adiciona novas imagens ao final
6315
6326
  // Verifica se há limite máximo e quantos arquivos ainda podem ser adicionados
@@ -6474,13 +6485,12 @@ class TCloudUiUploadAreaComponent {
6474
6485
  const matchesMime = hasTypesFilter
6475
6486
  ? this.acceptedFileTypes.includes(file.type)
6476
6487
  : false;
6477
- // Verifica por extensão (case-insensitive, garante ponto inicial)
6488
+ // Verifica por extensão (case-insensitive, por sufixo para suportar extensões compostas como .tar.gz)
6478
6489
  let matchesExt = false;
6479
6490
  if (hasExtFilter) {
6480
- const lastDot = file.name.lastIndexOf('.');
6481
- const fileExt = lastDot !== -1 ? file.name.substring(lastDot).toLowerCase() : '';
6491
+ const fileName = file.name.toLowerCase();
6482
6492
  const normalizedExts = this.acceptedExtensions.map(e => (e.startsWith('.') ? e : `.${e}`).toLowerCase());
6483
- matchesExt = normalizedExts.includes(fileExt);
6493
+ matchesExt = normalizedExts.some(ext => fileName.endsWith(ext));
6484
6494
  }
6485
6495
  return matchesMime || matchesExt;
6486
6496
  }
@@ -6558,11 +6568,11 @@ class TCloudUiUploadAreaComponent {
6558
6568
  isImageFile(index) {
6559
6569
  return this.images[index]?.file?.type?.startsWith('image/') ?? false;
6560
6570
  }
6561
- // Retorna a extensão do arquivo em maiúsculo (sem ponto), ex: 'PDF', 'DOC'
6571
+ // Retorna a extensão do arquivo em maiúsculo (sem ponto), ex: 'PDF', 'TAR.GZ'
6562
6572
  getFileExtension(index) {
6563
6573
  const name = this.images[index]?.name ?? '';
6564
- const lastDot = name.lastIndexOf('.');
6565
- return lastDot !== -1 ? name.substring(lastDot + 1).toUpperCase() : 'FILE';
6574
+ const extension = this.getFullExtension(name);
6575
+ return extension ? extension.substring(1).toUpperCase() : 'FILE';
6566
6576
  }
6567
6577
  // Valida dimensões da imagem
6568
6578
  validateImageDimensions(imageSrc, fileName) {