ngx-kit 7.3.2 → 7.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/ngx-kit-dropzone.mjs +5 -5
- package/fesm2022/ngx-kit-dropzone.mjs.map +1 -1
- package/fesm2022/ngx-kit-image-editor.mjs +14 -26
- package/fesm2022/ngx-kit-image-editor.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ngx-kit-dropzone.d.ts +4 -4
- package/types/ngx-kit-image-editor.d.ts +10 -27
|
@@ -147,7 +147,7 @@ let uidCounter = 0;
|
|
|
147
147
|
function nextId() {
|
|
148
148
|
return `ngx-dz-${Date.now().toString(36)}-${uidCounter++}`;
|
|
149
149
|
}
|
|
150
|
-
class
|
|
150
|
+
class NgxDropzone {
|
|
151
151
|
/** الگوی accept مثل input[type=file]: "image/*", ".pdf,.docx" و ... */
|
|
152
152
|
accept = input('', /* @ts-ignore */
|
|
153
153
|
...(ngDevMode ? [{ debugName: "accept" }] : /* istanbul ignore next */ []));
|
|
@@ -499,10 +499,10 @@ class NgxDropzoneComponent {
|
|
|
499
499
|
emitCurrentFiles() {
|
|
500
500
|
this.filesChange.emit(this.files().map((f) => f.file));
|
|
501
501
|
}
|
|
502
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type:
|
|
503
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NgxDropzoneComponent, isStandalone: true, selector: "ngx-dropzone", inputs: { accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, maxFiles: { classPropertyName: "maxFiles", publicName: "maxFiles", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showFileList: { classPropertyName: "showFileList", publicName: "showFileList", isSignal: true, isRequired: false, transformFunction: null }, uploadUrl: { classPropertyName: "uploadUrl", publicName: "uploadUrl", isSignal: true, isRequired: false, transformFunction: null }, uploadAlias: { classPropertyName: "uploadAlias", publicName: "uploadAlias", isSignal: true, isRequired: false, transformFunction: null }, autoUpload: { classPropertyName: "autoUpload", publicName: "autoUpload", isSignal: true, isRequired: false, transformFunction: null }, maxParallel: { classPropertyName: "maxParallel", publicName: "maxParallel", isSignal: true, isRequired: false, transformFunction: null }, uploadMode: { classPropertyName: "uploadMode", publicName: "uploadMode", isSignal: true, isRequired: false, transformFunction: null }, uploadData: { classPropertyName: "uploadData", publicName: "uploadData", isSignal: true, isRequired: false, transformFunction: null }, uploadHeaders: { classPropertyName: "uploadHeaders", publicName: "uploadHeaders", isSignal: true, isRequired: false, transformFunction: null }, uploadWithCredentials: { classPropertyName: "uploadWithCredentials", publicName: "uploadWithCredentials", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filesAdded: "filesAdded", filesRejected: "filesRejected", filesChange: "filesChange", uploadStarted: "uploadStarted", uploadProgress: "uploadProgress", uploadSuccess: "uploadSuccess", uploadError: "uploadError" }, host: { classAttribute: "ngx-dropzone-host" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"ngx-dropzone\"\n [class.dragging]=\"isDragging()\"\n [class.disabled]=\"disabled()\"\n [class.has-files]=\"files().length > 0\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-disabled]=\"disabled()\"\n (click)=\"onBrowseClick()\"\n (keydown)=\"onKeydown($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n <input\n #fileInput\n type=\"file\"\n class=\"ngx-dropzone-input\"\n [accept]=\"accept()\"\n [multiple]=\"multiple()\"\n [disabled]=\"disabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"onFileInputChange($event)\" />\n\n <div class=\"ngx-dropzone-icon-wrap\">\n <ng-content select=\"[dropzone-icon]\">\n <svg class=\"ngx-dropzone-icon\" viewBox=\"0 0 24 24\" fill=\"none\" width=\"30\" height=\"30\">\n <path\n d=\"M12 16V4M12 4l-4 4M12 4l4 4M4 16v2a2 2 0 002 2h12a2 2 0 002-2v-2\"\n stroke=\"currentColor\"\n stroke-width=\"1.8\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </ng-content>\n </div>\n\n <div class=\"ngx-dropzone-text\">\n <ng-content>\n <strong>Drop files here</strong>\n <span>or click to browse</span>\n </ng-content>\n </div>\n\n @if (hint()) {\n <div class=\"ngx-dropzone-hint\">{{ hint() }}</div>\n }\n</div>\n\n@if (!autoUpload() && uploadMode() === 'all' && pendingCount() > 0) {\n <div class=\"ngx-dropzone-actions\">\n <button\n type=\"button\"\n class=\"ngx-dropzone-upload-all\"\n [disabled]=\"disabled() || !hasUploadConfiguration()\"\n (click)=\"uploadAll(); $event.stopPropagation()\">\n Upload all\n <span>{{ pendingCount() }}</span>\n </button>\n </div>\n}\n\n@if (showFileList() && files().length) {\n <ul class=\"ngx-dropzone-list\">\n @for (item of files(); track item.id) {\n <li class=\"ngx-dropzone-item\" [class.is-uploading]=\"item.status === 'uploading'\">\n <div class=\"ngx-dropzone-thumb-wrap\">\n @if (item.previewUrl) {\n <img class=\"ngx-dropzone-thumb\" [src]=\"item.previewUrl\" [alt]=\"item.file.name\" />\n } @else {\n <span class=\"ngx-dropzone-file-icon\">\uD83D\uDCC4</span>\n }\n </div>\n\n <div class=\"ngx-dropzone-meta\">\n <span class=\"ngx-dropzone-name\" [title]=\"item.file.name\">{{ item.file.name }}</span>\n <span class=\"ngx-dropzone-size\">{{ formatSize(item.file.size) }}</span>\n\n @if (item.status === 'uploading' || item.status === 'uploaded') {\n <div\n class=\"ngx-dropzone-progress\"\n role=\"progressbar\"\n [attr.aria-valuenow]=\"item.progress\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n [attr.aria-label]=\"'Upload progress for ' + item.file.name\">\n <span class=\"ngx-dropzone-progress-bar\" [style.width.%]=\"item.progress\"></span>\n </div>\n <span class=\"ngx-dropzone-progress-text\">{{ item.progress }}%</span>\n }\n\n @if (item.status === 'error') {\n <span class=\"ngx-dropzone-error\">Upload failed</span>\n }\n </div>\n\n <div class=\"ngx-dropzone-row-actions\">\n @if (!autoUpload() && uploadMode() === 'single' && isPending(item)) {\n <button\n type=\"button\"\n class=\"ngx-dropzone-upload\"\n [disabled]=\"disabled() || !hasUploadConfiguration()\"\n [attr.aria-label]=\"'Upload ' + item.file.name\"\n (click)=\"uploadSingle(item.id); $event.stopPropagation()\">\n Upload\n </button>\n }\n\n @if (item.status === 'error') {\n <button\n type=\"button\"\n class=\"ngx-dropzone-retry\"\n [disabled]=\"disabled() || !hasUploadConfiguration()\"\n [attr.aria-label]=\"'Retry upload for ' + item.file.name\"\n (click)=\"retryUpload(item.id); $event.stopPropagation()\">\n Retry\n </button>\n }\n\n @if (item.status === 'uploaded') {\n <span class=\"ngx-dropzone-status success\" aria-label=\"Uploaded\">\u2713</span>\n } @else if (item.status === 'uploading') {\n <span class=\"ngx-dropzone-status uploading\" aria-label=\"Uploading\"></span>\n } @else if (item.status === 'error') {\n <span class=\"ngx-dropzone-status error\" aria-label=\"Upload failed\">!</span>\n } @else {\n <span class=\"ngx-dropzone-status pending\" aria-label=\"Pending\">\u2022</span>\n }\n\n <button\n type=\"button\"\n class=\"ngx-dropzone-remove\"\n [attr.aria-label]=\"'Remove ' + item.file.name\"\n (click)=\"removeFile(item.id); $event.stopPropagation()\">\n \u2715\n </button>\n </div>\n </li>\n }\n </ul>\n}\n", styles: ["@charset \"UTF-8\";:host{display:block}.ngx-dropzone{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.65rem;padding:2.25rem 1.5rem;border-radius:16px;cursor:pointer;text-align:center;overflow:hidden;background:light-dark(#fafbfc,#1a1a1e);border:2px dashed light-dark(#d6dae1,#35353c);transition:border-color .2s ease,background-color .2s ease,transform .2s cubic-bezier(.34,1.56,.64,1),box-shadow .2s ease}.ngx-dropzone:before{content:\"\";position:absolute;inset:0;background:radial-gradient(circle at 50% 0%,light-dark(rgba(37,99,235,.06),rgba(59,130,246,.1)),transparent 65%);opacity:0;transition:opacity .2s ease;pointer-events:none}.ngx-dropzone:hover:not(.disabled){border-color:light-dark(#93c5fd,#3b82f6);box-shadow:0 4px 18px light-dark(rgba(37,99,235,.08),rgba(0,0,0,.35))}.ngx-dropzone:hover:not(.disabled):before{opacity:1}.ngx-dropzone:focus-visible{outline:2px solid light-dark(#2563eb,#60a5fa);outline-offset:3px}.ngx-dropzone.dragging{border-color:light-dark(#2563eb,#60a5fa);border-style:solid;background:light-dark(#eff6ff,#16213a);transform:scale(1.015);box-shadow:0 8px 28px light-dark(rgba(37,99,235,.18),rgba(59,130,246,.25))}.ngx-dropzone.dragging:before{opacity:1}.ngx-dropzone.dragging .ngx-dropzone-icon-wrap{transform:translateY(-4px) scale(1.08)}.ngx-dropzone.disabled{cursor:not-allowed;opacity:.55}.ngx-dropzone.has-files{padding-block:1.5rem}.ngx-dropzone-input{position:absolute;inset-inline-start:-9999px;width:1px;height:1px;opacity:0}.ngx-dropzone-icon-wrap{display:flex;align-items:center;justify-content:center;inline-size:56px;block-size:56px;border-radius:50%;background:light-dark(#eef2ff,#232433);color:light-dark(#4f46e5,#818cf8);transition:transform .22s cubic-bezier(.34,1.56,.64,1);z-index:1}.ngx-dropzone-text{z-index:1;display:flex;flex-direction:column;gap:.15rem}.ngx-dropzone-text strong{font-size:.92rem;font-weight:600;color:light-dark(#1f2937,#e4e4e7)}.ngx-dropzone-text span{font-size:.8rem;color:light-dark(#9ca3af,#71717a)}.ngx-dropzone-hint{z-index:1;font-size:.72rem;color:light-dark(#9ca3af,#6b7280);background:light-dark(#f3f4f6,#232327);padding:.15rem .6rem;border-radius:999px}.ngx-dropzone-list{list-style:none;margin:.85rem 0 0;padding:0;display:flex;flex-direction:column;gap:.45rem}.ngx-dropzone-item{display:flex;align-items:center;gap:.7rem;padding:.5rem .6rem;border-radius:10px;background:light-dark(#ffffff,#1f1f24);border:1px solid light-dark(#eef0f3,#2d2d33);transition:transform .16s ease,box-shadow .16s ease;animation:ngx-dropzone-item-in .22s cubic-bezier(.22,.9,.32,1) both}.ngx-dropzone-item:hover{box-shadow:0 2px 10px light-dark(rgba(0,0,0,.06),rgba(0,0,0,.4))}@keyframes ngx-dropzone-item-in{0%{opacity:0;transform:translateY(-6px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}.ngx-dropzone-thumb-wrap{flex-shrink:0;inline-size:38px;block-size:38px;border-radius:8px;overflow:hidden;background:light-dark(#f4f4f5,#29292f);display:flex;align-items:center;justify-content:center}.ngx-dropzone-thumb{inline-size:100%;block-size:100%;object-fit:cover}.ngx-dropzone-file-icon{font-size:1.1rem}.ngx-dropzone-meta{flex:1;min-inline-size:0;display:flex;flex-direction:column;gap:.1rem}.ngx-dropzone-name{font-size:.8rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:light-dark(#1f2937,#e4e4e7)}.ngx-dropzone-size{font-size:.7rem;color:light-dark(#9ca3af,#71717a)}.ngx-dropzone-status{flex-shrink:0;inline-size:20px;block-size:20px;border-radius:50%;background:light-dark(#dcfce7,#14532d);color:light-dark(#16a34a,#4ade80);font-size:.7rem;display:flex;align-items:center;justify-content:center}.ngx-dropzone-remove{flex-shrink:0;appearance:none;border:none;background:transparent;cursor:pointer;color:light-dark(#9ca3af,#71717a);font-size:.8rem;line-height:1;padding:.3rem;border-radius:6px;transition:background-color .14s ease,color .14s ease}.ngx-dropzone-remove:hover{color:light-dark(#dc2626,#f87171);background:light-dark(#fee2e2,#3f1d1d)}.ngx-dropzone-actions{display:flex;justify-content:flex-end;margin-top:.7rem}.ngx-dropzone-upload-all,.ngx-dropzone-upload,.ngx-dropzone-retry{appearance:none;border:1px solid light-dark(#dbe3f0,#3b3b45);border-radius:7px;background:light-dark(#2563eb,#3b82f6);color:#fff;cursor:pointer;font:inherit;font-size:.75rem;font-weight:600;padding:.35rem .65rem;transition:opacity .14s ease,transform .14s ease}.ngx-dropzone-upload:hover:not(:disabled),.ngx-dropzone-upload-all:hover:not(:disabled),.ngx-dropzone-retry:hover:not(:disabled){transform:translateY(-1px)}.ngx-dropzone-upload-all:disabled,.ngx-dropzone-upload:disabled,.ngx-dropzone-retry:disabled{cursor:not-allowed;opacity:.5}.ngx-dropzone-upload-all{display:inline-flex;align-items:center;gap:.45rem}.ngx-dropzone-upload-all span{min-inline-size:1.15rem;block-size:1.15rem;display:inline-flex;align-items:center;justify-content:center;border-radius:999px;background:#ffffff2e}.ngx-dropzone-retry{background:transparent;color:light-dark(#dc2626,#f87171)}.ngx-dropzone-row-actions{flex-shrink:0;display:flex;align-items:center;gap:.35rem}.ngx-dropzone-item.is-uploading .ngx-dropzone-status.uploading{animation:ngx-dropzone-upload-pulse 1.1s ease-in-out infinite}.ngx-dropzone-status.pending{background:light-dark(#f4f4f5,#29292f);color:light-dark(#a1a1aa,#71717a)}.ngx-dropzone-status.uploading{background:light-dark(#dbeafe,#172554);border:3px solid light-dark(#93c5fd,#3b82f6)}.ngx-dropzone-status.error{background:light-dark(#fee2e2,#450a0a);color:light-dark(#dc2626,#f87171);font-weight:700}.ngx-dropzone-status.success{background:light-dark(#dcfce7,#14532d);color:light-dark(#16a34a,#4ade80)}.ngx-dropzone-progress{position:relative;inline-size:100%;block-size:4px;margin-top:.35rem;overflow:hidden;border-radius:999px;background:light-dark(#e5e7eb,#303038)}.ngx-dropzone-progress-bar{display:block;block-size:100%;border-radius:inherit;background:light-dark(#2563eb,#60a5fa);transition:width .12s linear}.ngx-dropzone-progress-text{font-size:.65rem;color:light-dark(#6b7280,#a1a1aa)}.ngx-dropzone-error{font-size:.65rem;color:light-dark(#dc2626,#f87171)}@keyframes ngx-dropzone-upload-pulse{50%{opacity:.45}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
502
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDropzone, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
503
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NgxDropzone, isStandalone: true, selector: "ngx-dropzone", inputs: { accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, maxFiles: { classPropertyName: "maxFiles", publicName: "maxFiles", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showFileList: { classPropertyName: "showFileList", publicName: "showFileList", isSignal: true, isRequired: false, transformFunction: null }, uploadUrl: { classPropertyName: "uploadUrl", publicName: "uploadUrl", isSignal: true, isRequired: false, transformFunction: null }, uploadAlias: { classPropertyName: "uploadAlias", publicName: "uploadAlias", isSignal: true, isRequired: false, transformFunction: null }, autoUpload: { classPropertyName: "autoUpload", publicName: "autoUpload", isSignal: true, isRequired: false, transformFunction: null }, maxParallel: { classPropertyName: "maxParallel", publicName: "maxParallel", isSignal: true, isRequired: false, transformFunction: null }, uploadMode: { classPropertyName: "uploadMode", publicName: "uploadMode", isSignal: true, isRequired: false, transformFunction: null }, uploadData: { classPropertyName: "uploadData", publicName: "uploadData", isSignal: true, isRequired: false, transformFunction: null }, uploadHeaders: { classPropertyName: "uploadHeaders", publicName: "uploadHeaders", isSignal: true, isRequired: false, transformFunction: null }, uploadWithCredentials: { classPropertyName: "uploadWithCredentials", publicName: "uploadWithCredentials", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filesAdded: "filesAdded", filesRejected: "filesRejected", filesChange: "filesChange", uploadStarted: "uploadStarted", uploadProgress: "uploadProgress", uploadSuccess: "uploadSuccess", uploadError: "uploadError" }, host: { classAttribute: "ngx-dropzone-host" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"ngx-dropzone\"\n [class.dragging]=\"isDragging()\"\n [class.disabled]=\"disabled()\"\n [class.has-files]=\"files().length > 0\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-disabled]=\"disabled()\"\n (click)=\"onBrowseClick()\"\n (keydown)=\"onKeydown($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n <input\n #fileInput\n type=\"file\"\n class=\"ngx-dropzone-input\"\n [accept]=\"accept()\"\n [multiple]=\"multiple()\"\n [disabled]=\"disabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"onFileInputChange($event)\" />\n\n <div class=\"ngx-dropzone-icon-wrap\">\n <ng-content select=\"[dropzone-icon]\">\n <svg class=\"ngx-dropzone-icon\" viewBox=\"0 0 24 24\" fill=\"none\" width=\"30\" height=\"30\">\n <path\n d=\"M12 16V4M12 4l-4 4M12 4l4 4M4 16v2a2 2 0 002 2h12a2 2 0 002-2v-2\"\n stroke=\"currentColor\"\n stroke-width=\"1.8\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </ng-content>\n </div>\n\n <div class=\"ngx-dropzone-text\">\n <ng-content>\n <strong>Drop files here</strong>\n <span>or click to browse</span>\n </ng-content>\n </div>\n\n @if (hint()) {\n <div class=\"ngx-dropzone-hint\">{{ hint() }}</div>\n }\n</div>\n\n@if (!autoUpload() && uploadMode() === 'all' && pendingCount() > 0) {\n <div class=\"ngx-dropzone-actions\">\n <button\n type=\"button\"\n class=\"ngx-dropzone-upload-all\"\n [disabled]=\"disabled() || !hasUploadConfiguration()\"\n (click)=\"uploadAll(); $event.stopPropagation()\">\n Upload all\n <span>{{ pendingCount() }}</span>\n </button>\n </div>\n}\n\n@if (showFileList() && files().length) {\n <ul class=\"ngx-dropzone-list\">\n @for (item of files(); track item.id) {\n <li class=\"ngx-dropzone-item\" [class.is-uploading]=\"item.status === 'uploading'\">\n <div class=\"ngx-dropzone-thumb-wrap\">\n @if (item.previewUrl) {\n <img class=\"ngx-dropzone-thumb\" [src]=\"item.previewUrl\" [alt]=\"item.file.name\" />\n } @else {\n <span class=\"ngx-dropzone-file-icon\">\uD83D\uDCC4</span>\n }\n </div>\n\n <div class=\"ngx-dropzone-meta\">\n <span class=\"ngx-dropzone-name\" [title]=\"item.file.name\">{{ item.file.name }}</span>\n <span class=\"ngx-dropzone-size\">{{ formatSize(item.file.size) }}</span>\n\n @if (item.status === 'uploading' || item.status === 'uploaded') {\n <div\n class=\"ngx-dropzone-progress\"\n role=\"progressbar\"\n [attr.aria-valuenow]=\"item.progress\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n [attr.aria-label]=\"'Upload progress for ' + item.file.name\">\n <span class=\"ngx-dropzone-progress-bar\" [style.width.%]=\"item.progress\"></span>\n </div>\n <span class=\"ngx-dropzone-progress-text\">{{ item.progress }}%</span>\n }\n\n @if (item.status === 'error') {\n <span class=\"ngx-dropzone-error\">Upload failed</span>\n }\n </div>\n\n <div class=\"ngx-dropzone-row-actions\">\n @if (!autoUpload() && uploadMode() === 'single' && isPending(item)) {\n <button\n type=\"button\"\n class=\"ngx-dropzone-upload\"\n [disabled]=\"disabled() || !hasUploadConfiguration()\"\n [attr.aria-label]=\"'Upload ' + item.file.name\"\n (click)=\"uploadSingle(item.id); $event.stopPropagation()\">\n Upload\n </button>\n }\n\n @if (item.status === 'error') {\n <button\n type=\"button\"\n class=\"ngx-dropzone-retry\"\n [disabled]=\"disabled() || !hasUploadConfiguration()\"\n [attr.aria-label]=\"'Retry upload for ' + item.file.name\"\n (click)=\"retryUpload(item.id); $event.stopPropagation()\">\n Retry\n </button>\n }\n\n @if (item.status === 'uploaded') {\n <span class=\"ngx-dropzone-status success\" aria-label=\"Uploaded\">\u2713</span>\n } @else if (item.status === 'uploading') {\n <span class=\"ngx-dropzone-status uploading\" aria-label=\"Uploading\"></span>\n } @else if (item.status === 'error') {\n <span class=\"ngx-dropzone-status error\" aria-label=\"Upload failed\">!</span>\n } @else {\n <span class=\"ngx-dropzone-status pending\" aria-label=\"Pending\">\u2022</span>\n }\n\n <button\n type=\"button\"\n class=\"ngx-dropzone-remove\"\n [attr.aria-label]=\"'Remove ' + item.file.name\"\n (click)=\"removeFile(item.id); $event.stopPropagation()\">\n \u2715\n </button>\n </div>\n </li>\n }\n </ul>\n}\n", styles: ["@charset \"UTF-8\";:host{display:block}.ngx-dropzone{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.65rem;padding:2.25rem 1.5rem;border-radius:16px;cursor:pointer;text-align:center;overflow:hidden;background:light-dark(#fafbfc,#1a1a1e);border:2px dashed light-dark(#d6dae1,#35353c);transition:border-color .2s ease,background-color .2s ease,transform .2s cubic-bezier(.34,1.56,.64,1),box-shadow .2s ease}.ngx-dropzone:before{content:\"\";position:absolute;inset:0;background:radial-gradient(circle at 50% 0%,light-dark(rgba(37,99,235,.06),rgba(59,130,246,.1)),transparent 65%);opacity:0;transition:opacity .2s ease;pointer-events:none}.ngx-dropzone:hover:not(.disabled){border-color:light-dark(#93c5fd,#3b82f6);box-shadow:0 4px 18px light-dark(rgba(37,99,235,.08),rgba(0,0,0,.35))}.ngx-dropzone:hover:not(.disabled):before{opacity:1}.ngx-dropzone:focus-visible{outline:2px solid light-dark(#2563eb,#60a5fa);outline-offset:3px}.ngx-dropzone.dragging{border-color:light-dark(#2563eb,#60a5fa);border-style:solid;background:light-dark(#eff6ff,#16213a);transform:scale(1.015);box-shadow:0 8px 28px light-dark(rgba(37,99,235,.18),rgba(59,130,246,.25))}.ngx-dropzone.dragging:before{opacity:1}.ngx-dropzone.dragging .ngx-dropzone-icon-wrap{transform:translateY(-4px) scale(1.08)}.ngx-dropzone.disabled{cursor:not-allowed;opacity:.55}.ngx-dropzone.has-files{padding-block:1.5rem}.ngx-dropzone-input{position:absolute;inset-inline-start:-9999px;width:1px;height:1px;opacity:0}.ngx-dropzone-icon-wrap{display:flex;align-items:center;justify-content:center;inline-size:56px;block-size:56px;border-radius:50%;background:light-dark(#eef2ff,#232433);color:light-dark(#4f46e5,#818cf8);transition:transform .22s cubic-bezier(.34,1.56,.64,1);z-index:1}.ngx-dropzone-text{z-index:1;display:flex;flex-direction:column;gap:.15rem}.ngx-dropzone-text strong{font-size:.92rem;font-weight:600;color:light-dark(#1f2937,#e4e4e7)}.ngx-dropzone-text span{font-size:.8rem;color:light-dark(#9ca3af,#71717a)}.ngx-dropzone-hint{z-index:1;font-size:.72rem;color:light-dark(#9ca3af,#6b7280);background:light-dark(#f3f4f6,#232327);padding:.15rem .6rem;border-radius:999px}.ngx-dropzone-list{list-style:none;margin:.85rem 0 0;padding:0;display:flex;flex-direction:column;gap:.45rem}.ngx-dropzone-item{display:flex;align-items:center;gap:.7rem;padding:.5rem .6rem;border-radius:10px;background:light-dark(#ffffff,#1f1f24);border:1px solid light-dark(#eef0f3,#2d2d33);transition:transform .16s ease,box-shadow .16s ease;animation:ngx-dropzone-item-in .22s cubic-bezier(.22,.9,.32,1) both}.ngx-dropzone-item:hover{box-shadow:0 2px 10px light-dark(rgba(0,0,0,.06),rgba(0,0,0,.4))}@keyframes ngx-dropzone-item-in{0%{opacity:0;transform:translateY(-6px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}.ngx-dropzone-thumb-wrap{flex-shrink:0;inline-size:38px;block-size:38px;border-radius:8px;overflow:hidden;background:light-dark(#f4f4f5,#29292f);display:flex;align-items:center;justify-content:center}.ngx-dropzone-thumb{inline-size:100%;block-size:100%;object-fit:cover}.ngx-dropzone-file-icon{font-size:1.1rem}.ngx-dropzone-meta{flex:1;min-inline-size:0;display:flex;flex-direction:column;gap:.1rem}.ngx-dropzone-name{font-size:.8rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:light-dark(#1f2937,#e4e4e7)}.ngx-dropzone-size{font-size:.7rem;color:light-dark(#9ca3af,#71717a)}.ngx-dropzone-status{flex-shrink:0;inline-size:20px;block-size:20px;border-radius:50%;background:light-dark(#dcfce7,#14532d);color:light-dark(#16a34a,#4ade80);font-size:.7rem;display:flex;align-items:center;justify-content:center}.ngx-dropzone-remove{flex-shrink:0;appearance:none;border:none;background:transparent;cursor:pointer;color:light-dark(#9ca3af,#71717a);font-size:.8rem;line-height:1;padding:.3rem;border-radius:6px;transition:background-color .14s ease,color .14s ease}.ngx-dropzone-remove:hover{color:light-dark(#dc2626,#f87171);background:light-dark(#fee2e2,#3f1d1d)}.ngx-dropzone-actions{display:flex;justify-content:flex-end;margin-top:.7rem}.ngx-dropzone-upload-all,.ngx-dropzone-upload,.ngx-dropzone-retry{appearance:none;border:1px solid light-dark(#dbe3f0,#3b3b45);border-radius:7px;background:light-dark(#2563eb,#3b82f6);color:#fff;cursor:pointer;font:inherit;font-size:.75rem;font-weight:600;padding:.35rem .65rem;transition:opacity .14s ease,transform .14s ease}.ngx-dropzone-upload:hover:not(:disabled),.ngx-dropzone-upload-all:hover:not(:disabled),.ngx-dropzone-retry:hover:not(:disabled){transform:translateY(-1px)}.ngx-dropzone-upload-all:disabled,.ngx-dropzone-upload:disabled,.ngx-dropzone-retry:disabled{cursor:not-allowed;opacity:.5}.ngx-dropzone-upload-all{display:inline-flex;align-items:center;gap:.45rem}.ngx-dropzone-upload-all span{min-inline-size:1.15rem;block-size:1.15rem;display:inline-flex;align-items:center;justify-content:center;border-radius:999px;background:#ffffff2e}.ngx-dropzone-retry{background:transparent;color:light-dark(#dc2626,#f87171)}.ngx-dropzone-row-actions{flex-shrink:0;display:flex;align-items:center;gap:.35rem}.ngx-dropzone-item.is-uploading .ngx-dropzone-status.uploading{animation:ngx-dropzone-upload-pulse 1.1s ease-in-out infinite}.ngx-dropzone-status.pending{background:light-dark(#f4f4f5,#29292f);color:light-dark(#a1a1aa,#71717a)}.ngx-dropzone-status.uploading{background:light-dark(#dbeafe,#172554);border:3px solid light-dark(#93c5fd,#3b82f6)}.ngx-dropzone-status.error{background:light-dark(#fee2e2,#450a0a);color:light-dark(#dc2626,#f87171);font-weight:700}.ngx-dropzone-status.success{background:light-dark(#dcfce7,#14532d);color:light-dark(#16a34a,#4ade80)}.ngx-dropzone-progress{position:relative;inline-size:100%;block-size:4px;margin-top:.35rem;overflow:hidden;border-radius:999px;background:light-dark(#e5e7eb,#303038)}.ngx-dropzone-progress-bar{display:block;block-size:100%;border-radius:inherit;background:light-dark(#2563eb,#60a5fa);transition:width .12s linear}.ngx-dropzone-progress-text{font-size:.65rem;color:light-dark(#6b7280,#a1a1aa)}.ngx-dropzone-error{font-size:.65rem;color:light-dark(#dc2626,#f87171)}@keyframes ngx-dropzone-upload-pulse{50%{opacity:.45}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
504
504
|
}
|
|
505
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type:
|
|
505
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDropzone, decorators: [{
|
|
506
506
|
type: Component,
|
|
507
507
|
args: [{ selector: 'ngx-dropzone', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
508
508
|
class: 'ngx-dropzone-host',
|
|
@@ -513,5 +513,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
|
|
|
513
513
|
* Generated bundle index. Do not edit.
|
|
514
514
|
*/
|
|
515
515
|
|
|
516
|
-
export { NGX_DROPZONE_UPLOAD_SERVICE,
|
|
516
|
+
export { NGX_DROPZONE_UPLOAD_SERVICE, NgxDropzone, NgxDropzoneHttpUploadService, extractFilesFromDataTransfer, formatBytes, matchesAccept };
|
|
517
517
|
//# sourceMappingURL=ngx-kit-dropzone.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngx-kit-dropzone.mjs","sources":["../../../projects/libs/dropzone/services/ngx-dropzone-http-upload.service.ts","../../../projects/libs/dropzone/services/ngx-dropzone-upload.token.ts","../../../projects/libs/dropzone/utils/file-matching.ts","../../../projects/libs/dropzone/components/dropzone.component.ts","../../../projects/libs/dropzone/components/dropzone.component.html","../../../projects/libs/dropzone/ngx-kit-dropzone.ts"],"sourcesContent":["import {\n HttpClient,\n HttpEvent,\n HttpEventType,\n HttpHeaders,\n HttpResponse,\n HttpUploadProgressEvent,\n} from '@angular/common/http';\nimport { Injectable, inject } from '@angular/core';\nimport { Observable, filter, map } from 'rxjs';\nimport {\n NgxDropzoneUploadEvent,\n NgxDropzoneUploadRequest,\n NgxDropzoneUploadService,\n} from '../contracts/dropzone-upload';\n\n@Injectable({ providedIn: 'root' })\nexport class NgxDropzoneHttpUploadService implements NgxDropzoneUploadService {\n private readonly http = inject(HttpClient);\n\n upload<TResponse = unknown>(\n request: NgxDropzoneUploadRequest,\n ): Observable<NgxDropzoneUploadEvent<TResponse>> {\n const body = new FormData();\n body.append(request.alias, request.file, request.file.name);\n\n for (const [key, value] of Object.entries(request.data ?? {})) {\n body.append(key, value instanceof Blob ? value : String(value));\n }\n\n const headers =\n request.headers instanceof HttpHeaders ? request.headers : new HttpHeaders(request.headers);\n\n return this.http\n .post<TResponse>(request.url, body, {\n headers,\n withCredentials: request.withCredentials ?? false,\n observe: 'events',\n reportProgress: true,\n })\n .pipe(\n filter(\n (event): event is HttpUploadProgressEvent | HttpResponse<TResponse> =>\n event.type === HttpEventType.UploadProgress || event.type === HttpEventType.Response,\n ),\n map((event): NgxDropzoneUploadEvent<TResponse> => {\n if (event.type === HttpEventType.UploadProgress) {\n const total = event.total;\n\n return {\n type: 'progress',\n loaded: event.loaded,\n total,\n percent: total ? Math.min(100, Math.round((event.loaded / total) * 100)) : 0,\n };\n }\n\n return {\n type: 'response',\n response: event.body as TResponse,\n status: event.status,\n headers: event.headers,\n };\n }),\n );\n }\n}\n","import { InjectionToken, inject } from '@angular/core';\nimport { NgxDropzoneHttpUploadService } from './ngx-dropzone-http-upload.service';\nimport { NgxDropzoneUploadService } from '../contracts/dropzone-upload';\n\n/**\n * Upload adapter used by ngx-dropzone.\n *\n * Default: Angular HttpClient.\n * Override this token at application/component level to use Axios or any\n * other upload implementation.\n */\nexport const NGX_DROPZONE_UPLOAD_SERVICE = new InjectionToken<NgxDropzoneUploadService>(\n 'NGX_DROPZONE_UPLOAD_SERVICE',\n {\n providedIn: 'root',\n factory: () => inject(NgxDropzoneHttpUploadService),\n },\n);\n","/**\n * چک میکنه یه فایل با pattern رشتهای accept (مثل input[type=file])\n * مطابقت داره یا نه. پشتیبانی میشه از:\n * - MIME کامل: \"image/png\"\n * - MIME با wildcard: \"image/*\"\n * - پسوند فایل: \".png\", \".jpg\"\n * - لیست کاما-جدا از موارد بالا: \"image/*,.pdf,.docx\"\n */\nexport function matchesAccept(file: File, accept?: string): boolean {\n if (!accept || accept.trim() === '') return true;\n\n const patterns = accept\n .split(',')\n .map((p) => p.trim().toLowerCase())\n .filter(Boolean);\n\n if (!patterns.length) return true;\n\n const fileName = file.name.toLowerCase();\n const fileType = (file.type || '').toLowerCase();\n\n return patterns.some((pattern) => {\n if (pattern.startsWith('.')) {\n return fileName.endsWith(pattern);\n }\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -1); // \"image/\"\n return fileType.startsWith(prefix);\n }\n return fileType === pattern;\n });\n}\n\n/** تبدیل بایت به یه رشتهی خوانا (KB/MB/GB) */\nexport function formatBytes(bytes: number): string {\n if (bytes === 0) return '0 B';\n const units = ['B', 'KB', 'MB', 'GB', 'TB'];\n const i = Math.floor(Math.log(bytes) / Math.log(1024));\n const value = bytes / Math.pow(1024, i);\n return `${value.toFixed(i === 0 ? 0 : 1)} ${units[i]}`;\n}\n\n/** استخراج فایلهای واقعی از یک DataTransfer، شامل پیمایش بازگشتیِ پوشهها (وقتی مرورگر پشتیبانی کنه) */\nexport async function extractFilesFromDataTransfer(dataTransfer: DataTransfer): Promise<File[]> {\n const items = Array.from(dataTransfer.items || []);\n const hasEntrySupport = items.length > 0 && typeof items[0].webkitGetAsEntry === 'function';\n\n if (!hasEntrySupport) {\n return Array.from(dataTransfer.files || []);\n }\n\n const entries = items\n .map((item) => item.webkitGetAsEntry?.())\n .filter((e): e is FileSystemEntry => !!e);\n\n if (!entries.length) {\n return Array.from(dataTransfer.files || []);\n }\n\n const files: File[] = [];\n await Promise.all(entries.map((entry) => walkEntry(entry, files)));\n return files;\n}\n\nfunction walkEntry(entry: FileSystemEntry, out: File[]): Promise<void> {\n return new Promise((resolve) => {\n if (entry.isFile) {\n (entry as FileSystemFileEntry).file(\n (file) => {\n out.push(file);\n resolve();\n },\n () => resolve(),\n );\n } else if (entry.isDirectory) {\n const reader = (entry as FileSystemDirectoryEntry).createReader();\n const readAll: FileSystemEntry[] = [];\n const readBatch = () => {\n reader.readEntries(\n async (batch) => {\n if (!batch.length) {\n await Promise.all(readAll.map((e) => walkEntry(e, out)));\n resolve();\n return;\n }\n readAll.push(...batch);\n readBatch();\n },\n () => resolve(),\n );\n };\n readBatch();\n } else {\n resolve();\n }\n });\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n OnDestroy,\n computed,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { Subscription, finalize } from 'rxjs';\nimport {\n NgxDropzoneFile,\n NgxDropzoneRejectedFile,\n NgxDropzoneRejectionReason,\n} from '../contracts/dropzone-file';\nimport {\n NgxDropzoneUploadProgressEvent,\n NgxDropzoneUploadService,\n} from '../contracts/dropzone-upload';\nimport { NGX_DROPZONE_UPLOAD_SERVICE } from '../services/ngx-dropzone-upload.token';\nimport { extractFilesFromDataTransfer, formatBytes, matchesAccept } from '../utils/file-matching';\n\nlet uidCounter = 0;\nfunction nextId(): string {\n return `ngx-dz-${Date.now().toString(36)}-${uidCounter++}`;\n}\n\nexport type NgxDropzoneUploadMode = 'all' | 'single';\n\n@Component({\n selector: 'ngx-dropzone',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './dropzone.component.html',\n styleUrl: './dropzone.component.scss',\n host: {\n class: 'ngx-dropzone-host',\n },\n})\nexport class NgxDropzoneComponent implements OnDestroy {\n /** الگوی accept مثل input[type=file]: \"image/*\", \".pdf,.docx\" و ... */\n accept = input<string>('');\n multiple = input<boolean>(true);\n /** حداکثر حجم هر فایل به بایت؛ undefined یعنی بدون محدودیت */\n maxFileSize = input<number | undefined>(undefined);\n /** حداکثر تعداد فایل مجاز؛ undefined یعنی بدون محدودیت */\n maxFiles = input<number | undefined>(undefined);\n disabled = input<boolean>(false);\n /** نمایش لیست/پیشنمایش فایلهای انتخابشده داخل خودِ کامپوننت */\n showFileList = input<boolean>(true);\n\n /** Upload endpoint. */\n uploadUrl = input<string>('');\n /** Multipart form-data field name. */\n uploadAlias = input<string>('file');\n /** Automatically enqueue newly accepted files for upload. */\n autoUpload = input<boolean>(false);\n /** Maximum number of simultaneous uploads. */\n maxParallel = input<number>(3);\n /**\n * Manual upload behavior:\n * - all: one \"Upload all\" action uploads all pending files.\n * - single: every pending row gets its own Upload button.\n */\n uploadMode = input<NgxDropzoneUploadMode>('all');\n /** Extra multipart form fields sent with every file. */\n uploadData = input<Record<string, string | Blob | number | boolean>>({});\n /** Optional request headers. */\n uploadHeaders = input<Record<string, string | string[]>>({});\n /** Send credentials/cookies with the upload request. */\n uploadWithCredentials = input<boolean>(false);\n\n filesAdded = output<File[]>();\n filesRejected = output<NgxDropzoneRejectedFile[]>();\n filesChange = output<File[]>();\n\n /** Emitted when an individual upload starts. */\n uploadStarted = output<NgxDropzoneFile>();\n /** Emitted for every upload progress update. */\n uploadProgress = output<NgxDropzoneUploadProgressEvent>();\n /** Emitted after a file is successfully uploaded. */\n uploadSuccess = output<NgxDropzoneFile>();\n /** Emitted when an upload fails. */\n uploadError = output<{ item: NgxDropzoneFile; error: unknown }>();\n\n protected readonly files = signal<NgxDropzoneFile[]>([]);\n protected readonly isDragging = signal(false);\n private dragCounter = 0;\n\n private readonly uploadService = inject<NgxDropzoneUploadService>(NGX_DROPZONE_UPLOAD_SERVICE);\n private readonly fileInput = viewChild<ElementRef<HTMLInputElement>>('fileInput');\n private readonly uploadSubscriptions = new Map<string, Subscription>();\n private readonly uploadQueue: string[] = [];\n private activeUploads = 0;\n private readonly activeUploadIds = new Set<string>();\n\n protected readonly pendingCount = computed(\n () => this.files().filter((item) => this.isPending(item)).length,\n );\n\n protected readonly hasUploadConfiguration = computed(() => this.uploadUrl().trim().length > 0);\n\n protected readonly hint = computed(() => {\n const parts: string[] = [];\n const accept = this.accept();\n if (accept) parts.push(accept);\n const max = this.maxFileSize();\n if (max) parts.push(`max ${formatBytes(max)}`);\n return parts.join(' · ');\n });\n\n protected formatSize(bytes: number): string {\n return formatBytes(bytes);\n }\n\n protected isPending(item: NgxDropzoneFile): boolean {\n return item.status === 'pending' || item.status === 'accepted';\n }\n\n protected trackById(_index: number, item: NgxDropzoneFile): string {\n return item.id;\n }\n\n ngOnDestroy(): void {\n for (const subscription of this.uploadSubscriptions.values()) {\n subscription.unsubscribe();\n }\n this.uploadSubscriptions.clear();\n\n for (const item of this.files()) {\n if (item.previewUrl) URL.revokeObjectURL(item.previewUrl);\n }\n }\n\n protected onDragEnter(ev: DragEvent): void {\n ev.preventDefault();\n if (this.disabled()) return;\n this.dragCounter++;\n this.isDragging.set(true);\n }\n\n protected onDragOver(ev: DragEvent): void {\n ev.preventDefault();\n if (ev.dataTransfer) {\n ev.dataTransfer.dropEffect = this.disabled() ? 'none' : 'copy';\n }\n }\n\n protected onDragLeave(ev: DragEvent): void {\n ev.preventDefault();\n if (this.disabled()) return;\n this.dragCounter = Math.max(0, this.dragCounter - 1);\n if (this.dragCounter === 0) this.isDragging.set(false);\n }\n\n protected async onDrop(ev: DragEvent): Promise<void> {\n ev.preventDefault();\n this.dragCounter = 0;\n this.isDragging.set(false);\n if (this.disabled() || !ev.dataTransfer) return;\n\n const files = await extractFilesFromDataTransfer(ev.dataTransfer);\n this.handleIncomingFiles(files);\n }\n\n protected onBrowseClick(): void {\n if (this.disabled()) return;\n this.fileInput()?.nativeElement.click();\n }\n\n protected onKeydown(ev: KeyboardEvent): void {\n if (ev.key === 'Enter' || ev.key === ' ') {\n ev.preventDefault();\n this.onBrowseClick();\n }\n }\n\n protected onFileInputChange(ev: Event): void {\n const input = ev.target as HTMLInputElement;\n const files = Array.from(input.files ?? []);\n this.handleIncomingFiles(files);\n input.value = '';\n }\n\n protected removeFile(id: string): void {\n const target = this.files().find((f) => f.id === id);\n this.uploadSubscriptions.get(id)?.unsubscribe();\n this.uploadSubscriptions.delete(id);\n\n // Unsubscribing an HttpClient upload cancels the request. Release its\n // concurrency slot immediately; finalize() will see that the id is no\n // longer active and won't decrement twice.\n if (this.activeUploadIds.delete(id)) {\n this.activeUploads = Math.max(0, this.activeUploads - 1);\n }\n\n if (target?.previewUrl) URL.revokeObjectURL(target.previewUrl);\n\n this.files.update((list) => list.filter((f) => f.id !== id));\n\n // Remove stale queue entries. The queue is intentionally lazy, so an\n // entry can safely remain until pumpQueue() sees that it no longer exists.\n this.emitCurrentFiles();\n this.pumpQueue();\n }\n\n protected uploadAll(): void {\n this.enqueueUploads(\n this.files()\n .filter((item) => this.isPending(item))\n .map((item) => item.id),\n );\n }\n\n protected uploadSingle(id: string): void {\n this.enqueueUploads([id]);\n }\n\n protected retryUpload(id: string): void {\n this.files.update((list) =>\n list.map((item) =>\n item.id === id ? { ...item, status: 'pending', progress: 0, error: undefined } : item,\n ),\n );\n this.enqueueUploads([id]);\n }\n\n private handleIncomingFiles(incoming: File[]): void {\n if (!incoming.length) return;\n\n const accepted: NgxDropzoneFile[] = [];\n const rejected: NgxDropzoneRejectedFile[] = [];\n\n // A single-file dropzone behaves like a native single-select input:\n // selecting another file replaces the previous one.\n const existingCount = this.multiple() ? this.files().length : 0;\n const maxFiles = this.maxFiles();\n const maxSize = this.maxFileSize();\n const isMultiple = this.multiple();\n\n const pool = isMultiple ? incoming : incoming.slice(0, 1);\n\n for (const file of pool) {\n let reason: NgxDropzoneRejectionReason | undefined;\n\n if (!matchesAccept(file, this.accept())) {\n reason = 'type';\n } else if (maxSize != null && file.size > maxSize) {\n reason = 'size';\n } else if (maxFiles != null && existingCount + accepted.length >= maxFiles) {\n reason = 'count';\n }\n\n if (reason) {\n rejected.push({ file, reason });\n continue;\n }\n\n const isImage = file.type.startsWith('image/');\n accepted.push({\n id: nextId(),\n file,\n previewUrl: isImage ? URL.createObjectURL(file) : undefined,\n status: 'accepted',\n progress: 0,\n });\n }\n\n if (accepted.length) {\n if (!isMultiple) {\n for (const previous of this.files()) {\n this.uploadSubscriptions.get(previous.id)?.unsubscribe();\n this.uploadSubscriptions.delete(previous.id);\n this.activeUploadIds.delete(previous.id);\n if (previous.previewUrl) URL.revokeObjectURL(previous.previewUrl);\n }\n this.activeUploads = this.activeUploadIds.size;\n }\n\n this.files.update((list) => (isMultiple ? [...list, ...accepted] : accepted));\n this.filesAdded.emit(accepted.map((a) => a.file));\n this.emitCurrentFiles();\n\n if (this.autoUpload()) {\n this.enqueueUploads(accepted.map((item) => item.id));\n }\n }\n\n if (rejected.length) {\n this.filesRejected.emit(rejected);\n }\n }\n\n private enqueueUploads(ids: string[]): void {\n if (!this.uploadUrl().trim()) {\n const error = new Error('ngx-dropzone: uploadUrl is required for uploading files.');\n for (const id of ids) this.markUploadError(id, error, false);\n return;\n }\n\n const queued = new Set(this.uploadQueue);\n for (const id of ids) {\n const item = this.files().find((file) => file.id === id);\n if (!item || !this.isPending(item) || queued.has(id)) continue;\n this.uploadQueue.push(id);\n queued.add(id);\n }\n\n this.pumpQueue();\n }\n\n private pumpQueue(): void {\n const limit = Math.max(1, Math.floor(this.maxParallel() || 1));\n\n while (this.activeUploads < limit && this.uploadQueue.length) {\n const id = this.uploadQueue.shift()!;\n const item = this.files().find((file) => file.id === id);\n\n if (!item || !this.isPending(item)) continue;\n\n this.startUpload(item);\n }\n }\n\n private startUpload(item: NgxDropzoneFile): void {\n this.activeUploads++;\n this.activeUploadIds.add(item.id);\n\n this.updateFile(item.id, {\n status: 'uploading',\n progress: 0,\n error: undefined,\n });\n\n const current = this.files().find((file) => file.id === item.id);\n if (current) this.uploadStarted.emit(current);\n\n let subscription: Subscription;\n\n try {\n subscription = this.uploadService\n .upload({\n url: this.uploadUrl(),\n alias: this.uploadAlias() || 'file',\n file: item.file,\n data: this.uploadData(),\n headers: this.uploadHeaders(),\n withCredentials: this.uploadWithCredentials(),\n })\n .pipe(finalize(() => this.finishUpload(item.id)))\n .subscribe({\n next: (event) => {\n if (event.type === 'progress') {\n this.updateFile(item.id, {\n progress: event.percent,\n });\n\n const updated = this.files().find((file) => file.id === item.id);\n if (updated) {\n this.uploadProgress.emit({\n item: updated,\n loaded: event.loaded,\n total: event.total,\n percent: event.percent,\n });\n }\n return;\n }\n\n this.updateFile(item.id, {\n status: 'uploaded',\n progress: 100,\n response: event.response,\n error: undefined,\n });\n\n const updated = this.files().find((file) => file.id === item.id);\n if (updated) this.uploadSuccess.emit(updated);\n },\n error: (error) => {\n this.markUploadError(item.id, error, true);\n },\n });\n } catch (error) {\n this.markUploadError(item.id, error, true);\n this.finishUpload(item.id);\n return;\n }\n\n if (!subscription.closed) this.uploadSubscriptions.set(item.id, subscription);\n }\n\n private markUploadError(id: string, error: unknown, releaseActiveSlot: boolean): void {\n this.updateFile(id, {\n status: 'error',\n error,\n });\n\n const item = this.files().find((file) => file.id === id);\n if (item) this.uploadError.emit({ item, error });\n\n if (!releaseActiveSlot) {\n this.pumpQueue();\n }\n }\n\n private finishUpload(id: string): void {\n this.uploadSubscriptions.delete(id);\n\n if (this.activeUploadIds.delete(id)) {\n this.activeUploads = Math.max(0, this.activeUploads - 1);\n }\n\n this.pumpQueue();\n }\n\n private updateFile(id: string, patch: Partial<NgxDropzoneFile>): void {\n this.files.update((list) =>\n list.map((item) => (item.id === id ? { ...item, ...patch } : item)),\n );\n }\n\n private emitCurrentFiles(): void {\n this.filesChange.emit(this.files().map((f) => f.file));\n }\n}\n","<div\n class=\"ngx-dropzone\"\n [class.dragging]=\"isDragging()\"\n [class.disabled]=\"disabled()\"\n [class.has-files]=\"files().length > 0\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-disabled]=\"disabled()\"\n (click)=\"onBrowseClick()\"\n (keydown)=\"onKeydown($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n <input\n #fileInput\n type=\"file\"\n class=\"ngx-dropzone-input\"\n [accept]=\"accept()\"\n [multiple]=\"multiple()\"\n [disabled]=\"disabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"onFileInputChange($event)\" />\n\n <div class=\"ngx-dropzone-icon-wrap\">\n <ng-content select=\"[dropzone-icon]\">\n <svg class=\"ngx-dropzone-icon\" viewBox=\"0 0 24 24\" fill=\"none\" width=\"30\" height=\"30\">\n <path\n d=\"M12 16V4M12 4l-4 4M12 4l4 4M4 16v2a2 2 0 002 2h12a2 2 0 002-2v-2\"\n stroke=\"currentColor\"\n stroke-width=\"1.8\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </ng-content>\n </div>\n\n <div class=\"ngx-dropzone-text\">\n <ng-content>\n <strong>Drop files here</strong>\n <span>or click to browse</span>\n </ng-content>\n </div>\n\n @if (hint()) {\n <div class=\"ngx-dropzone-hint\">{{ hint() }}</div>\n }\n</div>\n\n@if (!autoUpload() && uploadMode() === 'all' && pendingCount() > 0) {\n <div class=\"ngx-dropzone-actions\">\n <button\n type=\"button\"\n class=\"ngx-dropzone-upload-all\"\n [disabled]=\"disabled() || !hasUploadConfiguration()\"\n (click)=\"uploadAll(); $event.stopPropagation()\">\n Upload all\n <span>{{ pendingCount() }}</span>\n </button>\n </div>\n}\n\n@if (showFileList() && files().length) {\n <ul class=\"ngx-dropzone-list\">\n @for (item of files(); track item.id) {\n <li class=\"ngx-dropzone-item\" [class.is-uploading]=\"item.status === 'uploading'\">\n <div class=\"ngx-dropzone-thumb-wrap\">\n @if (item.previewUrl) {\n <img class=\"ngx-dropzone-thumb\" [src]=\"item.previewUrl\" [alt]=\"item.file.name\" />\n } @else {\n <span class=\"ngx-dropzone-file-icon\">📄</span>\n }\n </div>\n\n <div class=\"ngx-dropzone-meta\">\n <span class=\"ngx-dropzone-name\" [title]=\"item.file.name\">{{ item.file.name }}</span>\n <span class=\"ngx-dropzone-size\">{{ formatSize(item.file.size) }}</span>\n\n @if (item.status === 'uploading' || item.status === 'uploaded') {\n <div\n class=\"ngx-dropzone-progress\"\n role=\"progressbar\"\n [attr.aria-valuenow]=\"item.progress\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n [attr.aria-label]=\"'Upload progress for ' + item.file.name\">\n <span class=\"ngx-dropzone-progress-bar\" [style.width.%]=\"item.progress\"></span>\n </div>\n <span class=\"ngx-dropzone-progress-text\">{{ item.progress }}%</span>\n }\n\n @if (item.status === 'error') {\n <span class=\"ngx-dropzone-error\">Upload failed</span>\n }\n </div>\n\n <div class=\"ngx-dropzone-row-actions\">\n @if (!autoUpload() && uploadMode() === 'single' && isPending(item)) {\n <button\n type=\"button\"\n class=\"ngx-dropzone-upload\"\n [disabled]=\"disabled() || !hasUploadConfiguration()\"\n [attr.aria-label]=\"'Upload ' + item.file.name\"\n (click)=\"uploadSingle(item.id); $event.stopPropagation()\">\n Upload\n </button>\n }\n\n @if (item.status === 'error') {\n <button\n type=\"button\"\n class=\"ngx-dropzone-retry\"\n [disabled]=\"disabled() || !hasUploadConfiguration()\"\n [attr.aria-label]=\"'Retry upload for ' + item.file.name\"\n (click)=\"retryUpload(item.id); $event.stopPropagation()\">\n Retry\n </button>\n }\n\n @if (item.status === 'uploaded') {\n <span class=\"ngx-dropzone-status success\" aria-label=\"Uploaded\">✓</span>\n } @else if (item.status === 'uploading') {\n <span class=\"ngx-dropzone-status uploading\" aria-label=\"Uploading\"></span>\n } @else if (item.status === 'error') {\n <span class=\"ngx-dropzone-status error\" aria-label=\"Upload failed\">!</span>\n } @else {\n <span class=\"ngx-dropzone-status pending\" aria-label=\"Pending\">•</span>\n }\n\n <button\n type=\"button\"\n class=\"ngx-dropzone-remove\"\n [attr.aria-label]=\"'Remove ' + item.file.name\"\n (click)=\"removeFile(item.id); $event.stopPropagation()\">\n ✕\n </button>\n </div>\n </li>\n }\n </ul>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;MAiBa,4BAA4B,CAAA;AACtB,IAAA,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC;AAE1C,IAAA,MAAM,CACJ,OAAiC,EAAA;AAEjC,QAAA,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE;AAC3B,QAAA,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;AAE3D,QAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE;YAC7D,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,YAAY,IAAI,GAAG,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QACjE;QAEA,MAAM,OAAO,GACX,OAAO,CAAC,OAAO,YAAY,WAAW,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC;QAE7F,OAAO,IAAI,CAAC;AACT,aAAA,IAAI,CAAY,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE;YAClC,OAAO;AACP,YAAA,eAAe,EAAE,OAAO,CAAC,eAAe,IAAI,KAAK;AACjD,YAAA,OAAO,EAAE,QAAQ;AACjB,YAAA,cAAc,EAAE,IAAI;SACrB;AACA,aAAA,IAAI,CACH,MAAM,CACJ,CAAC,KAAK,KACJ,KAAK,CAAC,IAAI,KAAK,aAAa,CAAC,cAAc,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,CAAC,QAAQ,CACvF,EACD,GAAG,CAAC,CAAC,KAAK,KAAuC;YAC/C,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,CAAC,cAAc,EAAE;AAC/C,gBAAA,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK;gBAEzB,OAAO;AACL,oBAAA,IAAI,EAAE,UAAU;oBAChB,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,KAAK;AACL,oBAAA,OAAO,EAAE,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC;iBAC7E;YACH;YAEA,OAAO;AACL,gBAAA,IAAI,EAAE,UAAU;gBAChB,QAAQ,EAAE,KAAK,CAAC,IAAiB;gBACjC,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,OAAO,EAAE,KAAK,CAAC,OAAO;aACvB;QACH,CAAC,CAAC,CACH;IACL;uGAhDW,4BAA4B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAA5B,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,4BAA4B,cADf,MAAM,EAAA,CAAA;;2FACnB,4BAA4B,EAAA,UAAA,EAAA,CAAA;kBADxC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACZlC;;;;;;AAMG;MACU,2BAA2B,GAAG,IAAI,cAAc,CAC3D,6BAA6B,EAC7B;AACE,IAAA,UAAU,EAAE,MAAM;AAClB,IAAA,OAAO,EAAE,MAAM,MAAM,CAAC,4BAA4B,CAAC;AACpD,CAAA;;AChBH;;;;;;;AAOG;AACG,SAAU,aAAa,CAAC,IAAU,EAAE,MAAe,EAAA;IACvD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE;AAAE,QAAA,OAAO,IAAI;IAEhD,MAAM,QAAQ,GAAG;SACd,KAAK,CAAC,GAAG;AACT,SAAA,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;SACjC,MAAM,CAAC,OAAO,CAAC;IAElB,IAAI,CAAC,QAAQ,CAAC,MAAM;AAAE,QAAA,OAAO,IAAI;IAEjC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;AACxC,IAAA,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,EAAE,WAAW,EAAE;AAEhD,IAAA,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,KAAI;AAC/B,QAAA,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;AAC3B,YAAA,OAAO,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC;QACnC;AACA,QAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AAC1B,YAAA,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACpC,YAAA,OAAO,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;QACpC;QACA,OAAO,QAAQ,KAAK,OAAO;AAC7B,IAAA,CAAC,CAAC;AACJ;AAEA;AACM,SAAU,WAAW,CAAC,KAAa,EAAA;IACvC,IAAI,KAAK,KAAK,CAAC;AAAE,QAAA,OAAO,KAAK;AAC7B,IAAA,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;IAC3C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACtD,IAAA,MAAM,KAAK,GAAG,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACvC,OAAO,CAAA,EAAG,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA,CAAA,EAAI,KAAK,CAAC,CAAC,CAAC,CAAA,CAAE;AACxD;AAEA;AACO,eAAe,4BAA4B,CAAC,YAA0B,EAAA;AAC3E,IAAA,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,IAAI,EAAE,CAAC;AAClD,IAAA,MAAM,eAAe,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,gBAAgB,KAAK,UAAU;IAE3F,IAAI,CAAC,eAAe,EAAE;QACpB,OAAO,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,IAAI,EAAE,CAAC;IAC7C;IAEA,MAAM,OAAO,GAAG;SACb,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,gBAAgB,IAAI;SACvC,MAAM,CAAC,CAAC,CAAC,KAA2B,CAAC,CAAC,CAAC,CAAC;AAE3C,IAAA,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;QACnB,OAAO,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,IAAI,EAAE,CAAC;IAC7C;IAEA,MAAM,KAAK,GAAW,EAAE;IACxB,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;AAClE,IAAA,OAAO,KAAK;AACd;AAEA,SAAS,SAAS,CAAC,KAAsB,EAAE,GAAW,EAAA;AACpD,IAAA,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,KAAI;AAC7B,QAAA,IAAI,KAAK,CAAC,MAAM,EAAE;AACf,YAAA,KAA6B,CAAC,IAAI,CACjC,CAAC,IAAI,KAAI;AACP,gBAAA,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;AACd,gBAAA,OAAO,EAAE;AACX,YAAA,CAAC,EACD,MAAM,OAAO,EAAE,CAChB;QACH;AAAO,aAAA,IAAI,KAAK,CAAC,WAAW,EAAE;AAC5B,YAAA,MAAM,MAAM,GAAI,KAAkC,CAAC,YAAY,EAAE;YACjE,MAAM,OAAO,GAAsB,EAAE;YACrC,MAAM,SAAS,GAAG,MAAK;AACrB,gBAAA,MAAM,CAAC,WAAW,CAChB,OAAO,KAAK,KAAI;AACd,oBAAA,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;wBACjB,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;AACxD,wBAAA,OAAO,EAAE;wBACT;oBACF;AACA,oBAAA,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;AACtB,oBAAA,SAAS,EAAE;AACb,gBAAA,CAAC,EACD,MAAM,OAAO,EAAE,CAChB;AACH,YAAA,CAAC;AACD,YAAA,SAAS,EAAE;QACb;aAAO;AACL,YAAA,OAAO,EAAE;QACX;AACF,IAAA,CAAC,CAAC;AACJ;;ACvEA,IAAI,UAAU,GAAG,CAAC;AAClB,SAAS,MAAM,GAAA;AACb,IAAA,OAAO,CAAA,OAAA,EAAU,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA,CAAA,EAAI,UAAU,EAAE,EAAE;AAC5D;MAca,oBAAoB,CAAA;;IAE/B,MAAM,GAAG,KAAK,CAAS,EAAE;+EAAC;IAC1B,QAAQ,GAAG,KAAK,CAAU,IAAI;iFAAC;;IAE/B,WAAW,GAAG,KAAK,CAAqB,SAAS;oFAAC;;IAElD,QAAQ,GAAG,KAAK,CAAqB,SAAS;iFAAC;IAC/C,QAAQ,GAAG,KAAK,CAAU,KAAK;iFAAC;;IAEhC,YAAY,GAAG,KAAK,CAAU,IAAI;qFAAC;;IAGnC,SAAS,GAAG,KAAK,CAAS,EAAE;kFAAC;;IAE7B,WAAW,GAAG,KAAK,CAAS,MAAM;oFAAC;;IAEnC,UAAU,GAAG,KAAK,CAAU,KAAK;mFAAC;;IAElC,WAAW,GAAG,KAAK,CAAS,CAAC;oFAAC;AAC9B;;;;AAIG;IACH,UAAU,GAAG,KAAK,CAAwB,KAAK;mFAAC;;IAEhD,UAAU,GAAG,KAAK,CAAmD,EAAE;mFAAC;;IAExE,aAAa,GAAG,KAAK,CAAoC,EAAE;sFAAC;;IAE5D,qBAAqB,GAAG,KAAK,CAAU,KAAK;8FAAC;IAE7C,UAAU,GAAG,MAAM,EAAU;IAC7B,aAAa,GAAG,MAAM,EAA6B;IACnD,WAAW,GAAG,MAAM,EAAU;;IAG9B,aAAa,GAAG,MAAM,EAAmB;;IAEzC,cAAc,GAAG,MAAM,EAAkC;;IAEzD,aAAa,GAAG,MAAM,EAAmB;;IAEzC,WAAW,GAAG,MAAM,EAA6C;IAE9C,KAAK,GAAG,MAAM,CAAoB,EAAE;8EAAC;IACrC,UAAU,GAAG,MAAM,CAAC,KAAK;mFAAC;IACrC,WAAW,GAAG,CAAC;AAEN,IAAA,aAAa,GAAG,MAAM,CAA2B,2BAA2B,CAAC;IAC7E,SAAS,GAAG,SAAS,CAA+B,WAAW;kFAAC;AAChE,IAAA,mBAAmB,GAAG,IAAI,GAAG,EAAwB;IACrD,WAAW,GAAa,EAAE;IACnC,aAAa,GAAG,CAAC;AACR,IAAA,eAAe,GAAG,IAAI,GAAG,EAAU;IAEjC,YAAY,GAAG,QAAQ,CACxC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM;qFACjE;AAEkB,IAAA,sBAAsB,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;+FAAC;AAE3E,IAAA,IAAI,GAAG,QAAQ,CAAC,MAAK;QACtC,MAAM,KAAK,GAAa,EAAE;AAC1B,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE;AAC5B,QAAA,IAAI,MAAM;AAAE,YAAA,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;AAC9B,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE;AAC9B,QAAA,IAAI,GAAG;YAAE,KAAK,CAAC,IAAI,CAAC,CAAA,IAAA,EAAO,WAAW,CAAC,GAAG,CAAC,CAAA,CAAE,CAAC;AAC9C,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;IAC1B,CAAC;6EAAC;AAEQ,IAAA,UAAU,CAAC,KAAa,EAAA;AAChC,QAAA,OAAO,WAAW,CAAC,KAAK,CAAC;IAC3B;AAEU,IAAA,SAAS,CAAC,IAAqB,EAAA;QACvC,OAAO,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU;IAChE;IAEU,SAAS,CAAC,MAAc,EAAE,IAAqB,EAAA;QACvD,OAAO,IAAI,CAAC,EAAE;IAChB;IAEA,WAAW,GAAA;QACT,KAAK,MAAM,YAAY,IAAI,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,EAAE;YAC5D,YAAY,CAAC,WAAW,EAAE;QAC5B;AACA,QAAA,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE;QAEhC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,EAAE;YAC/B,IAAI,IAAI,CAAC,UAAU;AAAE,gBAAA,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC;QAC3D;IACF;AAEU,IAAA,WAAW,CAAC,EAAa,EAAA;QACjC,EAAE,CAAC,cAAc,EAAE;QACnB,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;QACrB,IAAI,CAAC,WAAW,EAAE;AAClB,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;IAC3B;AAEU,IAAA,UAAU,CAAC,EAAa,EAAA;QAChC,EAAE,CAAC,cAAc,EAAE;AACnB,QAAA,IAAI,EAAE,CAAC,YAAY,EAAE;AACnB,YAAA,EAAE,CAAC,YAAY,CAAC,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,MAAM,GAAG,MAAM;QAChE;IACF;AAEU,IAAA,WAAW,CAAC,EAAa,EAAA;QACjC,EAAE,CAAC,cAAc,EAAE;QACnB,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;AACrB,QAAA,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;AACpD,QAAA,IAAI,IAAI,CAAC,WAAW,KAAK,CAAC;AAAE,YAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;IACxD;IAEU,MAAM,MAAM,CAAC,EAAa,EAAA;QAClC,EAAE,CAAC,cAAc,EAAE;AACnB,QAAA,IAAI,CAAC,WAAW,GAAG,CAAC;AACpB,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;QAC1B,IAAI,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,YAAY;YAAE;QAEzC,MAAM,KAAK,GAAG,MAAM,4BAA4B,CAAC,EAAE,CAAC,YAAY,CAAC;AACjE,QAAA,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC;IACjC;IAEU,aAAa,GAAA;QACrB,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;QACrB,IAAI,CAAC,SAAS,EAAE,EAAE,aAAa,CAAC,KAAK,EAAE;IACzC;AAEU,IAAA,SAAS,CAAC,EAAiB,EAAA;AACnC,QAAA,IAAI,EAAE,CAAC,GAAG,KAAK,OAAO,IAAI,EAAE,CAAC,GAAG,KAAK,GAAG,EAAE;YACxC,EAAE,CAAC,cAAc,EAAE;YACnB,IAAI,CAAC,aAAa,EAAE;QACtB;IACF;AAEU,IAAA,iBAAiB,CAAC,EAAS,EAAA;AACnC,QAAA,MAAM,KAAK,GAAG,EAAE,CAAC,MAA0B;AAC3C,QAAA,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;AAC3C,QAAA,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC;AAC/B,QAAA,KAAK,CAAC,KAAK,GAAG,EAAE;IAClB;AAEU,IAAA,UAAU,CAAC,EAAU,EAAA;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;QACpD,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,WAAW,EAAE;AAC/C,QAAA,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC;;;;QAKnC,IAAI,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE;AACnC,YAAA,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC;QAC1D;QAEA,IAAI,MAAM,EAAE,UAAU;AAAE,YAAA,GAAG,CAAC,eAAe,CAAC,MAAM,CAAC,UAAU,CAAC;QAE9D,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;;;QAI5D,IAAI,CAAC,gBAAgB,EAAE;QACvB,IAAI,CAAC,SAAS,EAAE;IAClB;IAEU,SAAS,GAAA;AACjB,QAAA,IAAI,CAAC,cAAc,CACjB,IAAI,CAAC,KAAK;AACP,aAAA,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;aACrC,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC,CAC1B;IACH;AAEU,IAAA,YAAY,CAAC,EAAU,EAAA;AAC/B,QAAA,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;IAC3B;AAEU,IAAA,WAAW,CAAC,EAAU,EAAA;QAC9B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,KACrB,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,KACZ,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI,CACtF,CACF;AACD,QAAA,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;IAC3B;AAEQ,IAAA,mBAAmB,CAAC,QAAgB,EAAA;QAC1C,IAAI,CAAC,QAAQ,CAAC,MAAM;YAAE;QAEtB,MAAM,QAAQ,GAAsB,EAAE;QACtC,MAAM,QAAQ,GAA8B,EAAE;;;AAI9C,QAAA,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,MAAM,GAAG,CAAC;AAC/D,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE;AAChC,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE;AAClC,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE;AAElC,QAAA,MAAM,IAAI,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAEzD,QAAA,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE;AACvB,YAAA,IAAI,MAA8C;YAElD,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE;gBACvC,MAAM,GAAG,MAAM;YACjB;iBAAO,IAAI,OAAO,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,GAAG,OAAO,EAAE;gBACjD,MAAM,GAAG,MAAM;YACjB;AAAO,iBAAA,IAAI,QAAQ,IAAI,IAAI,IAAI,aAAa,GAAG,QAAQ,CAAC,MAAM,IAAI,QAAQ,EAAE;gBAC1E,MAAM,GAAG,OAAO;YAClB;YAEA,IAAI,MAAM,EAAE;gBACV,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gBAC/B;YACF;YAEA,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;YAC9C,QAAQ,CAAC,IAAI,CAAC;gBACZ,EAAE,EAAE,MAAM,EAAE;gBACZ,IAAI;AACJ,gBAAA,UAAU,EAAE,OAAO,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,SAAS;AAC3D,gBAAA,MAAM,EAAE,UAAU;AAClB,gBAAA,QAAQ,EAAE,CAAC;AACZ,aAAA,CAAC;QACJ;AAEA,QAAA,IAAI,QAAQ,CAAC,MAAM,EAAE;YACnB,IAAI,CAAC,UAAU,EAAE;gBACf,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,KAAK,EAAE,EAAE;AACnC,oBAAA,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,WAAW,EAAE;oBACxD,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC5C,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACxC,IAAI,QAAQ,CAAC,UAAU;AAAE,wBAAA,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,UAAU,CAAC;gBACnE;gBACA,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI;YAChD;AAEA,YAAA,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC;AAC7E,YAAA,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;YACjD,IAAI,CAAC,gBAAgB,EAAE;AAEvB,YAAA,IAAI,IAAI,CAAC,UAAU,EAAE,EAAE;AACrB,gBAAA,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC;YACtD;QACF;AAEA,QAAA,IAAI,QAAQ,CAAC,MAAM,EAAE;AACnB,YAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC;QACnC;IACF;AAEQ,IAAA,cAAc,CAAC,GAAa,EAAA;QAClC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;AAC5B,YAAA,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,0DAA0D,CAAC;YACnF,KAAK,MAAM,EAAE,IAAI,GAAG;gBAAE,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC;YAC5D;QACF;QAEA,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC;AACxC,QAAA,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE;YACpB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC;AACxD,YAAA,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE;AACtD,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;AACzB,YAAA,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QAChB;QAEA,IAAI,CAAC,SAAS,EAAE;IAClB;IAEQ,SAAS,GAAA;QACf,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;AAE9D,QAAA,OAAO,IAAI,CAAC,aAAa,GAAG,KAAK,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE;YAC5D,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,EAAG;YACpC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC;YAExD,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;gBAAE;AAEpC,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QACxB;IACF;AAEQ,IAAA,WAAW,CAAC,IAAqB,EAAA;QACvC,IAAI,CAAC,aAAa,EAAE;QACpB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;AAEjC,QAAA,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE;AACvB,YAAA,MAAM,EAAE,WAAW;AACnB,YAAA,QAAQ,EAAE,CAAC;AACX,YAAA,KAAK,EAAE,SAAS;AACjB,SAAA,CAAC;QAEF,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;AAChE,QAAA,IAAI,OAAO;AAAE,YAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC;AAE7C,QAAA,IAAI,YAA0B;AAE9B,QAAA,IAAI;YACF,YAAY,GAAG,IAAI,CAAC;AACjB,iBAAA,MAAM,CAAC;AACN,gBAAA,GAAG,EAAE,IAAI,CAAC,SAAS,EAAE;AACrB,gBAAA,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,MAAM;gBACnC,IAAI,EAAE,IAAI,CAAC,IAAI;AACf,gBAAA,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE;AACvB,gBAAA,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE;AAC7B,gBAAA,eAAe,EAAE,IAAI,CAAC,qBAAqB,EAAE;aAC9C;AACA,iBAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC/C,iBAAA,SAAS,CAAC;AACT,gBAAA,IAAI,EAAE,CAAC,KAAK,KAAI;AACd,oBAAA,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE;AAC7B,wBAAA,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE;4BACvB,QAAQ,EAAE,KAAK,CAAC,OAAO;AACxB,yBAAA,CAAC;wBAEF,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;wBAChE,IAAI,OAAO,EAAE;AACX,4BAAA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC;AACvB,gCAAA,IAAI,EAAE,OAAO;gCACb,MAAM,EAAE,KAAK,CAAC,MAAM;gCACpB,KAAK,EAAE,KAAK,CAAC,KAAK;gCAClB,OAAO,EAAE,KAAK,CAAC,OAAO;AACvB,6BAAA,CAAC;wBACJ;wBACA;oBACF;AAEA,oBAAA,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE;AACvB,wBAAA,MAAM,EAAE,UAAU;AAClB,wBAAA,QAAQ,EAAE,GAAG;wBACb,QAAQ,EAAE,KAAK,CAAC,QAAQ;AACxB,wBAAA,KAAK,EAAE,SAAS;AACjB,qBAAA,CAAC;oBAEF,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;AAChE,oBAAA,IAAI,OAAO;AAAE,wBAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC;gBAC/C,CAAC;AACD,gBAAA,KAAK,EAAE,CAAC,KAAK,KAAI;oBACf,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC;gBAC5C,CAAC;AACF,aAAA,CAAC;QACN;QAAE,OAAO,KAAK,EAAE;YACd,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC;AAC1C,YAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B;QACF;QAEA,IAAI,CAAC,YAAY,CAAC,MAAM;YAAE,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,YAAY,CAAC;IAC/E;AAEQ,IAAA,eAAe,CAAC,EAAU,EAAE,KAAc,EAAE,iBAA0B,EAAA;AAC5E,QAAA,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE;AAClB,YAAA,MAAM,EAAE,OAAO;YACf,KAAK;AACN,SAAA,CAAC;QAEF,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC;AACxD,QAAA,IAAI,IAAI;YAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QAEhD,IAAI,CAAC,iBAAiB,EAAE;YACtB,IAAI,CAAC,SAAS,EAAE;QAClB;IACF;AAEQ,IAAA,YAAY,CAAC,EAAU,EAAA;AAC7B,QAAA,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC;QAEnC,IAAI,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE;AACnC,YAAA,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC;QAC1D;QAEA,IAAI,CAAC,SAAS,EAAE;IAClB;IAEQ,UAAU,CAAC,EAAU,EAAE,KAA+B,EAAA;AAC5D,QAAA,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,KACrB,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC,CACpE;IACH;IAEQ,gBAAgB,GAAA;QACtB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;IACxD;uGAjYW,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAApB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,oBAAoB,s1EC1CjC,u/JA6IA,EAAA,MAAA,EAAA,CAAA,+hMAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FDnGa,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBAVhC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,cAAc,cACZ,IAAI,EAAA,eAAA,EACC,uBAAuB,CAAC,MAAM,EAAA,IAAA,EAGzC;AACJ,wBAAA,KAAK,EAAE,mBAAmB;AAC3B,qBAAA,EAAA,QAAA,EAAA,u/JAAA,EAAA,MAAA,EAAA,CAAA,+hMAAA,CAAA,EAAA;43DAqDoE,WAAW,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AE7FlF;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"ngx-kit-dropzone.mjs","sources":["../../../projects/libs/dropzone/services/ngx-dropzone-http-upload.service.ts","../../../projects/libs/dropzone/services/ngx-dropzone-upload.token.ts","../../../projects/libs/dropzone/utils/file-matching.ts","../../../projects/libs/dropzone/components/dropzone.component.ts","../../../projects/libs/dropzone/components/dropzone.component.html","../../../projects/libs/dropzone/ngx-kit-dropzone.ts"],"sourcesContent":["import {\n HttpClient,\n HttpEvent,\n HttpEventType,\n HttpHeaders,\n HttpResponse,\n HttpUploadProgressEvent,\n} from '@angular/common/http';\nimport { Injectable, inject } from '@angular/core';\nimport { Observable, filter, map } from 'rxjs';\nimport {\n NgxDropzoneUploadEvent,\n NgxDropzoneUploadRequest,\n NgxDropzoneUploadService,\n} from '../contracts/dropzone-upload';\n\n@Injectable({ providedIn: 'root' })\nexport class NgxDropzoneHttpUploadService implements NgxDropzoneUploadService {\n private readonly http = inject(HttpClient);\n\n upload<TResponse = unknown>(\n request: NgxDropzoneUploadRequest,\n ): Observable<NgxDropzoneUploadEvent<TResponse>> {\n const body = new FormData();\n body.append(request.alias, request.file, request.file.name);\n\n for (const [key, value] of Object.entries(request.data ?? {})) {\n body.append(key, value instanceof Blob ? value : String(value));\n }\n\n const headers =\n request.headers instanceof HttpHeaders ? request.headers : new HttpHeaders(request.headers);\n\n return this.http\n .post<TResponse>(request.url, body, {\n headers,\n withCredentials: request.withCredentials ?? false,\n observe: 'events',\n reportProgress: true,\n })\n .pipe(\n filter(\n (event): event is HttpUploadProgressEvent | HttpResponse<TResponse> =>\n event.type === HttpEventType.UploadProgress || event.type === HttpEventType.Response,\n ),\n map((event): NgxDropzoneUploadEvent<TResponse> => {\n if (event.type === HttpEventType.UploadProgress) {\n const total = event.total;\n\n return {\n type: 'progress',\n loaded: event.loaded,\n total,\n percent: total ? Math.min(100, Math.round((event.loaded / total) * 100)) : 0,\n };\n }\n\n return {\n type: 'response',\n response: event.body as TResponse,\n status: event.status,\n headers: event.headers,\n };\n }),\n );\n }\n}\n","import { InjectionToken, inject } from '@angular/core';\nimport { NgxDropzoneHttpUploadService } from './ngx-dropzone-http-upload.service';\nimport { NgxDropzoneUploadService } from '../contracts/dropzone-upload';\n\n/**\n * Upload adapter used by ngx-dropzone.\n *\n * Default: Angular HttpClient.\n * Override this token at application/component level to use Axios or any\n * other upload implementation.\n */\nexport const NGX_DROPZONE_UPLOAD_SERVICE = new InjectionToken<NgxDropzoneUploadService>(\n 'NGX_DROPZONE_UPLOAD_SERVICE',\n {\n providedIn: 'root',\n factory: () => inject(NgxDropzoneHttpUploadService),\n },\n);\n","/**\n * چک میکنه یه فایل با pattern رشتهای accept (مثل input[type=file])\n * مطابقت داره یا نه. پشتیبانی میشه از:\n * - MIME کامل: \"image/png\"\n * - MIME با wildcard: \"image/*\"\n * - پسوند فایل: \".png\", \".jpg\"\n * - لیست کاما-جدا از موارد بالا: \"image/*,.pdf,.docx\"\n */\nexport function matchesAccept(file: File, accept?: string): boolean {\n if (!accept || accept.trim() === '') return true;\n\n const patterns = accept\n .split(',')\n .map((p) => p.trim().toLowerCase())\n .filter(Boolean);\n\n if (!patterns.length) return true;\n\n const fileName = file.name.toLowerCase();\n const fileType = (file.type || '').toLowerCase();\n\n return patterns.some((pattern) => {\n if (pattern.startsWith('.')) {\n return fileName.endsWith(pattern);\n }\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -1); // \"image/\"\n return fileType.startsWith(prefix);\n }\n return fileType === pattern;\n });\n}\n\n/** تبدیل بایت به یه رشتهی خوانا (KB/MB/GB) */\nexport function formatBytes(bytes: number): string {\n if (bytes === 0) return '0 B';\n const units = ['B', 'KB', 'MB', 'GB', 'TB'];\n const i = Math.floor(Math.log(bytes) / Math.log(1024));\n const value = bytes / Math.pow(1024, i);\n return `${value.toFixed(i === 0 ? 0 : 1)} ${units[i]}`;\n}\n\n/** استخراج فایلهای واقعی از یک DataTransfer، شامل پیمایش بازگشتیِ پوشهها (وقتی مرورگر پشتیبانی کنه) */\nexport async function extractFilesFromDataTransfer(dataTransfer: DataTransfer): Promise<File[]> {\n const items = Array.from(dataTransfer.items || []);\n const hasEntrySupport = items.length > 0 && typeof items[0].webkitGetAsEntry === 'function';\n\n if (!hasEntrySupport) {\n return Array.from(dataTransfer.files || []);\n }\n\n const entries = items\n .map((item) => item.webkitGetAsEntry?.())\n .filter((e): e is FileSystemEntry => !!e);\n\n if (!entries.length) {\n return Array.from(dataTransfer.files || []);\n }\n\n const files: File[] = [];\n await Promise.all(entries.map((entry) => walkEntry(entry, files)));\n return files;\n}\n\nfunction walkEntry(entry: FileSystemEntry, out: File[]): Promise<void> {\n return new Promise((resolve) => {\n if (entry.isFile) {\n (entry as FileSystemFileEntry).file(\n (file) => {\n out.push(file);\n resolve();\n },\n () => resolve(),\n );\n } else if (entry.isDirectory) {\n const reader = (entry as FileSystemDirectoryEntry).createReader();\n const readAll: FileSystemEntry[] = [];\n const readBatch = () => {\n reader.readEntries(\n async (batch) => {\n if (!batch.length) {\n await Promise.all(readAll.map((e) => walkEntry(e, out)));\n resolve();\n return;\n }\n readAll.push(...batch);\n readBatch();\n },\n () => resolve(),\n );\n };\n readBatch();\n } else {\n resolve();\n }\n });\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n OnDestroy,\n computed,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { Subscription, finalize } from 'rxjs';\nimport {\n NgxDropzoneFile,\n NgxDropzoneRejectedFile,\n NgxDropzoneRejectionReason,\n} from '../contracts/dropzone-file';\nimport {\n NgxDropzoneUploadProgressEvent,\n NgxDropzoneUploadService,\n} from '../contracts/dropzone-upload';\nimport { NGX_DROPZONE_UPLOAD_SERVICE } from '../services/ngx-dropzone-upload.token';\nimport { extractFilesFromDataTransfer, formatBytes, matchesAccept } from '../utils/file-matching';\n\nlet uidCounter = 0;\nfunction nextId(): string {\n return `ngx-dz-${Date.now().toString(36)}-${uidCounter++}`;\n}\n\nexport type NgxDropzoneUploadMode = 'all' | 'single';\n\n@Component({\n selector: 'ngx-dropzone',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './dropzone.component.html',\n styleUrl: './dropzone.component.scss',\n host: {\n class: 'ngx-dropzone-host',\n },\n})\nexport class NgxDropzone implements OnDestroy {\n /** الگوی accept مثل input[type=file]: \"image/*\", \".pdf,.docx\" و ... */\n accept = input<string>('');\n multiple = input<boolean>(true);\n /** حداکثر حجم هر فایل به بایت؛ undefined یعنی بدون محدودیت */\n maxFileSize = input<number | undefined>(undefined);\n /** حداکثر تعداد فایل مجاز؛ undefined یعنی بدون محدودیت */\n maxFiles = input<number | undefined>(undefined);\n disabled = input<boolean>(false);\n /** نمایش لیست/پیشنمایش فایلهای انتخابشده داخل خودِ کامپوننت */\n showFileList = input<boolean>(true);\n\n /** Upload endpoint. */\n uploadUrl = input<string>('');\n /** Multipart form-data field name. */\n uploadAlias = input<string>('file');\n /** Automatically enqueue newly accepted files for upload. */\n autoUpload = input<boolean>(false);\n /** Maximum number of simultaneous uploads. */\n maxParallel = input<number>(3);\n /**\n * Manual upload behavior:\n * - all: one \"Upload all\" action uploads all pending files.\n * - single: every pending row gets its own Upload button.\n */\n uploadMode = input<NgxDropzoneUploadMode>('all');\n /** Extra multipart form fields sent with every file. */\n uploadData = input<Record<string, string | Blob | number | boolean>>({});\n /** Optional request headers. */\n uploadHeaders = input<Record<string, string | string[]>>({});\n /** Send credentials/cookies with the upload request. */\n uploadWithCredentials = input<boolean>(false);\n\n filesAdded = output<File[]>();\n filesRejected = output<NgxDropzoneRejectedFile[]>();\n filesChange = output<File[]>();\n\n /** Emitted when an individual upload starts. */\n uploadStarted = output<NgxDropzoneFile>();\n /** Emitted for every upload progress update. */\n uploadProgress = output<NgxDropzoneUploadProgressEvent>();\n /** Emitted after a file is successfully uploaded. */\n uploadSuccess = output<NgxDropzoneFile>();\n /** Emitted when an upload fails. */\n uploadError = output<{ item: NgxDropzoneFile; error: unknown }>();\n\n protected readonly files = signal<NgxDropzoneFile[]>([]);\n protected readonly isDragging = signal(false);\n private dragCounter = 0;\n\n private readonly uploadService = inject<NgxDropzoneUploadService>(NGX_DROPZONE_UPLOAD_SERVICE);\n private readonly fileInput = viewChild<ElementRef<HTMLInputElement>>('fileInput');\n private readonly uploadSubscriptions = new Map<string, Subscription>();\n private readonly uploadQueue: string[] = [];\n private activeUploads = 0;\n private readonly activeUploadIds = new Set<string>();\n\n protected readonly pendingCount = computed(\n () => this.files().filter((item) => this.isPending(item)).length,\n );\n\n protected readonly hasUploadConfiguration = computed(() => this.uploadUrl().trim().length > 0);\n\n protected readonly hint = computed(() => {\n const parts: string[] = [];\n const accept = this.accept();\n if (accept) parts.push(accept);\n const max = this.maxFileSize();\n if (max) parts.push(`max ${formatBytes(max)}`);\n return parts.join(' · ');\n });\n\n protected formatSize(bytes: number): string {\n return formatBytes(bytes);\n }\n\n protected isPending(item: NgxDropzoneFile): boolean {\n return item.status === 'pending' || item.status === 'accepted';\n }\n\n protected trackById(_index: number, item: NgxDropzoneFile): string {\n return item.id;\n }\n\n ngOnDestroy(): void {\n for (const subscription of this.uploadSubscriptions.values()) {\n subscription.unsubscribe();\n }\n this.uploadSubscriptions.clear();\n\n for (const item of this.files()) {\n if (item.previewUrl) URL.revokeObjectURL(item.previewUrl);\n }\n }\n\n protected onDragEnter(ev: DragEvent): void {\n ev.preventDefault();\n if (this.disabled()) return;\n this.dragCounter++;\n this.isDragging.set(true);\n }\n\n protected onDragOver(ev: DragEvent): void {\n ev.preventDefault();\n if (ev.dataTransfer) {\n ev.dataTransfer.dropEffect = this.disabled() ? 'none' : 'copy';\n }\n }\n\n protected onDragLeave(ev: DragEvent): void {\n ev.preventDefault();\n if (this.disabled()) return;\n this.dragCounter = Math.max(0, this.dragCounter - 1);\n if (this.dragCounter === 0) this.isDragging.set(false);\n }\n\n protected async onDrop(ev: DragEvent): Promise<void> {\n ev.preventDefault();\n this.dragCounter = 0;\n this.isDragging.set(false);\n if (this.disabled() || !ev.dataTransfer) return;\n\n const files = await extractFilesFromDataTransfer(ev.dataTransfer);\n this.handleIncomingFiles(files);\n }\n\n protected onBrowseClick(): void {\n if (this.disabled()) return;\n this.fileInput()?.nativeElement.click();\n }\n\n protected onKeydown(ev: KeyboardEvent): void {\n if (ev.key === 'Enter' || ev.key === ' ') {\n ev.preventDefault();\n this.onBrowseClick();\n }\n }\n\n protected onFileInputChange(ev: Event): void {\n const input = ev.target as HTMLInputElement;\n const files = Array.from(input.files ?? []);\n this.handleIncomingFiles(files);\n input.value = '';\n }\n\n protected removeFile(id: string): void {\n const target = this.files().find((f) => f.id === id);\n this.uploadSubscriptions.get(id)?.unsubscribe();\n this.uploadSubscriptions.delete(id);\n\n // Unsubscribing an HttpClient upload cancels the request. Release its\n // concurrency slot immediately; finalize() will see that the id is no\n // longer active and won't decrement twice.\n if (this.activeUploadIds.delete(id)) {\n this.activeUploads = Math.max(0, this.activeUploads - 1);\n }\n\n if (target?.previewUrl) URL.revokeObjectURL(target.previewUrl);\n\n this.files.update((list) => list.filter((f) => f.id !== id));\n\n // Remove stale queue entries. The queue is intentionally lazy, so an\n // entry can safely remain until pumpQueue() sees that it no longer exists.\n this.emitCurrentFiles();\n this.pumpQueue();\n }\n\n protected uploadAll(): void {\n this.enqueueUploads(\n this.files()\n .filter((item) => this.isPending(item))\n .map((item) => item.id),\n );\n }\n\n protected uploadSingle(id: string): void {\n this.enqueueUploads([id]);\n }\n\n protected retryUpload(id: string): void {\n this.files.update((list) =>\n list.map((item) =>\n item.id === id ? { ...item, status: 'pending', progress: 0, error: undefined } : item,\n ),\n );\n this.enqueueUploads([id]);\n }\n\n private handleIncomingFiles(incoming: File[]): void {\n if (!incoming.length) return;\n\n const accepted: NgxDropzoneFile[] = [];\n const rejected: NgxDropzoneRejectedFile[] = [];\n\n // A single-file dropzone behaves like a native single-select input:\n // selecting another file replaces the previous one.\n const existingCount = this.multiple() ? this.files().length : 0;\n const maxFiles = this.maxFiles();\n const maxSize = this.maxFileSize();\n const isMultiple = this.multiple();\n\n const pool = isMultiple ? incoming : incoming.slice(0, 1);\n\n for (const file of pool) {\n let reason: NgxDropzoneRejectionReason | undefined;\n\n if (!matchesAccept(file, this.accept())) {\n reason = 'type';\n } else if (maxSize != null && file.size > maxSize) {\n reason = 'size';\n } else if (maxFiles != null && existingCount + accepted.length >= maxFiles) {\n reason = 'count';\n }\n\n if (reason) {\n rejected.push({ file, reason });\n continue;\n }\n\n const isImage = file.type.startsWith('image/');\n accepted.push({\n id: nextId(),\n file,\n previewUrl: isImage ? URL.createObjectURL(file) : undefined,\n status: 'accepted',\n progress: 0,\n });\n }\n\n if (accepted.length) {\n if (!isMultiple) {\n for (const previous of this.files()) {\n this.uploadSubscriptions.get(previous.id)?.unsubscribe();\n this.uploadSubscriptions.delete(previous.id);\n this.activeUploadIds.delete(previous.id);\n if (previous.previewUrl) URL.revokeObjectURL(previous.previewUrl);\n }\n this.activeUploads = this.activeUploadIds.size;\n }\n\n this.files.update((list) => (isMultiple ? [...list, ...accepted] : accepted));\n this.filesAdded.emit(accepted.map((a) => a.file));\n this.emitCurrentFiles();\n\n if (this.autoUpload()) {\n this.enqueueUploads(accepted.map((item) => item.id));\n }\n }\n\n if (rejected.length) {\n this.filesRejected.emit(rejected);\n }\n }\n\n private enqueueUploads(ids: string[]): void {\n if (!this.uploadUrl().trim()) {\n const error = new Error('ngx-dropzone: uploadUrl is required for uploading files.');\n for (const id of ids) this.markUploadError(id, error, false);\n return;\n }\n\n const queued = new Set(this.uploadQueue);\n for (const id of ids) {\n const item = this.files().find((file) => file.id === id);\n if (!item || !this.isPending(item) || queued.has(id)) continue;\n this.uploadQueue.push(id);\n queued.add(id);\n }\n\n this.pumpQueue();\n }\n\n private pumpQueue(): void {\n const limit = Math.max(1, Math.floor(this.maxParallel() || 1));\n\n while (this.activeUploads < limit && this.uploadQueue.length) {\n const id = this.uploadQueue.shift()!;\n const item = this.files().find((file) => file.id === id);\n\n if (!item || !this.isPending(item)) continue;\n\n this.startUpload(item);\n }\n }\n\n private startUpload(item: NgxDropzoneFile): void {\n this.activeUploads++;\n this.activeUploadIds.add(item.id);\n\n this.updateFile(item.id, {\n status: 'uploading',\n progress: 0,\n error: undefined,\n });\n\n const current = this.files().find((file) => file.id === item.id);\n if (current) this.uploadStarted.emit(current);\n\n let subscription: Subscription;\n\n try {\n subscription = this.uploadService\n .upload({\n url: this.uploadUrl(),\n alias: this.uploadAlias() || 'file',\n file: item.file,\n data: this.uploadData(),\n headers: this.uploadHeaders(),\n withCredentials: this.uploadWithCredentials(),\n })\n .pipe(finalize(() => this.finishUpload(item.id)))\n .subscribe({\n next: (event) => {\n if (event.type === 'progress') {\n this.updateFile(item.id, {\n progress: event.percent,\n });\n\n const updated = this.files().find((file) => file.id === item.id);\n if (updated) {\n this.uploadProgress.emit({\n item: updated,\n loaded: event.loaded,\n total: event.total,\n percent: event.percent,\n });\n }\n return;\n }\n\n this.updateFile(item.id, {\n status: 'uploaded',\n progress: 100,\n response: event.response,\n error: undefined,\n });\n\n const updated = this.files().find((file) => file.id === item.id);\n if (updated) this.uploadSuccess.emit(updated);\n },\n error: (error) => {\n this.markUploadError(item.id, error, true);\n },\n });\n } catch (error) {\n this.markUploadError(item.id, error, true);\n this.finishUpload(item.id);\n return;\n }\n\n if (!subscription.closed) this.uploadSubscriptions.set(item.id, subscription);\n }\n\n private markUploadError(id: string, error: unknown, releaseActiveSlot: boolean): void {\n this.updateFile(id, {\n status: 'error',\n error,\n });\n\n const item = this.files().find((file) => file.id === id);\n if (item) this.uploadError.emit({ item, error });\n\n if (!releaseActiveSlot) {\n this.pumpQueue();\n }\n }\n\n private finishUpload(id: string): void {\n this.uploadSubscriptions.delete(id);\n\n if (this.activeUploadIds.delete(id)) {\n this.activeUploads = Math.max(0, this.activeUploads - 1);\n }\n\n this.pumpQueue();\n }\n\n private updateFile(id: string, patch: Partial<NgxDropzoneFile>): void {\n this.files.update((list) =>\n list.map((item) => (item.id === id ? { ...item, ...patch } : item)),\n );\n }\n\n private emitCurrentFiles(): void {\n this.filesChange.emit(this.files().map((f) => f.file));\n }\n}\n","<div\n class=\"ngx-dropzone\"\n [class.dragging]=\"isDragging()\"\n [class.disabled]=\"disabled()\"\n [class.has-files]=\"files().length > 0\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-disabled]=\"disabled()\"\n (click)=\"onBrowseClick()\"\n (keydown)=\"onKeydown($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n <input\n #fileInput\n type=\"file\"\n class=\"ngx-dropzone-input\"\n [accept]=\"accept()\"\n [multiple]=\"multiple()\"\n [disabled]=\"disabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"onFileInputChange($event)\" />\n\n <div class=\"ngx-dropzone-icon-wrap\">\n <ng-content select=\"[dropzone-icon]\">\n <svg class=\"ngx-dropzone-icon\" viewBox=\"0 0 24 24\" fill=\"none\" width=\"30\" height=\"30\">\n <path\n d=\"M12 16V4M12 4l-4 4M12 4l4 4M4 16v2a2 2 0 002 2h12a2 2 0 002-2v-2\"\n stroke=\"currentColor\"\n stroke-width=\"1.8\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </ng-content>\n </div>\n\n <div class=\"ngx-dropzone-text\">\n <ng-content>\n <strong>Drop files here</strong>\n <span>or click to browse</span>\n </ng-content>\n </div>\n\n @if (hint()) {\n <div class=\"ngx-dropzone-hint\">{{ hint() }}</div>\n }\n</div>\n\n@if (!autoUpload() && uploadMode() === 'all' && pendingCount() > 0) {\n <div class=\"ngx-dropzone-actions\">\n <button\n type=\"button\"\n class=\"ngx-dropzone-upload-all\"\n [disabled]=\"disabled() || !hasUploadConfiguration()\"\n (click)=\"uploadAll(); $event.stopPropagation()\">\n Upload all\n <span>{{ pendingCount() }}</span>\n </button>\n </div>\n}\n\n@if (showFileList() && files().length) {\n <ul class=\"ngx-dropzone-list\">\n @for (item of files(); track item.id) {\n <li class=\"ngx-dropzone-item\" [class.is-uploading]=\"item.status === 'uploading'\">\n <div class=\"ngx-dropzone-thumb-wrap\">\n @if (item.previewUrl) {\n <img class=\"ngx-dropzone-thumb\" [src]=\"item.previewUrl\" [alt]=\"item.file.name\" />\n } @else {\n <span class=\"ngx-dropzone-file-icon\">📄</span>\n }\n </div>\n\n <div class=\"ngx-dropzone-meta\">\n <span class=\"ngx-dropzone-name\" [title]=\"item.file.name\">{{ item.file.name }}</span>\n <span class=\"ngx-dropzone-size\">{{ formatSize(item.file.size) }}</span>\n\n @if (item.status === 'uploading' || item.status === 'uploaded') {\n <div\n class=\"ngx-dropzone-progress\"\n role=\"progressbar\"\n [attr.aria-valuenow]=\"item.progress\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n [attr.aria-label]=\"'Upload progress for ' + item.file.name\">\n <span class=\"ngx-dropzone-progress-bar\" [style.width.%]=\"item.progress\"></span>\n </div>\n <span class=\"ngx-dropzone-progress-text\">{{ item.progress }}%</span>\n }\n\n @if (item.status === 'error') {\n <span class=\"ngx-dropzone-error\">Upload failed</span>\n }\n </div>\n\n <div class=\"ngx-dropzone-row-actions\">\n @if (!autoUpload() && uploadMode() === 'single' && isPending(item)) {\n <button\n type=\"button\"\n class=\"ngx-dropzone-upload\"\n [disabled]=\"disabled() || !hasUploadConfiguration()\"\n [attr.aria-label]=\"'Upload ' + item.file.name\"\n (click)=\"uploadSingle(item.id); $event.stopPropagation()\">\n Upload\n </button>\n }\n\n @if (item.status === 'error') {\n <button\n type=\"button\"\n class=\"ngx-dropzone-retry\"\n [disabled]=\"disabled() || !hasUploadConfiguration()\"\n [attr.aria-label]=\"'Retry upload for ' + item.file.name\"\n (click)=\"retryUpload(item.id); $event.stopPropagation()\">\n Retry\n </button>\n }\n\n @if (item.status === 'uploaded') {\n <span class=\"ngx-dropzone-status success\" aria-label=\"Uploaded\">✓</span>\n } @else if (item.status === 'uploading') {\n <span class=\"ngx-dropzone-status uploading\" aria-label=\"Uploading\"></span>\n } @else if (item.status === 'error') {\n <span class=\"ngx-dropzone-status error\" aria-label=\"Upload failed\">!</span>\n } @else {\n <span class=\"ngx-dropzone-status pending\" aria-label=\"Pending\">•</span>\n }\n\n <button\n type=\"button\"\n class=\"ngx-dropzone-remove\"\n [attr.aria-label]=\"'Remove ' + item.file.name\"\n (click)=\"removeFile(item.id); $event.stopPropagation()\">\n ✕\n </button>\n </div>\n </li>\n }\n </ul>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -264,27 +264,7 @@ class NgxImageEditorLocalization {
|
|
|
264
264
|
const DEFAULT_NGX_IMAGE_EDITOR_LOCALIZATION = new NgxImageEditorLocalization();
|
|
265
265
|
|
|
266
266
|
const ALL_FILTERS = ['none', 'grayscale', 'sepia', 'invert', 'cartoon'];
|
|
267
|
-
|
|
268
|
-
* ویرایشگر تصویر: کراپ + چرخش + روشنایی/کنتراست/اشباع + فیلترهای آماده
|
|
269
|
-
* (سیاهوسفید، سپیا، معکوس، کارتونی) + فشردهسازی خروجی. کاملاً روی Canvas
|
|
270
|
-
* خام پیاده شده، بدون هیچ وابستگی خارجیای.
|
|
271
|
-
*
|
|
272
|
-
* نکتهی مهمِ معماری: تمام تعامل زنده (چرخوندن، جابهجا/ریسایز کراپباکس،
|
|
273
|
-
* پیشنمایش فیلترها حتی کارتونی) روی یه کپیِ کوچیکشده از تصویر انجام میشه
|
|
274
|
-
* (createWorkingCopy)، نه روی تصویر اصلی که ممکنه چند مگاپیکسل باشه — وگرنه
|
|
275
|
-
* درگکردن اسلایدرها/گوشههای کراپ رو کاربر حس تاخیر میکرد. فقط لحظهی
|
|
276
|
-
* save()، رندر نهایی از روی تصویر اصلیِ کامل انجام میشه.
|
|
277
|
-
*
|
|
278
|
-
* اندازهی صحنه (stage) با panelSize کنترل میشه: عرض همیشه ۱۰۰٪ عرضِ
|
|
279
|
-
* والدِ کامپوننته (با ResizeObserver اندازهگیری میشه، پس با تغییر سایز
|
|
280
|
-
* صفحه/layout هم زنده هماهنگ میمونه)، ارتفاع دقیقاً همون چیزیه که کاربر با
|
|
281
|
-
* panelSize میده. تصویر همیشه با یک مقیاسِ «contain» واقعی (هم بر اساس
|
|
282
|
-
* عرض، هم بر اساس ارتفاع — هرکدوم تنگتره) جا داده میشه، پس کلِ تصویر
|
|
283
|
-
* همیشه در محدودهی همین باکس دیده میشه، صرفنظر از اندازهی واقعیِ فایل.
|
|
284
|
-
* سقفِ مقیاس هم ۱ هست، یعنی تصاویر کوچیک بزرگنمایی نمیشن (که باعثِ محو
|
|
285
|
-
* شدنشون میشد).
|
|
286
|
-
*/
|
|
287
|
-
class NgxImageEditorComponent {
|
|
267
|
+
class NgxImageEditor {
|
|
288
268
|
source = input(null, /* @ts-ignore */
|
|
289
269
|
...(ngDevMode ? [{ debugName: "source" }] : /* istanbul ignore next */ []));
|
|
290
270
|
/** قفل نسبتِ کراپ (مثلاً ۱ برای آواتار مربعی)؛ undefined یعنی آزاد */
|
|
@@ -566,16 +546,24 @@ class NgxImageEditorComponent {
|
|
|
566
546
|
const type = this.outputType();
|
|
567
547
|
const blob = await canvasToBlob(finalCanvas, type, this.quality());
|
|
568
548
|
const dataUrl = finalCanvas.toDataURL(type, this.quality());
|
|
569
|
-
|
|
549
|
+
const file = new File([blob], '', { type });
|
|
550
|
+
this.saved.emit({
|
|
551
|
+
blob,
|
|
552
|
+
dataUrl,
|
|
553
|
+
width: finalCanvas.width,
|
|
554
|
+
height: finalCanvas.height,
|
|
555
|
+
file,
|
|
556
|
+
type,
|
|
557
|
+
});
|
|
570
558
|
}
|
|
571
559
|
finally {
|
|
572
560
|
this.saving.set(false);
|
|
573
561
|
}
|
|
574
562
|
}
|
|
575
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type:
|
|
576
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NgxImageEditorComponent, isStandalone: true, selector: "ngx-image-editor", inputs: { source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null }, aspectRatio: { classPropertyName: "aspectRatio", publicName: "aspectRatio", isSignal: true, isRequired: false, transformFunction: null }, outputMaxWidth: { classPropertyName: "outputMaxWidth", publicName: "outputMaxWidth", isSignal: true, isRequired: false, transformFunction: null }, outputMaxHeight: { classPropertyName: "outputMaxHeight", publicName: "outputMaxHeight", isSignal: true, isRequired: false, transformFunction: null }, outputType: { classPropertyName: "outputType", publicName: "outputType", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, quality: { classPropertyName: "quality", publicName: "quality", isSignal: true, isRequired: false, transformFunction: null }, localize: { classPropertyName: "localize", publicName: "localize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { saved: "saved", cancelled: "cancelled" }, host: { classAttribute: "ngx-image-editor-host" }, viewQueries: [{ propertyName: "stageWrapEl", first: true, predicate: ["stageWrap"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (loading()) {\n <div class=\"ngx-ie-state\">{{ localize().LoadingImage }}</div>\n} @else if (loadError()) {\n <div class=\"ngx-ie-state ngx-ie-state--error\">{{ loadError() }}</div>\n} @else if (stageImageUrl()) {\n <div class=\"ngx-ie-layout\">\n <div class=\"ngx-ie-stage-wrap\" #stageWrap>\n <div\n class=\"ngx-ie-stage\"\n [style.width.px]=\"stageSize().width\"\n [style.height.px]=\"stageSize().height\">\n <img class=\"ngx-ie-stage-img\" [src]=\"stageImageUrl()\" alt=\"\" draggable=\"false\" />\n\n <div\n class=\"ngx-ie-crop-box\"\n [style.left]=\"cropOverlayStyle().left\"\n [style.top]=\"cropOverlayStyle().top\"\n [style.width]=\"cropOverlayStyle().width\"\n [style.height]=\"cropOverlayStyle().height\"\n ngxPointerDrag\n (dragStart)=\"onMoveDragStart()\"\n (dragMove)=\"onMoveDragMove($event)\">\n <span\n class=\"ngx-ie-handle ngx-ie-handle--nw\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('nw', $event)\"></span>\n <span\n class=\"ngx-ie-handle ngx-ie-handle--ne\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('ne', $event)\"></span>\n <span\n class=\"ngx-ie-handle ngx-ie-handle--sw\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('sw', $event)\"></span>\n <span\n class=\"ngx-ie-handle ngx-ie-handle--se\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('se', $event)\"></span>\n </div>\n </div>\n </div>\n\n <div class=\"ngx-ie-panel-row\">\n <div class=\"ngx-ie-panel\">\n <div class=\"ngx-ie-preview\">\n @if (previewUrl(); as url) {\n <img [src]=\"url\" alt=\"Preview\" />\n }\n </div>\n\n <div class=\"ngx-ie-row ngx-ie-rotate-row\">\n <button type=\"button\" (click)=\"rotateBy(-90)\" title=\"Rotate 90\u00B0 left\">\u27F2 90</button>\n <button type=\"button\" (click)=\"rotateBy(90)\" title=\"Rotate 90\u00B0 right\">\u27F3 90</button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"rotation()\"\n (ngModelChange)=\"rotation.set($event)\"\n [min]=\"-180\"\n [max]=\"180\">\n <span>{{ localize().Rotation }} ({{ rotation() }}\u00B0)</span>\n </slider>\n\n <button\n type=\"button\"\n (click)=\"rotation.set(0)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"brightness()\"\n (ngModelChange)=\"brightness.set($event)\"\n [min]=\"0\"\n [max]=\"200\">\n <span>{{ localize().Brightness }} ({{ brightness() }}%)</span>\n </slider>\n <button\n type=\"button\"\n (click)=\"brightness.set(100)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"contrast()\"\n (ngModelChange)=\"contrast.set($event)\"\n [min]=\"0\"\n [max]=\"200\">\n <span>{{ localize().Contrast }} ({{ contrast() }}%)</span>\n </slider>\n <button\n type=\"button\"\n (click)=\"contrast.set(100)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"saturation()\"\n (ngModelChange)=\"saturation.set($event)\"\n [min]=\"0\"\n [max]=\"200\">\n <span>{{ localize().Saturation }} ({{ saturation() }}%)</span>\n </slider>\n <button\n type=\"button\"\n (click)=\"saturation.set(100)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n @if (filters().length) {\n <div>\n <span>{{ localize().Filter }}</span>\n <div class=\"ngx-ie-filter-row\">\n @for (f of filters(); track f) {\n <button type=\"button\" [class.active]=\"filterPreset() === f\" (click)=\"setFilter(f)\">\n {{ filterLabels()[f] }}\n </button>\n }\n </div>\n </div>\n }\n\n <div class=\"ngx-ie-row ngx-ie-actions\">\n <button type=\"button\" class=\"ngx-ie-btn-secondary\" (click)=\"cancel()\">\n {{ localize().Cancel }}\n </button>\n <button type=\"button\" class=\"ngx-ie-btn-primary\" [disabled]=\"saving()\" (click)=\"save()\">\n {{ saving() ? localize().Saving : localize().Save }}\n </button>\n </div>\n </div>\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:block;min-height:70dvh;--ngx-image-editor-panel-width: 25%}.ngx-ie-state{padding:2rem;text-align:center;color:light-dark(#6b7280,#9ca3af)}.ngx-ie-state--error{color:light-dark(#b91c1c,#f87171)}.ngx-ie-layout{display:grid;grid-template-columns:1fr var(--ngx-image-editor-panel-width, 30%);gap:1.25rem;height:100%}.ngx-ie-stage-wrap{width:100%;display:flex;align-items:center;justify-content:center;background:light-dark(#f3f4f6,#18181b);border-radius:10px;overflow:hidden;flex-shrink:0}.ngx-ie-stage{position:relative;touch-action:none;-webkit-user-select:none;user-select:none;direction:ltr}.ngx-ie-stage-img{display:block;inline-size:100%;block-size:100%;border-radius:4px;pointer-events:none;background:#fff;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:16px 16px;background-position:0 0,0 8px,8px -8px,-8px 0px}.ngx-ie-crop-box{position:absolute;box-sizing:border-box;border:2px solid #2563eb;box-shadow:0 0 0 9999px #00000073;cursor:move;touch-action:none}.ngx-ie-handle{position:absolute;inline-size:14px;block-size:14px;background:#fff;border:2px solid #2563eb;border-radius:50%;touch-action:none}.ngx-ie-handle--nw{inset-inline-start:-7px;inset-block-start:-7px;cursor:nwse-resize}.ngx-ie-handle--ne{inset-inline-end:-7px;inset-block-start:-7px;cursor:nesw-resize}.ngx-ie-handle--sw{inset-inline-start:-7px;inset-block-end:-7px;cursor:nesw-resize}.ngx-ie-handle--se{inset-inline-end:-7px;inset-block-end:-7px;cursor:nwse-resize}.ngx-ie-panel{flex:1;display:flex;flex-direction:column;gap:.75rem}.ngx-ie-panel-row{display:flex;flex-wrap:wrap;gap:1.25rem}.ngx-ie-preview{display:flex;align-items:center;justify-content:center;min-block-size:100px;background:light-dark(#f3f4f6,#18181b);border-radius:8px;overflow:hidden}.ngx-ie-preview img{max-inline-size:100%;max-block-size:160px;display:block;background:#fff;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:16px 16px;background-position:0 0,0 8px,8px -8px,-8px 0px}.ngx-ie-field{display:flex;gap:.3rem;align-items:flex-end}.ngx-ie-field slider{flex:1}.ngx-ie-row{display:flex;gap:.5rem}.ngx-ie-rotate-row button,.ngx-ie-filter-row button{appearance:none;border:1px solid light-dark(#e5e7eb,#33333a);background:light-dark(#ffffff,#232327);color:light-dark(#374151,#d4d4d8);border-radius:999px;padding:.4rem .85rem;font-size:.75rem;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,transform .15s ease,color .15s ease}.ngx-ie-rotate-row button:hover,.ngx-ie-filter-row button:hover{background:light-dark(#f3f4f6,#2c2c31);transform:translateY(-1px)}.ngx-ie-rotate-row button:active,.ngx-ie-filter-row button:active{transform:translateY(0)}.ngx-ie-rotate-row button.active,.ngx-ie-filter-row button.active{background:light-dark(#2563eb,#3b82f6);border-color:light-dark(#2563eb,#3b82f6);color:#fff;box-shadow:0 2px 10px light-dark(rgba(37,99,235,.3),rgba(59,130,246,.3))}.ngx-ie-filter-row{display:flex;flex-wrap:wrap;gap:.4rem}.ngx-ie-actions{margin-block-start:auto;justify-content:flex-end}.ngx-ie-btn-primary,.ngx-ie-btn-secondary{appearance:none;border:none;border-radius:8px;padding:.55rem 1.1rem;font-size:.85rem;cursor:pointer;font-weight:500;transition:transform .15s ease,box-shadow .15s ease,opacity .15s ease}.ngx-ie-btn-primary:hover,.ngx-ie-btn-secondary:hover{transform:translateY(-1px)}.ngx-ie-btn-primary:active,.ngx-ie-btn-secondary:active{transform:translateY(0)}.ngx-ie-btn-primary{background:light-dark(#2563eb,#3b82f6);color:#fff;box-shadow:0 2px 10px light-dark(rgba(37,99,235,.25),rgba(59,130,246,.25))}.ngx-ie-btn-primary:disabled{opacity:.6;cursor:not-allowed;transform:none}.ngx-ie-btn-secondary{background:light-dark(#e5e7eb,#3f3f46);color:light-dark(#374151,#e4e4e7)}@media(max-width:768px){:host{height:unset!important}.ngx-ie-layout{display:flex;flex-direction:column}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: SliderComponent, selector: "slider", inputs: ["step", "min", "max", "background", "isBgTransparent"], outputs: ["change"] }, { kind: "directive", type: NgxPointerDragDirective, selector: "[ngxPointerDrag]", outputs: ["dragStart", "dragMove", "dragEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
563
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxImageEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
564
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NgxImageEditor, isStandalone: true, selector: "ngx-image-editor", inputs: { source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null }, aspectRatio: { classPropertyName: "aspectRatio", publicName: "aspectRatio", isSignal: true, isRequired: false, transformFunction: null }, outputMaxWidth: { classPropertyName: "outputMaxWidth", publicName: "outputMaxWidth", isSignal: true, isRequired: false, transformFunction: null }, outputMaxHeight: { classPropertyName: "outputMaxHeight", publicName: "outputMaxHeight", isSignal: true, isRequired: false, transformFunction: null }, outputType: { classPropertyName: "outputType", publicName: "outputType", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, quality: { classPropertyName: "quality", publicName: "quality", isSignal: true, isRequired: false, transformFunction: null }, localize: { classPropertyName: "localize", publicName: "localize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { saved: "saved", cancelled: "cancelled" }, host: { classAttribute: "ngx-image-editor-host" }, viewQueries: [{ propertyName: "stageWrapEl", first: true, predicate: ["stageWrap"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (loading()) {\n <div class=\"ngx-ie-state\">{{ localize().LoadingImage }}</div>\n} @else if (loadError()) {\n <div class=\"ngx-ie-state ngx-ie-state--error\">{{ loadError() }}</div>\n} @else if (stageImageUrl()) {\n <div class=\"ngx-ie-layout\">\n <div class=\"ngx-ie-stage-wrap\" #stageWrap>\n <div\n class=\"ngx-ie-stage\"\n [style.width.px]=\"stageSize().width\"\n [style.height.px]=\"stageSize().height\">\n <img class=\"ngx-ie-stage-img\" [src]=\"stageImageUrl()\" alt=\"\" draggable=\"false\" />\n\n <div\n class=\"ngx-ie-crop-box\"\n [style.left]=\"cropOverlayStyle().left\"\n [style.top]=\"cropOverlayStyle().top\"\n [style.width]=\"cropOverlayStyle().width\"\n [style.height]=\"cropOverlayStyle().height\"\n ngxPointerDrag\n (dragStart)=\"onMoveDragStart()\"\n (dragMove)=\"onMoveDragMove($event)\">\n <span\n class=\"ngx-ie-handle ngx-ie-handle--nw\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('nw', $event)\"></span>\n <span\n class=\"ngx-ie-handle ngx-ie-handle--ne\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('ne', $event)\"></span>\n <span\n class=\"ngx-ie-handle ngx-ie-handle--sw\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('sw', $event)\"></span>\n <span\n class=\"ngx-ie-handle ngx-ie-handle--se\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('se', $event)\"></span>\n </div>\n </div>\n </div>\n\n <div class=\"ngx-ie-panel-row\">\n <div class=\"ngx-ie-panel\">\n <div class=\"ngx-ie-preview\">\n @if (previewUrl(); as url) {\n <img [src]=\"url\" alt=\"Preview\" />\n }\n </div>\n\n <div class=\"ngx-ie-row ngx-ie-rotate-row\">\n <button type=\"button\" (click)=\"rotateBy(-90)\" title=\"Rotate 90\u00B0 left\">\u27F2 90</button>\n <button type=\"button\" (click)=\"rotateBy(90)\" title=\"Rotate 90\u00B0 right\">\u27F3 90</button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"rotation()\"\n (ngModelChange)=\"rotation.set($event)\"\n [min]=\"-180\"\n [max]=\"180\">\n <span>{{ localize().Rotation }} ({{ rotation() }}\u00B0)</span>\n </slider>\n\n <button\n type=\"button\"\n (click)=\"rotation.set(0)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"brightness()\"\n (ngModelChange)=\"brightness.set($event)\"\n [min]=\"0\"\n [max]=\"200\">\n <span>{{ localize().Brightness }} ({{ brightness() }}%)</span>\n </slider>\n <button\n type=\"button\"\n (click)=\"brightness.set(100)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"contrast()\"\n (ngModelChange)=\"contrast.set($event)\"\n [min]=\"0\"\n [max]=\"200\">\n <span>{{ localize().Contrast }} ({{ contrast() }}%)</span>\n </slider>\n <button\n type=\"button\"\n (click)=\"contrast.set(100)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"saturation()\"\n (ngModelChange)=\"saturation.set($event)\"\n [min]=\"0\"\n [max]=\"200\">\n <span>{{ localize().Saturation }} ({{ saturation() }}%)</span>\n </slider>\n <button\n type=\"button\"\n (click)=\"saturation.set(100)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n @if (filters().length) {\n <div>\n <span>{{ localize().Filter }}</span>\n <div class=\"ngx-ie-filter-row\">\n @for (f of filters(); track f) {\n <button type=\"button\" [class.active]=\"filterPreset() === f\" (click)=\"setFilter(f)\">\n {{ filterLabels()[f] }}\n </button>\n }\n </div>\n </div>\n }\n\n <div class=\"ngx-ie-row ngx-ie-actions\">\n <button type=\"button\" class=\"ngx-ie-btn-secondary\" (click)=\"cancel()\">\n {{ localize().Cancel }}\n </button>\n <button type=\"button\" class=\"ngx-ie-btn-primary\" [disabled]=\"saving()\" (click)=\"save()\">\n {{ saving() ? localize().Saving : localize().Save }}\n </button>\n </div>\n </div>\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:block;min-height:70dvh;--ngx-image-editor-panel-width: 25%}.ngx-ie-state{padding:2rem;text-align:center;color:light-dark(#6b7280,#9ca3af)}.ngx-ie-state--error{color:light-dark(#b91c1c,#f87171)}.ngx-ie-layout{display:grid;grid-template-columns:1fr var(--ngx-image-editor-panel-width, 30%);gap:1.25rem;height:100%}.ngx-ie-stage-wrap{width:100%;display:flex;align-items:center;justify-content:center;background:light-dark(#f3f4f6,#18181b);border-radius:10px;overflow:hidden;flex-shrink:0}.ngx-ie-stage{position:relative;touch-action:none;-webkit-user-select:none;user-select:none;direction:ltr}.ngx-ie-stage-img{display:block;inline-size:100%;block-size:100%;border-radius:4px;pointer-events:none;background:#fff;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:16px 16px;background-position:0 0,0 8px,8px -8px,-8px 0px}.ngx-ie-crop-box{position:absolute;box-sizing:border-box;border:2px solid #2563eb;box-shadow:0 0 0 9999px #00000073;cursor:move;touch-action:none}.ngx-ie-handle{position:absolute;inline-size:14px;block-size:14px;background:#fff;border:2px solid #2563eb;border-radius:50%;touch-action:none}.ngx-ie-handle--nw{inset-inline-start:-7px;inset-block-start:-7px;cursor:nwse-resize}.ngx-ie-handle--ne{inset-inline-end:-7px;inset-block-start:-7px;cursor:nesw-resize}.ngx-ie-handle--sw{inset-inline-start:-7px;inset-block-end:-7px;cursor:nesw-resize}.ngx-ie-handle--se{inset-inline-end:-7px;inset-block-end:-7px;cursor:nwse-resize}.ngx-ie-panel{flex:1;display:flex;flex-direction:column;gap:.75rem}.ngx-ie-panel-row{display:flex;flex-wrap:wrap;gap:1.25rem}.ngx-ie-preview{display:flex;align-items:center;justify-content:center;min-block-size:100px;background:light-dark(#f3f4f6,#18181b);border-radius:8px;overflow:hidden}.ngx-ie-preview img{max-inline-size:100%;max-block-size:160px;display:block;background:#fff;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:16px 16px;background-position:0 0,0 8px,8px -8px,-8px 0px}.ngx-ie-field{display:flex;gap:.3rem;align-items:flex-end}.ngx-ie-field slider{flex:1}.ngx-ie-row{display:flex;gap:.5rem}.ngx-ie-rotate-row button,.ngx-ie-filter-row button{appearance:none;border:1px solid light-dark(#e5e7eb,#33333a);background:light-dark(#ffffff,#232327);color:light-dark(#374151,#d4d4d8);border-radius:999px;padding:.4rem .85rem;font-size:.75rem;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,transform .15s ease,color .15s ease}.ngx-ie-rotate-row button:hover,.ngx-ie-filter-row button:hover{background:light-dark(#f3f4f6,#2c2c31);transform:translateY(-1px)}.ngx-ie-rotate-row button:active,.ngx-ie-filter-row button:active{transform:translateY(0)}.ngx-ie-rotate-row button.active,.ngx-ie-filter-row button.active{background:light-dark(#2563eb,#3b82f6);border-color:light-dark(#2563eb,#3b82f6);color:#fff;box-shadow:0 2px 10px light-dark(rgba(37,99,235,.3),rgba(59,130,246,.3))}.ngx-ie-filter-row{display:flex;flex-wrap:wrap;gap:.4rem}.ngx-ie-actions{margin-block-start:auto;justify-content:flex-end}.ngx-ie-btn-primary,.ngx-ie-btn-secondary{appearance:none;border:none;border-radius:8px;padding:.55rem 1.1rem;font-size:.85rem;cursor:pointer;font-weight:500;transition:transform .15s ease,box-shadow .15s ease,opacity .15s ease}.ngx-ie-btn-primary:hover,.ngx-ie-btn-secondary:hover{transform:translateY(-1px)}.ngx-ie-btn-primary:active,.ngx-ie-btn-secondary:active{transform:translateY(0)}.ngx-ie-btn-primary{background:light-dark(#2563eb,#3b82f6);color:#fff;box-shadow:0 2px 10px light-dark(rgba(37,99,235,.25),rgba(59,130,246,.25))}.ngx-ie-btn-primary:disabled{opacity:.6;cursor:not-allowed;transform:none}.ngx-ie-btn-secondary{background:light-dark(#e5e7eb,#3f3f46);color:light-dark(#374151,#e4e4e7)}@media(max-width:768px){:host{height:unset!important}.ngx-ie-layout{display:flex;flex-direction:column}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: SliderComponent, selector: "slider", inputs: ["step", "min", "max", "background", "isBgTransparent"], outputs: ["change"] }, { kind: "directive", type: NgxPointerDragDirective, selector: "[ngxPointerDrag]", outputs: ["dragStart", "dragMove", "dragEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
577
565
|
}
|
|
578
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type:
|
|
566
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxImageEditor, decorators: [{
|
|
579
567
|
type: Component,
|
|
580
568
|
args: [{ selector: 'ngx-image-editor', standalone: true, imports: [FormsModule, SliderComponent, NgxPointerDragDirective], changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'ngx-image-editor-host' }, template: "@if (loading()) {\n <div class=\"ngx-ie-state\">{{ localize().LoadingImage }}</div>\n} @else if (loadError()) {\n <div class=\"ngx-ie-state ngx-ie-state--error\">{{ loadError() }}</div>\n} @else if (stageImageUrl()) {\n <div class=\"ngx-ie-layout\">\n <div class=\"ngx-ie-stage-wrap\" #stageWrap>\n <div\n class=\"ngx-ie-stage\"\n [style.width.px]=\"stageSize().width\"\n [style.height.px]=\"stageSize().height\">\n <img class=\"ngx-ie-stage-img\" [src]=\"stageImageUrl()\" alt=\"\" draggable=\"false\" />\n\n <div\n class=\"ngx-ie-crop-box\"\n [style.left]=\"cropOverlayStyle().left\"\n [style.top]=\"cropOverlayStyle().top\"\n [style.width]=\"cropOverlayStyle().width\"\n [style.height]=\"cropOverlayStyle().height\"\n ngxPointerDrag\n (dragStart)=\"onMoveDragStart()\"\n (dragMove)=\"onMoveDragMove($event)\">\n <span\n class=\"ngx-ie-handle ngx-ie-handle--nw\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('nw', $event)\"></span>\n <span\n class=\"ngx-ie-handle ngx-ie-handle--ne\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('ne', $event)\"></span>\n <span\n class=\"ngx-ie-handle ngx-ie-handle--sw\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('sw', $event)\"></span>\n <span\n class=\"ngx-ie-handle ngx-ie-handle--se\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('se', $event)\"></span>\n </div>\n </div>\n </div>\n\n <div class=\"ngx-ie-panel-row\">\n <div class=\"ngx-ie-panel\">\n <div class=\"ngx-ie-preview\">\n @if (previewUrl(); as url) {\n <img [src]=\"url\" alt=\"Preview\" />\n }\n </div>\n\n <div class=\"ngx-ie-row ngx-ie-rotate-row\">\n <button type=\"button\" (click)=\"rotateBy(-90)\" title=\"Rotate 90\u00B0 left\">\u27F2 90</button>\n <button type=\"button\" (click)=\"rotateBy(90)\" title=\"Rotate 90\u00B0 right\">\u27F3 90</button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"rotation()\"\n (ngModelChange)=\"rotation.set($event)\"\n [min]=\"-180\"\n [max]=\"180\">\n <span>{{ localize().Rotation }} ({{ rotation() }}\u00B0)</span>\n </slider>\n\n <button\n type=\"button\"\n (click)=\"rotation.set(0)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"brightness()\"\n (ngModelChange)=\"brightness.set($event)\"\n [min]=\"0\"\n [max]=\"200\">\n <span>{{ localize().Brightness }} ({{ brightness() }}%)</span>\n </slider>\n <button\n type=\"button\"\n (click)=\"brightness.set(100)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"contrast()\"\n (ngModelChange)=\"contrast.set($event)\"\n [min]=\"0\"\n [max]=\"200\">\n <span>{{ localize().Contrast }} ({{ contrast() }}%)</span>\n </slider>\n <button\n type=\"button\"\n (click)=\"contrast.set(100)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"saturation()\"\n (ngModelChange)=\"saturation.set($event)\"\n [min]=\"0\"\n [max]=\"200\">\n <span>{{ localize().Saturation }} ({{ saturation() }}%)</span>\n </slider>\n <button\n type=\"button\"\n (click)=\"saturation.set(100)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n @if (filters().length) {\n <div>\n <span>{{ localize().Filter }}</span>\n <div class=\"ngx-ie-filter-row\">\n @for (f of filters(); track f) {\n <button type=\"button\" [class.active]=\"filterPreset() === f\" (click)=\"setFilter(f)\">\n {{ filterLabels()[f] }}\n </button>\n }\n </div>\n </div>\n }\n\n <div class=\"ngx-ie-row ngx-ie-actions\">\n <button type=\"button\" class=\"ngx-ie-btn-secondary\" (click)=\"cancel()\">\n {{ localize().Cancel }}\n </button>\n <button type=\"button\" class=\"ngx-ie-btn-primary\" [disabled]=\"saving()\" (click)=\"save()\">\n {{ saving() ? localize().Saving : localize().Save }}\n </button>\n </div>\n </div>\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:block;min-height:70dvh;--ngx-image-editor-panel-width: 25%}.ngx-ie-state{padding:2rem;text-align:center;color:light-dark(#6b7280,#9ca3af)}.ngx-ie-state--error{color:light-dark(#b91c1c,#f87171)}.ngx-ie-layout{display:grid;grid-template-columns:1fr var(--ngx-image-editor-panel-width, 30%);gap:1.25rem;height:100%}.ngx-ie-stage-wrap{width:100%;display:flex;align-items:center;justify-content:center;background:light-dark(#f3f4f6,#18181b);border-radius:10px;overflow:hidden;flex-shrink:0}.ngx-ie-stage{position:relative;touch-action:none;-webkit-user-select:none;user-select:none;direction:ltr}.ngx-ie-stage-img{display:block;inline-size:100%;block-size:100%;border-radius:4px;pointer-events:none;background:#fff;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:16px 16px;background-position:0 0,0 8px,8px -8px,-8px 0px}.ngx-ie-crop-box{position:absolute;box-sizing:border-box;border:2px solid #2563eb;box-shadow:0 0 0 9999px #00000073;cursor:move;touch-action:none}.ngx-ie-handle{position:absolute;inline-size:14px;block-size:14px;background:#fff;border:2px solid #2563eb;border-radius:50%;touch-action:none}.ngx-ie-handle--nw{inset-inline-start:-7px;inset-block-start:-7px;cursor:nwse-resize}.ngx-ie-handle--ne{inset-inline-end:-7px;inset-block-start:-7px;cursor:nesw-resize}.ngx-ie-handle--sw{inset-inline-start:-7px;inset-block-end:-7px;cursor:nesw-resize}.ngx-ie-handle--se{inset-inline-end:-7px;inset-block-end:-7px;cursor:nwse-resize}.ngx-ie-panel{flex:1;display:flex;flex-direction:column;gap:.75rem}.ngx-ie-panel-row{display:flex;flex-wrap:wrap;gap:1.25rem}.ngx-ie-preview{display:flex;align-items:center;justify-content:center;min-block-size:100px;background:light-dark(#f3f4f6,#18181b);border-radius:8px;overflow:hidden}.ngx-ie-preview img{max-inline-size:100%;max-block-size:160px;display:block;background:#fff;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:16px 16px;background-position:0 0,0 8px,8px -8px,-8px 0px}.ngx-ie-field{display:flex;gap:.3rem;align-items:flex-end}.ngx-ie-field slider{flex:1}.ngx-ie-row{display:flex;gap:.5rem}.ngx-ie-rotate-row button,.ngx-ie-filter-row button{appearance:none;border:1px solid light-dark(#e5e7eb,#33333a);background:light-dark(#ffffff,#232327);color:light-dark(#374151,#d4d4d8);border-radius:999px;padding:.4rem .85rem;font-size:.75rem;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,transform .15s ease,color .15s ease}.ngx-ie-rotate-row button:hover,.ngx-ie-filter-row button:hover{background:light-dark(#f3f4f6,#2c2c31);transform:translateY(-1px)}.ngx-ie-rotate-row button:active,.ngx-ie-filter-row button:active{transform:translateY(0)}.ngx-ie-rotate-row button.active,.ngx-ie-filter-row button.active{background:light-dark(#2563eb,#3b82f6);border-color:light-dark(#2563eb,#3b82f6);color:#fff;box-shadow:0 2px 10px light-dark(rgba(37,99,235,.3),rgba(59,130,246,.3))}.ngx-ie-filter-row{display:flex;flex-wrap:wrap;gap:.4rem}.ngx-ie-actions{margin-block-start:auto;justify-content:flex-end}.ngx-ie-btn-primary,.ngx-ie-btn-secondary{appearance:none;border:none;border-radius:8px;padding:.55rem 1.1rem;font-size:.85rem;cursor:pointer;font-weight:500;transition:transform .15s ease,box-shadow .15s ease,opacity .15s ease}.ngx-ie-btn-primary:hover,.ngx-ie-btn-secondary:hover{transform:translateY(-1px)}.ngx-ie-btn-primary:active,.ngx-ie-btn-secondary:active{transform:translateY(0)}.ngx-ie-btn-primary{background:light-dark(#2563eb,#3b82f6);color:#fff;box-shadow:0 2px 10px light-dark(rgba(37,99,235,.25),rgba(59,130,246,.25))}.ngx-ie-btn-primary:disabled{opacity:.6;cursor:not-allowed;transform:none}.ngx-ie-btn-secondary{background:light-dark(#e5e7eb,#3f3f46);color:light-dark(#374151,#e4e4e7)}@media(max-width:768px){:host{height:unset!important}.ngx-ie-layout{display:flex;flex-direction:column}}\n"] }]
|
|
581
569
|
}], ctorParameters: () => [], propDecorators: { source: [{ type: i0.Input, args: [{ isSignal: true, alias: "source", required: false }] }], aspectRatio: [{ type: i0.Input, args: [{ isSignal: true, alias: "aspectRatio", required: false }] }], outputMaxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "outputMaxWidth", required: false }] }], outputMaxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "outputMaxHeight", required: false }] }], outputType: [{ type: i0.Input, args: [{ isSignal: true, alias: "outputType", required: false }] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }], quality: [{ type: i0.Input, args: [{ isSignal: true, alias: "quality", required: false }] }], localize: [{ type: i0.Input, args: [{ isSignal: true, alias: "localize", required: false }] }], saved: [{ type: i0.Output, args: ["saved"] }], cancelled: [{ type: i0.Output, args: ["cancelled"] }], stageWrapEl: [{ type: i0.ViewChild, args: ['stageWrap', { isSignal: true }] }] } });
|
|
@@ -584,5 +572,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
|
|
|
584
572
|
* Generated bundle index. Do not edit.
|
|
585
573
|
*/
|
|
586
574
|
|
|
587
|
-
export { DEFAULT_NGX_IMAGE_EDITOR_LOCALIZATION, NGX_IMAGE_EDITOR_LOCALIZATION,
|
|
575
|
+
export { DEFAULT_NGX_IMAGE_EDITOR_LOCALIZATION, NGX_IMAGE_EDITOR_LOCALIZATION, NgxImageEditor, NgxImageEditorLocalization, NgxPointerDragDirective, applyCartoonEffect, canvasToBlob, createWorkingCopy, fitWithin, loadImage, renderComposite, renderRotated };
|
|
588
576
|
//# sourceMappingURL=ngx-kit-image-editor.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngx-kit-image-editor.mjs","sources":["../../../projects/libs/image-editor/directives/pointer-drag.directive.ts","../../../projects/libs/image-editor/utils/image-io.ts","../../../projects/libs/image-editor/utils/cartoonify.ts","../../../projects/libs/image-editor/utils/render-pipeline.ts","../../../projects/libs/image-editor/tokens/localization.ts","../../../projects/libs/image-editor/components/image-editor.component.ts","../../../projects/libs/image-editor/components/image-editor.component.html","../../../projects/libs/image-editor/ngx-kit-image-editor.ts"],"sourcesContent":["import { Directive, HostListener, output } from '@angular/core';\n\nexport interface NgxPointerDragDelta {\n dx: number;\n dy: number;\n}\n\n/**\n * درگ عمومی روی پایهی Pointer Events + setPointerCapture (دقیقاً همون\n * تکنیکی که در ngx-kit/data-table برای ریسایز ستون استفاده شده) — نیازی به\n * listener سطح document نداره چون بعد از setPointerCapture، رویدادهای\n * pointermove/pointerup حتی بیرون از محدودهی المنت هم به خودش میرسن.\n *\n * dx/dy تجمعی از لحظهی pointerdown هستن (نه دلتای بین دو move متوالی)، چون\n * معمولاً مصرفکننده میخواد «موقعیت شروع + دلتای کل» رو حساب کنه، نه جمع\n * تدریجی گرد شوندهی دلتاهای ریز.\n */\n@Directive({\n selector: '[ngxPointerDrag]',\n standalone: true,\n})\nexport class NgxPointerDragDirective {\n dragStart = output<void>();\n dragMove = output<NgxPointerDragDelta>();\n dragEnd = output<void>();\n\n private dragging = false;\n private startX = 0;\n private startY = 0;\n\n @HostListener('pointerdown', ['$event'])\n onPointerDown(ev: PointerEvent): void {\n ev.preventDefault();\n ev.stopPropagation();\n this.dragging = true;\n this.startX = ev.clientX;\n this.startY = ev.clientY;\n (ev.target as HTMLElement).setPointerCapture(ev.pointerId);\n this.dragStart.emit();\n }\n\n @HostListener('pointermove', ['$event'])\n onPointerMove(ev: PointerEvent): void {\n if (!this.dragging) return;\n this.dragMove.emit({ dx: ev.clientX - this.startX, dy: ev.clientY - this.startY });\n }\n\n @HostListener('pointerup')\n @HostListener('pointercancel')\n onPointerUp(): void {\n if (!this.dragging) return;\n this.dragging = false;\n this.dragEnd.emit();\n }\n}\n","/** یه File/Blob/data-URL/URL رو به یک HTMLImageElement بارگذاریشده تبدیل میکنه */\nexport function loadImage(source: File | Blob | string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n // برای URLهای cross-origin لازم میشه، وگرنه canvas بعداً «tainted» میشه\n // و toBlob/toDataURL با SecurityError شکست میخوره.\n img.crossOrigin = 'anonymous';\n\n const objectUrl = typeof source === 'string' ? null : URL.createObjectURL(source);\n const url = objectUrl ?? (source as string);\n\n img.onload = () => {\n if (objectUrl) URL.revokeObjectURL(objectUrl);\n resolve(img);\n };\n img.onerror = () => {\n if (objectUrl) URL.revokeObjectURL(objectUrl);\n reject(new Error('Failed to load image'));\n };\n img.src = url;\n });\n}\n\n/** canvas.toBlob بهصورت Promise، بههمراه fallback برای مرورگرهای قدیمیتر */\nexport function canvasToBlob(\n canvas: HTMLCanvasElement,\n type = 'image/jpeg',\n quality = 0.92,\n): Promise<Blob> {\n return new Promise((resolve, reject) => {\n canvas.toBlob(\n (blob) => {\n if (blob) resolve(blob);\n else reject(new Error('Failed to convert canvas to blob'));\n },\n type,\n quality,\n );\n });\n}\n\n/**\n * یه کپیِ کوچیکشده از تصویر اصلی میسازه که کل UI ویرایشگر (چرخش، کراپ،\n * پیشنمایش فیلترها/کارتونی) روی همین کار میکنه، نه روی تصویر اصلی که\n * ممکنه چند مگاپیکسل باشه. این باعث میشه درگکردنِ اسلایدرها یا لبههای\n * کراپ روون بمونه؛ خروجی نهایی (save) همیشه از روی تصویر اصلیِ کامل رندر\n * میشه، نه از روی این کپی.\n */\nexport function createWorkingCopy(img: HTMLImageElement, maxSize = 1200): HTMLCanvasElement {\n const { width, height } = fitWithin(img.naturalWidth, img.naturalHeight, maxSize, maxSize);\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d')!;\n ctx.drawImage(img, 0, 0, width, height);\n return canvas;\n}\n\n/** ابعاد جدید رو طوری حساب میکنه که از maxWidth/maxHeight بیشتر نشه، با حفظ نسبت تصویر */\nexport function fitWithin(\n width: number,\n height: number,\n maxWidth?: number,\n maxHeight?: number,\n): { width: number; height: number } {\n if (!maxWidth && !maxHeight) return { width, height };\n let ratio = 1;\n if (maxWidth) ratio = Math.min(ratio, maxWidth / width);\n if (maxHeight) ratio = Math.min(ratio, maxHeight / height);\n if (ratio >= 1) return { width, height };\n return { width: Math.round(width * ratio), height: Math.round(height * ratio) };\n}\n","/**\n * افکت «کارتونی»: چون ctx.filter استاندارد چیزی شبیه cartoon نداره (فقط\n * brightness/contrast/saturate/grayscale/sepia/invert/blur/hue-rotate)، این\n * یکی رو واقعاً با پردازش پیکسلی پیاده کردیم؛ دو مرحله:\n *\n * ۱) Posterize: هر کانال رنگ به تعداد محدودی سطح گرد میشه (پهنههای رنگیِ\n * صاف و یکدست، حسِ کارتونی رنگ میده).\n * ۲) لبهیابی Sobel روی نسخهی خاکستریِ تصویر: هرجا شدت لبه از حد آستانه\n * بیشتر باشه، پیکسل تیره میشه (حسِ خط دور کارتونی).\n *\n * روی خودِ ImageData کار میکنه، پس هزینهش با اندازهی تصویر خطیست؛ برای\n * تصاویر خیلی بزرگ (>~3000px) بهتره قبلش resize بشه (که در کامپوننت اصلی\n * با fitWithin قبل از اعمال فیلتر انجام میشه).\n */\nexport function applyCartoonEffect(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n options: { levels?: number; edgeThreshold?: number } = {},\n): void {\n const levels = options.levels ?? 5;\n const edgeThreshold = options.edgeThreshold ?? 80;\n\n const imageData = ctx.getImageData(0, 0, width, height);\n const src = imageData.data;\n\n // ۱) خاکستری برای Sobel\n const gray = new Uint8ClampedArray(width * height);\n for (let i = 0, p = 0; i < src.length; i += 4, p++) {\n gray[p] = (src[i] * 0.299 + src[i + 1] * 0.587 + src[i + 2] * 0.114) | 0;\n }\n\n // ۲) Posterize رنگها\n const step = 255 / (levels - 1);\n for (let i = 0; i < src.length; i += 4) {\n src[i] = Math.round(Math.round(src[i] / step) * step);\n src[i + 1] = Math.round(Math.round(src[i + 1] / step) * step);\n src[i + 2] = Math.round(Math.round(src[i + 2] / step) * step);\n }\n\n // ۳) Sobel روی gray، خط دور تیره روی src\n const gxKernel = [-1, 0, 1, -2, 0, 2, -1, 0, 1];\n const gyKernel = [-1, -2, -1, 0, 0, 0, 1, 2, 1];\n\n for (let y = 1; y < height - 1; y++) {\n for (let x = 1; x < width - 1; x++) {\n let gx = 0;\n let gy = 0;\n let k = 0;\n for (let dy = -1; dy <= 1; dy++) {\n for (let dx = -1; dx <= 1; dx++) {\n const v = gray[(y + dy) * width + (x + dx)];\n gx += v * gxKernel[k];\n gy += v * gyKernel[k];\n k++;\n }\n }\n const magnitude = Math.sqrt(gx * gx + gy * gy);\n if (magnitude > edgeThreshold) {\n const idx = (y * width + x) * 4;\n src[idx] = 20;\n src[idx + 1] = 20;\n src[idx + 2] = 20;\n }\n }\n }\n\n ctx.putImageData(imageData, 0, 0);\n}\n","import { NgxCropRect, NgxImageEditorAdjustments } from '../contracts/image-editor-types';\nimport { applyCartoonEffect } from './cartoonify';\nimport { fitWithin } from './image-io';\n\n/** تصویر مبدأ رو با زاویهی دادهشده روی یه canvas جدید (به اندازهی bounding-box نتیجه) میچرخونه */\nexport function renderRotated(\n source: CanvasImageSource,\n width: number,\n height: number,\n degrees: number,\n): HTMLCanvasElement {\n const rad = (degrees * Math.PI) / 180;\n const sin = Math.abs(Math.sin(rad));\n const cos = Math.abs(Math.cos(rad));\n const newW = Math.max(1, Math.round(width * cos + height * sin));\n const newH = Math.max(1, Math.round(width * sin + height * cos));\n\n const canvas = document.createElement('canvas');\n canvas.width = newW;\n canvas.height = newH;\n const ctx = canvas.getContext('2d')!;\n ctx.translate(newW / 2, newH / 2);\n ctx.rotate(rad);\n ctx.drawImage(source, -width / 2, -height / 2, width, height);\n return canvas;\n}\n\nfunction buildCssFilter(adjustments: NgxImageEditorAdjustments): string {\n const parts = [\n `brightness(${adjustments.brightness}%)`,\n `contrast(${adjustments.contrast}%)`,\n `saturate(${adjustments.saturation}%)`,\n ];\n if (adjustments.filter === 'grayscale') parts.push('grayscale(1)');\n if (adjustments.filter === 'sepia') parts.push('sepia(1)');\n if (adjustments.filter === 'invert') parts.push('invert(1)');\n return parts.join(' ');\n}\n\n/**\n * کراپ + فیلترها رو روی یه canvas خروجی میسازه. brightness/contrast/\n * saturation/grayscale/sepia/invert همه با ctx.filter بومیِ Canvas 2D انجام\n * میشن (شتابدهیشده توسط مرورگر، بدون حلقهی پیکسلی دستی)؛ فقط cartoon\n * (که معادل بومی نداره) با پردازش پیکسلی جدا انجام میشه.\n *\n * maxWidth/maxHeight برای دو حالت استفاده میشه: پیشنمایش زنده (عدد کوچیک،\n * برای واکنشگرا موندن حین کشیدن اسلایدرها) و خروجی نهایی (بدون محدودیت یا\n * محدودیت دلخواه کاربر).\n */\nexport function renderComposite(\n source: CanvasImageSource,\n sourceWidth: number,\n sourceHeight: number,\n crop: NgxCropRect,\n adjustments: NgxImageEditorAdjustments,\n maxWidth?: number,\n maxHeight?: number,\n): HTMLCanvasElement {\n const { width: outW, height: outH } = fitWithin(crop.width, crop.height, maxWidth, maxHeight);\n\n const canvas = document.createElement('canvas');\n canvas.width = Math.max(1, outW);\n canvas.height = Math.max(1, outH);\n const ctx = canvas.getContext('2d')!;\n\n ctx.filter = buildCssFilter(adjustments);\n ctx.drawImage(source, crop.x, crop.y, crop.width, crop.height, 0, 0, canvas.width, canvas.height);\n ctx.filter = 'none';\n\n if (adjustments.filter === 'cartoon') {\n applyCartoonEffect(ctx, canvas.width, canvas.height);\n }\n\n return canvas;\n}\n","import { InjectionToken } from '@angular/core';\n\nexport const NGX_IMAGE_EDITOR_LOCALIZATION = new InjectionToken<NgxImageEditorLocalization>(\n 'ngx-image-localization',\n {\n factory: () => DEFAULT_NGX_IMAGE_EDITOR_LOCALIZATION,\n },\n);\n\nexport class NgxImageEditorLocalization {\n LoadingImage = 'Loading image…';\n Rotation = 'Fine rotation';\n Brightness = 'Brightness';\n Contrast = 'Contrast';\n Saturation = 'Saturation';\n Filter = 'Filter';\n None = 'None';\n Grayscale = 'Grayscale';\n Sepia = 'Sepia';\n Invert = 'Invert';\n Cartoon = 'Cartoon';\n Cancel = 'Cancel';\n Save = 'Save';\n Saving = 'Saving…';\n Reset = 'Reset';\n}\nexport const DEFAULT_NGX_IMAGE_EDITOR_LOCALIZATION = new NgxImageEditorLocalization();\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n computed,\n effect,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { SliderComponent } from 'ngx-kit/core';\nimport {\n NgxCropRect,\n NgxImageEditorAdjustments,\n NgxImageEditorResult,\n NgxImageFilterPreset,\n} from '../contracts/image-editor-types';\nimport { NgxPointerDragDelta, NgxPointerDragDirective } from '../directives/pointer-drag.directive';\nimport { canvasToBlob, createWorkingCopy, loadImage } from '../utils/image-io';\nimport { renderComposite, renderRotated } from '../utils/render-pipeline';\nimport { Corner } from '../types/corner';\nimport { NGX_IMAGE_EDITOR_LOCALIZATION, NgxImageEditorLocalization } from '../tokens/localization';\n\nconst ALL_FILTERS: NgxImageFilterPreset[] = ['none', 'grayscale', 'sepia', 'invert', 'cartoon'];\n\n/**\n * ویرایشگر تصویر: کراپ + چرخش + روشنایی/کنتراست/اشباع + فیلترهای آماده\n * (سیاهوسفید، سپیا، معکوس، کارتونی) + فشردهسازی خروجی. کاملاً روی Canvas\n * خام پیاده شده، بدون هیچ وابستگی خارجیای.\n *\n * نکتهی مهمِ معماری: تمام تعامل زنده (چرخوندن، جابهجا/ریسایز کراپباکس،\n * پیشنمایش فیلترها حتی کارتونی) روی یه کپیِ کوچیکشده از تصویر انجام میشه\n * (createWorkingCopy)، نه روی تصویر اصلی که ممکنه چند مگاپیکسل باشه — وگرنه\n * درگکردن اسلایدرها/گوشههای کراپ رو کاربر حس تاخیر میکرد. فقط لحظهی\n * save()، رندر نهایی از روی تصویر اصلیِ کامل انجام میشه.\n *\n * اندازهی صحنه (stage) با panelSize کنترل میشه: عرض همیشه ۱۰۰٪ عرضِ\n * والدِ کامپوننته (با ResizeObserver اندازهگیری میشه، پس با تغییر سایز\n * صفحه/layout هم زنده هماهنگ میمونه)، ارتفاع دقیقاً همون چیزیه که کاربر با\n * panelSize میده. تصویر همیشه با یک مقیاسِ «contain» واقعی (هم بر اساس\n * عرض، هم بر اساس ارتفاع — هرکدوم تنگتره) جا داده میشه، پس کلِ تصویر\n * همیشه در محدودهی همین باکس دیده میشه، صرفنظر از اندازهی واقعیِ فایل.\n * سقفِ مقیاس هم ۱ هست، یعنی تصاویر کوچیک بزرگنمایی نمیشن (که باعثِ محو\n * شدنشون میشد).\n */\n@Component({\n selector: 'ngx-image-editor',\n standalone: true,\n imports: [FormsModule, SliderComponent, NgxPointerDragDirective],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './image-editor.component.html',\n styleUrl: './image-editor.component.scss',\n host: { class: 'ngx-image-editor-host' },\n})\nexport class NgxImageEditorComponent {\n source = input<File | Blob | string | null>(null);\n /** قفل نسبتِ کراپ (مثلاً ۱ برای آواتار مربعی)؛ undefined یعنی آزاد */\n aspectRatio = input<number | undefined>(undefined);\n outputMaxWidth = input<number | undefined>(undefined);\n outputMaxHeight = input<number | undefined>(undefined);\n outputType = input<'image/jpeg' | 'image/png' | 'image/webp'>('image/jpeg');\n\n /**\n * کدوم فیلترها نشون داده بشن (و به چه ترتیبی). اگه ندید، هر ۵ تا نشون داده\n * میشن. آرایهی خالی یعنی کلِ بخشِ فیلتر مخفی بشه.\n */\n filters = input<NgxImageFilterPreset[]>(ALL_FILTERS);\n quality = input(0.92);\n\n defaultLocalization = inject(NGX_IMAGE_EDITOR_LOCALIZATION);\n localize = input<NgxImageEditorLocalization>(this.defaultLocalization);\n\n saved = output<NgxImageEditorResult>();\n cancelled = output<void>();\n\n protected readonly loading = signal(false);\n protected readonly saving = signal(false);\n protected readonly loadError = signal<string | null>(null);\n\n private readonly originalImage = signal<HTMLImageElement | null>(null);\n private readonly workingCanvas = signal<HTMLCanvasElement | null>(null);\n private readonly stageWrapEl = viewChild<ElementRef<HTMLElement>>('stageWrap');\n /** عرضِ واقعیِ رندرشدهی کانتینر؛ چون عرض همیشه ۱۰۰٪ (fluid) هست، باید زنده اندازهگیری بشه */\n private readonly containerWidth = signal(0);\n\n protected readonly rotation = signal(0);\n protected readonly brightness = signal(100);\n protected readonly contrast = signal(100);\n protected readonly saturation = signal(100);\n protected readonly filterPreset = signal<NgxImageFilterPreset>('none');\n\n protected readonly crop = signal<NgxCropRect>({ x: 0, y: 0, width: 0, height: 0 });\n\n protected readonly adjustments = computed<NgxImageEditorAdjustments>(() => ({\n brightness: this.brightness(),\n contrast: this.contrast(),\n saturation: this.saturation(),\n rotation: this.rotation(),\n filter: this.filterPreset(),\n }));\n\n protected readonly filterLabels = computed<Record<NgxImageFilterPreset, string>>(() => {\n const t = this.localize();\n return {\n none: t.None,\n grayscale: t.Grayscale,\n sepia: t.Sepia,\n invert: t.Invert,\n cartoon: t.Cartoon,\n };\n });\n\n /** تصویرِ (کوچیکشدهیِ) چرخیده — پایهی نمایش صحنهی کراپ */\n protected readonly rotatedWorkingCanvas = computed(() => {\n const wc = this.workingCanvas();\n if (!wc) return null;\n return renderRotated(wc, wc.width, wc.height, this.rotation());\n });\n\n protected readonly panelSize = computed(() => {\n return this.stageWrapEl()?.nativeElement.getBoundingClientRect().height ?? 0;\n });\n\n /**\n * مقیاسِ «contain» واقعی: کوچیکترینِ نسبتِ عرض و ارتفاع (هرکدوم تنگتره)\n * تعیینکنندهست، و سقفش هم ۱ هست تا تصاویر کوچیک بزرگنمایی نشن.\n */\n protected readonly displayScale = computed(() => {\n const rc = this.rotatedWorkingCanvas();\n const containerW = this.containerWidth();\n const panelH = this.panelSize();\n if (!rc || rc.width <= 0 || rc.height <= 0 || containerW <= 0 || panelH <= 0) return 1;\n return Math.min(containerW / rc.width, panelH / rc.height, 1);\n });\n\n protected readonly stageImageUrl = computed(() => {\n const rc = this.rotatedWorkingCanvas();\n return rc ? rc.toDataURL('image/png') : null;\n });\n\n protected readonly stageSize = computed(() => {\n const rc = this.rotatedWorkingCanvas();\n const scale = this.displayScale();\n return rc ? { width: rc.width * scale, height: rc.height * scale } : { width: 0, height: 0 };\n });\n\n protected readonly cropOverlayStyle = computed(() => {\n const scale = this.displayScale();\n const c = this.crop();\n return {\n left: `${c.x * scale}px`,\n top: `${c.y * scale}px`,\n width: `${c.width * scale}px`,\n height: `${c.height * scale}px`,\n };\n });\n\n /** پیشنمایش نهایی (کوچیک، حداکثر ۴۸۰ پیکسل) — شامل همهچیز، حتی افکت کارتونی */\n protected readonly previewUrl = computed(() => {\n const rc = this.rotatedWorkingCanvas();\n const c = this.crop();\n if (!rc || c.width <= 0 || c.height <= 0) return null;\n const canvas = renderComposite(rc, rc.width, rc.height, c, this.adjustments(), 480, 480);\n return canvas.toDataURL('image/png');\n });\n\n private moveSnapshot: NgxCropRect | null = null;\n private resizeSnapshot: NgxCropRect | null = null;\n\n constructor() {\n // بارگذاری تصویر هروقت source عوض بشه\n effect(() => {\n const src = this.source();\n if (!src) {\n this.originalImage.set(null);\n this.workingCanvas.set(null);\n return;\n }\n this.loading.set(true);\n this.loadError.set(null);\n loadImage(src)\n .then((img) => {\n this.originalImage.set(img);\n this.workingCanvas.set(createWorkingCopy(img));\n this.resetAdjustments();\n })\n .catch((err) => this.loadError.set(err?.message ?? 'Failed to load image'))\n .finally(() => this.loading.set(false));\n });\n\n // هر وقت چرخیدهشده عوض بشه (بارگذاریِ تصویر جدید یا چرخش)، کراپ روی کل قاب ریست بشه\n effect(() => {\n const rc = this.rotatedWorkingCanvas();\n if (rc) {\n this.crop.set({ x: 0, y: 0, width: rc.width, height: rc.height });\n }\n });\n\n // اگه فیلترِ فعلاً انتخابشده دیگه توی لیستِ مجازِ filters() نباشه (مثلاً\n // مصرفکننده cartoon رو غیرفعال کرده درحالیکه کاربر روش بود)، برو روی\n // اولین فیلترِ مجاز؛ اگه لیست خالی باشه (کلاً فیلتر مخفیه)، روی none بمون.\n effect(() => {\n const allowed = this.filters();\n if (allowed.length && !allowed.includes(this.filterPreset())) {\n this.filterPreset.set(allowed[0]);\n }\n });\n\n // اندازهگیریِ زندهی عرضِ واقعیِ کانتینر — چون عرض همیشه ۱۰۰٪ (fluid)ه،\n // فقط با ResizeObserver میشه فهمید الان چند پیکسله (نه یه عددِ ثابتِ ورودی).\n effect((onCleanup) => {\n const el = this.stageWrapEl()?.nativeElement;\n if (!el) return;\n this.containerWidth.set(el.getBoundingClientRect().width);\n const ro = new ResizeObserver((entries) => {\n const width = entries[0]?.contentRect.width;\n if (width != null) this.containerWidth.set(width);\n });\n ro.observe(el);\n onCleanup(() => ro.disconnect());\n });\n }\n\n private resetAdjustments(): void {\n this.rotation.set(0);\n this.brightness.set(100);\n this.contrast.set(100);\n this.saturation.set(100);\n this.filterPreset.set(this.filters()[0] ?? 'none');\n }\n\n protected rotateBy(delta: number): void {\n this.rotation.update((r) => {\n let next = r + delta;\n if (next > 180) next -= 360;\n if (next < -180) next += 360;\n return next;\n });\n }\n\n protected setFilter(preset: NgxImageFilterPreset): void {\n this.filterPreset.set(preset);\n }\n\n // ---------- درگ جابهجاییِ کل کراپباکس ----------\n protected onMoveDragStart(): void {\n this.moveSnapshot = { ...this.crop() };\n }\n\n protected onMoveDragMove(delta: NgxPointerDragDelta): void {\n const rc = this.rotatedWorkingCanvas();\n const snap = this.moveSnapshot;\n if (!rc || !snap) return;\n const scale = this.displayScale();\n const dxSrc = delta.dx / scale;\n const dySrc = delta.dy / scale;\n const maxX = Math.max(0, rc.width - snap.width);\n const maxY = Math.max(0, rc.height - snap.height);\n const x = Math.min(Math.max(0, snap.x + dxSrc), maxX);\n const y = Math.min(Math.max(0, snap.y + dySrc), maxY);\n this.crop.set({ ...snap, x, y });\n }\n\n // ---------- درگ ریسایز از گوشهها ----------\n protected onResizeDragStart(): void {\n this.resizeSnapshot = { ...this.crop() };\n }\n\n protected onResizeDragMove(corner: Corner, delta: NgxPointerDragDelta): void {\n const rc = this.rotatedWorkingCanvas();\n const snap = this.resizeSnapshot;\n if (!rc || !snap) return;\n\n const scale = this.displayScale();\n const dxSrc = delta.dx / scale;\n const dySrc = delta.dy / scale;\n const minSize = 24;\n\n let { x, y, width, height } = snap;\n\n if (corner === 'nw' || corner === 'sw') {\n const newX = Math.min(snap.x + dxSrc, snap.x + snap.width - minSize);\n x = Math.max(0, newX);\n width = snap.x + snap.width - x;\n }\n if (corner === 'ne' || corner === 'se') {\n width = Math.min(Math.max(minSize, snap.width + dxSrc), rc.width - snap.x);\n }\n if (corner === 'nw' || corner === 'ne') {\n const newY = Math.min(snap.y + dySrc, snap.y + snap.height - minSize);\n y = Math.max(0, newY);\n height = snap.y + snap.height - y;\n }\n if (corner === 'sw' || corner === 'se') {\n height = Math.min(Math.max(minSize, snap.height + dySrc), rc.height - snap.y);\n }\n\n const ratio = this.aspectRatio();\n if (ratio) {\n height = width / ratio;\n }\n\n this.crop.set({ x, y, width, height });\n }\n\n protected cancel(): void {\n this.cancelled.emit();\n }\n\n async save(): Promise<void> {\n const original = this.originalImage();\n const working = this.workingCanvas();\n if (!original || !working) return;\n\n this.saving.set(true);\n try {\n // نسبت مقیاس بین کپیِ کوچیکشده (که کراپ/چرخش روش تعریف شده) و تصویر\n // اصلیِ کامل. چون createWorkingCopy مقیاس یکنواخت (همجهت) اعمال\n // میکنه، همین یه ضریب برای هر دو بعد و بعد از چرخش هم معتبر میمونه.\n const scaleToOriginal = original.naturalWidth / working.width;\n\n const rotatedFull = renderRotated(\n original,\n original.naturalWidth,\n original.naturalHeight,\n this.rotation(),\n );\n\n const c = this.crop();\n const cropInFullRes: NgxCropRect = {\n x: c.x * scaleToOriginal,\n y: c.y * scaleToOriginal,\n width: c.width * scaleToOriginal,\n height: c.height * scaleToOriginal,\n };\n\n const finalCanvas = renderComposite(\n rotatedFull,\n rotatedFull.width,\n rotatedFull.height,\n cropInFullRes,\n this.adjustments(),\n this.outputMaxWidth(),\n this.outputMaxHeight(),\n );\n\n const type = this.outputType();\n const blob = await canvasToBlob(finalCanvas, type, this.quality());\n const dataUrl = finalCanvas.toDataURL(type, this.quality());\n this.saved.emit({ blob, dataUrl, width: finalCanvas.width, height: finalCanvas.height });\n } finally {\n this.saving.set(false);\n }\n }\n}\n","@if (loading()) {\n <div class=\"ngx-ie-state\">{{ localize().LoadingImage }}</div>\n} @else if (loadError()) {\n <div class=\"ngx-ie-state ngx-ie-state--error\">{{ loadError() }}</div>\n} @else if (stageImageUrl()) {\n <div class=\"ngx-ie-layout\">\n <div class=\"ngx-ie-stage-wrap\" #stageWrap>\n <div\n class=\"ngx-ie-stage\"\n [style.width.px]=\"stageSize().width\"\n [style.height.px]=\"stageSize().height\">\n <img class=\"ngx-ie-stage-img\" [src]=\"stageImageUrl()\" alt=\"\" draggable=\"false\" />\n\n <div\n class=\"ngx-ie-crop-box\"\n [style.left]=\"cropOverlayStyle().left\"\n [style.top]=\"cropOverlayStyle().top\"\n [style.width]=\"cropOverlayStyle().width\"\n [style.height]=\"cropOverlayStyle().height\"\n ngxPointerDrag\n (dragStart)=\"onMoveDragStart()\"\n (dragMove)=\"onMoveDragMove($event)\">\n <span\n class=\"ngx-ie-handle ngx-ie-handle--nw\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('nw', $event)\"></span>\n <span\n class=\"ngx-ie-handle ngx-ie-handle--ne\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('ne', $event)\"></span>\n <span\n class=\"ngx-ie-handle ngx-ie-handle--sw\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('sw', $event)\"></span>\n <span\n class=\"ngx-ie-handle ngx-ie-handle--se\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('se', $event)\"></span>\n </div>\n </div>\n </div>\n\n <div class=\"ngx-ie-panel-row\">\n <div class=\"ngx-ie-panel\">\n <div class=\"ngx-ie-preview\">\n @if (previewUrl(); as url) {\n <img [src]=\"url\" alt=\"Preview\" />\n }\n </div>\n\n <div class=\"ngx-ie-row ngx-ie-rotate-row\">\n <button type=\"button\" (click)=\"rotateBy(-90)\" title=\"Rotate 90° left\">⟲ 90</button>\n <button type=\"button\" (click)=\"rotateBy(90)\" title=\"Rotate 90° right\">⟳ 90</button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"rotation()\"\n (ngModelChange)=\"rotation.set($event)\"\n [min]=\"-180\"\n [max]=\"180\">\n <span>{{ localize().Rotation }} ({{ rotation() }}°)</span>\n </slider>\n\n <button\n type=\"button\"\n (click)=\"rotation.set(0)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"brightness()\"\n (ngModelChange)=\"brightness.set($event)\"\n [min]=\"0\"\n [max]=\"200\">\n <span>{{ localize().Brightness }} ({{ brightness() }}%)</span>\n </slider>\n <button\n type=\"button\"\n (click)=\"brightness.set(100)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"contrast()\"\n (ngModelChange)=\"contrast.set($event)\"\n [min]=\"0\"\n [max]=\"200\">\n <span>{{ localize().Contrast }} ({{ contrast() }}%)</span>\n </slider>\n <button\n type=\"button\"\n (click)=\"contrast.set(100)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"saturation()\"\n (ngModelChange)=\"saturation.set($event)\"\n [min]=\"0\"\n [max]=\"200\">\n <span>{{ localize().Saturation }} ({{ saturation() }}%)</span>\n </slider>\n <button\n type=\"button\"\n (click)=\"saturation.set(100)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n @if (filters().length) {\n <div>\n <span>{{ localize().Filter }}</span>\n <div class=\"ngx-ie-filter-row\">\n @for (f of filters(); track f) {\n <button type=\"button\" [class.active]=\"filterPreset() === f\" (click)=\"setFilter(f)\">\n {{ filterLabels()[f] }}\n </button>\n }\n </div>\n </div>\n }\n\n <div class=\"ngx-ie-row ngx-ie-actions\">\n <button type=\"button\" class=\"ngx-ie-btn-secondary\" (click)=\"cancel()\">\n {{ localize().Cancel }}\n </button>\n <button type=\"button\" class=\"ngx-ie-btn-primary\" [disabled]=\"saving()\" (click)=\"save()\">\n {{ saving() ? localize().Saving : localize().Save }}\n </button>\n </div>\n </div>\n </div>\n </div>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ngx-kit-image-editor.mjs","sources":["../../../projects/libs/image-editor/directives/pointer-drag.directive.ts","../../../projects/libs/image-editor/utils/image-io.ts","../../../projects/libs/image-editor/utils/cartoonify.ts","../../../projects/libs/image-editor/utils/render-pipeline.ts","../../../projects/libs/image-editor/tokens/localization.ts","../../../projects/libs/image-editor/components/image-editor.component.ts","../../../projects/libs/image-editor/components/image-editor.component.html","../../../projects/libs/image-editor/ngx-kit-image-editor.ts"],"sourcesContent":["import { Directive, HostListener, output } from '@angular/core';\n\nexport interface NgxPointerDragDelta {\n dx: number;\n dy: number;\n}\n\n/**\n * درگ عمومی روی پایهی Pointer Events + setPointerCapture (دقیقاً همون\n * تکنیکی که در ngx-kit/data-table برای ریسایز ستون استفاده شده) — نیازی به\n * listener سطح document نداره چون بعد از setPointerCapture، رویدادهای\n * pointermove/pointerup حتی بیرون از محدودهی المنت هم به خودش میرسن.\n *\n * dx/dy تجمعی از لحظهی pointerdown هستن (نه دلتای بین دو move متوالی)، چون\n * معمولاً مصرفکننده میخواد «موقعیت شروع + دلتای کل» رو حساب کنه، نه جمع\n * تدریجی گرد شوندهی دلتاهای ریز.\n */\n@Directive({\n selector: '[ngxPointerDrag]',\n standalone: true,\n})\nexport class NgxPointerDragDirective {\n dragStart = output<void>();\n dragMove = output<NgxPointerDragDelta>();\n dragEnd = output<void>();\n\n private dragging = false;\n private startX = 0;\n private startY = 0;\n\n @HostListener('pointerdown', ['$event'])\n onPointerDown(ev: PointerEvent): void {\n ev.preventDefault();\n ev.stopPropagation();\n this.dragging = true;\n this.startX = ev.clientX;\n this.startY = ev.clientY;\n (ev.target as HTMLElement).setPointerCapture(ev.pointerId);\n this.dragStart.emit();\n }\n\n @HostListener('pointermove', ['$event'])\n onPointerMove(ev: PointerEvent): void {\n if (!this.dragging) return;\n this.dragMove.emit({ dx: ev.clientX - this.startX, dy: ev.clientY - this.startY });\n }\n\n @HostListener('pointerup')\n @HostListener('pointercancel')\n onPointerUp(): void {\n if (!this.dragging) return;\n this.dragging = false;\n this.dragEnd.emit();\n }\n}\n","/** یه File/Blob/data-URL/URL رو به یک HTMLImageElement بارگذاریشده تبدیل میکنه */\nexport function loadImage(source: File | Blob | string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n // برای URLهای cross-origin لازم میشه، وگرنه canvas بعداً «tainted» میشه\n // و toBlob/toDataURL با SecurityError شکست میخوره.\n img.crossOrigin = 'anonymous';\n\n const objectUrl = typeof source === 'string' ? null : URL.createObjectURL(source);\n const url = objectUrl ?? (source as string);\n\n img.onload = () => {\n if (objectUrl) URL.revokeObjectURL(objectUrl);\n resolve(img);\n };\n img.onerror = () => {\n if (objectUrl) URL.revokeObjectURL(objectUrl);\n reject(new Error('Failed to load image'));\n };\n img.src = url;\n });\n}\n\n/** canvas.toBlob بهصورت Promise، بههمراه fallback برای مرورگرهای قدیمیتر */\nexport function canvasToBlob(\n canvas: HTMLCanvasElement,\n type = 'image/jpeg',\n quality = 0.92,\n): Promise<Blob> {\n return new Promise((resolve, reject) => {\n canvas.toBlob(\n (blob) => {\n if (blob) resolve(blob);\n else reject(new Error('Failed to convert canvas to blob'));\n },\n type,\n quality,\n );\n });\n}\n\n/**\n * یه کپیِ کوچیکشده از تصویر اصلی میسازه که کل UI ویرایشگر (چرخش، کراپ،\n * پیشنمایش فیلترها/کارتونی) روی همین کار میکنه، نه روی تصویر اصلی که\n * ممکنه چند مگاپیکسل باشه. این باعث میشه درگکردنِ اسلایدرها یا لبههای\n * کراپ روون بمونه؛ خروجی نهایی (save) همیشه از روی تصویر اصلیِ کامل رندر\n * میشه، نه از روی این کپی.\n */\nexport function createWorkingCopy(img: HTMLImageElement, maxSize = 1200): HTMLCanvasElement {\n const { width, height } = fitWithin(img.naturalWidth, img.naturalHeight, maxSize, maxSize);\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d')!;\n ctx.drawImage(img, 0, 0, width, height);\n return canvas;\n}\n\n/** ابعاد جدید رو طوری حساب میکنه که از maxWidth/maxHeight بیشتر نشه، با حفظ نسبت تصویر */\nexport function fitWithin(\n width: number,\n height: number,\n maxWidth?: number,\n maxHeight?: number,\n): { width: number; height: number } {\n if (!maxWidth && !maxHeight) return { width, height };\n let ratio = 1;\n if (maxWidth) ratio = Math.min(ratio, maxWidth / width);\n if (maxHeight) ratio = Math.min(ratio, maxHeight / height);\n if (ratio >= 1) return { width, height };\n return { width: Math.round(width * ratio), height: Math.round(height * ratio) };\n}\n","/**\n * افکت «کارتونی»: چون ctx.filter استاندارد چیزی شبیه cartoon نداره (فقط\n * brightness/contrast/saturate/grayscale/sepia/invert/blur/hue-rotate)، این\n * یکی رو واقعاً با پردازش پیکسلی پیاده کردیم؛ دو مرحله:\n *\n * ۱) Posterize: هر کانال رنگ به تعداد محدودی سطح گرد میشه (پهنههای رنگیِ\n * صاف و یکدست، حسِ کارتونی رنگ میده).\n * ۲) لبهیابی Sobel روی نسخهی خاکستریِ تصویر: هرجا شدت لبه از حد آستانه\n * بیشتر باشه، پیکسل تیره میشه (حسِ خط دور کارتونی).\n *\n * روی خودِ ImageData کار میکنه، پس هزینهش با اندازهی تصویر خطیست؛ برای\n * تصاویر خیلی بزرگ (>~3000px) بهتره قبلش resize بشه (که در کامپوننت اصلی\n * با fitWithin قبل از اعمال فیلتر انجام میشه).\n */\nexport function applyCartoonEffect(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n options: { levels?: number; edgeThreshold?: number } = {},\n): void {\n const levels = options.levels ?? 5;\n const edgeThreshold = options.edgeThreshold ?? 80;\n\n const imageData = ctx.getImageData(0, 0, width, height);\n const src = imageData.data;\n\n // ۱) خاکستری برای Sobel\n const gray = new Uint8ClampedArray(width * height);\n for (let i = 0, p = 0; i < src.length; i += 4, p++) {\n gray[p] = (src[i] * 0.299 + src[i + 1] * 0.587 + src[i + 2] * 0.114) | 0;\n }\n\n // ۲) Posterize رنگها\n const step = 255 / (levels - 1);\n for (let i = 0; i < src.length; i += 4) {\n src[i] = Math.round(Math.round(src[i] / step) * step);\n src[i + 1] = Math.round(Math.round(src[i + 1] / step) * step);\n src[i + 2] = Math.round(Math.round(src[i + 2] / step) * step);\n }\n\n // ۳) Sobel روی gray، خط دور تیره روی src\n const gxKernel = [-1, 0, 1, -2, 0, 2, -1, 0, 1];\n const gyKernel = [-1, -2, -1, 0, 0, 0, 1, 2, 1];\n\n for (let y = 1; y < height - 1; y++) {\n for (let x = 1; x < width - 1; x++) {\n let gx = 0;\n let gy = 0;\n let k = 0;\n for (let dy = -1; dy <= 1; dy++) {\n for (let dx = -1; dx <= 1; dx++) {\n const v = gray[(y + dy) * width + (x + dx)];\n gx += v * gxKernel[k];\n gy += v * gyKernel[k];\n k++;\n }\n }\n const magnitude = Math.sqrt(gx * gx + gy * gy);\n if (magnitude > edgeThreshold) {\n const idx = (y * width + x) * 4;\n src[idx] = 20;\n src[idx + 1] = 20;\n src[idx + 2] = 20;\n }\n }\n }\n\n ctx.putImageData(imageData, 0, 0);\n}\n","import { NgxCropRect, NgxImageEditorAdjustments } from '../contracts/image-editor-types';\nimport { applyCartoonEffect } from './cartoonify';\nimport { fitWithin } from './image-io';\n\n/** تصویر مبدأ رو با زاویهی دادهشده روی یه canvas جدید (به اندازهی bounding-box نتیجه) میچرخونه */\nexport function renderRotated(\n source: CanvasImageSource,\n width: number,\n height: number,\n degrees: number,\n): HTMLCanvasElement {\n const rad = (degrees * Math.PI) / 180;\n const sin = Math.abs(Math.sin(rad));\n const cos = Math.abs(Math.cos(rad));\n const newW = Math.max(1, Math.round(width * cos + height * sin));\n const newH = Math.max(1, Math.round(width * sin + height * cos));\n\n const canvas = document.createElement('canvas');\n canvas.width = newW;\n canvas.height = newH;\n const ctx = canvas.getContext('2d')!;\n ctx.translate(newW / 2, newH / 2);\n ctx.rotate(rad);\n ctx.drawImage(source, -width / 2, -height / 2, width, height);\n return canvas;\n}\n\nfunction buildCssFilter(adjustments: NgxImageEditorAdjustments): string {\n const parts = [\n `brightness(${adjustments.brightness}%)`,\n `contrast(${adjustments.contrast}%)`,\n `saturate(${adjustments.saturation}%)`,\n ];\n if (adjustments.filter === 'grayscale') parts.push('grayscale(1)');\n if (adjustments.filter === 'sepia') parts.push('sepia(1)');\n if (adjustments.filter === 'invert') parts.push('invert(1)');\n return parts.join(' ');\n}\n\n/**\n * کراپ + فیلترها رو روی یه canvas خروجی میسازه. brightness/contrast/\n * saturation/grayscale/sepia/invert همه با ctx.filter بومیِ Canvas 2D انجام\n * میشن (شتابدهیشده توسط مرورگر، بدون حلقهی پیکسلی دستی)؛ فقط cartoon\n * (که معادل بومی نداره) با پردازش پیکسلی جدا انجام میشه.\n *\n * maxWidth/maxHeight برای دو حالت استفاده میشه: پیشنمایش زنده (عدد کوچیک،\n * برای واکنشگرا موندن حین کشیدن اسلایدرها) و خروجی نهایی (بدون محدودیت یا\n * محدودیت دلخواه کاربر).\n */\nexport function renderComposite(\n source: CanvasImageSource,\n sourceWidth: number,\n sourceHeight: number,\n crop: NgxCropRect,\n adjustments: NgxImageEditorAdjustments,\n maxWidth?: number,\n maxHeight?: number,\n): HTMLCanvasElement {\n const { width: outW, height: outH } = fitWithin(crop.width, crop.height, maxWidth, maxHeight);\n\n const canvas = document.createElement('canvas');\n canvas.width = Math.max(1, outW);\n canvas.height = Math.max(1, outH);\n const ctx = canvas.getContext('2d')!;\n\n ctx.filter = buildCssFilter(adjustments);\n ctx.drawImage(source, crop.x, crop.y, crop.width, crop.height, 0, 0, canvas.width, canvas.height);\n ctx.filter = 'none';\n\n if (adjustments.filter === 'cartoon') {\n applyCartoonEffect(ctx, canvas.width, canvas.height);\n }\n\n return canvas;\n}\n","import { InjectionToken } from '@angular/core';\n\nexport const NGX_IMAGE_EDITOR_LOCALIZATION = new InjectionToken<NgxImageEditorLocalization>(\n 'ngx-image-localization',\n {\n factory: () => DEFAULT_NGX_IMAGE_EDITOR_LOCALIZATION,\n },\n);\n\nexport class NgxImageEditorLocalization {\n LoadingImage = 'Loading image…';\n Rotation = 'Fine rotation';\n Brightness = 'Brightness';\n Contrast = 'Contrast';\n Saturation = 'Saturation';\n Filter = 'Filter';\n None = 'None';\n Grayscale = 'Grayscale';\n Sepia = 'Sepia';\n Invert = 'Invert';\n Cartoon = 'Cartoon';\n Cancel = 'Cancel';\n Save = 'Save';\n Saving = 'Saving…';\n Reset = 'Reset';\n}\nexport const DEFAULT_NGX_IMAGE_EDITOR_LOCALIZATION = new NgxImageEditorLocalization();\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n computed,\n effect,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { SliderComponent } from 'ngx-kit/core';\nimport {\n NgxCropRect,\n NgxImageEditorAdjustments,\n NgxImageEditorResult,\n NgxImageFilterPreset,\n type NgxImageFileType,\n} from '../contracts/image-editor-types';\nimport { NgxPointerDragDelta, NgxPointerDragDirective } from '../directives/pointer-drag.directive';\nimport { canvasToBlob, createWorkingCopy, loadImage } from '../utils/image-io';\nimport { renderComposite, renderRotated } from '../utils/render-pipeline';\nimport { Corner } from '../types/corner';\nimport { NGX_IMAGE_EDITOR_LOCALIZATION, NgxImageEditorLocalization } from '../tokens/localization';\n\nconst ALL_FILTERS: NgxImageFilterPreset[] = ['none', 'grayscale', 'sepia', 'invert', 'cartoon'];\n\n@Component({\n selector: 'ngx-image-editor',\n standalone: true,\n imports: [FormsModule, SliderComponent, NgxPointerDragDirective],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './image-editor.component.html',\n styleUrl: './image-editor.component.scss',\n host: { class: 'ngx-image-editor-host' },\n})\nexport class NgxImageEditor {\n source = input<File | Blob | string | null>(null);\n /** قفل نسبتِ کراپ (مثلاً ۱ برای آواتار مربعی)؛ undefined یعنی آزاد */\n aspectRatio = input<number | undefined>(undefined);\n outputMaxWidth = input<number | undefined>(undefined);\n outputMaxHeight = input<number | undefined>(undefined);\n outputType = input<NgxImageFileType>('image/jpeg');\n\n /**\n * کدوم فیلترها نشون داده بشن (و به چه ترتیبی). اگه ندید، هر ۵ تا نشون داده\n * میشن. آرایهی خالی یعنی کلِ بخشِ فیلتر مخفی بشه.\n */\n filters = input<NgxImageFilterPreset[]>(ALL_FILTERS);\n quality = input(0.92);\n\n defaultLocalization = inject(NGX_IMAGE_EDITOR_LOCALIZATION);\n localize = input<NgxImageEditorLocalization>(this.defaultLocalization);\n\n saved = output<NgxImageEditorResult>();\n cancelled = output<void>();\n\n protected readonly loading = signal(false);\n protected readonly saving = signal(false);\n protected readonly loadError = signal<string | null>(null);\n\n private readonly originalImage = signal<HTMLImageElement | null>(null);\n private readonly workingCanvas = signal<HTMLCanvasElement | null>(null);\n private readonly stageWrapEl = viewChild<ElementRef<HTMLElement>>('stageWrap');\n /** عرضِ واقعیِ رندرشدهی کانتینر؛ چون عرض همیشه ۱۰۰٪ (fluid) هست، باید زنده اندازهگیری بشه */\n private readonly containerWidth = signal(0);\n\n protected readonly rotation = signal(0);\n protected readonly brightness = signal(100);\n protected readonly contrast = signal(100);\n protected readonly saturation = signal(100);\n protected readonly filterPreset = signal<NgxImageFilterPreset>('none');\n\n protected readonly crop = signal<NgxCropRect>({ x: 0, y: 0, width: 0, height: 0 });\n\n protected readonly adjustments = computed<NgxImageEditorAdjustments>(() => ({\n brightness: this.brightness(),\n contrast: this.contrast(),\n saturation: this.saturation(),\n rotation: this.rotation(),\n filter: this.filterPreset(),\n }));\n\n protected readonly filterLabels = computed<Record<NgxImageFilterPreset, string>>(() => {\n const t = this.localize();\n return {\n none: t.None,\n grayscale: t.Grayscale,\n sepia: t.Sepia,\n invert: t.Invert,\n cartoon: t.Cartoon,\n };\n });\n\n /** تصویرِ (کوچیکشدهیِ) چرخیده — پایهی نمایش صحنهی کراپ */\n protected readonly rotatedWorkingCanvas = computed(() => {\n const wc = this.workingCanvas();\n if (!wc) return null;\n return renderRotated(wc, wc.width, wc.height, this.rotation());\n });\n\n protected readonly panelSize = computed(() => {\n return this.stageWrapEl()?.nativeElement.getBoundingClientRect().height ?? 0;\n });\n\n /**\n * مقیاسِ «contain» واقعی: کوچیکترینِ نسبتِ عرض و ارتفاع (هرکدوم تنگتره)\n * تعیینکنندهست، و سقفش هم ۱ هست تا تصاویر کوچیک بزرگنمایی نشن.\n */\n protected readonly displayScale = computed(() => {\n const rc = this.rotatedWorkingCanvas();\n const containerW = this.containerWidth();\n const panelH = this.panelSize();\n if (!rc || rc.width <= 0 || rc.height <= 0 || containerW <= 0 || panelH <= 0) return 1;\n return Math.min(containerW / rc.width, panelH / rc.height, 1);\n });\n\n protected readonly stageImageUrl = computed(() => {\n const rc = this.rotatedWorkingCanvas();\n return rc ? rc.toDataURL('image/png') : null;\n });\n\n protected readonly stageSize = computed(() => {\n const rc = this.rotatedWorkingCanvas();\n const scale = this.displayScale();\n return rc ? { width: rc.width * scale, height: rc.height * scale } : { width: 0, height: 0 };\n });\n\n protected readonly cropOverlayStyle = computed(() => {\n const scale = this.displayScale();\n const c = this.crop();\n return {\n left: `${c.x * scale}px`,\n top: `${c.y * scale}px`,\n width: `${c.width * scale}px`,\n height: `${c.height * scale}px`,\n };\n });\n\n /** پیشنمایش نهایی (کوچیک، حداکثر ۴۸۰ پیکسل) — شامل همهچیز، حتی افکت کارتونی */\n protected readonly previewUrl = computed(() => {\n const rc = this.rotatedWorkingCanvas();\n const c = this.crop();\n if (!rc || c.width <= 0 || c.height <= 0) return null;\n const canvas = renderComposite(rc, rc.width, rc.height, c, this.adjustments(), 480, 480);\n return canvas.toDataURL('image/png');\n });\n\n private moveSnapshot: NgxCropRect | null = null;\n private resizeSnapshot: NgxCropRect | null = null;\n\n constructor() {\n // بارگذاری تصویر هروقت source عوض بشه\n effect(() => {\n const src = this.source();\n if (!src) {\n this.originalImage.set(null);\n this.workingCanvas.set(null);\n return;\n }\n this.loading.set(true);\n this.loadError.set(null);\n loadImage(src)\n .then((img) => {\n this.originalImage.set(img);\n this.workingCanvas.set(createWorkingCopy(img));\n this.resetAdjustments();\n })\n .catch((err) => this.loadError.set(err?.message ?? 'Failed to load image'))\n .finally(() => this.loading.set(false));\n });\n\n // هر وقت چرخیدهشده عوض بشه (بارگذاریِ تصویر جدید یا چرخش)، کراپ روی کل قاب ریست بشه\n effect(() => {\n const rc = this.rotatedWorkingCanvas();\n if (rc) {\n this.crop.set({ x: 0, y: 0, width: rc.width, height: rc.height });\n }\n });\n\n // اگه فیلترِ فعلاً انتخابشده دیگه توی لیستِ مجازِ filters() نباشه (مثلاً\n // مصرفکننده cartoon رو غیرفعال کرده درحالیکه کاربر روش بود)، برو روی\n // اولین فیلترِ مجاز؛ اگه لیست خالی باشه (کلاً فیلتر مخفیه)، روی none بمون.\n effect(() => {\n const allowed = this.filters();\n if (allowed.length && !allowed.includes(this.filterPreset())) {\n this.filterPreset.set(allowed[0]);\n }\n });\n\n // اندازهگیریِ زندهی عرضِ واقعیِ کانتینر — چون عرض همیشه ۱۰۰٪ (fluid)ه،\n // فقط با ResizeObserver میشه فهمید الان چند پیکسله (نه یه عددِ ثابتِ ورودی).\n effect((onCleanup) => {\n const el = this.stageWrapEl()?.nativeElement;\n if (!el) return;\n this.containerWidth.set(el.getBoundingClientRect().width);\n const ro = new ResizeObserver((entries) => {\n const width = entries[0]?.contentRect.width;\n if (width != null) this.containerWidth.set(width);\n });\n ro.observe(el);\n onCleanup(() => ro.disconnect());\n });\n }\n\n private resetAdjustments(): void {\n this.rotation.set(0);\n this.brightness.set(100);\n this.contrast.set(100);\n this.saturation.set(100);\n this.filterPreset.set(this.filters()[0] ?? 'none');\n }\n\n protected rotateBy(delta: number): void {\n this.rotation.update((r) => {\n let next = r + delta;\n if (next > 180) next -= 360;\n if (next < -180) next += 360;\n return next;\n });\n }\n\n protected setFilter(preset: NgxImageFilterPreset): void {\n this.filterPreset.set(preset);\n }\n\n // ---------- درگ جابهجاییِ کل کراپباکس ----------\n protected onMoveDragStart(): void {\n this.moveSnapshot = { ...this.crop() };\n }\n\n protected onMoveDragMove(delta: NgxPointerDragDelta): void {\n const rc = this.rotatedWorkingCanvas();\n const snap = this.moveSnapshot;\n if (!rc || !snap) return;\n const scale = this.displayScale();\n const dxSrc = delta.dx / scale;\n const dySrc = delta.dy / scale;\n const maxX = Math.max(0, rc.width - snap.width);\n const maxY = Math.max(0, rc.height - snap.height);\n const x = Math.min(Math.max(0, snap.x + dxSrc), maxX);\n const y = Math.min(Math.max(0, snap.y + dySrc), maxY);\n this.crop.set({ ...snap, x, y });\n }\n\n // ---------- درگ ریسایز از گوشهها ----------\n protected onResizeDragStart(): void {\n this.resizeSnapshot = { ...this.crop() };\n }\n\n protected onResizeDragMove(corner: Corner, delta: NgxPointerDragDelta): void {\n const rc = this.rotatedWorkingCanvas();\n const snap = this.resizeSnapshot;\n if (!rc || !snap) return;\n\n const scale = this.displayScale();\n const dxSrc = delta.dx / scale;\n const dySrc = delta.dy / scale;\n const minSize = 24;\n\n let { x, y, width, height } = snap;\n\n if (corner === 'nw' || corner === 'sw') {\n const newX = Math.min(snap.x + dxSrc, snap.x + snap.width - minSize);\n x = Math.max(0, newX);\n width = snap.x + snap.width - x;\n }\n if (corner === 'ne' || corner === 'se') {\n width = Math.min(Math.max(minSize, snap.width + dxSrc), rc.width - snap.x);\n }\n if (corner === 'nw' || corner === 'ne') {\n const newY = Math.min(snap.y + dySrc, snap.y + snap.height - minSize);\n y = Math.max(0, newY);\n height = snap.y + snap.height - y;\n }\n if (corner === 'sw' || corner === 'se') {\n height = Math.min(Math.max(minSize, snap.height + dySrc), rc.height - snap.y);\n }\n\n const ratio = this.aspectRatio();\n if (ratio) {\n height = width / ratio;\n }\n\n this.crop.set({ x, y, width, height });\n }\n\n protected cancel(): void {\n this.cancelled.emit();\n }\n\n async save(): Promise<void> {\n const original = this.originalImage();\n const working = this.workingCanvas();\n if (!original || !working) return;\n\n this.saving.set(true);\n try {\n // نسبت مقیاس بین کپیِ کوچیکشده (که کراپ/چرخش روش تعریف شده) و تصویر\n // اصلیِ کامل. چون createWorkingCopy مقیاس یکنواخت (همجهت) اعمال\n // میکنه، همین یه ضریب برای هر دو بعد و بعد از چرخش هم معتبر میمونه.\n const scaleToOriginal = original.naturalWidth / working.width;\n\n const rotatedFull = renderRotated(\n original,\n original.naturalWidth,\n original.naturalHeight,\n this.rotation(),\n );\n\n const c = this.crop();\n const cropInFullRes: NgxCropRect = {\n x: c.x * scaleToOriginal,\n y: c.y * scaleToOriginal,\n width: c.width * scaleToOriginal,\n height: c.height * scaleToOriginal,\n };\n\n const finalCanvas = renderComposite(\n rotatedFull,\n rotatedFull.width,\n rotatedFull.height,\n cropInFullRes,\n this.adjustments(),\n this.outputMaxWidth(),\n this.outputMaxHeight(),\n );\n\n const type = this.outputType();\n const blob = await canvasToBlob(finalCanvas, type, this.quality());\n const dataUrl = finalCanvas.toDataURL(type, this.quality());\n const file = new File([blob], '', { type });\n this.saved.emit({\n blob,\n dataUrl,\n width: finalCanvas.width,\n height: finalCanvas.height,\n file,\n type,\n });\n } finally {\n this.saving.set(false);\n }\n }\n}\n","@if (loading()) {\n <div class=\"ngx-ie-state\">{{ localize().LoadingImage }}</div>\n} @else if (loadError()) {\n <div class=\"ngx-ie-state ngx-ie-state--error\">{{ loadError() }}</div>\n} @else if (stageImageUrl()) {\n <div class=\"ngx-ie-layout\">\n <div class=\"ngx-ie-stage-wrap\" #stageWrap>\n <div\n class=\"ngx-ie-stage\"\n [style.width.px]=\"stageSize().width\"\n [style.height.px]=\"stageSize().height\">\n <img class=\"ngx-ie-stage-img\" [src]=\"stageImageUrl()\" alt=\"\" draggable=\"false\" />\n\n <div\n class=\"ngx-ie-crop-box\"\n [style.left]=\"cropOverlayStyle().left\"\n [style.top]=\"cropOverlayStyle().top\"\n [style.width]=\"cropOverlayStyle().width\"\n [style.height]=\"cropOverlayStyle().height\"\n ngxPointerDrag\n (dragStart)=\"onMoveDragStart()\"\n (dragMove)=\"onMoveDragMove($event)\">\n <span\n class=\"ngx-ie-handle ngx-ie-handle--nw\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('nw', $event)\"></span>\n <span\n class=\"ngx-ie-handle ngx-ie-handle--ne\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('ne', $event)\"></span>\n <span\n class=\"ngx-ie-handle ngx-ie-handle--sw\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('sw', $event)\"></span>\n <span\n class=\"ngx-ie-handle ngx-ie-handle--se\"\n ngxPointerDrag\n (dragStart)=\"onResizeDragStart()\"\n (dragMove)=\"onResizeDragMove('se', $event)\"></span>\n </div>\n </div>\n </div>\n\n <div class=\"ngx-ie-panel-row\">\n <div class=\"ngx-ie-panel\">\n <div class=\"ngx-ie-preview\">\n @if (previewUrl(); as url) {\n <img [src]=\"url\" alt=\"Preview\" />\n }\n </div>\n\n <div class=\"ngx-ie-row ngx-ie-rotate-row\">\n <button type=\"button\" (click)=\"rotateBy(-90)\" title=\"Rotate 90° left\">⟲ 90</button>\n <button type=\"button\" (click)=\"rotateBy(90)\" title=\"Rotate 90° right\">⟳ 90</button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"rotation()\"\n (ngModelChange)=\"rotation.set($event)\"\n [min]=\"-180\"\n [max]=\"180\">\n <span>{{ localize().Rotation }} ({{ rotation() }}°)</span>\n </slider>\n\n <button\n type=\"button\"\n (click)=\"rotation.set(0)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"brightness()\"\n (ngModelChange)=\"brightness.set($event)\"\n [min]=\"0\"\n [max]=\"200\">\n <span>{{ localize().Brightness }} ({{ brightness() }}%)</span>\n </slider>\n <button\n type=\"button\"\n (click)=\"brightness.set(100)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"contrast()\"\n (ngModelChange)=\"contrast.set($event)\"\n [min]=\"0\"\n [max]=\"200\">\n <span>{{ localize().Contrast }} ({{ contrast() }}%)</span>\n </slider>\n <button\n type=\"button\"\n (click)=\"contrast.set(100)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n <div class=\"ngx-ie-field\">\n <slider\n [ngModel]=\"saturation()\"\n (ngModelChange)=\"saturation.set($event)\"\n [min]=\"0\"\n [max]=\"200\">\n <span>{{ localize().Saturation }} ({{ saturation() }}%)</span>\n </slider>\n <button\n type=\"button\"\n (click)=\"saturation.set(100)\"\n class=\"ngx-ie-btn-secondary\"\n [title]=\"localize().Reset\">\n x\n </button>\n </div>\n\n @if (filters().length) {\n <div>\n <span>{{ localize().Filter }}</span>\n <div class=\"ngx-ie-filter-row\">\n @for (f of filters(); track f) {\n <button type=\"button\" [class.active]=\"filterPreset() === f\" (click)=\"setFilter(f)\">\n {{ filterLabels()[f] }}\n </button>\n }\n </div>\n </div>\n }\n\n <div class=\"ngx-ie-row ngx-ie-actions\">\n <button type=\"button\" class=\"ngx-ie-btn-secondary\" (click)=\"cancel()\">\n {{ localize().Cancel }}\n </button>\n <button type=\"button\" class=\"ngx-ie-btn-primary\" [disabled]=\"saving()\" (click)=\"save()\">\n {{ saving() ? localize().Saving : localize().Save }}\n </button>\n </div>\n </div>\n </div>\n </div>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -77,7 +77,7 @@ interface NgxDropzoneFileLike {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
type NgxDropzoneUploadMode = 'all' | 'single';
|
|
80
|
-
declare class
|
|
80
|
+
declare class NgxDropzone implements OnDestroy {
|
|
81
81
|
/** الگوی accept مثل input[type=file]: "image/*", ".pdf,.docx" و ... */
|
|
82
82
|
accept: _angular_core.InputSignal<string>;
|
|
83
83
|
multiple: _angular_core.InputSignal<boolean>;
|
|
@@ -157,8 +157,8 @@ declare class NgxDropzoneComponent implements OnDestroy {
|
|
|
157
157
|
private finishUpload;
|
|
158
158
|
private updateFile;
|
|
159
159
|
private emitCurrentFiles;
|
|
160
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<
|
|
161
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<
|
|
160
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgxDropzone, never>;
|
|
161
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<NgxDropzone, "ngx-dropzone", never, { "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "maxFileSize": { "alias": "maxFileSize"; "required": false; "isSignal": true; }; "maxFiles": { "alias": "maxFiles"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "showFileList": { "alias": "showFileList"; "required": false; "isSignal": true; }; "uploadUrl": { "alias": "uploadUrl"; "required": false; "isSignal": true; }; "uploadAlias": { "alias": "uploadAlias"; "required": false; "isSignal": true; }; "autoUpload": { "alias": "autoUpload"; "required": false; "isSignal": true; }; "maxParallel": { "alias": "maxParallel"; "required": false; "isSignal": true; }; "uploadMode": { "alias": "uploadMode"; "required": false; "isSignal": true; }; "uploadData": { "alias": "uploadData"; "required": false; "isSignal": true; }; "uploadHeaders": { "alias": "uploadHeaders"; "required": false; "isSignal": true; }; "uploadWithCredentials": { "alias": "uploadWithCredentials"; "required": false; "isSignal": true; }; }, { "filesAdded": "filesAdded"; "filesRejected": "filesRejected"; "filesChange": "filesChange"; "uploadStarted": "uploadStarted"; "uploadProgress": "uploadProgress"; "uploadSuccess": "uploadSuccess"; "uploadError": "uploadError"; }, never, ["[dropzone-icon]", "*"], true, never>;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
declare class NgxDropzoneHttpUploadService implements NgxDropzoneUploadService {
|
|
@@ -191,5 +191,5 @@ declare function formatBytes(bytes: number): string;
|
|
|
191
191
|
/** استخراج فایلهای واقعی از یک DataTransfer، شامل پیمایش بازگشتیِ پوشهها (وقتی مرورگر پشتیبانی کنه) */
|
|
192
192
|
declare function extractFilesFromDataTransfer(dataTransfer: DataTransfer): Promise<File[]>;
|
|
193
193
|
|
|
194
|
-
export { NGX_DROPZONE_UPLOAD_SERVICE,
|
|
194
|
+
export { NGX_DROPZONE_UPLOAD_SERVICE, NgxDropzone, NgxDropzoneHttpUploadService, extractFilesFromDataTransfer, formatBytes, matchesAccept };
|
|
195
195
|
export type { NgxDropzoneFile, NgxDropzoneFileLike, NgxDropzoneFileStatus, NgxDropzoneRejectedFile, NgxDropzoneRejectionReason, NgxDropzoneUploadEvent, NgxDropzoneUploadMode, NgxDropzoneUploadProgressEvent, NgxDropzoneUploadRequest, NgxDropzoneUploadService };
|
|
@@ -9,6 +9,7 @@ interface NgxCropRect {
|
|
|
9
9
|
height: number;
|
|
10
10
|
}
|
|
11
11
|
type NgxImageFilterPreset = 'none' | 'grayscale' | 'sepia' | 'invert' | 'cartoon';
|
|
12
|
+
type NgxImageFileType = 'image/jpeg' | 'image/png' | 'image/webp';
|
|
12
13
|
interface NgxImageEditorAdjustments {
|
|
13
14
|
/** همه ۱۰۰ یعنی بدون تغییر؛ بازهی معقول ۰ تا ۲۰۰ */
|
|
14
15
|
brightness: number;
|
|
@@ -19,10 +20,12 @@ interface NgxImageEditorAdjustments {
|
|
|
19
20
|
filter: NgxImageFilterPreset;
|
|
20
21
|
}
|
|
21
22
|
interface NgxImageEditorResult {
|
|
23
|
+
file: File;
|
|
22
24
|
blob: Blob;
|
|
23
25
|
dataUrl: string;
|
|
24
26
|
width: number;
|
|
25
27
|
height: number;
|
|
28
|
+
type: NgxImageFileType;
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
interface NgxPointerDragDelta {
|
|
@@ -75,33 +78,13 @@ declare class NgxImageEditorLocalization {
|
|
|
75
78
|
}
|
|
76
79
|
declare const DEFAULT_NGX_IMAGE_EDITOR_LOCALIZATION: NgxImageEditorLocalization;
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
* (سیاهوسفید، سپیا، معکوس، کارتونی) + فشردهسازی خروجی. کاملاً روی Canvas
|
|
81
|
-
* خام پیاده شده، بدون هیچ وابستگی خارجیای.
|
|
82
|
-
*
|
|
83
|
-
* نکتهی مهمِ معماری: تمام تعامل زنده (چرخوندن، جابهجا/ریسایز کراپباکس،
|
|
84
|
-
* پیشنمایش فیلترها حتی کارتونی) روی یه کپیِ کوچیکشده از تصویر انجام میشه
|
|
85
|
-
* (createWorkingCopy)، نه روی تصویر اصلی که ممکنه چند مگاپیکسل باشه — وگرنه
|
|
86
|
-
* درگکردن اسلایدرها/گوشههای کراپ رو کاربر حس تاخیر میکرد. فقط لحظهی
|
|
87
|
-
* save()، رندر نهایی از روی تصویر اصلیِ کامل انجام میشه.
|
|
88
|
-
*
|
|
89
|
-
* اندازهی صحنه (stage) با panelSize کنترل میشه: عرض همیشه ۱۰۰٪ عرضِ
|
|
90
|
-
* والدِ کامپوننته (با ResizeObserver اندازهگیری میشه، پس با تغییر سایز
|
|
91
|
-
* صفحه/layout هم زنده هماهنگ میمونه)، ارتفاع دقیقاً همون چیزیه که کاربر با
|
|
92
|
-
* panelSize میده. تصویر همیشه با یک مقیاسِ «contain» واقعی (هم بر اساس
|
|
93
|
-
* عرض، هم بر اساس ارتفاع — هرکدوم تنگتره) جا داده میشه، پس کلِ تصویر
|
|
94
|
-
* همیشه در محدودهی همین باکس دیده میشه، صرفنظر از اندازهی واقعیِ فایل.
|
|
95
|
-
* سقفِ مقیاس هم ۱ هست، یعنی تصاویر کوچیک بزرگنمایی نمیشن (که باعثِ محو
|
|
96
|
-
* شدنشون میشد).
|
|
97
|
-
*/
|
|
98
|
-
declare class NgxImageEditorComponent {
|
|
99
|
-
source: _angular_core.InputSignal<string | Blob | File | null>;
|
|
81
|
+
declare class NgxImageEditor {
|
|
82
|
+
source: _angular_core.InputSignal<string | File | Blob | null>;
|
|
100
83
|
/** قفل نسبتِ کراپ (مثلاً ۱ برای آواتار مربعی)؛ undefined یعنی آزاد */
|
|
101
84
|
aspectRatio: _angular_core.InputSignal<number | undefined>;
|
|
102
85
|
outputMaxWidth: _angular_core.InputSignal<number | undefined>;
|
|
103
86
|
outputMaxHeight: _angular_core.InputSignal<number | undefined>;
|
|
104
|
-
outputType: _angular_core.InputSignal<
|
|
87
|
+
outputType: _angular_core.InputSignal<NgxImageFileType>;
|
|
105
88
|
/**
|
|
106
89
|
* کدوم فیلترها نشون داده بشن (و به چه ترتیبی). اگه ندید، هر ۵ تا نشون داده
|
|
107
90
|
* میشن. آرایهی خالی یعنی کلِ بخشِ فیلتر مخفی بشه.
|
|
@@ -161,8 +144,8 @@ declare class NgxImageEditorComponent {
|
|
|
161
144
|
protected onResizeDragMove(corner: Corner, delta: NgxPointerDragDelta): void;
|
|
162
145
|
protected cancel(): void;
|
|
163
146
|
save(): Promise<void>;
|
|
164
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<
|
|
165
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<
|
|
147
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgxImageEditor, never>;
|
|
148
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<NgxImageEditor, "ngx-image-editor", never, { "source": { "alias": "source"; "required": false; "isSignal": true; }; "aspectRatio": { "alias": "aspectRatio"; "required": false; "isSignal": true; }; "outputMaxWidth": { "alias": "outputMaxWidth"; "required": false; "isSignal": true; }; "outputMaxHeight": { "alias": "outputMaxHeight"; "required": false; "isSignal": true; }; "outputType": { "alias": "outputType"; "required": false; "isSignal": true; }; "filters": { "alias": "filters"; "required": false; "isSignal": true; }; "quality": { "alias": "quality"; "required": false; "isSignal": true; }; "localize": { "alias": "localize"; "required": false; "isSignal": true; }; }, { "saved": "saved"; "cancelled": "cancelled"; }, never, never, true, never>;
|
|
166
149
|
}
|
|
167
150
|
|
|
168
151
|
/** یه File/Blob/data-URL/URL رو به یک HTMLImageElement بارگذاریشده تبدیل میکنه */
|
|
@@ -216,5 +199,5 @@ declare function applyCartoonEffect(ctx: CanvasRenderingContext2D, width: number
|
|
|
216
199
|
edgeThreshold?: number;
|
|
217
200
|
}): void;
|
|
218
201
|
|
|
219
|
-
export { DEFAULT_NGX_IMAGE_EDITOR_LOCALIZATION, NGX_IMAGE_EDITOR_LOCALIZATION,
|
|
220
|
-
export type { NgxCropRect, NgxImageEditorAdjustments, NgxImageEditorResult, NgxImageFilterPreset, NgxPointerDragDelta };
|
|
202
|
+
export { DEFAULT_NGX_IMAGE_EDITOR_LOCALIZATION, NGX_IMAGE_EDITOR_LOCALIZATION, NgxImageEditor, NgxImageEditorLocalization, NgxPointerDragDirective, applyCartoonEffect, canvasToBlob, createWorkingCopy, fitWithin, loadImage, renderComposite, renderRotated };
|
|
203
|
+
export type { NgxCropRect, NgxImageEditorAdjustments, NgxImageEditorResult, NgxImageFileType, NgxImageFilterPreset, NgxPointerDragDelta };
|