cloud-ide-element 1.0.12 → 1.0.14

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.
@@ -1482,12 +1482,12 @@ class CideEleButtonComponent {
1482
1482
  }
1483
1483
  }
1484
1484
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleButtonComponent, deps: [{ token: CideElementsService }, { token: i2$1.Router }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
1485
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideEleButtonComponent, isStandalone: true, selector: "button[cideEleButton], a[cideEleButton]", inputs: { label: "label", variant: "variant", size: "size", type: "type", shape: "shape", elevation: "elevation", disabled: "disabled", id: "id", loading: "loading", fullWidth: "fullWidth", leftIcon: "leftIcon", rightIcon: "rightIcon", customClass: "customClass", tooltip: "tooltip", ariaLabel: "ariaLabel", testId: "testId", routerLink: "routerLink", routerExtras: "routerExtras", preventDoubleClick: "preventDoubleClick", animated: "animated" }, outputs: { btnClick: "btnClick", doubleClick: "doubleClick" }, host: { listeners: { "click": "onClick($event)" }, properties: { "class.cide-button-disabled": "disabled || loading", "attr.disabled": "(disabled || loading) ? true : null", "class.primary": "variant === \"primary\"", "class.secondary": "variant === \"secondary\"", "class.outline": "variant === \"outline\"", "class.text": "variant === \"text\"", "class.link": "variant === \"link\"", "class.success": "variant === \"success\"", "class.danger": "variant === \"danger\"", "class.warning": "variant === \"warning\"", "class.info": "variant === \"info\"", "class.xs": "size === \"xs\"", "class.sm": "size === \"sm\"", "class.md": "size === \"md\"", "class.lg": "size === \"lg\"", "class.xl": "size === \"xl\"", "class.rounded": "shape === \"rounded\"", "class.pill": "shape === \"pill\"", "class.square": "shape === \"square\"", "class.elevation-none": "elevation === \"none\"", "class.elevation-low": "elevation === \"low\"", "class.elevation-medium": "elevation === \"medium\"", "class.elevation-high": "elevation === \"high\"", "attr.type": "type", "attr.aria-label": "ariaLabel", "attr.aria-disabled": "disabled || loading", "attr.data-testid": "testId", "attr.title": "tooltip", "class": "customClass" }, classAttribute: "cide-button tw-rounded-md tw-text-white tw-py-0.5 tw-select-none tw-justify-around tw-flex" }, usesOnChanges: true, ngImport: i0, template: "<!-- Button content container -->\r\n<div class=\"tw-flex tw-items-center tw-justify-center cide-ele-btn-content tw-w-full\">\r\n <!-- Left icon -->\r\n @if (leftIcon) {\r\n <span class=\"tw-icon-container tw-mr-2\">\r\n <i class=\"tw-text-base material-symbols-outlined\">{{leftIcon}}</i>\r\n </span>\r\n }\r\n \r\n <!-- Loading spinner -->\r\n @if (loading) {\r\n <cide-ele-spinner\r\n class=\"tw-inline-block tw-my-1 tw-mr-2\" \r\n size=\"xs\"\r\n [ngClass]=\"{'cide-pill-disabled': (disabled || loading)}\">\r\n </cide-ele-spinner>\r\n }\r\n \r\n <!-- Button label or content -->\r\n @if (label) {\r\n <span>{{ label }}</span>\r\n } @else {\r\n <span class=\"tw-flex tw-items-center tw-justify-center\">\r\n <ng-content></ng-content>\r\n </span>\r\n }\r\n \r\n <!-- Right icon -->\r\n @if (rightIcon) {\r\n <span class=\"tw-icon-container tw-ml-2\">\r\n <i class=\"tw-text-base material-symbols-outlined\">{{rightIcon}}</i>\r\n </span>\r\n }\r\n \r\n <!-- Spacer for spinner when loading to maintain button width -->\r\n @if (loading) {\r\n <span class=\"tw-w-6 tw-p-1 tw-mr-2\"></span>\r\n }\r\n</div>\r\n", styles: [":host{position:relative;background-color:var(--cide-theme-color-brand-primary, #3b82f6);cursor:pointer;font-family:inherit;font-weight:500;outline:none;overflow:hidden;transition:all .2s ease-in-out;border:none;text-align:center;vertical-align:middle;text-decoration:none;line-height:1.5;letter-spacing:.025em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}:host:focus-visible{outline:2px solid var(--cide-theme-color-brand-primary);outline-offset:2px;box-shadow:0 0 0 3px #3b82f64d}:host:hover:not(:disabled){background-color:var(--cide-theme-color-brand-primary-hover, #2563eb);transform:translateY(-1px)}:host:active:not(:disabled){transform:translateY(1px)}:host.cide-button-disabled{background-color:var(--cide-button-background-disabled, #9ca3af)!important;cursor:var(--cide-button-cursor-disabled, not-allowed)!important;opacity:.7;pointer-events:none;transform:none!important}:host.xs{font-size:.75rem;padding:.2rem .4rem}:host.sm{font-size:.875rem;padding:.25rem .5rem}:host.md{font-size:1rem;padding:.25rem .75rem}:host.lg{font-size:1.125rem;padding:.75rem 1rem}:host.xl{font-size:1.25rem;padding:1rem 1.5rem}:host.rounded{border-radius:.5rem}:host.pill{border-radius:9999px}:host.square{border-radius:0}:host.elevation-none{box-shadow:none}:host.elevation-low{box-shadow:0 1px 2px #0000000d}:host.elevation-medium{box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f}:host.elevation-high{box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -2px #0000000d}.ripple-effect{position:absolute;border-radius:50%;background-color:#fff6;transform:scale(0);animation:ripple .6s linear;pointer-events:none}@keyframes ripple{to{transform:scale(4);opacity:0}}:host{color:#fff}:host.secondary{background-color:var(--cide-theme-secondary-color, #4b5563);color:#fff}:host.secondary:hover:not(:disabled){background-color:var(--cide-theme-secondary-color-hover, #374151)}:host.success{background-color:var(--cide-theme-success-color, #10b981);color:#fff}:host.success:hover:not(:disabled){background-color:var(--cide-theme-success-color-hover, #059669)}:host.danger{background-color:var(--cide-theme-danger-color, #ef4444);color:#fff}:host.danger:hover:not(:disabled){background-color:var(--cide-theme-danger-color-hover, #dc2626)}:host.warning{background-color:var(--cide-theme-warning-color, #f59e0b);color:#fff}:host.warning:hover:not(:disabled){background-color:var(--cide-theme-warning-color-hover, #d97706)}:host.info{background-color:var(--cide-theme-info-color, #3b82f6);color:#fff}:host.info:hover:not(:disabled){background-color:var(--cide-theme-info-color-hover, #2563eb)}:host.outline{background-color:transparent;color:var(--cide-theme-color-brand-primary, #3b82f6);border:1px solid var(--cide-theme-color-brand-primary, #3b82f6)}:host.outline:hover:not(:disabled){background-color:#3b82f60d}:host.outline.secondary{color:var(--cide-theme-secondary-color, #4b5563);border-color:var(--cide-theme-secondary-color, #4b5563)}:host.outline.success{color:var(--cide-theme-success-color, #10b981);border-color:var(--cide-theme-success-color, #10b981)}:host.outline.danger{color:var(--cide-theme-danger-color, #ef4444);border-color:var(--cide-theme-danger-color, #ef4444)}:host.outline.warning{color:var(--cide-theme-warning-color, #f59e0b);border-color:var(--cide-theme-warning-color, #f59e0b)}:host.outline.info{color:var(--cide-theme-info-color, #3b82f6);border-color:var(--cide-theme-info-color, #3b82f6)}:host.text{background-color:transparent;color:var(--cide-theme-color-brand-primary, #3b82f6);border:none;padding-left:.5rem;padding-right:.5rem}:host.text:hover:not(:disabled){background-color:#3b82f60d;text-decoration:underline}:host.text.secondary{color:var(--cide-theme-secondary-color, #4b5563)}:host.text.success{color:var(--cide-theme-success-color, #10b981)}:host.text.danger{color:var(--cide-theme-danger-color, #ef4444)}:host.text.warning{color:var(--cide-theme-warning-color, #f59e0b)}:host.text.info{color:var(--cide-theme-info-color, #3b82f6)}:host.link{background-color:transparent;color:var(--cide-theme-color-brand-primary, #3b82f6);border:none;text-decoration:underline;padding:0;font-weight:400}:host.link:hover:not(:disabled){color:var(--cide-theme-color-brand-primary-hover, #2563eb);text-decoration:underline}:host.link.secondary{color:var(--cide-theme-secondary-color, #4b5563)}:host.link.success{color:var(--cide-theme-success-color, #10b981)}:host.link.danger{color:var(--cide-theme-danger-color, #ef4444)}:host.link.warning{color:var(--cide-theme-warning-color, #f59e0b)}:host.link.info{color:var(--cide-theme-info-color, #3b82f6)}.tw-icon-container{display:inline-flex;align-items:center;justify-content:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: CideSpinnerComponent, selector: "cide-ele-spinner", inputs: ["size", "type"] }] });
1485
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideEleButtonComponent, isStandalone: true, selector: "button[cideEleButton], a[cideEleButton]", inputs: { label: "label", variant: "variant", size: "size", type: "type", shape: "shape", elevation: "elevation", disabled: "disabled", id: "id", loading: "loading", fullWidth: "fullWidth", leftIcon: "leftIcon", rightIcon: "rightIcon", customClass: "customClass", tooltip: "tooltip", ariaLabel: "ariaLabel", testId: "testId", routerLink: "routerLink", routerExtras: "routerExtras", preventDoubleClick: "preventDoubleClick", animated: "animated" }, outputs: { btnClick: "btnClick", doubleClick: "doubleClick" }, host: { listeners: { "click": "onClick($event)" }, properties: { "class.cide-button-disabled": "disabled || loading", "attr.disabled": "(disabled || loading) ? true : null", "class.primary": "variant === \"primary\"", "class.secondary": "variant === \"secondary\"", "class.outline": "variant === \"outline\"", "class.text": "variant === \"text\"", "class.link": "variant === \"link\"", "class.success": "variant === \"success\"", "class.danger": "variant === \"danger\"", "class.warning": "variant === \"warning\"", "class.info": "variant === \"info\"", "class.xs": "size === \"xs\"", "class.sm": "size === \"sm\"", "class.md": "size === \"md\"", "class.lg": "size === \"lg\"", "class.xl": "size === \"xl\"", "class.rounded": "shape === \"rounded\"", "class.pill": "shape === \"pill\"", "class.square": "shape === \"square\"", "class.elevation-none": "elevation === \"none\"", "class.elevation-low": "elevation === \"low\"", "class.elevation-medium": "elevation === \"medium\"", "class.elevation-high": "elevation === \"high\"", "attr.type": "type", "attr.aria-label": "ariaLabel", "attr.aria-disabled": "disabled || loading", "attr.data-testid": "testId", "attr.title": "tooltip", "class": "customClass" }, classAttribute: "cide-button tw-rounded-md tw-text-white tw-py-0.5 tw-select-none tw-flex tw-items-center tw-justify-center" }, usesOnChanges: true, ngImport: i0, template: "<!-- Button content container -->\r\n<div class=\"tw-flex tw-items-center tw-justify-center cide-ele-btn-content tw-w-full\">\r\n <!-- Left icon -->\r\n @if (leftIcon) {\r\n <span class=\"tw-icon-container tw-mr-2\">\r\n <i class=\"tw-text-base material-symbols-outlined\">{{leftIcon}}</i>\r\n </span>\r\n }\r\n \r\n <!-- Loading spinner -->\r\n @if (loading) {\r\n <cide-ele-spinner\r\n class=\"tw-inline-block tw-my-1 tw-mr-2\" \r\n size=\"xs\"\r\n [ngClass]=\"{'cide-pill-disabled': (disabled || loading)}\">\r\n </cide-ele-spinner>\r\n }\r\n \r\n <!-- Button label or content -->\r\n @if (label) {\r\n <span>{{ label }}</span>\r\n } @else {\r\n <span class=\"tw-flex tw-items-center tw-justify-center\">\r\n <ng-content></ng-content>\r\n </span>\r\n }\r\n \r\n <!-- Right icon -->\r\n @if (rightIcon) {\r\n <span class=\"tw-icon-container tw-ml-2\">\r\n <i class=\"tw-text-base material-symbols-outlined\">{{rightIcon}}</i>\r\n </span>\r\n }\r\n \r\n <!-- Spacer for spinner when loading to maintain button width -->\r\n @if (loading) {\r\n <span class=\"tw-w-6 tw-p-1 tw-mr-2\"></span>\r\n }\r\n</div>\r\n", styles: [":host{position:relative;background-color:var(--cide-theme-color-brand-primary, #3b82f6);cursor:pointer;font-family:inherit;font-weight:500;outline:none;overflow:hidden;transition:all .2s ease-in-out;border:none;text-align:center;vertical-align:middle;text-decoration:none;line-height:1.5;letter-spacing:.025em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}:host:focus-visible{outline:2px solid var(--cide-theme-color-brand-primary);outline-offset:2px;box-shadow:0 0 0 3px #3b82f64d}:host:hover:not(:disabled){background-color:var(--cide-theme-color-brand-primary-hover, #2563eb);transform:translateY(-1px)}:host:active:not(:disabled){transform:translateY(1px)}:host.cide-button-disabled{background-color:var(--cide-button-background-disabled, #9ca3af)!important;cursor:var(--cide-button-cursor-disabled, not-allowed)!important;opacity:.7;pointer-events:none;transform:none!important}:host.xs{font-size:.75rem;padding:.2rem .4rem}:host.sm{font-size:.875rem;padding:.25rem .5rem}:host.md{font-size:1rem;padding:.25rem .75rem}:host.lg{font-size:1.125rem;padding:.75rem 1rem}:host.xl{font-size:1.25rem;padding:1rem 1.5rem}:host.rounded{border-radius:.5rem}:host.pill{border-radius:9999px}:host.square{border-radius:0}:host.elevation-none{box-shadow:none}:host.elevation-low{box-shadow:0 1px 2px #0000000d}:host.elevation-medium{box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f}:host.elevation-high{box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -2px #0000000d}.ripple-effect{position:absolute;border-radius:50%;background-color:#fff6;transform:scale(0);animation:ripple .6s linear;pointer-events:none}@keyframes ripple{to{transform:scale(4);opacity:0}}:host{color:#fff}:host.secondary{background-color:var(--cide-theme-secondary-color, #4b5563);color:#fff}:host.secondary:hover:not(:disabled){background-color:var(--cide-theme-secondary-color-hover, #374151)}:host.success{background-color:var(--cide-theme-success-color, #10b981);color:#fff}:host.success:hover:not(:disabled){background-color:var(--cide-theme-success-color-hover, #059669)}:host.danger{background-color:var(--cide-theme-danger-color, #ef4444);color:#fff}:host.danger:hover:not(:disabled){background-color:var(--cide-theme-danger-color-hover, #dc2626)}:host.warning{background-color:var(--cide-theme-warning-color, #f59e0b);color:#fff}:host.warning:hover:not(:disabled){background-color:var(--cide-theme-warning-color-hover, #d97706)}:host.info{background-color:var(--cide-theme-info-color, #3b82f6);color:#fff}:host.info:hover:not(:disabled){background-color:var(--cide-theme-info-color-hover, #2563eb)}:host.outline{background-color:transparent;color:var(--cide-theme-color-brand-primary, #3b82f6);border:1px solid var(--cide-theme-color-brand-primary, #3b82f6)}:host.outline:hover:not(:disabled){background-color:#3b82f60d}:host.outline.secondary{color:var(--cide-theme-secondary-color, #4b5563);border-color:var(--cide-theme-secondary-color, #4b5563)}:host.outline.success{color:var(--cide-theme-success-color, #10b981);border-color:var(--cide-theme-success-color, #10b981)}:host.outline.danger{color:var(--cide-theme-danger-color, #ef4444);border-color:var(--cide-theme-danger-color, #ef4444)}:host.outline.warning{color:var(--cide-theme-warning-color, #f59e0b);border-color:var(--cide-theme-warning-color, #f59e0b)}:host.outline.info{color:var(--cide-theme-info-color, #3b82f6);border-color:var(--cide-theme-info-color, #3b82f6)}:host.text{background-color:transparent;color:var(--cide-theme-color-brand-primary, #3b82f6);border:none;padding-left:.5rem;padding-right:.5rem}:host.text:hover:not(:disabled){background-color:#3b82f60d;text-decoration:underline}:host.text.secondary{color:var(--cide-theme-secondary-color, #4b5563)}:host.text.success{color:var(--cide-theme-success-color, #10b981)}:host.text.danger{color:var(--cide-theme-danger-color, #ef4444)}:host.text.warning{color:var(--cide-theme-warning-color, #f59e0b)}:host.text.info{color:var(--cide-theme-info-color, #3b82f6)}:host.link{background-color:transparent;color:var(--cide-theme-color-brand-primary, #3b82f6);border:none;text-decoration:underline;padding:0;font-weight:400}:host.link:hover:not(:disabled){color:var(--cide-theme-color-brand-primary-hover, #2563eb);text-decoration:underline}:host.link.secondary{color:var(--cide-theme-secondary-color, #4b5563)}:host.link.success{color:var(--cide-theme-success-color, #10b981)}:host.link.danger{color:var(--cide-theme-danger-color, #ef4444)}:host.link.warning{color:var(--cide-theme-warning-color, #f59e0b)}:host.link.info{color:var(--cide-theme-info-color, #3b82f6)}.tw-icon-container{display:inline-flex;align-items:center;justify-content:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: CideSpinnerComponent, selector: "cide-ele-spinner", inputs: ["size", "type"] }] });
1486
1486
  }
1487
1487
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleButtonComponent, decorators: [{
1488
1488
  type: Component,
1489
1489
  args: [{ selector: 'button[cideEleButton], a[cideEleButton]', standalone: true, imports: [CommonModule, CideSpinnerComponent], host: {
1490
- 'class': 'cide-button tw-rounded-md tw-text-white tw-py-0.5 tw-select-none tw-justify-around tw-flex',
1490
+ 'class': 'cide-button tw-rounded-md tw-text-white tw-py-0.5 tw-select-none tw-flex tw-items-center tw-justify-center',
1491
1491
  '[class.cide-button-disabled]': 'disabled || loading',
1492
1492
  '[attr.disabled]': '(disabled || loading) ? true : null',
1493
1493
  '[class.primary]': 'variant === "primary"',
@@ -3375,841 +3375,361 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
3375
3375
  }]
3376
3376
  }], ctorParameters: () => [] });
3377
3377
 
3378
- class KeyboardShortcutService {
3379
- shortcuts = new Map();
3380
- overrides = new Map();
3381
- keydownListener;
3382
- constructor() {
3383
- this.setupGlobalListener();
3378
+ class CideEleFloatingContainerService {
3379
+ injector;
3380
+ containers = signal(new Map(), ...(ngDevMode ? [{ debugName: "containers" }] : []));
3381
+ nextZIndex = signal(1000, ...(ngDevMode ? [{ debugName: "nextZIndex" }] : []));
3382
+ instanceCounter = signal(0, ...(ngDevMode ? [{ debugName: "instanceCounter" }] : []));
3383
+ // Dynamic component management
3384
+ componentRegistry = new Map();
3385
+ activeComponents = new Map();
3386
+ constructor(injector) {
3387
+ this.injector = injector;
3388
+ // Keyboard shortcuts are registered by FloatingContainerShortcutsService independently
3384
3389
  }
3385
- ngOnDestroy() {
3386
- this.removeGlobalListener();
3390
+ // Computed properties
3391
+ visibleContainers = computed(() => Array.from(this.containers().values()).filter(container => container.isVisible), ...(ngDevMode ? [{ debugName: "visibleContainers" }] : []));
3392
+ minimizedContainers = computed(() => Array.from(this.containers().values()).filter(container => container.isMinimized), ...(ngDevMode ? [{ debugName: "minimizedContainers" }] : []));
3393
+ maximizedContainers = computed(() => Array.from(this.containers().values()).filter(container => container.isMaximized), ...(ngDevMode ? [{ debugName: "maximizedContainers" }] : []));
3394
+ // Container management methods
3395
+ show(config) {
3396
+ const containerId = config.id || this.generateId();
3397
+ const instanceId = this.generateInstanceId(config.componentId || 'default');
3398
+ // Get the highest z-index and add 1 to bring new container to front
3399
+ const maxZIndex = this.getMaxZIndex();
3400
+ const zIndex = maxZIndex + 1;
3401
+ const now = new Date();
3402
+ const container = {
3403
+ id: containerId,
3404
+ config: { ...config, id: containerId },
3405
+ isVisible: true,
3406
+ isMinimized: false,
3407
+ isMaximized: false,
3408
+ zIndex,
3409
+ instanceId,
3410
+ componentType: config.componentId || 'default',
3411
+ createdAt: now,
3412
+ lastAccessed: now
3413
+ };
3414
+ this.containers.update(containers => {
3415
+ const newContainers = new Map(containers);
3416
+ newContainers.set(containerId, container);
3417
+ return newContainers;
3418
+ });
3419
+ this.nextZIndex.update(z => z + 1);
3420
+ return containerId;
3387
3421
  }
3388
- /**
3389
- * Register a new keyboard shortcut
3390
- */
3391
- register(shortcut) {
3392
- this.shortcuts.set(shortcut.id, shortcut);
3393
- console.log(`⌨️ [KeyboardShortcut] Registered shortcut: ${shortcut.id} (${this.getKeyDescription(shortcut)})`);
3422
+ hide(containerId) {
3423
+ this.containers.update(containers => {
3424
+ const newContainers = new Map(containers);
3425
+ const container = newContainers.get(containerId);
3426
+ if (container) {
3427
+ container.isVisible = false;
3428
+ newContainers.set(containerId, container);
3429
+ }
3430
+ return newContainers;
3431
+ });
3394
3432
  }
3395
3433
  /**
3396
- * Override an existing shortcut with new key combination
3434
+ * Get the maximum z-index among all visible containers
3397
3435
  */
3398
- override(shortcutId, newKey, options) {
3399
- const originalShortcut = this.shortcuts.get(shortcutId);
3400
- if (!originalShortcut) {
3401
- console.warn(`⚠️ [KeyboardShortcut] Cannot override shortcut '${shortcutId}' - not found`);
3402
- return;
3436
+ getMaxZIndex() {
3437
+ const containers = this.containers();
3438
+ let maxZIndex = 1000; // Base z-index
3439
+ for (const container of containers.values()) {
3440
+ if (container.isVisible && container.zIndex > maxZIndex) {
3441
+ maxZIndex = container.zIndex;
3442
+ }
3403
3443
  }
3404
- const override = {
3405
- shortcutId,
3406
- newKey,
3407
- newCtrlKey: options?.ctrlKey,
3408
- newAltKey: options?.altKey,
3409
- newShiftKey: options?.shiftKey,
3410
- newMetaKey: options?.metaKey
3411
- };
3412
- this.overrides.set(shortcutId, override);
3413
- console.log(`🔄 [KeyboardShortcut] Override registered for '${shortcutId}': ${this.getKeyDescription({ ...originalShortcut, ...options, key: newKey })}`);
3414
- }
3415
- /**
3416
- * Remove a shortcut
3417
- */
3418
- unregister(shortcutId) {
3419
- this.shortcuts.delete(shortcutId);
3420
- this.overrides.delete(shortcutId);
3421
- console.log(`🗑️ [KeyboardShortcut] Removed shortcut: ${shortcutId}`);
3444
+ return maxZIndex;
3422
3445
  }
3423
3446
  /**
3424
- * Remove override for a shortcut (restore original key combination)
3447
+ * Bring a container to the front (highest z-index)
3425
3448
  */
3426
- removeOverride(shortcutId) {
3427
- this.overrides.delete(shortcutId);
3428
- console.log(`🔄 [KeyboardShortcut] Override removed for: ${shortcutId}`);
3449
+ bringToFront(containerId) {
3450
+ const maxZIndex = this.getMaxZIndex();
3451
+ const newZIndex = maxZIndex + 1;
3452
+ console.log(`🎯 [FloatingContainer] Bringing container '${containerId}' to front`);
3453
+ console.log(`🎯 [FloatingContainer] Current max z-index: ${maxZIndex}, new z-index: ${newZIndex}`);
3454
+ this.containers.update(containers => {
3455
+ const newContainers = new Map(containers);
3456
+ const container = newContainers.get(containerId);
3457
+ if (container) {
3458
+ const oldZIndex = container.zIndex;
3459
+ container.zIndex = newZIndex;
3460
+ container.lastAccessed = new Date();
3461
+ newContainers.set(containerId, container);
3462
+ console.log(`🎯 [FloatingContainer] Container '${containerId}' z-index updated: ${oldZIndex} → ${newZIndex}`);
3463
+ }
3464
+ else {
3465
+ console.warn(`⚠️ [FloatingContainer] Container '${containerId}' not found!`);
3466
+ }
3467
+ return newContainers;
3468
+ });
3429
3469
  }
3430
- /**
3431
- * Get all registered shortcuts
3432
- */
3433
- getAllShortcuts() {
3434
- return Array.from(this.shortcuts.values());
3470
+ minimize(containerId) {
3471
+ this.containers.update(containers => {
3472
+ const newContainers = new Map(containers);
3473
+ const container = newContainers.get(containerId);
3474
+ if (container) {
3475
+ container.isMinimized = !container.isMinimized;
3476
+ newContainers.set(containerId, container);
3477
+ }
3478
+ return newContainers;
3479
+ });
3435
3480
  }
3436
- /**
3437
- * Get shortcuts by category or filter
3438
- */
3439
- getShortcuts(filter) {
3440
- const shortcuts = this.getAllShortcuts();
3441
- return filter ? shortcuts.filter(filter) : shortcuts;
3481
+ maximize(containerId) {
3482
+ this.containers.update(containers => {
3483
+ const newContainers = new Map(containers);
3484
+ const container = newContainers.get(containerId);
3485
+ if (container) {
3486
+ container.isMaximized = !container.isMaximized;
3487
+ newContainers.set(containerId, container);
3488
+ }
3489
+ return newContainers;
3490
+ });
3442
3491
  }
3443
- /**
3444
- * Check if a shortcut is registered
3445
- */
3446
- hasShortcut(shortcutId) {
3447
- return this.shortcuts.has(shortcutId);
3492
+ getContainer(containerId) {
3493
+ return this.containers().get(containerId);
3448
3494
  }
3449
- /**
3450
- * Get shortcut information
3451
- */
3452
- getShortcut(shortcutId) {
3453
- return this.shortcuts.get(shortcutId);
3495
+ isVisible(containerId) {
3496
+ const container = this.getContainer(containerId);
3497
+ return container ? container.isVisible : false;
3454
3498
  }
3455
- /**
3456
- * Clear all shortcuts
3457
- */
3458
- clearAll() {
3459
- this.shortcuts.clear();
3460
- this.overrides.clear();
3461
- console.log(`🧹 [KeyboardShortcut] All shortcuts cleared`);
3499
+ isMinimized(containerId) {
3500
+ const container = this.getContainer(containerId);
3501
+ return container ? container.isMinimized : false;
3462
3502
  }
3463
- /**
3464
- * Set up global keyboard listener
3465
- */
3466
- setupGlobalListener() {
3467
- this.keydownListener = (event) => {
3468
- this.handleKeydown(event);
3469
- };
3470
- document.addEventListener('keydown', this.keydownListener);
3471
- console.log(`🎧 [KeyboardShortcut] Global keyboard listener attached`);
3503
+ isMaximized(containerId) {
3504
+ const container = this.getContainer(containerId);
3505
+ return container ? container.isMaximized : false;
3472
3506
  }
3473
- /**
3474
- * Remove global keyboard listener
3475
- */
3476
- removeGlobalListener() {
3477
- if (this.keydownListener) {
3478
- document.removeEventListener('keydown', this.keydownListener);
3479
- this.keydownListener = undefined;
3480
- console.log(`🎧 [KeyboardShortcut] Global keyboard listener removed`);
3481
- }
3507
+ hideAll() {
3508
+ this.containers.update(containers => {
3509
+ const newContainers = new Map(containers);
3510
+ for (const [id, container] of newContainers) {
3511
+ container.isVisible = false;
3512
+ newContainers.set(id, container);
3513
+ }
3514
+ return newContainers;
3515
+ });
3482
3516
  }
3483
- /**
3484
- * Handle keydown events
3485
- */
3486
- handleKeydown(event) {
3487
- for (const [shortcutId, shortcut] of this.shortcuts) {
3488
- if (this.matchesShortcut(event, shortcut)) {
3489
- // Check for override
3490
- const override = this.overrides.get(shortcutId);
3491
- if (override && !this.matchesOverride(event, override)) {
3492
- continue; // Skip if override doesn't match
3493
- }
3494
- if (shortcut.preventDefault !== false) {
3495
- event.preventDefault();
3496
- }
3497
- if (shortcut.stopPropagation) {
3498
- event.stopPropagation();
3517
+ minimizeAll() {
3518
+ this.containers.update(containers => {
3519
+ const newContainers = new Map(containers);
3520
+ for (const [id, container] of newContainers) {
3521
+ if (container.isVisible) {
3522
+ container.isMinimized = true;
3523
+ newContainers.set(id, container);
3499
3524
  }
3500
- console.log(`⌨️ [KeyboardShortcut] Executing shortcut: ${shortcutId}`);
3501
- shortcut.action();
3502
- break; // Only execute one shortcut per keydown
3503
3525
  }
3504
- }
3526
+ return newContainers;
3527
+ });
3505
3528
  }
3506
- /**
3507
- * Check if event matches shortcut
3508
- */
3509
- matchesShortcut(event, shortcut) {
3510
- return event.key === shortcut.key &&
3511
- (shortcut.ctrlKey === undefined || event.ctrlKey === shortcut.ctrlKey) &&
3512
- (shortcut.altKey === undefined || event.altKey === shortcut.altKey) &&
3513
- (shortcut.shiftKey === undefined || event.shiftKey === shortcut.shiftKey) &&
3514
- (shortcut.metaKey === undefined || event.metaKey === shortcut.metaKey);
3529
+ generateId() {
3530
+ return `floating-container-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
3515
3531
  }
3516
- /**
3517
- * Check if event matches override
3518
- */
3519
- matchesOverride(event, override) {
3520
- return event.key === override.newKey &&
3521
- (override.newCtrlKey === undefined || event.ctrlKey === override.newCtrlKey) &&
3522
- (override.newAltKey === undefined || event.altKey === override.newAltKey) &&
3523
- (override.newShiftKey === undefined || event.shiftKey === override.newShiftKey) &&
3524
- (override.newMetaKey === undefined || event.metaKey === override.newMetaKey);
3532
+ generateInstanceId(componentType) {
3533
+ const counter = this.instanceCounter() + 1;
3534
+ this.instanceCounter.update(c => c + 1);
3535
+ return `${componentType}-instance-${counter}-${Date.now()}`;
3525
3536
  }
3526
- /**
3527
- * Get human-readable key description
3528
- */
3529
- getKeyDescription(shortcut) {
3530
- const modifiers = [];
3531
- if (shortcut.ctrlKey)
3532
- modifiers.push('Ctrl');
3533
- if (shortcut.altKey)
3534
- modifiers.push('Alt');
3535
- if (shortcut.shiftKey)
3536
- modifiers.push('Shift');
3537
- if (shortcut.metaKey)
3538
- modifiers.push('Meta');
3539
- return [...modifiers, shortcut.key].join(' + ');
3537
+ // Multiple instance management methods
3538
+ getInstancesByComponentType(componentType) {
3539
+ return Array.from(this.containers().values())
3540
+ .filter(container => container.componentType === componentType);
3540
3541
  }
3541
- /**
3542
- * Get key description for a shortcut ID
3543
- */
3544
- getKeyDescriptionForShortcut(shortcutId) {
3545
- const shortcut = this.shortcuts.get(shortcutId);
3546
- if (!shortcut)
3547
- return 'Not found';
3548
- const override = this.overrides.get(shortcutId);
3549
- if (override) {
3550
- return this.getKeyDescription({
3551
- key: override.newKey,
3552
- ctrlKey: override.newCtrlKey,
3553
- altKey: override.newAltKey,
3554
- shiftKey: override.newShiftKey,
3555
- metaKey: override.newMetaKey
3556
- });
3557
- }
3558
- return this.getKeyDescription(shortcut);
3542
+ getActiveInstancesByComponentType(componentType) {
3543
+ return Array.from(this.containers().values())
3544
+ .filter(container => container.componentType === componentType && container.isVisible);
3559
3545
  }
3560
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: KeyboardShortcutService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3561
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: KeyboardShortcutService, providedIn: 'root' });
3562
- }
3563
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: KeyboardShortcutService, decorators: [{
3564
- type: Injectable,
3565
- args: [{
3566
- providedIn: 'root'
3567
- }]
3568
- }], ctorParameters: () => [] });
3569
-
3570
- class FloatingContainerShortcutsService {
3571
- keyboardShortcutService = inject(KeyboardShortcutService);
3572
- containerService = inject(CideEleFloatingContainerService);
3573
- // Z-index layers for different container states
3574
- Z_INDEX_LAYERS = {
3575
- HIDDEN: 100, // Hidden containers (behind everything)
3576
- BACKGROUND: 1000, // Background containers
3577
- NORMAL: 2000, // Normal visible containers
3578
- FOCUSED: 3000, // Focused containers
3579
- MODAL: 4000, // Modal containers
3580
- TOOLTIP: 5000 // Tooltips and overlays
3581
- };
3582
- constructor() {
3583
- this.registerDefaultShortcuts();
3546
+ getInstanceCount(componentType) {
3547
+ return this.getInstancesByComponentType(componentType).length;
3584
3548
  }
3585
- /**
3586
- * Register default floating container shortcuts
3587
- */
3588
- registerDefaultShortcuts() {
3589
- console.log('🎯 [FloatingContainerShortcuts] Registering default shortcuts');
3590
- // Alt + 1, Alt + 2, etc. - Focus specific containers
3591
- this.registerNumberShortcuts();
3592
- // Alt + N - New container
3593
- this.keyboardShortcutService.register({
3594
- id: 'floating-container-new',
3595
- key: 'n',
3596
- altKey: true,
3597
- description: 'Create new floating container',
3598
- action: () => this.openNewContainer(),
3599
- preventDefault: true
3600
- });
3601
- // Alt + P - Previous container
3602
- this.keyboardShortcutService.register({
3603
- id: 'floating-container-previous',
3604
- key: 'p',
3605
- altKey: true,
3606
- description: 'Focus previous container',
3607
- action: () => this.focusPreviousContainer(),
3608
- preventDefault: true
3609
- });
3610
- // Alt + H - Hide all containers
3611
- this.keyboardShortcutService.register({
3612
- id: 'floating-container-hide-all',
3613
- key: 'h',
3614
- altKey: true,
3615
- description: 'Hide all containers',
3616
- action: () => this.hideAllContainers(),
3617
- preventDefault: true
3618
- });
3619
- // Alt + S - Show all containers
3620
- this.keyboardShortcutService.register({
3621
- id: 'floating-container-show-all',
3622
- key: 's',
3623
- altKey: true,
3624
- description: 'Show all containers',
3625
- action: () => this.showAllContainers(),
3626
- preventDefault: true
3627
- });
3628
- // Alt + M - Minimize all containers
3629
- this.keyboardShortcutService.register({
3630
- id: 'floating-container-minimize-all',
3631
- key: 'm',
3632
- altKey: true,
3633
- description: 'Minimize all containers',
3634
- action: () => this.minimizeAllContainers(),
3635
- preventDefault: true
3636
- });
3637
- // Alt + W - Close current container
3638
- this.keyboardShortcutService.register({
3639
- id: 'floating-container-close-current',
3640
- key: 'w',
3641
- altKey: true,
3642
- description: 'Close current container',
3643
- action: () => this.closeCurrentContainer(),
3644
- preventDefault: true
3645
- });
3646
- // Alt + D - Duplicate current container
3647
- this.keyboardShortcutService.register({
3648
- id: 'floating-container-duplicate',
3649
- key: 'd',
3650
- altKey: true,
3651
- description: 'Duplicate current container',
3652
- action: () => this.duplicateCurrentContainer(),
3653
- preventDefault: true
3549
+ getActiveInstanceCount(componentType) {
3550
+ return this.getActiveInstancesByComponentType(componentType).length;
3551
+ }
3552
+ // Close all instances of a component type
3553
+ closeAllInstancesOfType(componentType) {
3554
+ const instances = this.getInstancesByComponentType(componentType);
3555
+ instances.forEach(instance => {
3556
+ this.hide(instance.id);
3654
3557
  });
3655
- // Alt + T - Toggle container visibility
3656
- this.keyboardShortcutService.register({
3657
- id: 'floating-container-toggle-visibility',
3658
- key: 't',
3659
- altKey: true,
3660
- description: 'Toggle container visibility',
3661
- action: () => this.toggleContainerVisibility(),
3662
- preventDefault: true
3558
+ }
3559
+ // Minimize all instances of a component type
3560
+ minimizeAllInstancesOfType(componentType) {
3561
+ const instances = this.getActiveInstancesByComponentType(componentType);
3562
+ instances.forEach(instance => {
3563
+ this.minimize(instance.id);
3663
3564
  });
3664
- // Alt + O - Open file uploader
3665
- this.keyboardShortcutService.register({
3666
- id: 'floating-container-open-file-uploader',
3667
- key: 'o',
3668
- altKey: true,
3669
- description: 'Open file uploader',
3670
- action: () => this.openFileUploader(),
3671
- preventDefault: true
3565
+ }
3566
+ // Bring all instances of a component type to front
3567
+ bringAllInstancesToFront(componentType) {
3568
+ const instances = this.getActiveInstancesByComponentType(componentType);
3569
+ instances.forEach(instance => {
3570
+ this.bringToFront(instance.id);
3672
3571
  });
3673
- // Alt + R - Open entity rights sharing
3674
- this.keyboardShortcutService.register({
3675
- id: 'floating-container-open-entity-rights',
3676
- key: 'r',
3677
- altKey: true,
3678
- description: 'Open entity rights sharing',
3679
- action: () => this.openEntityRightsSharing(),
3680
- preventDefault: true
3572
+ }
3573
+ // Get instance by unique instance ID
3574
+ getInstanceByInstanceId(instanceId) {
3575
+ return Array.from(this.containers().values())
3576
+ .find(container => container.instanceId === instanceId);
3577
+ }
3578
+ // Update last accessed time
3579
+ updateLastAccessed(containerId) {
3580
+ this.containers.update(containers => {
3581
+ const newContainers = new Map(containers);
3582
+ const container = newContainers.get(containerId);
3583
+ if (container) {
3584
+ container.lastAccessed = new Date();
3585
+ newContainers.set(containerId, container);
3586
+ }
3587
+ return newContainers;
3681
3588
  });
3682
- console.log('✅ [FloatingContainerShortcuts] Default shortcuts registered');
3683
3589
  }
3590
+ // ===== DYNAMIC COMPONENT MANAGEMENT =====
3684
3591
  /**
3685
- * Register number shortcuts (Alt + 1, Alt + 2, etc.)
3592
+ * Register a component for dynamic loading
3686
3593
  */
3687
- registerNumberShortcuts() {
3688
- for (let i = 1; i <= 9; i++) {
3689
- this.keyboardShortcutService.register({
3690
- id: `floating-container-focus-${i}`,
3691
- key: i.toString(),
3692
- altKey: true,
3693
- description: `Focus container ${i}`,
3694
- action: () => this.focusContainerByIndex(i - 1),
3695
- preventDefault: true
3696
- });
3697
- }
3594
+ registerComponent(componentId, componentType) {
3595
+ this.componentRegistry.set(componentId, componentType);
3698
3596
  }
3699
3597
  /**
3700
- * Open new floating container
3598
+ * Unregister a component
3701
3599
  */
3702
- openNewContainer() {
3703
- console.log('🎯 [FloatingContainerShortcuts] Opening new container');
3704
- const containerId = this.containerService.show({
3705
- id: 'new-container-' + Date.now(),
3706
- title: 'New Container',
3707
- width: '400px',
3708
- height: '300px'
3709
- });
3710
- console.log('✅ [FloatingContainerShortcuts] New container created:', containerId);
3600
+ unregisterComponent(componentId) {
3601
+ this.componentRegistry.delete(componentId);
3711
3602
  }
3712
3603
  /**
3713
- * Focus previous container
3604
+ * Get registered component type
3714
3605
  */
3715
- focusPreviousContainer() {
3716
- console.log('🎯 [FloatingContainerShortcuts] Focusing previous container');
3717
- const containers = this.containerService.visibleContainers();
3718
- if (containers.length > 0) {
3719
- // For now, just focus the last container
3720
- const previousIndex = containers.length - 1;
3721
- this.containerService.bringToFront(containers[previousIndex].id);
3722
- }
3606
+ getComponentType(componentId) {
3607
+ return this.componentRegistry.get(componentId);
3723
3608
  }
3724
3609
  /**
3725
- * Hide all containers
3610
+ * Check if component is registered
3726
3611
  */
3727
- hideAllContainers() {
3728
- console.log('🎯 [FloatingContainerShortcuts] Hiding all containers');
3729
- const containers = this.containerService.visibleContainers();
3730
- containers.forEach(container => {
3731
- this.containerService.setZIndex(container.id, this.Z_INDEX_LAYERS.HIDDEN);
3732
- });
3733
- console.log('✅ [FloatingContainerShortcuts] All containers hidden');
3612
+ isComponentRegistered(componentId) {
3613
+ return this.componentRegistry.has(componentId);
3734
3614
  }
3735
3615
  /**
3736
- * Show all containers
3616
+ * Get registered component IDs
3737
3617
  */
3738
- showAllContainers() {
3739
- console.log('🎯 [FloatingContainerShortcuts] Showing all containers');
3740
- const containers = this.containerService.visibleContainers();
3741
- containers.forEach((container, index) => {
3742
- this.containerService.setZIndex(container.id, this.Z_INDEX_LAYERS.NORMAL + index);
3743
- });
3744
- console.log('✅ [FloatingContainerShortcuts] All containers shown');
3618
+ getRegisteredComponentIds() {
3619
+ return Array.from(this.componentRegistry.keys());
3745
3620
  }
3746
3621
  /**
3747
- * Minimize all containers
3622
+ * Create and load component dynamically
3748
3623
  */
3749
- minimizeAllContainers() {
3750
- console.log('🎯 [FloatingContainerShortcuts] Minimizing all containers');
3751
- const containers = this.containerService.visibleContainers();
3752
- containers.forEach(container => {
3753
- // Implement minimize logic here
3754
- console.log('📦 [FloatingContainerShortcuts] Minimizing container:', container.id);
3755
- });
3756
- console.log('✅ [FloatingContainerShortcuts] All containers minimized');
3624
+ loadComponent(componentId, viewContainer, config) {
3625
+ const componentType = this.componentRegistry.get(componentId);
3626
+ if (!componentType) {
3627
+ return null;
3628
+ }
3629
+ try {
3630
+ viewContainer.clear();
3631
+ const componentRef = viewContainer.createComponent(componentType, {
3632
+ injector: this.injector
3633
+ });
3634
+ // Set inputs if provided
3635
+ if (config?.inputs) {
3636
+ Object.keys(config.inputs).forEach(key => {
3637
+ if (componentRef.instance && typeof componentRef.instance === 'object' && key in componentRef.instance) {
3638
+ componentRef.instance[key] = config.inputs[key];
3639
+ }
3640
+ });
3641
+ }
3642
+ // Set outputs if provided
3643
+ if (config?.outputs) {
3644
+ Object.keys(config.outputs).forEach(key => {
3645
+ if (componentRef.instance && typeof componentRef.instance === 'object' && key in componentRef.instance) {
3646
+ const output = componentRef.instance[key];
3647
+ if (output && typeof output.subscribe === 'function') {
3648
+ output.subscribe(config.outputs[key]);
3649
+ }
3650
+ }
3651
+ });
3652
+ }
3653
+ this.activeComponents.set(componentId, componentRef);
3654
+ return componentRef;
3655
+ }
3656
+ catch (error) {
3657
+ return null;
3658
+ }
3757
3659
  }
3758
3660
  /**
3759
- * Focus container by index
3661
+ * Destroy component
3760
3662
  */
3761
- focusContainerByIndex(index) {
3762
- console.log('🎯 [FloatingContainerShortcuts] Focusing container at index:', index);
3763
- const containers = this.containerService.visibleContainers();
3764
- if (containers[index]) {
3765
- this.containerService.bringToFront(containers[index].id);
3766
- console.log('✅ [FloatingContainerShortcuts] Container focused:', containers[index].id);
3767
- }
3768
- else {
3769
- console.warn('⚠️ [FloatingContainerShortcuts] Container not found at index:', index);
3663
+ destroyComponent(componentId) {
3664
+ const componentRef = this.activeComponents.get(componentId);
3665
+ if (componentRef) {
3666
+ componentRef.destroy();
3667
+ this.activeComponents.delete(componentId);
3770
3668
  }
3771
3669
  }
3772
3670
  /**
3773
- * Open file uploader
3671
+ * Get active component count
3774
3672
  */
3775
- openFileUploader() {
3776
- console.log('🎯 [FloatingContainerShortcuts] Opening file uploader');
3777
- // Implement file uploader opening logic here
3778
- console.log('✅ [FloatingContainerShortcuts] File uploader opened');
3673
+ getActiveComponentCount() {
3674
+ return this.activeComponents.size;
3779
3675
  }
3780
3676
  /**
3781
- * Open entity rights sharing
3677
+ * Clear all active components
3782
3678
  */
3783
- openEntityRightsSharing() {
3784
- console.log('🎯 [FloatingContainerShortcuts] Opening entity rights sharing');
3785
- // Implement entity rights sharing opening logic here
3786
- console.log('✅ [FloatingContainerShortcuts] Entity rights sharing opened');
3679
+ clearActiveComponents() {
3680
+ this.activeComponents.forEach(componentRef => componentRef.destroy());
3681
+ this.activeComponents.clear();
3787
3682
  }
3683
+ // ===== CONTAINER MANAGER FUNCTIONALITY =====
3788
3684
  /**
3789
- * Duplicate current container
3685
+ * Get config signal for a container
3790
3686
  */
3791
- duplicateCurrentContainer() {
3792
- console.log('🎯 [FloatingContainerShortcuts] Duplicating current container');
3793
- const containers = this.containerService.visibleContainers();
3794
- if (containers.length > 0) {
3795
- const containerToDuplicate = containers[containers.length - 1]; // Use last container
3796
- const newContainerId = this.containerService.show({
3797
- id: 'duplicate-' + Date.now(),
3798
- title: `${containerToDuplicate.config.title} (Copy)`,
3799
- width: containerToDuplicate.config.width,
3800
- height: containerToDuplicate.config.height
3801
- });
3802
- console.log('✅ [FloatingContainerShortcuts] Container duplicated:', newContainerId);
3803
- }
3804
- else {
3805
- console.warn('⚠️ [FloatingContainerShortcuts] No container to duplicate');
3806
- }
3687
+ getConfigSignal(config) {
3688
+ return signal(config);
3807
3689
  }
3808
3690
  /**
3809
- * Close current container
3691
+ * Get minimized signal for a container
3810
3692
  */
3811
- closeCurrentContainer() {
3812
- console.log('🎯 [FloatingContainerShortcuts] Closing current container');
3813
- const containers = this.containerService.visibleContainers();
3814
- if (containers.length > 0) {
3815
- const containerToClose = containers[containers.length - 1]; // Use last container
3816
- this.containerService.hide(containerToClose.id);
3817
- console.log('✅ [FloatingContainerShortcuts] Container closed:', containerToClose.id);
3818
- }
3819
- else {
3820
- console.warn('⚠️ [FloatingContainerShortcuts] No container to close');
3821
- }
3693
+ getMinimizedSignal(containerId) {
3694
+ return computed(() => {
3695
+ const container = this.getContainer(containerId);
3696
+ return container?.isMinimized || false;
3697
+ });
3822
3698
  }
3823
3699
  /**
3824
- * Toggle container visibility
3700
+ * Get maximized signal for a container
3825
3701
  */
3826
- toggleContainerVisibility() {
3827
- console.log('🎯 [FloatingContainerShortcuts] Toggling container visibility');
3828
- const containers = this.containerService.visibleContainers();
3829
- if (containers.length > 0) {
3830
- const containerToToggle = containers[containers.length - 1]; // Use last container
3831
- const currentZIndex = this.containerService.getZIndexSignal(containerToToggle.id)();
3832
- if (currentZIndex === this.Z_INDEX_LAYERS.HIDDEN) {
3833
- this.containerService.setZIndex(containerToToggle.id, this.Z_INDEX_LAYERS.NORMAL);
3834
- console.log('✅ [FloatingContainerShortcuts] Container shown:', containerToToggle.id);
3835
- }
3836
- else {
3837
- this.containerService.setZIndex(containerToToggle.id, this.Z_INDEX_LAYERS.HIDDEN);
3838
- console.log('✅ [FloatingContainerShortcuts] Container hidden:', containerToToggle.id);
3839
- }
3840
- }
3841
- else {
3842
- console.warn('⚠️ [FloatingContainerShortcuts] No container to toggle');
3843
- }
3844
- }
3845
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FloatingContainerShortcutsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3846
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FloatingContainerShortcutsService, providedIn: 'root' });
3847
- }
3848
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FloatingContainerShortcutsService, decorators: [{
3849
- type: Injectable,
3850
- args: [{
3851
- providedIn: 'root'
3852
- }]
3853
- }], ctorParameters: () => [] });
3854
-
3855
- class CideEleFloatingContainerService {
3856
- injector;
3857
- shortcutsService;
3858
- containers = signal(new Map(), ...(ngDevMode ? [{ debugName: "containers" }] : []));
3859
- nextZIndex = signal(1000, ...(ngDevMode ? [{ debugName: "nextZIndex" }] : []));
3860
- instanceCounter = signal(0, ...(ngDevMode ? [{ debugName: "instanceCounter" }] : []));
3861
- // Dynamic component management
3862
- componentRegistry = new Map();
3863
- activeComponents = new Map();
3864
- constructor(injector, shortcutsService) {
3865
- this.injector = injector;
3866
- this.shortcutsService = shortcutsService;
3867
- // Keyboard shortcuts are automatically registered by FloatingContainerShortcutsService
3868
- console.log('🎯 [FloatingContainerService] Shortcuts service injected and shortcuts registered');
3869
- }
3870
- // Computed properties
3871
- visibleContainers = computed(() => Array.from(this.containers().values()).filter(container => container.isVisible), ...(ngDevMode ? [{ debugName: "visibleContainers" }] : []));
3872
- minimizedContainers = computed(() => Array.from(this.containers().values()).filter(container => container.isMinimized), ...(ngDevMode ? [{ debugName: "minimizedContainers" }] : []));
3873
- maximizedContainers = computed(() => Array.from(this.containers().values()).filter(container => container.isMaximized), ...(ngDevMode ? [{ debugName: "maximizedContainers" }] : []));
3874
- // Container management methods
3875
- show(config) {
3876
- const containerId = config.id || this.generateId();
3877
- const instanceId = this.generateInstanceId(config.componentId || 'default');
3878
- // Get the highest z-index and add 1 to bring new container to front
3879
- const maxZIndex = this.getMaxZIndex();
3880
- const zIndex = maxZIndex + 1;
3881
- const now = new Date();
3882
- const container = {
3883
- id: containerId,
3884
- config: { ...config, id: containerId },
3885
- isVisible: true,
3886
- isMinimized: false,
3887
- isMaximized: false,
3888
- zIndex,
3889
- instanceId,
3890
- componentType: config.componentId || 'default',
3891
- createdAt: now,
3892
- lastAccessed: now
3893
- };
3894
- this.containers.update(containers => {
3895
- const newContainers = new Map(containers);
3896
- newContainers.set(containerId, container);
3897
- return newContainers;
3702
+ getMaximizedSignal(containerId) {
3703
+ return computed(() => {
3704
+ const container = this.getContainer(containerId);
3705
+ return container?.isMaximized || false;
3898
3706
  });
3899
- this.nextZIndex.update(z => z + 1);
3900
- return containerId;
3901
3707
  }
3902
- hide(containerId) {
3903
- this.containers.update(containers => {
3904
- const newContainers = new Map(containers);
3905
- const container = newContainers.get(containerId);
3906
- if (container) {
3907
- container.isVisible = false;
3908
- newContainers.set(containerId, container);
3909
- }
3910
- return newContainers;
3708
+ getZIndexSignal(containerId) {
3709
+ return computed(() => {
3710
+ const container = this.getContainer(containerId);
3711
+ const zIndex = container?.zIndex || 1000;
3712
+ console.log(`🎯 [FloatingContainer] Z-index signal for '${containerId}': ${zIndex}`);
3713
+ return zIndex;
3911
3714
  });
3912
3715
  }
3913
3716
  /**
3914
- * Get the maximum z-index among all visible containers
3915
- */
3916
- getMaxZIndex() {
3917
- const containers = this.containers();
3918
- let maxZIndex = 1000; // Base z-index
3919
- for (const container of containers.values()) {
3920
- if (container.isVisible && container.zIndex > maxZIndex) {
3921
- maxZIndex = container.zIndex;
3922
- }
3923
- }
3924
- return maxZIndex;
3925
- }
3926
- /**
3927
- * Bring a container to the front (highest z-index)
3717
+ * Set z-index for a specific container
3928
3718
  */
3929
- bringToFront(containerId) {
3930
- const maxZIndex = this.getMaxZIndex();
3931
- const newZIndex = maxZIndex + 1;
3932
- console.log(`🎯 [FloatingContainer] Bringing container '${containerId}' to front`);
3933
- console.log(`🎯 [FloatingContainer] Current max z-index: ${maxZIndex}, new z-index: ${newZIndex}`);
3719
+ setZIndex(containerId, zIndex) {
3720
+ console.log(`🎯 [FloatingContainer] Setting z-index for '${containerId}' to ${zIndex}`);
3934
3721
  this.containers.update(containers => {
3935
3722
  const newContainers = new Map(containers);
3936
3723
  const container = newContainers.get(containerId);
3937
3724
  if (container) {
3938
3725
  const oldZIndex = container.zIndex;
3939
- container.zIndex = newZIndex;
3726
+ container.zIndex = zIndex;
3940
3727
  container.lastAccessed = new Date();
3941
3728
  newContainers.set(containerId, container);
3942
- console.log(`🎯 [FloatingContainer] Container '${containerId}' z-index updated: ${oldZIndex} → ${newZIndex}`);
3729
+ console.log(`🎯 [FloatingContainer] Container '${containerId}' z-index updated: ${oldZIndex} → ${zIndex}`);
3943
3730
  }
3944
3731
  else {
3945
- console.warn(`⚠️ [FloatingContainer] Container '${containerId}' not found!`);
3946
- }
3947
- return newContainers;
3948
- });
3949
- }
3950
- minimize(containerId) {
3951
- this.containers.update(containers => {
3952
- const newContainers = new Map(containers);
3953
- const container = newContainers.get(containerId);
3954
- if (container) {
3955
- container.isMinimized = !container.isMinimized;
3956
- newContainers.set(containerId, container);
3957
- }
3958
- return newContainers;
3959
- });
3960
- }
3961
- maximize(containerId) {
3962
- this.containers.update(containers => {
3963
- const newContainers = new Map(containers);
3964
- const container = newContainers.get(containerId);
3965
- if (container) {
3966
- container.isMaximized = !container.isMaximized;
3967
- newContainers.set(containerId, container);
3968
- }
3969
- return newContainers;
3970
- });
3971
- }
3972
- getContainer(containerId) {
3973
- return this.containers().get(containerId);
3974
- }
3975
- isVisible(containerId) {
3976
- const container = this.getContainer(containerId);
3977
- return container ? container.isVisible : false;
3978
- }
3979
- isMinimized(containerId) {
3980
- const container = this.getContainer(containerId);
3981
- return container ? container.isMinimized : false;
3982
- }
3983
- isMaximized(containerId) {
3984
- const container = this.getContainer(containerId);
3985
- return container ? container.isMaximized : false;
3986
- }
3987
- hideAll() {
3988
- this.containers.update(containers => {
3989
- const newContainers = new Map(containers);
3990
- for (const [id, container] of newContainers) {
3991
- container.isVisible = false;
3992
- newContainers.set(id, container);
3993
- }
3994
- return newContainers;
3995
- });
3996
- }
3997
- minimizeAll() {
3998
- this.containers.update(containers => {
3999
- const newContainers = new Map(containers);
4000
- for (const [id, container] of newContainers) {
4001
- if (container.isVisible) {
4002
- container.isMinimized = true;
4003
- newContainers.set(id, container);
4004
- }
4005
- }
4006
- return newContainers;
4007
- });
4008
- }
4009
- generateId() {
4010
- return `floating-container-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
4011
- }
4012
- generateInstanceId(componentType) {
4013
- const counter = this.instanceCounter() + 1;
4014
- this.instanceCounter.update(c => c + 1);
4015
- return `${componentType}-instance-${counter}-${Date.now()}`;
4016
- }
4017
- // Multiple instance management methods
4018
- getInstancesByComponentType(componentType) {
4019
- return Array.from(this.containers().values())
4020
- .filter(container => container.componentType === componentType);
4021
- }
4022
- getActiveInstancesByComponentType(componentType) {
4023
- return Array.from(this.containers().values())
4024
- .filter(container => container.componentType === componentType && container.isVisible);
4025
- }
4026
- getInstanceCount(componentType) {
4027
- return this.getInstancesByComponentType(componentType).length;
4028
- }
4029
- getActiveInstanceCount(componentType) {
4030
- return this.getActiveInstancesByComponentType(componentType).length;
4031
- }
4032
- // Close all instances of a component type
4033
- closeAllInstancesOfType(componentType) {
4034
- const instances = this.getInstancesByComponentType(componentType);
4035
- instances.forEach(instance => {
4036
- this.hide(instance.id);
4037
- });
4038
- }
4039
- // Minimize all instances of a component type
4040
- minimizeAllInstancesOfType(componentType) {
4041
- const instances = this.getActiveInstancesByComponentType(componentType);
4042
- instances.forEach(instance => {
4043
- this.minimize(instance.id);
4044
- });
4045
- }
4046
- // Bring all instances of a component type to front
4047
- bringAllInstancesToFront(componentType) {
4048
- const instances = this.getActiveInstancesByComponentType(componentType);
4049
- instances.forEach(instance => {
4050
- this.bringToFront(instance.id);
4051
- });
4052
- }
4053
- // Get instance by unique instance ID
4054
- getInstanceByInstanceId(instanceId) {
4055
- return Array.from(this.containers().values())
4056
- .find(container => container.instanceId === instanceId);
4057
- }
4058
- // Update last accessed time
4059
- updateLastAccessed(containerId) {
4060
- this.containers.update(containers => {
4061
- const newContainers = new Map(containers);
4062
- const container = newContainers.get(containerId);
4063
- if (container) {
4064
- container.lastAccessed = new Date();
4065
- newContainers.set(containerId, container);
4066
- }
4067
- return newContainers;
4068
- });
4069
- }
4070
- // ===== DYNAMIC COMPONENT MANAGEMENT =====
4071
- /**
4072
- * Register a component for dynamic loading
4073
- */
4074
- registerComponent(componentId, componentType) {
4075
- this.componentRegistry.set(componentId, componentType);
4076
- }
4077
- /**
4078
- * Unregister a component
4079
- */
4080
- unregisterComponent(componentId) {
4081
- this.componentRegistry.delete(componentId);
4082
- }
4083
- /**
4084
- * Get registered component type
4085
- */
4086
- getComponentType(componentId) {
4087
- return this.componentRegistry.get(componentId);
4088
- }
4089
- /**
4090
- * Check if component is registered
4091
- */
4092
- isComponentRegistered(componentId) {
4093
- return this.componentRegistry.has(componentId);
4094
- }
4095
- /**
4096
- * Get registered component IDs
4097
- */
4098
- getRegisteredComponentIds() {
4099
- return Array.from(this.componentRegistry.keys());
4100
- }
4101
- /**
4102
- * Create and load component dynamically
4103
- */
4104
- loadComponent(componentId, viewContainer, config) {
4105
- const componentType = this.componentRegistry.get(componentId);
4106
- if (!componentType) {
4107
- return null;
4108
- }
4109
- try {
4110
- viewContainer.clear();
4111
- const componentRef = viewContainer.createComponent(componentType, {
4112
- injector: this.injector
4113
- });
4114
- // Set inputs if provided
4115
- if (config?.inputs) {
4116
- Object.keys(config.inputs).forEach(key => {
4117
- if (componentRef.instance && typeof componentRef.instance === 'object' && key in componentRef.instance) {
4118
- componentRef.instance[key] = config.inputs[key];
4119
- }
4120
- });
4121
- }
4122
- // Set outputs if provided
4123
- if (config?.outputs) {
4124
- Object.keys(config.outputs).forEach(key => {
4125
- if (componentRef.instance && typeof componentRef.instance === 'object' && key in componentRef.instance) {
4126
- const output = componentRef.instance[key];
4127
- if (output && typeof output.subscribe === 'function') {
4128
- output.subscribe(config.outputs[key]);
4129
- }
4130
- }
4131
- });
4132
- }
4133
- this.activeComponents.set(componentId, componentRef);
4134
- return componentRef;
4135
- }
4136
- catch (error) {
4137
- return null;
4138
- }
4139
- }
4140
- /**
4141
- * Destroy component
4142
- */
4143
- destroyComponent(componentId) {
4144
- const componentRef = this.activeComponents.get(componentId);
4145
- if (componentRef) {
4146
- componentRef.destroy();
4147
- this.activeComponents.delete(componentId);
4148
- }
4149
- }
4150
- /**
4151
- * Get active component count
4152
- */
4153
- getActiveComponentCount() {
4154
- return this.activeComponents.size;
4155
- }
4156
- /**
4157
- * Clear all active components
4158
- */
4159
- clearActiveComponents() {
4160
- this.activeComponents.forEach(componentRef => componentRef.destroy());
4161
- this.activeComponents.clear();
4162
- }
4163
- // ===== CONTAINER MANAGER FUNCTIONALITY =====
4164
- /**
4165
- * Get config signal for a container
4166
- */
4167
- getConfigSignal(config) {
4168
- return signal(config);
4169
- }
4170
- /**
4171
- * Get minimized signal for a container
4172
- */
4173
- getMinimizedSignal(containerId) {
4174
- return computed(() => {
4175
- const container = this.getContainer(containerId);
4176
- return container?.isMinimized || false;
4177
- });
4178
- }
4179
- /**
4180
- * Get maximized signal for a container
4181
- */
4182
- getMaximizedSignal(containerId) {
4183
- return computed(() => {
4184
- const container = this.getContainer(containerId);
4185
- return container?.isMaximized || false;
4186
- });
4187
- }
4188
- getZIndexSignal(containerId) {
4189
- return computed(() => {
4190
- const container = this.getContainer(containerId);
4191
- const zIndex = container?.zIndex || 1000;
4192
- console.log(`🎯 [FloatingContainer] Z-index signal for '${containerId}': ${zIndex}`);
4193
- return zIndex;
4194
- });
4195
- }
4196
- /**
4197
- * Set z-index for a specific container
4198
- */
4199
- setZIndex(containerId, zIndex) {
4200
- console.log(`🎯 [FloatingContainer] Setting z-index for '${containerId}' to ${zIndex}`);
4201
- this.containers.update(containers => {
4202
- const newContainers = new Map(containers);
4203
- const container = newContainers.get(containerId);
4204
- if (container) {
4205
- const oldZIndex = container.zIndex;
4206
- container.zIndex = zIndex;
4207
- container.lastAccessed = new Date();
4208
- newContainers.set(containerId, container);
4209
- console.log(`🎯 [FloatingContainer] Container '${containerId}' z-index updated: ${oldZIndex} → ${zIndex}`);
4210
- }
4211
- else {
4212
- console.warn(`⚠️ [FloatingContainer] Container '${containerId}' not found for z-index update!`);
3732
+ console.warn(`⚠️ [FloatingContainer] Container '${containerId}' not found for z-index update!`);
4213
3733
  }
4214
3734
  return newContainers;
4215
3735
  });
@@ -4254,7 +3774,7 @@ class CideEleFloatingContainerService {
4254
3774
  onMaximize(containerId) {
4255
3775
  this.maximize(containerId);
4256
3776
  }
4257
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleFloatingContainerService, deps: [{ token: i0.Injector }, { token: FloatingContainerShortcutsService }], target: i0.ɵɵFactoryTarget.Injectable });
3777
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleFloatingContainerService, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
4258
3778
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleFloatingContainerService, providedIn: 'root' });
4259
3779
  }
4260
3780
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleFloatingContainerService, decorators: [{
@@ -4262,7 +3782,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
4262
3782
  args: [{
4263
3783
  providedIn: 'root'
4264
3784
  }]
4265
- }], ctorParameters: () => [{ type: i0.Injector }, { type: FloatingContainerShortcutsService }] });
3785
+ }], ctorParameters: () => [{ type: i0.Injector }] });
4266
3786
 
4267
3787
  class CideEleFloatingFileUploaderService {
4268
3788
  containerService = inject(CideEleFloatingContainerService);
@@ -5468,6 +4988,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
5468
4988
  class CideEleFloatingFileUploaderComponent {
5469
4989
  destroyRef = inject(DestroyRef);
5470
4990
  fileManagerService = inject(CideEleFileManagerService);
4991
+ fileInputRef;
5471
4992
  // Input data from floating container
5472
4993
  data = {};
5473
4994
  // Signals for reactive state (simplified for floating container)
@@ -5863,10 +5384,8 @@ class CideEleFloatingFileUploaderComponent {
5863
5384
  * Trigger file input click
5864
5385
  */
5865
5386
  triggerFileInput() {
5866
- // Use ViewChild or querySelector with specific selector to target only this component's file input
5867
- const fileInput = document.querySelector('.floating-uploader input[type="file"]');
5868
- if (fileInput) {
5869
- fileInput.click();
5387
+ if (this.fileInputRef?.nativeElement) {
5388
+ this.fileInputRef.nativeElement.click();
5870
5389
  }
5871
5390
  }
5872
5391
  /**
@@ -5899,15 +5418,18 @@ class CideEleFloatingFileUploaderComponent {
5899
5418
  });
5900
5419
  }
5901
5420
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleFloatingFileUploaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5902
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideEleFloatingFileUploaderComponent, isStandalone: true, selector: "cide-ele-floating-file-uploader", inputs: { data: "data" }, ngImport: i0, template: "<!-- File Uploader Content (No absolute positioning - works within floating container) -->\n@if (isVisible()) {\n<div class=\"tw-w-full tw-h-full tw-overflow-hidden\">\n <!-- Content starts directly - no header needed since floating container provides it -->\n\n <!-- Content -->\n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-4\">\n \n <!-- Drag and Drop Zone -->\n <div class=\"tw-mb-4 tw-p-6 tw-border-2 tw-border-dashed tw-border-gray-300 tw-rounded-lg tw-bg-gray-50 tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-center hover:tw-border-blue-500 hover:tw-bg-blue-50\" \n [class.tw-border-blue-500]=\"isDragOver()\"\n [class.tw-bg-blue-100]=\"isDragOver()\"\n [class.tw-scale-105]=\"isDragOver()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\" \n (drop)=\"onDrop($event)\" \n (click)=\"triggerFileInput()\">\n \n <!-- Hidden file input -->\n <input #fileInput \n type=\"file\" \n [multiple]=\"data.multiple !== false\" \n [accept]=\"data.allowedFileTypes?.join(',') || '*/*'\" \n (change)=\"onFileInputChange($event)\" \n class=\"tw-hidden\">\n \n <div class=\"tw-flex tw-flex-col tw-items-center tw-gap-2\">\n <cide-ele-icon class=\"tw-text-gray-400 tw-transition-colors tw-duration-200\" \n [class.tw-text-blue-500]=\"isDragOver()\"\n size=\"sm\">cloud_upload</cide-ele-icon>\n \n <div>\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-700\">\n {{ isDragOver() ? 'Drop files here' : 'Drag files here or click to browse' }}\n </div>\n @if (data.description) {\n <div class=\"tw-text-xs tw-text-gray-500 tw-mt-1\">{{ data.description }}</div>\n }\n </div>\n </div>\n </div>\n \n <!-- Upload Queue - Show files from service state -->\n @if (allFilesForGroup().length > 0) {\n <div class=\"tw-space-y-2\">\n <!-- Show all files from service state -->\n @for (file of allFilesForGroup(); track file.fileId) {\n <div class=\"tw-flex tw-items-center tw-px-4 tw-py-3 tw-rounded-lg tw-transition-colors tw-duration-200\"\n [class.tw-bg-blue-50]=\"file.stage === 'uploading'\"\n [class.tw-bg-green-50]=\"file.stage === 'complete'\"\n [class.tw-bg-red-50]=\"file.stage === 'error'\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-flex-1 tw-min-w-0\">\n <cide-ele-icon class=\"tw-flex-shrink-0\" size=\"xs\">{{ getStatusIcon(file.stage) }}</cide-ele-icon>\n <div class=\"tw-min-w-0 tw-flex-1\">\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-truncate\">{{ file.fileName }}</div>\n <div class=\"tw-text-xs\">\n @switch (file.stage) {\n @case ('pending') {\n <span class=\"tw-text-yellow-600 tw-font-medium\">Waiting...</span>\n }\n @case ('reading') {\n <span class=\"tw-text-yellow-600 tw-font-medium\">Reading...</span>\n }\n @case ('uploading') {\n <span class=\"tw-text-blue-600 tw-font-medium\">Uploading...</span>\n }\n @case ('complete') {\n <span class=\"tw-text-green-600 tw-font-medium\">Completed</span>\n }\n @case ('error') {\n <span class=\"tw-text-red-600 tw-font-medium\">Failed</span>\n }\n }\n </div>\n </div>\n </div>\n\n <!-- Progress Bar (only for uploading files) -->\n @if (file.stage === 'uploading' && file.percentage !== undefined) {\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-ml-2 tw-min-w-[80px]\">\n <div class=\"tw-flex-1 tw-h-1 tw-bg-gray-200 tw-rounded-full tw-overflow-hidden\">\n <div class=\"tw-h-full tw-bg-blue-500 tw-transition-all tw-duration-300\" [style.width.%]=\"file.percentage\"></div>\n </div>\n <span class=\"tw-text-xs tw-text-gray-500 tw-min-w-[24px] tw-text-right\">{{ file.percentage }}%</span>\n </div>\n }\n\n <!-- Actions -->\n <div class=\"tw-flex tw-gap-1 tw-ml-2\">\n @switch (file.stage) {\n @case ('pending') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('reading') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('uploading') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('complete') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-text-green-600\" title=\"Completed\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n </button>\n }\n @case ('error') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-blue-50 hover:tw-text-blue-600\" \n title=\"Retry\">\n <cide-ele-icon size=\"xs\">refresh</cide-ele-icon>\n </button>\n }\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <!-- No uploads message when manually opened -->\n <div class=\"tw-py-8 tw-text-center tw-text-gray-500\">\n <div class=\"tw-flex tw-flex-col tw-items-center tw-gap-4\">\n <cide-ele-icon size=\"md\" class=\"tw-text-gray-300 tw-opacity-70\">cloud_upload</cide-ele-icon>\n <div>\n <h4 class=\"tw-text-lg tw-font-semibold tw-text-gray-700 tw-mb-2\">No active uploads</h4>\n <p class=\"tw-text-sm tw-text-gray-500\">Upload files to see their progress here</p>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Status summary - integrated into content -->\n @if (hasActiveUploads()) {\n <div class=\"tw-px-4 tw-py-2 tw-bg-gray-50\">\n <div class=\"tw-flex tw-gap-3 tw-text-xs\">\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-blue-600\">\n <cide-ele-icon size=\"xs\">upload</cide-ele-icon>\n <span>{{ getUploadingCount() }} uploading</span>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-green-600\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n <span>{{ getCompletedCount() }} completed</span>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-red-600\">\n <cide-ele-icon size=\"xs\">error</cide-ele-icon>\n <span>{{ getFailedCount() }} failed</span>\n </div>\n </div>\n </div>\n }\n</div>\n}", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }] });
5421
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.7", type: CideEleFloatingFileUploaderComponent, isStandalone: true, selector: "cide-ele-floating-file-uploader", inputs: { data: "data" }, viewQueries: [{ propertyName: "fileInputRef", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: "<!-- File Uploader Content (No absolute positioning - works within floating container) -->\n@if (isVisible()) {\n<div class=\"tw-w-full tw-h-full tw-overflow-hidden\">\n <!-- Content starts directly - no header needed since floating container provides it -->\n\n <!-- Content -->\n <div class=\"tw-flex-1 tw-overflow-y-auto\">\n \n <!-- Drag and Drop Zone -->\n <div class=\"tw-mb-4 tw-p-6 tw-border-2 tw-border-dashed tw-border-gray-300 tw-rounded-lg tw-bg-gray-50 tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-center hover:tw-border-blue-500 hover:tw-bg-blue-50\" \n [class.tw-border-blue-500]=\"isDragOver()\"\n [class.tw-bg-blue-100]=\"isDragOver()\"\n [class.tw-scale-105]=\"isDragOver()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\" \n (drop)=\"onDrop($event)\" \n (click)=\"triggerFileInput()\">\n \n <!-- Hidden file input -->\n <input #fileInput \n type=\"file\" \n [multiple]=\"data.multiple !== false\" \n [accept]=\"data.allowedFileTypes?.join(',') || '*/*'\" \n (change)=\"onFileInputChange($event)\" \n class=\"tw-hidden\">\n \n <div class=\"tw-flex tw-flex-col tw-items-center tw-gap-2\">\n <cide-ele-icon class=\"tw-text-gray-400 tw-transition-colors tw-duration-200\" \n [class.tw-text-blue-500]=\"isDragOver()\"\n size=\"sm\">cloud_upload</cide-ele-icon>\n \n <div>\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-700\">\n {{ isDragOver() ? 'Drop files here' : 'Drag files here or click to browse' }}\n </div>\n @if (data.description) {\n <div class=\"tw-text-xs tw-text-gray-500 tw-mt-1\">{{ data.description }}</div>\n }\n </div>\n </div>\n </div>\n \n <!-- Upload Queue - Show files from service state -->\n @if (allFilesForGroup().length > 0) {\n <div class=\"tw-space-y-2 tw-max-h-[60vh] tw-overflow-y-auto tw-pr-1\">\n <!-- Show all files from service state -->\n @for (file of allFilesForGroup(); track file.fileId) {\n <div class=\"tw-flex tw-items-center tw-px-4 tw-py-3 tw-rounded-lg tw-transition-colors tw-duration-200 hover:tw-bg-gray-100 hover:tw-shadow-sm\"\n [class.tw-bg-blue-50]=\"file.stage === 'uploading'\"\n [class.tw-bg-green-50]=\"file.stage === 'complete'\"\n [class.tw-bg-red-50]=\"file.stage === 'error'\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-flex-1 tw-min-w-0\">\n <cide-ele-icon class=\"tw-flex-shrink-0\" size=\"xs\">{{ getStatusIcon(file.stage) }}</cide-ele-icon>\n <div class=\"tw-min-w-0 tw-flex-1\">\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-truncate\">{{ file.fileName }}</div>\n <div class=\"tw-text-xs\">\n @switch (file.stage) {\n @case ('pending') {\n <span class=\"tw-text-yellow-600 tw-font-medium\">Waiting...</span>\n }\n @case ('reading') {\n <span class=\"tw-text-yellow-600 tw-font-medium\">Reading...</span>\n }\n @case ('uploading') {\n <span class=\"tw-text-blue-600 tw-font-medium\">Uploading...</span>\n }\n @case ('complete') {\n <span class=\"tw-text-green-600 tw-font-medium\">Completed</span>\n }\n @case ('error') {\n <span class=\"tw-text-red-600 tw-font-medium\">Failed</span>\n }\n }\n </div>\n </div>\n </div>\n\n <!-- Progress Bar (only for uploading files) -->\n @if (file.stage === 'uploading' && file.percentage !== undefined) {\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-ml-2 tw-min-w-[80px]\">\n <div class=\"tw-flex-1 tw-h-1 tw-bg-gray-200 tw-rounded-full tw-overflow-hidden\">\n <div class=\"tw-h-full tw-bg-blue-500 tw-transition-all tw-duration-300\" [style.width.%]=\"file.percentage\"></div>\n </div>\n <span class=\"tw-text-xs tw-text-gray-500 tw-min-w-[24px] tw-text-right\">{{ file.percentage }}%</span>\n </div>\n }\n\n <!-- Actions -->\n <div class=\"tw-flex tw-gap-1 tw-ml-2\">\n @switch (file.stage) {\n @case ('pending') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('reading') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('uploading') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('complete') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-text-green-600\" title=\"Completed\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n </button>\n }\n @case ('error') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-blue-50 hover:tw-text-blue-600\" \n title=\"Retry\">\n <cide-ele-icon size=\"xs\">refresh</cide-ele-icon>\n </button>\n }\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <!-- No uploads message when manually opened -->\n <div class=\"tw-py-8 tw-text-center tw-text-gray-500\">\n <div class=\"tw-flex tw-flex-col tw-items-center tw-gap-4\">\n <cide-ele-icon size=\"md\" class=\"tw-text-gray-300 tw-opacity-70\">cloud_upload</cide-ele-icon>\n <div>\n <h4 class=\"tw-text-lg tw-font-semibold tw-text-gray-700 tw-mb-2\">No active uploads</h4>\n <p class=\"tw-text-sm tw-text-gray-500\">Upload files to see their progress here</p>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Status summary - integrated into content -->\n @if (hasActiveUploads()) {\n <div class=\"tw-px-4 tw-py-2 tw-bg-gray-50\">\n <div class=\"tw-flex tw-gap-3 tw-text-xs\">\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-blue-600\">\n <cide-ele-icon size=\"xs\">upload</cide-ele-icon>\n <span>{{ getUploadingCount() }} uploading</span>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-green-600\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n <span>{{ getCompletedCount() }} completed</span>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-red-600\">\n <cide-ele-icon size=\"xs\">error</cide-ele-icon>\n <span>{{ getFailedCount() }} failed</span>\n </div>\n </div>\n </div>\n }\n</div>\n}", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideIconComponent, selector: "cide-ele-icon", inputs: ["size", "type", "toolTip"] }] });
5903
5422
  }
5904
5423
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: CideEleFloatingFileUploaderComponent, decorators: [{
5905
5424
  type: Component,
5906
5425
  args: [{ selector: 'cide-ele-floating-file-uploader', standalone: true, imports: [
5907
5426
  CommonModule,
5908
5427
  CideIconComponent
5909
- ], template: "<!-- File Uploader Content (No absolute positioning - works within floating container) -->\n@if (isVisible()) {\n<div class=\"tw-w-full tw-h-full tw-overflow-hidden\">\n <!-- Content starts directly - no header needed since floating container provides it -->\n\n <!-- Content -->\n <div class=\"tw-flex-1 tw-overflow-y-auto tw-p-4\">\n \n <!-- Drag and Drop Zone -->\n <div class=\"tw-mb-4 tw-p-6 tw-border-2 tw-border-dashed tw-border-gray-300 tw-rounded-lg tw-bg-gray-50 tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-center hover:tw-border-blue-500 hover:tw-bg-blue-50\" \n [class.tw-border-blue-500]=\"isDragOver()\"\n [class.tw-bg-blue-100]=\"isDragOver()\"\n [class.tw-scale-105]=\"isDragOver()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\" \n (drop)=\"onDrop($event)\" \n (click)=\"triggerFileInput()\">\n \n <!-- Hidden file input -->\n <input #fileInput \n type=\"file\" \n [multiple]=\"data.multiple !== false\" \n [accept]=\"data.allowedFileTypes?.join(',') || '*/*'\" \n (change)=\"onFileInputChange($event)\" \n class=\"tw-hidden\">\n \n <div class=\"tw-flex tw-flex-col tw-items-center tw-gap-2\">\n <cide-ele-icon class=\"tw-text-gray-400 tw-transition-colors tw-duration-200\" \n [class.tw-text-blue-500]=\"isDragOver()\"\n size=\"sm\">cloud_upload</cide-ele-icon>\n \n <div>\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-700\">\n {{ isDragOver() ? 'Drop files here' : 'Drag files here or click to browse' }}\n </div>\n @if (data.description) {\n <div class=\"tw-text-xs tw-text-gray-500 tw-mt-1\">{{ data.description }}</div>\n }\n </div>\n </div>\n </div>\n \n <!-- Upload Queue - Show files from service state -->\n @if (allFilesForGroup().length > 0) {\n <div class=\"tw-space-y-2\">\n <!-- Show all files from service state -->\n @for (file of allFilesForGroup(); track file.fileId) {\n <div class=\"tw-flex tw-items-center tw-px-4 tw-py-3 tw-rounded-lg tw-transition-colors tw-duration-200\"\n [class.tw-bg-blue-50]=\"file.stage === 'uploading'\"\n [class.tw-bg-green-50]=\"file.stage === 'complete'\"\n [class.tw-bg-red-50]=\"file.stage === 'error'\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-flex-1 tw-min-w-0\">\n <cide-ele-icon class=\"tw-flex-shrink-0\" size=\"xs\">{{ getStatusIcon(file.stage) }}</cide-ele-icon>\n <div class=\"tw-min-w-0 tw-flex-1\">\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-truncate\">{{ file.fileName }}</div>\n <div class=\"tw-text-xs\">\n @switch (file.stage) {\n @case ('pending') {\n <span class=\"tw-text-yellow-600 tw-font-medium\">Waiting...</span>\n }\n @case ('reading') {\n <span class=\"tw-text-yellow-600 tw-font-medium\">Reading...</span>\n }\n @case ('uploading') {\n <span class=\"tw-text-blue-600 tw-font-medium\">Uploading...</span>\n }\n @case ('complete') {\n <span class=\"tw-text-green-600 tw-font-medium\">Completed</span>\n }\n @case ('error') {\n <span class=\"tw-text-red-600 tw-font-medium\">Failed</span>\n }\n }\n </div>\n </div>\n </div>\n\n <!-- Progress Bar (only for uploading files) -->\n @if (file.stage === 'uploading' && file.percentage !== undefined) {\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-ml-2 tw-min-w-[80px]\">\n <div class=\"tw-flex-1 tw-h-1 tw-bg-gray-200 tw-rounded-full tw-overflow-hidden\">\n <div class=\"tw-h-full tw-bg-blue-500 tw-transition-all tw-duration-300\" [style.width.%]=\"file.percentage\"></div>\n </div>\n <span class=\"tw-text-xs tw-text-gray-500 tw-min-w-[24px] tw-text-right\">{{ file.percentage }}%</span>\n </div>\n }\n\n <!-- Actions -->\n <div class=\"tw-flex tw-gap-1 tw-ml-2\">\n @switch (file.stage) {\n @case ('pending') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('reading') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('uploading') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('complete') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-text-green-600\" title=\"Completed\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n </button>\n }\n @case ('error') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-blue-50 hover:tw-text-blue-600\" \n title=\"Retry\">\n <cide-ele-icon size=\"xs\">refresh</cide-ele-icon>\n </button>\n }\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <!-- No uploads message when manually opened -->\n <div class=\"tw-py-8 tw-text-center tw-text-gray-500\">\n <div class=\"tw-flex tw-flex-col tw-items-center tw-gap-4\">\n <cide-ele-icon size=\"md\" class=\"tw-text-gray-300 tw-opacity-70\">cloud_upload</cide-ele-icon>\n <div>\n <h4 class=\"tw-text-lg tw-font-semibold tw-text-gray-700 tw-mb-2\">No active uploads</h4>\n <p class=\"tw-text-sm tw-text-gray-500\">Upload files to see their progress here</p>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Status summary - integrated into content -->\n @if (hasActiveUploads()) {\n <div class=\"tw-px-4 tw-py-2 tw-bg-gray-50\">\n <div class=\"tw-flex tw-gap-3 tw-text-xs\">\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-blue-600\">\n <cide-ele-icon size=\"xs\">upload</cide-ele-icon>\n <span>{{ getUploadingCount() }} uploading</span>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-green-600\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n <span>{{ getCompletedCount() }} completed</span>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-red-600\">\n <cide-ele-icon size=\"xs\">error</cide-ele-icon>\n <span>{{ getFailedCount() }} failed</span>\n </div>\n </div>\n </div>\n }\n</div>\n}" }]
5910
- }], ctorParameters: () => [], propDecorators: { data: [{
5428
+ ], template: "<!-- File Uploader Content (No absolute positioning - works within floating container) -->\n@if (isVisible()) {\n<div class=\"tw-w-full tw-h-full tw-overflow-hidden\">\n <!-- Content starts directly - no header needed since floating container provides it -->\n\n <!-- Content -->\n <div class=\"tw-flex-1 tw-overflow-y-auto\">\n \n <!-- Drag and Drop Zone -->\n <div class=\"tw-mb-4 tw-p-6 tw-border-2 tw-border-dashed tw-border-gray-300 tw-rounded-lg tw-bg-gray-50 tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-center hover:tw-border-blue-500 hover:tw-bg-blue-50\" \n [class.tw-border-blue-500]=\"isDragOver()\"\n [class.tw-bg-blue-100]=\"isDragOver()\"\n [class.tw-scale-105]=\"isDragOver()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\" \n (drop)=\"onDrop($event)\" \n (click)=\"triggerFileInput()\">\n \n <!-- Hidden file input -->\n <input #fileInput \n type=\"file\" \n [multiple]=\"data.multiple !== false\" \n [accept]=\"data.allowedFileTypes?.join(',') || '*/*'\" \n (change)=\"onFileInputChange($event)\" \n class=\"tw-hidden\">\n \n <div class=\"tw-flex tw-flex-col tw-items-center tw-gap-2\">\n <cide-ele-icon class=\"tw-text-gray-400 tw-transition-colors tw-duration-200\" \n [class.tw-text-blue-500]=\"isDragOver()\"\n size=\"sm\">cloud_upload</cide-ele-icon>\n \n <div>\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-700\">\n {{ isDragOver() ? 'Drop files here' : 'Drag files here or click to browse' }}\n </div>\n @if (data.description) {\n <div class=\"tw-text-xs tw-text-gray-500 tw-mt-1\">{{ data.description }}</div>\n }\n </div>\n </div>\n </div>\n \n <!-- Upload Queue - Show files from service state -->\n @if (allFilesForGroup().length > 0) {\n <div class=\"tw-space-y-2 tw-max-h-[60vh] tw-overflow-y-auto tw-pr-1\">\n <!-- Show all files from service state -->\n @for (file of allFilesForGroup(); track file.fileId) {\n <div class=\"tw-flex tw-items-center tw-px-4 tw-py-3 tw-rounded-lg tw-transition-colors tw-duration-200 hover:tw-bg-gray-100 hover:tw-shadow-sm\"\n [class.tw-bg-blue-50]=\"file.stage === 'uploading'\"\n [class.tw-bg-green-50]=\"file.stage === 'complete'\"\n [class.tw-bg-red-50]=\"file.stage === 'error'\">\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-flex-1 tw-min-w-0\">\n <cide-ele-icon class=\"tw-flex-shrink-0\" size=\"xs\">{{ getStatusIcon(file.stage) }}</cide-ele-icon>\n <div class=\"tw-min-w-0 tw-flex-1\">\n <div class=\"tw-text-sm tw-font-medium tw-text-gray-900 tw-truncate\">{{ file.fileName }}</div>\n <div class=\"tw-text-xs\">\n @switch (file.stage) {\n @case ('pending') {\n <span class=\"tw-text-yellow-600 tw-font-medium\">Waiting...</span>\n }\n @case ('reading') {\n <span class=\"tw-text-yellow-600 tw-font-medium\">Reading...</span>\n }\n @case ('uploading') {\n <span class=\"tw-text-blue-600 tw-font-medium\">Uploading...</span>\n }\n @case ('complete') {\n <span class=\"tw-text-green-600 tw-font-medium\">Completed</span>\n }\n @case ('error') {\n <span class=\"tw-text-red-600 tw-font-medium\">Failed</span>\n }\n }\n </div>\n </div>\n </div>\n\n <!-- Progress Bar (only for uploading files) -->\n @if (file.stage === 'uploading' && file.percentage !== undefined) {\n <div class=\"tw-flex tw-items-center tw-gap-2 tw-ml-2 tw-min-w-[80px]\">\n <div class=\"tw-flex-1 tw-h-1 tw-bg-gray-200 tw-rounded-full tw-overflow-hidden\">\n <div class=\"tw-h-full tw-bg-blue-500 tw-transition-all tw-duration-300\" [style.width.%]=\"file.percentage\"></div>\n </div>\n <span class=\"tw-text-xs tw-text-gray-500 tw-min-w-[24px] tw-text-right\">{{ file.percentage }}%</span>\n </div>\n }\n\n <!-- Actions -->\n <div class=\"tw-flex tw-gap-1 tw-ml-2\">\n @switch (file.stage) {\n @case ('pending') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('reading') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('uploading') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-red-50 hover:tw-text-red-600\" \n (click)=\"cancelUpload(file.fileId)\" title=\"Cancel\">\n <cide-ele-icon size=\"xs\">cancel</cide-ele-icon>\n </button>\n }\n @case ('complete') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-text-green-600\" title=\"Completed\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n </button>\n }\n @case ('error') {\n <button class=\"tw-flex tw-items-center tw-justify-center tw-w-5 tw-h-5 tw-border-none tw-bg-transparent tw-rounded tw-cursor-pointer tw-transition-all tw-duration-200 tw-text-gray-400 hover:tw-bg-blue-50 hover:tw-text-blue-600\" \n title=\"Retry\">\n <cide-ele-icon size=\"xs\">refresh</cide-ele-icon>\n </button>\n }\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <!-- No uploads message when manually opened -->\n <div class=\"tw-py-8 tw-text-center tw-text-gray-500\">\n <div class=\"tw-flex tw-flex-col tw-items-center tw-gap-4\">\n <cide-ele-icon size=\"md\" class=\"tw-text-gray-300 tw-opacity-70\">cloud_upload</cide-ele-icon>\n <div>\n <h4 class=\"tw-text-lg tw-font-semibold tw-text-gray-700 tw-mb-2\">No active uploads</h4>\n <p class=\"tw-text-sm tw-text-gray-500\">Upload files to see their progress here</p>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Status summary - integrated into content -->\n @if (hasActiveUploads()) {\n <div class=\"tw-px-4 tw-py-2 tw-bg-gray-50\">\n <div class=\"tw-flex tw-gap-3 tw-text-xs\">\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-blue-600\">\n <cide-ele-icon size=\"xs\">upload</cide-ele-icon>\n <span>{{ getUploadingCount() }} uploading</span>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-green-600\">\n <cide-ele-icon size=\"xs\">check_circle</cide-ele-icon>\n <span>{{ getCompletedCount() }} completed</span>\n </div>\n <div class=\"tw-flex tw-items-center tw-gap-1 tw-text-red-600\">\n <cide-ele-icon size=\"xs\">error</cide-ele-icon>\n <span>{{ getFailedCount() }} failed</span>\n </div>\n </div>\n </div>\n }\n</div>\n}" }]
5429
+ }], ctorParameters: () => [], propDecorators: { fileInputRef: [{
5430
+ type: ViewChild,
5431
+ args: ['fileInput']
5432
+ }], data: [{
5911
5433
  type: Input
5912
5434
  }] } });
5913
5435
 
@@ -6065,7 +5587,199 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImpor
6065
5587
  type: Output
6066
5588
  }] } });
6067
5589
 
6068
- /**
5590
+ class KeyboardShortcutService {
5591
+ shortcuts = new Map();
5592
+ overrides = new Map();
5593
+ keydownListener;
5594
+ constructor() {
5595
+ this.setupGlobalListener();
5596
+ }
5597
+ ngOnDestroy() {
5598
+ this.removeGlobalListener();
5599
+ }
5600
+ /**
5601
+ * Register a new keyboard shortcut
5602
+ */
5603
+ register(shortcut) {
5604
+ this.shortcuts.set(shortcut.id, shortcut);
5605
+ console.log(`⌨️ [KeyboardShortcut] Registered shortcut: ${shortcut.id} (${this.getKeyDescription(shortcut)})`);
5606
+ }
5607
+ /**
5608
+ * Override an existing shortcut with new key combination
5609
+ */
5610
+ override(shortcutId, newKey, options) {
5611
+ const originalShortcut = this.shortcuts.get(shortcutId);
5612
+ if (!originalShortcut) {
5613
+ console.warn(`⚠️ [KeyboardShortcut] Cannot override shortcut '${shortcutId}' - not found`);
5614
+ return;
5615
+ }
5616
+ const override = {
5617
+ shortcutId,
5618
+ newKey,
5619
+ newCtrlKey: options?.ctrlKey,
5620
+ newAltKey: options?.altKey,
5621
+ newShiftKey: options?.shiftKey,
5622
+ newMetaKey: options?.metaKey
5623
+ };
5624
+ this.overrides.set(shortcutId, override);
5625
+ console.log(`🔄 [KeyboardShortcut] Override registered for '${shortcutId}': ${this.getKeyDescription({ ...originalShortcut, ...options, key: newKey })}`);
5626
+ }
5627
+ /**
5628
+ * Remove a shortcut
5629
+ */
5630
+ unregister(shortcutId) {
5631
+ this.shortcuts.delete(shortcutId);
5632
+ this.overrides.delete(shortcutId);
5633
+ console.log(`🗑️ [KeyboardShortcut] Removed shortcut: ${shortcutId}`);
5634
+ }
5635
+ /**
5636
+ * Remove override for a shortcut (restore original key combination)
5637
+ */
5638
+ removeOverride(shortcutId) {
5639
+ this.overrides.delete(shortcutId);
5640
+ console.log(`🔄 [KeyboardShortcut] Override removed for: ${shortcutId}`);
5641
+ }
5642
+ /**
5643
+ * Get all registered shortcuts
5644
+ */
5645
+ getAllShortcuts() {
5646
+ return Array.from(this.shortcuts.values());
5647
+ }
5648
+ /**
5649
+ * Get shortcuts by category or filter
5650
+ */
5651
+ getShortcuts(filter) {
5652
+ const shortcuts = this.getAllShortcuts();
5653
+ return filter ? shortcuts.filter(filter) : shortcuts;
5654
+ }
5655
+ /**
5656
+ * Check if a shortcut is registered
5657
+ */
5658
+ hasShortcut(shortcutId) {
5659
+ return this.shortcuts.has(shortcutId);
5660
+ }
5661
+ /**
5662
+ * Get shortcut information
5663
+ */
5664
+ getShortcut(shortcutId) {
5665
+ return this.shortcuts.get(shortcutId);
5666
+ }
5667
+ /**
5668
+ * Clear all shortcuts
5669
+ */
5670
+ clearAll() {
5671
+ this.shortcuts.clear();
5672
+ this.overrides.clear();
5673
+ console.log(`🧹 [KeyboardShortcut] All shortcuts cleared`);
5674
+ }
5675
+ /**
5676
+ * Set up global keyboard listener
5677
+ */
5678
+ setupGlobalListener() {
5679
+ this.keydownListener = (event) => {
5680
+ this.handleKeydown(event);
5681
+ };
5682
+ document.addEventListener('keydown', this.keydownListener);
5683
+ console.log(`🎧 [KeyboardShortcut] Global keyboard listener attached`);
5684
+ }
5685
+ /**
5686
+ * Remove global keyboard listener
5687
+ */
5688
+ removeGlobalListener() {
5689
+ if (this.keydownListener) {
5690
+ document.removeEventListener('keydown', this.keydownListener);
5691
+ this.keydownListener = undefined;
5692
+ console.log(`🎧 [KeyboardShortcut] Global keyboard listener removed`);
5693
+ }
5694
+ }
5695
+ /**
5696
+ * Handle keydown events
5697
+ */
5698
+ handleKeydown(event) {
5699
+ for (const [shortcutId, shortcut] of this.shortcuts) {
5700
+ if (this.matchesShortcut(event, shortcut)) {
5701
+ // Check for override
5702
+ const override = this.overrides.get(shortcutId);
5703
+ if (override && !this.matchesOverride(event, override)) {
5704
+ continue; // Skip if override doesn't match
5705
+ }
5706
+ if (shortcut.preventDefault !== false) {
5707
+ event.preventDefault();
5708
+ }
5709
+ if (shortcut.stopPropagation) {
5710
+ event.stopPropagation();
5711
+ }
5712
+ console.log(`⌨️ [KeyboardShortcut] Executing shortcut: ${shortcutId}`);
5713
+ shortcut.action();
5714
+ break; // Only execute one shortcut per keydown
5715
+ }
5716
+ }
5717
+ }
5718
+ /**
5719
+ * Check if event matches shortcut
5720
+ */
5721
+ matchesShortcut(event, shortcut) {
5722
+ return event.key === shortcut.key &&
5723
+ (shortcut.ctrlKey === undefined || event.ctrlKey === shortcut.ctrlKey) &&
5724
+ (shortcut.altKey === undefined || event.altKey === shortcut.altKey) &&
5725
+ (shortcut.shiftKey === undefined || event.shiftKey === shortcut.shiftKey) &&
5726
+ (shortcut.metaKey === undefined || event.metaKey === shortcut.metaKey);
5727
+ }
5728
+ /**
5729
+ * Check if event matches override
5730
+ */
5731
+ matchesOverride(event, override) {
5732
+ return event.key === override.newKey &&
5733
+ (override.newCtrlKey === undefined || event.ctrlKey === override.newCtrlKey) &&
5734
+ (override.newAltKey === undefined || event.altKey === override.newAltKey) &&
5735
+ (override.newShiftKey === undefined || event.shiftKey === override.newShiftKey) &&
5736
+ (override.newMetaKey === undefined || event.metaKey === override.newMetaKey);
5737
+ }
5738
+ /**
5739
+ * Get human-readable key description
5740
+ */
5741
+ getKeyDescription(shortcut) {
5742
+ const modifiers = [];
5743
+ if (shortcut.ctrlKey)
5744
+ modifiers.push('Ctrl');
5745
+ if (shortcut.altKey)
5746
+ modifiers.push('Alt');
5747
+ if (shortcut.shiftKey)
5748
+ modifiers.push('Shift');
5749
+ if (shortcut.metaKey)
5750
+ modifiers.push('Meta');
5751
+ return [...modifiers, shortcut.key].join(' + ');
5752
+ }
5753
+ /**
5754
+ * Get key description for a shortcut ID
5755
+ */
5756
+ getKeyDescriptionForShortcut(shortcutId) {
5757
+ const shortcut = this.shortcuts.get(shortcutId);
5758
+ if (!shortcut)
5759
+ return 'Not found';
5760
+ const override = this.overrides.get(shortcutId);
5761
+ if (override) {
5762
+ return this.getKeyDescription({
5763
+ key: override.newKey,
5764
+ ctrlKey: override.newCtrlKey,
5765
+ altKey: override.newAltKey,
5766
+ shiftKey: override.newShiftKey,
5767
+ metaKey: override.newMetaKey
5768
+ });
5769
+ }
5770
+ return this.getKeyDescription(shortcut);
5771
+ }
5772
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: KeyboardShortcutService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
5773
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: KeyboardShortcutService, providedIn: 'root' });
5774
+ }
5775
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: KeyboardShortcutService, decorators: [{
5776
+ type: Injectable,
5777
+ args: [{
5778
+ providedIn: 'root'
5779
+ }]
5780
+ }], ctorParameters: () => [] });
5781
+
5782
+ /**
6069
5783
  <!-- Basic horizontal (left-right) layout -->
6070
5784
  <div class="panel-container">
6071
5785
  <div class="left-panel">
@@ -10654,8 +10368,294 @@ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "20.1.7", ng
10654
10368
  ` }]
10655
10369
  }], ctorParameters: null, propDecorators: null }) });
10656
10370
 
10371
+ class FloatingContainerShortcutsService {
10372
+ keyboardShortcutService = inject(KeyboardShortcutService);
10373
+ containerService = inject(CideEleFloatingContainerService);
10374
+ // Z-index layers for different container states
10375
+ Z_INDEX_LAYERS = {
10376
+ HIDDEN: 100, // Hidden containers (behind everything)
10377
+ BACKGROUND: 1000, // Background containers
10378
+ NORMAL: 2000, // Normal visible containers
10379
+ FOCUSED: 3000, // Focused containers
10380
+ MODAL: 4000, // Modal containers
10381
+ TOOLTIP: 5000 // Tooltips and overlays
10382
+ };
10383
+ constructor() {
10384
+ this.registerDefaultShortcuts();
10385
+ }
10386
+ /**
10387
+ * Register default floating container shortcuts
10388
+ */
10389
+ registerDefaultShortcuts() {
10390
+ console.log('🎯 [FloatingContainerShortcuts] Registering default shortcuts');
10391
+ // Alt + 1, Alt + 2, etc. - Focus specific containers
10392
+ this.registerNumberShortcuts();
10393
+ // Alt + N - New container
10394
+ this.keyboardShortcutService.register({
10395
+ id: 'floating-container-new',
10396
+ key: 'n',
10397
+ altKey: true,
10398
+ description: 'Create new floating container',
10399
+ action: () => this.openNewContainer(),
10400
+ preventDefault: true
10401
+ });
10402
+ // Alt + P - Previous container
10403
+ this.keyboardShortcutService.register({
10404
+ id: 'floating-container-previous',
10405
+ key: 'p',
10406
+ altKey: true,
10407
+ description: 'Focus previous container',
10408
+ action: () => this.focusPreviousContainer(),
10409
+ preventDefault: true
10410
+ });
10411
+ // Alt + H - Hide all containers
10412
+ this.keyboardShortcutService.register({
10413
+ id: 'floating-container-hide-all',
10414
+ key: 'h',
10415
+ altKey: true,
10416
+ description: 'Hide all containers',
10417
+ action: () => this.hideAllContainers(),
10418
+ preventDefault: true
10419
+ });
10420
+ // Alt + S - Show all containers
10421
+ this.keyboardShortcutService.register({
10422
+ id: 'floating-container-show-all',
10423
+ key: 's',
10424
+ altKey: true,
10425
+ description: 'Show all containers',
10426
+ action: () => this.showAllContainers(),
10427
+ preventDefault: true
10428
+ });
10429
+ // Alt + M - Minimize all containers
10430
+ this.keyboardShortcutService.register({
10431
+ id: 'floating-container-minimize-all',
10432
+ key: 'm',
10433
+ altKey: true,
10434
+ description: 'Minimize all containers',
10435
+ action: () => this.minimizeAllContainers(),
10436
+ preventDefault: true
10437
+ });
10438
+ // Alt + W - Close current container
10439
+ this.keyboardShortcutService.register({
10440
+ id: 'floating-container-close-current',
10441
+ key: 'w',
10442
+ altKey: true,
10443
+ description: 'Close current container',
10444
+ action: () => this.closeCurrentContainer(),
10445
+ preventDefault: true
10446
+ });
10447
+ // Alt + D - Duplicate current container
10448
+ this.keyboardShortcutService.register({
10449
+ id: 'floating-container-duplicate',
10450
+ key: 'd',
10451
+ altKey: true,
10452
+ description: 'Duplicate current container',
10453
+ action: () => this.duplicateCurrentContainer(),
10454
+ preventDefault: true
10455
+ });
10456
+ // Alt + T - Toggle container visibility
10457
+ this.keyboardShortcutService.register({
10458
+ id: 'floating-container-toggle-visibility',
10459
+ key: 't',
10460
+ altKey: true,
10461
+ description: 'Toggle container visibility',
10462
+ action: () => this.toggleContainerVisibility(),
10463
+ preventDefault: true
10464
+ });
10465
+ // Alt + O - Open file uploader
10466
+ this.keyboardShortcutService.register({
10467
+ id: 'floating-container-open-file-uploader',
10468
+ key: 'o',
10469
+ altKey: true,
10470
+ description: 'Open file uploader',
10471
+ action: () => this.openFileUploader(),
10472
+ preventDefault: true
10473
+ });
10474
+ // Alt + R - Open entity rights sharing
10475
+ this.keyboardShortcutService.register({
10476
+ id: 'floating-container-open-entity-rights',
10477
+ key: 'r',
10478
+ altKey: true,
10479
+ description: 'Open entity rights sharing',
10480
+ action: () => this.openEntityRightsSharing(),
10481
+ preventDefault: true
10482
+ });
10483
+ console.log('✅ [FloatingContainerShortcuts] Default shortcuts registered');
10484
+ }
10485
+ /**
10486
+ * Register number shortcuts (Alt + 1, Alt + 2, etc.)
10487
+ */
10488
+ registerNumberShortcuts() {
10489
+ for (let i = 1; i <= 9; i++) {
10490
+ this.keyboardShortcutService.register({
10491
+ id: `floating-container-focus-${i}`,
10492
+ key: i.toString(),
10493
+ altKey: true,
10494
+ description: `Focus container ${i}`,
10495
+ action: () => this.focusContainerByIndex(i - 1),
10496
+ preventDefault: true
10497
+ });
10498
+ }
10499
+ }
10500
+ /**
10501
+ * Open new floating container
10502
+ */
10503
+ openNewContainer() {
10504
+ console.log('🎯 [FloatingContainerShortcuts] Opening new container');
10505
+ const containerId = this.containerService.show({
10506
+ id: 'new-container-' + Date.now(),
10507
+ title: 'New Container',
10508
+ width: '400px',
10509
+ height: '300px'
10510
+ });
10511
+ console.log('✅ [FloatingContainerShortcuts] New container created:', containerId);
10512
+ }
10513
+ /**
10514
+ * Focus previous container
10515
+ */
10516
+ focusPreviousContainer() {
10517
+ console.log('🎯 [FloatingContainerShortcuts] Focusing previous container');
10518
+ const containers = this.containerService.visibleContainers();
10519
+ if (containers.length > 0) {
10520
+ // For now, just focus the last container
10521
+ const previousIndex = containers.length - 1;
10522
+ this.containerService.bringToFront(containers[previousIndex].id);
10523
+ }
10524
+ }
10525
+ /**
10526
+ * Hide all containers
10527
+ */
10528
+ hideAllContainers() {
10529
+ console.log('🎯 [FloatingContainerShortcuts] Hiding all containers');
10530
+ const containers = this.containerService.visibleContainers();
10531
+ containers.forEach(container => {
10532
+ this.containerService.setZIndex(container.id, this.Z_INDEX_LAYERS.HIDDEN);
10533
+ });
10534
+ console.log('✅ [FloatingContainerShortcuts] All containers hidden');
10535
+ }
10536
+ /**
10537
+ * Show all containers
10538
+ */
10539
+ showAllContainers() {
10540
+ console.log('🎯 [FloatingContainerShortcuts] Showing all containers');
10541
+ const containers = this.containerService.visibleContainers();
10542
+ containers.forEach((container, index) => {
10543
+ this.containerService.setZIndex(container.id, this.Z_INDEX_LAYERS.NORMAL + index);
10544
+ });
10545
+ console.log('✅ [FloatingContainerShortcuts] All containers shown');
10546
+ }
10547
+ /**
10548
+ * Minimize all containers
10549
+ */
10550
+ minimizeAllContainers() {
10551
+ console.log('🎯 [FloatingContainerShortcuts] Minimizing all containers');
10552
+ const containers = this.containerService.visibleContainers();
10553
+ containers.forEach(container => {
10554
+ // Implement minimize logic here
10555
+ console.log('📦 [FloatingContainerShortcuts] Minimizing container:', container.id);
10556
+ });
10557
+ console.log('✅ [FloatingContainerShortcuts] All containers minimized');
10558
+ }
10559
+ /**
10560
+ * Focus container by index
10561
+ */
10562
+ focusContainerByIndex(index) {
10563
+ console.log('🎯 [FloatingContainerShortcuts] Focusing container at index:', index);
10564
+ const containers = this.containerService.visibleContainers();
10565
+ if (containers[index]) {
10566
+ this.containerService.bringToFront(containers[index].id);
10567
+ console.log('✅ [FloatingContainerShortcuts] Container focused:', containers[index].id);
10568
+ }
10569
+ else {
10570
+ console.warn('⚠️ [FloatingContainerShortcuts] Container not found at index:', index);
10571
+ }
10572
+ }
10573
+ /**
10574
+ * Open file uploader
10575
+ */
10576
+ openFileUploader() {
10577
+ console.log('🎯 [FloatingContainerShortcuts] Opening file uploader');
10578
+ // Implement file uploader opening logic here
10579
+ console.log('✅ [FloatingContainerShortcuts] File uploader opened');
10580
+ }
10581
+ /**
10582
+ * Open entity rights sharing
10583
+ */
10584
+ openEntityRightsSharing() {
10585
+ console.log('🎯 [FloatingContainerShortcuts] Opening entity rights sharing');
10586
+ // Implement entity rights sharing opening logic here
10587
+ console.log('✅ [FloatingContainerShortcuts] Entity rights sharing opened');
10588
+ }
10589
+ /**
10590
+ * Duplicate current container
10591
+ */
10592
+ duplicateCurrentContainer() {
10593
+ console.log('🎯 [FloatingContainerShortcuts] Duplicating current container');
10594
+ const containers = this.containerService.visibleContainers();
10595
+ if (containers.length > 0) {
10596
+ const containerToDuplicate = containers[containers.length - 1]; // Use last container
10597
+ const newContainerId = this.containerService.show({
10598
+ id: 'duplicate-' + Date.now(),
10599
+ title: `${containerToDuplicate.config.title} (Copy)`,
10600
+ width: containerToDuplicate.config.width,
10601
+ height: containerToDuplicate.config.height
10602
+ });
10603
+ console.log('✅ [FloatingContainerShortcuts] Container duplicated:', newContainerId);
10604
+ }
10605
+ else {
10606
+ console.warn('⚠️ [FloatingContainerShortcuts] No container to duplicate');
10607
+ }
10608
+ }
10609
+ /**
10610
+ * Close current container
10611
+ */
10612
+ closeCurrentContainer() {
10613
+ console.log('🎯 [FloatingContainerShortcuts] Closing current container');
10614
+ const containers = this.containerService.visibleContainers();
10615
+ if (containers.length > 0) {
10616
+ const containerToClose = containers[containers.length - 1]; // Use last container
10617
+ this.containerService.hide(containerToClose.id);
10618
+ console.log('✅ [FloatingContainerShortcuts] Container closed:', containerToClose.id);
10619
+ }
10620
+ else {
10621
+ console.warn('⚠️ [FloatingContainerShortcuts] No container to close');
10622
+ }
10623
+ }
10624
+ /**
10625
+ * Toggle container visibility
10626
+ */
10627
+ toggleContainerVisibility() {
10628
+ console.log('🎯 [FloatingContainerShortcuts] Toggling container visibility');
10629
+ const containers = this.containerService.visibleContainers();
10630
+ if (containers.length > 0) {
10631
+ const containerToToggle = containers[containers.length - 1]; // Use last container
10632
+ const currentZIndex = this.containerService.getZIndexSignal(containerToToggle.id)();
10633
+ if (currentZIndex === this.Z_INDEX_LAYERS.HIDDEN) {
10634
+ this.containerService.setZIndex(containerToToggle.id, this.Z_INDEX_LAYERS.NORMAL);
10635
+ console.log('✅ [FloatingContainerShortcuts] Container shown:', containerToToggle.id);
10636
+ }
10637
+ else {
10638
+ this.containerService.setZIndex(containerToToggle.id, this.Z_INDEX_LAYERS.HIDDEN);
10639
+ console.log('✅ [FloatingContainerShortcuts] Container hidden:', containerToToggle.id);
10640
+ }
10641
+ }
10642
+ else {
10643
+ console.warn('⚠️ [FloatingContainerShortcuts] No container to toggle');
10644
+ }
10645
+ }
10646
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FloatingContainerShortcutsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
10647
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FloatingContainerShortcutsService, providedIn: 'root' });
10648
+ }
10649
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: FloatingContainerShortcutsService, decorators: [{
10650
+ type: Injectable,
10651
+ args: [{
10652
+ providedIn: 'root'
10653
+ }]
10654
+ }], ctorParameters: () => [] });
10655
+
10657
10656
  class CideEleFloatingFeaturesService {
10658
10657
  containerService = inject(CideEleFloatingContainerService);
10658
+ shortcutsService = inject(FloatingContainerShortcutsService);
10659
10659
  constructor() {
10660
10660
  // File uploader is handled by its own dedicated service
10661
10661
  // Entity rights sharing is handled by its own dedicated service