@pegasusheavy/ngx-tailwindcss 0.3.6 → 0.3.7

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, makeEnvironmentProviders, inject, PLATFORM_ID, DestroyRef, signal, Injectable, APP_INITIALIZER, computed, LOCALE_ID, effect, ElementRef, Renderer2, booleanAttribute, HostListener, Input, Directive, numberAttribute, NgZone, EventEmitter, Output, ChangeDetectionStrategy, Component, HostBinding, forwardRef, ViewChild, input, output, ContentChildren, ContentChild, viewChild, model, contentChildren } from '@angular/core';
2
+ import { InjectionToken, makeEnvironmentProviders, inject, PLATFORM_ID, DestroyRef, signal, Injectable, APP_INITIALIZER, computed, LOCALE_ID, effect, ElementRef, Renderer2, booleanAttribute, HostListener, Input, Directive, numberAttribute, NgZone, EventEmitter, Output, ChangeDetectionStrategy, Component, HostBinding, forwardRef, ViewChild, input, output, ContentChildren, ContentChild, viewChild, contentChildren } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { DOCUMENT, isPlatformBrowser, CommonModule, NgStyle } from '@angular/common';
5
5
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@@ -3848,8 +3848,8 @@ const BUTTON_VARIANTS = {
3848
3848
  warning: 'bg-amber-500 hover:bg-amber-600 active:bg-amber-700 text-white shadow-sm hover:shadow focus-visible:ring-amber-500',
3849
3849
  danger: 'bg-rose-600 hover:bg-rose-700 active:bg-rose-800 text-white shadow-sm hover:shadow focus-visible:ring-rose-500',
3850
3850
  info: 'bg-cyan-600 hover:bg-cyan-700 active:bg-cyan-800 text-white shadow-sm hover:shadow focus-visible:ring-cyan-500',
3851
- ghost: 'bg-transparent hover:bg-slate-100 dark:hover:bg-zinc-800 active:bg-slate-200 dark:active:bg-zinc-700 text-slate-700 dark:text-zinc-300 focus-visible:ring-slate-500',
3852
- outline: 'bg-white dark:bg-zinc-800 border-2 border-slate-500 dark:border-zinc-500 hover:border-slate-600 dark:hover:border-zinc-400 hover:bg-slate-100 dark:hover:bg-zinc-700 active:bg-slate-200 dark:active:bg-zinc-600 text-slate-800 dark:text-zinc-200 shadow-sm focus-visible:ring-slate-500',
3851
+ ghost: 'bg-transparent hover:bg-slate-100 active:bg-slate-200 text-slate-700 focus-visible:ring-slate-500',
3852
+ outline: 'bg-white border-2 border-slate-500 hover:border-slate-600 hover:bg-slate-100 active:bg-slate-200 text-slate-800 shadow-sm focus-visible:ring-slate-500',
3853
3853
  link: 'bg-transparent text-blue-600 hover:text-blue-700 hover:underline active:text-blue-800 focus-visible:ring-blue-500 p-0 shadow-none',
3854
3854
  };
3855
3855
  const BUTTON_SIZES = {
@@ -4307,7 +4307,7 @@ class TwInputComponent {
4307
4307
  useExisting: forwardRef(() => TwInputComponent),
4308
4308
  multi: true,
4309
4309
  },
4310
- ], viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["inputElement"], descendants: true }], ngImport: i0, template: "@if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-slate-700 mb-1.5\">\n {{ label }}\n @if (required) {\n <span class=\"text-rose-500 ml-0.5\">*</span>\n }\n </label>\n}\n\n<div [class]=\"wrapperClasses()\">\n <!-- Prefix -->\n <ng-content select=\"[twInputPrefix]\"></ng-content>\n\n <!-- Input element -->\n <input\n #inputElement\n [id]=\"inputId\"\n [type]=\"type\"\n [class]=\"computedClasses()\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n [attr.aria-invalid]=\"hasError\"\n [attr.aria-describedby]=\"describedBy\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.inputmode]=\"inputmode\"\n [attr.pattern]=\"pattern\"\n [attr.min]=\"min\"\n [attr.max]=\"max\"\n [attr.minlength]=\"minlength\"\n [attr.maxlength]=\"maxlength\"\n [attr.step]=\"step\"\n [value]=\"value\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n (focus)=\"onFocus.emit($event)\"\n />\n\n <!-- Suffix -->\n <ng-content select=\"[twInputSuffix]\"></ng-content>\n\n <!-- Clear button -->\n @if (clearable && value && !disabled && !readonly) {\n <button\n type=\"button\"\n class=\"flex items-center justify-center w-5 h-5 text-slate-400 hover:text-slate-600 transition-colors\"\n (click)=\"clear()\"\n aria-label=\"Clear input\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n }\n</div>\n\n@if (hint && !error) {\n <span class=\"block text-xs text-slate-500 mt-1.5\">{{ hint }}</span>\n}\n\n@if (error) {\n <span class=\"block text-xs text-rose-600 mt-1.5\" role=\"alert\">{{ error }}</span>\n}\n\n<ng-content select=\"tw-hint, [twHint], tw-error, [twError]\"></ng-content>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4310
+ ], viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["inputElement"], descendants: true }], ngImport: i0, template: "@if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5\">\n {{ label }}\n @if (required) {\n <span class=\"text-rose-500 ml-0.5\">*</span>\n }\n </label>\n}\n\n<div [class]=\"wrapperClasses()\">\n <!-- Prefix -->\n <ng-content select=\"[twInputPrefix]\"></ng-content>\n\n <!-- Input element -->\n <input\n #inputElement\n [id]=\"inputId\"\n [type]=\"type\"\n [class]=\"computedClasses()\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n [attr.aria-invalid]=\"hasError\"\n [attr.aria-describedby]=\"describedBy\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.inputmode]=\"inputmode\"\n [attr.pattern]=\"pattern\"\n [attr.min]=\"min\"\n [attr.max]=\"max\"\n [attr.minlength]=\"minlength\"\n [attr.maxlength]=\"maxlength\"\n [attr.step]=\"step\"\n [value]=\"value\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n (focus)=\"onFocus.emit($event)\"\n />\n\n <!-- Suffix -->\n <ng-content select=\"[twInputSuffix]\"></ng-content>\n\n <!-- Clear button -->\n @if (clearable && value && !disabled && !readonly) {\n <button\n type=\"button\"\n class=\"flex items-center justify-center w-5 h-5 text-slate-400 hover:text-slate-600 dark:text-slate-500 dark:hover:text-slate-300 transition-colors\"\n (click)=\"clear()\"\n aria-label=\"Clear input\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n }\n</div>\n\n@if (hint && !error) {\n <span class=\"block text-xs text-slate-500 dark:text-slate-400 mt-1.5\">{{ hint }}</span>\n}\n\n@if (error) {\n <span class=\"block text-xs text-rose-600 mt-1.5\" role=\"alert\">{{ error }}</span>\n}\n\n<ng-content select=\"tw-hint, [twHint], tw-error, [twError]\"></ng-content>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4311
4311
  }
4312
4312
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TwInputComponent, decorators: [{
4313
4313
  type: Component,
@@ -4319,7 +4319,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
4319
4319
  },
4320
4320
  ], host: {
4321
4321
  class: 'block',
4322
- }, template: "@if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-slate-700 mb-1.5\">\n {{ label }}\n @if (required) {\n <span class=\"text-rose-500 ml-0.5\">*</span>\n }\n </label>\n}\n\n<div [class]=\"wrapperClasses()\">\n <!-- Prefix -->\n <ng-content select=\"[twInputPrefix]\"></ng-content>\n\n <!-- Input element -->\n <input\n #inputElement\n [id]=\"inputId\"\n [type]=\"type\"\n [class]=\"computedClasses()\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n [attr.aria-invalid]=\"hasError\"\n [attr.aria-describedby]=\"describedBy\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.inputmode]=\"inputmode\"\n [attr.pattern]=\"pattern\"\n [attr.min]=\"min\"\n [attr.max]=\"max\"\n [attr.minlength]=\"minlength\"\n [attr.maxlength]=\"maxlength\"\n [attr.step]=\"step\"\n [value]=\"value\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n (focus)=\"onFocus.emit($event)\"\n />\n\n <!-- Suffix -->\n <ng-content select=\"[twInputSuffix]\"></ng-content>\n\n <!-- Clear button -->\n @if (clearable && value && !disabled && !readonly) {\n <button\n type=\"button\"\n class=\"flex items-center justify-center w-5 h-5 text-slate-400 hover:text-slate-600 transition-colors\"\n (click)=\"clear()\"\n aria-label=\"Clear input\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n }\n</div>\n\n@if (hint && !error) {\n <span class=\"block text-xs text-slate-500 mt-1.5\">{{ hint }}</span>\n}\n\n@if (error) {\n <span class=\"block text-xs text-rose-600 mt-1.5\" role=\"alert\">{{ error }}</span>\n}\n\n<ng-content select=\"tw-hint, [twHint], tw-error, [twError]\"></ng-content>\n" }]
4322
+ }, template: "@if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5\">\n {{ label }}\n @if (required) {\n <span class=\"text-rose-500 ml-0.5\">*</span>\n }\n </label>\n}\n\n<div [class]=\"wrapperClasses()\">\n <!-- Prefix -->\n <ng-content select=\"[twInputPrefix]\"></ng-content>\n\n <!-- Input element -->\n <input\n #inputElement\n [id]=\"inputId\"\n [type]=\"type\"\n [class]=\"computedClasses()\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n [attr.aria-invalid]=\"hasError\"\n [attr.aria-describedby]=\"describedBy\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.inputmode]=\"inputmode\"\n [attr.pattern]=\"pattern\"\n [attr.min]=\"min\"\n [attr.max]=\"max\"\n [attr.minlength]=\"minlength\"\n [attr.maxlength]=\"maxlength\"\n [attr.step]=\"step\"\n [value]=\"value\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n (focus)=\"onFocus.emit($event)\"\n />\n\n <!-- Suffix -->\n <ng-content select=\"[twInputSuffix]\"></ng-content>\n\n <!-- Clear button -->\n @if (clearable && value && !disabled && !readonly) {\n <button\n type=\"button\"\n class=\"flex items-center justify-center w-5 h-5 text-slate-400 hover:text-slate-600 dark:text-slate-500 dark:hover:text-slate-300 transition-colors\"\n (click)=\"clear()\"\n aria-label=\"Clear input\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n }\n</div>\n\n@if (hint && !error) {\n <span class=\"block text-xs text-slate-500 dark:text-slate-400 mt-1.5\">{{ hint }}</span>\n}\n\n@if (error) {\n <span class=\"block text-xs text-rose-600 mt-1.5\" role=\"alert\">{{ error }}</span>\n}\n\n<ng-content select=\"tw-hint, [twHint], tw-error, [twError]\"></ng-content>\n" }]
4323
4323
  }], propDecorators: { inputElement: [{
4324
4324
  type: ViewChild,
4325
4325
  args: ['inputElement']
@@ -4452,7 +4452,7 @@ class TwTextareaComponent {
4452
4452
  useExisting: forwardRef(() => TwTextareaComponent),
4453
4453
  multi: true,
4454
4454
  },
4455
- ], viewQueries: [{ propertyName: "textareaElement", first: true, predicate: ["textareaElement"], descendants: true }], ngImport: i0, template: "@if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-slate-700 mb-1.5\">\n {{ label }}\n @if (required) {\n <span class=\"text-rose-500 ml-0.5\">*</span>\n }\n </label>\n}\n\n<textarea\n #textareaElement\n [id]=\"inputId\"\n [class]=\"computedClasses()\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n [rows]=\"rows\"\n [attr.aria-invalid]=\"hasError\"\n [attr.minlength]=\"minlength\"\n [attr.maxlength]=\"maxlength\"\n [value]=\"value\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n></textarea>\n\n@if (hint && !error) {\n <span class=\"block text-xs text-slate-500 mt-1.5\">{{ hint }}</span>\n}\n\n@if (error) {\n <span class=\"block text-xs text-rose-600 mt-1.5\" role=\"alert\">{{ error }}</span>\n}\n\n@if (maxlength && showCount) {\n <span class=\"block text-xs text-slate-400 mt-1 text-right\">\n {{ value.length }} / {{ maxlength }}\n </span>\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4455
+ ], viewQueries: [{ propertyName: "textareaElement", first: true, predicate: ["textareaElement"], descendants: true }], ngImport: i0, template: "@if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5\">\n {{ label }}\n @if (required) {\n <span class=\"text-rose-500 ml-0.5\">*</span>\n }\n </label>\n}\n\n<textarea\n #textareaElement\n [id]=\"inputId\"\n [class]=\"computedClasses()\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n [rows]=\"rows\"\n [attr.aria-invalid]=\"hasError\"\n [attr.minlength]=\"minlength\"\n [attr.maxlength]=\"maxlength\"\n [value]=\"value\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n></textarea>\n\n@if (hint && !error) {\n <span class=\"block text-xs text-slate-500 dark:text-slate-400 mt-1.5\">{{ hint }}</span>\n}\n\n@if (error) {\n <span class=\"block text-xs text-rose-600 mt-1.5\" role=\"alert\">{{ error }}</span>\n}\n\n@if (maxlength && showCount) {\n <span class=\"block text-xs text-slate-400 mt-1 text-right\">\n {{ value.length }} / {{ maxlength }}\n </span>\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4456
4456
  }
4457
4457
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TwTextareaComponent, decorators: [{
4458
4458
  type: Component,
@@ -4464,7 +4464,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
4464
4464
  },
4465
4465
  ], host: {
4466
4466
  class: 'block',
4467
- }, template: "@if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-slate-700 mb-1.5\">\n {{ label }}\n @if (required) {\n <span class=\"text-rose-500 ml-0.5\">*</span>\n }\n </label>\n}\n\n<textarea\n #textareaElement\n [id]=\"inputId\"\n [class]=\"computedClasses()\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n [rows]=\"rows\"\n [attr.aria-invalid]=\"hasError\"\n [attr.minlength]=\"minlength\"\n [attr.maxlength]=\"maxlength\"\n [value]=\"value\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n></textarea>\n\n@if (hint && !error) {\n <span class=\"block text-xs text-slate-500 mt-1.5\">{{ hint }}</span>\n}\n\n@if (error) {\n <span class=\"block text-xs text-rose-600 mt-1.5\" role=\"alert\">{{ error }}</span>\n}\n\n@if (maxlength && showCount) {\n <span class=\"block text-xs text-slate-400 mt-1 text-right\">\n {{ value.length }} / {{ maxlength }}\n </span>\n}\n" }]
4467
+ }, template: "@if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5\">\n {{ label }}\n @if (required) {\n <span class=\"text-rose-500 ml-0.5\">*</span>\n }\n </label>\n}\n\n<textarea\n #textareaElement\n [id]=\"inputId\"\n [class]=\"computedClasses()\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n [rows]=\"rows\"\n [attr.aria-invalid]=\"hasError\"\n [attr.minlength]=\"minlength\"\n [attr.maxlength]=\"maxlength\"\n [value]=\"value\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n></textarea>\n\n@if (hint && !error) {\n <span class=\"block text-xs text-slate-500 dark:text-slate-400 mt-1.5\">{{ hint }}</span>\n}\n\n@if (error) {\n <span class=\"block text-xs text-rose-600 mt-1.5\" role=\"alert\">{{ error }}</span>\n}\n\n@if (maxlength && showCount) {\n <span class=\"block text-xs text-slate-400 mt-1 text-right\">\n {{ value.length }} / {{ maxlength }}\n </span>\n}\n" }]
4468
4468
  }], propDecorators: { textareaElement: [{
4469
4469
  type: ViewChild,
4470
4470
  args: ['textareaElement']
@@ -9799,19 +9799,16 @@ class TwPaginationComponent {
9799
9799
  const rightSiblingIndex = Math.min(current + siblings, total);
9800
9800
  const showLeftEllipsis = leftSiblingIndex > 2;
9801
9801
  const showRightEllipsis = rightSiblingIndex < total - 1;
9802
- // Use unique ellipsis identifiers to avoid duplicate keys in @for tracking
9803
- const LEFT_ELLIPSIS = '...left';
9804
- const RIGHT_ELLIPSIS = '...right';
9805
9802
  if (!showLeftEllipsis && showRightEllipsis) {
9806
9803
  const leftRange = range(1, 3 + siblings * 2);
9807
- return [...leftRange.map(String), RIGHT_ELLIPSIS, String(total)];
9804
+ return [...leftRange.map(String), '...', String(total)];
9808
9805
  }
9809
9806
  if (showLeftEllipsis && !showRightEllipsis) {
9810
9807
  const rightRange = range(total - (3 + siblings * 2) + 1, total);
9811
- return ['1', LEFT_ELLIPSIS, ...rightRange.map(String)];
9808
+ return ['1', '...', ...rightRange.map(String)];
9812
9809
  }
9813
9810
  const middleRange = range(leftSiblingIndex, rightSiblingIndex);
9814
- return ['1', LEFT_ELLIPSIS, ...middleRange.map(String), RIGHT_ELLIPSIS, String(total)];
9811
+ return ['1', '...', ...middleRange.map(String), '...', String(total)];
9815
9812
  }, ...(ngDevMode ? [{ debugName: "visiblePages" }] : []));
9816
9813
  goToPage(page) {
9817
9814
  if (page >= 1 && page <= this.totalPagesValue() && page !== this._currentPage()) {
@@ -9886,11 +9883,11 @@ class TwPaginationComponent {
9886
9883
  return baseClasses.join(' ');
9887
9884
  }
9888
9885
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TwPaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9889
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: TwPaginationComponent, isStandalone: true, selector: "tw-pagination", inputs: { currentPage: "currentPage", totalPages: "totalPages", totalItems: "totalItems", itemsPerPage: "itemsPerPage", siblingCount: "siblingCount", size: "size", variant: "variant", showFirstLast: "showFirstLast" }, outputs: { pageChange: "pageChange" }, ngImport: i0, template: "@switch (variantValue()) {\n @case ('simple') {\n <div class=\"flex items-center justify-between\">\n <button\n type=\"button\"\n [disabled]=\"currentPageValue() <= 1\"\n [class]=\"simpleButtonClasses(currentPageValue() <= 1)\"\n (click)=\"goToPage(currentPageValue() - 1)\"\n >\n <svg\n class=\"w-5 h-5 mr-1\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n Previous\n </button>\n <span class=\"text-sm text-slate-600\">\n Page {{ currentPageValue() }} of {{ totalPagesValue() }}\n </span>\n <button\n type=\"button\"\n [disabled]=\"currentPageValue() >= totalPagesValue()\"\n [class]=\"simpleButtonClasses(currentPageValue() >= totalPagesValue())\"\n (click)=\"goToPage(currentPageValue() + 1)\"\n >\n Next\n <svg\n class=\"w-5 h-5 ml-1\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n </div>\n }\n @default {\n <nav class=\"flex items-center gap-1\" aria-label=\"Pagination\">\n <!-- Previous -->\n <button\n type=\"button\"\n [disabled]=\"currentPageValue() <= 1\"\n [class]=\"navButtonClasses(currentPageValue() <= 1)\"\n (click)=\"goToPage(currentPageValue() - 1)\"\n aria-label=\"Previous page\"\n >\n <svg class=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n\n <!-- Page numbers -->\n @for (page of visiblePages(); track page) {\n @if (page.startsWith('...')) {\n <span [class]=\"ellipsisClasses()\">...</span>\n } @else {\n <button\n type=\"button\"\n [class]=\"pageButtonClasses(+page === currentPageValue())\"\n [attr.aria-current]=\"+page === currentPageValue() ? 'page' : null\"\n (click)=\"goToPage(+page)\"\n >\n {{ page }}\n </button>\n }\n }\n\n <!-- Next -->\n <button\n type=\"button\"\n [disabled]=\"currentPageValue() >= totalPagesValue()\"\n [class]=\"navButtonClasses(currentPageValue() >= totalPagesValue())\"\n (click)=\"goToPage(currentPageValue() + 1)\"\n aria-label=\"Next page\"\n >\n <svg class=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n </nav>\n }\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
9886
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: TwPaginationComponent, isStandalone: true, selector: "tw-pagination", inputs: { currentPage: "currentPage", totalPages: "totalPages", totalItems: "totalItems", itemsPerPage: "itemsPerPage", siblingCount: "siblingCount", size: "size", variant: "variant", showFirstLast: "showFirstLast" }, outputs: { pageChange: "pageChange" }, ngImport: i0, template: "@switch (variantValue()) {\n @case ('simple') {\n <div class=\"flex items-center justify-between\">\n <button\n type=\"button\"\n [disabled]=\"currentPageValue() <= 1\"\n [class]=\"simpleButtonClasses(currentPageValue() <= 1)\"\n (click)=\"goToPage(currentPageValue() - 1)\"\n >\n <svg\n class=\"w-5 h-5 mr-1\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n Previous\n </button>\n <span class=\"text-sm text-slate-600\">\n Page {{ currentPageValue() }} of {{ totalPagesValue() }}\n </span>\n <button\n type=\"button\"\n [disabled]=\"currentPageValue() >= totalPagesValue()\"\n [class]=\"simpleButtonClasses(currentPageValue() >= totalPagesValue())\"\n (click)=\"goToPage(currentPageValue() + 1)\"\n >\n Next\n <svg\n class=\"w-5 h-5 ml-1\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n </div>\n }\n @default {\n <nav class=\"flex items-center gap-1\" aria-label=\"Pagination\">\n <!-- Previous -->\n <button\n type=\"button\"\n [disabled]=\"currentPageValue() <= 1\"\n [class]=\"navButtonClasses(currentPageValue() <= 1)\"\n (click)=\"goToPage(currentPageValue() - 1)\"\n aria-label=\"Previous page\"\n >\n <svg class=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n\n <!-- Page numbers -->\n @for (page of visiblePages(); track page) {\n @if (page === '...') {\n <span [class]=\"ellipsisClasses()\">...</span>\n } @else {\n <button\n type=\"button\"\n [class]=\"pageButtonClasses(+page === currentPageValue())\"\n [attr.aria-current]=\"+page === currentPageValue() ? 'page' : null\"\n (click)=\"goToPage(+page)\"\n >\n {{ page }}\n </button>\n }\n }\n\n <!-- Next -->\n <button\n type=\"button\"\n [disabled]=\"currentPageValue() >= totalPagesValue()\"\n [class]=\"navButtonClasses(currentPageValue() >= totalPagesValue())\"\n (click)=\"goToPage(currentPageValue() + 1)\"\n aria-label=\"Next page\"\n >\n <svg class=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n </nav>\n }\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
9890
9887
  }
9891
9888
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TwPaginationComponent, decorators: [{
9892
9889
  type: Component,
9893
- args: [{ selector: 'tw-pagination', standalone: true, imports: [CommonModule], template: "@switch (variantValue()) {\n @case ('simple') {\n <div class=\"flex items-center justify-between\">\n <button\n type=\"button\"\n [disabled]=\"currentPageValue() <= 1\"\n [class]=\"simpleButtonClasses(currentPageValue() <= 1)\"\n (click)=\"goToPage(currentPageValue() - 1)\"\n >\n <svg\n class=\"w-5 h-5 mr-1\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n Previous\n </button>\n <span class=\"text-sm text-slate-600\">\n Page {{ currentPageValue() }} of {{ totalPagesValue() }}\n </span>\n <button\n type=\"button\"\n [disabled]=\"currentPageValue() >= totalPagesValue()\"\n [class]=\"simpleButtonClasses(currentPageValue() >= totalPagesValue())\"\n (click)=\"goToPage(currentPageValue() + 1)\"\n >\n Next\n <svg\n class=\"w-5 h-5 ml-1\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n </div>\n }\n @default {\n <nav class=\"flex items-center gap-1\" aria-label=\"Pagination\">\n <!-- Previous -->\n <button\n type=\"button\"\n [disabled]=\"currentPageValue() <= 1\"\n [class]=\"navButtonClasses(currentPageValue() <= 1)\"\n (click)=\"goToPage(currentPageValue() - 1)\"\n aria-label=\"Previous page\"\n >\n <svg class=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n\n <!-- Page numbers -->\n @for (page of visiblePages(); track page) {\n @if (page.startsWith('...')) {\n <span [class]=\"ellipsisClasses()\">...</span>\n } @else {\n <button\n type=\"button\"\n [class]=\"pageButtonClasses(+page === currentPageValue())\"\n [attr.aria-current]=\"+page === currentPageValue() ? 'page' : null\"\n (click)=\"goToPage(+page)\"\n >\n {{ page }}\n </button>\n }\n }\n\n <!-- Next -->\n <button\n type=\"button\"\n [disabled]=\"currentPageValue() >= totalPagesValue()\"\n [class]=\"navButtonClasses(currentPageValue() >= totalPagesValue())\"\n (click)=\"goToPage(currentPageValue() + 1)\"\n aria-label=\"Next page\"\n >\n <svg class=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n </nav>\n }\n}\n" }]
9890
+ args: [{ selector: 'tw-pagination', standalone: true, imports: [CommonModule], template: "@switch (variantValue()) {\n @case ('simple') {\n <div class=\"flex items-center justify-between\">\n <button\n type=\"button\"\n [disabled]=\"currentPageValue() <= 1\"\n [class]=\"simpleButtonClasses(currentPageValue() <= 1)\"\n (click)=\"goToPage(currentPageValue() - 1)\"\n >\n <svg\n class=\"w-5 h-5 mr-1\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n Previous\n </button>\n <span class=\"text-sm text-slate-600\">\n Page {{ currentPageValue() }} of {{ totalPagesValue() }}\n </span>\n <button\n type=\"button\"\n [disabled]=\"currentPageValue() >= totalPagesValue()\"\n [class]=\"simpleButtonClasses(currentPageValue() >= totalPagesValue())\"\n (click)=\"goToPage(currentPageValue() + 1)\"\n >\n Next\n <svg\n class=\"w-5 h-5 ml-1\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n </div>\n }\n @default {\n <nav class=\"flex items-center gap-1\" aria-label=\"Pagination\">\n <!-- Previous -->\n <button\n type=\"button\"\n [disabled]=\"currentPageValue() <= 1\"\n [class]=\"navButtonClasses(currentPageValue() <= 1)\"\n (click)=\"goToPage(currentPageValue() - 1)\"\n aria-label=\"Previous page\"\n >\n <svg class=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n\n <!-- Page numbers -->\n @for (page of visiblePages(); track page) {\n @if (page === '...') {\n <span [class]=\"ellipsisClasses()\">...</span>\n } @else {\n <button\n type=\"button\"\n [class]=\"pageButtonClasses(+page === currentPageValue())\"\n [attr.aria-current]=\"+page === currentPageValue() ? 'page' : null\"\n (click)=\"goToPage(+page)\"\n >\n {{ page }}\n </button>\n }\n }\n\n <!-- Next -->\n <button\n type=\"button\"\n [disabled]=\"currentPageValue() >= totalPagesValue()\"\n [class]=\"navButtonClasses(currentPageValue() >= totalPagesValue())\"\n (click)=\"goToPage(currentPageValue() + 1)\"\n aria-label=\"Next page\"\n >\n <svg class=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n </nav>\n }\n}\n" }]
9894
9891
  }], propDecorators: { currentPage: [{
9895
9892
  type: Input
9896
9893
  }], totalPages: [{
@@ -13210,8 +13207,6 @@ class TwVolumeDialComponent {
13210
13207
  a11y = inject(MusicAccessibilityService);
13211
13208
  dialSvg = viewChild('dialSvg', ...(ngDevMode ? [{ debugName: "dialSvg" }] : []));
13212
13209
  // Inputs
13213
- /** Initial/bound value - supports two-way binding with [(value)] */
13214
- value = model(0, ...(ngDevMode ? [{ debugName: "value" }] : []));
13215
13210
  min = input(0, ...(ngDevMode ? [{ debugName: "min" }] : []));
13216
13211
  max = input(100, ...(ngDevMode ? [{ debugName: "max" }] : []));
13217
13212
  step = input(1, ...(ngDevMode ? [{ debugName: "step" }] : []));
@@ -13238,8 +13233,10 @@ class TwVolumeDialComponent {
13238
13233
  announceChanges = input(true, ...(ngDevMode ? [{ debugName: "announceChanges" }] : [])); // Announce value changes to screen readers
13239
13234
  reducedMotion = input('auto', ...(ngDevMode ? [{ debugName: "reducedMotion" }] : [])); // Respect reduced motion preference
13240
13235
  // Outputs
13241
- // Note: valueChange is automatically created by the model() signal
13236
+ valueChange = output();
13242
13237
  hapticTrigger = output(); // Haptic feedback trigger points
13238
+ // Internal state
13239
+ value = signal(0, ...(ngDevMode ? [{ debugName: "value" }] : []));
13243
13240
  isDragging = false;
13244
13241
  startAngle = 0;
13245
13242
  startValue = 0;
@@ -13490,6 +13487,7 @@ class TwVolumeDialComponent {
13490
13487
  if (newValue !== this.value()) {
13491
13488
  this.value.set(newValue);
13492
13489
  this.onChangeFn(newValue);
13490
+ this.valueChange.emit(newValue);
13493
13491
  // Announce to screen readers (debounced)
13494
13492
  if (this.announceChanges()) {
13495
13493
  this.a11y.announceValueChange(this.label() || 'Volume', this.displayValue(), this.unit());
@@ -13510,7 +13508,7 @@ class TwVolumeDialComponent {
13510
13508
  // Disabled state is handled via input
13511
13509
  }
13512
13510
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TwVolumeDialComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
13513
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: TwVolumeDialComponent, isStandalone: true, selector: "tw-volume-dial", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showValue: { classPropertyName: "showValue", publicName: "showValue", isSignal: true, isRequired: false, transformFunction: null }, showTicks: { classPropertyName: "showTicks", publicName: "showTicks", isSignal: true, isRequired: false, transformFunction: null }, showLabel: { classPropertyName: "showLabel", publicName: "showLabel", isSignal: true, isRequired: false, transformFunction: null }, showLedRing: { classPropertyName: "showLedRing", publicName: "showLedRing", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, unit: { classPropertyName: "unit", publicName: "unit", isSignal: true, isRequired: false, transformFunction: null }, centerDetent: { classPropertyName: "centerDetent", publicName: "centerDetent", isSignal: true, isRequired: false, transformFunction: null }, detentValue: { classPropertyName: "detentValue", publicName: "detentValue", isSignal: true, isRequired: false, transformFunction: null }, classOverride: { classPropertyName: "classOverride", publicName: "classOverride", isSignal: true, isRequired: false, transformFunction: null }, customSize: { classPropertyName: "customSize", publicName: "customSize", isSignal: true, isRequired: false, transformFunction: null }, customStrokeWidth: { classPropertyName: "customStrokeWidth", publicName: "customStrokeWidth", isSignal: true, isRequired: false, transformFunction: null }, hapticFeedback: { classPropertyName: "hapticFeedback", publicName: "hapticFeedback", isSignal: true, isRequired: false, transformFunction: null }, touchGuard: { classPropertyName: "touchGuard", publicName: "touchGuard", isSignal: true, isRequired: false, transformFunction: null }, minTouchDuration: { classPropertyName: "minTouchDuration", publicName: "minTouchDuration", isSignal: true, isRequired: false, transformFunction: null }, announceChanges: { classPropertyName: "announceChanges", publicName: "announceChanges", isSignal: true, isRequired: false, transformFunction: null }, reducedMotion: { classPropertyName: "reducedMotion", publicName: "reducedMotion", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", hapticTrigger: "hapticTrigger" }, host: { classAttribute: "inline-block" }, providers: [
13511
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: TwVolumeDialComponent, isStandalone: true, selector: "tw-volume-dial", inputs: { min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showValue: { classPropertyName: "showValue", publicName: "showValue", isSignal: true, isRequired: false, transformFunction: null }, showTicks: { classPropertyName: "showTicks", publicName: "showTicks", isSignal: true, isRequired: false, transformFunction: null }, showLabel: { classPropertyName: "showLabel", publicName: "showLabel", isSignal: true, isRequired: false, transformFunction: null }, showLedRing: { classPropertyName: "showLedRing", publicName: "showLedRing", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, unit: { classPropertyName: "unit", publicName: "unit", isSignal: true, isRequired: false, transformFunction: null }, centerDetent: { classPropertyName: "centerDetent", publicName: "centerDetent", isSignal: true, isRequired: false, transformFunction: null }, detentValue: { classPropertyName: "detentValue", publicName: "detentValue", isSignal: true, isRequired: false, transformFunction: null }, classOverride: { classPropertyName: "classOverride", publicName: "classOverride", isSignal: true, isRequired: false, transformFunction: null }, customSize: { classPropertyName: "customSize", publicName: "customSize", isSignal: true, isRequired: false, transformFunction: null }, customStrokeWidth: { classPropertyName: "customStrokeWidth", publicName: "customStrokeWidth", isSignal: true, isRequired: false, transformFunction: null }, hapticFeedback: { classPropertyName: "hapticFeedback", publicName: "hapticFeedback", isSignal: true, isRequired: false, transformFunction: null }, touchGuard: { classPropertyName: "touchGuard", publicName: "touchGuard", isSignal: true, isRequired: false, transformFunction: null }, minTouchDuration: { classPropertyName: "minTouchDuration", publicName: "minTouchDuration", isSignal: true, isRequired: false, transformFunction: null }, announceChanges: { classPropertyName: "announceChanges", publicName: "announceChanges", isSignal: true, isRequired: false, transformFunction: null }, reducedMotion: { classPropertyName: "reducedMotion", publicName: "reducedMotion", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", hapticTrigger: "hapticTrigger" }, host: { classAttribute: "inline-block" }, providers: [
13514
13512
  {
13515
13513
  provide: NG_VALUE_ACCESSOR,
13516
13514
  useExisting: forwardRef(() => TwVolumeDialComponent),
@@ -13529,7 +13527,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
13529
13527
  ], host: {
13530
13528
  class: 'inline-block',
13531
13529
  }, template: "<div\n [class]=\"containerClasses()\"\n [style.width.px]=\"sizeConfig().size\"\n [style.height.px]=\"sizeConfig().size + (showValue() ? 24 : 0)\"\n>\n <!-- SVG Dial -->\n <svg\n #dialSvg\n [attr.width]=\"sizeConfig().size\"\n [attr.height]=\"sizeConfig().size\"\n [attr.viewBox]=\"'0 0 ' + sizeConfig().size + ' ' + sizeConfig().size\"\n class=\"cursor-pointer select-none\"\n [class.opacity-50]=\"disabled()\"\n [class.cursor-not-allowed]=\"disabled()\"\n (mousedown)=\"onMouseDown($event)\"\n (touchstart)=\"onTouchStart($event)\"\n (keydown)=\"onKeyDown($event)\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n role=\"slider\"\n [attr.aria-valuenow]=\"value()\"\n [attr.aria-valuemin]=\"min()\"\n [attr.aria-valuemax]=\"max()\"\n [attr.aria-label]=\"label() || 'Volume dial'\"\n [attr.aria-disabled]=\"disabled()\"\n >\n <!-- Track (background arc) -->\n <path\n [attr.d]=\"trackPath()\"\n fill=\"none\"\n [attr.stroke-width]=\"sizeConfig().strokeWidth\"\n [class]=\"variantConfig().track\"\n stroke-linecap=\"round\"\n />\n\n <!-- Fill (value arc) -->\n <path\n [attr.d]=\"fillPath()\"\n fill=\"none\"\n [attr.stroke-width]=\"sizeConfig().strokeWidth\"\n [class]=\"variantConfig().fill\"\n stroke-linecap=\"round\"\n />\n\n <!-- Tick marks -->\n @if (showTicks()) {\n @for (tick of tickMarks(); track tick.angle) {\n <line\n [attr.x1]=\"tick.x1\"\n [attr.y1]=\"tick.y1\"\n [attr.x2]=\"tick.x2\"\n [attr.y2]=\"tick.y2\"\n [class]=\"\n tick.isMajor\n ? 'stroke-slate-400 dark:stroke-slate-500'\n : 'stroke-slate-300 dark:stroke-slate-600'\n \"\n [attr.stroke-width]=\"tick.isMajor ? 2 : 1\"\n />\n }\n }\n\n <!-- Knob center -->\n <circle\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.r]=\"knobRadius()\"\n [class]=\"variantConfig().knob\"\n stroke-width=\"2\"\n />\n\n <!-- Indicator line -->\n <line\n [attr.x1]=\"center()\"\n [attr.y1]=\"center()\"\n [attr.x2]=\"indicatorEnd().x\"\n [attr.y2]=\"indicatorEnd().y\"\n [class]=\"variantConfig().indicator\"\n [attr.stroke-width]=\"sizeConfig().strokeWidth - 1\"\n stroke-linecap=\"round\"\n />\n\n <!-- LED ring (for led variant) -->\n @if (variant() === 'led' && showLedRing()) {\n @for (led of ledSegments(); track led.index) {\n <circle\n [attr.cx]=\"led.x\"\n [attr.cy]=\"led.y\"\n [attr.r]=\"3\"\n [class]=\"led.active ? 'fill-emerald-400' : 'fill-slate-700'\"\n />\n }\n }\n </svg>\n\n <!-- Value display -->\n @if (showValue()) {\n <div [class]=\"valueClasses()\">{{ displayValue() }}{{ unit() }}</div>\n }\n\n <!-- Label -->\n @if (label() && showLabel()) {\n <div\n class=\"absolute -bottom-6 left-1/2 -translate-x-1/2 text-xs text-slate-500 dark:text-slate-400 whitespace-nowrap\"\n >\n {{ label() }}\n </div>\n }\n</div>\n" }]
13532
- }], propDecorators: { dialSvg: [{ type: i0.ViewChild, args: ['dialSvg', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], showTicks: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTicks", required: false }] }], showLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLabel", required: false }] }], showLedRing: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLedRing", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], unit: [{ type: i0.Input, args: [{ isSignal: true, alias: "unit", required: false }] }], centerDetent: [{ type: i0.Input, args: [{ isSignal: true, alias: "centerDetent", required: false }] }], detentValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "detentValue", required: false }] }], classOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "classOverride", required: false }] }], customSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "customSize", required: false }] }], customStrokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "customStrokeWidth", required: false }] }], hapticFeedback: [{ type: i0.Input, args: [{ isSignal: true, alias: "hapticFeedback", required: false }] }], touchGuard: [{ type: i0.Input, args: [{ isSignal: true, alias: "touchGuard", required: false }] }], minTouchDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "minTouchDuration", required: false }] }], announceChanges: [{ type: i0.Input, args: [{ isSignal: true, alias: "announceChanges", required: false }] }], reducedMotion: [{ type: i0.Input, args: [{ isSignal: true, alias: "reducedMotion", required: false }] }], hapticTrigger: [{ type: i0.Output, args: ["hapticTrigger"] }] } });
13530
+ }], propDecorators: { dialSvg: [{ type: i0.ViewChild, args: ['dialSvg', { isSignal: true }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], showTicks: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTicks", required: false }] }], showLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLabel", required: false }] }], showLedRing: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLedRing", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], unit: [{ type: i0.Input, args: [{ isSignal: true, alias: "unit", required: false }] }], centerDetent: [{ type: i0.Input, args: [{ isSignal: true, alias: "centerDetent", required: false }] }], detentValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "detentValue", required: false }] }], classOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "classOverride", required: false }] }], customSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "customSize", required: false }] }], customStrokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "customStrokeWidth", required: false }] }], hapticFeedback: [{ type: i0.Input, args: [{ isSignal: true, alias: "hapticFeedback", required: false }] }], touchGuard: [{ type: i0.Input, args: [{ isSignal: true, alias: "touchGuard", required: false }] }], minTouchDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "minTouchDuration", required: false }] }], announceChanges: [{ type: i0.Input, args: [{ isSignal: true, alias: "announceChanges", required: false }] }], reducedMotion: [{ type: i0.Input, args: [{ isSignal: true, alias: "reducedMotion", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], hapticTrigger: [{ type: i0.Output, args: ["hapticTrigger"] }] } });
13533
13531
 
13534
13532
  // RMS calculation window size (samples)
13535
13533
  const RMS_WINDOW_SIZE = 1024;
@@ -19135,7 +19133,7 @@ class TwChannelStripComponent {
19135
19133
  useExisting: forwardRef(() => TwChannelStripComponent),
19136
19134
  multi: true,
19137
19135
  },
19138
- ], ngImport: i0, template: "<div [class]=\"containerClasses()\">\n <!-- Channel Label with Signal Indicator -->\n @if (showLabel()) {\n <div [class]=\"labelClasses()\" class=\"relative flex items-center justify-center gap-1\">\n <!-- Signal Present Indicator -->\n @if (showSignalIndicator()) {\n <div\n class=\"w-2 h-2 rounded-full transition-all duration-150\"\n [class.bg-green-500]=\"signalPresent()\"\n [class.shadow-[0_0_6px_rgba(34,197,94,0.8)]]=\"signalPresent()\"\n [class.bg-slate-600]=\"!signalPresent()\"\n title=\"Signal Present\"\n ></div>\n }\n <span class=\"text-slate-400\">{{ channelNumber() }}</span>\n <span class=\"text-white\">{{ label() }}</span>\n </div>\n }\n\n <!-- Input Gain Control -->\n @if (showInputGain()) {\n <div class=\"flex flex-col items-center gap-1\">\n <tw-volume-dial\n [ngModel]=\"inputGain()\"\n (ngModelChange)=\"onInputGainChange($event)\"\n [min]=\"-20\"\n [max]=\"20\"\n [step]=\"1\"\n [size]=\"size() === 'lg' ? 'sm' : 'xs'\"\n [variant]=\"variant() === 'vintage' ? 'vintage' : 'minimal'\"\n [disabled]=\"disabled()\"\n [centerDetent]=\"true\"\n [detentValue]=\"0\"\n label=\"\"\n [showValue]=\"false\"\n ></tw-volume-dial>\n <span class=\"text-[9px] text-slate-500 font-mono\">{{ formatGain(inputGain()) }}dB</span>\n <span class=\"text-[8px] text-slate-600\">GAIN</span>\n </div>\n }\n\n <!-- Record Button -->\n @if (showRecord()) {\n <button\n type=\"button\"\n [class]=\"buttonSize()\"\n class=\"rounded-full flex items-center justify-center font-bold transition-all\"\n [class.bg-red-600]=\"record()\"\n [class.text-white]=\"record()\"\n [class.bg-slate-700]=\"!record()\"\n [class.text-slate-400]=\"!record()\"\n [class.hover:bg-red-500]=\"!record()\"\n [class.animate-pulse]=\"record()\"\n [disabled]=\"disabled()\"\n (click)=\"toggleRecord()\"\n title=\"Record Arm\"\n >\n R\n </button>\n }\n\n <!-- Aux Send Knobs -->\n @if (showAuxSends()) {\n <div class=\"flex flex-col gap-1 w-full border-t border-slate-700/50 pt-2\">\n <span class=\"text-[8px] text-slate-500 text-center\">SENDS</span>\n <div\n class=\"grid gap-1\"\n [class.grid-cols-2]=\"auxSendCount() > 2\"\n [class.grid-cols-1]=\"auxSendCount() <= 2\"\n >\n @for (aux of auxSendArray(); track aux.index) {\n <div class=\"flex flex-col items-center\">\n <tw-volume-dial\n [ngModel]=\"aux.value\"\n (ngModelChange)=\"onAuxSendChange(aux.index, $event)\"\n [min]=\"0\"\n [max]=\"100\"\n [step]=\"1\"\n size=\"xs\"\n [variant]=\"variant() === 'vintage' ? 'vintage' : 'minimal'\"\n [disabled]=\"disabled() || mute()\"\n label=\"\"\n [showValue]=\"false\"\n ></tw-volume-dial>\n <span class=\"text-[8px] text-slate-500 truncate max-w-full\">{{ aux.label }}</span>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- VU Meter -->\n @if (showMeter()) {\n <div class=\"flex-1 flex items-center justify-center py-1\">\n @if (stereo()) {\n <tw-vu-meter\n [leftValue]=\"meterLevel()\"\n [rightValue]=\"meterLevelRight()\"\n [stereo]=\"true\"\n [segmentCount]=\"size() === 'sm' ? 8 : 12\"\n [height]=\"size() === 'sm' ? 60 : size() === 'lg' ? 100 : 80\"\n variant=\"led\"\n ></tw-vu-meter>\n } @else {\n <tw-vu-meter\n [value]=\"meterLevel()\"\n [segmentCount]=\"size() === 'sm' ? 8 : 12\"\n [height]=\"size() === 'sm' ? 60 : size() === 'lg' ? 100 : 80\"\n variant=\"led\"\n ></tw-vu-meter>\n }\n </div>\n }\n\n <!-- Volume Fader / Dial -->\n <tw-volume-dial\n [ngModel]=\"volume()\"\n (ngModelChange)=\"onVolumeChange($event)\"\n [min]=\"0\"\n [max]=\"100\"\n [step]=\"1\"\n [size]=\"dialSize()\"\n [variant]=\"variant() === 'vintage' ? 'vintage' : 'modern'\"\n [disabled]=\"disabled() || mute()\"\n label=\"\"\n [showValue]=\"size() !== 'sm'\"\n ></tw-volume-dial>\n\n <!-- Pan Control -->\n @if (showPan()) {\n <tw-volume-dial\n [ngModel]=\"pan()\"\n (ngModelChange)=\"onPanChange($event)\"\n [min]=\"-100\"\n [max]=\"100\"\n [step]=\"1\"\n [size]=\"size() === 'lg' ? 'md' : 'sm'\"\n [variant]=\"variant() === 'vintage' ? 'vintage' : 'minimal'\"\n [disabled]=\"disabled()\"\n [centerDetent]=\"true\"\n [detentValue]=\"0\"\n label=\"\"\n [showValue]=\"false\"\n ></tw-volume-dial>\n <span class=\"text-[10px] text-slate-500\">PAN</span>\n }\n\n <!-- Mute / Solo Buttons -->\n @if (showMuteSolo()) {\n <div class=\"flex gap-1\">\n <button\n type=\"button\"\n [class]=\"buttonSize()\"\n class=\"rounded flex items-center justify-center font-bold transition-all\"\n [class.bg-amber-500]=\"mute()\"\n [class.text-black]=\"mute()\"\n [class.bg-slate-700]=\"!mute()\"\n [class.text-slate-400]=\"!mute()\"\n [class.hover:bg-amber-400]=\"!mute()\"\n [disabled]=\"disabled()\"\n (click)=\"toggleMute()\"\n title=\"Mute\"\n >\n M\n </button>\n <button\n type=\"button\"\n [class]=\"buttonSize()\"\n class=\"rounded flex items-center justify-center font-bold transition-all\"\n [class.bg-green-500]=\"solo()\"\n [class.text-black]=\"solo()\"\n [class.bg-slate-700]=\"!solo()\"\n [class.text-slate-400]=\"!solo()\"\n [class.hover:bg-green-400]=\"!solo()\"\n [disabled]=\"disabled()\"\n (click)=\"toggleSolo()\"\n title=\"Solo\"\n >\n S\n </button>\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: TwVolumeDialComponent, selector: "tw-volume-dial", inputs: ["value", "min", "max", "step", "variant", "size", "disabled", "showValue", "showTicks", "showLabel", "showLedRing", "label", "unit", "centerDetent", "detentValue", "classOverride", "customSize", "customStrokeWidth", "hapticFeedback", "touchGuard", "minTouchDuration", "announceChanges", "reducedMotion"], outputs: ["valueChange", "hapticTrigger"] }, { kind: "component", type: TwVuMeterComponent, selector: "tw-vu-meter", inputs: ["value", "leftValue", "rightValue", "min", "max", "stereo", "variant", "orientation", "meterMode", "segmentCount", "height", "width", "barWidth", "gapSize", "rmsDecayRate", "customHeight", "customWidth", "customBarWidth", "customGapSize", "showPeak", "peakHoldTime", "peakDecayRate", "showClip", "clipThreshold", "showScale", "showChannelLabels", "label", "labelPosition", "yellowThreshold", "redThreshold", "classOverride"], outputs: ["clipDetected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
19136
+ ], ngImport: i0, template: "<div [class]=\"containerClasses()\">\n <!-- Channel Label with Signal Indicator -->\n @if (showLabel()) {\n <div [class]=\"labelClasses()\" class=\"relative flex items-center justify-center gap-1\">\n <!-- Signal Present Indicator -->\n @if (showSignalIndicator()) {\n <div\n class=\"w-2 h-2 rounded-full transition-all duration-150\"\n [class.bg-green-500]=\"signalPresent()\"\n [class.shadow-[0_0_6px_rgba(34,197,94,0.8)]]=\"signalPresent()\"\n [class.bg-slate-600]=\"!signalPresent()\"\n title=\"Signal Present\"\n ></div>\n }\n <span class=\"text-slate-400\">{{ channelNumber() }}</span>\n <span class=\"text-white\">{{ label() }}</span>\n </div>\n }\n\n <!-- Input Gain Control -->\n @if (showInputGain()) {\n <div class=\"flex flex-col items-center gap-1\">\n <tw-volume-dial\n [ngModel]=\"inputGain()\"\n (ngModelChange)=\"onInputGainChange($event)\"\n [min]=\"-20\"\n [max]=\"20\"\n [step]=\"1\"\n [size]=\"size() === 'lg' ? 'sm' : 'xs'\"\n [variant]=\"variant() === 'vintage' ? 'vintage' : 'minimal'\"\n [disabled]=\"disabled()\"\n [centerDetent]=\"true\"\n [detentValue]=\"0\"\n label=\"\"\n [showValue]=\"false\"\n ></tw-volume-dial>\n <span class=\"text-[9px] text-slate-500 font-mono\">{{ formatGain(inputGain()) }}dB</span>\n <span class=\"text-[8px] text-slate-600\">GAIN</span>\n </div>\n }\n\n <!-- Record Button -->\n @if (showRecord()) {\n <button\n type=\"button\"\n [class]=\"buttonSize()\"\n class=\"rounded-full flex items-center justify-center font-bold transition-all\"\n [class.bg-red-600]=\"record()\"\n [class.text-white]=\"record()\"\n [class.bg-slate-700]=\"!record()\"\n [class.text-slate-400]=\"!record()\"\n [class.hover:bg-red-500]=\"!record()\"\n [class.animate-pulse]=\"record()\"\n [disabled]=\"disabled()\"\n (click)=\"toggleRecord()\"\n title=\"Record Arm\"\n >\n R\n </button>\n }\n\n <!-- Aux Send Knobs -->\n @if (showAuxSends()) {\n <div class=\"flex flex-col gap-1 w-full border-t border-slate-700/50 pt-2\">\n <span class=\"text-[8px] text-slate-500 text-center\">SENDS</span>\n <div\n class=\"grid gap-1\"\n [class.grid-cols-2]=\"auxSendCount() > 2\"\n [class.grid-cols-1]=\"auxSendCount() <= 2\"\n >\n @for (aux of auxSendArray(); track aux.index) {\n <div class=\"flex flex-col items-center\">\n <tw-volume-dial\n [ngModel]=\"aux.value\"\n (ngModelChange)=\"onAuxSendChange(aux.index, $event)\"\n [min]=\"0\"\n [max]=\"100\"\n [step]=\"1\"\n size=\"xs\"\n [variant]=\"variant() === 'vintage' ? 'vintage' : 'minimal'\"\n [disabled]=\"disabled() || mute()\"\n label=\"\"\n [showValue]=\"false\"\n ></tw-volume-dial>\n <span class=\"text-[8px] text-slate-500 truncate max-w-full\">{{ aux.label }}</span>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- VU Meter -->\n @if (showMeter()) {\n <div class=\"flex-1 flex items-center justify-center py-1\">\n @if (stereo()) {\n <tw-vu-meter\n [leftValue]=\"meterLevel()\"\n [rightValue]=\"meterLevelRight()\"\n [stereo]=\"true\"\n [segmentCount]=\"size() === 'sm' ? 8 : 12\"\n [height]=\"size() === 'sm' ? 60 : size() === 'lg' ? 100 : 80\"\n variant=\"led\"\n ></tw-vu-meter>\n } @else {\n <tw-vu-meter\n [value]=\"meterLevel()\"\n [segmentCount]=\"size() === 'sm' ? 8 : 12\"\n [height]=\"size() === 'sm' ? 60 : size() === 'lg' ? 100 : 80\"\n variant=\"led\"\n ></tw-vu-meter>\n }\n </div>\n }\n\n <!-- Volume Fader / Dial -->\n <tw-volume-dial\n [ngModel]=\"volume()\"\n (ngModelChange)=\"onVolumeChange($event)\"\n [min]=\"0\"\n [max]=\"100\"\n [step]=\"1\"\n [size]=\"dialSize()\"\n [variant]=\"variant() === 'vintage' ? 'vintage' : 'modern'\"\n [disabled]=\"disabled() || mute()\"\n label=\"\"\n [showValue]=\"size() !== 'sm'\"\n ></tw-volume-dial>\n\n <!-- Pan Control -->\n @if (showPan()) {\n <tw-volume-dial\n [ngModel]=\"pan()\"\n (ngModelChange)=\"onPanChange($event)\"\n [min]=\"-100\"\n [max]=\"100\"\n [step]=\"1\"\n [size]=\"size() === 'lg' ? 'md' : 'sm'\"\n [variant]=\"variant() === 'vintage' ? 'vintage' : 'minimal'\"\n [disabled]=\"disabled()\"\n [centerDetent]=\"true\"\n [detentValue]=\"0\"\n label=\"\"\n [showValue]=\"false\"\n ></tw-volume-dial>\n <span class=\"text-[10px] text-slate-500\">PAN</span>\n }\n\n <!-- Mute / Solo Buttons -->\n @if (showMuteSolo()) {\n <div class=\"flex gap-1\">\n <button\n type=\"button\"\n [class]=\"buttonSize()\"\n class=\"rounded flex items-center justify-center font-bold transition-all\"\n [class.bg-amber-500]=\"mute()\"\n [class.text-black]=\"mute()\"\n [class.bg-slate-700]=\"!mute()\"\n [class.text-slate-400]=\"!mute()\"\n [class.hover:bg-amber-400]=\"!mute()\"\n [disabled]=\"disabled()\"\n (click)=\"toggleMute()\"\n title=\"Mute\"\n >\n M\n </button>\n <button\n type=\"button\"\n [class]=\"buttonSize()\"\n class=\"rounded flex items-center justify-center font-bold transition-all\"\n [class.bg-green-500]=\"solo()\"\n [class.text-black]=\"solo()\"\n [class.bg-slate-700]=\"!solo()\"\n [class.text-slate-400]=\"!solo()\"\n [class.hover:bg-green-400]=\"!solo()\"\n [disabled]=\"disabled()\"\n (click)=\"toggleSolo()\"\n title=\"Solo\"\n >\n S\n </button>\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: TwVolumeDialComponent, selector: "tw-volume-dial", inputs: ["min", "max", "step", "variant", "size", "disabled", "showValue", "showTicks", "showLabel", "showLedRing", "label", "unit", "centerDetent", "detentValue", "classOverride", "customSize", "customStrokeWidth", "hapticFeedback", "touchGuard", "minTouchDuration", "announceChanges", "reducedMotion"], outputs: ["valueChange", "hapticTrigger"] }, { kind: "component", type: TwVuMeterComponent, selector: "tw-vu-meter", inputs: ["value", "leftValue", "rightValue", "min", "max", "stereo", "variant", "orientation", "meterMode", "segmentCount", "height", "width", "barWidth", "gapSize", "rmsDecayRate", "customHeight", "customWidth", "customBarWidth", "customGapSize", "showPeak", "peakHoldTime", "peakDecayRate", "showClip", "clipThreshold", "showScale", "showChannelLabels", "label", "labelPosition", "yellowThreshold", "redThreshold", "classOverride"], outputs: ["clipDetected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
19139
19137
  }
19140
19138
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TwChannelStripComponent, decorators: [{
19141
19139
  type: Component,
@@ -40180,7 +40178,7 @@ class TwTerminalComponent {
40180
40178
  // Computed classes
40181
40179
  containerClasses = computed(() => {
40182
40180
  const variant = this.variant();
40183
- const base = 'flex flex-col h-full overflow-hidden';
40181
+ const base = 'flex flex-col h-full overflow-hidden rounded-lg';
40184
40182
  const variantClasses = {
40185
40183
  default: 'bg-gray-900 text-gray-100',
40186
40184
  dark: 'bg-black text-gray-200',
@@ -40339,7 +40337,7 @@ class TwTerminalComponent {
40339
40337
  <!-- Input area -->
40340
40338
  @if (showInput()) {
40341
40339
  <div
40342
- class="flex items-center gap-2 px-4 py-2 border-t border-gray-700 bg-gray-800"
40340
+ class="flex items-center gap-2 px-4 py-2 border-t border-gray-700 bg-gray-800 rounded-b-lg"
40343
40341
  >
40344
40342
  <span class="text-green-400 font-mono">{{ prompt() }}</span>
40345
40343
  <input
@@ -40437,7 +40435,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
40437
40435
  <!-- Input area -->
40438
40436
  @if (showInput()) {
40439
40437
  <div
40440
- class="flex items-center gap-2 px-4 py-2 border-t border-gray-700 bg-gray-800"
40438
+ class="flex items-center gap-2 px-4 py-2 border-t border-gray-700 bg-gray-800 rounded-b-lg"
40441
40439
  >
40442
40440
  <span class="text-green-400 font-mono">{{ prompt() }}</span>
40443
40441
  <input
@@ -40567,7 +40565,7 @@ class TwLogViewerComponent {
40567
40565
  }
40568
40566
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TwLogViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
40569
40567
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: TwLogViewerComponent, isStandalone: true, selector: "tw-log-viewer", inputs: { entries: { classPropertyName: "entries", publicName: "entries", isSignal: true, isRequired: false, transformFunction: null }, showSource: { classPropertyName: "showSource", publicName: "showSource", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { entrySelect: "entrySelect", clearLogs: "clearLogs", exportClick: "exportClick" }, host: { classAttribute: "tw-log-viewer block" }, ngImport: i0, template: `
40570
- <div class="flex flex-col h-full bg-white dark:bg-gray-900 overflow-hidden">
40568
+ <div class="flex flex-col h-full bg-white dark:bg-gray-900 rounded-lg overflow-hidden">
40571
40569
  <!-- Toolbar -->
40572
40570
  <div
40573
40571
  class="flex items-center gap-2 px-3 py-2 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800"
@@ -40717,7 +40715,7 @@ class TwLogViewerComponent {
40717
40715
 
40718
40716
  <!-- Status bar -->
40719
40717
  <div
40720
- class="flex items-center justify-between px-3 py-1.5 text-xs text-gray-500 dark:text-gray-400 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800"
40718
+ class="flex items-center justify-between px-3 py-1.5 text-xs text-gray-500 dark:text-gray-400 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 rounded-b-lg"
40721
40719
  >
40722
40720
  <span>{{ filteredEntries().length }} / {{ entries().length }} entries</span>
40723
40721
  <span>
@@ -40738,7 +40736,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
40738
40736
  standalone: true,
40739
40737
  imports: [CommonModule, FormsModule],
40740
40738
  template: `
40741
- <div class="flex flex-col h-full bg-white dark:bg-gray-900 overflow-hidden">
40739
+ <div class="flex flex-col h-full bg-white dark:bg-gray-900 rounded-lg overflow-hidden">
40742
40740
  <!-- Toolbar -->
40743
40741
  <div
40744
40742
  class="flex items-center gap-2 px-3 py-2 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800"
@@ -40888,7 +40886,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
40888
40886
 
40889
40887
  <!-- Status bar -->
40890
40888
  <div
40891
- class="flex items-center justify-between px-3 py-1.5 text-xs text-gray-500 dark:text-gray-400 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800"
40889
+ class="flex items-center justify-between px-3 py-1.5 text-xs text-gray-500 dark:text-gray-400 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 rounded-b-lg"
40892
40890
  >
40893
40891
  <span>{{ filteredEntries().length }} / {{ entries().length }} entries</span>
40894
40892
  <span>
@@ -43424,149 +43422,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
43424
43422
  args: [{ providedIn: 'root' }]
43425
43423
  }], ctorParameters: () => [] });
43426
43424
 
43427
- /**
43428
- * Dynamic import utilities that prevent bundlers from analyzing/resolving the imports at build time.
43429
- *
43430
- * The trick is to use a variable for the module specifier, which makes it impossible for bundlers
43431
- * to statically analyze the import. This is intentional for optional dependencies like Electron and Tauri.
43432
- */
43433
- /* eslint-disable @typescript-eslint/no-explicit-any */
43434
- /**
43435
- * Creates a dynamic import function that bundlers cannot statically analyze.
43436
- * This prevents build errors for optional dependencies that may not be installed.
43437
- */
43438
- function createDynamicImport() {
43439
- // Use Function constructor to create import at runtime, preventing static analysis
43440
- return new Function('modulePath', 'return import(modulePath)');
43441
- }
43442
- const dynamicImport = createDynamicImport();
43443
- /**
43444
- * Dynamically import the Electron module.
43445
- * This will only work at runtime when running in an Electron context.
43446
- * Returns null if Electron is not available.
43447
- */
43448
- async function importElectron() {
43449
- try {
43450
- const electron = await dynamicImport('electron');
43451
- return electron;
43452
- }
43453
- catch {
43454
- return null;
43455
- }
43456
- }
43457
- /**
43458
- * Dynamically import Tauri dialog plugin.
43459
- * This will only work at runtime when running in a Tauri context.
43460
- * Returns null if Tauri dialog is not available.
43461
- */
43462
- async function importTauriDialog() {
43463
- try {
43464
- const dialog = await dynamicImport('@tauri-apps/plugin-dialog');
43465
- return dialog;
43466
- }
43467
- catch {
43468
- return null;
43469
- }
43470
- }
43471
- /**
43472
- * Dynamically import Tauri notification plugin.
43473
- * This will only work at runtime when running in a Tauri context.
43474
- * Returns null if Tauri notification is not available.
43475
- */
43476
- async function importTauriNotification() {
43477
- try {
43478
- const notification = await dynamicImport('@tauri-apps/plugin-notification');
43479
- return notification;
43480
- }
43481
- catch {
43482
- return null;
43483
- }
43484
- }
43485
- /**
43486
- * Dynamically import Tauri process plugin.
43487
- * This will only work at runtime when running in a Tauri context.
43488
- * Returns null if Tauri process is not available.
43489
- */
43490
- async function importTauriProcess() {
43491
- try {
43492
- const process = await dynamicImport('@tauri-apps/plugin-process');
43493
- return process;
43494
- }
43495
- catch {
43496
- return null;
43497
- }
43498
- }
43499
- /**
43500
- * Dynamically import Tauri updater plugin.
43501
- * This will only work at runtime when running in a Tauri context.
43502
- * Returns null if Tauri updater is not available.
43503
- */
43504
- async function importTauriUpdater() {
43505
- try {
43506
- const updater = await dynamicImport('@tauri-apps/plugin-updater');
43507
- return updater;
43508
- }
43509
- catch {
43510
- return null;
43511
- }
43512
- }
43513
- /**
43514
- * Dynamically import Tauri app API.
43515
- * This will only work at runtime when running in a Tauri context.
43516
- * Returns null if Tauri app is not available.
43517
- */
43518
- async function importTauriApp() {
43519
- try {
43520
- const app = await dynamicImport('@tauri-apps/api/app');
43521
- return app;
43522
- }
43523
- catch {
43524
- return null;
43525
- }
43526
- }
43527
- /**
43528
- * Dynamically import Tauri menu API.
43529
- * This will only work at runtime when running in a Tauri context.
43530
- * Returns null if Tauri menu is not available.
43531
- */
43532
- async function importTauriMenu() {
43533
- try {
43534
- const menu = await dynamicImport('@tauri-apps/api/menu');
43535
- return menu;
43536
- }
43537
- catch {
43538
- return null;
43539
- }
43540
- }
43541
- /**
43542
- * Dynamically import Tauri tray API.
43543
- * This will only work at runtime when running in a Tauri context.
43544
- * Returns null if Tauri tray is not available.
43545
- */
43546
- async function importTauriTray() {
43547
- try {
43548
- const tray = await dynamicImport('@tauri-apps/api/tray');
43549
- return tray;
43550
- }
43551
- catch {
43552
- return null;
43553
- }
43554
- }
43555
- /**
43556
- * Dynamically import Tauri window API.
43557
- * This will only work at runtime when running in a Tauri context.
43558
- * Returns null if Tauri window is not available.
43559
- */
43560
- async function importTauriWindow() {
43561
- try {
43562
- const window = await dynamicImport('@tauri-apps/api/window');
43563
- return window;
43564
- }
43565
- catch {
43566
- return null;
43567
- }
43568
- }
43569
-
43570
43425
  const PLATFORM_TAURI$4 = 'tauri';
43571
43426
  const PLATFORM_ELECTRON$4 = 'electron';
43572
43427
  class FilePickerService {
@@ -43609,14 +43464,12 @@ class FilePickerService {
43609
43464
  }
43610
43465
  async openFileTauri(options) {
43611
43466
  try {
43612
- const dialog = await importTauriDialog();
43613
- if (!dialog)
43614
- return null;
43467
+ const { open } = await import('@tauri-apps/plugin-dialog');
43615
43468
  const filters = options.filters?.map(f => ({
43616
43469
  name: f.name,
43617
43470
  extensions: f.extensions,
43618
43471
  }));
43619
- const result = await dialog.open({
43472
+ const result = await open({
43620
43473
  title: options.title,
43621
43474
  defaultPath: options.defaultPath,
43622
43475
  filters,
@@ -43640,10 +43493,8 @@ class FilePickerService {
43640
43493
  }
43641
43494
  async openFileElectron(options) {
43642
43495
  try {
43643
- const electron = await importElectron();
43644
- if (!electron?.ipcRenderer)
43645
- return null;
43646
- const result = await electron.ipcRenderer.invoke('show-open-dialog', {
43496
+ const { ipcRenderer } = await import('electron');
43497
+ const result = await ipcRenderer.invoke('show-open-dialog', {
43647
43498
  title: options.title,
43648
43499
  defaultPath: options.defaultPath,
43649
43500
  properties: [
@@ -43703,14 +43554,12 @@ class FilePickerService {
43703
43554
  }
43704
43555
  async saveFileTauri(options) {
43705
43556
  try {
43706
- const dialog = await importTauriDialog();
43707
- if (!dialog)
43708
- return null;
43557
+ const { save } = await import('@tauri-apps/plugin-dialog');
43709
43558
  const filters = options.filters?.map(f => ({
43710
43559
  name: f.name,
43711
43560
  extensions: f.extensions,
43712
43561
  }));
43713
- const result = await dialog.save({
43562
+ const result = await save({
43714
43563
  title: options.title,
43715
43564
  defaultPath: options.defaultPath,
43716
43565
  filters,
@@ -43724,10 +43573,8 @@ class FilePickerService {
43724
43573
  }
43725
43574
  async saveFileElectron(options) {
43726
43575
  try {
43727
- const electron = await importElectron();
43728
- if (!electron?.ipcRenderer)
43729
- return null;
43730
- const result = await electron.ipcRenderer.invoke('show-save-dialog', {
43576
+ const { ipcRenderer } = await import('electron');
43577
+ const result = await ipcRenderer.invoke('show-save-dialog', {
43731
43578
  title: options.title,
43732
43579
  defaultPath: options.defaultPath,
43733
43580
  filters: options.filters?.map(f => ({
@@ -43751,10 +43598,8 @@ class FilePickerService {
43751
43598
  }
43752
43599
  async selectDirectoryTauri(options) {
43753
43600
  try {
43754
- const dialog = await importTauriDialog();
43755
- if (!dialog)
43756
- return null;
43757
- const result = await dialog.open({
43601
+ const { open } = await import('@tauri-apps/plugin-dialog');
43602
+ const result = await open({
43758
43603
  title: options.title,
43759
43604
  defaultPath: options.defaultPath,
43760
43605
  directory: true,
@@ -43770,10 +43615,8 @@ class FilePickerService {
43770
43615
  }
43771
43616
  async selectDirectoryElectron(options) {
43772
43617
  try {
43773
- const electron = await importElectron();
43774
- if (!electron?.ipcRenderer)
43775
- return null;
43776
- const result = await electron.ipcRenderer.invoke('show-open-dialog', {
43618
+ const { ipcRenderer } = await import('electron');
43619
+ const result = await ipcRenderer.invoke('show-open-dialog', {
43777
43620
  title: options.title,
43778
43621
  defaultPath: options.defaultPath,
43779
43622
  properties: ['openDirectory'],
@@ -43861,8 +43704,8 @@ class SystemTrayService {
43861
43704
  await tray.setIcon(icon);
43862
43705
  }
43863
43706
  else if (platform === PLATFORM_ELECTRON$3) {
43864
- const electron = await importElectron();
43865
- electron?.ipcRenderer?.send('tray-set-icon', icon);
43707
+ const { ipcRenderer } = await import('electron');
43708
+ ipcRenderer.send('tray-set-icon', icon);
43866
43709
  }
43867
43710
  }
43868
43711
  async setTooltip(tooltip) {
@@ -43872,8 +43715,8 @@ class SystemTrayService {
43872
43715
  await tray.setTooltip(tooltip);
43873
43716
  }
43874
43717
  else if (platform === PLATFORM_ELECTRON$3) {
43875
- const electron = await importElectron();
43876
- electron?.ipcRenderer?.send('tray-set-tooltip', tooltip);
43718
+ const { ipcRenderer } = await import('electron');
43719
+ ipcRenderer.send('tray-set-tooltip', tooltip);
43877
43720
  }
43878
43721
  }
43879
43722
  async setMenu(menu) {
@@ -43882,8 +43725,8 @@ class SystemTrayService {
43882
43725
  await this.setTauriMenu(menu);
43883
43726
  }
43884
43727
  else if (platform === PLATFORM_ELECTRON$3) {
43885
- const electron = await importElectron();
43886
- electron?.ipcRenderer?.send('tray-set-menu', this.convertMenuForElectron(menu));
43728
+ const { ipcRenderer } = await import('electron');
43729
+ ipcRenderer.send('tray-set-menu', this.convertMenuForElectron(menu));
43887
43730
  }
43888
43731
  }
43889
43732
  async destroy() {
@@ -43892,16 +43735,14 @@ class SystemTrayService {
43892
43735
  this.trayInstance = null;
43893
43736
  }
43894
43737
  else if (platform === PLATFORM_ELECTRON$3) {
43895
- const electron = await importElectron();
43896
- electron?.ipcRenderer?.send('tray-destroy');
43738
+ const { ipcRenderer } = await import('electron');
43739
+ ipcRenderer.send('tray-destroy');
43897
43740
  }
43898
43741
  this.isVisible.set(false);
43899
43742
  }
43900
43743
  async createTauriTray(config) {
43901
43744
  try {
43902
- const tauriTray = await importTauriTray();
43903
- if (!tauriTray)
43904
- return false;
43745
+ const tauriTray = await import('@tauri-apps/api/tray');
43905
43746
  this.trayInstance = await tauriTray.TrayIcon.new({
43906
43747
  icon: config.icon,
43907
43748
  tooltip: config.tooltip,
@@ -43920,10 +43761,8 @@ class SystemTrayService {
43920
43761
  }
43921
43762
  async createElectronTray(config) {
43922
43763
  try {
43923
- const electron = await importElectron();
43924
- if (!electron?.ipcRenderer)
43925
- return false;
43926
- await electron.ipcRenderer.invoke('tray-create', {
43764
+ const { ipcRenderer } = await import('electron');
43765
+ await ipcRenderer.invoke('tray-create', {
43927
43766
  icon: config.icon,
43928
43767
  tooltip: config.tooltip,
43929
43768
  menu: config.menu ? this.convertMenuForElectron(config.menu) : undefined,
@@ -43938,9 +43777,7 @@ class SystemTrayService {
43938
43777
  }
43939
43778
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
43940
43779
  async buildTauriMenu(items) {
43941
- const tauriMenu = await importTauriMenu();
43942
- if (!tauriMenu)
43943
- return null;
43780
+ const tauriMenu = await import('@tauri-apps/api/menu');
43944
43781
  const { Menu, MenuItem, Submenu } = tauriMenu;
43945
43782
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
43946
43783
  const menuItems = [];
@@ -44027,9 +43864,7 @@ class NativeNotificationsService {
44027
43864
  const platform = this.platformService.platform();
44028
43865
  if (platform === PLATFORM_TAURI$2) {
44029
43866
  try {
44030
- const notification = await importTauriNotification();
44031
- if (!notification)
44032
- return false;
43867
+ const notification = await import('@tauri-apps/plugin-notification');
44033
43868
  let granted = await notification.isPermissionGranted();
44034
43869
  if (!granted) {
44035
43870
  const result = await notification.requestPermission();
@@ -44080,8 +43915,8 @@ class NativeNotificationsService {
44080
43915
  }
44081
43916
  else if (platform === PLATFORM_ELECTRON$2) {
44082
43917
  try {
44083
- const electron = await importElectron();
44084
- electron?.ipcRenderer?.send('set-badge-count', count);
43918
+ const { ipcRenderer } = await import('electron');
43919
+ ipcRenderer.send('set-badge-count', count);
44085
43920
  }
44086
43921
  catch (error) {
44087
43922
  console.error('Failed to set Electron badge count:', error);
@@ -44101,9 +43936,7 @@ class NativeNotificationsService {
44101
43936
  }
44102
43937
  async showTauriNotification(options) {
44103
43938
  try {
44104
- const notification = await importTauriNotification();
44105
- if (!notification)
44106
- return null;
43939
+ const notification = await import('@tauri-apps/plugin-notification');
44107
43940
  const id = `notification-${Date.now()}`;
44108
43941
  await notification.sendNotification({
44109
43942
  title: options.title,
@@ -44119,11 +43952,9 @@ class NativeNotificationsService {
44119
43952
  }
44120
43953
  async showElectronNotification(options) {
44121
43954
  try {
44122
- const electron = await importElectron();
44123
- if (!electron?.ipcRenderer)
44124
- return null;
43955
+ const { ipcRenderer } = await import('electron');
44125
43956
  const id = `notification-${Date.now()}`;
44126
- await electron.ipcRenderer.invoke('show-notification', {
43957
+ await ipcRenderer.invoke('show-notification', {
44127
43958
  title: options.title,
44128
43959
  body: options.body,
44129
43960
  icon: options.icon,
@@ -44185,16 +44016,11 @@ class DockService {
44185
44016
  const platform = this.platformService.platform();
44186
44017
  if (platform === PLATFORM_TAURI$1) {
44187
44018
  try {
44188
- const tauriWindow = await importTauriWindow();
44189
- if (!tauriWindow)
44190
- return;
44191
- const appWindow = tauriWindow.getCurrentWindow();
44192
- // Tauri doesn't have direct dock badge API, so we append badge to window title
44193
- const currentTitle = await appWindow.title();
44194
- // Remove any existing badge from title (e.g., "App (3)" -> "App")
44195
- const baseTitle = currentTitle.replace(/\s*\(\d+\)\s*$/, '');
44196
- const newTitle = text ? `${baseTitle} (${text})` : baseTitle;
44197
- await appWindow.setTitle(newTitle);
44019
+ const { getCurrentWindow } = await import('@tauri-apps/api/window');
44020
+ // Tauri doesn't have direct dock badge API, use window title instead
44021
+ const appWindow = getCurrentWindow();
44022
+ // Badge functionality varies by platform in Tauri
44023
+ console.warn('Dock badge not directly supported in Tauri, consider using notifications');
44198
44024
  }
44199
44025
  catch (error) {
44200
44026
  console.error('Failed to set Tauri dock badge:', error);
@@ -44202,8 +44028,8 @@ class DockService {
44202
44028
  }
44203
44029
  else if (platform === PLATFORM_ELECTRON$1) {
44204
44030
  try {
44205
- const electron = await importElectron();
44206
- electron?.ipcRenderer?.send('set-dock-badge', text);
44031
+ const { ipcRenderer } = await import('electron');
44032
+ ipcRenderer.send('set-dock-badge', text);
44207
44033
  }
44208
44034
  catch (error) {
44209
44035
  console.error('Failed to set Electron dock badge:', error);
@@ -44223,10 +44049,10 @@ class DockService {
44223
44049
  const platform = this.platformService.platform();
44224
44050
  if (platform === PLATFORM_ELECTRON$1) {
44225
44051
  try {
44226
- const electron = await importElectron();
44052
+ const { ipcRenderer } = await import('electron');
44227
44053
  // Progress should be between 0 and 1, or -1 to clear
44228
44054
  const normalizedProgress = progress < 0 ? -1 : Math.min(1, Math.max(0, progress / 100));
44229
- electron?.ipcRenderer?.send('set-progress', normalizedProgress);
44055
+ ipcRenderer.send('set-progress', normalizedProgress);
44230
44056
  }
44231
44057
  catch (error) {
44232
44058
  console.error('Failed to set Electron progress:', error);
@@ -44247,10 +44073,8 @@ class DockService {
44247
44073
  const platform = this.platformService.platform();
44248
44074
  if (platform === PLATFORM_ELECTRON$1) {
44249
44075
  try {
44250
- const electron = await importElectron();
44251
- if (!electron?.ipcRenderer)
44252
- return -1;
44253
- return await electron.ipcRenderer.invoke('dock-bounce', type);
44076
+ const { ipcRenderer } = await import('electron');
44077
+ return await ipcRenderer.invoke('dock-bounce', type);
44254
44078
  }
44255
44079
  catch (error) {
44256
44080
  console.error('Failed to bounce Electron dock:', error);
@@ -44266,8 +44090,8 @@ class DockService {
44266
44090
  const platform = this.platformService.platform();
44267
44091
  if (platform === PLATFORM_ELECTRON$1) {
44268
44092
  try {
44269
- const electron = await importElectron();
44270
- electron?.ipcRenderer?.send('cancel-dock-bounce', id);
44093
+ const { ipcRenderer } = await import('electron');
44094
+ ipcRenderer.send('cancel-dock-bounce', id);
44271
44095
  }
44272
44096
  catch (error) {
44273
44097
  console.error('Failed to cancel Electron dock bounce:', error);
@@ -44281,8 +44105,8 @@ class DockService {
44281
44105
  const platform = this.platformService.platform();
44282
44106
  if (platform === PLATFORM_ELECTRON$1) {
44283
44107
  try {
44284
- const electron = await importElectron();
44285
- electron?.ipcRenderer?.send('set-dock-menu', this.convertMenuForElectron(items));
44108
+ const { ipcRenderer } = await import('electron');
44109
+ ipcRenderer.send('set-dock-menu', this.convertMenuForElectron(items));
44286
44110
  }
44287
44111
  catch (error) {
44288
44112
  console.error('Failed to set Electron dock menu:', error);
@@ -44296,8 +44120,8 @@ class DockService {
44296
44120
  const platform = this.platformService.platform();
44297
44121
  if (platform === PLATFORM_ELECTRON$1) {
44298
44122
  try {
44299
- const electron = await importElectron();
44300
- electron?.ipcRenderer?.send('show-dock');
44123
+ const { ipcRenderer } = await import('electron');
44124
+ ipcRenderer.send('show-dock');
44301
44125
  }
44302
44126
  catch (error) {
44303
44127
  console.error('Failed to show Electron dock:', error);
@@ -44311,8 +44135,8 @@ class DockService {
44311
44135
  const platform = this.platformService.platform();
44312
44136
  if (platform === PLATFORM_ELECTRON$1) {
44313
44137
  try {
44314
- const electron = await importElectron();
44315
- electron?.ipcRenderer?.send('hide-dock');
44138
+ const { ipcRenderer } = await import('electron');
44139
+ ipcRenderer.send('hide-dock');
44316
44140
  }
44317
44141
  catch (error) {
44318
44142
  console.error('Failed to hide Electron dock:', error);
@@ -44326,10 +44150,8 @@ class DockService {
44326
44150
  const platform = this.platformService.platform();
44327
44151
  if (platform === PLATFORM_TAURI$1) {
44328
44152
  try {
44329
- const tauriWindow = await importTauriWindow();
44330
- if (!tauriWindow)
44331
- return;
44332
- const appWindow = tauriWindow.getCurrentWindow();
44153
+ const { getCurrentWindow } = await import('@tauri-apps/api/window');
44154
+ const appWindow = getCurrentWindow();
44333
44155
  await appWindow.requestUserAttention(flash ? 2 : null); // 2 = Informational
44334
44156
  }
44335
44157
  catch (error) {
@@ -44338,8 +44160,8 @@ class DockService {
44338
44160
  }
44339
44161
  else if (platform === PLATFORM_ELECTRON$1) {
44340
44162
  try {
44341
- const electron = await importElectron();
44342
- electron?.ipcRenderer?.send('flash-frame', flash);
44163
+ const { ipcRenderer } = await import('electron');
44164
+ ipcRenderer.send('flash-frame', flash);
44343
44165
  }
44344
44166
  catch (error) {
44345
44167
  console.error('Failed to flash Electron frame:', error);
@@ -44474,26 +44296,24 @@ class UpdateService {
44474
44296
  }
44475
44297
  async setupElectronListeners() {
44476
44298
  try {
44477
- const electron = await importElectron();
44478
- if (!electron?.ipcRenderer)
44479
- return;
44480
- electron.ipcRenderer.on('update-available', (_event, info) => {
44299
+ const { ipcRenderer } = await import('electron');
44300
+ ipcRenderer.on('update-available', (_event, info) => {
44481
44301
  this.status.set('available');
44482
44302
  this.updateInfo.set(info);
44483
44303
  this.updateAvailable$.next(info);
44484
44304
  });
44485
- electron.ipcRenderer.on('update-not-available', () => {
44305
+ ipcRenderer.on('update-not-available', () => {
44486
44306
  this.status.set('not-available');
44487
44307
  });
44488
- electron.ipcRenderer.on('download-progress', (_event, progress) => {
44308
+ ipcRenderer.on('download-progress', (_event, progress) => {
44489
44309
  this.progress.set(progress);
44490
44310
  this.downloadProgress$.next(progress);
44491
44311
  });
44492
- electron.ipcRenderer.on('update-downloaded', () => {
44312
+ ipcRenderer.on('update-downloaded', () => {
44493
44313
  this.status.set('downloaded');
44494
44314
  this.updateDownloaded$.next();
44495
44315
  });
44496
- electron.ipcRenderer.on('update-error', (_event, error) => {
44316
+ ipcRenderer.on('update-error', (_event, error) => {
44497
44317
  this.status.set('error');
44498
44318
  this.error.set(error);
44499
44319
  this.updateError$.next(error);
@@ -44504,10 +44324,8 @@ class UpdateService {
44504
44324
  }
44505
44325
  }
44506
44326
  async checkTauriUpdates() {
44507
- const updater = await importTauriUpdater();
44508
- const app = await importTauriApp();
44509
- if (!updater || !app)
44510
- return null;
44327
+ const updater = await import('@tauri-apps/plugin-updater');
44328
+ const app = await import('@tauri-apps/api/app');
44511
44329
  const currentVersion = await app.getVersion();
44512
44330
  const update = await updater.check();
44513
44331
  if (update?.available) {
@@ -44526,10 +44344,8 @@ class UpdateService {
44526
44344
  return null;
44527
44345
  }
44528
44346
  async checkElectronUpdates() {
44529
- const electron = await importElectron();
44530
- if (!electron?.ipcRenderer)
44531
- return null;
44532
- const result = (await electron.ipcRenderer.invoke('check-for-updates'));
44347
+ const { ipcRenderer } = await import('electron');
44348
+ const result = (await ipcRenderer.invoke('check-for-updates'));
44533
44349
  if (result?.updateAvailable) {
44534
44350
  const info = {
44535
44351
  currentVersion: result.currentVersion || '',
@@ -44546,9 +44362,7 @@ class UpdateService {
44546
44362
  return null;
44547
44363
  }
44548
44364
  async downloadTauriUpdate() {
44549
- const updater = await importTauriUpdater();
44550
- if (!updater)
44551
- return;
44365
+ const updater = await import('@tauri-apps/plugin-updater');
44552
44366
  const update = await updater.check();
44553
44367
  if (update?.available) {
44554
44368
  await update.downloadAndInstall(event => {
@@ -44578,16 +44392,16 @@ class UpdateService {
44578
44392
  }
44579
44393
  }
44580
44394
  async downloadElectronUpdate() {
44581
- const electron = await importElectron();
44582
- electron?.ipcRenderer?.send('download-update');
44395
+ const { ipcRenderer } = await import('electron');
44396
+ ipcRenderer.send('download-update');
44583
44397
  }
44584
44398
  async installTauriUpdate() {
44585
- const process = await importTauriProcess();
44586
- await process?.relaunch();
44399
+ const process = await import('@tauri-apps/plugin-process');
44400
+ await process.relaunch();
44587
44401
  }
44588
44402
  async installElectronUpdate() {
44589
- const electron = await importElectron();
44590
- electron?.ipcRenderer?.send('quit-and-install');
44403
+ const { ipcRenderer } = await import('electron');
44404
+ ipcRenderer.send('quit-and-install');
44591
44405
  }
44592
44406
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: UpdateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
44593
44407
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: UpdateService, providedIn: 'root' });