@konce-pt/angular 0.2.0 → 0.3.0

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 { input, booleanAttribute, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, model, output, signal, Injectable, inject, ElementRef, effect, viewChild, afterNextRender, TemplateRef, contentChildren, Directive, linkedSignal, contentChild } from '@angular/core';
2
+ import { input, booleanAttribute, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, model, output, signal, Injectable, inject, ElementRef, effect, afterNextRender, numberAttribute, viewChild, Directive, DestroyRef, TemplateRef, contentChildren, viewChildren, afterRenderEffect, linkedSignal, contentChild } from '@angular/core';
3
3
  import { CdkOverlayOrigin, CdkConnectedOverlay } from '@angular/cdk/overlay';
4
4
  import { NgTemplateOutlet } from '@angular/common';
5
5
 
@@ -241,6 +241,7 @@ const KPT_ICONS = {
241
241
  'dots-vertical': '<path d="M11 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" /> <path d="M11 19a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" /> <path d="M11 5a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />',
242
242
  'photo': '<path d="M15 8h.01" /> <path d="M3 6a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v12a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3v-12" /> <path d="M3 16l5 -5c.928 -.893 2.072 -.893 3 0l5 5" /> <path d="M14 14l1 -1c.928 -.893 2.072 -.893 3 0l3 3" />',
243
243
  'trash': '<path d="M4 7l16 0" /> <path d="M10 11l0 6" /> <path d="M14 11l0 6" /> <path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12" /> <path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3" />',
244
+ 'pencil': '<path d="M4 20h4l10.5 -10.5a2.828 2.828 0 1 0 -4 -4l-10.5 10.5v4" /> <path d="M13.5 6.5l4 4" />',
244
245
  'eye': '<path d="M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" /> <path d="M21 12c-2.4 4 -5.4 6 -9 6c-3.6 0 -6.6 -2 -9 -6c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6" />',
245
246
  'eye-off': '<path d="M10.585 10.587a2 2 0 0 0 2.829 2.828" /> <path d="M16.681 16.673a8.717 8.717 0 0 1 -4.681 1.327c-3.6 0 -6.6 -2 -9 -6c1.272 -2.12 2.712 -3.678 4.32 -4.674m2.86 -1.146a9.055 9.055 0 0 1 1.82 -.18c3.6 0 6.6 2 9 6c-.666 1.11 -1.379 2.067 -2.138 2.87" /> <path d="M3 3l18 18" />',
246
247
  'minus': '<path d="M5 12l14 0" />',
@@ -248,6 +249,19 @@ const KPT_ICONS = {
248
249
  'arrow-down': '<path d="M12 5l0 14" /> <path d="M18 13l-6 6" /> <path d="M6 13l6 6" />',
249
250
  'zoom-in': '<path d="M3 10a7 7 0 1 0 14 0a7 7 0 1 0 -14 0" /> <path d="M7 10l6 0" /> <path d="M10 7l0 6" /> <path d="M21 21l-6 -6" />',
250
251
  'info-circle': '<path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0" /> <path d="M12 9h.01" /> <path d="M11 12h1v4h1" />',
252
+ 'phone': '<path d="M5 4h4l2 5l-2.5 1.5a11 11 0 0 0 5 5l1.5 -2.5l5 2v4a2 2 0 0 1 -2 2a16 16 0 0 1 -15 -15a2 2 0 0 1 2 -2" />',
253
+ 'map-pin': '<path d="M9 11a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" /> <path d="M17.657 16.657l-4.243 4.243a2 2 0 0 1 -2.827 0l-4.244 -4.243a8 8 0 1 1 11.314 0z" />',
254
+ 'world': '<path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0" /> <path d="M3.6 9h16.8" /> <path d="M3.6 15h16.8" /> <path d="M11.5 3a17 17 0 0 0 0 18" /> <path d="M12.5 3a17 17 0 0 1 0 18" />',
255
+ 'clock': '<path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0" /> <path d="M12 7v5l3 3" />',
256
+ 'align-left': '<path d="M4 6l16 0" /> <path d="M4 12l10 0" /> <path d="M4 18l14 0" />',
257
+ 'align-center': '<path d="M4 6l16 0" /> <path d="M8 12l8 0" /> <path d="M6 18l12 0" />',
258
+ 'align-right': '<path d="M4 6l16 0" /> <path d="M10 12l10 0" /> <path d="M6 18l14 0" />',
259
+ 'align-justified': '<path d="M4 6l16 0" /> <path d="M4 12l16 0" /> <path d="M4 18l12 0" />',
260
+ 'palette': '<path d="M12 21a9 9 0 0 1 0 -18a9 8 0 0 1 9 8a4.5 4 0 0 1 -4.5 4h-2.5a2 2 0 0 0 -1 3.75a1.3 1.3 0 0 1 -1 2.25" /> <path d="M8.5 10.5a1 1 0 1 0 2 0a1 1 0 0 0 -2 0" /> <path d="M12.5 7.5a1 1 0 1 0 2 0a1 1 0 0 0 -2 0" /> <path d="M16.5 10.5a1 1 0 1 0 2 0a1 1 0 0 0 -2 0" />',
261
+ 'highlight': '<path d="M3 19h4l10.5 -10.5a2.828 2.828 0 1 0 -4 -4l-10.5 10.5v4" /> <path d="M12.5 5.5l4 4" /> <path d="M4.5 13.5l4 4" /> <path d="M21 15v4h-8" />',
262
+ 'clipboard': '<path d="M9 5h-2a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-12a2 2 0 0 0 -2 -2h-2" /> <path d="M9 3m0 2a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v0a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2z" />',
263
+ 'clipboard-text': '<path d="M9 5h-2a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-12a2 2 0 0 0 -2 -2h-2" /> <path d="M9 3m0 2a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v0a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2z" /> <path d="M9 12h6" /> <path d="M9 16h6" />',
264
+ 'table': '<path d="M3 5a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-14z" /> <path d="M3 10h18" /> <path d="M10 3v18" />',
251
265
  };
252
266
 
253
267
  /**
@@ -755,10 +769,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
755
769
  * kontrolki (np. `kpt-input`). Prezentacyjny — stan błędu przekazuje się przez `error`
756
770
  * (zwykle z pola Signal Forms). Wygląd sterowany tokenami `--kpt-form-field-*`.
757
771
  *
772
+ * Etykieta ma 4 warianty (`labelType`): `fixed` (domyślny, nad kontrolką) oraz trzy warianty
773
+ * unoszącej się etykiety (Float Label) z animowanym przejściem: `over` (nad obramowaniem),
774
+ * `in` (u góry wewnątrz pola) i `on` (na obramowaniu, notch). Uniesienie następuje przy focusie
775
+ * (CSS `:focus-within`) lub gdy pole jest wypełnione (wykrywane po zdarzeniach `input`/`change`
776
+ * oraz wartości początkowej) — bez wymogu placeholdera na kontrolce.
777
+ *
758
778
  * @example
759
779
  * <kpt-form-field label="E-mail" [error]="emailError()" hint="Firmowy adres">
760
780
  * <kpt-input [control]="f.email" type="email" />
761
781
  * </kpt-form-field>
782
+ *
783
+ * @example
784
+ * <kpt-form-field label="E-mail" labelType="over">
785
+ * <kpt-input />
786
+ * </kpt-form-field>
762
787
  */
763
788
  class KptFormField {
764
789
  /** Tekst etykiety. */
@@ -775,13 +800,37 @@ class KptFormField {
775
800
  /** Id kontrolki dla powiązania `label[for]`. */
776
801
  controlId = input('', /* @ts-ignore */
777
802
  ...(ngDevMode ? [{ debugName: "controlId" }] : /* istanbul ignore next */ []));
803
+ /**
804
+ * Wariant etykiety: `fixed` (domyślnie, statyczna nad kontrolką) lub Float Label —
805
+ * `over` (nad obramowaniem), `in` (u góry wewnątrz pola), `on` (na obramowaniu, notch).
806
+ * Uniesienie następuje przy focusie lub wypełnieniu pola.
807
+ */
808
+ labelType = input('fixed', /* @ts-ignore */
809
+ ...(ngDevMode ? [{ debugName: "labelType" }] : /* istanbul ignore next */ []));
810
+ host = inject(ElementRef);
811
+ /** Czy projektowana kontrolka ma wartość — steruje uniesieniem etykiety w wariantach float. */
812
+ filled = signal(false, /* @ts-ignore */
813
+ ...(ngDevMode ? [{ debugName: "filled" }] : /* istanbul ignore next */ []));
814
+ constructor() {
815
+ // Wartość początkowa (np. pole prefill) — po pierwszym renderze projekcji.
816
+ afterNextRender(() => this.updateFilled());
817
+ }
818
+ /** Odczytuje wartość projektowanego `input`/`textarea` i aktualizuje stan `filled`. */
819
+ updateFilled() {
820
+ const el = this.host.nativeElement.querySelector('.kpt-form-field__control input, .kpt-form-field__control textarea');
821
+ this.filled.set(!!el && el.value !== '');
822
+ }
778
823
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptFormField, deps: [], target: i0.ɵɵFactoryTarget.Component });
779
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptFormField, isStandalone: true, selector: "kpt-form-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "kpt-form-field-host" }, ngImport: i0, template: "<div class=\"kpt-form-field\" [class.kpt-form-field--invalid]=\"!!error()\">\n @if (label()) {\n <label class=\"kpt-form-field__label\" [attr.for]=\"controlId() || null\">\n {{ label() }}\n @if (required()) {\n <span class=\"kpt-form-field__required\" aria-hidden=\"true\">*</span>\n }\n </label>\n }\n\n <div class=\"kpt-form-field__control\">\n <ng-content />\n </div>\n\n @if (error()) {\n <p class=\"kpt-form-field__message kpt-form-field__message--error\" role=\"alert\">{{ error() }}</p>\n } @else if (hint()) {\n <p class=\"kpt-form-field__message kpt-form-field__message--hint\">{{ hint() }}</p>\n }\n</div>\n", styles: ["@layer kpt.components{.kpt-form-field{display:flex;flex-direction:column;gap:var(--kpt-space-1, .25rem)}.kpt-form-field__label{font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-medium, 500);color:var(--kpt-form-field-label)}.kpt-form-field__required{color:var(--kpt-color-danger);margin-inline-start:.125rem}.kpt-form-field__message{font-size:var(--kpt-font-size-xs, .75rem);line-height:var(--kpt-font-line-height-normal, 1.5)}.kpt-form-field__message--hint{color:var(--kpt-form-field-hint)}.kpt-form-field__message--error{color:var(--kpt-form-field-error)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
824
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptFormField, isStandalone: true, selector: "kpt-form-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null }, labelType: { classPropertyName: "labelType", publicName: "labelType", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "input": "updateFilled()", "change": "updateFilled()" }, classAttribute: "kpt-form-field-host" }, ngImport: i0, template: "<div\n class=\"kpt-form-field\"\n [class]=\"'kpt-form-field--' + labelType()\"\n [class.kpt-form-field--float]=\"labelType() !== 'fixed'\"\n [class.kpt-form-field--invalid]=\"!!error()\"\n>\n <div class=\"kpt-form-field__box\" [class.is-filled]=\"filled()\">\n @if (label()) {\n <label class=\"kpt-form-field__label\" [attr.for]=\"controlId() || null\">\n {{ label() }}\n @if (required()) {\n <span class=\"kpt-form-field__required\" aria-hidden=\"true\">*</span>\n }\n </label>\n }\n\n <div class=\"kpt-form-field__control\">\n <ng-content />\n </div>\n </div>\n\n @if (error()) {\n <p class=\"kpt-form-field__message kpt-form-field__message--error\" role=\"alert\">{{ error() }}</p>\n } @else if (hint()) {\n <p class=\"kpt-form-field__message kpt-form-field__message--hint\">{{ hint() }}</p>\n }\n</div>\n", styles: ["@layer kpt.components{.kpt-form-field,.kpt-form-field__box{display:flex;flex-direction:column;gap:var(--kpt-space-1, .25rem)}.kpt-form-field__label{font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-medium, 500);color:var(--kpt-form-field-label)}.kpt-form-field__required{color:var(--kpt-color-danger);margin-inline-start:.125rem}.kpt-form-field__message{font-size:var(--kpt-font-size-xs, .75rem);line-height:var(--kpt-font-line-height-normal, 1.5)}.kpt-form-field__message--hint{color:var(--kpt-form-field-hint)}.kpt-form-field__message--error{color:var(--kpt-form-field-error)}.kpt-form-field--float .kpt-form-field__box{position:relative;display:block}.kpt-form-field--float .kpt-form-field__label{position:absolute;top:50%;left:var(--kpt-space-3, .75rem);margin:0;max-width:calc(100% - 2 * var(--kpt-space-3, .75rem));overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1;transform:translateY(-50%);transform-origin:left center;pointer-events:none;font-weight:var(--kpt-font-weight-normal, 400);color:var(--kpt-form-field-placeholder);transition:transform var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard),color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-form-field--float .kpt-form-field__box:focus-within .kpt-form-field__label{color:var(--kpt-form-field-border-focus)}.kpt-form-field--float.kpt-form-field--invalid .kpt-form-field__box:is(:focus-within,.is-filled) .kpt-form-field__label,.kpt-form-field--float.kpt-form-field--invalid .kpt-form-field__box:focus-within .kpt-form-field__label{color:var(--kpt-form-field-border-error)}.kpt-form-field--over .kpt-form-field__box{margin-top:1.1rem}.kpt-form-field--over .kpt-form-field__box:is(:focus-within,.is-filled) .kpt-form-field__label{left:0;transform:translateY(calc(-50% - 1.87rem)) scale(.85)}.kpt-form-field--in .kpt-form-field__control :is(input,textarea){height:3.25rem;padding-top:1.15rem}.kpt-form-field--in .kpt-form-field__box:is(:focus-within,.is-filled) .kpt-form-field__label{transform:translateY(calc(-50% - .95rem)) scale(.85)}.kpt-form-field--on .kpt-form-field__box:is(:focus-within,.is-filled) .kpt-form-field__label{left:calc(var(--kpt-space-3, .75rem) - .25rem);padding-inline:.25rem;background:var(--kpt-form-field-bg);transform:translateY(calc(-50% - 1.25rem)) scale(.85)}@media(prefers-reduced-motion:reduce){.kpt-form-field--float .kpt-form-field__label{transition:none}}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
780
825
  }
781
826
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptFormField, decorators: [{
782
827
  type: Component,
783
- args: [{ selector: 'kpt-form-field', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'kpt-form-field-host' }, template: "<div class=\"kpt-form-field\" [class.kpt-form-field--invalid]=\"!!error()\">\n @if (label()) {\n <label class=\"kpt-form-field__label\" [attr.for]=\"controlId() || null\">\n {{ label() }}\n @if (required()) {\n <span class=\"kpt-form-field__required\" aria-hidden=\"true\">*</span>\n }\n </label>\n }\n\n <div class=\"kpt-form-field__control\">\n <ng-content />\n </div>\n\n @if (error()) {\n <p class=\"kpt-form-field__message kpt-form-field__message--error\" role=\"alert\">{{ error() }}</p>\n } @else if (hint()) {\n <p class=\"kpt-form-field__message kpt-form-field__message--hint\">{{ hint() }}</p>\n }\n</div>\n", styles: ["@layer kpt.components{.kpt-form-field{display:flex;flex-direction:column;gap:var(--kpt-space-1, .25rem)}.kpt-form-field__label{font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-medium, 500);color:var(--kpt-form-field-label)}.kpt-form-field__required{color:var(--kpt-color-danger);margin-inline-start:.125rem}.kpt-form-field__message{font-size:var(--kpt-font-size-xs, .75rem);line-height:var(--kpt-font-line-height-normal, 1.5)}.kpt-form-field__message--hint{color:var(--kpt-form-field-hint)}.kpt-form-field__message--error{color:var(--kpt-form-field-error)}}\n"] }]
784
- }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], controlId: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlId", required: false }] }] } });
828
+ args: [{ selector: 'kpt-form-field', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
829
+ class: 'kpt-form-field-host',
830
+ '(input)': 'updateFilled()',
831
+ '(change)': 'updateFilled()',
832
+ }, template: "<div\n class=\"kpt-form-field\"\n [class]=\"'kpt-form-field--' + labelType()\"\n [class.kpt-form-field--float]=\"labelType() !== 'fixed'\"\n [class.kpt-form-field--invalid]=\"!!error()\"\n>\n <div class=\"kpt-form-field__box\" [class.is-filled]=\"filled()\">\n @if (label()) {\n <label class=\"kpt-form-field__label\" [attr.for]=\"controlId() || null\">\n {{ label() }}\n @if (required()) {\n <span class=\"kpt-form-field__required\" aria-hidden=\"true\">*</span>\n }\n </label>\n }\n\n <div class=\"kpt-form-field__control\">\n <ng-content />\n </div>\n </div>\n\n @if (error()) {\n <p class=\"kpt-form-field__message kpt-form-field__message--error\" role=\"alert\">{{ error() }}</p>\n } @else if (hint()) {\n <p class=\"kpt-form-field__message kpt-form-field__message--hint\">{{ hint() }}</p>\n }\n</div>\n", styles: ["@layer kpt.components{.kpt-form-field,.kpt-form-field__box{display:flex;flex-direction:column;gap:var(--kpt-space-1, .25rem)}.kpt-form-field__label{font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-medium, 500);color:var(--kpt-form-field-label)}.kpt-form-field__required{color:var(--kpt-color-danger);margin-inline-start:.125rem}.kpt-form-field__message{font-size:var(--kpt-font-size-xs, .75rem);line-height:var(--kpt-font-line-height-normal, 1.5)}.kpt-form-field__message--hint{color:var(--kpt-form-field-hint)}.kpt-form-field__message--error{color:var(--kpt-form-field-error)}.kpt-form-field--float .kpt-form-field__box{position:relative;display:block}.kpt-form-field--float .kpt-form-field__label{position:absolute;top:50%;left:var(--kpt-space-3, .75rem);margin:0;max-width:calc(100% - 2 * var(--kpt-space-3, .75rem));overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1;transform:translateY(-50%);transform-origin:left center;pointer-events:none;font-weight:var(--kpt-font-weight-normal, 400);color:var(--kpt-form-field-placeholder);transition:transform var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard),color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-form-field--float .kpt-form-field__box:focus-within .kpt-form-field__label{color:var(--kpt-form-field-border-focus)}.kpt-form-field--float.kpt-form-field--invalid .kpt-form-field__box:is(:focus-within,.is-filled) .kpt-form-field__label,.kpt-form-field--float.kpt-form-field--invalid .kpt-form-field__box:focus-within .kpt-form-field__label{color:var(--kpt-form-field-border-error)}.kpt-form-field--over .kpt-form-field__box{margin-top:1.1rem}.kpt-form-field--over .kpt-form-field__box:is(:focus-within,.is-filled) .kpt-form-field__label{left:0;transform:translateY(calc(-50% - 1.87rem)) scale(.85)}.kpt-form-field--in .kpt-form-field__control :is(input,textarea){height:3.25rem;padding-top:1.15rem}.kpt-form-field--in .kpt-form-field__box:is(:focus-within,.is-filled) .kpt-form-field__label{transform:translateY(calc(-50% - .95rem)) scale(.85)}.kpt-form-field--on .kpt-form-field__box:is(:focus-within,.is-filled) .kpt-form-field__label{left:calc(var(--kpt-space-3, .75rem) - .25rem);padding-inline:.25rem;background:var(--kpt-form-field-bg);transform:translateY(calc(-50% - 1.25rem)) scale(.85)}@media(prefers-reduced-motion:reduce){.kpt-form-field--float .kpt-form-field__label{transition:none}}}\n"] }]
833
+ }], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], controlId: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlId", required: false }] }], labelType: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelType", required: false }] }] } });
785
834
 
786
835
  let nextUniqueId = 0;
787
836
  /**
@@ -900,6 +949,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
900
949
  /**
901
950
  * Przełącznik (switch/toggle) zintegrowany z Signal Forms (`FormCheckboxControl`).
902
951
  * `<kpt-switch [formField]="f.notifications" label="Powiadomienia" />`
952
+ *
953
+ * Wariant z tekstem stanu: `onLabel`/`offLabel` — wyświetlany tekst zmienia się
954
+ * przy przełączaniu (np. „Włączony”/„Wyłączony”).
955
+ * `<kpt-switch [(checked)]="on" onLabel="Włączony" offLabel="Wyłączony" />`
903
956
  */
904
957
  class KptSwitch {
905
958
  checked = model(false, /* @ts-ignore */
@@ -910,9 +963,26 @@ class KptSwitch {
910
963
  touch = output();
911
964
  label = input('', /* @ts-ignore */
912
965
  ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
966
+ /** Pozycja etykiety `label` względem przełącznika: 'end' (prawo, domyślnie) lub 'start' (lewo). */
967
+ labelPosition = input('end', /* @ts-ignore */
968
+ ...(ngDevMode ? [{ debugName: "labelPosition" }] : /* istanbul ignore next */ []));
969
+ /** Tekst stanu włączonego (wyświetlany, gdy `checked`). */
970
+ onLabel = input('', /* @ts-ignore */
971
+ ...(ngDevMode ? [{ debugName: "onLabel" }] : /* istanbul ignore next */ []));
972
+ /** Tekst stanu wyłączonego (wyświetlany, gdy nie `checked`). */
973
+ offLabel = input('', /* @ts-ignore */
974
+ ...(ngDevMode ? [{ debugName: "offLabel" }] : /* istanbul ignore next */ []));
975
+ hasStateLabels = computed(() => !!(this.onLabel() || this.offLabel()), /* @ts-ignore */
976
+ ...(ngDevMode ? [{ debugName: "hasStateLabels" }] : /* istanbul ignore next */ []));
977
+ /** Tekst zależny od stanu przełącznika. */
978
+ stateLabel = computed(() => (this.checked() ? this.onLabel() : this.offLabel()), /* @ts-ignore */
979
+ ...(ngDevMode ? [{ debugName: "stateLabel" }] : /* istanbul ignore next */ []));
913
980
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptSwitch, deps: [], target: i0.ɵɵFactoryTarget.Component });
914
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptSwitch, isStandalone: true, selector: "kpt-switch", inputs: { checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", touch: "touch" }, host: { classAttribute: "kpt-switch-host" }, ngImport: i0, template: `
981
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptSwitch, isStandalone: true, selector: "kpt-switch", inputs: { checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, labelPosition: { classPropertyName: "labelPosition", publicName: "labelPosition", isSignal: true, isRequired: false, transformFunction: null }, onLabel: { classPropertyName: "onLabel", publicName: "onLabel", isSignal: true, isRequired: false, transformFunction: null }, offLabel: { classPropertyName: "offLabel", publicName: "offLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", touch: "touch" }, host: { classAttribute: "kpt-switch-host" }, ngImport: i0, template: `
915
982
  <label class="kpt-switch" [class.kpt-switch--disabled]="disabled()">
983
+ @if (label() && labelPosition() === 'start') {
984
+ <span class="kpt-switch__label kpt-switch__label--start">{{ label() }}</span>
985
+ }
916
986
  <input
917
987
  type="checkbox"
918
988
  role="switch"
@@ -924,17 +994,23 @@ class KptSwitch {
924
994
  (blur)="touch.emit()"
925
995
  />
926
996
  <span class="kpt-switch__track" aria-hidden="true"><span class="kpt-switch__thumb"></span></span>
927
- @if (label()) {
997
+ @if (label() && labelPosition() === 'end') {
928
998
  <span class="kpt-switch__label">{{ label() }}</span>
929
999
  }
1000
+ @if (hasStateLabels()) {
1001
+ <span class="kpt-switch__state" [class.kpt-switch__state--on]="checked()">{{ stateLabel() }}</span>
1002
+ }
930
1003
  <ng-content />
931
1004
  </label>
932
- `, isInline: true, styles: ["@layer kpt.components{.kpt-switch{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);cursor:pointer;font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface)}.kpt-switch--disabled{cursor:not-allowed;opacity:.55}.kpt-switch__input{position:absolute;opacity:0;width:1px;height:1px}.kpt-switch__track{position:relative;display:inline-block;width:2.25rem;height:1.25rem;flex-shrink:0;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-border-strong);transition:background-color var(--kpt-motion-duration-base, .2s) var(--kpt-motion-easing-standard)}.kpt-switch__thumb{position:absolute;top:.15rem;left:.15rem;width:.95rem;height:.95rem;border-radius:50%;background:var(--kpt-color-surface);box-shadow:var(--kpt-elevation-1);transition:transform var(--kpt-motion-duration-base, .2s) var(--kpt-motion-easing-standard)}.kpt-switch__input:checked+.kpt-switch__track{background:var(--kpt-color-primary)}.kpt-switch__input:checked+.kpt-switch__track .kpt-switch__thumb{transform:translate(1rem)}.kpt-switch__input:focus-visible+.kpt-switch__track{outline:var(--kpt-border-width-medium, 2px) solid var(--kpt-color-focus-ring);outline-offset:2px}@media(prefers-reduced-motion:reduce){.kpt-switch__thumb,.kpt-switch__track{transition:none}}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1005
+ `, isInline: true, styles: ["@layer kpt.components{.kpt-switch{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);cursor:pointer;font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface)}.kpt-switch--disabled{cursor:not-allowed;opacity:.55}.kpt-switch__input{position:absolute;opacity:0;width:1px;height:1px}.kpt-switch__track{position:relative;display:inline-block;width:2.25rem;height:1.25rem;flex-shrink:0;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-border-strong);transition:background-color var(--kpt-motion-duration-base, .2s) var(--kpt-motion-easing-standard)}.kpt-switch__thumb{position:absolute;top:.15rem;left:.15rem;width:.95rem;height:.95rem;border-radius:50%;background:var(--kpt-color-surface);box-shadow:var(--kpt-elevation-1);transition:transform var(--kpt-motion-duration-base, .2s) var(--kpt-motion-easing-standard)}.kpt-switch__state{font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-medium, 500);font-variant-numeric:tabular-nums;color:var(--kpt-color-on-surface-muted);transition:color var(--kpt-motion-duration-base, .2s) var(--kpt-motion-easing-standard)}.kpt-switch__state--on{color:var(--kpt-color-primary)}.kpt-switch__input:checked+.kpt-switch__track{background:var(--kpt-color-primary)}.kpt-switch__input:checked+.kpt-switch__track .kpt-switch__thumb{transform:translate(1rem)}.kpt-switch__input:focus-visible+.kpt-switch__track{outline:var(--kpt-border-width-medium, 2px) solid var(--kpt-color-focus-ring);outline-offset:2px}@media(prefers-reduced-motion:reduce){.kpt-switch__thumb,.kpt-switch__track{transition:none}}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
933
1006
  }
934
1007
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptSwitch, decorators: [{
935
1008
  type: Component,
936
1009
  args: [{ selector: 'kpt-switch', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: `
937
1010
  <label class="kpt-switch" [class.kpt-switch--disabled]="disabled()">
1011
+ @if (label() && labelPosition() === 'start') {
1012
+ <span class="kpt-switch__label kpt-switch__label--start">{{ label() }}</span>
1013
+ }
938
1014
  <input
939
1015
  type="checkbox"
940
1016
  role="switch"
@@ -946,13 +1022,129 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
946
1022
  (blur)="touch.emit()"
947
1023
  />
948
1024
  <span class="kpt-switch__track" aria-hidden="true"><span class="kpt-switch__thumb"></span></span>
949
- @if (label()) {
1025
+ @if (label() && labelPosition() === 'end') {
950
1026
  <span class="kpt-switch__label">{{ label() }}</span>
951
1027
  }
1028
+ @if (hasStateLabels()) {
1029
+ <span class="kpt-switch__state" [class.kpt-switch__state--on]="checked()">{{ stateLabel() }}</span>
1030
+ }
952
1031
  <ng-content />
953
1032
  </label>
954
- `, host: { class: 'kpt-switch-host' }, styles: ["@layer kpt.components{.kpt-switch{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);cursor:pointer;font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface)}.kpt-switch--disabled{cursor:not-allowed;opacity:.55}.kpt-switch__input{position:absolute;opacity:0;width:1px;height:1px}.kpt-switch__track{position:relative;display:inline-block;width:2.25rem;height:1.25rem;flex-shrink:0;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-border-strong);transition:background-color var(--kpt-motion-duration-base, .2s) var(--kpt-motion-easing-standard)}.kpt-switch__thumb{position:absolute;top:.15rem;left:.15rem;width:.95rem;height:.95rem;border-radius:50%;background:var(--kpt-color-surface);box-shadow:var(--kpt-elevation-1);transition:transform var(--kpt-motion-duration-base, .2s) var(--kpt-motion-easing-standard)}.kpt-switch__input:checked+.kpt-switch__track{background:var(--kpt-color-primary)}.kpt-switch__input:checked+.kpt-switch__track .kpt-switch__thumb{transform:translate(1rem)}.kpt-switch__input:focus-visible+.kpt-switch__track{outline:var(--kpt-border-width-medium, 2px) solid var(--kpt-color-focus-ring);outline-offset:2px}@media(prefers-reduced-motion:reduce){.kpt-switch__thumb,.kpt-switch__track{transition:none}}}\n"] }]
955
- }], propDecorators: { checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
1033
+ `, host: { class: 'kpt-switch-host' }, styles: ["@layer kpt.components{.kpt-switch{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);cursor:pointer;font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface)}.kpt-switch--disabled{cursor:not-allowed;opacity:.55}.kpt-switch__input{position:absolute;opacity:0;width:1px;height:1px}.kpt-switch__track{position:relative;display:inline-block;width:2.25rem;height:1.25rem;flex-shrink:0;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-border-strong);transition:background-color var(--kpt-motion-duration-base, .2s) var(--kpt-motion-easing-standard)}.kpt-switch__thumb{position:absolute;top:.15rem;left:.15rem;width:.95rem;height:.95rem;border-radius:50%;background:var(--kpt-color-surface);box-shadow:var(--kpt-elevation-1);transition:transform var(--kpt-motion-duration-base, .2s) var(--kpt-motion-easing-standard)}.kpt-switch__state{font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-medium, 500);font-variant-numeric:tabular-nums;color:var(--kpt-color-on-surface-muted);transition:color var(--kpt-motion-duration-base, .2s) var(--kpt-motion-easing-standard)}.kpt-switch__state--on{color:var(--kpt-color-primary)}.kpt-switch__input:checked+.kpt-switch__track{background:var(--kpt-color-primary)}.kpt-switch__input:checked+.kpt-switch__track .kpt-switch__thumb{transform:translate(1rem)}.kpt-switch__input:focus-visible+.kpt-switch__track{outline:var(--kpt-border-width-medium, 2px) solid var(--kpt-color-focus-ring);outline-offset:2px}@media(prefers-reduced-motion:reduce){.kpt-switch__thumb,.kpt-switch__track{transition:none}}}\n"] }]
1034
+ }], propDecorators: { checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], labelPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPosition", required: false }] }], onLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "onLabel", required: false }] }], offLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "offLabel", required: false }] }] } });
1035
+
1036
+ /**
1037
+ * Grupa przełączników. Domyślnie pojedynczy wybór (wzajemnie wykluczające się) —
1038
+ * włączenie jednego wyłącza pozostałe, a wartość to `value` wybranej opcji (lub `null`).
1039
+ * Z `multiple` przechodzi w tryb wielokrotny — wartość to tablica `T[]` zaznaczonych opcji.
1040
+ * Zintegrowana z Signal Forms (`FormValueControl<T | T[] | null>`).
1041
+ *
1042
+ * @example
1043
+ * <kpt-switch-group [(value)]="plan" [options]="plans" />
1044
+ * <kpt-switch-group multiple [(value)]="tags" [options]="tagOptions" />
1045
+ */
1046
+ class KptSwitchGroup {
1047
+ value = model(null, /* @ts-ignore */
1048
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
1049
+ options = input([], /* @ts-ignore */
1050
+ ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
1051
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1052
+ invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1053
+ touched = input(false, { ...(ngDevMode ? { debugName: "touched" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1054
+ touch = output();
1055
+ /** Układ: 'vertical' (domyślnie) lub 'horizontal'. */
1056
+ orientation = input('vertical', /* @ts-ignore */
1057
+ ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
1058
+ /** Tryb wielokrotnego wyboru — wartość to tablica `T[]` zaznaczonych opcji. Domyślnie false (pojedynczy wybór). */
1059
+ multiple = input(false, { ...(ngDevMode ? { debugName: "multiple" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1060
+ /**
1061
+ * Czy ponowne kliknięcie aktywnej opcji ją odznacza (value = null). Dotyczy tylko trybu pojedynczego —
1062
+ * w trybie `multiple` odznaczanie jest zawsze dozwolone. Domyślnie tak.
1063
+ */
1064
+ allowDeselect = input(true, { ...(ngDevMode ? { debugName: "allowDeselect" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1065
+ /** Aktualna wartość jako tablica (tryb multiple) — normalizuje `null`/pojedynczą wartość. */
1066
+ selectedValues = computed(() => {
1067
+ const v = this.value();
1068
+ if (Array.isArray(v))
1069
+ return v;
1070
+ return v == null ? [] : [v];
1071
+ }, /* @ts-ignore */
1072
+ ...(ngDevMode ? [{ debugName: "selectedValues" }] : /* istanbul ignore next */ []));
1073
+ isChecked(optValue) {
1074
+ if (this.multiple())
1075
+ return this.selectedValues().includes(optValue);
1076
+ return optValue === this.value();
1077
+ }
1078
+ onToggle(opt, checked) {
1079
+ if (this.multiple()) {
1080
+ const current = this.selectedValues();
1081
+ if (checked) {
1082
+ if (!current.includes(opt.value))
1083
+ this.value.set([...current, opt.value]);
1084
+ }
1085
+ else {
1086
+ this.value.set(current.filter((v) => v !== opt.value));
1087
+ }
1088
+ return;
1089
+ }
1090
+ if (checked) {
1091
+ this.value.set(opt.value);
1092
+ return;
1093
+ }
1094
+ // Wyłączono aktywną opcję.
1095
+ if (this.allowDeselect()) {
1096
+ this.value.set(null);
1097
+ }
1098
+ else {
1099
+ // Odznaczanie niedozwolone — przywróć zaznaczenie (wymusza ponowne wypchnięcie [checked]).
1100
+ const current = opt.value;
1101
+ this.value.set(null);
1102
+ this.value.set(current);
1103
+ }
1104
+ }
1105
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptSwitchGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
1106
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptSwitchGroup, isStandalone: true, selector: "kpt-switch-group", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, allowDeselect: { classPropertyName: "allowDeselect", publicName: "allowDeselect", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { classAttribute: "kpt-switch-group-host" }, ngImport: i0, template: `
1107
+ <div
1108
+ class="kpt-switch-group"
1109
+ [class.kpt-switch-group--horizontal]="orientation() === 'horizontal'"
1110
+ role="group"
1111
+ [attr.aria-invalid]="invalid() ? 'true' : null"
1112
+ >
1113
+ @for (opt of options(); track opt.value) {
1114
+ <kpt-switch
1115
+ class="kpt-switch-group__item"
1116
+ [checked]="isChecked(opt.value)"
1117
+ [label]="opt.label"
1118
+ [disabled]="disabled() || opt.disabled"
1119
+ (checkedChange)="onToggle(opt, $event)"
1120
+ (touch)="touch.emit()"
1121
+ />
1122
+ }
1123
+ </div>
1124
+ `, isInline: true, styles: ["@layer kpt.components{.kpt-switch-group{display:flex;flex-direction:column;gap:var(--kpt-space-2, .5rem)}.kpt-switch-group--horizontal{flex-direction:row;flex-wrap:wrap;gap:var(--kpt-space-4, 1rem)}}\n"], dependencies: [{ kind: "component", type: KptSwitch, selector: "kpt-switch", inputs: ["checked", "disabled", "invalid", "touched", "label", "labelPosition", "onLabel", "offLabel"], outputs: ["checkedChange", "touch"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1125
+ }
1126
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptSwitchGroup, decorators: [{
1127
+ type: Component,
1128
+ args: [{ selector: 'kpt-switch-group', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [KptSwitch], template: `
1129
+ <div
1130
+ class="kpt-switch-group"
1131
+ [class.kpt-switch-group--horizontal]="orientation() === 'horizontal'"
1132
+ role="group"
1133
+ [attr.aria-invalid]="invalid() ? 'true' : null"
1134
+ >
1135
+ @for (opt of options(); track opt.value) {
1136
+ <kpt-switch
1137
+ class="kpt-switch-group__item"
1138
+ [checked]="isChecked(opt.value)"
1139
+ [label]="opt.label"
1140
+ [disabled]="disabled() || opt.disabled"
1141
+ (checkedChange)="onToggle(opt, $event)"
1142
+ (touch)="touch.emit()"
1143
+ />
1144
+ }
1145
+ </div>
1146
+ `, host: { class: 'kpt-switch-group-host' }, styles: ["@layer kpt.components{.kpt-switch-group{display:flex;flex-direction:column;gap:var(--kpt-space-2, .5rem)}.kpt-switch-group--horizontal{flex-direction:row;flex-wrap:wrap;gap:var(--kpt-space-4, 1rem)}}\n"] }]
1147
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], allowDeselect: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowDeselect", required: false }] }] } });
956
1148
 
957
1149
  let nextGroupId = 0;
958
1150
  /**
@@ -989,7 +1181,7 @@ class KptRadioGroup {
989
1181
  </label>
990
1182
  }
991
1183
  </div>
992
- `, isInline: true, styles: ["@layer kpt.components{.kpt-radio-group{display:flex;flex-direction:column;gap:var(--kpt-space-2, .5rem)}.kpt-radio{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);cursor:pointer;font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface)}.kpt-radio--disabled{cursor:not-allowed;opacity:.55}.kpt-radio__input{position:absolute;opacity:0;width:1px;height:1px}.kpt-radio__dot{position:relative;display:inline-block;width:1.15rem;height:1.15rem;flex-shrink:0;border:var(--kpt-border-width-medium, 2px) solid var(--kpt-form-field-border);border-radius:50%;background:var(--kpt-form-field-bg);transition:border-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-radio__dot:after{content:\"\";position:absolute;inset:0;margin:auto;width:.6rem;height:.6rem;border-radius:50%;background:var(--kpt-color-primary);transform:scale(0);transition:transform var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-radio__input:checked+.kpt-radio__dot{border-color:var(--kpt-color-primary)}.kpt-radio__input:checked+.kpt-radio__dot:after{transform:scale(1)}.kpt-radio__input:focus-visible+.kpt-radio__dot{outline:var(--kpt-border-width-medium, 2px) solid var(--kpt-color-focus-ring);outline-offset:2px}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1184
+ `, isInline: true, styles: ["@layer kpt.components{.kpt-radio-group{display:flex;flex-direction:column;gap:var(--kpt-space-2, .5rem)}.kpt-radio{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);cursor:pointer;font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface)}.kpt-radio--disabled{cursor:not-allowed;opacity:.55}.kpt-radio__input{position:absolute;opacity:0;width:1px;height:1px}.kpt-radio__dot{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;width:1.15rem;height:1.15rem;flex-shrink:0;border:var(--kpt-border-width-medium, 2px) solid var(--kpt-form-field-border);border-radius:50%;background:var(--kpt-form-field-bg);transition:border-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-radio__dot:after{content:\"\";width:.5rem;height:.5rem;border-radius:50%;background:var(--kpt-color-primary);transform:scale(0);transition:transform var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-radio__input:checked+.kpt-radio__dot{border-color:var(--kpt-color-primary)}.kpt-radio__input:checked+.kpt-radio__dot:after{transform:scale(1)}.kpt-radio__input:focus-visible+.kpt-radio__dot{outline:var(--kpt-border-width-medium, 2px) solid var(--kpt-color-focus-ring);outline-offset:2px}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
993
1185
  }
994
1186
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptRadioGroup, decorators: [{
995
1187
  type: Component,
@@ -1011,7 +1203,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
1011
1203
  </label>
1012
1204
  }
1013
1205
  </div>
1014
- `, host: { class: 'kpt-radio-group-host' }, styles: ["@layer kpt.components{.kpt-radio-group{display:flex;flex-direction:column;gap:var(--kpt-space-2, .5rem)}.kpt-radio{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);cursor:pointer;font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface)}.kpt-radio--disabled{cursor:not-allowed;opacity:.55}.kpt-radio__input{position:absolute;opacity:0;width:1px;height:1px}.kpt-radio__dot{position:relative;display:inline-block;width:1.15rem;height:1.15rem;flex-shrink:0;border:var(--kpt-border-width-medium, 2px) solid var(--kpt-form-field-border);border-radius:50%;background:var(--kpt-form-field-bg);transition:border-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-radio__dot:after{content:\"\";position:absolute;inset:0;margin:auto;width:.6rem;height:.6rem;border-radius:50%;background:var(--kpt-color-primary);transform:scale(0);transition:transform var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-radio__input:checked+.kpt-radio__dot{border-color:var(--kpt-color-primary)}.kpt-radio__input:checked+.kpt-radio__dot:after{transform:scale(1)}.kpt-radio__input:focus-visible+.kpt-radio__dot{outline:var(--kpt-border-width-medium, 2px) solid var(--kpt-color-focus-ring);outline-offset:2px}}\n"] }]
1206
+ `, host: { class: 'kpt-radio-group-host' }, styles: ["@layer kpt.components{.kpt-radio-group{display:flex;flex-direction:column;gap:var(--kpt-space-2, .5rem)}.kpt-radio{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);cursor:pointer;font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface)}.kpt-radio--disabled{cursor:not-allowed;opacity:.55}.kpt-radio__input{position:absolute;opacity:0;width:1px;height:1px}.kpt-radio__dot{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;width:1.15rem;height:1.15rem;flex-shrink:0;border:var(--kpt-border-width-medium, 2px) solid var(--kpt-form-field-border);border-radius:50%;background:var(--kpt-form-field-bg);transition:border-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-radio__dot:after{content:\"\";width:.5rem;height:.5rem;border-radius:50%;background:var(--kpt-color-primary);transform:scale(0);transition:transform var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-radio__input:checked+.kpt-radio__dot{border-color:var(--kpt-color-primary)}.kpt-radio__input:checked+.kpt-radio__dot:after{transform:scale(1)}.kpt-radio__input:focus-visible+.kpt-radio__dot{outline:var(--kpt-border-width-medium, 2px) solid var(--kpt-color-focus-ring);outline-offset:2px}}\n"] }]
1015
1207
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }] } });
1016
1208
 
1017
1209
  /**
@@ -1149,6 +1341,287 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
1149
1341
  args: [{ selector: 'kpt-select', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [CdkOverlayOrigin, CdkConnectedOverlay, KptIcon], host: { class: 'kpt-select-host' }, template: "<div\n class=\"kpt-select\"\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n role=\"combobox\"\n tabindex=\"0\"\n [class.kpt-select--open]=\"open()\"\n [class.kpt-select--disabled]=\"disabled()\"\n [class.kpt-select--invalid]=\"invalid()\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-disabled]=\"disabled() || null\"\n (click)=\"toggleOpen()\"\n (keydown)=\"onTriggerKeydown($event)\"\n (blur)=\"touch.emit()\"\n>\n <div class=\"kpt-select__value\">\n @if (multiple() && selectedOptions().length) {\n @for (opt of selectedOptions(); track opt.value) {\n <span class=\"kpt-select__chip\">\n {{ opt.label }}\n <button type=\"button\" class=\"kpt-select__chip-remove\" (click)=\"removeChip(opt, $event)\" aria-label=\"Usu\u0144\">\n <kpt-icon name=\"x\" />\n </button>\n </span>\n }\n } @else if (!multiple() && hasValue()) {\n <span class=\"kpt-select__single\">{{ singleLabel() }}</span>\n } @else {\n <span class=\"kpt-select__placeholder\">{{ placeholder() }}</span>\n }\n </div>\n <kpt-icon class=\"kpt-select__chevron\" name=\"chevron-down\" />\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayWidth]=\"trigger.elementRef.nativeElement.offsetWidth\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\"\n>\n <div class=\"kpt-select__panel\" (keydown)=\"onPanelKeydown($event)\">\n @if (filter()) {\n <div class=\"kpt-select__search\">\n <kpt-icon name=\"search\" />\n <input\n type=\"text\"\n class=\"kpt-select__search-input\"\n [value]=\"filterText()\"\n (input)=\"onFilterInput($event)\"\n placeholder=\"Szukaj\u2026\"\n />\n </div>\n }\n <ul class=\"kpt-select__list\" role=\"listbox\" [attr.aria-multiselectable]=\"multiple()\">\n @for (opt of filteredOptions(); track opt.value; let i = $index) {\n <li\n class=\"kpt-select__option\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected(opt)\"\n [class.kpt-select__option--selected]=\"isSelected(opt)\"\n [class.kpt-select__option--active]=\"i === activeIndex()\"\n [class.kpt-select__option--disabled]=\"opt.disabled\"\n (click)=\"pick(opt)\"\n (mouseenter)=\"activeIndex.set(i)\"\n >\n @if (multiple()) {\n <span class=\"kpt-select__check\" [class.is-on]=\"isSelected(opt)\"><kpt-icon name=\"check\" /></span>\n }\n <span class=\"kpt-select__option-label\">{{ opt.label }}</span>\n @if (!multiple() && isSelected(opt)) {\n <kpt-icon class=\"kpt-select__option-tick\" name=\"check\" />\n }\n </li>\n } @empty {\n <li class=\"kpt-select__empty\">Brak wynik\u00F3w</li>\n }\n </ul>\n </div>\n</ng-template>\n", styles: ["@layer kpt.components{.kpt-select-host{display:block}.kpt-select{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);min-height:2.5rem;padding:.35rem var(--kpt-space-3, .75rem);box-sizing:border-box;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer;transition:border-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-select:hover:not(.kpt-select--disabled){border-color:var(--kpt-form-field-border-hover)}.kpt-select:focus-visible,.kpt-select.kpt-select--open{outline:none;border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-select.kpt-select--invalid{border-color:var(--kpt-form-field-border-error)}.kpt-select.kpt-select--disabled{cursor:not-allowed;opacity:.6;background:var(--kpt-color-surface-variant)}.kpt-select__value{flex:1;min-width:0;display:flex;flex-wrap:wrap;gap:.35rem;align-items:center}.kpt-select__placeholder{color:var(--kpt-form-field-placeholder)}.kpt-select__single{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kpt-select__chip{display:inline-flex;align-items:center;gap:.25rem;padding:.1rem .25rem .1rem .5rem;border-radius:var(--kpt-radius-sm, .25rem);background:var(--kpt-color-muted);color:var(--kpt-color-on-muted);font-size:var(--kpt-font-size-xs, .75rem)}.kpt-select__chip-remove{display:inline-flex;border:0;background:none;cursor:pointer;color:inherit;padding:0;opacity:.7}.kpt-select__chip-remove:hover{opacity:1}.kpt-select__chevron{color:var(--kpt-color-on-surface-muted);transition:transform var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-select.kpt-select--open .kpt-select__chevron{transform:rotate(180deg)}.kpt-select__panel{background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3);overflow:hidden;font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface)}.kpt-select__search{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);color:var(--kpt-color-on-surface-muted)}.kpt-select__search-input{flex:1;min-width:0;border:0;background:none;outline:none;color:var(--kpt-color-on-surface);font:inherit}.kpt-select__search-input::placeholder{color:var(--kpt-color-on-surface-muted)}.kpt-select__list{list-style:none;margin:0;padding:.25rem;max-height:15rem;overflow-y:auto}.kpt-select__option{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);padding:.45rem .6rem;border-radius:var(--kpt-radius-sm, .25rem);cursor:pointer}.kpt-select__option--active{background:var(--kpt-color-surface-variant)}.kpt-select__option--selected{color:var(--kpt-color-on-surface);font-weight:var(--kpt-font-weight-medium, 500)}.kpt-select__option--disabled{opacity:.45;cursor:not-allowed}.kpt-select__option-label{flex:1;min-width:0}.kpt-select__option-tick{color:var(--kpt-color-primary)}.kpt-select__check{display:inline-flex;align-items:center;justify-content:center;width:1.05rem;height:1.05rem;flex-shrink:0;border:var(--kpt-border-width-medium, 2px) solid var(--kpt-form-field-border);border-radius:var(--kpt-radius-sm, .25rem);color:var(--kpt-color-on-primary);font-size:.7rem}.kpt-select__check kpt-icon{opacity:0}.kpt-select__check.is-on{background:var(--kpt-color-primary);border-color:var(--kpt-color-primary)}.kpt-select__check.is-on kpt-icon{opacity:1}.kpt-select__empty{list-style:none;padding:.75rem .6rem;color:var(--kpt-color-on-surface-muted);text-align:center}}\n"] }]
1150
1342
  }], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }] } });
1151
1343
 
1344
+ const R_OUTER = 40;
1345
+ const R_INNER = 26;
1346
+ const pad$2 = (n) => String(n).padStart(2, '0');
1347
+ /**
1348
+ * Tarcza zegara (wybór godziny) — dwa etapy: godziny → minuty, klik lub przeciąganie.
1349
+ * Format 12/24h (`hourFormat`); w 24h dodatkowy wewnętrzny pierścień 13–00, w 12h AM/PM.
1350
+ * Wartość `HH:mm` (zawsze 24h). Używana przez `kpt-datepicker` i `kpt-date-range`.
1351
+ *
1352
+ * @example
1353
+ * <kpt-clock [(value)]="time" [hourFormat]="12" [minuteStep]="5" />
1354
+ */
1355
+ class KptClock {
1356
+ value = model('', /* @ts-ignore */
1357
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
1358
+ hourFormat = input(24, { ...(ngDevMode ? { debugName: "hourFormat" } : /* istanbul ignore next */ {}), transform: numberAttribute });
1359
+ minuteStep = input(1, { ...(ngDevMode ? { debugName: "minuteStep" } : /* istanbul ignore next */ {}), transform: numberAttribute });
1360
+ hour = signal(0, /* @ts-ignore */
1361
+ ...(ngDevMode ? [{ debugName: "hour" }] : /* istanbul ignore next */ []));
1362
+ minute = signal(0, /* @ts-ignore */
1363
+ ...(ngDevMode ? [{ debugName: "minute" }] : /* istanbul ignore next */ []));
1364
+ clockPhase = signal('hours', /* @ts-ignore */
1365
+ ...(ngDevMode ? [{ debugName: "clockPhase" }] : /* istanbul ignore next */ []));
1366
+ constructor() {
1367
+ // Synchronizacja wartości zewnętrznej → stan tarczy (zapis idempotentny, bez pętli).
1368
+ effect(() => {
1369
+ const t = this.parse(this.value());
1370
+ this.hour.set(t?.h ?? 0);
1371
+ this.minute.set(t?.m ?? 0);
1372
+ });
1373
+ }
1374
+ parse(v) {
1375
+ const m = /^(\d{2}):(\d{2})$/.exec(v ?? '');
1376
+ return m ? { h: +m[1], m: +m[2] } : null;
1377
+ }
1378
+ emit() {
1379
+ this.value.set(`${pad$2(this.hour())}:${pad$2(this.minute())}`);
1380
+ }
1381
+ ampm = computed(() => (this.hour() < 12 ? 'AM' : 'PM'), /* @ts-ignore */
1382
+ ...(ngDevMode ? [{ debugName: "ampm" }] : /* istanbul ignore next */ []));
1383
+ hour12 = computed(() => {
1384
+ const h = this.hour() % 12;
1385
+ return h === 0 ? 12 : h;
1386
+ }, /* @ts-ignore */
1387
+ ...(ngDevMode ? [{ debugName: "hour12" }] : /* istanbul ignore next */ []));
1388
+ hourLabel = computed(() => this.hourFormat() === 12 ? String(this.hour12()) : pad$2(this.hour()), /* @ts-ignore */
1389
+ ...(ngDevMode ? [{ debugName: "hourLabel" }] : /* istanbul ignore next */ []));
1390
+ minuteLabel = computed(() => pad$2(this.minute()), /* @ts-ignore */
1391
+ ...(ngDevMode ? [{ debugName: "minuteLabel" }] : /* istanbul ignore next */ []));
1392
+ from12h(h12, ap) {
1393
+ const base = h12 % 12; // 12 → 0
1394
+ return ap === 'PM' ? base + 12 : base;
1395
+ }
1396
+ hourMarks = computed(() => {
1397
+ const marks = [];
1398
+ if (this.hourFormat() === 12) {
1399
+ const ap = this.ampm();
1400
+ const curH12 = this.hour12();
1401
+ for (let i = 0; i < 12; i++) {
1402
+ const theta = (i / 12) * 2 * Math.PI;
1403
+ const h12 = i === 0 ? 12 : i;
1404
+ marks.push({
1405
+ label: String(h12),
1406
+ hour24: this.from12h(h12, ap),
1407
+ x: 50 + R_OUTER * Math.sin(theta),
1408
+ y: 50 - R_OUTER * Math.cos(theta),
1409
+ inner: false,
1410
+ selected: curH12 === h12,
1411
+ });
1412
+ }
1413
+ return marks;
1414
+ }
1415
+ const cur = this.hour();
1416
+ for (let i = 0; i < 12; i++) {
1417
+ const theta = (i / 12) * 2 * Math.PI;
1418
+ const hour24 = i === 0 ? 12 : i;
1419
+ marks.push({
1420
+ label: i === 0 ? '12' : String(i),
1421
+ hour24,
1422
+ x: 50 + R_OUTER * Math.sin(theta),
1423
+ y: 50 - R_OUTER * Math.cos(theta),
1424
+ inner: false,
1425
+ selected: cur === hour24,
1426
+ });
1427
+ }
1428
+ for (let i = 0; i < 12; i++) {
1429
+ const theta = (i / 12) * 2 * Math.PI;
1430
+ const hour24 = i === 0 ? 0 : i + 12;
1431
+ marks.push({
1432
+ label: i === 0 ? '00' : String(i + 12),
1433
+ hour24,
1434
+ x: 50 + R_INNER * Math.sin(theta),
1435
+ y: 50 - R_INNER * Math.cos(theta),
1436
+ inner: true,
1437
+ selected: cur === hour24,
1438
+ });
1439
+ }
1440
+ return marks;
1441
+ }, /* @ts-ignore */
1442
+ ...(ngDevMode ? [{ debugName: "hourMarks" }] : /* istanbul ignore next */ []));
1443
+ minuteMarks = computed(() => {
1444
+ const cur = this.minute();
1445
+ return Array.from({ length: 12 }, (_, i) => {
1446
+ const val = i * 5;
1447
+ const theta = (i / 12) * 2 * Math.PI;
1448
+ return {
1449
+ label: pad$2(val),
1450
+ hour24: val,
1451
+ x: 50 + R_OUTER * Math.sin(theta),
1452
+ y: 50 - R_OUTER * Math.cos(theta),
1453
+ inner: false,
1454
+ selected: cur === val,
1455
+ };
1456
+ });
1457
+ }, /* @ts-ignore */
1458
+ ...(ngDevMode ? [{ debugName: "minuteMarks" }] : /* istanbul ignore next */ []));
1459
+ handAngle = computed(() => this.clockPhase() === 'hours' ? (this.hour() % 12) * 30 : this.minute() * 6, /* @ts-ignore */
1460
+ ...(ngDevMode ? [{ debugName: "handAngle" }] : /* istanbul ignore next */ []));
1461
+ handInner = computed(() => this.clockPhase() === 'hours' && this.hourFormat() === 24 && (this.hour() === 0 || this.hour() >= 13), /* @ts-ignore */
1462
+ ...(ngDevMode ? [{ debugName: "handInner" }] : /* istanbul ignore next */ []));
1463
+ setPhase(phase) {
1464
+ this.clockPhase.set(phase);
1465
+ }
1466
+ setAmpm(target) {
1467
+ this.hour.set(this.from12h(this.hour12(), target));
1468
+ this.emit();
1469
+ }
1470
+ pickHour(mark) {
1471
+ this.hour.set(mark.hour24);
1472
+ this.clockPhase.set('minutes');
1473
+ this.emit();
1474
+ }
1475
+ pickMinute(mark) {
1476
+ this.minute.set(mark.hour24);
1477
+ this.emit();
1478
+ }
1479
+ onDialPointer(event, face) {
1480
+ if (event.type === 'pointerdown')
1481
+ face.setPointerCapture(event.pointerId);
1482
+ else if (!(event.buttons & 1))
1483
+ return;
1484
+ const rect = face.getBoundingClientRect();
1485
+ const dx = event.clientX - (rect.left + rect.width / 2);
1486
+ const dy = event.clientY - (rect.top + rect.height / 2);
1487
+ let deg = (Math.atan2(dx, -dy) * 180) / Math.PI;
1488
+ if (deg < 0)
1489
+ deg += 360;
1490
+ if (this.clockPhase() === 'hours') {
1491
+ const idx = Math.round(deg / 30) % 12;
1492
+ if (this.hourFormat() === 12) {
1493
+ const h12 = idx === 0 ? 12 : idx;
1494
+ this.hour.set(this.from12h(h12, this.ampm()));
1495
+ }
1496
+ else {
1497
+ const radius = Math.hypot(dx, dy) / (rect.width / 2);
1498
+ const inner = radius < (R_OUTER + R_INNER) / 2 / 50;
1499
+ this.hour.set(inner ? (idx === 0 ? 0 : idx + 12) : idx === 0 ? 12 : idx);
1500
+ }
1501
+ }
1502
+ else {
1503
+ const step = Math.max(1, this.minuteStep());
1504
+ const raw = Math.round(deg / 6) % 60;
1505
+ this.minute.set((Math.round(raw / step) * step) % 60);
1506
+ }
1507
+ this.emit();
1508
+ }
1509
+ onDialUp() {
1510
+ if (this.clockPhase() === 'hours')
1511
+ this.clockPhase.set('minutes');
1512
+ }
1513
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptClock, deps: [], target: i0.ɵɵFactoryTarget.Component });
1514
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptClock, isStandalone: true, selector: "kpt-clock", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, hourFormat: { classPropertyName: "hourFormat", publicName: "hourFormat", isSignal: true, isRequired: false, transformFunction: null }, minuteStep: { classPropertyName: "minuteStep", publicName: "minuteStep", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { classAttribute: "kpt-clock-host" }, ngImport: i0, template: `
1515
+ <div class="kpt-clock">
1516
+ <div class="kpt-clock__time">
1517
+ <button type="button" class="kpt-clock__seg" [class.is-active]="clockPhase() === 'hours'" (click)="setPhase('hours')">{{ hourLabel() }}</button>
1518
+ <span class="kpt-clock__colon">:</span>
1519
+ <button type="button" class="kpt-clock__seg" [class.is-active]="clockPhase() === 'minutes'" (click)="setPhase('minutes')">{{ minuteLabel() }}</button>
1520
+ @if (hourFormat() === 12) {
1521
+ <div class="kpt-clock__ampm">
1522
+ <button type="button" [class.is-active]="ampm() === 'AM'" (click)="setAmpm('AM')">AM</button>
1523
+ <button type="button" [class.is-active]="ampm() === 'PM'" (click)="setAmpm('PM')">PM</button>
1524
+ </div>
1525
+ }
1526
+ </div>
1527
+ <div
1528
+ class="kpt-clock__face"
1529
+ #face
1530
+ (pointerdown)="onDialPointer($event, face)"
1531
+ (pointermove)="onDialPointer($event, face)"
1532
+ (pointerup)="onDialUp()"
1533
+ >
1534
+ <span class="kpt-clock__center"></span>
1535
+ <span
1536
+ class="kpt-clock__hand"
1537
+ [class.kpt-clock__hand--inner]="handInner()"
1538
+ [style.transform]="'rotate(' + handAngle() + 'deg)'"
1539
+ ></span>
1540
+ @if (clockPhase() === 'hours') {
1541
+ @for (mark of hourMarks(); track mark.hour24) {
1542
+ <button
1543
+ type="button"
1544
+ class="kpt-clock__num"
1545
+ [class.kpt-clock__num--inner]="mark.inner"
1546
+ [class.kpt-clock__num--selected]="mark.selected"
1547
+ [style.left.%]="mark.x"
1548
+ [style.top.%]="mark.y"
1549
+ (click)="pickHour(mark)"
1550
+ >{{ mark.label }}</button>
1551
+ }
1552
+ } @else {
1553
+ @for (mark of minuteMarks(); track mark.hour24) {
1554
+ <button
1555
+ type="button"
1556
+ class="kpt-clock__num"
1557
+ [class.kpt-clock__num--selected]="mark.selected"
1558
+ [style.left.%]="mark.x"
1559
+ [style.top.%]="mark.y"
1560
+ (click)="pickMinute(mark)"
1561
+ >{{ mark.label }}</button>
1562
+ }
1563
+ }
1564
+ </div>
1565
+ </div>
1566
+ `, isInline: true, styles: ["@layer kpt.components{.kpt-clock-host{display:block}.kpt-clock__time{display:flex;align-items:center;justify-content:center;gap:var(--kpt-space-1, .25rem);margin-bottom:var(--kpt-space-3, .75rem);font-variant-numeric:tabular-nums}.kpt-clock__seg{border:0;background:none;padding:.1rem .4rem;border-radius:var(--kpt-radius-sm, .25rem);font-size:var(--kpt-font-size-2xl, 1.5rem);font-weight:var(--kpt-font-weight-semibold, 600);color:var(--kpt-color-on-surface-muted);cursor:pointer}.kpt-clock__seg.is-active{color:var(--kpt-color-primary);background:var(--kpt-color-muted)}.kpt-clock__colon{font-size:var(--kpt-font-size-2xl, 1.5rem);font-weight:var(--kpt-font-weight-semibold, 600);color:var(--kpt-color-on-surface-muted)}.kpt-clock__ampm{display:flex;flex-direction:column;gap:2px;margin-inline-start:var(--kpt-space-2, .5rem)}.kpt-clock__ampm button{border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);background:none;padding:.1rem .4rem;border-radius:var(--kpt-radius-sm, .25rem);font-size:var(--kpt-font-size-xs, .75rem);font-weight:var(--kpt-font-weight-semibold, 600);color:var(--kpt-color-on-surface-muted);cursor:pointer}.kpt-clock__ampm button.is-active{background:var(--kpt-color-primary);border-color:var(--kpt-color-primary);color:var(--kpt-color-on-primary)}.kpt-clock__face{position:relative;width:13rem;max-width:100%;aspect-ratio:1;margin:0 auto;border-radius:50%;background:var(--kpt-color-surface-variant);touch-action:none;-webkit-user-select:none;user-select:none}.kpt-clock__center{position:absolute;left:50%;top:50%;width:8px;height:8px;transform:translate(-50%,-50%);border-radius:50%;background:var(--kpt-color-primary);z-index:2}.kpt-clock__hand{position:absolute;left:50%;bottom:50%;width:2px;height:40%;margin-left:-1px;transform-origin:bottom center;background:var(--kpt-color-primary);z-index:1}.kpt-clock__hand--inner{height:26%}.kpt-clock__hand:before{content:\"\";position:absolute;top:-3px;left:50%;width:8px;height:8px;transform:translate(-50%);border-radius:50%;background:var(--kpt-color-primary)}.kpt-clock__num{position:absolute;transform:translate(-50%,-50%);display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:50%;background:none;color:var(--kpt-color-on-surface);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer;z-index:2}.kpt-clock__num:hover{background:var(--kpt-color-muted)}.kpt-clock__num--inner{width:1.6rem;height:1.6rem;font-size:var(--kpt-font-size-xs, .75rem);color:var(--kpt-color-on-surface-muted)}.kpt-clock__num--selected{background:var(--kpt-color-primary)!important;color:var(--kpt-color-on-primary)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1567
+ }
1568
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptClock, decorators: [{
1569
+ type: Component,
1570
+ args: [{ selector: 'kpt-clock', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: `
1571
+ <div class="kpt-clock">
1572
+ <div class="kpt-clock__time">
1573
+ <button type="button" class="kpt-clock__seg" [class.is-active]="clockPhase() === 'hours'" (click)="setPhase('hours')">{{ hourLabel() }}</button>
1574
+ <span class="kpt-clock__colon">:</span>
1575
+ <button type="button" class="kpt-clock__seg" [class.is-active]="clockPhase() === 'minutes'" (click)="setPhase('minutes')">{{ minuteLabel() }}</button>
1576
+ @if (hourFormat() === 12) {
1577
+ <div class="kpt-clock__ampm">
1578
+ <button type="button" [class.is-active]="ampm() === 'AM'" (click)="setAmpm('AM')">AM</button>
1579
+ <button type="button" [class.is-active]="ampm() === 'PM'" (click)="setAmpm('PM')">PM</button>
1580
+ </div>
1581
+ }
1582
+ </div>
1583
+ <div
1584
+ class="kpt-clock__face"
1585
+ #face
1586
+ (pointerdown)="onDialPointer($event, face)"
1587
+ (pointermove)="onDialPointer($event, face)"
1588
+ (pointerup)="onDialUp()"
1589
+ >
1590
+ <span class="kpt-clock__center"></span>
1591
+ <span
1592
+ class="kpt-clock__hand"
1593
+ [class.kpt-clock__hand--inner]="handInner()"
1594
+ [style.transform]="'rotate(' + handAngle() + 'deg)'"
1595
+ ></span>
1596
+ @if (clockPhase() === 'hours') {
1597
+ @for (mark of hourMarks(); track mark.hour24) {
1598
+ <button
1599
+ type="button"
1600
+ class="kpt-clock__num"
1601
+ [class.kpt-clock__num--inner]="mark.inner"
1602
+ [class.kpt-clock__num--selected]="mark.selected"
1603
+ [style.left.%]="mark.x"
1604
+ [style.top.%]="mark.y"
1605
+ (click)="pickHour(mark)"
1606
+ >{{ mark.label }}</button>
1607
+ }
1608
+ } @else {
1609
+ @for (mark of minuteMarks(); track mark.hour24) {
1610
+ <button
1611
+ type="button"
1612
+ class="kpt-clock__num"
1613
+ [class.kpt-clock__num--selected]="mark.selected"
1614
+ [style.left.%]="mark.x"
1615
+ [style.top.%]="mark.y"
1616
+ (click)="pickMinute(mark)"
1617
+ >{{ mark.label }}</button>
1618
+ }
1619
+ }
1620
+ </div>
1621
+ </div>
1622
+ `, host: { class: 'kpt-clock-host' }, styles: ["@layer kpt.components{.kpt-clock-host{display:block}.kpt-clock__time{display:flex;align-items:center;justify-content:center;gap:var(--kpt-space-1, .25rem);margin-bottom:var(--kpt-space-3, .75rem);font-variant-numeric:tabular-nums}.kpt-clock__seg{border:0;background:none;padding:.1rem .4rem;border-radius:var(--kpt-radius-sm, .25rem);font-size:var(--kpt-font-size-2xl, 1.5rem);font-weight:var(--kpt-font-weight-semibold, 600);color:var(--kpt-color-on-surface-muted);cursor:pointer}.kpt-clock__seg.is-active{color:var(--kpt-color-primary);background:var(--kpt-color-muted)}.kpt-clock__colon{font-size:var(--kpt-font-size-2xl, 1.5rem);font-weight:var(--kpt-font-weight-semibold, 600);color:var(--kpt-color-on-surface-muted)}.kpt-clock__ampm{display:flex;flex-direction:column;gap:2px;margin-inline-start:var(--kpt-space-2, .5rem)}.kpt-clock__ampm button{border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);background:none;padding:.1rem .4rem;border-radius:var(--kpt-radius-sm, .25rem);font-size:var(--kpt-font-size-xs, .75rem);font-weight:var(--kpt-font-weight-semibold, 600);color:var(--kpt-color-on-surface-muted);cursor:pointer}.kpt-clock__ampm button.is-active{background:var(--kpt-color-primary);border-color:var(--kpt-color-primary);color:var(--kpt-color-on-primary)}.kpt-clock__face{position:relative;width:13rem;max-width:100%;aspect-ratio:1;margin:0 auto;border-radius:50%;background:var(--kpt-color-surface-variant);touch-action:none;-webkit-user-select:none;user-select:none}.kpt-clock__center{position:absolute;left:50%;top:50%;width:8px;height:8px;transform:translate(-50%,-50%);border-radius:50%;background:var(--kpt-color-primary);z-index:2}.kpt-clock__hand{position:absolute;left:50%;bottom:50%;width:2px;height:40%;margin-left:-1px;transform-origin:bottom center;background:var(--kpt-color-primary);z-index:1}.kpt-clock__hand--inner{height:26%}.kpt-clock__hand:before{content:\"\";position:absolute;top:-3px;left:50%;width:8px;height:8px;transform:translate(-50%);border-radius:50%;background:var(--kpt-color-primary)}.kpt-clock__num{position:absolute;transform:translate(-50%,-50%);display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:50%;background:none;color:var(--kpt-color-on-surface);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer;z-index:2}.kpt-clock__num:hover{background:var(--kpt-color-muted)}.kpt-clock__num--inner{width:1.6rem;height:1.6rem;font-size:var(--kpt-font-size-xs, .75rem);color:var(--kpt-color-on-surface-muted)}.kpt-clock__num--selected{background:var(--kpt-color-primary)!important;color:var(--kpt-color-on-primary)}}\n"] }]
1623
+ }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], hourFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "hourFormat", required: false }] }], minuteStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }] } });
1624
+
1152
1625
  const WEEKDAYS$1 = ['Pn', 'Wt', 'Śr', 'Cz', 'Pt', 'So', 'Nd'];
1153
1626
  const MONTHS$1 = [
1154
1627
  'styczeń', 'luty', 'marzec', 'kwiecień', 'maj', 'czerwiec',
@@ -1157,11 +1630,17 @@ const MONTHS$1 = [
1157
1630
  const pad$1 = (n) => String(n).padStart(2, '0');
1158
1631
  const toIso$1 = (d) => `${d.getFullYear()}-${pad$1(d.getMonth() + 1)}-${pad$1(d.getDate())}`;
1159
1632
  /**
1160
- * Wybór daty z własnym kalendarzem (CDK Overlay), Signal Forms. Wartość ISO 'RRRR-MM-DD'.
1633
+ * Wybór daty/godziny z własnym kalendarzem (CDK Overlay), Signal Forms.
1634
+ * Granulacja przez `selectionMode`: data, miesiąc+rok, rok, miesiąc, data+godzina, sama godzina.
1635
+ * Godzina na tarczy zegara (dwa etapy: godziny → minuty), format 12/24h przez `hourFormat`.
1636
+ * Format wartości zależy od trybu: 'RRRR-MM-DD' / 'RRRR-MM' / 'RRRR' / 'MM'
1637
+ * / 'RRRR-MM-DDTHH:mm' (datetime) / 'HH:mm' (time). Czas przechowywany zawsze 24h.
1161
1638
  * Wymaga stylów overlay CDK: `import '@angular/cdk/overlay-prebuilt.css';`
1162
1639
  *
1163
1640
  * @example
1164
1641
  * <kpt-datepicker [formField]="f.birthDate" minDate="1900-01-01" />
1642
+ * <kpt-datepicker selectionMode="datetime" [hourFormat]="12" [(value)]="meetingAt" />
1643
+ * <kpt-datepicker selectionMode="time" [(value)]="alarm" />
1165
1644
  */
1166
1645
  class KptDatepicker {
1167
1646
  value = model('', /* @ts-ignore */
@@ -1170,38 +1649,132 @@ class KptDatepicker {
1170
1649
  invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1171
1650
  touched = input(false, { ...(ngDevMode ? { debugName: "touched" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1172
1651
  touch = output();
1173
- placeholder = input('RRRR-MM-DD', /* @ts-ignore */
1652
+ placeholder = input('', /* @ts-ignore */
1174
1653
  ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
1654
+ displayFormat = input('pl', /* @ts-ignore */
1655
+ ...(ngDevMode ? [{ debugName: "displayFormat" }] : /* istanbul ignore next */ []));
1656
+ /** Granulacja wyboru. */
1657
+ selectionMode = input('date', /* @ts-ignore */
1658
+ ...(ngDevMode ? [{ debugName: "selectionMode" }] : /* istanbul ignore next */ []));
1659
+ /** Prezentacja miesiąca w trybie 'month': słownie ('long') lub liczbą ('number'). */
1660
+ monthDisplay = input('long', /* @ts-ignore */
1661
+ ...(ngDevMode ? [{ debugName: "monthDisplay" }] : /* istanbul ignore next */ []));
1662
+ /** Format godziny: 24 lub 12 (z AM/PM). */
1663
+ hourFormat = input(24, { ...(ngDevMode ? { debugName: "hourFormat" } : /* istanbul ignore next */ {}), transform: numberAttribute });
1664
+ /** Krok minut (snap na tarczy). */
1665
+ minuteStep = input(1, { ...(ngDevMode ? { debugName: "minuteStep" } : /* istanbul ignore next */ {}), transform: numberAttribute });
1175
1666
  minDate = input(null, /* @ts-ignore */
1176
1667
  ...(ngDevMode ? [{ debugName: "minDate" }] : /* istanbul ignore next */ []));
1177
1668
  maxDate = input(null, /* @ts-ignore */
1178
1669
  ...(ngDevMode ? [{ debugName: "maxDate" }] : /* istanbul ignore next */ []));
1670
+ effectivePlaceholder = computed(() => {
1671
+ if (this.placeholder())
1672
+ return this.placeholder();
1673
+ const iso = this.displayFormat() === 'iso';
1674
+ const time = this.hourFormat() === 12 ? '--:-- --' : '--:--';
1675
+ switch (this.selectionMode()) {
1676
+ case 'monthYear': return iso ? 'RRRR-MM' : 'MM.RRRR';
1677
+ case 'year': return 'RRRR';
1678
+ case 'month': return this.monthDisplay() === 'number' ? 'MM' : 'Miesiąc';
1679
+ case 'time': return time;
1680
+ case 'datetime': return `${iso ? 'RRRR-MM-DD' : 'DD.MM.RRRR'} ${time}`;
1681
+ default: return iso ? 'RRRR-MM-DD' : 'DD.MM.RRRR';
1682
+ }
1683
+ }, /* @ts-ignore */
1684
+ ...(ngDevMode ? [{ debugName: "effectivePlaceholder" }] : /* istanbul ignore next */ []));
1179
1685
  weekdays = WEEKDAYS$1;
1180
1686
  open = signal(false, /* @ts-ignore */
1181
1687
  ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
1182
1688
  today = new Date();
1183
1689
  view = signal({ y: this.today.getFullYear(), m: this.today.getMonth() }, /* @ts-ignore */
1184
1690
  ...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
1691
+ // ── Stan czasu (bufor 'HH:mm', 24h) ──
1692
+ timeStr = signal('', /* @ts-ignore */
1693
+ ...(ngDevMode ? [{ debugName: "timeStr" }] : /* istanbul ignore next */ []));
1694
+ dtView = signal('calendar', /* @ts-ignore */
1695
+ ...(ngDevMode ? [{ debugName: "dtView" }] : /* istanbul ignore next */ []));
1696
+ pendingDate = signal('', /* @ts-ignore */
1697
+ ...(ngDevMode ? [{ debugName: "pendingDate" }] : /* istanbul ignore next */ []));
1185
1698
  positions = [
1186
1699
  { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
1187
1700
  { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
1188
1701
  ];
1702
+ viewYear = computed(() => this.view().y, /* @ts-ignore */
1703
+ ...(ngDevMode ? [{ debugName: "viewYear" }] : /* istanbul ignore next */ []));
1189
1704
  monthLabel = computed(() => {
1190
1705
  const { y, m } = this.view();
1191
1706
  return `${MONTHS$1[m]} ${y}`;
1192
1707
  }, /* @ts-ignore */
1193
1708
  ...(ngDevMode ? [{ debugName: "monthLabel" }] : /* istanbul ignore next */ []));
1709
+ yearPageStart = computed(() => {
1710
+ const y = this.view().y;
1711
+ return y - (((y % 12) + 12) % 12);
1712
+ }, /* @ts-ignore */
1713
+ ...(ngDevMode ? [{ debugName: "yearPageStart" }] : /* istanbul ignore next */ []));
1714
+ yearRangeLabel = computed(() => `${this.yearPageStart()} – ${this.yearPageStart() + 11}`, /* @ts-ignore */
1715
+ ...(ngDevMode ? [{ debugName: "yearRangeLabel" }] : /* istanbul ignore next */ []));
1716
+ // ── Prezentacja czasu ──
1717
+ formatTime(h, m) {
1718
+ if (this.hourFormat() === 12) {
1719
+ const h12 = h % 12 === 0 ? 12 : h % 12;
1720
+ return `${h12}:${pad$1(m)} ${h < 12 ? 'AM' : 'PM'}`;
1721
+ }
1722
+ return `${pad$1(h)}:${pad$1(m)}`;
1723
+ }
1724
+ /** Etykieta czasu na pasku trybu datetime (uwzględnia AM/PM). */
1725
+ timeBarLabel = computed(() => {
1726
+ const t = this.parseTime(this.timeStr());
1727
+ return this.formatTime(t?.h ?? 0, t?.m ?? 0);
1728
+ }, /* @ts-ignore */
1729
+ ...(ngDevMode ? [{ debugName: "timeBarLabel" }] : /* istanbul ignore next */ []));
1194
1730
  display = computed(() => {
1195
- const d = this.parse(this.value());
1196
- return d ? `${pad$1(d.getDate())}.${pad$1(d.getMonth() + 1)}.${d.getFullYear()}` : '';
1731
+ const v = this.value();
1732
+ if (!v)
1733
+ return '';
1734
+ const iso = this.displayFormat() === 'iso';
1735
+ switch (this.selectionMode()) {
1736
+ case 'monthYear': {
1737
+ const m = /^(\d{4})-(\d{2})$/.exec(v);
1738
+ return m ? (iso ? v : `${m[2]}.${m[1]}`) : '';
1739
+ }
1740
+ case 'year':
1741
+ return /^\d{4}$/.test(v) ? v : '';
1742
+ case 'month': {
1743
+ const m = /^(\d{2})$/.exec(v);
1744
+ if (!m)
1745
+ return '';
1746
+ return this.monthDisplay() === 'number' ? m[1] : (MONTHS$1[+m[1] - 1] ?? '');
1747
+ }
1748
+ case 'time': {
1749
+ const t = this.parseTime(v);
1750
+ return t ? this.formatTime(t.h, t.m) : '';
1751
+ }
1752
+ case 'datetime': {
1753
+ const dt = this.parseDateTime(v);
1754
+ if (!dt)
1755
+ return '';
1756
+ const datePart = iso ? dt.date : `${dt.date.slice(8, 10)}.${dt.date.slice(5, 7)}.${dt.date.slice(0, 4)}`;
1757
+ const sep = iso ? 'T' : ' ';
1758
+ return `${datePart}${sep}${this.formatTime(dt.h, dt.m)}`;
1759
+ }
1760
+ default: {
1761
+ const d = this.parseDate(v);
1762
+ if (!d)
1763
+ return '';
1764
+ return iso ? toIso$1(d) : `${pad$1(d.getDate())}.${pad$1(d.getMonth() + 1)}.${d.getFullYear()}`;
1765
+ }
1766
+ }
1197
1767
  }, /* @ts-ignore */
1198
1768
  ...(ngDevMode ? [{ debugName: "display" }] : /* istanbul ignore next */ []));
1769
+ // ── Siatka dni (tryby 'date' / 'datetime') ──
1770
+ selectedDateIso = computed(() => this.selectionMode() === 'datetime' ? this.pendingDate() : this.value(), /* @ts-ignore */
1771
+ ...(ngDevMode ? [{ debugName: "selectedDateIso" }] : /* istanbul ignore next */ []));
1199
1772
  weeks = computed(() => {
1200
1773
  const { y, m } = this.view();
1201
1774
  const first = new Date(y, m, 1);
1202
1775
  const startOffset = (first.getDay() + 6) % 7; // poniedziałek = 0
1203
1776
  const start = new Date(y, m, 1 - startOffset);
1204
- const sel = this.value();
1777
+ const sel = this.selectedDateIso();
1205
1778
  const min = this.minDate();
1206
1779
  const max = this.maxDate();
1207
1780
  const todayIso = toIso$1(this.today);
@@ -1225,18 +1798,113 @@ class KptDatepicker {
1225
1798
  return weeks;
1226
1799
  }, /* @ts-ignore */
1227
1800
  ...(ngDevMode ? [{ debugName: "weeks" }] : /* istanbul ignore next */ []));
1228
- parse(iso) {
1801
+ // ── Siatka miesięcy (tryby 'monthYear' / 'month') ──
1802
+ monthCells = computed(() => {
1803
+ const { y } = this.view();
1804
+ const sel = this.value();
1805
+ const isMonthOnly = this.selectionMode() === 'month';
1806
+ const numeric = this.monthDisplay() === 'number';
1807
+ return MONTHS$1.map((name, i) => {
1808
+ const mm = pad$1(i + 1);
1809
+ const value = isMonthOnly ? mm : `${y}-${mm}`;
1810
+ return {
1811
+ label: numeric ? mm : name,
1812
+ value,
1813
+ selected: sel === value,
1814
+ disabled: isMonthOnly ? false : this.isMonthYearDisabled(y, i),
1815
+ };
1816
+ });
1817
+ }, /* @ts-ignore */
1818
+ ...(ngDevMode ? [{ debugName: "monthCells" }] : /* istanbul ignore next */ []));
1819
+ // ── Siatka lat (tryb 'year') ──
1820
+ yearCells = computed(() => {
1821
+ const start = this.yearPageStart();
1822
+ const sel = this.value();
1823
+ return Array.from({ length: 12 }, (_, i) => {
1824
+ const year = start + i;
1825
+ const value = String(year);
1826
+ return { label: value, value, selected: sel === value, disabled: this.isYearDisabled(year) };
1827
+ });
1828
+ }, /* @ts-ignore */
1829
+ ...(ngDevMode ? [{ debugName: "yearCells" }] : /* istanbul ignore next */ []));
1830
+ // ── Parsowanie ──
1831
+ parseDate(iso) {
1229
1832
  const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(iso ?? '');
1230
1833
  if (!match)
1231
1834
  return null;
1232
1835
  return new Date(+match[1], +match[2] - 1, +match[3]);
1233
1836
  }
1837
+ parseTime(v) {
1838
+ const m = /^(\d{2}):(\d{2})$/.exec(v ?? '');
1839
+ return m ? { h: +m[1], m: +m[2] } : null;
1840
+ }
1841
+ parseDateTime(v) {
1842
+ const m = /^(\d{4}-\d{2}-\d{2})[T ](\d{2}):(\d{2})$/.exec(v ?? '');
1843
+ return m ? { date: m[1], h: +m[2], m: +m[3] } : null;
1844
+ }
1845
+ isYearDisabled(year) {
1846
+ const min = this.minDate();
1847
+ const max = this.maxDate();
1848
+ if (min && year < +min.slice(0, 4))
1849
+ return true;
1850
+ if (max && year > +max.slice(0, 4))
1851
+ return true;
1852
+ return false;
1853
+ }
1854
+ isMonthYearDisabled(y, monthIndex) {
1855
+ const ym = `${y}-${pad$1(monthIndex + 1)}`;
1856
+ const min = this.minDate();
1857
+ const max = this.maxDate();
1858
+ if (min && ym < min.slice(0, 7))
1859
+ return true;
1860
+ if (max && ym > max.slice(0, 7))
1861
+ return true;
1862
+ return false;
1863
+ }
1864
+ initialView() {
1865
+ const v = this.value();
1866
+ switch (this.selectionMode()) {
1867
+ case 'monthYear': {
1868
+ const m = /^(\d{4})-(\d{2})$/.exec(v);
1869
+ return m ? { y: +m[1], m: +m[2] - 1 } : { y: this.today.getFullYear(), m: this.today.getMonth() };
1870
+ }
1871
+ case 'year':
1872
+ return { y: /^\d{4}$/.test(v) ? +v : this.today.getFullYear(), m: 0 };
1873
+ case 'month':
1874
+ return { y: this.today.getFullYear(), m: 0 };
1875
+ case 'datetime': {
1876
+ const dt = this.parseDateTime(v);
1877
+ if (dt) {
1878
+ const d = this.parseDate(dt.date);
1879
+ return { y: d.getFullYear(), m: d.getMonth() };
1880
+ }
1881
+ return { y: this.today.getFullYear(), m: this.today.getMonth() };
1882
+ }
1883
+ default: {
1884
+ const d = this.parseDate(v) ?? this.today;
1885
+ return { y: d.getFullYear(), m: d.getMonth() };
1886
+ }
1887
+ }
1888
+ }
1889
+ syncTimeFromValue() {
1890
+ const mode = this.selectionMode();
1891
+ if (mode === 'time') {
1892
+ const t = this.parseTime(this.value());
1893
+ this.timeStr.set(t ? `${pad$1(t.h)}:${pad$1(t.m)}` : '00:00');
1894
+ }
1895
+ else if (mode === 'datetime') {
1896
+ const dt = this.parseDateTime(this.value());
1897
+ this.timeStr.set(dt ? `${pad$1(dt.h)}:${pad$1(dt.m)}` : '00:00');
1898
+ this.pendingDate.set(dt?.date ?? '');
1899
+ }
1900
+ }
1234
1901
  toggleOpen() {
1235
1902
  if (this.disabled())
1236
1903
  return;
1237
1904
  if (!this.open()) {
1238
- const d = this.parse(this.value()) ?? this.today;
1239
- this.view.set({ y: d.getFullYear(), m: d.getMonth() });
1905
+ this.view.set(this.initialView());
1906
+ this.syncTimeFromValue();
1907
+ this.dtView.set(this.selectionMode() === 'time' ? 'clock' : 'calendar');
1240
1908
  }
1241
1909
  this.open.update((o) => !o);
1242
1910
  }
@@ -1246,29 +1914,72 @@ class KptDatepicker {
1246
1914
  this.open.set(false);
1247
1915
  this.touch.emit();
1248
1916
  }
1917
+ // ── Wybór data/miesiąc/rok ──
1249
1918
  selectDay(cell) {
1250
1919
  if (cell.disabled)
1251
1920
  return;
1921
+ if (this.selectionMode() === 'datetime') {
1922
+ this.pendingDate.set(cell.iso);
1923
+ return; // czas jeszcze do wyboru
1924
+ }
1252
1925
  this.value.set(cell.iso);
1253
1926
  this.close();
1254
1927
  }
1928
+ selectCell(cell) {
1929
+ if (cell.disabled)
1930
+ return;
1931
+ this.value.set(cell.value);
1932
+ this.close();
1933
+ }
1934
+ // ── Zegar (delegowany do kpt-clock przez timeStr) ──
1935
+ openClock() {
1936
+ this.dtView.set('clock');
1937
+ }
1938
+ backToCalendar() {
1939
+ this.dtView.set('calendar');
1940
+ }
1941
+ commit() {
1942
+ const time = this.timeStr() || '00:00';
1943
+ if (this.selectionMode() === 'time') {
1944
+ this.value.set(time);
1945
+ }
1946
+ else {
1947
+ const dt = this.parseDateTime(this.value());
1948
+ const date = this.pendingDate() || dt?.date || toIso$1(this.today);
1949
+ this.value.set(`${date}T${time}`);
1950
+ }
1951
+ this.close();
1952
+ }
1255
1953
  prevMonth() {
1256
1954
  this.view.update(({ y, m }) => (m === 0 ? { y: y - 1, m: 11 } : { y, m: m - 1 }));
1257
1955
  }
1258
1956
  nextMonth() {
1259
1957
  this.view.update(({ y, m }) => (m === 11 ? { y: y + 1, m: 0 } : { y, m: m + 1 }));
1260
1958
  }
1959
+ prevYear() {
1960
+ this.view.update(({ y, m }) => ({ y: y - 1, m }));
1961
+ }
1962
+ nextYear() {
1963
+ this.view.update(({ y, m }) => ({ y: y + 1, m }));
1964
+ }
1965
+ prevYearPage() {
1966
+ this.view.update(({ y, m }) => ({ y: y - 12, m }));
1967
+ }
1968
+ nextYearPage() {
1969
+ this.view.update(({ y, m }) => ({ y: y + 12, m }));
1970
+ }
1261
1971
  clear(event) {
1262
1972
  event.stopPropagation();
1263
1973
  this.value.set('');
1974
+ this.pendingDate.set('');
1264
1975
  }
1265
1976
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptDatepicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
1266
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptDatepicker, isStandalone: true, selector: "kpt-datepicker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { classAttribute: "kpt-datepicker-host" }, ngImport: i0, template: "<div\n class=\"kpt-datepicker\"\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n role=\"button\"\n tabindex=\"0\"\n [class.kpt-datepicker--open]=\"open()\"\n [class.kpt-datepicker--disabled]=\"disabled()\"\n [class.kpt-datepicker--invalid]=\"invalid()\"\n [attr.aria-disabled]=\"disabled() || null\"\n (click)=\"toggleOpen()\"\n (keydown.enter)=\"toggleOpen()\"\n (blur)=\"touch.emit()\"\n>\n @if (display()) {\n <span class=\"kpt-datepicker__value\">{{ display() }}</span>\n } @else {\n <span class=\"kpt-datepicker__placeholder\">{{ placeholder() }}</span>\n }\n <span class=\"kpt-datepicker__spacer\"></span>\n @if (display()) {\n <button type=\"button\" class=\"kpt-datepicker__clear\" (click)=\"clear($event)\" aria-label=\"Wyczy\u015B\u0107\"><kpt-icon name=\"x\" /></button>\n }\n <kpt-icon class=\"kpt-datepicker__icon\" name=\"calendar\" />\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\"\n>\n <div class=\"kpt-calendar\" (keydown.escape)=\"close()\">\n <div class=\"kpt-calendar__header\">\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"prevMonth()\" aria-label=\"Poprzedni miesi\u0105c\"><kpt-icon name=\"chevron-left\" /></button>\n <span class=\"kpt-calendar__title\">{{ monthLabel() }}</span>\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"nextMonth()\" aria-label=\"Nast\u0119pny miesi\u0105c\"><kpt-icon name=\"chevron-right\" /></button>\n </div>\n <div class=\"kpt-calendar__weekdays\">\n @for (wd of weekdays; track wd) {\n <span class=\"kpt-calendar__weekday\">{{ wd }}</span>\n }\n </div>\n <div class=\"kpt-calendar__grid\">\n @for (week of weeks(); track $index) {\n @for (cell of week; track cell.iso) {\n <button\n type=\"button\"\n class=\"kpt-calendar__day\"\n [class.kpt-calendar__day--muted]=\"!cell.inMonth\"\n [class.kpt-calendar__day--today]=\"cell.today\"\n [class.kpt-calendar__day--selected]=\"cell.selected\"\n [disabled]=\"cell.disabled\"\n [attr.aria-pressed]=\"cell.selected\"\n (click)=\"selectDay(cell)\"\n >{{ cell.day }}</button>\n }\n }\n </div>\n </div>\n</ng-template>\n", styles: ["@layer kpt.components{.kpt-datepicker-host{display:block}.kpt-datepicker{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);height:2.5rem;padding-inline:var(--kpt-space-3, .75rem);box-sizing:border-box;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-datepicker:hover:not(.kpt-datepicker--disabled){border-color:var(--kpt-form-field-border-hover)}.kpt-datepicker:focus-visible,.kpt-datepicker.kpt-datepicker--open{outline:none;border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-datepicker.kpt-datepicker--invalid{border-color:var(--kpt-form-field-border-error)}.kpt-datepicker.kpt-datepicker--disabled{cursor:not-allowed;opacity:.6;background:var(--kpt-color-surface-variant)}.kpt-datepicker__placeholder{color:var(--kpt-form-field-placeholder)}.kpt-datepicker__spacer{flex:1}.kpt-datepicker__icon{color:var(--kpt-color-on-surface-muted)}.kpt-datepicker__clear{display:inline-flex;border:0;background:none;cursor:pointer;color:var(--kpt-color-on-surface-muted);padding:0}.kpt-datepicker__clear:hover{color:var(--kpt-color-on-surface)}.kpt-calendar{width:17rem;padding:var(--kpt-space-3, .75rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3);color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem)}.kpt-calendar__header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--kpt-space-2, .5rem)}.kpt-calendar__title{font-weight:var(--kpt-font-weight-semibold, 600);text-transform:capitalize}.kpt-calendar__nav{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:var(--kpt-radius-md, .5rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer}.kpt-calendar__nav:hover{background:var(--kpt-color-muted)}.kpt-calendar__weekdays,.kpt-calendar__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}.kpt-calendar__weekday{text-align:center;font-size:var(--kpt-font-size-xs, .75rem);color:var(--kpt-color-on-surface-muted);padding:.25rem 0}.kpt-calendar__day{aspect-ratio:1;border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer;font:inherit}.kpt-calendar__day:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-calendar__day--muted{color:var(--kpt-color-on-surface-muted);opacity:.5}.kpt-calendar__day--today{box-shadow:inset 0 0 0 1px var(--kpt-color-border-strong)}.kpt-calendar__day--selected{background:var(--kpt-color-primary)!important;color:var(--kpt-color-on-primary)}.kpt-calendar__day:disabled{opacity:.3;cursor:not-allowed}}\n"], dependencies: [{ kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1977
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptDatepicker, isStandalone: true, selector: "kpt-datepicker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, displayFormat: { classPropertyName: "displayFormat", publicName: "displayFormat", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, monthDisplay: { classPropertyName: "monthDisplay", publicName: "monthDisplay", isSignal: true, isRequired: false, transformFunction: null }, hourFormat: { classPropertyName: "hourFormat", publicName: "hourFormat", isSignal: true, isRequired: false, transformFunction: null }, minuteStep: { classPropertyName: "minuteStep", publicName: "minuteStep", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { classAttribute: "kpt-datepicker-host" }, ngImport: i0, template: "<div\n class=\"kpt-datepicker\"\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n role=\"button\"\n tabindex=\"0\"\n [class.kpt-datepicker--open]=\"open()\"\n [class.kpt-datepicker--disabled]=\"disabled()\"\n [class.kpt-datepicker--invalid]=\"invalid()\"\n [attr.aria-disabled]=\"disabled() || null\"\n (click)=\"toggleOpen()\"\n (keydown.enter)=\"toggleOpen()\"\n (blur)=\"touch.emit()\"\n>\n @if (display()) {\n <span class=\"kpt-datepicker__value\">{{ display() }}</span>\n } @else {\n <span class=\"kpt-datepicker__placeholder\">{{ effectivePlaceholder() }}</span>\n }\n <span class=\"kpt-datepicker__spacer\"></span>\n @if (display()) {\n <button type=\"button\" class=\"kpt-datepicker__clear\" (click)=\"clear($event)\" aria-label=\"Wyczy\u015B\u0107\"><kpt-icon name=\"x\" /></button>\n }\n <kpt-icon class=\"kpt-datepicker__icon\" name=\"calendar\" />\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\"\n>\n <div class=\"kpt-calendar\" [class.kpt-calendar--clock]=\"selectionMode() === 'time' || (selectionMode() === 'datetime' && dtView() === 'clock')\" (keydown.escape)=\"close()\">\n @switch (selectionMode()) {\n @case ('time') {\n <kpt-clock [(value)]=\"timeStr\" [hourFormat]=\"hourFormat()\" [minuteStep]=\"minuteStep()\" />\n <div class=\"kpt-calendar__footer\">\n <kpt-button size=\"sm\" (click)=\"commit()\">Gotowe</kpt-button>\n </div>\n }\n @case ('datetime') {\n @if (dtView() === 'calendar') {\n <div class=\"kpt-calendar__header\">\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"prevMonth()\" aria-label=\"Poprzedni miesi\u0105c\"><kpt-icon name=\"chevron-left\" /></button>\n <span class=\"kpt-calendar__title\">{{ monthLabel() }}</span>\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"nextMonth()\" aria-label=\"Nast\u0119pny miesi\u0105c\"><kpt-icon name=\"chevron-right\" /></button>\n </div>\n <div class=\"kpt-calendar__weekdays\">\n @for (wd of weekdays; track wd) {\n <span class=\"kpt-calendar__weekday\">{{ wd }}</span>\n }\n </div>\n <div class=\"kpt-calendar__grid\">\n @for (week of weeks(); track $index) {\n @for (cell of week; track cell.iso) {\n <button\n type=\"button\"\n class=\"kpt-calendar__day\"\n [class.kpt-calendar__day--muted]=\"!cell.inMonth\"\n [class.kpt-calendar__day--today]=\"cell.today\"\n [class.kpt-calendar__day--selected]=\"cell.selected\"\n [disabled]=\"cell.disabled\"\n [attr.aria-pressed]=\"cell.selected\"\n (click)=\"selectDay(cell)\"\n >{{ cell.day }}</button>\n }\n }\n </div>\n <button type=\"button\" class=\"kpt-calendar__timebar\" (click)=\"openClock()\">\n <kpt-icon name=\"clock\" />\n <span>{{ timeBarLabel() }}</span>\n </button>\n } @else {\n <div class=\"kpt-calendar__header\">\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"backToCalendar()\" aria-label=\"Kalendarz\"><kpt-icon name=\"chevron-left\" /></button>\n <span class=\"kpt-calendar__title\">Godzina</span>\n </div>\n <kpt-clock [(value)]=\"timeStr\" [hourFormat]=\"hourFormat()\" [minuteStep]=\"minuteStep()\" />\n }\n <div class=\"kpt-calendar__footer\">\n <kpt-button size=\"sm\" (click)=\"commit()\">Gotowe</kpt-button>\n </div>\n }\n @case ('monthYear') {\n <div class=\"kpt-calendar__header\">\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"prevYear()\" aria-label=\"Poprzedni rok\"><kpt-icon name=\"chevron-left\" /></button>\n <span class=\"kpt-calendar__title\">{{ viewYear() }}</span>\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"nextYear()\" aria-label=\"Nast\u0119pny rok\"><kpt-icon name=\"chevron-right\" /></button>\n </div>\n <div class=\"kpt-calendar__grid kpt-calendar__grid--cells\">\n @for (cell of monthCells(); track cell.value) {\n <button\n type=\"button\"\n class=\"kpt-calendar__cell\"\n [class.kpt-calendar__cell--selected]=\"cell.selected\"\n [disabled]=\"cell.disabled\"\n [attr.aria-pressed]=\"cell.selected\"\n (click)=\"selectCell(cell)\"\n >{{ cell.label }}</button>\n }\n </div>\n }\n @case ('year') {\n <div class=\"kpt-calendar__header\">\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"prevYearPage()\" aria-label=\"Poprzednie lata\"><kpt-icon name=\"chevron-left\" /></button>\n <span class=\"kpt-calendar__title\">{{ yearRangeLabel() }}</span>\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"nextYearPage()\" aria-label=\"Nast\u0119pne lata\"><kpt-icon name=\"chevron-right\" /></button>\n </div>\n <div class=\"kpt-calendar__grid kpt-calendar__grid--cells\">\n @for (cell of yearCells(); track cell.value) {\n <button\n type=\"button\"\n class=\"kpt-calendar__cell\"\n [class.kpt-calendar__cell--selected]=\"cell.selected\"\n [disabled]=\"cell.disabled\"\n [attr.aria-pressed]=\"cell.selected\"\n (click)=\"selectCell(cell)\"\n >{{ cell.label }}</button>\n }\n </div>\n }\n @case ('month') {\n <div class=\"kpt-calendar__header\">\n <span class=\"kpt-calendar__title\">Miesi\u0105c</span>\n </div>\n <div class=\"kpt-calendar__grid kpt-calendar__grid--cells\">\n @for (cell of monthCells(); track cell.value) {\n <button\n type=\"button\"\n class=\"kpt-calendar__cell\"\n [class.kpt-calendar__cell--selected]=\"cell.selected\"\n [attr.aria-pressed]=\"cell.selected\"\n (click)=\"selectCell(cell)\"\n >{{ cell.label }}</button>\n }\n </div>\n }\n @default {\n <div class=\"kpt-calendar__header\">\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"prevMonth()\" aria-label=\"Poprzedni miesi\u0105c\"><kpt-icon name=\"chevron-left\" /></button>\n <span class=\"kpt-calendar__title\">{{ monthLabel() }}</span>\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"nextMonth()\" aria-label=\"Nast\u0119pny miesi\u0105c\"><kpt-icon name=\"chevron-right\" /></button>\n </div>\n <div class=\"kpt-calendar__weekdays\">\n @for (wd of weekdays; track wd) {\n <span class=\"kpt-calendar__weekday\">{{ wd }}</span>\n }\n </div>\n <div class=\"kpt-calendar__grid\">\n @for (week of weeks(); track $index) {\n @for (cell of week; track cell.iso) {\n <button\n type=\"button\"\n class=\"kpt-calendar__day\"\n [class.kpt-calendar__day--muted]=\"!cell.inMonth\"\n [class.kpt-calendar__day--today]=\"cell.today\"\n [class.kpt-calendar__day--selected]=\"cell.selected\"\n [disabled]=\"cell.disabled\"\n [attr.aria-pressed]=\"cell.selected\"\n (click)=\"selectDay(cell)\"\n >{{ cell.day }}</button>\n }\n }\n </div>\n }\n }\n </div>\n</ng-template>\n", styles: ["@layer kpt.components{.kpt-datepicker-host{display:block}.kpt-datepicker{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);height:2.5rem;padding-inline:var(--kpt-space-3, .75rem);box-sizing:border-box;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-datepicker:hover:not(.kpt-datepicker--disabled){border-color:var(--kpt-form-field-border-hover)}.kpt-datepicker:focus-visible,.kpt-datepicker.kpt-datepicker--open{outline:none;border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-datepicker.kpt-datepicker--invalid{border-color:var(--kpt-form-field-border-error)}.kpt-datepicker.kpt-datepicker--disabled{cursor:not-allowed;opacity:.6;background:var(--kpt-color-surface-variant)}.kpt-datepicker__placeholder{color:var(--kpt-form-field-placeholder)}.kpt-datepicker__spacer{flex:1}.kpt-datepicker__icon{color:var(--kpt-color-on-surface-muted)}.kpt-datepicker__clear{display:inline-flex;border:0;background:none;cursor:pointer;color:var(--kpt-color-on-surface-muted);padding:0}.kpt-datepicker__clear:hover{color:var(--kpt-color-on-surface)}.kpt-calendar{width:17rem;padding:var(--kpt-space-3, .75rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3);color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem)}.kpt-calendar__header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--kpt-space-2, .5rem)}.kpt-calendar__title{font-weight:var(--kpt-font-weight-semibold, 600);text-transform:capitalize}.kpt-calendar__nav{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:var(--kpt-radius-md, .5rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer}.kpt-calendar__nav:hover{background:var(--kpt-color-muted)}.kpt-calendar__weekdays,.kpt-calendar__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}.kpt-calendar__weekday{text-align:center;font-size:var(--kpt-font-size-xs, .75rem);color:var(--kpt-color-on-surface-muted);padding:.25rem 0}.kpt-calendar__day{aspect-ratio:1;border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer;font:inherit}.kpt-calendar__day:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-calendar__day--muted{color:var(--kpt-color-on-surface-muted);opacity:.5}.kpt-calendar__day--today{box-shadow:inset 0 0 0 1px var(--kpt-color-border-strong)}.kpt-calendar__day--selected{background:var(--kpt-color-primary)!important;color:var(--kpt-color-on-primary)}.kpt-calendar__day:disabled{opacity:.3;cursor:not-allowed}.kpt-calendar__grid--cells{grid-template-columns:repeat(3,1fr);gap:4px}.kpt-calendar__cell{padding:.6rem .25rem;border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer;font:inherit;text-transform:capitalize}.kpt-calendar__cell:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-calendar__cell--selected{background:var(--kpt-color-primary)!important;color:var(--kpt-color-on-primary)}.kpt-calendar__cell:disabled{opacity:.3;cursor:not-allowed}.kpt-calendar__timebar{display:flex;align-items:center;justify-content:center;gap:var(--kpt-space-2, .5rem);width:100%;margin-top:var(--kpt-space-2, .5rem);padding:var(--kpt-space-2, .5rem);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);background:none;color:var(--kpt-color-on-surface);font:inherit;font-variant-numeric:tabular-nums;cursor:pointer}.kpt-calendar__timebar:hover{background:var(--kpt-color-muted)}.kpt-calendar__timebar kpt-icon{color:var(--kpt-color-on-surface-muted)}.kpt-calendar__footer{display:flex;justify-content:flex-end;margin-top:var(--kpt-space-3, .75rem)}.kpt-calendar--clock{width:16rem}}\n"], dependencies: [{ kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }, { kind: "component", type: KptButton, selector: "kpt-button", inputs: ["variant", "size", "type", "disabled", "loading", "fullWidth"] }, { kind: "component", type: KptClock, selector: "kpt-clock", inputs: ["value", "hourFormat", "minuteStep"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1267
1978
  }
1268
1979
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptDatepicker, decorators: [{
1269
1980
  type: Component,
1270
- args: [{ selector: 'kpt-datepicker', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [CdkOverlayOrigin, CdkConnectedOverlay, KptIcon], host: { class: 'kpt-datepicker-host' }, template: "<div\n class=\"kpt-datepicker\"\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n role=\"button\"\n tabindex=\"0\"\n [class.kpt-datepicker--open]=\"open()\"\n [class.kpt-datepicker--disabled]=\"disabled()\"\n [class.kpt-datepicker--invalid]=\"invalid()\"\n [attr.aria-disabled]=\"disabled() || null\"\n (click)=\"toggleOpen()\"\n (keydown.enter)=\"toggleOpen()\"\n (blur)=\"touch.emit()\"\n>\n @if (display()) {\n <span class=\"kpt-datepicker__value\">{{ display() }}</span>\n } @else {\n <span class=\"kpt-datepicker__placeholder\">{{ placeholder() }}</span>\n }\n <span class=\"kpt-datepicker__spacer\"></span>\n @if (display()) {\n <button type=\"button\" class=\"kpt-datepicker__clear\" (click)=\"clear($event)\" aria-label=\"Wyczy\u015B\u0107\"><kpt-icon name=\"x\" /></button>\n }\n <kpt-icon class=\"kpt-datepicker__icon\" name=\"calendar\" />\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\"\n>\n <div class=\"kpt-calendar\" (keydown.escape)=\"close()\">\n <div class=\"kpt-calendar__header\">\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"prevMonth()\" aria-label=\"Poprzedni miesi\u0105c\"><kpt-icon name=\"chevron-left\" /></button>\n <span class=\"kpt-calendar__title\">{{ monthLabel() }}</span>\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"nextMonth()\" aria-label=\"Nast\u0119pny miesi\u0105c\"><kpt-icon name=\"chevron-right\" /></button>\n </div>\n <div class=\"kpt-calendar__weekdays\">\n @for (wd of weekdays; track wd) {\n <span class=\"kpt-calendar__weekday\">{{ wd }}</span>\n }\n </div>\n <div class=\"kpt-calendar__grid\">\n @for (week of weeks(); track $index) {\n @for (cell of week; track cell.iso) {\n <button\n type=\"button\"\n class=\"kpt-calendar__day\"\n [class.kpt-calendar__day--muted]=\"!cell.inMonth\"\n [class.kpt-calendar__day--today]=\"cell.today\"\n [class.kpt-calendar__day--selected]=\"cell.selected\"\n [disabled]=\"cell.disabled\"\n [attr.aria-pressed]=\"cell.selected\"\n (click)=\"selectDay(cell)\"\n >{{ cell.day }}</button>\n }\n }\n </div>\n </div>\n</ng-template>\n", styles: ["@layer kpt.components{.kpt-datepicker-host{display:block}.kpt-datepicker{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);height:2.5rem;padding-inline:var(--kpt-space-3, .75rem);box-sizing:border-box;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-datepicker:hover:not(.kpt-datepicker--disabled){border-color:var(--kpt-form-field-border-hover)}.kpt-datepicker:focus-visible,.kpt-datepicker.kpt-datepicker--open{outline:none;border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-datepicker.kpt-datepicker--invalid{border-color:var(--kpt-form-field-border-error)}.kpt-datepicker.kpt-datepicker--disabled{cursor:not-allowed;opacity:.6;background:var(--kpt-color-surface-variant)}.kpt-datepicker__placeholder{color:var(--kpt-form-field-placeholder)}.kpt-datepicker__spacer{flex:1}.kpt-datepicker__icon{color:var(--kpt-color-on-surface-muted)}.kpt-datepicker__clear{display:inline-flex;border:0;background:none;cursor:pointer;color:var(--kpt-color-on-surface-muted);padding:0}.kpt-datepicker__clear:hover{color:var(--kpt-color-on-surface)}.kpt-calendar{width:17rem;padding:var(--kpt-space-3, .75rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3);color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem)}.kpt-calendar__header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--kpt-space-2, .5rem)}.kpt-calendar__title{font-weight:var(--kpt-font-weight-semibold, 600);text-transform:capitalize}.kpt-calendar__nav{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:var(--kpt-radius-md, .5rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer}.kpt-calendar__nav:hover{background:var(--kpt-color-muted)}.kpt-calendar__weekdays,.kpt-calendar__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}.kpt-calendar__weekday{text-align:center;font-size:var(--kpt-font-size-xs, .75rem);color:var(--kpt-color-on-surface-muted);padding:.25rem 0}.kpt-calendar__day{aspect-ratio:1;border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer;font:inherit}.kpt-calendar__day:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-calendar__day--muted{color:var(--kpt-color-on-surface-muted);opacity:.5}.kpt-calendar__day--today{box-shadow:inset 0 0 0 1px var(--kpt-color-border-strong)}.kpt-calendar__day--selected{background:var(--kpt-color-primary)!important;color:var(--kpt-color-on-primary)}.kpt-calendar__day:disabled{opacity:.3;cursor:not-allowed}}\n"] }]
1271
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }] } });
1981
+ args: [{ selector: 'kpt-datepicker', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [CdkOverlayOrigin, CdkConnectedOverlay, KptIcon, KptButton, KptClock], host: { class: 'kpt-datepicker-host' }, template: "<div\n class=\"kpt-datepicker\"\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n role=\"button\"\n tabindex=\"0\"\n [class.kpt-datepicker--open]=\"open()\"\n [class.kpt-datepicker--disabled]=\"disabled()\"\n [class.kpt-datepicker--invalid]=\"invalid()\"\n [attr.aria-disabled]=\"disabled() || null\"\n (click)=\"toggleOpen()\"\n (keydown.enter)=\"toggleOpen()\"\n (blur)=\"touch.emit()\"\n>\n @if (display()) {\n <span class=\"kpt-datepicker__value\">{{ display() }}</span>\n } @else {\n <span class=\"kpt-datepicker__placeholder\">{{ effectivePlaceholder() }}</span>\n }\n <span class=\"kpt-datepicker__spacer\"></span>\n @if (display()) {\n <button type=\"button\" class=\"kpt-datepicker__clear\" (click)=\"clear($event)\" aria-label=\"Wyczy\u015B\u0107\"><kpt-icon name=\"x\" /></button>\n }\n <kpt-icon class=\"kpt-datepicker__icon\" name=\"calendar\" />\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\"\n>\n <div class=\"kpt-calendar\" [class.kpt-calendar--clock]=\"selectionMode() === 'time' || (selectionMode() === 'datetime' && dtView() === 'clock')\" (keydown.escape)=\"close()\">\n @switch (selectionMode()) {\n @case ('time') {\n <kpt-clock [(value)]=\"timeStr\" [hourFormat]=\"hourFormat()\" [minuteStep]=\"minuteStep()\" />\n <div class=\"kpt-calendar__footer\">\n <kpt-button size=\"sm\" (click)=\"commit()\">Gotowe</kpt-button>\n </div>\n }\n @case ('datetime') {\n @if (dtView() === 'calendar') {\n <div class=\"kpt-calendar__header\">\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"prevMonth()\" aria-label=\"Poprzedni miesi\u0105c\"><kpt-icon name=\"chevron-left\" /></button>\n <span class=\"kpt-calendar__title\">{{ monthLabel() }}</span>\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"nextMonth()\" aria-label=\"Nast\u0119pny miesi\u0105c\"><kpt-icon name=\"chevron-right\" /></button>\n </div>\n <div class=\"kpt-calendar__weekdays\">\n @for (wd of weekdays; track wd) {\n <span class=\"kpt-calendar__weekday\">{{ wd }}</span>\n }\n </div>\n <div class=\"kpt-calendar__grid\">\n @for (week of weeks(); track $index) {\n @for (cell of week; track cell.iso) {\n <button\n type=\"button\"\n class=\"kpt-calendar__day\"\n [class.kpt-calendar__day--muted]=\"!cell.inMonth\"\n [class.kpt-calendar__day--today]=\"cell.today\"\n [class.kpt-calendar__day--selected]=\"cell.selected\"\n [disabled]=\"cell.disabled\"\n [attr.aria-pressed]=\"cell.selected\"\n (click)=\"selectDay(cell)\"\n >{{ cell.day }}</button>\n }\n }\n </div>\n <button type=\"button\" class=\"kpt-calendar__timebar\" (click)=\"openClock()\">\n <kpt-icon name=\"clock\" />\n <span>{{ timeBarLabel() }}</span>\n </button>\n } @else {\n <div class=\"kpt-calendar__header\">\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"backToCalendar()\" aria-label=\"Kalendarz\"><kpt-icon name=\"chevron-left\" /></button>\n <span class=\"kpt-calendar__title\">Godzina</span>\n </div>\n <kpt-clock [(value)]=\"timeStr\" [hourFormat]=\"hourFormat()\" [minuteStep]=\"minuteStep()\" />\n }\n <div class=\"kpt-calendar__footer\">\n <kpt-button size=\"sm\" (click)=\"commit()\">Gotowe</kpt-button>\n </div>\n }\n @case ('monthYear') {\n <div class=\"kpt-calendar__header\">\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"prevYear()\" aria-label=\"Poprzedni rok\"><kpt-icon name=\"chevron-left\" /></button>\n <span class=\"kpt-calendar__title\">{{ viewYear() }}</span>\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"nextYear()\" aria-label=\"Nast\u0119pny rok\"><kpt-icon name=\"chevron-right\" /></button>\n </div>\n <div class=\"kpt-calendar__grid kpt-calendar__grid--cells\">\n @for (cell of monthCells(); track cell.value) {\n <button\n type=\"button\"\n class=\"kpt-calendar__cell\"\n [class.kpt-calendar__cell--selected]=\"cell.selected\"\n [disabled]=\"cell.disabled\"\n [attr.aria-pressed]=\"cell.selected\"\n (click)=\"selectCell(cell)\"\n >{{ cell.label }}</button>\n }\n </div>\n }\n @case ('year') {\n <div class=\"kpt-calendar__header\">\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"prevYearPage()\" aria-label=\"Poprzednie lata\"><kpt-icon name=\"chevron-left\" /></button>\n <span class=\"kpt-calendar__title\">{{ yearRangeLabel() }}</span>\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"nextYearPage()\" aria-label=\"Nast\u0119pne lata\"><kpt-icon name=\"chevron-right\" /></button>\n </div>\n <div class=\"kpt-calendar__grid kpt-calendar__grid--cells\">\n @for (cell of yearCells(); track cell.value) {\n <button\n type=\"button\"\n class=\"kpt-calendar__cell\"\n [class.kpt-calendar__cell--selected]=\"cell.selected\"\n [disabled]=\"cell.disabled\"\n [attr.aria-pressed]=\"cell.selected\"\n (click)=\"selectCell(cell)\"\n >{{ cell.label }}</button>\n }\n </div>\n }\n @case ('month') {\n <div class=\"kpt-calendar__header\">\n <span class=\"kpt-calendar__title\">Miesi\u0105c</span>\n </div>\n <div class=\"kpt-calendar__grid kpt-calendar__grid--cells\">\n @for (cell of monthCells(); track cell.value) {\n <button\n type=\"button\"\n class=\"kpt-calendar__cell\"\n [class.kpt-calendar__cell--selected]=\"cell.selected\"\n [attr.aria-pressed]=\"cell.selected\"\n (click)=\"selectCell(cell)\"\n >{{ cell.label }}</button>\n }\n </div>\n }\n @default {\n <div class=\"kpt-calendar__header\">\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"prevMonth()\" aria-label=\"Poprzedni miesi\u0105c\"><kpt-icon name=\"chevron-left\" /></button>\n <span class=\"kpt-calendar__title\">{{ monthLabel() }}</span>\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"nextMonth()\" aria-label=\"Nast\u0119pny miesi\u0105c\"><kpt-icon name=\"chevron-right\" /></button>\n </div>\n <div class=\"kpt-calendar__weekdays\">\n @for (wd of weekdays; track wd) {\n <span class=\"kpt-calendar__weekday\">{{ wd }}</span>\n }\n </div>\n <div class=\"kpt-calendar__grid\">\n @for (week of weeks(); track $index) {\n @for (cell of week; track cell.iso) {\n <button\n type=\"button\"\n class=\"kpt-calendar__day\"\n [class.kpt-calendar__day--muted]=\"!cell.inMonth\"\n [class.kpt-calendar__day--today]=\"cell.today\"\n [class.kpt-calendar__day--selected]=\"cell.selected\"\n [disabled]=\"cell.disabled\"\n [attr.aria-pressed]=\"cell.selected\"\n (click)=\"selectDay(cell)\"\n >{{ cell.day }}</button>\n }\n }\n </div>\n }\n }\n </div>\n</ng-template>\n", styles: ["@layer kpt.components{.kpt-datepicker-host{display:block}.kpt-datepicker{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);height:2.5rem;padding-inline:var(--kpt-space-3, .75rem);box-sizing:border-box;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-datepicker:hover:not(.kpt-datepicker--disabled){border-color:var(--kpt-form-field-border-hover)}.kpt-datepicker:focus-visible,.kpt-datepicker.kpt-datepicker--open{outline:none;border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-datepicker.kpt-datepicker--invalid{border-color:var(--kpt-form-field-border-error)}.kpt-datepicker.kpt-datepicker--disabled{cursor:not-allowed;opacity:.6;background:var(--kpt-color-surface-variant)}.kpt-datepicker__placeholder{color:var(--kpt-form-field-placeholder)}.kpt-datepicker__spacer{flex:1}.kpt-datepicker__icon{color:var(--kpt-color-on-surface-muted)}.kpt-datepicker__clear{display:inline-flex;border:0;background:none;cursor:pointer;color:var(--kpt-color-on-surface-muted);padding:0}.kpt-datepicker__clear:hover{color:var(--kpt-color-on-surface)}.kpt-calendar{width:17rem;padding:var(--kpt-space-3, .75rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3);color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem)}.kpt-calendar__header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--kpt-space-2, .5rem)}.kpt-calendar__title{font-weight:var(--kpt-font-weight-semibold, 600);text-transform:capitalize}.kpt-calendar__nav{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:var(--kpt-radius-md, .5rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer}.kpt-calendar__nav:hover{background:var(--kpt-color-muted)}.kpt-calendar__weekdays,.kpt-calendar__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}.kpt-calendar__weekday{text-align:center;font-size:var(--kpt-font-size-xs, .75rem);color:var(--kpt-color-on-surface-muted);padding:.25rem 0}.kpt-calendar__day{aspect-ratio:1;border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer;font:inherit}.kpt-calendar__day:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-calendar__day--muted{color:var(--kpt-color-on-surface-muted);opacity:.5}.kpt-calendar__day--today{box-shadow:inset 0 0 0 1px var(--kpt-color-border-strong)}.kpt-calendar__day--selected{background:var(--kpt-color-primary)!important;color:var(--kpt-color-on-primary)}.kpt-calendar__day:disabled{opacity:.3;cursor:not-allowed}.kpt-calendar__grid--cells{grid-template-columns:repeat(3,1fr);gap:4px}.kpt-calendar__cell{padding:.6rem .25rem;border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer;font:inherit;text-transform:capitalize}.kpt-calendar__cell:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-calendar__cell--selected{background:var(--kpt-color-primary)!important;color:var(--kpt-color-on-primary)}.kpt-calendar__cell:disabled{opacity:.3;cursor:not-allowed}.kpt-calendar__timebar{display:flex;align-items:center;justify-content:center;gap:var(--kpt-space-2, .5rem);width:100%;margin-top:var(--kpt-space-2, .5rem);padding:var(--kpt-space-2, .5rem);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);background:none;color:var(--kpt-color-on-surface);font:inherit;font-variant-numeric:tabular-nums;cursor:pointer}.kpt-calendar__timebar:hover{background:var(--kpt-color-muted)}.kpt-calendar__timebar kpt-icon{color:var(--kpt-color-on-surface-muted)}.kpt-calendar__footer{display:flex;justify-content:flex-end;margin-top:var(--kpt-space-3, .75rem)}.kpt-calendar--clock{width:16rem}}\n"] }]
1982
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], displayFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayFormat", required: false }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], monthDisplay: [{ type: i0.Input, args: [{ isSignal: true, alias: "monthDisplay", required: false }] }], hourFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "hourFormat", required: false }] }], minuteStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }] } });
1272
1983
 
1273
1984
  /**
1274
1985
  * Pole wieloliniowe (textarea) na Signal Forms, z opcjonalnym auto-resize.
@@ -1343,16 +2054,113 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
1343
2054
  `, host: { class: 'kpt-textarea-host' }, styles: ["@layer kpt.components{.kpt-textarea-host{display:block}.kpt-textarea__field{display:block;width:100%;box-sizing:border-box;min-height:3rem;padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);font-family:inherit;font-size:var(--kpt-font-size-sm, .875rem);line-height:var(--kpt-font-line-height-normal, 1.5);color:var(--kpt-form-field-text);background:var(--kpt-form-field-bg);resize:vertical}.kpt-textarea__field::placeholder{color:var(--kpt-form-field-placeholder)}.kpt-textarea__field:hover:not(:disabled){border-color:var(--kpt-form-field-border-hover)}.kpt-textarea__field:focus-visible{outline:none;border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-textarea__field[aria-invalid=true]{border-color:var(--kpt-form-field-border-error)}.kpt-textarea__field:disabled{cursor:not-allowed;opacity:.6;background:var(--kpt-color-surface-variant)}}\n"] }]
1344
2055
  }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], autoResize: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoResize", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], ta: [{ type: i0.ViewChild, args: ['ta', { isSignal: true }] }] } });
1345
2056
 
2057
+ /**
2058
+ * Dymek podpowiedzi (tooltip) pokazywany na hover/focus hosta. Lekki — element dodawany
2059
+ * do `body` i pozycjonowany względem hosta (działa w trybie zoneless).
2060
+ *
2061
+ * @example
2062
+ * <kpt-button kptTooltip="Zapisz zmiany" kptTooltipPosition="bottom">Zapisz</kpt-button>
2063
+ */
2064
+ class KptTooltip {
2065
+ text = input.required({ ...(ngDevMode ? { debugName: "text" } : /* istanbul ignore next */ {}), alias: 'kptTooltip' });
2066
+ position = input('top', { ...(ngDevMode ? { debugName: "position" } : /* istanbul ignore next */ {}), alias: 'kptTooltipPosition' });
2067
+ host = inject(ElementRef);
2068
+ tip;
2069
+ show() {
2070
+ if (this.tip || !this.text())
2071
+ return;
2072
+ const tip = document.createElement('div');
2073
+ tip.className = 'kpt-tooltip';
2074
+ tip.setAttribute('role', 'tooltip');
2075
+ tip.textContent = this.text();
2076
+ tip.style.cssText =
2077
+ 'position:fixed;z-index:1400;max-width:16rem;padding:0.35rem 0.6rem;' +
2078
+ 'border-radius:var(--kpt-radius-sm,0.25rem);font-size:var(--kpt-font-size-xs,0.75rem);' +
2079
+ 'line-height:1.4;background:var(--kpt-color-on-surface);color:var(--kpt-color-surface);' +
2080
+ 'box-shadow:var(--kpt-elevation-2);pointer-events:none;opacity:0;transition:opacity 120ms;';
2081
+ document.body.appendChild(tip);
2082
+ this.tip = tip;
2083
+ this.reposition();
2084
+ requestAnimationFrame(() => {
2085
+ if (this.tip)
2086
+ this.tip.style.opacity = '1';
2087
+ });
2088
+ }
2089
+ hide() {
2090
+ this.tip?.remove();
2091
+ this.tip = undefined;
2092
+ }
2093
+ reposition() {
2094
+ const tip = this.tip;
2095
+ if (!tip)
2096
+ return;
2097
+ const r = this.host.nativeElement.getBoundingClientRect();
2098
+ const t = tip.getBoundingClientRect();
2099
+ const gap = 8;
2100
+ let top;
2101
+ let left;
2102
+ switch (this.position()) {
2103
+ case 'bottom':
2104
+ top = r.bottom + gap;
2105
+ left = r.left + r.width / 2 - t.width / 2;
2106
+ break;
2107
+ case 'left':
2108
+ top = r.top + r.height / 2 - t.height / 2;
2109
+ left = r.left - t.width - gap;
2110
+ break;
2111
+ case 'right':
2112
+ top = r.top + r.height / 2 - t.height / 2;
2113
+ left = r.right + gap;
2114
+ break;
2115
+ default:
2116
+ top = r.top - t.height - gap;
2117
+ left = r.left + r.width / 2 - t.width / 2;
2118
+ }
2119
+ tip.style.top = `${Math.max(4, top)}px`;
2120
+ tip.style.left = `${Math.max(4, left)}px`;
2121
+ }
2122
+ ngOnDestroy() {
2123
+ this.hide();
2124
+ }
2125
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptTooltip, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2126
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.0", type: KptTooltip, isStandalone: true, selector: "[kptTooltip]", inputs: { text: { classPropertyName: "text", publicName: "kptTooltip", isSignal: true, isRequired: true, transformFunction: null }, position: { classPropertyName: "position", publicName: "kptTooltipPosition", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "show()", "mouseleave": "hide()", "focus": "show()", "blur": "hide()" } }, ngImport: i0 });
2127
+ }
2128
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptTooltip, decorators: [{
2129
+ type: Directive,
2130
+ args: [{
2131
+ selector: '[kptTooltip]',
2132
+ host: {
2133
+ '(mouseenter)': 'show()',
2134
+ '(mouseleave)': 'hide()',
2135
+ '(focus)': 'show()',
2136
+ '(blur)': 'hide()',
2137
+ },
2138
+ }]
2139
+ }], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "kptTooltip", required: true }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "kptTooltipPosition", required: false }] }] } });
2140
+
1346
2141
  const ICON = {
2142
+ copy: 'copy',
2143
+ paste: 'clipboard',
2144
+ pasteText: 'clipboard-text',
2145
+ heading: 'code', // nieużywane (heading renderuje select)
1347
2146
  bold: 'bold',
1348
2147
  italic: 'italic',
1349
2148
  underline: 'underline',
1350
2149
  strike: 'strikethrough',
1351
2150
  ul: 'list',
1352
2151
  ol: 'list-numbers',
2152
+ foreColor: 'palette',
2153
+ backColor: 'highlight',
2154
+ alignLeft: 'align-left',
2155
+ alignCenter: 'align-center',
2156
+ alignRight: 'align-right',
2157
+ alignJustify: 'align-justified',
1353
2158
  link: 'link',
2159
+ table: 'table',
1354
2160
  clear: 'clear-formatting',
2161
+ html: 'code',
1355
2162
  };
2163
+ /** Narzędzia zwykłe → komenda execCommand + nazwa queryCommandState (dla stanu aktywnego). */
1356
2164
  const COMMAND = {
1357
2165
  bold: 'bold',
1358
2166
  italic: 'italic',
@@ -1360,19 +2168,71 @@ const COMMAND = {
1360
2168
  strike: 'strikeThrough',
1361
2169
  ul: 'insertUnorderedList',
1362
2170
  ol: 'insertOrderedList',
2171
+ alignLeft: 'justifyLeft',
2172
+ alignCenter: 'justifyCenter',
2173
+ alignRight: 'justifyRight',
2174
+ alignJustify: 'justifyFull',
1363
2175
  clear: 'removeFormat',
1364
2176
  };
2177
+ const ARIA = {
2178
+ copy: 'Kopiuj',
2179
+ paste: 'Wklej z formatowaniem',
2180
+ pasteText: 'Wklej bez formatowania',
2181
+ heading: 'Styl',
2182
+ bold: 'Pogrubienie',
2183
+ italic: 'Kursywa',
2184
+ underline: 'Podkreślenie',
2185
+ strike: 'Przekreślenie',
2186
+ ul: 'Lista punktowana',
2187
+ ol: 'Lista numerowana',
2188
+ foreColor: 'Kolor tekstu',
2189
+ backColor: 'Kolor tła tekstu',
2190
+ alignLeft: 'Wyrównaj do lewej',
2191
+ alignCenter: 'Wyśrodkuj',
2192
+ alignRight: 'Wyrównaj do prawej',
2193
+ alignJustify: 'Wyjustuj',
2194
+ link: 'Wstaw link',
2195
+ table: 'Tabela',
2196
+ clear: 'Usuń formatowanie',
2197
+ html: 'Podgląd HTML',
2198
+ };
2199
+ const SWATCHES = [
2200
+ '#000000', '#434343', '#666666', '#999999', '#b7b7b7', '#cccccc', '#ffffff',
2201
+ '#e11d48', '#ea580c', '#ca8a04', '#16a34a', '#0891b2', '#2563eb', '#7c3aed',
2202
+ ];
2203
+ const DEFAULT_TOOLBAR = [
2204
+ ['copy', 'paste', 'pasteText'],
2205
+ ['heading', 'bold', 'italic', 'underline', 'strike', 'ul', 'ol'],
2206
+ ['foreColor', 'backColor'],
2207
+ ['alignLeft', 'alignCenter', 'alignRight', 'alignJustify'],
2208
+ ['link', 'table', 'clear', 'html'],
2209
+ ];
2210
+ // Allowlisty sanityzacji wklejanego HTML.
2211
+ const ALLOWED_TAGS = new Set([
2212
+ 'P', 'BR', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'B', 'STRONG', 'I', 'EM', 'U', 'S', 'STRIKE',
2213
+ 'UL', 'OL', 'LI', 'A', 'SPAN', 'DIV', 'BLOCKQUOTE', 'FONT',
2214
+ 'TABLE', 'THEAD', 'TBODY', 'TFOOT', 'TR', 'TD', 'TH', 'COLGROUP', 'COL', 'CAPTION',
2215
+ ]);
2216
+ const ALLOWED_STYLES = new Set([
2217
+ 'color', 'background-color', 'text-align', 'font-weight', 'font-style', 'text-decoration',
2218
+ 'width', 'height', 'border', 'border-color', 'border-width', 'border-style', 'vertical-align',
2219
+ ]);
2220
+ const ALLOWED_ATTRS = new Set(['colspan', 'rowspan', 'span', 'width', 'class']);
1365
2221
  /**
1366
- * Lekki edytor tekstu sformatowanego (contenteditable) z konfigurowalnym paskiem przycisków.
1367
- * Wartość = HTML. Bez zależności zewnętrznych. Signal Forms.
2222
+ * Lekki edytor tekstu sformatowanego (contenteditable) z konfigurowalnym paskiem sekcji.
2223
+ * Narzędzia: schowek (kopiuj / wklej / wklej bez formatowania), styl (nagłówki H1–H6 / paragraf),
2224
+ * bold/italic/underline/strike/ul/ol, kolor tekstu i tła (popover), wyrównania, link, czyszczenie.
2225
+ * `toolbar` przyjmuje płaską listę lub grupy (sekcje). Wartość = HTML. Signal Forms.
2226
+ * Wymaga stylów overlay CDK (popover kolorów): `import '@angular/cdk/overlay-prebuilt.css';`
1368
2227
  *
1369
2228
  * @example
1370
- * <kpt-rich-text [formField]="f.body" [toolbar]="['bold','italic','ul','link']" />
2229
+ * <kpt-rich-text [formField]="f.body" />
2230
+ * <kpt-rich-text [(value)]="v" [toolbar]="[['bold','italic'],['ul','ol'],['link']]" />
1371
2231
  */
1372
2232
  class KptRichText {
1373
2233
  value = model('', /* @ts-ignore */
1374
2234
  ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
1375
- toolbar = input(['bold', 'italic', 'underline', 'strike', 'ul', 'ol', 'link', 'clear'], /* @ts-ignore */
2235
+ toolbar = input(DEFAULT_TOOLBAR, /* @ts-ignore */
1376
2236
  ...(ngDevMode ? [{ debugName: "toolbar" }] : /* istanbul ignore next */ []));
1377
2237
  placeholder = input('', /* @ts-ignore */
1378
2238
  ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
@@ -1380,8 +2240,71 @@ class KptRichText {
1380
2240
  invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1381
2241
  touched = input(false, { ...(ngDevMode ? { debugName: "touched" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1382
2242
  touch = output();
2243
+ swatches = SWATCHES;
1383
2244
  editor = viewChild('editor', /* @ts-ignore */
1384
2245
  ...(ngDevMode ? [{ debugName: "editor" }] : /* istanbul ignore next */ []));
2246
+ savedRange = null;
2247
+ colorOpen = signal(false, /* @ts-ignore */
2248
+ ...(ngDevMode ? [{ debugName: "colorOpen" }] : /* istanbul ignore next */ []));
2249
+ colorKind = signal('foreColor', /* @ts-ignore */
2250
+ ...(ngDevMode ? [{ debugName: "colorKind" }] : /* istanbul ignore next */ []));
2251
+ sourceView = signal(false, /* @ts-ignore */
2252
+ ...(ngDevMode ? [{ debugName: "sourceView" }] : /* istanbul ignore next */ []));
2253
+ styleOpen = signal(false, /* @ts-ignore */
2254
+ ...(ngDevMode ? [{ debugName: "styleOpen" }] : /* istanbul ignore next */ []));
2255
+ // ── Tabele ──
2256
+ tableOpen = signal(false, /* @ts-ignore */
2257
+ ...(ngDevMode ? [{ debugName: "tableOpen" }] : /* istanbul ignore next */ [])); // popover siatki wstawiania
2258
+ gridR = signal(0, /* @ts-ignore */
2259
+ ...(ngDevMode ? [{ debugName: "gridR" }] : /* istanbul ignore next */ []));
2260
+ gridC = signal(0, /* @ts-ignore */
2261
+ ...(ngDevMode ? [{ debugName: "gridC" }] : /* istanbul ignore next */ []));
2262
+ gridRows = Array.from({ length: 8 }, (_, i) => i + 1);
2263
+ gridCols = Array.from({ length: 8 }, (_, i) => i + 1);
2264
+ menuOpen = signal(false, /* @ts-ignore */
2265
+ ...(ngDevMode ? [{ debugName: "menuOpen" }] : /* istanbul ignore next */ [])); // menu kontekstowe
2266
+ menuPoint = signal({ x: 0, y: 0 }, /* @ts-ignore */
2267
+ ...(ngDevMode ? [{ debugName: "menuPoint" }] : /* istanbul ignore next */ []));
2268
+ borderOpen = signal(false, /* @ts-ignore */
2269
+ ...(ngDevMode ? [{ debugName: "borderOpen" }] : /* istanbul ignore next */ []));
2270
+ borderTarget = signal('table', /* @ts-ignore */
2271
+ ...(ngDevMode ? [{ debugName: "borderTarget" }] : /* istanbul ignore next */ []));
2272
+ ctxCell = null;
2273
+ resize = null;
2274
+ // Zaznaczanie wielu komórek
2275
+ selCount = signal(0, /* @ts-ignore */
2276
+ ...(ngDevMode ? [{ debugName: "selCount" }] : /* istanbul ignore next */ []));
2277
+ selCells = new Set();
2278
+ selAnchor = null;
2279
+ selecting = false;
2280
+ canSplitCtx = false;
2281
+ styleOptions = [
2282
+ { tag: 'p', label: 'Normalny' },
2283
+ { tag: 'h1', label: 'Nagłówek 1' },
2284
+ { tag: 'h2', label: 'Nagłówek 2' },
2285
+ { tag: 'h3', label: 'Nagłówek 3' },
2286
+ { tag: 'h4', label: 'Nagłówek 4' },
2287
+ { tag: 'h5', label: 'Nagłówek 5' },
2288
+ { tag: 'h6', label: 'Nagłówek 6' },
2289
+ ];
2290
+ styleLabel = computed(() => this.styleOptions.find((o) => o.tag === this.currentBlock())?.label ?? 'Normalny', /* @ts-ignore */
2291
+ ...(ngDevMode ? [{ debugName: "styleLabel" }] : /* istanbul ignore next */ []));
2292
+ activeCmds = signal(new Set(), /* @ts-ignore */
2293
+ ...(ngDevMode ? [{ debugName: "activeCmds" }] : /* istanbul ignore next */ []));
2294
+ currentBlock = signal('p', /* @ts-ignore */
2295
+ ...(ngDevMode ? [{ debugName: "currentBlock" }] : /* istanbul ignore next */ []));
2296
+ positions = [
2297
+ { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
2298
+ { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
2299
+ ];
2300
+ /** Sekcje paska (normalizacja płaskiej listy do jednej grupy). */
2301
+ sections = computed(() => {
2302
+ const t = this.toolbar();
2303
+ if (t.length === 0)
2304
+ return [];
2305
+ return Array.isArray(t[0]) ? t : [t];
2306
+ }, /* @ts-ignore */
2307
+ ...(ngDevMode ? [{ debugName: "sections" }] : /* istanbul ignore next */ []));
1385
2308
  constructor() {
1386
2309
  // Synchronizuj tylko przy zmianie zewnętrznej (bez resetu kursora podczas pisania).
1387
2310
  effect(() => {
@@ -1390,99 +2313,729 @@ class KptRichText {
1390
2313
  if (el && el.innerHTML !== v)
1391
2314
  el.innerHTML = v;
1392
2315
  });
2316
+ // Odzwierciedlenie stanu aktywnego narzędzi na podstawie zaznaczenia.
2317
+ const onSel = () => this.refreshState();
2318
+ const onMove = (e) => this.onResizeMove(e);
2319
+ const onUp = () => this.onResizeEnd();
2320
+ document.addEventListener('selectionchange', onSel);
2321
+ document.addEventListener('mousemove', onMove);
2322
+ document.addEventListener('mouseup', onUp);
2323
+ inject(DestroyRef).onDestroy(() => {
2324
+ document.removeEventListener('selectionchange', onSel);
2325
+ document.removeEventListener('mousemove', onMove);
2326
+ document.removeEventListener('mouseup', onUp);
2327
+ });
1393
2328
  }
1394
2329
  icon(item) {
1395
2330
  return ICON[item];
1396
2331
  }
2332
+ aria(item) {
2333
+ return ARIA[item];
2334
+ }
2335
+ isActive(item) {
2336
+ if (item === 'html')
2337
+ return this.sourceView();
2338
+ const cmd = COMMAND[item];
2339
+ return !!cmd && this.activeCmds().has(cmd);
2340
+ }
2341
+ inEditor() {
2342
+ const el = this.editor()?.nativeElement;
2343
+ const sel = window.getSelection();
2344
+ return !!el && !!sel && sel.rangeCount > 0 && el.contains(sel.anchorNode);
2345
+ }
2346
+ refreshState() {
2347
+ if (this.disabled() || !this.inEditor())
2348
+ return;
2349
+ const active = new Set();
2350
+ for (const cmd of Object.values(COMMAND)) {
2351
+ if (cmd && cmd !== 'removeFormat') {
2352
+ try {
2353
+ if (document.queryCommandState(cmd))
2354
+ active.add(cmd);
2355
+ }
2356
+ catch {
2357
+ /* nieobsługiwana komenda */
2358
+ }
2359
+ }
2360
+ }
2361
+ this.activeCmds.set(active);
2362
+ // Bieżący blok (dla selecta stylu).
2363
+ const sel = window.getSelection();
2364
+ let node = sel?.anchorNode;
2365
+ while (node && node !== this.editor()?.nativeElement) {
2366
+ const tag = node.tagName?.toLowerCase();
2367
+ if (tag && /^(h[1-6]|p|blockquote)$/.test(tag)) {
2368
+ this.currentBlock.set(tag);
2369
+ return;
2370
+ }
2371
+ node = node.parentElement;
2372
+ }
2373
+ this.currentBlock.set('p');
2374
+ }
1397
2375
  onInput() {
1398
2376
  const el = this.editor()?.nativeElement;
1399
2377
  if (el)
1400
2378
  this.value.set(el.innerHTML);
1401
2379
  }
2380
+ onSource(event) {
2381
+ this.value.set(event.target.value);
2382
+ }
2383
+ focusEditor() {
2384
+ this.editor()?.nativeElement.focus();
2385
+ }
2386
+ saveSelection() {
2387
+ const sel = window.getSelection();
2388
+ this.savedRange = sel && sel.rangeCount > 0 ? sel.getRangeAt(0).cloneRange() : null;
2389
+ }
2390
+ restoreSelection() {
2391
+ const sel = window.getSelection();
2392
+ if (this.savedRange && sel) {
2393
+ sel.removeAllRanges();
2394
+ sel.addRange(this.savedRange);
2395
+ }
2396
+ }
1402
2397
  exec(item) {
1403
2398
  if (this.disabled())
1404
2399
  return;
1405
- this.editor()?.nativeElement.focus();
1406
- if (item === 'link') {
1407
- const url = window.prompt('Adres URL:');
1408
- if (url)
1409
- document.execCommand('createLink', false, url);
2400
+ if (item === 'html') {
2401
+ this.sourceView.update((v) => !v);
2402
+ return;
2403
+ }
2404
+ if (item === 'table') {
2405
+ this.saveSelection();
2406
+ this.tableOpen.set(true);
2407
+ return;
2408
+ }
2409
+ this.focusEditor();
2410
+ switch (item) {
2411
+ case 'link': {
2412
+ const url = window.prompt('Adres URL:');
2413
+ if (url)
2414
+ document.execCommand('createLink', false, url);
2415
+ break;
2416
+ }
2417
+ case 'copy':
2418
+ document.execCommand('copy');
2419
+ break;
2420
+ case 'paste':
2421
+ void this.pasteRich();
2422
+ return;
2423
+ case 'pasteText':
2424
+ void this.pastePlain();
2425
+ return;
2426
+ default: {
2427
+ const cmd = COMMAND[item];
2428
+ if (cmd)
2429
+ document.execCommand(cmd);
2430
+ }
2431
+ }
2432
+ this.onInput();
2433
+ this.refreshState();
2434
+ }
2435
+ // ── Styl bloku (dropdown w stylu kpt-select, z podglądem wielkości) ──
2436
+ openStyle() {
2437
+ if (this.disabled())
2438
+ return;
2439
+ this.saveSelection();
2440
+ this.styleOpen.set(true);
2441
+ }
2442
+ closeStyle() {
2443
+ this.styleOpen.set(false);
2444
+ }
2445
+ pickStyle(tag) {
2446
+ this.styleOpen.set(false);
2447
+ this.focusEditor();
2448
+ this.restoreSelection();
2449
+ document.execCommand('formatBlock', false, `<${tag}>`);
2450
+ this.onInput();
2451
+ this.refreshState();
2452
+ }
2453
+ // ── Kolory ──
2454
+ openColor(kind) {
2455
+ if (this.disabled())
2456
+ return;
2457
+ this.saveSelection();
2458
+ this.colorKind.set(kind);
2459
+ this.colorOpen.set(true);
2460
+ }
2461
+ closeColor() {
2462
+ this.colorOpen.set(false);
2463
+ }
2464
+ applyColor(color) {
2465
+ this.colorOpen.set(false);
2466
+ if (this.colorKind() === 'cellBg') {
2467
+ for (const cell of this.activeCells())
2468
+ cell.style.backgroundColor = color;
2469
+ this.onInput();
2470
+ return;
2471
+ }
2472
+ this.focusEditor();
2473
+ this.restoreSelection();
2474
+ if (this.colorKind() === 'foreColor') {
2475
+ document.execCommand('foreColor', false, color);
2476
+ }
2477
+ else if (!document.execCommand('hiliteColor', false, color)) {
2478
+ document.execCommand('backColor', false, color);
2479
+ }
2480
+ this.onInput();
2481
+ }
2482
+ onColorInput(event) {
2483
+ this.applyColor(event.target.value);
2484
+ }
2485
+ // ── Schowek ──
2486
+ async pasteRich() {
2487
+ try {
2488
+ const items = await navigator.clipboard.read();
2489
+ for (const it of items) {
2490
+ if (it.types.includes('text/html')) {
2491
+ const blob = await it.getType('text/html');
2492
+ const html = this.sanitizeHtml(await blob.text());
2493
+ this.focusEditor();
2494
+ document.execCommand('insertHTML', false, html);
2495
+ this.onInput();
2496
+ return;
2497
+ }
2498
+ }
2499
+ const text = await navigator.clipboard.readText();
2500
+ this.focusEditor();
2501
+ document.execCommand('insertText', false, text);
2502
+ this.onInput();
2503
+ }
2504
+ catch {
2505
+ /* brak uprawnień / brak API — ignoruj */
2506
+ }
2507
+ }
2508
+ async pastePlain() {
2509
+ try {
2510
+ const text = await navigator.clipboard.readText();
2511
+ this.focusEditor();
2512
+ document.execCommand('insertText', false, text);
2513
+ this.onInput();
2514
+ }
2515
+ catch {
2516
+ /* brak uprawnień / brak API — ignoruj */
2517
+ }
2518
+ }
2519
+ /** Natywne wklejanie — oczyść (bez śmieci z Worda/WWW). */
2520
+ onPaste(event) {
2521
+ if (this.disabled())
2522
+ return;
2523
+ const html = event.clipboardData?.getData('text/html');
2524
+ const text = event.clipboardData?.getData('text/plain') ?? '';
2525
+ event.preventDefault();
2526
+ if (html) {
2527
+ document.execCommand('insertHTML', false, this.sanitizeHtml(html));
1410
2528
  }
1411
2529
  else {
1412
- document.execCommand(COMMAND[item]);
2530
+ document.execCommand('insertText', false, text);
1413
2531
  }
1414
2532
  this.onInput();
1415
2533
  }
1416
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptRichText, deps: [], target: i0.ɵɵFactoryTarget.Component });
1417
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptRichText, isStandalone: true, selector: "kpt-rich-text", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, toolbar: { classPropertyName: "toolbar", publicName: "toolbar", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { classAttribute: "kpt-rich-text-host" }, viewQueries: [{ propertyName: "editor", first: true, predicate: ["editor"], descendants: true, isSignal: true }], ngImport: i0, template: `
1418
- <div class="kpt-rich-text" [class.kpt-rich-text--invalid]="invalid()" [class.kpt-rich-text--disabled]="disabled()">
1419
- <div class="kpt-rich-text__toolbar" role="toolbar">
1420
- @for (item of toolbar(); track item) {
1421
- <button
1422
- type="button"
1423
- class="kpt-rich-text__tool"
1424
- [attr.aria-label]="item"
1425
- [disabled]="disabled()"
1426
- (mousedown)="$event.preventDefault()"
1427
- (click)="exec(item)"
1428
- ><kpt-icon [name]="icon(item)" /></button>
2534
+ // ── Tabele: wstawianie ──
2535
+ closeTable() {
2536
+ this.tableOpen.set(false);
2537
+ this.gridR.set(0);
2538
+ this.gridC.set(0);
2539
+ }
2540
+ gridHover(r, c) {
2541
+ this.gridR.set(r);
2542
+ this.gridC.set(c);
2543
+ }
2544
+ insertTable(rows, cols) {
2545
+ this.closeTable();
2546
+ this.focusEditor();
2547
+ this.restoreSelection();
2548
+ const w = (100 / cols).toFixed(4);
2549
+ const colgroup = `<colgroup>${Array.from({ length: cols }, () => `<col style="width:${w}%">`).join('')}</colgroup>`;
2550
+ const row = `<tr>${Array.from({ length: cols }, () => '<td><br></td>').join('')}</tr>`;
2551
+ const body = `<tbody>${Array.from({ length: rows }, () => row).join('')}</tbody>`;
2552
+ const table = `<table class="kpt-rt-table">${colgroup}${body}</table>`;
2553
+ document.execCommand('insertHTML', false, `${table}<p><br></p>`);
2554
+ this.onInput();
2555
+ }
2556
+ // ── Tabele: menu kontekstowe ──
2557
+ onContextMenu(event) {
2558
+ if (this.disabled())
2559
+ return;
2560
+ const cell = event.target.closest('td, th');
2561
+ const editor = this.editor()?.nativeElement;
2562
+ if (!cell || !editor?.contains(cell))
2563
+ return; // poza tabelą → natywne menu
2564
+ event.preventDefault();
2565
+ this.ctxCell = cell;
2566
+ this.canSplitCtx = (cell.colSpan || 1) > 1 || (cell.rowSpan || 1) > 1;
2567
+ this.menuPoint.set({ x: event.clientX, y: event.clientY });
2568
+ this.menuOpen.set(true);
2569
+ }
2570
+ closeMenu() {
2571
+ this.menuOpen.set(false);
2572
+ }
2573
+ ctxTable() {
2574
+ return this.ctxCell?.closest('table') ?? null;
2575
+ }
2576
+ afterTableOp() {
2577
+ this.menuOpen.set(false);
2578
+ this.onInput();
2579
+ }
2580
+ insertColumn(dir) {
2581
+ const cell = this.ctxCell;
2582
+ const table = this.ctxTable();
2583
+ if (!cell || !table)
2584
+ return;
2585
+ const idx = cell.cellIndex + (dir === 'right' ? 1 : 0);
2586
+ for (const tr of Array.from(table.rows)) {
2587
+ const td = document.createElement('td');
2588
+ td.innerHTML = '<br>';
2589
+ tr.insertBefore(td, tr.cells[idx] ?? null);
1429
2590
  }
1430
- </div>
1431
- <div
1432
- #editor
1433
- class="kpt-rich-text__editor"
1434
- [attr.contenteditable]="disabled() ? 'false' : 'true'"
1435
- [attr.data-placeholder]="placeholder()"
1436
- [attr.aria-invalid]="invalid() ? 'true' : null"
1437
- role="textbox"
1438
- aria-multiline="true"
1439
- (input)="onInput()"
1440
- (blur)="touch.emit()"
1441
- ></div>
1442
- </div>
1443
- `, isInline: true, styles: ["@layer kpt.components{.kpt-rich-text-host{display:block}.kpt-rich-text{border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);overflow:hidden;background:var(--kpt-form-field-bg)}.kpt-rich-text:focus-within{border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-rich-text--invalid{border-color:var(--kpt-form-field-border-error)}.kpt-rich-text--disabled{opacity:.6}.kpt-rich-text__toolbar{display:flex;flex-wrap:wrap;gap:.15rem;padding:.3rem;border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);background:var(--kpt-color-surface-variant)}.kpt-rich-text__tool{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer;font-size:1.05rem}.kpt-rich-text__tool:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-rich-text__tool:disabled{opacity:.5;cursor:not-allowed}.kpt-rich-text__editor{min-height:6rem;padding:var(--kpt-space-3, .75rem);font-size:var(--kpt-font-size-sm, .875rem);line-height:var(--kpt-font-line-height-normal, 1.5);color:var(--kpt-form-field-text);outline:none;overflow-y:auto}.kpt-rich-text__editor:empty:before{content:attr(data-placeholder);color:var(--kpt-form-field-placeholder)}.kpt-rich-text__editor a{color:var(--kpt-color-primary)}.kpt-rich-text__editor ul,.kpt-rich-text__editor ol{padding-inline-start:1.5rem}}\n"], dependencies: [{ kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2591
+ const colgroup = table.querySelector('colgroup');
2592
+ if (colgroup) {
2593
+ const col = document.createElement('col');
2594
+ colgroup.insertBefore(col, colgroup.children[idx] ?? null);
2595
+ this.normalizeColWidths(table);
2596
+ }
2597
+ this.afterTableOp();
2598
+ }
2599
+ deleteColumn() {
2600
+ const cell = this.ctxCell;
2601
+ const table = this.ctxTable();
2602
+ if (!cell || !table)
2603
+ return;
2604
+ const idx = cell.cellIndex;
2605
+ if ((table.rows[0]?.cells.length ?? 0) <= 1) {
2606
+ table.remove();
2607
+ this.afterTableOp();
2608
+ return;
2609
+ }
2610
+ for (const tr of Array.from(table.rows))
2611
+ tr.cells[idx]?.remove();
2612
+ table.querySelector('colgroup')?.children[idx]?.remove();
2613
+ this.normalizeColWidths(table);
2614
+ this.afterTableOp();
2615
+ }
2616
+ insertRow(dir) {
2617
+ const cell = this.ctxCell;
2618
+ const table = this.ctxTable();
2619
+ if (!cell || !table)
2620
+ return;
2621
+ const tr = cell.parentElement;
2622
+ const cols = tr.cells.length;
2623
+ const newRow = document.createElement('tr');
2624
+ newRow.innerHTML = Array.from({ length: cols }, () => '<td><br></td>').join('');
2625
+ tr.parentElement?.insertBefore(newRow, dir === 'below' ? tr.nextSibling : tr);
2626
+ this.afterTableOp();
2627
+ }
2628
+ deleteRow() {
2629
+ const cell = this.ctxCell;
2630
+ const table = this.ctxTable();
2631
+ if (!cell || !table)
2632
+ return;
2633
+ if (table.rows.length <= 1) {
2634
+ table.remove();
2635
+ this.afterTableOp();
2636
+ return;
2637
+ }
2638
+ cell.parentElement.remove();
2639
+ this.afterTableOp();
2640
+ }
2641
+ /** Zamień komórki wiersza między `<td>` a `<th>` (wiersz nagłówka). */
2642
+ toggleHeaderRow() {
2643
+ const cell = this.ctxCell;
2644
+ if (!cell)
2645
+ return;
2646
+ const tr = cell.parentElement;
2647
+ const toHeader = tr.cells[0]?.tagName !== 'TH';
2648
+ for (const c of Array.from(tr.cells))
2649
+ this.swapCellTag(c, toHeader ? 'th' : 'td');
2650
+ this.ctxCell = null; // komórki zostały podmienione
2651
+ this.afterTableOp();
2652
+ }
2653
+ /** Zamień komórki kolumny między `<td>` a `<th>` (kolumna nagłówka). */
2654
+ toggleHeaderColumn() {
2655
+ const cell = this.ctxCell;
2656
+ const table = this.ctxTable();
2657
+ if (!cell || !table)
2658
+ return;
2659
+ const idx = cell.cellIndex;
2660
+ const toHeader = cell.tagName !== 'TH';
2661
+ for (const tr of Array.from(table.rows)) {
2662
+ const c = tr.cells[idx];
2663
+ if (c)
2664
+ this.swapCellTag(c, toHeader ? 'th' : 'td');
2665
+ }
2666
+ this.ctxCell = null;
2667
+ this.afterTableOp();
2668
+ }
2669
+ swapCellTag(cell, tag) {
2670
+ if (cell.tagName.toLowerCase() === tag)
2671
+ return;
2672
+ const el = document.createElement(tag);
2673
+ for (const a of Array.from(cell.attributes))
2674
+ el.setAttribute(a.name, a.value);
2675
+ el.append(...Array.from(cell.childNodes));
2676
+ cell.replaceWith(el);
2677
+ }
2678
+ deleteTable() {
2679
+ this.ctxTable()?.remove();
2680
+ this.afterTableOp();
2681
+ }
2682
+ alignCell(a) {
2683
+ for (const cell of this.activeCells())
2684
+ cell.style.textAlign = a;
2685
+ this.afterTableOp();
2686
+ }
2687
+ /** Komórki objęte operacją: zaznaczenie (jeśli jest) lub bieżąca komórka menu. */
2688
+ activeCells() {
2689
+ if (this.selCells.size)
2690
+ return [...this.selCells];
2691
+ return this.ctxCell ? [this.ctxCell] : [];
2692
+ }
2693
+ openCellBg() {
2694
+ this.menuOpen.set(false);
2695
+ this.colorKind.set('cellBg');
2696
+ this.colorOpen.set(true);
2697
+ }
2698
+ // ── Obramowanie (tabela / komórka) ──
2699
+ openBorder() {
2700
+ this.menuOpen.set(false);
2701
+ this.borderOpen.set(true);
2702
+ }
2703
+ closeBorder() {
2704
+ this.borderOpen.set(false);
2705
+ }
2706
+ borderCells() {
2707
+ if (this.borderTarget() === 'cell')
2708
+ return this.activeCells();
2709
+ const table = this.ctxTable();
2710
+ return table ? Array.from(table.querySelectorAll('td, th')) : [];
2711
+ }
2712
+ setBorderWidth(w) {
2713
+ const px = { thin: '1px', medium: '2px', thick: '3px' };
2714
+ for (const cell of this.borderCells()) {
2715
+ if (w === 'none') {
2716
+ cell.style.borderStyle = 'none';
2717
+ cell.style.borderWidth = '';
2718
+ }
2719
+ else {
2720
+ cell.style.borderStyle = 'solid';
2721
+ cell.style.borderWidth = px[w];
2722
+ }
2723
+ }
2724
+ this.onInput();
2725
+ }
2726
+ setBorderColor(color) {
2727
+ for (const cell of this.borderCells()) {
2728
+ cell.style.borderColor = color;
2729
+ if (!cell.style.borderStyle || cell.style.borderStyle === 'none')
2730
+ cell.style.borderStyle = 'solid';
2731
+ if (!cell.style.borderWidth)
2732
+ cell.style.borderWidth = '1px';
2733
+ }
2734
+ this.onInput();
2735
+ }
2736
+ onBorderColorInput(event) {
2737
+ this.setBorderColor(event.target.value);
2738
+ }
2739
+ normalizeColWidths(table) {
2740
+ const cols = Array.from(table.querySelectorAll('col'));
2741
+ const w = (100 / cols.length).toFixed(4);
2742
+ for (const col of cols)
2743
+ col.style.width = `${w}%`;
2744
+ }
2745
+ // ── Tabele: resize kolumn + zaznaczanie komórek ──
2746
+ onEditorMouseDown(event) {
2747
+ if (this.disabled() || event.button !== 0)
2748
+ return; // tylko lewy przycisk
2749
+ const cell = event.target.closest('td, th');
2750
+ if (!cell) {
2751
+ this.clearSelection();
2752
+ return;
2753
+ }
2754
+ const rect = cell.getBoundingClientRect();
2755
+ if (event.clientX >= rect.right - 6) {
2756
+ // Strefa przy prawej krawędzi → resize kolumny.
2757
+ const table = cell.closest('table');
2758
+ const col = table?.querySelectorAll('col')[cell.cellIndex];
2759
+ if (col) {
2760
+ event.preventDefault();
2761
+ this.resize = { col, startX: event.clientX, startW: col.getBoundingClientRect().width };
2762
+ return;
2763
+ }
2764
+ }
2765
+ // Start zaznaczania (potwierdzone dopiero przy ruchu).
2766
+ this.clearSelection();
2767
+ this.selAnchor = cell;
2768
+ this.selecting = false;
2769
+ }
2770
+ onEditorMouseMove(event) {
2771
+ const cell = event.target.closest('td, th');
2772
+ const editor = this.editor()?.nativeElement;
2773
+ if (!editor)
2774
+ return;
2775
+ const near = !!cell && event.clientX >= cell.getBoundingClientRect().right - 6;
2776
+ editor.classList.toggle('is-col-resize', near || !!this.resize);
2777
+ }
2778
+ onResizeMove(event) {
2779
+ if (this.resize) {
2780
+ const w = Math.max(32, this.resize.startW + (event.clientX - this.resize.startX));
2781
+ this.resize.col.style.width = `${w}px`;
2782
+ return;
2783
+ }
2784
+ // Przeciąganie zaznaczenia komórek.
2785
+ if (!this.selAnchor || !(event.buttons & 1))
2786
+ return;
2787
+ const target = event.target;
2788
+ if (!(target instanceof Element))
2789
+ return;
2790
+ const focus = target.closest('td, th');
2791
+ if (!focus || focus.closest('table') !== this.selAnchor.closest('table'))
2792
+ return;
2793
+ if (focus === this.selAnchor && !this.selecting)
2794
+ return;
2795
+ this.selecting = true;
2796
+ event.preventDefault();
2797
+ window.getSelection()?.removeAllRanges();
2798
+ this.selectRegion(this.selAnchor, focus);
2799
+ }
2800
+ onResizeEnd() {
2801
+ if (this.resize) {
2802
+ this.resize = null;
2803
+ this.onInput();
2804
+ }
2805
+ if (this.selAnchor && !this.selecting)
2806
+ this.clearSelection(); // zwykły klik
2807
+ this.selAnchor = null;
2808
+ this.selecting = false;
2809
+ }
2810
+ // ── Macierz siatki (uwzględnia colspan/rowspan) ──
2811
+ buildGrid(table) {
2812
+ const grid = [];
2813
+ const pos = new Map();
2814
+ const rows = Array.from(table.rows);
2815
+ rows.forEach((tr, r) => {
2816
+ grid[r] ??= [];
2817
+ let c = 0;
2818
+ for (const cell of Array.from(tr.cells)) {
2819
+ while (grid[r][c])
2820
+ c++; // pomiń zajęte przez rowspan wyżej
2821
+ const colspan = cell.colSpan || 1;
2822
+ const rowspan = cell.rowSpan || 1;
2823
+ pos.set(cell, { r, c, rowspan, colspan });
2824
+ for (let dr = 0; dr < rowspan; dr++) {
2825
+ grid[r + dr] ??= [];
2826
+ for (let dc = 0; dc < colspan; dc++)
2827
+ grid[r + dr][c + dc] = cell;
2828
+ }
2829
+ c += colspan;
2830
+ }
2831
+ });
2832
+ return { grid, pos };
2833
+ }
2834
+ selectRegion(anchor, focus) {
2835
+ const table = anchor.closest('table');
2836
+ if (!table)
2837
+ return;
2838
+ const { grid, pos } = this.buildGrid(table);
2839
+ const a = pos.get(anchor);
2840
+ const f = pos.get(focus);
2841
+ if (!a || !f)
2842
+ return;
2843
+ let r0 = Math.min(a.r, f.r);
2844
+ let c0 = Math.min(a.c, f.c);
2845
+ let r1 = Math.max(a.r + a.rowspan - 1, f.r + f.rowspan - 1);
2846
+ let c1 = Math.max(a.c + a.colspan - 1, f.c + f.colspan - 1);
2847
+ // Rozszerz region, by w pełni objąć scalone komórki na brzegach.
2848
+ for (let changed = true; changed;) {
2849
+ changed = false;
2850
+ for (let r = r0; r <= r1; r++) {
2851
+ for (let c = c0; c <= c1; c++) {
2852
+ const cell = grid[r]?.[c];
2853
+ if (!cell)
2854
+ continue;
2855
+ const p = pos.get(cell);
2856
+ if (p.r < r0) {
2857
+ r0 = p.r;
2858
+ changed = true;
2859
+ }
2860
+ if (p.c < c0) {
2861
+ c0 = p.c;
2862
+ changed = true;
2863
+ }
2864
+ if (p.r + p.rowspan - 1 > r1) {
2865
+ r1 = p.r + p.rowspan - 1;
2866
+ changed = true;
2867
+ }
2868
+ if (p.c + p.colspan - 1 > c1) {
2869
+ c1 = p.c + p.colspan - 1;
2870
+ changed = true;
2871
+ }
2872
+ }
2873
+ }
2874
+ }
2875
+ const set = new Set();
2876
+ for (let r = r0; r <= r1; r++) {
2877
+ for (let c = c0; c <= c1; c++) {
2878
+ const cell = grid[r]?.[c];
2879
+ if (cell)
2880
+ set.add(cell);
2881
+ }
2882
+ }
2883
+ this.clearSelection();
2884
+ for (const cell of set)
2885
+ cell.classList.add('kpt-rt-cell-sel');
2886
+ this.selCells = set;
2887
+ this.selCount.set(set.size);
2888
+ }
2889
+ clearSelection() {
2890
+ for (const cell of this.selCells)
2891
+ cell.classList.remove('kpt-rt-cell-sel');
2892
+ this.selCells = new Set();
2893
+ this.selCount.set(0);
2894
+ }
2895
+ // ── Scalanie / dzielenie ──
2896
+ mergeCells() {
2897
+ if (this.selCells.size < 2)
2898
+ return;
2899
+ const cells = [...this.selCells];
2900
+ const table = cells[0].closest('table');
2901
+ const { pos } = this.buildGrid(table);
2902
+ let r0 = Infinity, c0 = Infinity, r1 = -1, c1 = -1;
2903
+ for (const cell of cells) {
2904
+ const p = pos.get(cell);
2905
+ r0 = Math.min(r0, p.r);
2906
+ c0 = Math.min(c0, p.c);
2907
+ r1 = Math.max(r1, p.r + p.rowspan - 1);
2908
+ c1 = Math.max(c1, p.c + p.colspan - 1);
2909
+ }
2910
+ const topLeft = cells.find((cell) => { const p = pos.get(cell); return p.r === r0 && p.c === c0; }) ?? cells[0];
2911
+ // Przenieś niepustą treść pozostałych komórek do górnej-lewej.
2912
+ for (const cell of cells) {
2913
+ if (cell === topLeft)
2914
+ continue;
2915
+ const html = cell.innerHTML.trim();
2916
+ if (html && html !== '<br>')
2917
+ topLeft.innerHTML += ` ${html}`;
2918
+ cell.remove();
2919
+ }
2920
+ const colspan = c1 - c0 + 1;
2921
+ const rowspan = r1 - r0 + 1;
2922
+ if (colspan > 1)
2923
+ topLeft.colSpan = colspan;
2924
+ else
2925
+ topLeft.removeAttribute('colspan');
2926
+ if (rowspan > 1)
2927
+ topLeft.rowSpan = rowspan;
2928
+ else
2929
+ topLeft.removeAttribute('rowspan');
2930
+ this.clearSelection();
2931
+ this.menuOpen.set(false);
2932
+ this.onInput();
2933
+ }
2934
+ splitCell() {
2935
+ const cell = this.ctxCell;
2936
+ if (!cell)
2937
+ return;
2938
+ const table = cell.closest('table');
2939
+ const { pos } = this.buildGrid(table);
2940
+ const p = pos.get(cell);
2941
+ if (!p || (p.colspan <= 1 && p.rowspan <= 1))
2942
+ return;
2943
+ const tag = cell.tagName.toLowerCase();
2944
+ cell.removeAttribute('colspan');
2945
+ cell.removeAttribute('rowspan');
2946
+ // Uzupełnij brakujące pozycje siatki pustymi komórkami (dla każdego pokrytego wiersza).
2947
+ for (let dr = 0; dr < p.rowspan; dr++) {
2948
+ const startCol = dr === 0 ? p.c + 1 : p.c; // origin zostaje w pierwszym wierszu
2949
+ const count = dr === 0 ? p.colspan - 1 : p.colspan;
2950
+ if (count <= 0)
2951
+ continue;
2952
+ const row = table.rows[p.r + dr];
2953
+ const before = this.cellBeforeGridCol(row, p.c, table);
2954
+ for (let i = 0; i < count; i++) {
2955
+ const el = document.createElement(tag);
2956
+ el.innerHTML = '<br>';
2957
+ row.insertBefore(el, before);
2958
+ }
2959
+ }
2960
+ this.menuOpen.set(false);
2961
+ this.onInput();
2962
+ }
2963
+ /** Komórka w wierszu, przed którą wstawić (pierwsza o origin-col > gridCol), lub null (na koniec). */
2964
+ cellBeforeGridCol(row, gridCol, table) {
2965
+ const { pos } = this.buildGrid(table);
2966
+ for (const cell of Array.from(row.cells)) {
2967
+ const p = pos.get(cell);
2968
+ if (p && p.c > gridCol)
2969
+ return cell;
2970
+ }
2971
+ return null;
2972
+ }
2973
+ canMerge() {
2974
+ return this.selCells.size >= 2;
2975
+ }
2976
+ canSplit() {
2977
+ return this.canSplitCtx;
2978
+ }
2979
+ sanitizeHtml(html) {
2980
+ const tpl = document.createElement('template');
2981
+ tpl.innerHTML = html;
2982
+ const walk = (root) => {
2983
+ for (const el of Array.from(root.querySelectorAll('*'))) {
2984
+ if (!ALLOWED_TAGS.has(el.tagName)) {
2985
+ el.replaceWith(...Array.from(el.childNodes));
2986
+ continue;
2987
+ }
2988
+ for (const attr of Array.from(el.attributes)) {
2989
+ const name = attr.name.toLowerCase();
2990
+ if (name.startsWith('on')) {
2991
+ el.removeAttribute(attr.name);
2992
+ }
2993
+ else if (name === 'href' || name === 'src') {
2994
+ if (/^\s*javascript:/i.test(attr.value))
2995
+ el.removeAttribute(attr.name);
2996
+ }
2997
+ else if (name === 'style') {
2998
+ const kept = attr.value
2999
+ .split(';')
3000
+ .map((s) => s.trim())
3001
+ .filter((s) => ALLOWED_STYLES.has(s.split(':')[0]?.trim().toLowerCase()));
3002
+ if (kept.length)
3003
+ el.setAttribute('style', kept.join('; '));
3004
+ else
3005
+ el.removeAttribute('style');
3006
+ }
3007
+ else if (!ALLOWED_ATTRS.has(name) && name !== 'color' && el.tagName !== 'A') {
3008
+ el.removeAttribute(attr.name);
3009
+ }
3010
+ }
3011
+ }
3012
+ };
3013
+ walk(tpl.content);
3014
+ return tpl.innerHTML;
3015
+ }
3016
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptRichText, deps: [], target: i0.ɵɵFactoryTarget.Component });
3017
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptRichText, isStandalone: true, selector: "kpt-rich-text", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, toolbar: { classPropertyName: "toolbar", publicName: "toolbar", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { classAttribute: "kpt-rich-text-host" }, viewQueries: [{ propertyName: "editor", first: true, predicate: ["editor"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"kpt-rich-text\" [class.kpt-rich-text--invalid]=\"invalid()\" [class.kpt-rich-text--disabled]=\"disabled()\">\n <div class=\"kpt-rich-text__toolbar\" role=\"toolbar\">\n @for (section of sections(); track $index; let firstSection = $first) {\n @if (!firstSection) {\n <span class=\"kpt-rich-text__divider\" aria-hidden=\"true\"></span>\n }\n @for (item of section; track item) {\n @switch (item) {\n @case ('heading') {\n <button\n type=\"button\"\n class=\"kpt-rich-text__style\"\n cdkOverlayOrigin\n #styleOrigin=\"cdkOverlayOrigin\"\n [class.is-open]=\"styleOpen()\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"aria(item)\"\n [attr.aria-expanded]=\"styleOpen()\"\n [kptTooltip]=\"aria(item)\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"openStyle()\"\n >\n <span>{{ styleLabel() }}</span>\n <kpt-icon name=\"chevron-down\" class=\"kpt-rich-text__style-caret\" />\n </button>\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"styleOrigin\"\n [cdkConnectedOverlayOpen]=\"styleOpen()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"closeStyle()\"\n (detach)=\"closeStyle()\"\n >\n <ul class=\"kpt-rich-text__style-panel\" role=\"listbox\">\n @for (o of styleOptions; track o.tag) {\n <li\n class=\"kpt-rich-text__style-opt\"\n [class]=\"'kpt-rich-text__style-opt kpt-rich-text__style-opt--' + o.tag\"\n role=\"option\"\n [attr.aria-selected]=\"currentBlock() === o.tag\"\n [class.is-selected]=\"currentBlock() === o.tag\"\n (click)=\"pickStyle(o.tag)\"\n >{{ o.label }}</li>\n }\n </ul>\n </ng-template>\n }\n @case ('foreColor') {\n <button\n type=\"button\"\n class=\"kpt-rich-text__tool kpt-rich-text__tool--color\"\n cdkOverlayOrigin\n #foreOrigin=\"cdkOverlayOrigin\"\n [attr.aria-label]=\"aria(item)\"\n [kptTooltip]=\"aria(item)\"\n [disabled]=\"disabled()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"openColor('foreColor')\"\n >\n <kpt-icon [name]=\"icon(item)\" />\n </button>\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"foreOrigin\"\n [cdkConnectedOverlayOpen]=\"colorOpen() && colorKind() === 'foreColor'\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"closeColor()\"\n (detach)=\"closeColor()\"\n >\n <ng-container [ngTemplateOutlet]=\"paletteTpl\" />\n </ng-template>\n }\n @case ('backColor') {\n <button\n type=\"button\"\n class=\"kpt-rich-text__tool kpt-rich-text__tool--color\"\n cdkOverlayOrigin\n #backOrigin=\"cdkOverlayOrigin\"\n [attr.aria-label]=\"aria(item)\"\n [kptTooltip]=\"aria(item)\"\n [disabled]=\"disabled()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"openColor('backColor')\"\n >\n <kpt-icon [name]=\"icon(item)\" />\n </button>\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"backOrigin\"\n [cdkConnectedOverlayOpen]=\"colorOpen() && colorKind() === 'backColor'\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"closeColor()\"\n (detach)=\"closeColor()\"\n >\n <ng-container [ngTemplateOutlet]=\"paletteTpl\" />\n </ng-template>\n }\n @case ('table') {\n <button\n type=\"button\"\n class=\"kpt-rich-text__tool\"\n cdkOverlayOrigin\n #tableOrigin=\"cdkOverlayOrigin\"\n [class.is-active]=\"tableOpen()\"\n [attr.aria-label]=\"aria(item)\"\n [kptTooltip]=\"aria(item)\"\n [disabled]=\"disabled()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"exec(item)\"\n >\n <kpt-icon [name]=\"icon(item)\" />\n </button>\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"tableOrigin\"\n [cdkConnectedOverlayOpen]=\"tableOpen()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"closeTable()\"\n (detach)=\"closeTable()\"\n >\n <div class=\"kpt-rt-grid-pop\" (mousedown)=\"$event.preventDefault()\">\n <div class=\"kpt-rt-grid\" (mouseleave)=\"gridHover(0, 0)\">\n @for (r of gridRows; track r) {\n <div class=\"kpt-rt-grid__row\">\n @for (c of gridCols; track c) {\n <span\n class=\"kpt-rt-grid__cell\"\n [class.is-on]=\"r <= gridR() && c <= gridC()\"\n (mouseenter)=\"gridHover(r, c)\"\n (click)=\"insertTable(r, c)\"\n ></span>\n }\n </div>\n }\n </div>\n <div class=\"kpt-rt-grid__label\">{{ gridR() }} \u00D7 {{ gridC() }}</div>\n </div>\n </ng-template>\n }\n @default {\n <button\n type=\"button\"\n class=\"kpt-rich-text__tool\"\n [class.is-active]=\"isActive(item)\"\n [attr.aria-label]=\"aria(item)\"\n [attr.aria-pressed]=\"isActive(item)\"\n [kptTooltip]=\"aria(item)\"\n [disabled]=\"disabled()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"exec(item)\"\n >\n <kpt-icon [name]=\"icon(item)\" />\n </button>\n }\n }\n }\n }\n </div>\n @if (sourceView()) {\n <textarea\n class=\"kpt-rich-text__source\"\n [value]=\"value()\"\n [disabled]=\"disabled()\"\n spellcheck=\"false\"\n aria-label=\"\u0179r\u00F3d\u0142o HTML\"\n (input)=\"onSource($event)\"\n (blur)=\"touch.emit()\"\n ></textarea>\n } @else {\n <div\n #editor\n class=\"kpt-rich-text__editor\"\n [attr.contenteditable]=\"disabled() ? 'false' : 'true'\"\n [attr.data-placeholder]=\"placeholder()\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n role=\"textbox\"\n aria-multiline=\"true\"\n (input)=\"onInput()\"\n (paste)=\"onPaste($event)\"\n (contextmenu)=\"onContextMenu($event)\"\n (mousedown)=\"onEditorMouseDown($event)\"\n (mousemove)=\"onEditorMouseMove($event)\"\n (blur)=\"touch.emit()\"\n ></div>\n }\n\n <!-- Menu kontekstowe tabeli (origin punktowy = pozycja kursora) -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"menuPoint()\"\n [cdkConnectedOverlayOpen]=\"menuOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"closeMenu()\"\n (detach)=\"closeMenu()\"\n >\n <div class=\"kpt-rt-menu\" (contextmenu)=\"$event.preventDefault()\">\n <div class=\"kpt-rt-menu__group\">Kolumna</div>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"insertColumn('left')\"><kpt-icon name=\"plus\" /> Wstaw z lewej</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"insertColumn('right')\"><kpt-icon name=\"plus\" /> Wstaw z prawej</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"toggleHeaderColumn()\"><kpt-icon name=\"table\" /> Nag\u0142\u00F3wek kolumny</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"deleteColumn()\"><kpt-icon name=\"trash\" /> Usu\u0144 kolumn\u0119</button>\n <div class=\"kpt-rt-menu__sep\"></div>\n <div class=\"kpt-rt-menu__group\">Wiersz</div>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"insertRow('above')\"><kpt-icon name=\"plus\" /> Wstaw powy\u017Cej</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"insertRow('below')\"><kpt-icon name=\"plus\" /> Wstaw poni\u017Cej</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"toggleHeaderRow()\"><kpt-icon name=\"table\" /> Nag\u0142\u00F3wek wiersza</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"deleteRow()\"><kpt-icon name=\"trash\" /> Usu\u0144 wiersz</button>\n <div class=\"kpt-rt-menu__sep\"></div>\n <div class=\"kpt-rt-menu__group\">Kom\u00F3rka</div>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"openCellBg()\"><kpt-icon name=\"palette\" /> Kolor t\u0142a</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"alignCell('left')\"><kpt-icon name=\"align-left\" /> Do lewej</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"alignCell('center')\"><kpt-icon name=\"align-center\" /> Wy\u015Brodkuj</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"alignCell('right')\"><kpt-icon name=\"align-right\" /> Do prawej</button>\n <div class=\"kpt-rt-menu__sep\"></div>\n <button type=\"button\" class=\"kpt-rt-menu__item\" [class.is-disabled]=\"!canMerge()\" (click)=\"mergeCells()\"><kpt-icon name=\"table\" /> Scal kom\u00F3rki</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" [class.is-disabled]=\"!canSplit()\" (click)=\"splitCell()\"><kpt-icon name=\"grip-vertical\" /> Podziel kom\u00F3rk\u0119</button>\n <div class=\"kpt-rt-menu__sep\"></div>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"openBorder()\"><kpt-icon name=\"table\" /> Obramowanie\u2026</button>\n <div class=\"kpt-rt-menu__sep\"></div>\n <button type=\"button\" class=\"kpt-rt-menu__item kpt-rt-menu__item--danger\" (click)=\"deleteTable()\"><kpt-icon name=\"trash\" /> Usu\u0144 tabel\u0119</button>\n </div>\n </ng-template>\n\n <!-- Popover obramowania (tabela / kom\u00F3rka) -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"menuPoint()\"\n [cdkConnectedOverlayOpen]=\"borderOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"closeBorder()\"\n (detach)=\"closeBorder()\"\n >\n <div class=\"kpt-rt-border\" (mousedown)=\"$event.preventDefault()\">\n <div class=\"kpt-rt-border__seg\">\n <button type=\"button\" [class.is-active]=\"borderTarget() === 'table'\" (click)=\"borderTarget.set('table')\">Tabela</button>\n <button type=\"button\" [class.is-active]=\"borderTarget() === 'cell'\" (click)=\"borderTarget.set('cell')\">Kom\u00F3rka</button>\n </div>\n <div class=\"kpt-rt-border__widths\">\n <button type=\"button\" (click)=\"setBorderWidth('none')\">Bez</button>\n <button type=\"button\" (click)=\"setBorderWidth('thin')\">Cienkie</button>\n <button type=\"button\" (click)=\"setBorderWidth('medium')\">\u015Arednie</button>\n <button type=\"button\" (click)=\"setBorderWidth('thick')\">Grube</button>\n </div>\n <div class=\"kpt-rich-text__swatches\">\n @for (c of swatches; track c) {\n <button type=\"button\" class=\"kpt-rich-text__swatch\" [style.background]=\"c\" [attr.aria-label]=\"c\" (click)=\"setBorderColor(c)\"></button>\n }\n </div>\n <label class=\"kpt-rich-text__picker\">\n <span>Kolor\u2026</span>\n <input type=\"color\" (input)=\"onBorderColorInput($event)\" />\n </label>\n </div>\n </ng-template>\n\n <!-- Popover koloru t\u0142a kom\u00F3rki (z menu kontekstowego) -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"menuPoint()\"\n [cdkConnectedOverlayOpen]=\"colorOpen() && colorKind() === 'cellBg'\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"closeColor()\"\n (detach)=\"closeColor()\"\n >\n <ng-container [ngTemplateOutlet]=\"paletteTpl\" />\n </ng-template>\n</div>\n\n<ng-template #paletteTpl>\n <div class=\"kpt-rich-text__palette\" (mousedown)=\"$event.preventDefault()\">\n <div class=\"kpt-rich-text__swatches\">\n @for (c of swatches; track c) {\n <button\n type=\"button\"\n class=\"kpt-rich-text__swatch\"\n [style.background]=\"c\"\n [attr.aria-label]=\"c\"\n (click)=\"applyColor(c)\"\n ></button>\n }\n </div>\n <label class=\"kpt-rich-text__picker\">\n <span>W\u0142asny\u2026</span>\n <input type=\"color\" (input)=\"onColorInput($event)\" />\n </label>\n </div>\n</ng-template>\n", styles: ["@layer kpt.components{.kpt-rich-text-host{display:block}.kpt-rich-text{border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);overflow:hidden;background:var(--kpt-form-field-bg)}.kpt-rich-text:focus-within{border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-rich-text--invalid{border-color:var(--kpt-form-field-border-error)}.kpt-rich-text--disabled{opacity:.6}.kpt-rich-text__toolbar{display:flex;flex-wrap:wrap;gap:.15rem;padding:.3rem;border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);background:var(--kpt-color-surface-variant)}.kpt-rich-text__tool{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer;font-size:1.05rem}.kpt-rich-text__tool:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-rich-text__tool:disabled{opacity:.5;cursor:not-allowed}.kpt-rich-text__tool.is-active{background:var(--kpt-color-muted);color:var(--kpt-color-primary)}.kpt-rich-text__divider{width:var(--kpt-border-width-thin, 1px);align-self:stretch;margin-inline:.2rem;background:var(--kpt-color-border)}.kpt-rich-text__style{display:inline-flex;align-items:center;gap:var(--kpt-space-1, .25rem);height:2rem;min-width:8rem;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-radius-sm, .25rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);padding-inline:.5rem;cursor:pointer}.kpt-rich-text__style span{flex:1;text-align:start}.kpt-rich-text__style:hover:not(:disabled){border-color:var(--kpt-form-field-border-hover)}.kpt-rich-text__style.is-open{border-color:var(--kpt-form-field-border-focus)}.kpt-rich-text__style:disabled{opacity:.5;cursor:not-allowed}.kpt-rich-text__style-caret{opacity:.6}.kpt-rich-text__editor{min-height:6rem;padding:var(--kpt-space-3, .75rem);font-size:var(--kpt-font-size-sm, .875rem);line-height:var(--kpt-font-line-height-normal, 1.5);color:var(--kpt-form-field-text);outline:none;overflow-y:auto}.kpt-rich-text__editor:empty:before{content:attr(data-placeholder);color:var(--kpt-form-field-placeholder)}.kpt-rich-text__editor a{color:var(--kpt-color-primary)}.kpt-rich-text__editor ul,.kpt-rich-text__editor ol{padding-inline-start:1.5rem}.kpt-rich-text__editor h1{font-size:1.6em;font-weight:700;margin:.4em 0}.kpt-rich-text__editor h2{font-size:1.4em;font-weight:700;margin:.4em 0}.kpt-rich-text__editor h3{font-size:1.2em;font-weight:600;margin:.4em 0}.kpt-rich-text__editor h4{font-size:1.05em;font-weight:600;margin:.4em 0}.kpt-rich-text__editor h5{font-size:.95em;font-weight:600;margin:.4em 0}.kpt-rich-text__editor h6{font-size:.85em;font-weight:600;margin:.4em 0;text-transform:uppercase}.kpt-rich-text__editor blockquote{margin:.4em 0;padding-inline-start:.75rem;border-inline-start:3px solid var(--kpt-color-border-strong);color:var(--kpt-color-on-surface-muted)}.kpt-rich-text__editor .kpt-rt-table{border-collapse:collapse;table-layout:fixed;width:100%;margin:.5em 0}.kpt-rich-text__editor .kpt-rt-table td,.kpt-rich-text__editor .kpt-rt-table th{border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);padding:.35rem .5rem;min-width:2rem;vertical-align:top;overflow-wrap:anywhere}.kpt-rich-text__editor .kpt-rt-table th{background:var(--kpt-color-surface-variant);font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-rich-text__editor .kpt-rt-table .kpt-rt-cell-sel{box-shadow:inset 0 0 0 2px var(--kpt-color-primary);background:color-mix(in oklch,var(--kpt-color-primary) 12%,transparent)}.kpt-rich-text__editor.is-col-resize{cursor:col-resize}.kpt-rich-text__source{display:block;width:100%;box-sizing:border-box;min-height:6rem;padding:var(--kpt-space-3, .75rem);border:0;background:var(--kpt-color-surface-variant);color:var(--kpt-form-field-text);font-family:var(--kpt-font-family-mono, ui-monospace, monospace);font-size:var(--kpt-font-size-xs, .75rem);line-height:var(--kpt-font-line-height-normal, 1.5);resize:vertical;outline:none}.kpt-rich-text__style-panel{min-width:11rem;margin:0;padding:.25rem;list-style:none;background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3);max-height:20rem;overflow-y:auto}.kpt-rich-text__style-opt{padding:.35rem .6rem;border-radius:var(--kpt-radius-sm, .25rem);color:var(--kpt-color-on-surface);cursor:pointer;line-height:1.2}.kpt-rich-text__style-opt:hover{background:var(--kpt-color-muted)}.kpt-rich-text__style-opt.is-selected{background:var(--kpt-color-muted);color:var(--kpt-color-primary)}.kpt-rich-text__style-opt--p{font-size:.95rem}.kpt-rich-text__style-opt--h1{font-size:1.7rem;font-weight:700}.kpt-rich-text__style-opt--h2{font-size:1.45rem;font-weight:700}.kpt-rich-text__style-opt--h3{font-size:1.25rem;font-weight:600}.kpt-rich-text__style-opt--h4{font-size:1.1rem;font-weight:600}.kpt-rich-text__style-opt--h5{font-size:1rem;font-weight:600}.kpt-rich-text__style-opt--h6{font-size:.85rem;font-weight:600;text-transform:uppercase;letter-spacing:.03em}.kpt-rich-text__palette{padding:var(--kpt-space-3, .75rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3)}.kpt-rich-text__swatches{display:grid;grid-template-columns:repeat(7,1fr);gap:4px}.kpt-rich-text__swatch{width:1.4rem;height:1.4rem;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-sm, .25rem);cursor:pointer}.kpt-rich-text__swatch:hover{transform:scale(1.1)}.kpt-rich-text__picker{display:flex;align-items:center;justify-content:space-between;gap:var(--kpt-space-2, .5rem);margin-top:var(--kpt-space-2, .5rem);font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface-muted)}.kpt-rich-text__picker input[type=color]{width:2rem;height:1.6rem;padding:0;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-sm, .25rem);background:none;cursor:pointer}.kpt-rt-grid-pop{padding:var(--kpt-space-2, .5rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3)}.kpt-rt-grid{display:flex;flex-direction:column;gap:3px}.kpt-rt-grid__row{display:flex;gap:3px}.kpt-rt-grid__cell{width:1rem;height:1rem;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:2px;cursor:pointer}.kpt-rt-grid__cell.is-on{background:var(--kpt-color-primary);border-color:var(--kpt-color-primary)}.kpt-rt-grid__label{margin-top:var(--kpt-space-2, .5rem);text-align:center;font-size:var(--kpt-font-size-xs, .75rem);color:var(--kpt-color-on-surface-muted)}.kpt-rt-menu{min-width:12rem;padding:.25rem;background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3);font-size:var(--kpt-font-size-sm, .875rem)}.kpt-rt-menu__group{padding:.3rem .6rem .15rem;font-size:var(--kpt-font-size-xs, .75rem);font-weight:var(--kpt-font-weight-semibold, 600);text-transform:uppercase;letter-spacing:.03em;color:var(--kpt-color-on-surface-muted)}.kpt-rt-menu__item{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);width:100%;padding:.4rem .6rem;border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font:inherit;text-align:start;cursor:pointer}.kpt-rt-menu__item:hover{background:var(--kpt-color-muted)}.kpt-rt-menu__item kpt-icon{color:var(--kpt-color-on-surface-muted)}.kpt-rt-menu__item--danger{color:var(--kpt-color-danger)}.kpt-rt-menu__item--danger kpt-icon{color:var(--kpt-color-danger)}.kpt-rt-menu__item.is-disabled{opacity:.4;pointer-events:none}.kpt-rt-menu__sep{height:1px;margin:.25rem 0;background:var(--kpt-color-border)}.kpt-rt-border{display:flex;flex-direction:column;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-3, .75rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3)}.kpt-rt-border__seg{display:flex;gap:2px;padding:2px;background:var(--kpt-color-surface-variant);border-radius:var(--kpt-radius-md, .5rem)}.kpt-rt-border__seg button{flex:1;border:0;background:none;padding:.25rem .5rem;border-radius:var(--kpt-radius-sm, .25rem);color:var(--kpt-color-on-surface-muted);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-rt-border__seg button.is-active{background:var(--kpt-color-surface-raised);color:var(--kpt-color-on-surface);font-weight:var(--kpt-font-weight-medium, 500);box-shadow:var(--kpt-elevation-1)}.kpt-rt-border__widths{display:flex;gap:.25rem}.kpt-rt-border__widths button{flex:1;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);background:none;padding:.25rem .3rem;border-radius:var(--kpt-radius-sm, .25rem);color:var(--kpt-color-on-surface);font:inherit;font-size:var(--kpt-font-size-xs, .75rem);cursor:pointer}.kpt-rt-border__widths button:hover{background:var(--kpt-color-muted)}}\n"], dependencies: [{ kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }, { kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: KptTooltip, selector: "[kptTooltip]", inputs: ["kptTooltip", "kptTooltipPosition"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1444
3018
  }
1445
3019
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptRichText, decorators: [{
1446
3020
  type: Component,
1447
- args: [{ selector: 'kpt-rich-text', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [KptIcon], template: `
1448
- <div class="kpt-rich-text" [class.kpt-rich-text--invalid]="invalid()" [class.kpt-rich-text--disabled]="disabled()">
1449
- <div class="kpt-rich-text__toolbar" role="toolbar">
1450
- @for (item of toolbar(); track item) {
1451
- <button
1452
- type="button"
1453
- class="kpt-rich-text__tool"
1454
- [attr.aria-label]="item"
1455
- [disabled]="disabled()"
1456
- (mousedown)="$event.preventDefault()"
1457
- (click)="exec(item)"
1458
- ><kpt-icon [name]="icon(item)" /></button>
1459
- }
1460
- </div>
1461
- <div
1462
- #editor
1463
- class="kpt-rich-text__editor"
1464
- [attr.contenteditable]="disabled() ? 'false' : 'true'"
1465
- [attr.data-placeholder]="placeholder()"
1466
- [attr.aria-invalid]="invalid() ? 'true' : null"
1467
- role="textbox"
1468
- aria-multiline="true"
1469
- (input)="onInput()"
1470
- (blur)="touch.emit()"
1471
- ></div>
1472
- </div>
1473
- `, host: { class: 'kpt-rich-text-host' }, styles: ["@layer kpt.components{.kpt-rich-text-host{display:block}.kpt-rich-text{border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);overflow:hidden;background:var(--kpt-form-field-bg)}.kpt-rich-text:focus-within{border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-rich-text--invalid{border-color:var(--kpt-form-field-border-error)}.kpt-rich-text--disabled{opacity:.6}.kpt-rich-text__toolbar{display:flex;flex-wrap:wrap;gap:.15rem;padding:.3rem;border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);background:var(--kpt-color-surface-variant)}.kpt-rich-text__tool{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer;font-size:1.05rem}.kpt-rich-text__tool:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-rich-text__tool:disabled{opacity:.5;cursor:not-allowed}.kpt-rich-text__editor{min-height:6rem;padding:var(--kpt-space-3, .75rem);font-size:var(--kpt-font-size-sm, .875rem);line-height:var(--kpt-font-line-height-normal, 1.5);color:var(--kpt-form-field-text);outline:none;overflow-y:auto}.kpt-rich-text__editor:empty:before{content:attr(data-placeholder);color:var(--kpt-form-field-placeholder)}.kpt-rich-text__editor a{color:var(--kpt-color-primary)}.kpt-rich-text__editor ul,.kpt-rich-text__editor ol{padding-inline-start:1.5rem}}\n"] }]
3021
+ args: [{ selector: 'kpt-rich-text', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [KptIcon, CdkOverlayOrigin, CdkConnectedOverlay, NgTemplateOutlet, KptTooltip], host: { class: 'kpt-rich-text-host' }, template: "<div class=\"kpt-rich-text\" [class.kpt-rich-text--invalid]=\"invalid()\" [class.kpt-rich-text--disabled]=\"disabled()\">\n <div class=\"kpt-rich-text__toolbar\" role=\"toolbar\">\n @for (section of sections(); track $index; let firstSection = $first) {\n @if (!firstSection) {\n <span class=\"kpt-rich-text__divider\" aria-hidden=\"true\"></span>\n }\n @for (item of section; track item) {\n @switch (item) {\n @case ('heading') {\n <button\n type=\"button\"\n class=\"kpt-rich-text__style\"\n cdkOverlayOrigin\n #styleOrigin=\"cdkOverlayOrigin\"\n [class.is-open]=\"styleOpen()\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"aria(item)\"\n [attr.aria-expanded]=\"styleOpen()\"\n [kptTooltip]=\"aria(item)\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"openStyle()\"\n >\n <span>{{ styleLabel() }}</span>\n <kpt-icon name=\"chevron-down\" class=\"kpt-rich-text__style-caret\" />\n </button>\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"styleOrigin\"\n [cdkConnectedOverlayOpen]=\"styleOpen()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"closeStyle()\"\n (detach)=\"closeStyle()\"\n >\n <ul class=\"kpt-rich-text__style-panel\" role=\"listbox\">\n @for (o of styleOptions; track o.tag) {\n <li\n class=\"kpt-rich-text__style-opt\"\n [class]=\"'kpt-rich-text__style-opt kpt-rich-text__style-opt--' + o.tag\"\n role=\"option\"\n [attr.aria-selected]=\"currentBlock() === o.tag\"\n [class.is-selected]=\"currentBlock() === o.tag\"\n (click)=\"pickStyle(o.tag)\"\n >{{ o.label }}</li>\n }\n </ul>\n </ng-template>\n }\n @case ('foreColor') {\n <button\n type=\"button\"\n class=\"kpt-rich-text__tool kpt-rich-text__tool--color\"\n cdkOverlayOrigin\n #foreOrigin=\"cdkOverlayOrigin\"\n [attr.aria-label]=\"aria(item)\"\n [kptTooltip]=\"aria(item)\"\n [disabled]=\"disabled()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"openColor('foreColor')\"\n >\n <kpt-icon [name]=\"icon(item)\" />\n </button>\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"foreOrigin\"\n [cdkConnectedOverlayOpen]=\"colorOpen() && colorKind() === 'foreColor'\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"closeColor()\"\n (detach)=\"closeColor()\"\n >\n <ng-container [ngTemplateOutlet]=\"paletteTpl\" />\n </ng-template>\n }\n @case ('backColor') {\n <button\n type=\"button\"\n class=\"kpt-rich-text__tool kpt-rich-text__tool--color\"\n cdkOverlayOrigin\n #backOrigin=\"cdkOverlayOrigin\"\n [attr.aria-label]=\"aria(item)\"\n [kptTooltip]=\"aria(item)\"\n [disabled]=\"disabled()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"openColor('backColor')\"\n >\n <kpt-icon [name]=\"icon(item)\" />\n </button>\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"backOrigin\"\n [cdkConnectedOverlayOpen]=\"colorOpen() && colorKind() === 'backColor'\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"closeColor()\"\n (detach)=\"closeColor()\"\n >\n <ng-container [ngTemplateOutlet]=\"paletteTpl\" />\n </ng-template>\n }\n @case ('table') {\n <button\n type=\"button\"\n class=\"kpt-rich-text__tool\"\n cdkOverlayOrigin\n #tableOrigin=\"cdkOverlayOrigin\"\n [class.is-active]=\"tableOpen()\"\n [attr.aria-label]=\"aria(item)\"\n [kptTooltip]=\"aria(item)\"\n [disabled]=\"disabled()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"exec(item)\"\n >\n <kpt-icon [name]=\"icon(item)\" />\n </button>\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"tableOrigin\"\n [cdkConnectedOverlayOpen]=\"tableOpen()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"closeTable()\"\n (detach)=\"closeTable()\"\n >\n <div class=\"kpt-rt-grid-pop\" (mousedown)=\"$event.preventDefault()\">\n <div class=\"kpt-rt-grid\" (mouseleave)=\"gridHover(0, 0)\">\n @for (r of gridRows; track r) {\n <div class=\"kpt-rt-grid__row\">\n @for (c of gridCols; track c) {\n <span\n class=\"kpt-rt-grid__cell\"\n [class.is-on]=\"r <= gridR() && c <= gridC()\"\n (mouseenter)=\"gridHover(r, c)\"\n (click)=\"insertTable(r, c)\"\n ></span>\n }\n </div>\n }\n </div>\n <div class=\"kpt-rt-grid__label\">{{ gridR() }} \u00D7 {{ gridC() }}</div>\n </div>\n </ng-template>\n }\n @default {\n <button\n type=\"button\"\n class=\"kpt-rich-text__tool\"\n [class.is-active]=\"isActive(item)\"\n [attr.aria-label]=\"aria(item)\"\n [attr.aria-pressed]=\"isActive(item)\"\n [kptTooltip]=\"aria(item)\"\n [disabled]=\"disabled()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"exec(item)\"\n >\n <kpt-icon [name]=\"icon(item)\" />\n </button>\n }\n }\n }\n }\n </div>\n @if (sourceView()) {\n <textarea\n class=\"kpt-rich-text__source\"\n [value]=\"value()\"\n [disabled]=\"disabled()\"\n spellcheck=\"false\"\n aria-label=\"\u0179r\u00F3d\u0142o HTML\"\n (input)=\"onSource($event)\"\n (blur)=\"touch.emit()\"\n ></textarea>\n } @else {\n <div\n #editor\n class=\"kpt-rich-text__editor\"\n [attr.contenteditable]=\"disabled() ? 'false' : 'true'\"\n [attr.data-placeholder]=\"placeholder()\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n role=\"textbox\"\n aria-multiline=\"true\"\n (input)=\"onInput()\"\n (paste)=\"onPaste($event)\"\n (contextmenu)=\"onContextMenu($event)\"\n (mousedown)=\"onEditorMouseDown($event)\"\n (mousemove)=\"onEditorMouseMove($event)\"\n (blur)=\"touch.emit()\"\n ></div>\n }\n\n <!-- Menu kontekstowe tabeli (origin punktowy = pozycja kursora) -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"menuPoint()\"\n [cdkConnectedOverlayOpen]=\"menuOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"closeMenu()\"\n (detach)=\"closeMenu()\"\n >\n <div class=\"kpt-rt-menu\" (contextmenu)=\"$event.preventDefault()\">\n <div class=\"kpt-rt-menu__group\">Kolumna</div>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"insertColumn('left')\"><kpt-icon name=\"plus\" /> Wstaw z lewej</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"insertColumn('right')\"><kpt-icon name=\"plus\" /> Wstaw z prawej</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"toggleHeaderColumn()\"><kpt-icon name=\"table\" /> Nag\u0142\u00F3wek kolumny</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"deleteColumn()\"><kpt-icon name=\"trash\" /> Usu\u0144 kolumn\u0119</button>\n <div class=\"kpt-rt-menu__sep\"></div>\n <div class=\"kpt-rt-menu__group\">Wiersz</div>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"insertRow('above')\"><kpt-icon name=\"plus\" /> Wstaw powy\u017Cej</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"insertRow('below')\"><kpt-icon name=\"plus\" /> Wstaw poni\u017Cej</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"toggleHeaderRow()\"><kpt-icon name=\"table\" /> Nag\u0142\u00F3wek wiersza</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"deleteRow()\"><kpt-icon name=\"trash\" /> Usu\u0144 wiersz</button>\n <div class=\"kpt-rt-menu__sep\"></div>\n <div class=\"kpt-rt-menu__group\">Kom\u00F3rka</div>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"openCellBg()\"><kpt-icon name=\"palette\" /> Kolor t\u0142a</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"alignCell('left')\"><kpt-icon name=\"align-left\" /> Do lewej</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"alignCell('center')\"><kpt-icon name=\"align-center\" /> Wy\u015Brodkuj</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"alignCell('right')\"><kpt-icon name=\"align-right\" /> Do prawej</button>\n <div class=\"kpt-rt-menu__sep\"></div>\n <button type=\"button\" class=\"kpt-rt-menu__item\" [class.is-disabled]=\"!canMerge()\" (click)=\"mergeCells()\"><kpt-icon name=\"table\" /> Scal kom\u00F3rki</button>\n <button type=\"button\" class=\"kpt-rt-menu__item\" [class.is-disabled]=\"!canSplit()\" (click)=\"splitCell()\"><kpt-icon name=\"grip-vertical\" /> Podziel kom\u00F3rk\u0119</button>\n <div class=\"kpt-rt-menu__sep\"></div>\n <button type=\"button\" class=\"kpt-rt-menu__item\" (click)=\"openBorder()\"><kpt-icon name=\"table\" /> Obramowanie\u2026</button>\n <div class=\"kpt-rt-menu__sep\"></div>\n <button type=\"button\" class=\"kpt-rt-menu__item kpt-rt-menu__item--danger\" (click)=\"deleteTable()\"><kpt-icon name=\"trash\" /> Usu\u0144 tabel\u0119</button>\n </div>\n </ng-template>\n\n <!-- Popover obramowania (tabela / kom\u00F3rka) -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"menuPoint()\"\n [cdkConnectedOverlayOpen]=\"borderOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"closeBorder()\"\n (detach)=\"closeBorder()\"\n >\n <div class=\"kpt-rt-border\" (mousedown)=\"$event.preventDefault()\">\n <div class=\"kpt-rt-border__seg\">\n <button type=\"button\" [class.is-active]=\"borderTarget() === 'table'\" (click)=\"borderTarget.set('table')\">Tabela</button>\n <button type=\"button\" [class.is-active]=\"borderTarget() === 'cell'\" (click)=\"borderTarget.set('cell')\">Kom\u00F3rka</button>\n </div>\n <div class=\"kpt-rt-border__widths\">\n <button type=\"button\" (click)=\"setBorderWidth('none')\">Bez</button>\n <button type=\"button\" (click)=\"setBorderWidth('thin')\">Cienkie</button>\n <button type=\"button\" (click)=\"setBorderWidth('medium')\">\u015Arednie</button>\n <button type=\"button\" (click)=\"setBorderWidth('thick')\">Grube</button>\n </div>\n <div class=\"kpt-rich-text__swatches\">\n @for (c of swatches; track c) {\n <button type=\"button\" class=\"kpt-rich-text__swatch\" [style.background]=\"c\" [attr.aria-label]=\"c\" (click)=\"setBorderColor(c)\"></button>\n }\n </div>\n <label class=\"kpt-rich-text__picker\">\n <span>Kolor\u2026</span>\n <input type=\"color\" (input)=\"onBorderColorInput($event)\" />\n </label>\n </div>\n </ng-template>\n\n <!-- Popover koloru t\u0142a kom\u00F3rki (z menu kontekstowego) -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"menuPoint()\"\n [cdkConnectedOverlayOpen]=\"colorOpen() && colorKind() === 'cellBg'\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"closeColor()\"\n (detach)=\"closeColor()\"\n >\n <ng-container [ngTemplateOutlet]=\"paletteTpl\" />\n </ng-template>\n</div>\n\n<ng-template #paletteTpl>\n <div class=\"kpt-rich-text__palette\" (mousedown)=\"$event.preventDefault()\">\n <div class=\"kpt-rich-text__swatches\">\n @for (c of swatches; track c) {\n <button\n type=\"button\"\n class=\"kpt-rich-text__swatch\"\n [style.background]=\"c\"\n [attr.aria-label]=\"c\"\n (click)=\"applyColor(c)\"\n ></button>\n }\n </div>\n <label class=\"kpt-rich-text__picker\">\n <span>W\u0142asny\u2026</span>\n <input type=\"color\" (input)=\"onColorInput($event)\" />\n </label>\n </div>\n</ng-template>\n", styles: ["@layer kpt.components{.kpt-rich-text-host{display:block}.kpt-rich-text{border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);overflow:hidden;background:var(--kpt-form-field-bg)}.kpt-rich-text:focus-within{border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-rich-text--invalid{border-color:var(--kpt-form-field-border-error)}.kpt-rich-text--disabled{opacity:.6}.kpt-rich-text__toolbar{display:flex;flex-wrap:wrap;gap:.15rem;padding:.3rem;border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);background:var(--kpt-color-surface-variant)}.kpt-rich-text__tool{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer;font-size:1.05rem}.kpt-rich-text__tool:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-rich-text__tool:disabled{opacity:.5;cursor:not-allowed}.kpt-rich-text__tool.is-active{background:var(--kpt-color-muted);color:var(--kpt-color-primary)}.kpt-rich-text__divider{width:var(--kpt-border-width-thin, 1px);align-self:stretch;margin-inline:.2rem;background:var(--kpt-color-border)}.kpt-rich-text__style{display:inline-flex;align-items:center;gap:var(--kpt-space-1, .25rem);height:2rem;min-width:8rem;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-radius-sm, .25rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);padding-inline:.5rem;cursor:pointer}.kpt-rich-text__style span{flex:1;text-align:start}.kpt-rich-text__style:hover:not(:disabled){border-color:var(--kpt-form-field-border-hover)}.kpt-rich-text__style.is-open{border-color:var(--kpt-form-field-border-focus)}.kpt-rich-text__style:disabled{opacity:.5;cursor:not-allowed}.kpt-rich-text__style-caret{opacity:.6}.kpt-rich-text__editor{min-height:6rem;padding:var(--kpt-space-3, .75rem);font-size:var(--kpt-font-size-sm, .875rem);line-height:var(--kpt-font-line-height-normal, 1.5);color:var(--kpt-form-field-text);outline:none;overflow-y:auto}.kpt-rich-text__editor:empty:before{content:attr(data-placeholder);color:var(--kpt-form-field-placeholder)}.kpt-rich-text__editor a{color:var(--kpt-color-primary)}.kpt-rich-text__editor ul,.kpt-rich-text__editor ol{padding-inline-start:1.5rem}.kpt-rich-text__editor h1{font-size:1.6em;font-weight:700;margin:.4em 0}.kpt-rich-text__editor h2{font-size:1.4em;font-weight:700;margin:.4em 0}.kpt-rich-text__editor h3{font-size:1.2em;font-weight:600;margin:.4em 0}.kpt-rich-text__editor h4{font-size:1.05em;font-weight:600;margin:.4em 0}.kpt-rich-text__editor h5{font-size:.95em;font-weight:600;margin:.4em 0}.kpt-rich-text__editor h6{font-size:.85em;font-weight:600;margin:.4em 0;text-transform:uppercase}.kpt-rich-text__editor blockquote{margin:.4em 0;padding-inline-start:.75rem;border-inline-start:3px solid var(--kpt-color-border-strong);color:var(--kpt-color-on-surface-muted)}.kpt-rich-text__editor .kpt-rt-table{border-collapse:collapse;table-layout:fixed;width:100%;margin:.5em 0}.kpt-rich-text__editor .kpt-rt-table td,.kpt-rich-text__editor .kpt-rt-table th{border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);padding:.35rem .5rem;min-width:2rem;vertical-align:top;overflow-wrap:anywhere}.kpt-rich-text__editor .kpt-rt-table th{background:var(--kpt-color-surface-variant);font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-rich-text__editor .kpt-rt-table .kpt-rt-cell-sel{box-shadow:inset 0 0 0 2px var(--kpt-color-primary);background:color-mix(in oklch,var(--kpt-color-primary) 12%,transparent)}.kpt-rich-text__editor.is-col-resize{cursor:col-resize}.kpt-rich-text__source{display:block;width:100%;box-sizing:border-box;min-height:6rem;padding:var(--kpt-space-3, .75rem);border:0;background:var(--kpt-color-surface-variant);color:var(--kpt-form-field-text);font-family:var(--kpt-font-family-mono, ui-monospace, monospace);font-size:var(--kpt-font-size-xs, .75rem);line-height:var(--kpt-font-line-height-normal, 1.5);resize:vertical;outline:none}.kpt-rich-text__style-panel{min-width:11rem;margin:0;padding:.25rem;list-style:none;background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3);max-height:20rem;overflow-y:auto}.kpt-rich-text__style-opt{padding:.35rem .6rem;border-radius:var(--kpt-radius-sm, .25rem);color:var(--kpt-color-on-surface);cursor:pointer;line-height:1.2}.kpt-rich-text__style-opt:hover{background:var(--kpt-color-muted)}.kpt-rich-text__style-opt.is-selected{background:var(--kpt-color-muted);color:var(--kpt-color-primary)}.kpt-rich-text__style-opt--p{font-size:.95rem}.kpt-rich-text__style-opt--h1{font-size:1.7rem;font-weight:700}.kpt-rich-text__style-opt--h2{font-size:1.45rem;font-weight:700}.kpt-rich-text__style-opt--h3{font-size:1.25rem;font-weight:600}.kpt-rich-text__style-opt--h4{font-size:1.1rem;font-weight:600}.kpt-rich-text__style-opt--h5{font-size:1rem;font-weight:600}.kpt-rich-text__style-opt--h6{font-size:.85rem;font-weight:600;text-transform:uppercase;letter-spacing:.03em}.kpt-rich-text__palette{padding:var(--kpt-space-3, .75rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3)}.kpt-rich-text__swatches{display:grid;grid-template-columns:repeat(7,1fr);gap:4px}.kpt-rich-text__swatch{width:1.4rem;height:1.4rem;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-sm, .25rem);cursor:pointer}.kpt-rich-text__swatch:hover{transform:scale(1.1)}.kpt-rich-text__picker{display:flex;align-items:center;justify-content:space-between;gap:var(--kpt-space-2, .5rem);margin-top:var(--kpt-space-2, .5rem);font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface-muted)}.kpt-rich-text__picker input[type=color]{width:2rem;height:1.6rem;padding:0;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-sm, .25rem);background:none;cursor:pointer}.kpt-rt-grid-pop{padding:var(--kpt-space-2, .5rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3)}.kpt-rt-grid{display:flex;flex-direction:column;gap:3px}.kpt-rt-grid__row{display:flex;gap:3px}.kpt-rt-grid__cell{width:1rem;height:1rem;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:2px;cursor:pointer}.kpt-rt-grid__cell.is-on{background:var(--kpt-color-primary);border-color:var(--kpt-color-primary)}.kpt-rt-grid__label{margin-top:var(--kpt-space-2, .5rem);text-align:center;font-size:var(--kpt-font-size-xs, .75rem);color:var(--kpt-color-on-surface-muted)}.kpt-rt-menu{min-width:12rem;padding:.25rem;background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3);font-size:var(--kpt-font-size-sm, .875rem)}.kpt-rt-menu__group{padding:.3rem .6rem .15rem;font-size:var(--kpt-font-size-xs, .75rem);font-weight:var(--kpt-font-weight-semibold, 600);text-transform:uppercase;letter-spacing:.03em;color:var(--kpt-color-on-surface-muted)}.kpt-rt-menu__item{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);width:100%;padding:.4rem .6rem;border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font:inherit;text-align:start;cursor:pointer}.kpt-rt-menu__item:hover{background:var(--kpt-color-muted)}.kpt-rt-menu__item kpt-icon{color:var(--kpt-color-on-surface-muted)}.kpt-rt-menu__item--danger{color:var(--kpt-color-danger)}.kpt-rt-menu__item--danger kpt-icon{color:var(--kpt-color-danger)}.kpt-rt-menu__item.is-disabled{opacity:.4;pointer-events:none}.kpt-rt-menu__sep{height:1px;margin:.25rem 0;background:var(--kpt-color-border)}.kpt-rt-border{display:flex;flex-direction:column;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-3, .75rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3)}.kpt-rt-border__seg{display:flex;gap:2px;padding:2px;background:var(--kpt-color-surface-variant);border-radius:var(--kpt-radius-md, .5rem)}.kpt-rt-border__seg button{flex:1;border:0;background:none;padding:.25rem .5rem;border-radius:var(--kpt-radius-sm, .25rem);color:var(--kpt-color-on-surface-muted);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-rt-border__seg button.is-active{background:var(--kpt-color-surface-raised);color:var(--kpt-color-on-surface);font-weight:var(--kpt-font-weight-medium, 500);box-shadow:var(--kpt-elevation-1)}.kpt-rt-border__widths{display:flex;gap:.25rem}.kpt-rt-border__widths button{flex:1;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);background:none;padding:.25rem .3rem;border-radius:var(--kpt-radius-sm, .25rem);color:var(--kpt-color-on-surface);font:inherit;font-size:var(--kpt-font-size-xs, .75rem);cursor:pointer}.kpt-rt-border__widths button:hover{background:var(--kpt-color-muted)}}\n"] }]
1474
3022
  }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], toolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolbar", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], editor: [{ type: i0.ViewChild, args: ['editor', { isSignal: true }] }] } });
1475
3023
 
1476
3024
  /**
1477
3025
  * Suwak wartości (slider) na Signal Forms.
3026
+ * W trybie `range` udostępnia dwa uchwyty, a wartość jest parą `[min, max]`.
1478
3027
  *
1479
3028
  * @example
1480
3029
  * <kpt-slider [formField]="f.volume" [min]="0" [max]="100" [step]="5" showValue />
3030
+ * <kpt-slider range [(value)]="zakres" [min]="0" [max]="100" showValue />
1481
3031
  */
1482
3032
  class KptSlider {
1483
3033
  value = model(0, /* @ts-ignore */
1484
3034
  ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
1485
- // Typ zgodny z FormValueControl (FormField może zsync-ować z walidatorami min/max).
3035
+ /** Tryb zakresu: dwa uchwyty; wartość jako para `[min, max]`. */
3036
+ range = input(false, { ...(ngDevMode ? { debugName: "range" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
3037
+ // Typ zgodny z FormValueControl<KptSliderValue> (FormField może zsync-ować walidatory min/max).
3038
+ // W praktyce zawsze liczby — do matematyki/szablonu używamy skalarnych `minN`/`maxN`.
1486
3039
  min = input(0, /* @ts-ignore */
1487
3040
  ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
1488
3041
  max = input(100, /* @ts-ignore */
@@ -1494,52 +3047,156 @@ class KptSlider {
1494
3047
  invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1495
3048
  touched = input(false, { ...(ngDevMode ? { debugName: "touched" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1496
3049
  touch = output();
1497
- percent = computed(() => {
1498
- const mn = this.min() ?? 0;
1499
- const mx = this.max() ?? 100;
1500
- const range = mx - mn;
1501
- return range <= 0 ? 0 : ((this.value() - mn) / range) * 100;
3050
+ // Skalarne granice do szablonu i obliczeń (min/max są typowane szeroko dla FormValueControl).
3051
+ toNum(v, fallback) {
3052
+ return typeof v === 'number' ? v : fallback;
3053
+ }
3054
+ minN = computed(() => this.toNum(this.min(), 0), /* @ts-ignore */
3055
+ ...(ngDevMode ? [{ debugName: "minN" }] : /* istanbul ignore next */ []));
3056
+ maxN = computed(() => this.toNum(this.max(), 100), /* @ts-ignore */
3057
+ ...(ngDevMode ? [{ debugName: "maxN" }] : /* istanbul ignore next */ []));
3058
+ /** Bieżąca para `[low, high]` — również dla trybu pojedynczego (low = min). */
3059
+ pair = computed(() => {
3060
+ const v = this.value();
3061
+ if (Array.isArray(v))
3062
+ return [v[0], v[1]];
3063
+ return [this.minN(), v];
1502
3064
  }, /* @ts-ignore */
1503
- ...(ngDevMode ? [{ debugName: "percent" }] : /* istanbul ignore next */ []));
3065
+ ...(ngDevMode ? [{ debugName: "pair" }] : /* istanbul ignore next */ []));
3066
+ single = computed(() => {
3067
+ const v = this.value();
3068
+ return Array.isArray(v) ? v[1] : v;
3069
+ }, /* @ts-ignore */
3070
+ ...(ngDevMode ? [{ debugName: "single" }] : /* istanbul ignore next */ []));
3071
+ low = computed(() => this.pair()[0], /* @ts-ignore */
3072
+ ...(ngDevMode ? [{ debugName: "low" }] : /* istanbul ignore next */ []));
3073
+ high = computed(() => this.pair()[1], /* @ts-ignore */
3074
+ ...(ngDevMode ? [{ debugName: "high" }] : /* istanbul ignore next */ []));
3075
+ setLow(v) {
3076
+ const [, hi] = this.pair();
3077
+ this.value.set([Math.min(v, hi), hi]);
3078
+ }
3079
+ setHigh(v) {
3080
+ const [lo] = this.pair();
3081
+ this.value.set([lo, Math.max(v, lo)]);
3082
+ }
3083
+ pct(val) {
3084
+ const mn = this.minN();
3085
+ const mx = this.maxN();
3086
+ const range = mx - mn;
3087
+ return range <= 0 ? 0 : ((val - mn) / range) * 100;
3088
+ }
3089
+ lowPct = computed(() => this.pct(this.low()), /* @ts-ignore */
3090
+ ...(ngDevMode ? [{ debugName: "lowPct" }] : /* istanbul ignore next */ []));
3091
+ highPct = computed(() => this.pct(this.high()), /* @ts-ignore */
3092
+ ...(ngDevMode ? [{ debugName: "highPct" }] : /* istanbul ignore next */ []));
1504
3093
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptSlider, deps: [], target: i0.ɵɵFactoryTarget.Component });
1505
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptSlider, isStandalone: true, selector: "kpt-slider", 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 }, showValue: { classPropertyName: "showValue", publicName: "showValue", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { classAttribute: "kpt-slider-host" }, ngImport: i0, template: `
1506
- <input
1507
- class="kpt-slider__input"
1508
- type="range"
1509
- [min]="min()"
1510
- [max]="max()"
1511
- [step]="step()"
1512
- [value]="value()"
1513
- [disabled]="disabled()"
1514
- [style.--_pct.%]="percent()"
1515
- (input)="value.set(+$any($event.target).value)"
1516
- (change)="touch.emit()"
1517
- />
1518
- @if (showValue()) {
1519
- <span class="kpt-slider__value">{{ value() }}</span>
3094
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptSlider, isStandalone: true, selector: "kpt-slider", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, range: { classPropertyName: "range", publicName: "range", 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 }, showValue: { classPropertyName: "showValue", publicName: "showValue", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { classAttribute: "kpt-slider-host" }, ngImport: i0, template: `
3095
+ @if (range()) {
3096
+ <div class="kpt-slider__range">
3097
+ <div class="kpt-slider__rail"></div>
3098
+ <div class="kpt-slider__fill" [style.left.%]="lowPct()" [style.right.%]="100 - highPct()"></div>
3099
+ <input
3100
+ class="kpt-slider__thumb kpt-slider__thumb--low"
3101
+ type="range"
3102
+ [min]="minN()"
3103
+ [max]="maxN()"
3104
+ [step]="step()"
3105
+ [value]="low()"
3106
+ [disabled]="disabled()"
3107
+ [attr.aria-label]="'Minimum'"
3108
+ (input)="setLow(+$any($event.target).value)"
3109
+ (change)="touch.emit()"
3110
+ />
3111
+ <input
3112
+ class="kpt-slider__thumb kpt-slider__thumb--high"
3113
+ type="range"
3114
+ [min]="minN()"
3115
+ [max]="maxN()"
3116
+ [step]="step()"
3117
+ [value]="high()"
3118
+ [disabled]="disabled()"
3119
+ [attr.aria-label]="'Maksimum'"
3120
+ (input)="setHigh(+$any($event.target).value)"
3121
+ (change)="touch.emit()"
3122
+ />
3123
+ </div>
3124
+ @if (showValue()) {
3125
+ <span class="kpt-slider__value">{{ low() }}–{{ high() }}</span>
3126
+ }
3127
+ } @else {
3128
+ <input
3129
+ class="kpt-slider__input"
3130
+ type="range"
3131
+ [min]="minN()"
3132
+ [max]="maxN()"
3133
+ [step]="step()"
3134
+ [value]="single()"
3135
+ [disabled]="disabled()"
3136
+ [style.--_pct.%]="highPct()"
3137
+ (input)="value.set(+$any($event.target).value)"
3138
+ (change)="touch.emit()"
3139
+ />
3140
+ @if (showValue()) {
3141
+ <span class="kpt-slider__value">{{ single() }}</span>
3142
+ }
1520
3143
  }
1521
- `, isInline: true, styles: ["@layer kpt.components{.kpt-slider-host{display:flex;align-items:center;gap:var(--kpt-space-3, .75rem)}.kpt-slider__input{--_pct: 0%;flex:1;height:1.25rem;appearance:none;background:none;cursor:pointer}.kpt-slider__input::-webkit-slider-runnable-track{height:.4rem;border-radius:var(--kpt-radius-full, 9999px);background:linear-gradient(to right,var(--kpt-color-primary) var(--_pct),var(--kpt-color-surface-variant) var(--_pct))}.kpt-slider__input::-moz-range-track{height:.4rem;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-surface-variant)}.kpt-slider__input::-moz-range-progress{height:.4rem;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-primary)}.kpt-slider__input::-webkit-slider-thumb{appearance:none;width:1.1rem;height:1.1rem;margin-top:-.35rem;border-radius:50%;background:var(--kpt-color-primary);box-shadow:var(--kpt-elevation-1)}.kpt-slider__input::-moz-range-thumb{width:1.1rem;height:1.1rem;border:0;border-radius:50%;background:var(--kpt-color-primary);box-shadow:var(--kpt-elevation-1)}.kpt-slider__input:focus-visible{outline:none}.kpt-slider__input:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 4px color-mix(in oklch,var(--kpt-color-focus-ring) 30%,transparent)}.kpt-slider__input:focus-visible::-moz-range-thumb{box-shadow:0 0 0 4px color-mix(in oklch,var(--kpt-color-focus-ring) 30%,transparent)}.kpt-slider__input:disabled{opacity:.5;cursor:not-allowed}.kpt-slider__value{min-width:2.5rem;text-align:end;font-size:var(--kpt-font-size-sm, .875rem);font-variant-numeric:tabular-nums;color:var(--kpt-color-on-surface)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3144
+ `, isInline: true, styles: ["@layer kpt.components{.kpt-slider-host{display:flex;align-items:center;gap:var(--kpt-space-3, .75rem)}.kpt-slider__input{--_pct: 0%;flex:1;height:1.25rem;appearance:none;background:none;cursor:pointer}.kpt-slider__input::-webkit-slider-runnable-track{height:.4rem;border-radius:var(--kpt-radius-full, 9999px);background:linear-gradient(to right,var(--kpt-color-primary) var(--_pct),var(--kpt-color-surface-variant) var(--_pct))}.kpt-slider__input::-moz-range-track{height:.4rem;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-surface-variant)}.kpt-slider__input::-moz-range-progress{height:.4rem;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-primary)}.kpt-slider__input::-webkit-slider-thumb{appearance:none;width:1.1rem;height:1.1rem;margin-top:-.35rem;border-radius:50%;background:var(--kpt-color-primary);box-shadow:var(--kpt-elevation-1)}.kpt-slider__input::-moz-range-thumb{width:1.1rem;height:1.1rem;border:0;border-radius:50%;background:var(--kpt-color-primary);box-shadow:var(--kpt-elevation-1)}.kpt-slider__input:focus-visible{outline:none}.kpt-slider__input:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 4px color-mix(in oklch,var(--kpt-color-focus-ring) 30%,transparent)}.kpt-slider__input:focus-visible::-moz-range-thumb{box-shadow:0 0 0 4px color-mix(in oklch,var(--kpt-color-focus-ring) 30%,transparent)}.kpt-slider__input:disabled{opacity:.5;cursor:not-allowed}.kpt-slider__value{min-width:2.5rem;text-align:end;font-size:var(--kpt-font-size-sm, .875rem);font-variant-numeric:tabular-nums;color:var(--kpt-color-on-surface)}.kpt-slider__range{position:relative;flex:1;height:1.25rem;display:flex;align-items:center}.kpt-slider__rail{position:absolute;inset-inline:0;height:.4rem;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-surface-variant)}.kpt-slider__fill{position:absolute;height:.4rem;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-primary)}.kpt-slider__thumb{position:absolute;inset-inline:0;width:100%;height:1.25rem;margin:0;appearance:none;background:none;pointer-events:none}.kpt-slider__thumb::-webkit-slider-runnable-track{height:.4rem;background:none}.kpt-slider__thumb::-moz-range-track{height:.4rem;background:none}.kpt-slider__thumb::-webkit-slider-thumb{pointer-events:auto;appearance:none;width:1.1rem;height:1.1rem;margin-top:-.35rem;border-radius:50%;background:var(--kpt-color-primary);box-shadow:var(--kpt-elevation-1);cursor:pointer}.kpt-slider__thumb::-moz-range-thumb{pointer-events:auto;width:1.1rem;height:1.1rem;border:0;border-radius:50%;background:var(--kpt-color-primary);box-shadow:var(--kpt-elevation-1);cursor:pointer}.kpt-slider__thumb:focus-visible{outline:none}.kpt-slider__thumb:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 4px color-mix(in oklch,var(--kpt-color-focus-ring) 30%,transparent)}.kpt-slider__thumb:focus-visible::-moz-range-thumb{box-shadow:0 0 0 4px color-mix(in oklch,var(--kpt-color-focus-ring) 30%,transparent)}.kpt-slider__thumb--high{z-index:1}.kpt-slider__thumb:disabled{opacity:.5;cursor:not-allowed}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1522
3145
  }
1523
3146
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptSlider, decorators: [{
1524
3147
  type: Component,
1525
3148
  args: [{ selector: 'kpt-slider', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: `
1526
- <input
1527
- class="kpt-slider__input"
1528
- type="range"
1529
- [min]="min()"
1530
- [max]="max()"
1531
- [step]="step()"
1532
- [value]="value()"
1533
- [disabled]="disabled()"
1534
- [style.--_pct.%]="percent()"
1535
- (input)="value.set(+$any($event.target).value)"
1536
- (change)="touch.emit()"
1537
- />
1538
- @if (showValue()) {
1539
- <span class="kpt-slider__value">{{ value() }}</span>
3149
+ @if (range()) {
3150
+ <div class="kpt-slider__range">
3151
+ <div class="kpt-slider__rail"></div>
3152
+ <div class="kpt-slider__fill" [style.left.%]="lowPct()" [style.right.%]="100 - highPct()"></div>
3153
+ <input
3154
+ class="kpt-slider__thumb kpt-slider__thumb--low"
3155
+ type="range"
3156
+ [min]="minN()"
3157
+ [max]="maxN()"
3158
+ [step]="step()"
3159
+ [value]="low()"
3160
+ [disabled]="disabled()"
3161
+ [attr.aria-label]="'Minimum'"
3162
+ (input)="setLow(+$any($event.target).value)"
3163
+ (change)="touch.emit()"
3164
+ />
3165
+ <input
3166
+ class="kpt-slider__thumb kpt-slider__thumb--high"
3167
+ type="range"
3168
+ [min]="minN()"
3169
+ [max]="maxN()"
3170
+ [step]="step()"
3171
+ [value]="high()"
3172
+ [disabled]="disabled()"
3173
+ [attr.aria-label]="'Maksimum'"
3174
+ (input)="setHigh(+$any($event.target).value)"
3175
+ (change)="touch.emit()"
3176
+ />
3177
+ </div>
3178
+ @if (showValue()) {
3179
+ <span class="kpt-slider__value">{{ low() }}–{{ high() }}</span>
3180
+ }
3181
+ } @else {
3182
+ <input
3183
+ class="kpt-slider__input"
3184
+ type="range"
3185
+ [min]="minN()"
3186
+ [max]="maxN()"
3187
+ [step]="step()"
3188
+ [value]="single()"
3189
+ [disabled]="disabled()"
3190
+ [style.--_pct.%]="highPct()"
3191
+ (input)="value.set(+$any($event.target).value)"
3192
+ (change)="touch.emit()"
3193
+ />
3194
+ @if (showValue()) {
3195
+ <span class="kpt-slider__value">{{ single() }}</span>
3196
+ }
1540
3197
  }
1541
- `, host: { class: 'kpt-slider-host' }, styles: ["@layer kpt.components{.kpt-slider-host{display:flex;align-items:center;gap:var(--kpt-space-3, .75rem)}.kpt-slider__input{--_pct: 0%;flex:1;height:1.25rem;appearance:none;background:none;cursor:pointer}.kpt-slider__input::-webkit-slider-runnable-track{height:.4rem;border-radius:var(--kpt-radius-full, 9999px);background:linear-gradient(to right,var(--kpt-color-primary) var(--_pct),var(--kpt-color-surface-variant) var(--_pct))}.kpt-slider__input::-moz-range-track{height:.4rem;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-surface-variant)}.kpt-slider__input::-moz-range-progress{height:.4rem;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-primary)}.kpt-slider__input::-webkit-slider-thumb{appearance:none;width:1.1rem;height:1.1rem;margin-top:-.35rem;border-radius:50%;background:var(--kpt-color-primary);box-shadow:var(--kpt-elevation-1)}.kpt-slider__input::-moz-range-thumb{width:1.1rem;height:1.1rem;border:0;border-radius:50%;background:var(--kpt-color-primary);box-shadow:var(--kpt-elevation-1)}.kpt-slider__input:focus-visible{outline:none}.kpt-slider__input:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 4px color-mix(in oklch,var(--kpt-color-focus-ring) 30%,transparent)}.kpt-slider__input:focus-visible::-moz-range-thumb{box-shadow:0 0 0 4px color-mix(in oklch,var(--kpt-color-focus-ring) 30%,transparent)}.kpt-slider__input:disabled{opacity:.5;cursor:not-allowed}.kpt-slider__value{min-width:2.5rem;text-align:end;font-size:var(--kpt-font-size-sm, .875rem);font-variant-numeric:tabular-nums;color:var(--kpt-color-on-surface)}}\n"] }]
1542
- }], propDecorators: { 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 }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }] } });
3198
+ `, host: { class: 'kpt-slider-host' }, styles: ["@layer kpt.components{.kpt-slider-host{display:flex;align-items:center;gap:var(--kpt-space-3, .75rem)}.kpt-slider__input{--_pct: 0%;flex:1;height:1.25rem;appearance:none;background:none;cursor:pointer}.kpt-slider__input::-webkit-slider-runnable-track{height:.4rem;border-radius:var(--kpt-radius-full, 9999px);background:linear-gradient(to right,var(--kpt-color-primary) var(--_pct),var(--kpt-color-surface-variant) var(--_pct))}.kpt-slider__input::-moz-range-track{height:.4rem;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-surface-variant)}.kpt-slider__input::-moz-range-progress{height:.4rem;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-primary)}.kpt-slider__input::-webkit-slider-thumb{appearance:none;width:1.1rem;height:1.1rem;margin-top:-.35rem;border-radius:50%;background:var(--kpt-color-primary);box-shadow:var(--kpt-elevation-1)}.kpt-slider__input::-moz-range-thumb{width:1.1rem;height:1.1rem;border:0;border-radius:50%;background:var(--kpt-color-primary);box-shadow:var(--kpt-elevation-1)}.kpt-slider__input:focus-visible{outline:none}.kpt-slider__input:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 4px color-mix(in oklch,var(--kpt-color-focus-ring) 30%,transparent)}.kpt-slider__input:focus-visible::-moz-range-thumb{box-shadow:0 0 0 4px color-mix(in oklch,var(--kpt-color-focus-ring) 30%,transparent)}.kpt-slider__input:disabled{opacity:.5;cursor:not-allowed}.kpt-slider__value{min-width:2.5rem;text-align:end;font-size:var(--kpt-font-size-sm, .875rem);font-variant-numeric:tabular-nums;color:var(--kpt-color-on-surface)}.kpt-slider__range{position:relative;flex:1;height:1.25rem;display:flex;align-items:center}.kpt-slider__rail{position:absolute;inset-inline:0;height:.4rem;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-surface-variant)}.kpt-slider__fill{position:absolute;height:.4rem;border-radius:var(--kpt-radius-full, 9999px);background:var(--kpt-color-primary)}.kpt-slider__thumb{position:absolute;inset-inline:0;width:100%;height:1.25rem;margin:0;appearance:none;background:none;pointer-events:none}.kpt-slider__thumb::-webkit-slider-runnable-track{height:.4rem;background:none}.kpt-slider__thumb::-moz-range-track{height:.4rem;background:none}.kpt-slider__thumb::-webkit-slider-thumb{pointer-events:auto;appearance:none;width:1.1rem;height:1.1rem;margin-top:-.35rem;border-radius:50%;background:var(--kpt-color-primary);box-shadow:var(--kpt-elevation-1);cursor:pointer}.kpt-slider__thumb::-moz-range-thumb{pointer-events:auto;width:1.1rem;height:1.1rem;border:0;border-radius:50%;background:var(--kpt-color-primary);box-shadow:var(--kpt-elevation-1);cursor:pointer}.kpt-slider__thumb:focus-visible{outline:none}.kpt-slider__thumb:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 4px color-mix(in oklch,var(--kpt-color-focus-ring) 30%,transparent)}.kpt-slider__thumb:focus-visible::-moz-range-thumb{box-shadow:0 0 0 4px color-mix(in oklch,var(--kpt-color-focus-ring) 30%,transparent)}.kpt-slider__thumb--high{z-index:1}.kpt-slider__thumb:disabled{opacity:.5;cursor:not-allowed}}\n"] }]
3199
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], range: [{ type: i0.Input, args: [{ isSignal: true, alias: "range", required: false }] }], 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 }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }] } });
1543
3200
 
1544
3201
  /**
1545
3202
  * Ocena gwiazdkami (rating) na Signal Forms.
@@ -1822,17 +3479,16 @@ const MONTHS = [
1822
3479
  ];
1823
3480
  const pad = (n) => String(n).padStart(2, '0');
1824
3481
  const toIso = (d) => `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
1825
- const fmt = (iso) => {
1826
- const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(iso);
1827
- return m ? `${m[3]}.${m[2]}.${m[1]}` : '';
1828
- };
1829
3482
  /**
1830
3483
  * Wybór zakresu dat z kalendarzem (CDK Overlay), Signal Forms.
1831
- * Wartość: `{ start: 'RRRR-MM-DD', end: 'RRRR-MM-DD' }`.
3484
+ * `mode`: 'date' (domyślnie), 'datetime' (data+godzina, tarcza zegara), 'time' (sama godzina).
3485
+ * Wartość: `{ start, end }` — daty 'RRRR-MM-DD', datetime 'RRRR-MM-DDTHH:mm', godziny 'HH:mm'.
1832
3486
  * Wymaga `import '@angular/cdk/overlay-prebuilt.css';`
1833
3487
  *
1834
3488
  * @example
1835
3489
  * <kpt-date-range [formField]="f.period" />
3490
+ * <kpt-date-range mode="datetime" [hourFormat]="12" [(value)]="span" />
3491
+ * <kpt-date-range mode="time" [(value)]="hours" />
1836
3492
  */
1837
3493
  class KptDateRange {
1838
3494
  value = model({ start: '', end: '' }, /* @ts-ignore */
@@ -1843,12 +3499,30 @@ class KptDateRange {
1843
3499
  touch = output();
1844
3500
  placeholder = input('Wybierz zakres', /* @ts-ignore */
1845
3501
  ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
3502
+ displayFormat = input('pl', /* @ts-ignore */
3503
+ ...(ngDevMode ? [{ debugName: "displayFormat" }] : /* istanbul ignore next */ []));
3504
+ mode = input('date', /* @ts-ignore */
3505
+ ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
3506
+ hourFormat = input(24, { ...(ngDevMode ? { debugName: "hourFormat" } : /* istanbul ignore next */ {}), transform: numberAttribute });
3507
+ minuteStep = input(1, { ...(ngDevMode ? { debugName: "minuteStep" } : /* istanbul ignore next */ {}), transform: numberAttribute });
1846
3508
  weekdays = WEEKDAYS;
1847
3509
  open = signal(false, /* @ts-ignore */
1848
3510
  ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
1849
3511
  today = new Date();
1850
3512
  view = signal({ y: this.today.getFullYear(), m: this.today.getMonth() }, /* @ts-ignore */
1851
3513
  ...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
3514
+ // ── Bufory czasu (tryby datetime/time) ──
3515
+ startTime = signal('', /* @ts-ignore */
3516
+ ...(ngDevMode ? [{ debugName: "startTime" }] : /* istanbul ignore next */ []));
3517
+ endTime = signal('', /* @ts-ignore */
3518
+ ...(ngDevMode ? [{ debugName: "endTime" }] : /* istanbul ignore next */ []));
3519
+ timeEnd = signal('start', /* @ts-ignore */
3520
+ ...(ngDevMode ? [{ debugName: "timeEnd" }] : /* istanbul ignore next */ [])); // który koniec edytuje tarcza
3521
+ // Daty zakresu (część kalendarzowa dla datetime — bez czasu)
3522
+ startDate = signal('', /* @ts-ignore */
3523
+ ...(ngDevMode ? [{ debugName: "startDate" }] : /* istanbul ignore next */ []));
3524
+ endDate = signal('', /* @ts-ignore */
3525
+ ...(ngDevMode ? [{ debugName: "endDate" }] : /* istanbul ignore next */ []));
1852
3526
  positions = [
1853
3527
  { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
1854
3528
  { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
@@ -1858,16 +3532,53 @@ class KptDateRange {
1858
3532
  return `${MONTHS[m]} ${y}`;
1859
3533
  }, /* @ts-ignore */
1860
3534
  ...(ngDevMode ? [{ debugName: "monthLabel" }] : /* istanbul ignore next */ []));
3535
+ datePart(v) {
3536
+ return v ? v.slice(0, 10) : '';
3537
+ }
3538
+ timePart(v) {
3539
+ const m = /[T ](\d{2}:\d{2})$/.exec(v);
3540
+ return m ? m[1] : '';
3541
+ }
3542
+ fmtDate(iso) {
3543
+ const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(iso);
3544
+ if (!m)
3545
+ return '';
3546
+ return this.displayFormat() === 'iso' ? `${m[1]}-${m[2]}-${m[3]}` : `${m[3]}.${m[2]}.${m[1]}`;
3547
+ }
3548
+ fmtTime(hhmm) {
3549
+ const m = /^(\d{2}):(\d{2})$/.exec(hhmm);
3550
+ if (!m)
3551
+ return '';
3552
+ if (this.hourFormat() === 12) {
3553
+ const h = +m[1];
3554
+ const h12 = h % 12 === 0 ? 12 : h % 12;
3555
+ return `${h12}:${m[2]} ${h < 12 ? 'AM' : 'PM'}`;
3556
+ }
3557
+ return hhmm;
3558
+ }
1861
3559
  display = computed(() => {
1862
3560
  const { start, end } = this.value();
1863
3561
  if (!start)
1864
3562
  return '';
1865
- return end ? `${fmt(start)} – ${fmt(end)}` : `${fmt(start)} – …`;
3563
+ const mode = this.mode();
3564
+ if (mode === 'time') {
3565
+ return end ? `${this.fmtTime(start)} – ${this.fmtTime(end)}` : `${this.fmtTime(start)} – …`;
3566
+ }
3567
+ if (mode === 'datetime') {
3568
+ const one = (v) => {
3569
+ const d = this.fmtDate(this.datePart(v));
3570
+ const t = this.fmtTime(this.timePart(v));
3571
+ return t ? `${d} ${t}` : d;
3572
+ };
3573
+ return end ? `${one(start)} – ${one(end)}` : `${one(start)} – …`;
3574
+ }
3575
+ return end ? `${this.fmtDate(start)} – ${this.fmtDate(end)}` : `${this.fmtDate(start)} – …`;
1866
3576
  }, /* @ts-ignore */
1867
3577
  ...(ngDevMode ? [{ debugName: "display" }] : /* istanbul ignore next */ []));
1868
3578
  weeks = computed(() => {
1869
3579
  const { y, m } = this.view();
1870
- const { start, end } = this.value();
3580
+ const start = this.mode() === 'datetime' ? this.startDate() : this.value().start;
3581
+ const end = this.mode() === 'datetime' ? this.endDate() : this.value().end;
1871
3582
  const first = new Date(y, m, 1);
1872
3583
  const startOffset = (first.getDay() + 6) % 7;
1873
3584
  const gridStart = new Date(y, m, 1 - startOffset);
@@ -1896,9 +3607,21 @@ class KptDateRange {
1896
3607
  if (this.disabled())
1897
3608
  return;
1898
3609
  if (!this.open()) {
1899
- const start = this.value().start;
1900
- const d = start ? new Date(start) : this.today;
3610
+ const { start, end } = this.value();
3611
+ const base = this.datePart(start) || toIso(this.today);
3612
+ const d = new Date(base);
1901
3613
  this.view.set({ y: d.getFullYear(), m: d.getMonth() });
3614
+ if (this.mode() === 'datetime') {
3615
+ this.startDate.set(this.datePart(start));
3616
+ this.endDate.set(this.datePart(end));
3617
+ this.startTime.set(this.timePart(start) || '00:00');
3618
+ this.endTime.set(this.timePart(end) || '00:00');
3619
+ }
3620
+ else if (this.mode() === 'time') {
3621
+ this.startTime.set(/^\d{2}:\d{2}$/.test(start) ? start : '00:00');
3622
+ this.endTime.set(/^\d{2}:\d{2}$/.test(end) ? end : '00:00');
3623
+ }
3624
+ this.timeEnd.set('start');
1902
3625
  }
1903
3626
  this.open.update((o) => !o);
1904
3627
  }
@@ -1909,6 +3632,22 @@ class KptDateRange {
1909
3632
  this.touch.emit();
1910
3633
  }
1911
3634
  selectDay(cell) {
3635
+ if (this.mode() === 'datetime') {
3636
+ const start = this.startDate();
3637
+ const end = this.endDate();
3638
+ if (!start || (start && end)) {
3639
+ this.startDate.set(cell.iso);
3640
+ this.endDate.set('');
3641
+ }
3642
+ else if (cell.iso < start) {
3643
+ this.endDate.set(start);
3644
+ this.startDate.set(cell.iso);
3645
+ }
3646
+ else {
3647
+ this.endDate.set(cell.iso);
3648
+ }
3649
+ return; // czas do wyboru → zamknięcie przez „Gotowe"
3650
+ }
1912
3651
  const { start, end } = this.value();
1913
3652
  if (!start || (start && end)) {
1914
3653
  this.value.set({ start: cell.iso, end: '' });
@@ -1921,6 +3660,26 @@ class KptDateRange {
1921
3660
  this.close();
1922
3661
  }
1923
3662
  }
3663
+ commit() {
3664
+ if (this.mode() === 'time') {
3665
+ const s = this.startTime() || '00:00';
3666
+ const e = this.endTime() || '00:00';
3667
+ // Normalizacja kolejności (start ≤ end).
3668
+ this.value.set(s <= e ? { start: s, end: e } : { start: e, end: s });
3669
+ }
3670
+ else if (this.mode() === 'datetime') {
3671
+ const sd = this.startDate();
3672
+ const ed = this.endDate() || sd;
3673
+ if (!sd) {
3674
+ this.close();
3675
+ return;
3676
+ }
3677
+ const start = `${sd}T${this.startTime() || '00:00'}`;
3678
+ const end = `${ed}T${this.endTime() || '00:00'}`;
3679
+ this.value.set(start <= end ? { start, end } : { start: end, end: start });
3680
+ }
3681
+ this.close();
3682
+ }
1924
3683
  prevMonth() {
1925
3684
  this.view.update(({ y, m }) => (m === 0 ? { y: y - 1, m: 11 } : { y, m: m - 1 }));
1926
3685
  }
@@ -1930,14 +3689,16 @@ class KptDateRange {
1930
3689
  clear(event) {
1931
3690
  event.stopPropagation();
1932
3691
  this.value.set({ start: '', end: '' });
3692
+ this.startDate.set('');
3693
+ this.endDate.set('');
1933
3694
  }
1934
3695
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptDateRange, deps: [], target: i0.ɵɵFactoryTarget.Component });
1935
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptDateRange, isStandalone: true, selector: "kpt-date-range", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { classAttribute: "kpt-date-range-host" }, ngImport: i0, template: "<div\n class=\"kpt-date-range\"\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n role=\"button\"\n tabindex=\"0\"\n [class.kpt-date-range--open]=\"open()\"\n [class.kpt-date-range--disabled]=\"disabled()\"\n [class.kpt-date-range--invalid]=\"invalid()\"\n (click)=\"toggleOpen()\"\n (keydown.enter)=\"toggleOpen()\"\n (blur)=\"touch.emit()\"\n>\n @if (display()) {\n <span class=\"kpt-date-range__value\">{{ display() }}</span>\n } @else {\n <span class=\"kpt-date-range__placeholder\">{{ placeholder() }}</span>\n }\n <span class=\"kpt-date-range__spacer\"></span>\n @if (display()) {\n <button type=\"button\" class=\"kpt-date-range__clear\" (click)=\"clear($event)\" aria-label=\"Wyczy\u015B\u0107\"><kpt-icon name=\"x\" /></button>\n }\n <kpt-icon class=\"kpt-date-range__icon\" name=\"calendar\" />\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\"\n>\n <div class=\"kpt-calendar\" (keydown.escape)=\"close()\">\n <div class=\"kpt-calendar__header\">\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"prevMonth()\" aria-label=\"Poprzedni miesi\u0105c\"><kpt-icon name=\"chevron-left\" /></button>\n <span class=\"kpt-calendar__title\">{{ monthLabel() }}</span>\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"nextMonth()\" aria-label=\"Nast\u0119pny miesi\u0105c\"><kpt-icon name=\"chevron-right\" /></button>\n </div>\n <div class=\"kpt-calendar__weekdays\">\n @for (wd of weekdays; track wd) {\n <span class=\"kpt-calendar__weekday\">{{ wd }}</span>\n }\n </div>\n <div class=\"kpt-calendar__grid\">\n @for (week of weeks(); track $index) {\n @for (cell of week; track cell.iso) {\n <button\n type=\"button\"\n class=\"kpt-calendar__day\"\n [class.kpt-calendar__day--muted]=\"!cell.inMonth\"\n [class.kpt-calendar__day--range]=\"cell.inRange\"\n [class.kpt-calendar__day--selected]=\"cell.isStart || cell.isEnd\"\n (click)=\"selectDay(cell)\"\n >{{ cell.day }}</button>\n }\n }\n </div>\n </div>\n</ng-template>\n", styles: ["@layer kpt.components{.kpt-date-range-host{display:block}.kpt-date-range{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);height:2.5rem;padding-inline:var(--kpt-space-3, .75rem);box-sizing:border-box;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-date-range:hover:not(.kpt-date-range--disabled){border-color:var(--kpt-form-field-border-hover)}.kpt-date-range:focus-visible,.kpt-date-range.kpt-date-range--open{outline:none;border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-date-range.kpt-date-range--invalid{border-color:var(--kpt-form-field-border-error)}.kpt-date-range.kpt-date-range--disabled{cursor:not-allowed;opacity:.6;background:var(--kpt-color-surface-variant)}.kpt-date-range__placeholder{color:var(--kpt-form-field-placeholder)}.kpt-date-range__spacer{flex:1}.kpt-date-range__icon{color:var(--kpt-color-on-surface-muted)}.kpt-date-range__clear{display:inline-flex;border:0;background:none;cursor:pointer;padding:0;color:var(--kpt-color-on-surface-muted)}.kpt-date-range__clear:hover{color:var(--kpt-color-on-surface)}.kpt-calendar{width:17rem;padding:var(--kpt-space-3, .75rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3);color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem)}.kpt-calendar__header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--kpt-space-2, .5rem)}.kpt-calendar__title{font-weight:var(--kpt-font-weight-semibold, 600);text-transform:capitalize}.kpt-calendar__nav{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:var(--kpt-radius-md, .5rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer}.kpt-calendar__nav:hover{background:var(--kpt-color-muted)}.kpt-calendar__weekdays,.kpt-calendar__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}.kpt-calendar__weekday{text-align:center;font-size:var(--kpt-font-size-xs, .75rem);color:var(--kpt-color-on-surface-muted);padding:.25rem 0}.kpt-calendar__day{aspect-ratio:1;border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer;font:inherit}.kpt-calendar__day:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-calendar__day--muted{color:var(--kpt-color-on-surface-muted);opacity:.5}.kpt-calendar__day--range{background:color-mix(in oklch,var(--kpt-color-primary) 14%,transparent);border-radius:0}.kpt-calendar__day--selected{background:var(--kpt-color-primary)!important;color:var(--kpt-color-on-primary)}}\n"], dependencies: [{ kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3696
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptDateRange, isStandalone: true, selector: "kpt-date-range", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, displayFormat: { classPropertyName: "displayFormat", publicName: "displayFormat", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, hourFormat: { classPropertyName: "hourFormat", publicName: "hourFormat", isSignal: true, isRequired: false, transformFunction: null }, minuteStep: { classPropertyName: "minuteStep", publicName: "minuteStep", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { classAttribute: "kpt-date-range-host" }, ngImport: i0, template: "<div\n class=\"kpt-date-range\"\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n role=\"button\"\n tabindex=\"0\"\n [class.kpt-date-range--open]=\"open()\"\n [class.kpt-date-range--disabled]=\"disabled()\"\n [class.kpt-date-range--invalid]=\"invalid()\"\n (click)=\"toggleOpen()\"\n (keydown.enter)=\"toggleOpen()\"\n (blur)=\"touch.emit()\"\n>\n @if (display()) {\n <span class=\"kpt-date-range__value\">{{ display() }}</span>\n } @else {\n <span class=\"kpt-date-range__placeholder\">{{ placeholder() }}</span>\n }\n <span class=\"kpt-date-range__spacer\"></span>\n @if (display()) {\n <button type=\"button\" class=\"kpt-date-range__clear\" (click)=\"clear($event)\" aria-label=\"Wyczy\u015B\u0107\"><kpt-icon name=\"x\" /></button>\n }\n <kpt-icon class=\"kpt-date-range__icon\" name=\"calendar\" />\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\"\n>\n <div class=\"kpt-calendar\" [class.kpt-calendar--clock]=\"mode() === 'time'\" (keydown.escape)=\"close()\">\n @if (mode() === 'time') {\n <div class=\"kpt-range-tabs\">\n <button type=\"button\" [class.is-active]=\"timeEnd() === 'start'\" (click)=\"timeEnd.set('start')\">Od</button>\n <button type=\"button\" [class.is-active]=\"timeEnd() === 'end'\" (click)=\"timeEnd.set('end')\">Koniec</button>\n </div>\n @if (timeEnd() === 'start') {\n <kpt-clock [value]=\"startTime()\" (valueChange)=\"startTime.set($event)\" [hourFormat]=\"hourFormat()\" [minuteStep]=\"minuteStep()\" />\n } @else {\n <kpt-clock [value]=\"endTime()\" (valueChange)=\"endTime.set($event)\" [hourFormat]=\"hourFormat()\" [minuteStep]=\"minuteStep()\" />\n }\n <div class=\"kpt-calendar__footer\">\n <kpt-button size=\"sm\" (click)=\"commit()\">Gotowe</kpt-button>\n </div>\n } @else {\n <div class=\"kpt-calendar__header\">\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"prevMonth()\" aria-label=\"Poprzedni miesi\u0105c\"><kpt-icon name=\"chevron-left\" /></button>\n <span class=\"kpt-calendar__title\">{{ monthLabel() }}</span>\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"nextMonth()\" aria-label=\"Nast\u0119pny miesi\u0105c\"><kpt-icon name=\"chevron-right\" /></button>\n </div>\n <div class=\"kpt-calendar__weekdays\">\n @for (wd of weekdays; track wd) {\n <span class=\"kpt-calendar__weekday\">{{ wd }}</span>\n }\n </div>\n <div class=\"kpt-calendar__grid\">\n @for (week of weeks(); track $index) {\n @for (cell of week; track cell.iso) {\n <button\n type=\"button\"\n class=\"kpt-calendar__day\"\n [class.kpt-calendar__day--muted]=\"!cell.inMonth\"\n [class.kpt-calendar__day--range]=\"cell.inRange\"\n [class.kpt-calendar__day--selected]=\"cell.isStart || cell.isEnd\"\n (click)=\"selectDay(cell)\"\n >{{ cell.day }}</button>\n }\n }\n </div>\n\n @if (mode() === 'datetime') {\n <div class=\"kpt-range-tabs\">\n <button type=\"button\" [class.is-active]=\"timeEnd() === 'start'\" (click)=\"timeEnd.set('start')\">Od (godzina)</button>\n <button type=\"button\" [class.is-active]=\"timeEnd() === 'end'\" (click)=\"timeEnd.set('end')\">Koniec (godzina)</button>\n </div>\n @if (timeEnd() === 'start') {\n <kpt-clock [value]=\"startTime()\" (valueChange)=\"startTime.set($event)\" [hourFormat]=\"hourFormat()\" [minuteStep]=\"minuteStep()\" />\n } @else {\n <kpt-clock [value]=\"endTime()\" (valueChange)=\"endTime.set($event)\" [hourFormat]=\"hourFormat()\" [minuteStep]=\"minuteStep()\" />\n }\n <div class=\"kpt-calendar__footer\">\n <kpt-button size=\"sm\" (click)=\"commit()\">Gotowe</kpt-button>\n </div>\n }\n }\n </div>\n</ng-template>\n", styles: ["@layer kpt.components{.kpt-date-range-host{display:block}.kpt-date-range{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);height:2.5rem;padding-inline:var(--kpt-space-3, .75rem);box-sizing:border-box;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-date-range:hover:not(.kpt-date-range--disabled){border-color:var(--kpt-form-field-border-hover)}.kpt-date-range:focus-visible,.kpt-date-range.kpt-date-range--open{outline:none;border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-date-range.kpt-date-range--invalid{border-color:var(--kpt-form-field-border-error)}.kpt-date-range.kpt-date-range--disabled{cursor:not-allowed;opacity:.6;background:var(--kpt-color-surface-variant)}.kpt-date-range__placeholder{color:var(--kpt-form-field-placeholder)}.kpt-date-range__spacer{flex:1}.kpt-date-range__icon{color:var(--kpt-color-on-surface-muted)}.kpt-date-range__clear{display:inline-flex;border:0;background:none;cursor:pointer;padding:0;color:var(--kpt-color-on-surface-muted)}.kpt-date-range__clear:hover{color:var(--kpt-color-on-surface)}.kpt-calendar{width:17rem;padding:var(--kpt-space-3, .75rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3);color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem)}.kpt-calendar__header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--kpt-space-2, .5rem)}.kpt-calendar__title{font-weight:var(--kpt-font-weight-semibold, 600);text-transform:capitalize}.kpt-calendar__nav{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:var(--kpt-radius-md, .5rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer}.kpt-calendar__nav:hover{background:var(--kpt-color-muted)}.kpt-calendar__weekdays,.kpt-calendar__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}.kpt-calendar__weekday{text-align:center;font-size:var(--kpt-font-size-xs, .75rem);color:var(--kpt-color-on-surface-muted);padding:.25rem 0}.kpt-calendar__day{aspect-ratio:1;border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer;font:inherit}.kpt-calendar__day:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-calendar__day--muted{color:var(--kpt-color-on-surface-muted);opacity:.5}.kpt-calendar__day--range{background:color-mix(in oklch,var(--kpt-color-primary) 14%,transparent);border-radius:0}.kpt-calendar__day--selected{background:var(--kpt-color-primary)!important;color:var(--kpt-color-on-primary)}.kpt-calendar__footer{display:flex;justify-content:flex-end;margin-top:var(--kpt-space-3, .75rem)}.kpt-calendar--clock{width:16rem}.kpt-range-tabs{display:flex;gap:var(--kpt-space-1, .25rem);margin-block:var(--kpt-space-3, .75rem) var(--kpt-space-2, .5rem);padding:2px;background:var(--kpt-color-surface-variant);border-radius:var(--kpt-radius-md, .5rem)}.kpt-range-tabs button{flex:1;border:0;background:none;padding:var(--kpt-space-1, .25rem) var(--kpt-space-2, .5rem);border-radius:var(--kpt-radius-sm, .25rem);color:var(--kpt-color-on-surface-muted);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-range-tabs button.is-active{background:var(--kpt-color-surface-raised);color:var(--kpt-color-on-surface);font-weight:var(--kpt-font-weight-medium, 500);box-shadow:var(--kpt-elevation-1)}}\n"], dependencies: [{ kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }, { kind: "component", type: KptButton, selector: "kpt-button", inputs: ["variant", "size", "type", "disabled", "loading", "fullWidth"] }, { kind: "component", type: KptClock, selector: "kpt-clock", inputs: ["value", "hourFormat", "minuteStep"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1936
3697
  }
1937
3698
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptDateRange, decorators: [{
1938
3699
  type: Component,
1939
- args: [{ selector: 'kpt-date-range', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [CdkOverlayOrigin, CdkConnectedOverlay, KptIcon], host: { class: 'kpt-date-range-host' }, template: "<div\n class=\"kpt-date-range\"\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n role=\"button\"\n tabindex=\"0\"\n [class.kpt-date-range--open]=\"open()\"\n [class.kpt-date-range--disabled]=\"disabled()\"\n [class.kpt-date-range--invalid]=\"invalid()\"\n (click)=\"toggleOpen()\"\n (keydown.enter)=\"toggleOpen()\"\n (blur)=\"touch.emit()\"\n>\n @if (display()) {\n <span class=\"kpt-date-range__value\">{{ display() }}</span>\n } @else {\n <span class=\"kpt-date-range__placeholder\">{{ placeholder() }}</span>\n }\n <span class=\"kpt-date-range__spacer\"></span>\n @if (display()) {\n <button type=\"button\" class=\"kpt-date-range__clear\" (click)=\"clear($event)\" aria-label=\"Wyczy\u015B\u0107\"><kpt-icon name=\"x\" /></button>\n }\n <kpt-icon class=\"kpt-date-range__icon\" name=\"calendar\" />\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\"\n>\n <div class=\"kpt-calendar\" (keydown.escape)=\"close()\">\n <div class=\"kpt-calendar__header\">\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"prevMonth()\" aria-label=\"Poprzedni miesi\u0105c\"><kpt-icon name=\"chevron-left\" /></button>\n <span class=\"kpt-calendar__title\">{{ monthLabel() }}</span>\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"nextMonth()\" aria-label=\"Nast\u0119pny miesi\u0105c\"><kpt-icon name=\"chevron-right\" /></button>\n </div>\n <div class=\"kpt-calendar__weekdays\">\n @for (wd of weekdays; track wd) {\n <span class=\"kpt-calendar__weekday\">{{ wd }}</span>\n }\n </div>\n <div class=\"kpt-calendar__grid\">\n @for (week of weeks(); track $index) {\n @for (cell of week; track cell.iso) {\n <button\n type=\"button\"\n class=\"kpt-calendar__day\"\n [class.kpt-calendar__day--muted]=\"!cell.inMonth\"\n [class.kpt-calendar__day--range]=\"cell.inRange\"\n [class.kpt-calendar__day--selected]=\"cell.isStart || cell.isEnd\"\n (click)=\"selectDay(cell)\"\n >{{ cell.day }}</button>\n }\n }\n </div>\n </div>\n</ng-template>\n", styles: ["@layer kpt.components{.kpt-date-range-host{display:block}.kpt-date-range{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);height:2.5rem;padding-inline:var(--kpt-space-3, .75rem);box-sizing:border-box;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-date-range:hover:not(.kpt-date-range--disabled){border-color:var(--kpt-form-field-border-hover)}.kpt-date-range:focus-visible,.kpt-date-range.kpt-date-range--open{outline:none;border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-date-range.kpt-date-range--invalid{border-color:var(--kpt-form-field-border-error)}.kpt-date-range.kpt-date-range--disabled{cursor:not-allowed;opacity:.6;background:var(--kpt-color-surface-variant)}.kpt-date-range__placeholder{color:var(--kpt-form-field-placeholder)}.kpt-date-range__spacer{flex:1}.kpt-date-range__icon{color:var(--kpt-color-on-surface-muted)}.kpt-date-range__clear{display:inline-flex;border:0;background:none;cursor:pointer;padding:0;color:var(--kpt-color-on-surface-muted)}.kpt-date-range__clear:hover{color:var(--kpt-color-on-surface)}.kpt-calendar{width:17rem;padding:var(--kpt-space-3, .75rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3);color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem)}.kpt-calendar__header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--kpt-space-2, .5rem)}.kpt-calendar__title{font-weight:var(--kpt-font-weight-semibold, 600);text-transform:capitalize}.kpt-calendar__nav{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:var(--kpt-radius-md, .5rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer}.kpt-calendar__nav:hover{background:var(--kpt-color-muted)}.kpt-calendar__weekdays,.kpt-calendar__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}.kpt-calendar__weekday{text-align:center;font-size:var(--kpt-font-size-xs, .75rem);color:var(--kpt-color-on-surface-muted);padding:.25rem 0}.kpt-calendar__day{aspect-ratio:1;border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer;font:inherit}.kpt-calendar__day:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-calendar__day--muted{color:var(--kpt-color-on-surface-muted);opacity:.5}.kpt-calendar__day--range{background:color-mix(in oklch,var(--kpt-color-primary) 14%,transparent);border-radius:0}.kpt-calendar__day--selected{background:var(--kpt-color-primary)!important;color:var(--kpt-color-on-primary)}}\n"] }]
1940
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }] } });
3700
+ args: [{ selector: 'kpt-date-range', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [CdkOverlayOrigin, CdkConnectedOverlay, KptIcon, KptButton, KptClock], host: { class: 'kpt-date-range-host' }, template: "<div\n class=\"kpt-date-range\"\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n role=\"button\"\n tabindex=\"0\"\n [class.kpt-date-range--open]=\"open()\"\n [class.kpt-date-range--disabled]=\"disabled()\"\n [class.kpt-date-range--invalid]=\"invalid()\"\n (click)=\"toggleOpen()\"\n (keydown.enter)=\"toggleOpen()\"\n (blur)=\"touch.emit()\"\n>\n @if (display()) {\n <span class=\"kpt-date-range__value\">{{ display() }}</span>\n } @else {\n <span class=\"kpt-date-range__placeholder\">{{ placeholder() }}</span>\n }\n <span class=\"kpt-date-range__spacer\"></span>\n @if (display()) {\n <button type=\"button\" class=\"kpt-date-range__clear\" (click)=\"clear($event)\" aria-label=\"Wyczy\u015B\u0107\"><kpt-icon name=\"x\" /></button>\n }\n <kpt-icon class=\"kpt-date-range__icon\" name=\"calendar\" />\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"open()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\"\n>\n <div class=\"kpt-calendar\" [class.kpt-calendar--clock]=\"mode() === 'time'\" (keydown.escape)=\"close()\">\n @if (mode() === 'time') {\n <div class=\"kpt-range-tabs\">\n <button type=\"button\" [class.is-active]=\"timeEnd() === 'start'\" (click)=\"timeEnd.set('start')\">Od</button>\n <button type=\"button\" [class.is-active]=\"timeEnd() === 'end'\" (click)=\"timeEnd.set('end')\">Koniec</button>\n </div>\n @if (timeEnd() === 'start') {\n <kpt-clock [value]=\"startTime()\" (valueChange)=\"startTime.set($event)\" [hourFormat]=\"hourFormat()\" [minuteStep]=\"minuteStep()\" />\n } @else {\n <kpt-clock [value]=\"endTime()\" (valueChange)=\"endTime.set($event)\" [hourFormat]=\"hourFormat()\" [minuteStep]=\"minuteStep()\" />\n }\n <div class=\"kpt-calendar__footer\">\n <kpt-button size=\"sm\" (click)=\"commit()\">Gotowe</kpt-button>\n </div>\n } @else {\n <div class=\"kpt-calendar__header\">\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"prevMonth()\" aria-label=\"Poprzedni miesi\u0105c\"><kpt-icon name=\"chevron-left\" /></button>\n <span class=\"kpt-calendar__title\">{{ monthLabel() }}</span>\n <button type=\"button\" class=\"kpt-calendar__nav\" (click)=\"nextMonth()\" aria-label=\"Nast\u0119pny miesi\u0105c\"><kpt-icon name=\"chevron-right\" /></button>\n </div>\n <div class=\"kpt-calendar__weekdays\">\n @for (wd of weekdays; track wd) {\n <span class=\"kpt-calendar__weekday\">{{ wd }}</span>\n }\n </div>\n <div class=\"kpt-calendar__grid\">\n @for (week of weeks(); track $index) {\n @for (cell of week; track cell.iso) {\n <button\n type=\"button\"\n class=\"kpt-calendar__day\"\n [class.kpt-calendar__day--muted]=\"!cell.inMonth\"\n [class.kpt-calendar__day--range]=\"cell.inRange\"\n [class.kpt-calendar__day--selected]=\"cell.isStart || cell.isEnd\"\n (click)=\"selectDay(cell)\"\n >{{ cell.day }}</button>\n }\n }\n </div>\n\n @if (mode() === 'datetime') {\n <div class=\"kpt-range-tabs\">\n <button type=\"button\" [class.is-active]=\"timeEnd() === 'start'\" (click)=\"timeEnd.set('start')\">Od (godzina)</button>\n <button type=\"button\" [class.is-active]=\"timeEnd() === 'end'\" (click)=\"timeEnd.set('end')\">Koniec (godzina)</button>\n </div>\n @if (timeEnd() === 'start') {\n <kpt-clock [value]=\"startTime()\" (valueChange)=\"startTime.set($event)\" [hourFormat]=\"hourFormat()\" [minuteStep]=\"minuteStep()\" />\n } @else {\n <kpt-clock [value]=\"endTime()\" (valueChange)=\"endTime.set($event)\" [hourFormat]=\"hourFormat()\" [minuteStep]=\"minuteStep()\" />\n }\n <div class=\"kpt-calendar__footer\">\n <kpt-button size=\"sm\" (click)=\"commit()\">Gotowe</kpt-button>\n </div>\n }\n }\n </div>\n</ng-template>\n", styles: ["@layer kpt.components{.kpt-date-range-host{display:block}.kpt-date-range{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);height:2.5rem;padding-inline:var(--kpt-space-3, .75rem);box-sizing:border-box;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-date-range:hover:not(.kpt-date-range--disabled){border-color:var(--kpt-form-field-border-hover)}.kpt-date-range:focus-visible,.kpt-date-range.kpt-date-range--open{outline:none;border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-date-range.kpt-date-range--invalid{border-color:var(--kpt-form-field-border-error)}.kpt-date-range.kpt-date-range--disabled{cursor:not-allowed;opacity:.6;background:var(--kpt-color-surface-variant)}.kpt-date-range__placeholder{color:var(--kpt-form-field-placeholder)}.kpt-date-range__spacer{flex:1}.kpt-date-range__icon{color:var(--kpt-color-on-surface-muted)}.kpt-date-range__clear{display:inline-flex;border:0;background:none;cursor:pointer;padding:0;color:var(--kpt-color-on-surface-muted)}.kpt-date-range__clear:hover{color:var(--kpt-color-on-surface)}.kpt-calendar{width:17rem;padding:var(--kpt-space-3, .75rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3);color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem)}.kpt-calendar__header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--kpt-space-2, .5rem)}.kpt-calendar__title{font-weight:var(--kpt-font-weight-semibold, 600);text-transform:capitalize}.kpt-calendar__nav{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:var(--kpt-radius-md, .5rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer}.kpt-calendar__nav:hover{background:var(--kpt-color-muted)}.kpt-calendar__weekdays,.kpt-calendar__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}.kpt-calendar__weekday{text-align:center;font-size:var(--kpt-font-size-xs, .75rem);color:var(--kpt-color-on-surface-muted);padding:.25rem 0}.kpt-calendar__day{aspect-ratio:1;border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);cursor:pointer;font:inherit}.kpt-calendar__day:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-calendar__day--muted{color:var(--kpt-color-on-surface-muted);opacity:.5}.kpt-calendar__day--range{background:color-mix(in oklch,var(--kpt-color-primary) 14%,transparent);border-radius:0}.kpt-calendar__day--selected{background:var(--kpt-color-primary)!important;color:var(--kpt-color-on-primary)}.kpt-calendar__footer{display:flex;justify-content:flex-end;margin-top:var(--kpt-space-3, .75rem)}.kpt-calendar--clock{width:16rem}.kpt-range-tabs{display:flex;gap:var(--kpt-space-1, .25rem);margin-block:var(--kpt-space-3, .75rem) var(--kpt-space-2, .5rem);padding:2px;background:var(--kpt-color-surface-variant);border-radius:var(--kpt-radius-md, .5rem)}.kpt-range-tabs button{flex:1;border:0;background:none;padding:var(--kpt-space-1, .25rem) var(--kpt-space-2, .5rem);border-radius:var(--kpt-radius-sm, .25rem);color:var(--kpt-color-on-surface-muted);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-range-tabs button.is-active{background:var(--kpt-color-surface-raised);color:var(--kpt-color-on-surface);font-weight:var(--kpt-font-weight-medium, 500);box-shadow:var(--kpt-elevation-1)}}\n"] }]
3701
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], displayFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayFormat", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], hourFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "hourFormat", required: false }] }], minuteStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }] } });
1941
3702
 
1942
3703
  /**
1943
3704
  * Pole liczbowe ze strzałkami krokowania na Signal Forms. Wartość = number | null.
@@ -2163,6 +3924,7 @@ class KptInputOtp {
2163
3924
  if (this.integerOnly() && !/\d/.test(ch))
2164
3925
  ch = '';
2165
3926
  this.setChar(i, ch);
3927
+ el.value = this.charAt(i); // sync DOM z modelem — kasuje odrzucony/znormalizowany znak
2166
3928
  if (ch)
2167
3929
  this.focusSibling(el, 1);
2168
3930
  }
@@ -2663,7 +4425,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
2663
4425
  /**
2664
4426
  * Karta Koncept UI — powierzchnia z wyniesieniem (elevated) lub obramowaniem (outlined).
2665
4427
  * Opcjonalny nagłówek przez `header`; treść przez projekcję. Stopkę wstaw z atrybutem
2666
- * `kptCardFooter`.
4428
+ * `kptCardFooter`. Dla bogatych układów (media/profil) ustaw `flush` (body bez paddingu)
4429
+ * i użyj reużywalnych klas: `kpt-card__media`, `__lead`, `__title`, `__subtitle`,
4430
+ * `__section`, `__tags`, `__meta`, `__avatar`, `__actions`.
2667
4431
  *
2668
4432
  * @example
2669
4433
  * <kpt-card header="Ustawienia">
@@ -2678,16 +4442,18 @@ class KptCard {
2678
4442
  /** Opcjonalny tekst nagłówka. */
2679
4443
  header = input('', /* @ts-ignore */
2680
4444
  ...(ngDevMode ? [{ debugName: "header" }] : /* istanbul ignore next */ []));
4445
+ /** Body bez wewnętrznego paddingu — dla układów zarządzających własnymi sekcjami. */
4446
+ flush = input(false, { ...(ngDevMode ? { debugName: "flush" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
2681
4447
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptCard, deps: [], target: i0.ɵɵFactoryTarget.Component });
2682
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptCard, isStandalone: true, selector: "kpt-card", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-variant": "variant()" }, classAttribute: "kpt-card" }, ngImport: i0, template: "@if (header()) {\n <div class=\"kpt-card__header\">{{ header() }}</div>\n}\n<div class=\"kpt-card__body\">\n <ng-content />\n</div>\n<ng-content select=\"[kptCardFooter]\" />\n", styles: ["@layer kpt.components{.kpt-card{display:block;background:var(--kpt-card-bg);color:var(--kpt-card-fg);border-radius:var(--kpt-card-radius, .75rem);border:var(--kpt-border-width-thin, 1px) solid transparent}.kpt-card[data-variant=elevated]{box-shadow:var(--kpt-card-shadow);border-color:var(--kpt-card-border)}.kpt-card[data-variant=outlined]{border-color:var(--kpt-card-border)}.kpt-card__header{padding:var(--kpt-card-padding, 1.5rem);padding-bottom:0;font-size:var(--kpt-font-size-lg, 1.125rem);font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-card__body{padding:var(--kpt-card-padding, 1.5rem)}.kpt-card [kptCardFooter]{display:flex;gap:var(--kpt-space-3, .75rem);align-items:center;padding:var(--kpt-card-padding, 1.5rem);padding-top:0}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
4448
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptCard, isStandalone: true, selector: "kpt-card", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, flush: { classPropertyName: "flush", publicName: "flush", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-variant": "variant()" }, classAttribute: "kpt-card" }, ngImport: i0, template: "@if (header()) {\n <div class=\"kpt-card__header\">{{ header() }}</div>\n}\n<div class=\"kpt-card__body\" [class.kpt-card__body--flush]=\"flush()\">\n <ng-content />\n</div>\n<ng-content select=\"[kptCardFooter]\" />\n", styles: ["@layer kpt.components{.kpt-card{display:block;background:var(--kpt-card-bg);color:var(--kpt-card-fg);border-radius:var(--kpt-card-radius, .75rem);border:var(--kpt-border-width-thin, 1px) solid transparent;overflow:clip}.kpt-card[data-variant=elevated]{box-shadow:var(--kpt-card-shadow);border-color:var(--kpt-card-border)}.kpt-card[data-variant=outlined]{border-color:var(--kpt-card-border)}.kpt-card__header{padding:var(--kpt-card-padding, 1.5rem);padding-bottom:0;font-size:var(--kpt-font-size-lg, 1.125rem);font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-card__body{padding:var(--kpt-card-padding, 1.5rem)}.kpt-card__body--flush{padding:0}.kpt-card__media{display:block;width:100%;object-fit:cover}.kpt-card__lead{display:flex;align-items:center;gap:var(--kpt-space-3, .75rem);padding:var(--kpt-card-padding, 1.5rem)}.kpt-card__title{font-size:var(--kpt-font-size-lg, 1.125rem);font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-card__subtitle{font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface-muted)}.kpt-card__section{display:flex;flex-direction:column;gap:var(--kpt-space-3, .75rem);padding:var(--kpt-card-padding, 1.5rem)}.kpt-card__tags{display:flex;flex-wrap:wrap;gap:var(--kpt-space-2, .5rem)}.kpt-card__meta{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface-muted)}.kpt-card__avatar{align-self:flex-start;margin-top:-2.5rem;border-radius:50%;box-shadow:0 0 0 4px var(--kpt-card-bg)}.kpt-card__actions{display:flex;gap:var(--kpt-space-3, .75rem)}.kpt-card__actions>*{flex:1 1 0}.kpt-card [kptCardFooter]{display:flex;gap:var(--kpt-space-3, .75rem);align-items:center;padding:var(--kpt-card-padding, 1.5rem);padding-top:0}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2683
4449
  }
2684
4450
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptCard, decorators: [{
2685
4451
  type: Component,
2686
4452
  args: [{ selector: 'kpt-card', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
2687
4453
  class: 'kpt-card',
2688
4454
  '[attr.data-variant]': 'variant()',
2689
- }, template: "@if (header()) {\n <div class=\"kpt-card__header\">{{ header() }}</div>\n}\n<div class=\"kpt-card__body\">\n <ng-content />\n</div>\n<ng-content select=\"[kptCardFooter]\" />\n", styles: ["@layer kpt.components{.kpt-card{display:block;background:var(--kpt-card-bg);color:var(--kpt-card-fg);border-radius:var(--kpt-card-radius, .75rem);border:var(--kpt-border-width-thin, 1px) solid transparent}.kpt-card[data-variant=elevated]{box-shadow:var(--kpt-card-shadow);border-color:var(--kpt-card-border)}.kpt-card[data-variant=outlined]{border-color:var(--kpt-card-border)}.kpt-card__header{padding:var(--kpt-card-padding, 1.5rem);padding-bottom:0;font-size:var(--kpt-font-size-lg, 1.125rem);font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-card__body{padding:var(--kpt-card-padding, 1.5rem)}.kpt-card [kptCardFooter]{display:flex;gap:var(--kpt-space-3, .75rem);align-items:center;padding:var(--kpt-card-padding, 1.5rem);padding-top:0}}\n"] }]
2690
- }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }] } });
4455
+ }, template: "@if (header()) {\n <div class=\"kpt-card__header\">{{ header() }}</div>\n}\n<div class=\"kpt-card__body\" [class.kpt-card__body--flush]=\"flush()\">\n <ng-content />\n</div>\n<ng-content select=\"[kptCardFooter]\" />\n", styles: ["@layer kpt.components{.kpt-card{display:block;background:var(--kpt-card-bg);color:var(--kpt-card-fg);border-radius:var(--kpt-card-radius, .75rem);border:var(--kpt-border-width-thin, 1px) solid transparent;overflow:clip}.kpt-card[data-variant=elevated]{box-shadow:var(--kpt-card-shadow);border-color:var(--kpt-card-border)}.kpt-card[data-variant=outlined]{border-color:var(--kpt-card-border)}.kpt-card__header{padding:var(--kpt-card-padding, 1.5rem);padding-bottom:0;font-size:var(--kpt-font-size-lg, 1.125rem);font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-card__body{padding:var(--kpt-card-padding, 1.5rem)}.kpt-card__body--flush{padding:0}.kpt-card__media{display:block;width:100%;object-fit:cover}.kpt-card__lead{display:flex;align-items:center;gap:var(--kpt-space-3, .75rem);padding:var(--kpt-card-padding, 1.5rem)}.kpt-card__title{font-size:var(--kpt-font-size-lg, 1.125rem);font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-card__subtitle{font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface-muted)}.kpt-card__section{display:flex;flex-direction:column;gap:var(--kpt-space-3, .75rem);padding:var(--kpt-card-padding, 1.5rem)}.kpt-card__tags{display:flex;flex-wrap:wrap;gap:var(--kpt-space-2, .5rem)}.kpt-card__meta{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface-muted)}.kpt-card__avatar{align-self:flex-start;margin-top:-2.5rem;border-radius:50%;box-shadow:0 0 0 4px var(--kpt-card-bg)}.kpt-card__actions{display:flex;gap:var(--kpt-space-3, .75rem)}.kpt-card__actions>*{flex:1 1 0}.kpt-card [kptCardFooter]{display:flex;gap:var(--kpt-space-3, .75rem);align-items:center;padding:var(--kpt-card-padding, 1.5rem);padding-top:0}}\n"] }]
4456
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], flush: [{ type: i0.Input, args: [{ isSignal: true, alias: "flush", required: false }] }] } });
2691
4457
 
2692
4458
  /**
2693
4459
  * Separator Koncept UI (linia pozioma lub pionowa). Kolor z `--kpt-color-border`.
@@ -2808,8 +4574,11 @@ class KptPanel {
2808
4574
  toggleable = input(false, { ...(ngDevMode ? { debugName: "toggleable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
2809
4575
  collapsed = model(false, /* @ts-ignore */
2810
4576
  ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
4577
+ animated = input(true, { ...(ngDevMode ? { debugName: "animated" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
4578
+ animationDuration = input(500, /* @ts-ignore */
4579
+ ...(ngDevMode ? [{ debugName: "animationDuration" }] : /* istanbul ignore next */ []));
2811
4580
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
2812
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptPanel, isStandalone: true, selector: "kpt-panel", inputs: { header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, toggleable: { classPropertyName: "toggleable", publicName: "toggleable", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange" }, host: { classAttribute: "kpt-panel-host" }, ngImport: i0, template: `
4581
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptPanel, isStandalone: true, selector: "kpt-panel", inputs: { header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, toggleable: { classPropertyName: "toggleable", publicName: "toggleable", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, animated: { classPropertyName: "animated", publicName: "animated", isSignal: true, isRequired: false, transformFunction: null }, animationDuration: { classPropertyName: "animationDuration", publicName: "animationDuration", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange" }, host: { properties: { "style.--kpt-anim-duration": "(animated() ? animationDuration() : 0) + 'ms'" }, classAttribute: "kpt-panel-host" }, ngImport: i0, template: `
2813
4582
  <div class="kpt-panel">
2814
4583
  <div class="kpt-panel__header">
2815
4584
  <span class="kpt-panel__title">{{ header() }}</span>
@@ -2820,11 +4589,18 @@ class KptPanel {
2820
4589
  </button>
2821
4590
  }
2822
4591
  </div>
2823
- @if (!collapsed()) {
2824
- <div class="kpt-panel__body"><ng-content /></div>
2825
- }
4592
+ <div
4593
+ class="kpt-panel__collapse"
4594
+ [class.is-open]="!collapsed()"
4595
+ [attr.inert]="collapsed() ? '' : null"
4596
+ [attr.aria-hidden]="collapsed()"
4597
+ >
4598
+ <div class="kpt-panel__collapse-inner">
4599
+ <div class="kpt-panel__body"><ng-content /></div>
4600
+ </div>
4601
+ </div>
2826
4602
  </div>
2827
- `, isInline: true, styles: ["@layer kpt.components{.kpt-panel-host{display:block}.kpt-panel{border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);background:var(--kpt-color-surface-raised);overflow:hidden}.kpt-panel__header{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-3, .75rem) var(--kpt-space-4, 1rem);background:var(--kpt-color-surface-variant);border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border)}.kpt-panel__title{font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-panel__actions{margin-left:auto;display:inline-flex;align-items:center;gap:var(--kpt-space-1, .25rem)}.kpt-panel__toggle{display:inline-flex;border:0;background:none;padding:0;cursor:pointer;color:var(--kpt-color-on-surface-muted)}.kpt-panel__toggle:hover{color:var(--kpt-color-on-surface)}.kpt-panel__body{padding:var(--kpt-space-4, 1rem)}}\n"], dependencies: [{ kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
4603
+ `, isInline: true, styles: ["@layer kpt.components{.kpt-panel-host{display:block}.kpt-panel{border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);background:var(--kpt-color-surface-raised);overflow:hidden}.kpt-panel__header{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-3, .75rem) var(--kpt-space-4, 1rem);background:var(--kpt-color-surface-variant);border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border)}.kpt-panel__title{font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-panel__actions{margin-left:auto;display:inline-flex;align-items:center;gap:var(--kpt-space-1, .25rem)}.kpt-panel__toggle{display:inline-flex;border:0;background:none;padding:0;cursor:pointer;color:var(--kpt-color-on-surface-muted)}.kpt-panel__toggle:hover{color:var(--kpt-color-on-surface)}.kpt-panel__collapse{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--kpt-anim-duration, .5s) var(--kpt-motion-easing-standard)}.kpt-panel__collapse.is-open{grid-template-rows:1fr}.kpt-panel__collapse-inner{overflow:hidden;min-height:0}.kpt-panel__body{padding:var(--kpt-space-4, 1rem)}@media(prefers-reduced-motion:reduce){.kpt-panel__collapse{transition:none}}}\n"], dependencies: [{ kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2828
4604
  }
2829
4605
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptPanel, decorators: [{
2830
4606
  type: Component,
@@ -2839,12 +4615,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
2839
4615
  </button>
2840
4616
  }
2841
4617
  </div>
2842
- @if (!collapsed()) {
2843
- <div class="kpt-panel__body"><ng-content /></div>
2844
- }
4618
+ <div
4619
+ class="kpt-panel__collapse"
4620
+ [class.is-open]="!collapsed()"
4621
+ [attr.inert]="collapsed() ? '' : null"
4622
+ [attr.aria-hidden]="collapsed()"
4623
+ >
4624
+ <div class="kpt-panel__collapse-inner">
4625
+ <div class="kpt-panel__body"><ng-content /></div>
4626
+ </div>
4627
+ </div>
2845
4628
  </div>
2846
- `, host: { class: 'kpt-panel-host' }, styles: ["@layer kpt.components{.kpt-panel-host{display:block}.kpt-panel{border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);background:var(--kpt-color-surface-raised);overflow:hidden}.kpt-panel__header{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-3, .75rem) var(--kpt-space-4, 1rem);background:var(--kpt-color-surface-variant);border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border)}.kpt-panel__title{font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-panel__actions{margin-left:auto;display:inline-flex;align-items:center;gap:var(--kpt-space-1, .25rem)}.kpt-panel__toggle{display:inline-flex;border:0;background:none;padding:0;cursor:pointer;color:var(--kpt-color-on-surface-muted)}.kpt-panel__toggle:hover{color:var(--kpt-color-on-surface)}.kpt-panel__body{padding:var(--kpt-space-4, 1rem)}}\n"] }]
2847
- }], propDecorators: { header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], toggleable: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleable", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }] } });
4629
+ `, host: {
4630
+ 'class': 'kpt-panel-host',
4631
+ '[style.--kpt-anim-duration]': "(animated() ? animationDuration() : 0) + 'ms'",
4632
+ }, styles: ["@layer kpt.components{.kpt-panel-host{display:block}.kpt-panel{border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);background:var(--kpt-color-surface-raised);overflow:hidden}.kpt-panel__header{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-3, .75rem) var(--kpt-space-4, 1rem);background:var(--kpt-color-surface-variant);border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border)}.kpt-panel__title{font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-panel__actions{margin-left:auto;display:inline-flex;align-items:center;gap:var(--kpt-space-1, .25rem)}.kpt-panel__toggle{display:inline-flex;border:0;background:none;padding:0;cursor:pointer;color:var(--kpt-color-on-surface-muted)}.kpt-panel__toggle:hover{color:var(--kpt-color-on-surface)}.kpt-panel__collapse{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--kpt-anim-duration, .5s) var(--kpt-motion-easing-standard)}.kpt-panel__collapse.is-open{grid-template-rows:1fr}.kpt-panel__collapse-inner{overflow:hidden;min-height:0}.kpt-panel__body{padding:var(--kpt-space-4, 1rem)}@media(prefers-reduced-motion:reduce){.kpt-panel__collapse{transition:none}}}\n"] }]
4633
+ }], propDecorators: { header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], toggleable: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleable", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], animated: [{ type: i0.Input, args: [{ isSignal: true, alias: "animated", required: false }] }], animationDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationDuration", required: false }] }] } });
2848
4634
 
2849
4635
  /**
2850
4636
  * Grupa pól z legendą (fieldset), opcjonalnie zwijana.
@@ -2858,8 +4644,11 @@ class KptFieldset {
2858
4644
  toggleable = input(false, { ...(ngDevMode ? { debugName: "toggleable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
2859
4645
  collapsed = model(false, /* @ts-ignore */
2860
4646
  ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
4647
+ animated = input(true, { ...(ngDevMode ? { debugName: "animated" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
4648
+ animationDuration = input(500, /* @ts-ignore */
4649
+ ...(ngDevMode ? [{ debugName: "animationDuration" }] : /* istanbul ignore next */ []));
2861
4650
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptFieldset, deps: [], target: i0.ɵɵFactoryTarget.Component });
2862
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptFieldset, isStandalone: true, selector: "kpt-fieldset", inputs: { legend: { classPropertyName: "legend", publicName: "legend", isSignal: true, isRequired: false, transformFunction: null }, toggleable: { classPropertyName: "toggleable", publicName: "toggleable", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange" }, host: { classAttribute: "kpt-fieldset-host" }, ngImport: i0, template: `
4651
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptFieldset, isStandalone: true, selector: "kpt-fieldset", inputs: { legend: { classPropertyName: "legend", publicName: "legend", isSignal: true, isRequired: false, transformFunction: null }, toggleable: { classPropertyName: "toggleable", publicName: "toggleable", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, animated: { classPropertyName: "animated", publicName: "animated", isSignal: true, isRequired: false, transformFunction: null }, animationDuration: { classPropertyName: "animationDuration", publicName: "animationDuration", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange" }, host: { properties: { "style.--kpt-anim-duration": "(animated() ? animationDuration() : 0) + 'ms'" }, classAttribute: "kpt-fieldset-host" }, ngImport: i0, template: `
2863
4652
  <fieldset class="kpt-fieldset">
2864
4653
  <legend class="kpt-fieldset__legend">
2865
4654
  @if (toggleable()) {
@@ -2871,11 +4660,18 @@ class KptFieldset {
2871
4660
  <span>{{ legend() }}</span>
2872
4661
  }
2873
4662
  </legend>
2874
- @if (!collapsed()) {
2875
- <div class="kpt-fieldset__body"><ng-content /></div>
2876
- }
4663
+ <div
4664
+ class="kpt-fieldset__collapse"
4665
+ [class.is-open]="!collapsed()"
4666
+ [attr.inert]="collapsed() ? '' : null"
4667
+ [attr.aria-hidden]="collapsed()"
4668
+ >
4669
+ <div class="kpt-fieldset__collapse-inner">
4670
+ <div class="kpt-fieldset__body"><ng-content /></div>
4671
+ </div>
4672
+ </div>
2877
4673
  </fieldset>
2878
- `, isInline: true, styles: ["@layer kpt.components{.kpt-fieldset-host{display:block}.kpt-fieldset{border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);padding:var(--kpt-space-4, 1rem);margin:0;min-inline-size:0}.kpt-fieldset__legend{padding-inline:var(--kpt-space-2, .5rem);font-weight:var(--kpt-font-weight-semibold, 600);color:var(--kpt-color-on-surface)}.kpt-fieldset__toggle{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);border:0;background:none;padding:0;cursor:pointer;color:inherit;font:inherit;font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-fieldset__body{padding-top:var(--kpt-space-2, .5rem)}}\n"], dependencies: [{ kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
4674
+ `, isInline: true, styles: ["@layer kpt.components{.kpt-fieldset-host{display:block}.kpt-fieldset{border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);padding:var(--kpt-space-4, 1rem);margin:0;min-inline-size:0}.kpt-fieldset__legend{padding-inline:var(--kpt-space-2, .5rem);font-weight:var(--kpt-font-weight-semibold, 600);color:var(--kpt-color-on-surface)}.kpt-fieldset__toggle{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);border:0;background:none;padding:0;cursor:pointer;color:inherit;font:inherit;font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-fieldset__collapse{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--kpt-anim-duration, .5s) var(--kpt-motion-easing-standard)}.kpt-fieldset__collapse.is-open{grid-template-rows:1fr}.kpt-fieldset__collapse-inner{overflow:hidden;min-height:0}.kpt-fieldset__body{padding-top:var(--kpt-space-2, .5rem)}@media(prefers-reduced-motion:reduce){.kpt-fieldset__collapse{transition:none}}}\n"], dependencies: [{ kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2879
4675
  }
2880
4676
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptFieldset, decorators: [{
2881
4677
  type: Component,
@@ -2891,12 +4687,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
2891
4687
  <span>{{ legend() }}</span>
2892
4688
  }
2893
4689
  </legend>
2894
- @if (!collapsed()) {
2895
- <div class="kpt-fieldset__body"><ng-content /></div>
2896
- }
4690
+ <div
4691
+ class="kpt-fieldset__collapse"
4692
+ [class.is-open]="!collapsed()"
4693
+ [attr.inert]="collapsed() ? '' : null"
4694
+ [attr.aria-hidden]="collapsed()"
4695
+ >
4696
+ <div class="kpt-fieldset__collapse-inner">
4697
+ <div class="kpt-fieldset__body"><ng-content /></div>
4698
+ </div>
4699
+ </div>
2897
4700
  </fieldset>
2898
- `, host: { class: 'kpt-fieldset-host' }, styles: ["@layer kpt.components{.kpt-fieldset-host{display:block}.kpt-fieldset{border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);padding:var(--kpt-space-4, 1rem);margin:0;min-inline-size:0}.kpt-fieldset__legend{padding-inline:var(--kpt-space-2, .5rem);font-weight:var(--kpt-font-weight-semibold, 600);color:var(--kpt-color-on-surface)}.kpt-fieldset__toggle{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);border:0;background:none;padding:0;cursor:pointer;color:inherit;font:inherit;font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-fieldset__body{padding-top:var(--kpt-space-2, .5rem)}}\n"] }]
2899
- }], propDecorators: { legend: [{ type: i0.Input, args: [{ isSignal: true, alias: "legend", required: false }] }], toggleable: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleable", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }] } });
4701
+ `, host: {
4702
+ 'class': 'kpt-fieldset-host',
4703
+ '[style.--kpt-anim-duration]': "(animated() ? animationDuration() : 0) + 'ms'",
4704
+ }, styles: ["@layer kpt.components{.kpt-fieldset-host{display:block}.kpt-fieldset{border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);padding:var(--kpt-space-4, 1rem);margin:0;min-inline-size:0}.kpt-fieldset__legend{padding-inline:var(--kpt-space-2, .5rem);font-weight:var(--kpt-font-weight-semibold, 600);color:var(--kpt-color-on-surface)}.kpt-fieldset__toggle{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);border:0;background:none;padding:0;cursor:pointer;color:inherit;font:inherit;font-weight:var(--kpt-font-weight-semibold, 600)}.kpt-fieldset__collapse{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--kpt-anim-duration, .5s) var(--kpt-motion-easing-standard)}.kpt-fieldset__collapse.is-open{grid-template-rows:1fr}.kpt-fieldset__collapse-inner{overflow:hidden;min-height:0}.kpt-fieldset__body{padding-top:var(--kpt-space-2, .5rem)}@media(prefers-reduced-motion:reduce){.kpt-fieldset__collapse{transition:none}}}\n"] }]
4705
+ }], propDecorators: { legend: [{ type: i0.Input, args: [{ isSignal: true, alias: "legend", required: false }] }], toggleable: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleable", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], animated: [{ type: i0.Input, args: [{ isSignal: true, alias: "animated", required: false }] }], animationDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationDuration", required: false }] }] } });
2900
4706
 
2901
4707
  /**
2902
4708
  * Splitter — dwa panele z przeciąganym uchwytem. Panele przez sloty `[kptSplitStart]` i `[kptSplitEnd]`.
@@ -3307,17 +5113,46 @@ class KptTabs {
3307
5113
  ...(ngDevMode ? [{ debugName: "tabs" }] : /* istanbul ignore next */ []));
3308
5114
  activeIndex = model(0, /* @ts-ignore */
3309
5115
  ...(ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []));
5116
+ animated = input(true, { ...(ngDevMode ? { debugName: "animated" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
5117
+ animationDuration = input(500, /* @ts-ignore */
5118
+ ...(ngDevMode ? [{ debugName: "animationDuration" }] : /* istanbul ignore next */ []));
5119
+ tabBtns = viewChildren('tabBtn', /* @ts-ignore */
5120
+ ...(ngDevMode ? [{ debugName: "tabBtns" }] : /* istanbul ignore next */ []));
5121
+ inkX = signal(0, /* @ts-ignore */
5122
+ ...(ngDevMode ? [{ debugName: "inkX" }] : /* istanbul ignore next */ []));
5123
+ inkW = signal(0, /* @ts-ignore */
5124
+ ...(ngDevMode ? [{ debugName: "inkW" }] : /* istanbul ignore next */ []));
5125
+ direction = signal(1, /* @ts-ignore */
5126
+ ...(ngDevMode ? [{ debugName: "direction" }] : /* istanbul ignore next */ []));
3310
5127
  activeTab = computed(() => this.tabs()[this.activeIndex()], /* @ts-ignore */
3311
5128
  ...(ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []));
5129
+ activePanels = computed(() => {
5130
+ const tab = this.activeTab();
5131
+ return tab ? [tab] : [];
5132
+ }, /* @ts-ignore */
5133
+ ...(ngDevMode ? [{ debugName: "activePanels" }] : /* istanbul ignore next */ []));
5134
+ constructor() {
5135
+ afterRenderEffect(() => this.measureInk());
5136
+ }
5137
+ measureInk() {
5138
+ const btn = this.tabBtns()[this.activeIndex()]?.nativeElement;
5139
+ if (!btn)
5140
+ return;
5141
+ this.inkX.set(btn.offsetLeft);
5142
+ this.inkW.set(btn.offsetWidth);
5143
+ }
3312
5144
  select(index) {
3313
- if (!this.tabs()[index]?.disabled())
3314
- this.activeIndex.set(index);
5145
+ if (this.tabs()[index]?.disabled())
5146
+ return;
5147
+ this.direction.set(index >= this.activeIndex() ? 1 : -1);
5148
+ this.activeIndex.set(index);
3315
5149
  }
3316
5150
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptTabs, deps: [], target: i0.ɵɵFactoryTarget.Component });
3317
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptTabs, isStandalone: true, selector: "kpt-tabs", inputs: { activeIndex: { classPropertyName: "activeIndex", publicName: "activeIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeIndex: "activeIndexChange" }, host: { classAttribute: "kpt-tabs-host" }, queries: [{ propertyName: "tabs", predicate: KptTab, isSignal: true }], ngImport: i0, template: `
5151
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptTabs, isStandalone: true, selector: "kpt-tabs", inputs: { activeIndex: { classPropertyName: "activeIndex", publicName: "activeIndex", isSignal: true, isRequired: false, transformFunction: null }, animated: { classPropertyName: "animated", publicName: "animated", isSignal: true, isRequired: false, transformFunction: null }, animationDuration: { classPropertyName: "animationDuration", publicName: "animationDuration", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeIndex: "activeIndexChange" }, host: { listeners: { "window:resize": "measureInk()" }, properties: { "style.--kpt-anim-duration": "(animated() ? animationDuration() : 0) + 'ms'", "style.--kpt-anim-dir": "direction()" }, classAttribute: "kpt-tabs-host" }, queries: [{ propertyName: "tabs", predicate: KptTab, isSignal: true }], viewQueries: [{ propertyName: "tabBtns", predicate: ["tabBtn"], descendants: true, isSignal: true }], ngImport: i0, template: `
3318
5152
  <div class="kpt-tabs__header" role="tablist">
3319
5153
  @for (tab of tabs(); track $index; let i = $index) {
3320
5154
  <button
5155
+ #tabBtn
3321
5156
  type="button"
3322
5157
  class="kpt-tabs__tab"
3323
5158
  role="tab"
@@ -3327,13 +5162,14 @@ class KptTabs {
3327
5162
  (click)="select(i)"
3328
5163
  >{{ tab.label() }}</button>
3329
5164
  }
5165
+ <span class="kpt-tabs__ink" [style.width.px]="inkW()" [style.transform]="'translateX(' + inkX() + 'px)'"></span>
3330
5166
  </div>
3331
5167
  <div class="kpt-tabs__body" role="tabpanel">
3332
- @if (activeTab(); as tab) {
3333
- <ng-container [ngTemplateOutlet]="tab.content()" />
5168
+ @for (tab of activePanels(); track activeIndex()) {
5169
+ <div class="kpt-tabs__panel"><ng-container [ngTemplateOutlet]="tab.content()" /></div>
3334
5170
  }
3335
5171
  </div>
3336
- `, isInline: true, styles: ["@layer kpt.components{.kpt-tabs-host{display:block}.kpt-tabs__header{display:flex;gap:.25rem;border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border)}.kpt-tabs__tab{appearance:none;border:0;background:none;padding:.65rem 1rem;margin-bottom:-1px;border-bottom:2px solid transparent;color:var(--kpt-color-on-surface-muted);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-medium, 500);cursor:pointer;transition:color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard),border-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-tabs__tab:hover:not(:disabled):not(.is-active){color:var(--kpt-color-on-surface)}.kpt-tabs__tab.is-active{color:var(--kpt-color-primary);border-bottom-color:var(--kpt-color-primary)}.kpt-tabs__tab:disabled{opacity:.45;cursor:not-allowed}.kpt-tabs__body{padding-block:var(--kpt-space-4, 1rem)}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
5172
+ `, isInline: true, styles: ["@layer kpt.components{.kpt-tabs-host{display:block}.kpt-tabs__header{position:relative;display:flex;gap:.25rem;border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border)}.kpt-tabs__tab{appearance:none;border:0;background:none;padding:.65rem 1rem;color:var(--kpt-color-on-surface-muted);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-medium, 500);cursor:pointer;transition:color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-tabs__tab:hover:not(:disabled):not(.is-active){color:var(--kpt-color-on-surface)}.kpt-tabs__tab.is-active{color:var(--kpt-color-primary)}.kpt-tabs__tab:disabled{opacity:.45;cursor:not-allowed}.kpt-tabs__ink{position:absolute;bottom:-1px;left:0;height:2px;background:var(--kpt-color-primary);pointer-events:none;transition:transform var(--kpt-anim-duration, .5s) var(--kpt-motion-easing-standard),width var(--kpt-anim-duration, .5s) var(--kpt-motion-easing-standard)}.kpt-tabs__body{padding-block:var(--kpt-space-4, 1rem);overflow-x:clip}@keyframes kpt-tabs-enter{0%{opacity:0;transform:translate(calc(var(--kpt-anim-dir, 1) * 1.5rem))}to{opacity:1;transform:none}}.kpt-tabs__panel{animation:kpt-tabs-enter var(--kpt-anim-duration, .5s) var(--kpt-motion-easing-standard)}@media(prefers-reduced-motion:reduce){.kpt-tabs__panel{animation:none}.kpt-tabs__ink{transition:none}}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3337
5173
  }
3338
5174
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptTabs, decorators: [{
3339
5175
  type: Component,
@@ -3341,6 +5177,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
3341
5177
  <div class="kpt-tabs__header" role="tablist">
3342
5178
  @for (tab of tabs(); track $index; let i = $index) {
3343
5179
  <button
5180
+ #tabBtn
3344
5181
  type="button"
3345
5182
  class="kpt-tabs__tab"
3346
5183
  role="tab"
@@ -3350,14 +5187,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
3350
5187
  (click)="select(i)"
3351
5188
  >{{ tab.label() }}</button>
3352
5189
  }
5190
+ <span class="kpt-tabs__ink" [style.width.px]="inkW()" [style.transform]="'translateX(' + inkX() + 'px)'"></span>
3353
5191
  </div>
3354
5192
  <div class="kpt-tabs__body" role="tabpanel">
3355
- @if (activeTab(); as tab) {
3356
- <ng-container [ngTemplateOutlet]="tab.content()" />
5193
+ @for (tab of activePanels(); track activeIndex()) {
5194
+ <div class="kpt-tabs__panel"><ng-container [ngTemplateOutlet]="tab.content()" /></div>
3357
5195
  }
3358
5196
  </div>
3359
- `, host: { class: 'kpt-tabs-host' }, styles: ["@layer kpt.components{.kpt-tabs-host{display:block}.kpt-tabs__header{display:flex;gap:.25rem;border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border)}.kpt-tabs__tab{appearance:none;border:0;background:none;padding:.65rem 1rem;margin-bottom:-1px;border-bottom:2px solid transparent;color:var(--kpt-color-on-surface-muted);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-medium, 500);cursor:pointer;transition:color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard),border-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-tabs__tab:hover:not(:disabled):not(.is-active){color:var(--kpt-color-on-surface)}.kpt-tabs__tab.is-active{color:var(--kpt-color-primary);border-bottom-color:var(--kpt-color-primary)}.kpt-tabs__tab:disabled{opacity:.45;cursor:not-allowed}.kpt-tabs__body{padding-block:var(--kpt-space-4, 1rem)}}\n"] }]
3360
- }], propDecorators: { tabs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => KptTab), { isSignal: true }] }], activeIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIndex", required: false }] }, { type: i0.Output, args: ["activeIndexChange"] }] } });
5197
+ `, host: {
5198
+ 'class': 'kpt-tabs-host',
5199
+ '[style.--kpt-anim-duration]': "(animated() ? animationDuration() : 0) + 'ms'",
5200
+ '[style.--kpt-anim-dir]': 'direction()',
5201
+ '(window:resize)': 'measureInk()',
5202
+ }, styles: ["@layer kpt.components{.kpt-tabs-host{display:block}.kpt-tabs__header{position:relative;display:flex;gap:.25rem;border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border)}.kpt-tabs__tab{appearance:none;border:0;background:none;padding:.65rem 1rem;color:var(--kpt-color-on-surface-muted);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-medium, 500);cursor:pointer;transition:color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-tabs__tab:hover:not(:disabled):not(.is-active){color:var(--kpt-color-on-surface)}.kpt-tabs__tab.is-active{color:var(--kpt-color-primary)}.kpt-tabs__tab:disabled{opacity:.45;cursor:not-allowed}.kpt-tabs__ink{position:absolute;bottom:-1px;left:0;height:2px;background:var(--kpt-color-primary);pointer-events:none;transition:transform var(--kpt-anim-duration, .5s) var(--kpt-motion-easing-standard),width var(--kpt-anim-duration, .5s) var(--kpt-motion-easing-standard)}.kpt-tabs__body{padding-block:var(--kpt-space-4, 1rem);overflow-x:clip}@keyframes kpt-tabs-enter{0%{opacity:0;transform:translate(calc(var(--kpt-anim-dir, 1) * 1.5rem))}to{opacity:1;transform:none}}.kpt-tabs__panel{animation:kpt-tabs-enter var(--kpt-anim-duration, .5s) var(--kpt-motion-easing-standard)}@media(prefers-reduced-motion:reduce){.kpt-tabs__panel{animation:none}.kpt-tabs__ink{transition:none}}}\n"] }]
5203
+ }], ctorParameters: () => [], propDecorators: { tabs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => KptTab), { isSignal: true }] }], activeIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIndex", required: false }] }, { type: i0.Output, args: ["activeIndexChange"] }], animated: [{ type: i0.Input, args: [{ isSignal: true, alias: "animated", required: false }] }], animationDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationDuration", required: false }] }], tabBtns: [{ type: i0.ViewChildren, args: ['tabBtn', { isSignal: true }] }] } });
3361
5204
 
3362
5205
  /**
3363
5206
  * Panel akordeonu. Umieszczaj w `kpt-accordion`. Stan `expanded` jest dwukierunkowy.
@@ -3369,6 +5212,12 @@ class KptAccordionPanel {
3369
5212
  expanded = model(false, /* @ts-ignore */
3370
5213
  ...(ngDevMode ? [{ debugName: "expanded" }] : /* istanbul ignore next */ []));
3371
5214
  accordion = inject(KptAccordion, { optional: true });
5215
+ animMs = computed(() => {
5216
+ const on = this.accordion?.animated() ?? true;
5217
+ const d = this.accordion?.animationDuration() ?? 500;
5218
+ return (on ? d : 0) + 'ms';
5219
+ }, /* @ts-ignore */
5220
+ ...(ngDevMode ? [{ debugName: "animMs" }] : /* istanbul ignore next */ []));
3372
5221
  toggle() {
3373
5222
  if (this.disabled())
3374
5223
  return;
@@ -3378,7 +5227,7 @@ class KptAccordionPanel {
3378
5227
  this.accordion?.onOpen(this);
3379
5228
  }
3380
5229
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptAccordionPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
3381
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptAccordionPanel, isStandalone: true, selector: "kpt-accordion-panel", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { expanded: "expandedChange" }, host: { classAttribute: "kpt-accordion-panel-host" }, ngImport: i0, template: `
5230
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.0", type: KptAccordionPanel, isStandalone: true, selector: "kpt-accordion-panel", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { expanded: "expandedChange" }, host: { properties: { "style.--kpt-anim-duration": "animMs()" }, classAttribute: "kpt-accordion-panel-host" }, ngImport: i0, template: `
3382
5231
  <div class="kpt-accordion-panel" [class.is-open]="expanded()">
3383
5232
  <button
3384
5233
  type="button"
@@ -3390,11 +5239,18 @@ class KptAccordionPanel {
3390
5239
  <span class="kpt-accordion-panel__title">{{ title() }}</span>
3391
5240
  <kpt-icon name="chevron-down" class="kpt-accordion-panel__chevron" [class.is-open]="expanded()" />
3392
5241
  </button>
3393
- @if (expanded()) {
3394
- <div class="kpt-accordion-panel__body"><ng-content /></div>
3395
- }
5242
+ <div
5243
+ class="kpt-accordion-panel__collapse"
5244
+ [class.is-open]="expanded()"
5245
+ [attr.inert]="expanded() ? null : ''"
5246
+ [attr.aria-hidden]="!expanded()"
5247
+ >
5248
+ <div class="kpt-accordion-panel__collapse-inner">
5249
+ <div class="kpt-accordion-panel__body"><ng-content /></div>
5250
+ </div>
5251
+ </div>
3396
5252
  </div>
3397
- `, isInline: true, styles: ["@layer kpt.components{.kpt-accordion-panel-host{display:block}.kpt-accordion-panel-host:not(:last-child) .kpt-accordion-panel{border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border)}.kpt-accordion-panel__header{display:flex;align-items:center;justify-content:space-between;gap:var(--kpt-space-3, .75rem);width:100%;padding:var(--kpt-space-4, 1rem) var(--kpt-space-5, 1.25rem);border:0;background:none;color:var(--kpt-color-on-surface);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-medium, 500);text-align:start;cursor:pointer}.kpt-accordion-panel__header:hover:not(:disabled){background:var(--kpt-color-surface-variant)}.kpt-accordion-panel__header:disabled{opacity:.5;cursor:not-allowed}.kpt-accordion-panel__chevron{color:var(--kpt-color-on-surface-muted);transition:transform var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-accordion-panel__chevron.is-open{transform:rotate(180deg)}.kpt-accordion-panel__body{padding:0 var(--kpt-space-5, 1.25rem) var(--kpt-space-4, 1rem);font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface)}}\n"], dependencies: [{ kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
5253
+ `, isInline: true, styles: ["@layer kpt.components{.kpt-accordion-panel-host{display:block}.kpt-accordion-panel-host:not(:last-child) .kpt-accordion-panel{border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border)}.kpt-accordion-panel__header{display:flex;align-items:center;justify-content:space-between;gap:var(--kpt-space-3, .75rem);width:100%;padding:var(--kpt-space-4, 1rem) var(--kpt-space-5, 1.25rem);border:0;background:none;color:var(--kpt-color-on-surface);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-medium, 500);text-align:start;cursor:pointer}.kpt-accordion-panel__header:hover:not(:disabled){background:var(--kpt-color-surface-variant)}.kpt-accordion-panel__header:disabled{opacity:.5;cursor:not-allowed}.kpt-accordion-panel__chevron{color:var(--kpt-color-on-surface-muted);transition:transform var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-accordion-panel__chevron.is-open{transform:rotate(180deg)}.kpt-accordion-panel__collapse{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--kpt-anim-duration, .5s) var(--kpt-motion-easing-standard)}.kpt-accordion-panel__collapse.is-open{grid-template-rows:1fr}.kpt-accordion-panel__collapse-inner{overflow:hidden;min-height:0}.kpt-accordion-panel__body{padding:0 var(--kpt-space-5, 1.25rem) var(--kpt-space-4, 1rem);font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface)}@media(prefers-reduced-motion:reduce){.kpt-accordion-panel__collapse{transition:none}}}\n"], dependencies: [{ kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3398
5254
  }
3399
5255
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptAccordionPanel, decorators: [{
3400
5256
  type: Component,
@@ -3410,11 +5266,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
3410
5266
  <span class="kpt-accordion-panel__title">{{ title() }}</span>
3411
5267
  <kpt-icon name="chevron-down" class="kpt-accordion-panel__chevron" [class.is-open]="expanded()" />
3412
5268
  </button>
3413
- @if (expanded()) {
3414
- <div class="kpt-accordion-panel__body"><ng-content /></div>
3415
- }
5269
+ <div
5270
+ class="kpt-accordion-panel__collapse"
5271
+ [class.is-open]="expanded()"
5272
+ [attr.inert]="expanded() ? null : ''"
5273
+ [attr.aria-hidden]="!expanded()"
5274
+ >
5275
+ <div class="kpt-accordion-panel__collapse-inner">
5276
+ <div class="kpt-accordion-panel__body"><ng-content /></div>
5277
+ </div>
5278
+ </div>
3416
5279
  </div>
3417
- `, host: { class: 'kpt-accordion-panel-host' }, styles: ["@layer kpt.components{.kpt-accordion-panel-host{display:block}.kpt-accordion-panel-host:not(:last-child) .kpt-accordion-panel{border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border)}.kpt-accordion-panel__header{display:flex;align-items:center;justify-content:space-between;gap:var(--kpt-space-3, .75rem);width:100%;padding:var(--kpt-space-4, 1rem) var(--kpt-space-5, 1.25rem);border:0;background:none;color:var(--kpt-color-on-surface);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-medium, 500);text-align:start;cursor:pointer}.kpt-accordion-panel__header:hover:not(:disabled){background:var(--kpt-color-surface-variant)}.kpt-accordion-panel__header:disabled{opacity:.5;cursor:not-allowed}.kpt-accordion-panel__chevron{color:var(--kpt-color-on-surface-muted);transition:transform var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-accordion-panel__chevron.is-open{transform:rotate(180deg)}.kpt-accordion-panel__body{padding:0 var(--kpt-space-5, 1.25rem) var(--kpt-space-4, 1rem);font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface)}}\n"] }]
5280
+ `, host: {
5281
+ 'class': 'kpt-accordion-panel-host',
5282
+ '[style.--kpt-anim-duration]': 'animMs()',
5283
+ }, styles: ["@layer kpt.components{.kpt-accordion-panel-host{display:block}.kpt-accordion-panel-host:not(:last-child) .kpt-accordion-panel{border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border)}.kpt-accordion-panel__header{display:flex;align-items:center;justify-content:space-between;gap:var(--kpt-space-3, .75rem);width:100%;padding:var(--kpt-space-4, 1rem) var(--kpt-space-5, 1.25rem);border:0;background:none;color:var(--kpt-color-on-surface);font:inherit;font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-medium, 500);text-align:start;cursor:pointer}.kpt-accordion-panel__header:hover:not(:disabled){background:var(--kpt-color-surface-variant)}.kpt-accordion-panel__header:disabled{opacity:.5;cursor:not-allowed}.kpt-accordion-panel__chevron{color:var(--kpt-color-on-surface-muted);transition:transform var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-accordion-panel__chevron.is-open{transform:rotate(180deg)}.kpt-accordion-panel__collapse{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--kpt-anim-duration, .5s) var(--kpt-motion-easing-standard)}.kpt-accordion-panel__collapse.is-open{grid-template-rows:1fr}.kpt-accordion-panel__collapse-inner{overflow:hidden;min-height:0}.kpt-accordion-panel__body{padding:0 var(--kpt-space-5, 1.25rem) var(--kpt-space-4, 1rem);font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface)}@media(prefers-reduced-motion:reduce){.kpt-accordion-panel__collapse{transition:none}}}\n"] }]
3418
5284
  }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }, { type: i0.Output, args: ["expandedChange"] }] } });
3419
5285
 
3420
5286
  /**
@@ -3428,6 +5294,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
3428
5294
  */
3429
5295
  class KptAccordion {
3430
5296
  multi = input(false, { ...(ngDevMode ? { debugName: "multi" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
5297
+ animated = input(true, { ...(ngDevMode ? { debugName: "animated" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
5298
+ animationDuration = input(500, /* @ts-ignore */
5299
+ ...(ngDevMode ? [{ debugName: "animationDuration" }] : /* istanbul ignore next */ []));
3431
5300
  panels = contentChildren(KptAccordionPanel, /* @ts-ignore */
3432
5301
  ...(ngDevMode ? [{ debugName: "panels" }] : /* istanbul ignore next */ []));
3433
5302
  /** Wywoływane przez panel przy otwarciu — zamyka pozostałe, gdy nie `multi`. */
@@ -3440,12 +5309,12 @@ class KptAccordion {
3440
5309
  }
3441
5310
  }
3442
5311
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptAccordion, deps: [], target: i0.ɵɵFactoryTarget.Component });
3443
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.0", type: KptAccordion, isStandalone: true, selector: "kpt-accordion", inputs: { multi: { classPropertyName: "multi", publicName: "multi", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "kpt-accordion-host" }, queries: [{ propertyName: "panels", predicate: KptAccordionPanel, isSignal: true }], ngImport: i0, template: `<ng-content />`, isInline: true, styles: ["@layer kpt.components{.kpt-accordion-host{display:block;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-lg, .75rem);overflow:hidden}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
5312
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.0", type: KptAccordion, isStandalone: true, selector: "kpt-accordion", inputs: { multi: { classPropertyName: "multi", publicName: "multi", isSignal: true, isRequired: false, transformFunction: null }, animated: { classPropertyName: "animated", publicName: "animated", isSignal: true, isRequired: false, transformFunction: null }, animationDuration: { classPropertyName: "animationDuration", publicName: "animationDuration", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "kpt-accordion-host" }, queries: [{ propertyName: "panels", predicate: KptAccordionPanel, isSignal: true }], ngImport: i0, template: `<ng-content />`, isInline: true, styles: ["@layer kpt.components{.kpt-accordion-host{display:block;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-lg, .75rem);overflow:hidden}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3444
5313
  }
3445
5314
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptAccordion, decorators: [{
3446
5315
  type: Component,
3447
5316
  args: [{ selector: 'kpt-accordion', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: `<ng-content />`, host: { class: 'kpt-accordion-host' }, styles: ["@layer kpt.components{.kpt-accordion-host{display:block;border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-lg, .75rem);overflow:hidden}}\n"] }]
3448
- }], propDecorators: { multi: [{ type: i0.Input, args: [{ isSignal: true, alias: "multi", required: false }] }], panels: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => KptAccordionPanel), { isSignal: true }] }] } });
5317
+ }], propDecorators: { multi: [{ type: i0.Input, args: [{ isSignal: true, alias: "multi", required: false }] }], animated: [{ type: i0.Input, args: [{ isSignal: true, alias: "animated", required: false }] }], animationDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationDuration", required: false }] }], panels: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => KptAccordionPanel), { isSignal: true }] }] } });
3449
5318
 
3450
5319
  /**
3451
5320
  * Ścieżka nawigacji (breadcrumbs).
@@ -3528,19 +5397,33 @@ class KptStepper {
3528
5397
  ...(ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []));
3529
5398
  activeIndex = model(0, /* @ts-ignore */
3530
5399
  ...(ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []));
5400
+ animated = input(true, { ...(ngDevMode ? { debugName: "animated" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
5401
+ animationDuration = input(500, /* @ts-ignore */
5402
+ ...(ngDevMode ? [{ debugName: "animationDuration" }] : /* istanbul ignore next */ []));
5403
+ direction = signal(1, /* @ts-ignore */
5404
+ ...(ngDevMode ? [{ debugName: "direction" }] : /* istanbul ignore next */ []));
3531
5405
  activeStep = computed(() => this.steps()[this.activeIndex()], /* @ts-ignore */
3532
5406
  ...(ngDevMode ? [{ debugName: "activeStep" }] : /* istanbul ignore next */ []));
5407
+ activePanels = computed(() => {
5408
+ const step = this.activeStep();
5409
+ return step ? [step] : [];
5410
+ }, /* @ts-ignore */
5411
+ ...(ngDevMode ? [{ debugName: "activePanels" }] : /* istanbul ignore next */ []));
3533
5412
  goTo(index) {
3534
- this.activeIndex.set(Math.max(0, Math.min(index, this.steps().length - 1)));
5413
+ const next = Math.max(0, Math.min(index, this.steps().length - 1));
5414
+ this.direction.set(next >= this.activeIndex() ? 1 : -1);
5415
+ this.activeIndex.set(next);
3535
5416
  }
3536
5417
  next() {
5418
+ this.direction.set(1);
3537
5419
  this.activeIndex.update((i) => Math.min(i + 1, this.steps().length - 1));
3538
5420
  }
3539
5421
  prev() {
5422
+ this.direction.set(-1);
3540
5423
  this.activeIndex.update((i) => Math.max(i - 1, 0));
3541
5424
  }
3542
5425
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptStepper, deps: [], target: i0.ɵɵFactoryTarget.Component });
3543
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptStepper, isStandalone: true, selector: "kpt-stepper", inputs: { activeIndex: { classPropertyName: "activeIndex", publicName: "activeIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeIndex: "activeIndexChange" }, host: { classAttribute: "kpt-stepper-host" }, queries: [{ propertyName: "steps", predicate: KptStep, isSignal: true }], ngImport: i0, template: `
5426
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptStepper, isStandalone: true, selector: "kpt-stepper", inputs: { activeIndex: { classPropertyName: "activeIndex", publicName: "activeIndex", isSignal: true, isRequired: false, transformFunction: null }, animated: { classPropertyName: "animated", publicName: "animated", isSignal: true, isRequired: false, transformFunction: null }, animationDuration: { classPropertyName: "animationDuration", publicName: "animationDuration", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeIndex: "activeIndexChange" }, host: { properties: { "style.--kpt-anim-duration": "(animated() ? animationDuration() : 0) + 'ms'", "style.--kpt-anim-dir": "direction()" }, classAttribute: "kpt-stepper-host" }, queries: [{ propertyName: "steps", predicate: KptStep, isSignal: true }], ngImport: i0, template: `
3544
5427
  <ol class="kpt-stepper__header">
3545
5428
  @for (step of steps(); track $index; let i = $index, last = $last) {
3546
5429
  <li class="kpt-stepper__step" [class.is-active]="i === activeIndex()" [class.is-done]="i < activeIndex()">
@@ -3553,11 +5436,11 @@ class KptStepper {
3553
5436
  }
3554
5437
  </ol>
3555
5438
  <div class="kpt-stepper__body">
3556
- @if (activeStep(); as step) {
3557
- <ng-container [ngTemplateOutlet]="step.content()" />
5439
+ @for (step of activePanels(); track activeIndex()) {
5440
+ <div class="kpt-stepper__panel"><ng-container [ngTemplateOutlet]="step.content()" /></div>
3558
5441
  }
3559
5442
  </div>
3560
- `, isInline: true, styles: ["@layer kpt.components{.kpt-stepper-host{display:block}.kpt-stepper__header{display:flex;align-items:center;list-style:none;margin:0;padding:0}.kpt-stepper__step{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);flex:1}.kpt-stepper__step:last-child{flex:0 0 auto}.kpt-stepper__marker{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;flex-shrink:0;border:var(--kpt-border-width-medium, 2px) solid var(--kpt-color-border-strong);border-radius:50%;background:var(--kpt-color-surface);color:var(--kpt-color-on-surface-muted);font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-semibold, 600);cursor:pointer}.kpt-stepper__label{font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface-muted);white-space:nowrap}.kpt-stepper__connector{flex:1;height:2px;margin-inline:var(--kpt-space-2, .5rem);background:var(--kpt-color-border)}.kpt-stepper__step.is-active .kpt-stepper__marker{border-color:var(--kpt-color-primary);color:var(--kpt-color-primary)}.kpt-stepper__step.is-active .kpt-stepper__label{color:var(--kpt-color-on-surface);font-weight:500}.kpt-stepper__step.is-done .kpt-stepper__marker{border-color:var(--kpt-color-primary);background:var(--kpt-color-primary);color:var(--kpt-color-on-primary)}.kpt-stepper__step.is-done .kpt-stepper__connector{background:var(--kpt-color-primary)}.kpt-stepper__body{padding-block:var(--kpt-space-5, 1.25rem)}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
5443
+ `, isInline: true, styles: ["@layer kpt.components{.kpt-stepper-host{display:block}.kpt-stepper__header{display:flex;align-items:center;list-style:none;margin:0;padding:0}.kpt-stepper__step{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);flex:1}.kpt-stepper__step:last-child{flex:0 0 auto}.kpt-stepper__marker{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;flex-shrink:0;border:var(--kpt-border-width-medium, 2px) solid var(--kpt-color-border-strong);border-radius:50%;background:var(--kpt-color-surface);color:var(--kpt-color-on-surface-muted);font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-semibold, 600);cursor:pointer}.kpt-stepper__label{font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface-muted);white-space:nowrap}.kpt-stepper__connector{flex:1;height:2px;margin-inline:var(--kpt-space-2, .5rem);background:var(--kpt-color-border)}.kpt-stepper__step.is-active .kpt-stepper__marker{border-color:var(--kpt-color-primary);color:var(--kpt-color-primary)}.kpt-stepper__step.is-active .kpt-stepper__label{color:var(--kpt-color-on-surface);font-weight:500}.kpt-stepper__step.is-done .kpt-stepper__marker{border-color:var(--kpt-color-primary);background:var(--kpt-color-primary);color:var(--kpt-color-on-primary)}.kpt-stepper__step.is-done .kpt-stepper__connector{background:var(--kpt-color-primary)}.kpt-stepper__body{padding-block:var(--kpt-space-5, 1.25rem);overflow-x:clip}@keyframes kpt-stepper-enter{0%{opacity:0;transform:translate(calc(var(--kpt-anim-dir, 1) * 1.5rem))}to{opacity:1;transform:none}}.kpt-stepper__panel{animation:kpt-stepper-enter var(--kpt-anim-duration, .5s) var(--kpt-motion-easing-standard)}@media(prefers-reduced-motion:reduce){.kpt-stepper__panel{animation:none}}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3561
5444
  }
3562
5445
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptStepper, decorators: [{
3563
5446
  type: Component,
@@ -3574,12 +5457,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
3574
5457
  }
3575
5458
  </ol>
3576
5459
  <div class="kpt-stepper__body">
3577
- @if (activeStep(); as step) {
3578
- <ng-container [ngTemplateOutlet]="step.content()" />
5460
+ @for (step of activePanels(); track activeIndex()) {
5461
+ <div class="kpt-stepper__panel"><ng-container [ngTemplateOutlet]="step.content()" /></div>
3579
5462
  }
3580
5463
  </div>
3581
- `, host: { class: 'kpt-stepper-host' }, styles: ["@layer kpt.components{.kpt-stepper-host{display:block}.kpt-stepper__header{display:flex;align-items:center;list-style:none;margin:0;padding:0}.kpt-stepper__step{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);flex:1}.kpt-stepper__step:last-child{flex:0 0 auto}.kpt-stepper__marker{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;flex-shrink:0;border:var(--kpt-border-width-medium, 2px) solid var(--kpt-color-border-strong);border-radius:50%;background:var(--kpt-color-surface);color:var(--kpt-color-on-surface-muted);font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-semibold, 600);cursor:pointer}.kpt-stepper__label{font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface-muted);white-space:nowrap}.kpt-stepper__connector{flex:1;height:2px;margin-inline:var(--kpt-space-2, .5rem);background:var(--kpt-color-border)}.kpt-stepper__step.is-active .kpt-stepper__marker{border-color:var(--kpt-color-primary);color:var(--kpt-color-primary)}.kpt-stepper__step.is-active .kpt-stepper__label{color:var(--kpt-color-on-surface);font-weight:500}.kpt-stepper__step.is-done .kpt-stepper__marker{border-color:var(--kpt-color-primary);background:var(--kpt-color-primary);color:var(--kpt-color-on-primary)}.kpt-stepper__step.is-done .kpt-stepper__connector{background:var(--kpt-color-primary)}.kpt-stepper__body{padding-block:var(--kpt-space-5, 1.25rem)}}\n"] }]
3582
- }], propDecorators: { steps: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => KptStep), { isSignal: true }] }], activeIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIndex", required: false }] }, { type: i0.Output, args: ["activeIndexChange"] }] } });
5464
+ `, host: {
5465
+ 'class': 'kpt-stepper-host',
5466
+ '[style.--kpt-anim-duration]': "(animated() ? animationDuration() : 0) + 'ms'",
5467
+ '[style.--kpt-anim-dir]': 'direction()',
5468
+ }, styles: ["@layer kpt.components{.kpt-stepper-host{display:block}.kpt-stepper__header{display:flex;align-items:center;list-style:none;margin:0;padding:0}.kpt-stepper__step{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);flex:1}.kpt-stepper__step:last-child{flex:0 0 auto}.kpt-stepper__marker{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;flex-shrink:0;border:var(--kpt-border-width-medium, 2px) solid var(--kpt-color-border-strong);border-radius:50%;background:var(--kpt-color-surface);color:var(--kpt-color-on-surface-muted);font-size:var(--kpt-font-size-sm, .875rem);font-weight:var(--kpt-font-weight-semibold, 600);cursor:pointer}.kpt-stepper__label{font-size:var(--kpt-font-size-sm, .875rem);color:var(--kpt-color-on-surface-muted);white-space:nowrap}.kpt-stepper__connector{flex:1;height:2px;margin-inline:var(--kpt-space-2, .5rem);background:var(--kpt-color-border)}.kpt-stepper__step.is-active .kpt-stepper__marker{border-color:var(--kpt-color-primary);color:var(--kpt-color-primary)}.kpt-stepper__step.is-active .kpt-stepper__label{color:var(--kpt-color-on-surface);font-weight:500}.kpt-stepper__step.is-done .kpt-stepper__marker{border-color:var(--kpt-color-primary);background:var(--kpt-color-primary);color:var(--kpt-color-on-primary)}.kpt-stepper__step.is-done .kpt-stepper__connector{background:var(--kpt-color-primary)}.kpt-stepper__body{padding-block:var(--kpt-space-5, 1.25rem);overflow-x:clip}@keyframes kpt-stepper-enter{0%{opacity:0;transform:translate(calc(var(--kpt-anim-dir, 1) * 1.5rem))}to{opacity:1;transform:none}}.kpt-stepper__panel{animation:kpt-stepper-enter var(--kpt-anim-duration, .5s) var(--kpt-motion-easing-standard)}@media(prefers-reduced-motion:reduce){.kpt-stepper__panel{animation:none}}}\n"] }]
5469
+ }], propDecorators: { steps: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => KptStep), { isSignal: true }] }], activeIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIndex", required: false }] }, { type: i0.Output, args: ["activeIndexChange"] }], animated: [{ type: i0.Input, args: [{ isSignal: true, alias: "animated", required: false }] }], animationDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationDuration", required: false }] }] } });
3583
5470
 
3584
5471
  /**
3585
5472
  * Paginator Koncept UI. Sterowany sygnałami; `pageIndex` i `pageSize` są dwukierunkowe.
@@ -3665,8 +5552,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
3665
5552
  }]
3666
5553
  }], propDecorators: { kptCell: [{ type: i0.Input, args: [{ isSignal: true, alias: "kptCell", required: true }] }] } });
3667
5554
 
5555
+ /**
5556
+ * Szablon rozwijanego wiersza (row detail) dla `kpt-data-table`. Renderowany pod
5557
+ * wierszem po rozwinięciu. Kontekst: `$implicit` = wiersz. Wymaga `expandable`.
5558
+ *
5559
+ * @example
5560
+ * <kpt-data-table [columns]="cols" [data]="rows" expandable>
5561
+ * <ng-template kptRowDetail let-row>
5562
+ * <div class="szczegoly">{{ row.opis }}</div>
5563
+ * </ng-template>
5564
+ * </kpt-data-table>
5565
+ */
5566
+ class KptRowDetailDef {
5567
+ template = inject(TemplateRef);
5568
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptRowDetailDef, deps: [], target: i0.ɵɵFactoryTarget.Directive });
5569
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.0", type: KptRowDetailDef, isStandalone: true, selector: "ng-template[kptRowDetail]", ngImport: i0 });
5570
+ }
5571
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptRowDetailDef, decorators: [{
5572
+ type: Directive,
5573
+ args: [{
5574
+ selector: 'ng-template[kptRowDetail]',
5575
+ }]
5576
+ }] });
5577
+
3668
5578
  const REM_PX = 16;
3669
5579
  const CHECKBOX_FROZEN_W = 3; // rem
5580
+ const EXPANDER_FROZEN_W = 2.5; // rem
3670
5581
  /**
3671
5582
  * Flagowa tabela danych Koncept UI: kolumny konfiguracją, sortowanie,
3672
5583
  * filtr globalny, paginacja, zaznaczanie wierszy i własne szablony komórek (`kptCell`).
@@ -3687,6 +5598,9 @@ class KptDataTable {
3687
5598
  data = input([], /* @ts-ignore */
3688
5599
  ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
3689
5600
  filterable = input(false, { ...(ngDevMode ? { debugName: "filterable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
5601
+ /** Pozycja wiersza filtrów kolumn względem etykiet: nad ('top') lub pod ('bottom'). */
5602
+ filterRowPosition = input('bottom', /* @ts-ignore */
5603
+ ...(ngDevMode ? [{ debugName: "filterRowPosition" }] : /* istanbul ignore next */ []));
3690
5604
  /** Rozmiar strony; 0 wyłącza paginację. */
3691
5605
  pageSize = input(0, /* @ts-ignore */
3692
5606
  ...(ngDevMode ? [{ debugName: "pageSize" }] : /* istanbul ignore next */ []));
@@ -3720,9 +5634,16 @@ class KptDataTable {
3720
5634
  /** Łączna liczba rekordów (wymagane w trybie lazy dla paginacji). */
3721
5635
  totalRecords = input(null, /* @ts-ignore */
3722
5636
  ...(ngDevMode ? [{ debugName: "totalRecords" }] : /* istanbul ignore next */ []));
5637
+ /** Rozwijane wiersze: dodaje kolumnę z przełącznikiem i renderuje szablon `kptRowDetail`. */
5638
+ expandable = input(false, { ...(ngDevMode ? { debugName: "expandable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
5639
+ /** Zezwala na rozwinięcie wielu wierszy naraz (domyślnie tak). */
5640
+ multiExpand = input(true, { ...(ngDevMode ? { debugName: "multiExpand" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
3723
5641
  // ── Model / zdarzenia ──
3724
5642
  selection = model([], /* @ts-ignore */
3725
5643
  ...(ngDevMode ? [{ debugName: "selection" }] : /* istanbul ignore next */ []));
5644
+ /** Rozwinięte wiersze (dwukierunkowo). */
5645
+ expandedRows = model([], /* @ts-ignore */
5646
+ ...(ngDevMode ? [{ debugName: "expandedRows" }] : /* istanbul ignore next */ []));
3726
5647
  rowClick = output();
3727
5648
  /** Emitowane w trybie lazy przy zmianie sortowania/filtra/strony. */
3728
5649
  lazyLoad = output();
@@ -3737,6 +5658,11 @@ class KptDataTable {
3737
5658
  viewportHeight = signal(400, /* @ts-ignore */
3738
5659
  ...(ngDevMode ? [{ debugName: "viewportHeight" }] : /* istanbul ignore next */ []));
3739
5660
  buffer = 6;
5661
+ // ── Sticky offset drugiego wiersza nagłówka (etykiety + filtry) ──
5662
+ theadEl = viewChild('theadEl', /* @ts-ignore */
5663
+ ...(ngDevMode ? [{ debugName: "theadEl" }] : /* istanbul ignore next */ []));
5664
+ theadOffset = signal(0, /* @ts-ignore */
5665
+ ...(ngDevMode ? [{ debugName: "theadOffset" }] : /* istanbul ignore next */ []));
3740
5666
  constructor() {
3741
5667
  // Tryb lazy: przy każdej zmianie stanu poproś rodzica o dane.
3742
5668
  effect(() => {
@@ -3748,6 +5674,7 @@ class KptDataTable {
3748
5674
  sortField: this.sortField(),
3749
5675
  sortDir: this.sortDir(),
3750
5676
  filter: this.filterText(),
5677
+ columnFilters: this.columnFilters(),
3751
5678
  });
3752
5679
  });
3753
5680
  // Zmierz wysokość viewportu dla wirtualizacji.
@@ -3756,6 +5683,15 @@ class KptDataTable {
3756
5683
  if (el)
3757
5684
  this.viewportHeight.set(el.clientHeight);
3758
5685
  });
5686
+ // Zmierz wysokość pierwszego wiersza nagłówka → offset sticky drugiego wiersza.
5687
+ afterRenderEffect(() => {
5688
+ this.filterRowPosition();
5689
+ this.hasColumnFilters();
5690
+ this.orderedColumns();
5691
+ const first = this.theadEl()?.nativeElement?.rows?.[0];
5692
+ if (first)
5693
+ this.theadOffset.set(first.offsetHeight);
5694
+ });
3759
5695
  }
3760
5696
  onScroll(event) {
3761
5697
  if (!this.virtualScroll())
@@ -3781,14 +5717,32 @@ class KptDataTable {
3781
5717
  // ── Przestawianie kolumn (natywny HTML5 drag-and-drop; działa w trybie zoneless) ──
3782
5718
  dragIndex = signal(null, /* @ts-ignore */
3783
5719
  ...(ngDevMode ? [{ debugName: "dragIndex" }] : /* istanbul ignore next */ []));
5720
+ /** Kolumna przeciągalna tylko gdy `reorderable` i nie jest zamrożona (frozen musi zostać wiodąca). */
5721
+ isColDraggable(col) {
5722
+ return this.reorderable() && !col.frozen;
5723
+ }
5724
+ /** Liczba wiodących kolumn zamrożonych — poza nie wolno upuszczać ani ich przesuwać. */
5725
+ frozenLeadCount() {
5726
+ let n = 0;
5727
+ for (const col of this.orderedColumns()) {
5728
+ if (col.frozen)
5729
+ n++;
5730
+ else
5731
+ break;
5732
+ }
5733
+ return n;
5734
+ }
3784
5735
  onColDragStart(index, event) {
5736
+ if (this.orderedColumns()[index]?.frozen)
5737
+ return; // frozen nieprzeciągalne
3785
5738
  this.dragIndex.set(index);
3786
5739
  event.dataTransfer?.setData('text/plain', String(index));
3787
5740
  if (event.dataTransfer)
3788
5741
  event.dataTransfer.effectAllowed = 'move';
3789
5742
  }
3790
- onColDragOver(event) {
3791
- if (this.dragIndex() !== null)
5743
+ onColDragOver(index, event) {
5744
+ // Zezwól na upuszczenie tylko poza obszarem kolumn zamrożonych.
5745
+ if (this.dragIndex() !== null && index >= this.frozenLeadCount())
3792
5746
  event.preventDefault();
3793
5747
  }
3794
5748
  onColDrop(index, event) {
@@ -3796,6 +5750,8 @@ class KptDataTable {
3796
5750
  const from = this.dragIndex();
3797
5751
  if (from === null || from === index)
3798
5752
  return;
5753
+ if (index < this.frozenLeadCount())
5754
+ return; // nie wsuwaj przed/pomiędzy kolumny zamrożone
3799
5755
  const cols = [...this.orderedColumns()];
3800
5756
  const [moved] = cols.splice(from, 1);
3801
5757
  cols.splice(index, 0, moved);
@@ -3839,9 +5795,30 @@ class KptDataTable {
3839
5795
  cellTemplate(field) {
3840
5796
  return this.cellMap().get(field) ?? null;
3841
5797
  }
5798
+ // ── Rozwijane wiersze ──
5799
+ rowDetailDef = contentChild(KptRowDetailDef, /* @ts-ignore */
5800
+ ...(ngDevMode ? [{ debugName: "rowDetailDef" }] : /* istanbul ignore next */ []));
5801
+ rowDetailTpl = computed(() => this.rowDetailDef()?.template ?? null, /* @ts-ignore */
5802
+ ...(ngDevMode ? [{ debugName: "rowDetailTpl" }] : /* istanbul ignore next */ []));
5803
+ /** Kolumna z przełącznikiem widoczna, gdy włączono `expandable` i podano szablon `kptRowDetail`. */
5804
+ hasRowDetail = computed(() => this.expandable() && !!this.rowDetailDef(), /* @ts-ignore */
5805
+ ...(ngDevMode ? [{ debugName: "hasRowDetail" }] : /* istanbul ignore next */ []));
5806
+ isExpanded(row) {
5807
+ return this.expandedRows().some((r) => this.sameRow(r, row));
5808
+ }
5809
+ toggleExpand(row) {
5810
+ if (this.isExpanded(row)) {
5811
+ this.expandedRows.set(this.expandedRows().filter((r) => !this.sameRow(r, row)));
5812
+ }
5813
+ else {
5814
+ this.expandedRows.set(this.multiExpand() ? [...this.expandedRows(), row] : [row]);
5815
+ }
5816
+ }
3842
5817
  // ── Stan ──
3843
5818
  filterText = signal('', /* @ts-ignore */
3844
5819
  ...(ngDevMode ? [{ debugName: "filterText" }] : /* istanbul ignore next */ []));
5820
+ columnFilters = signal({}, /* @ts-ignore */
5821
+ ...(ngDevMode ? [{ debugName: "columnFilters" }] : /* istanbul ignore next */ []));
3845
5822
  sortField = signal(null, /* @ts-ignore */
3846
5823
  ...(ngDevMode ? [{ debugName: "sortField" }] : /* istanbul ignore next */ []));
3847
5824
  sortDir = signal(null, /* @ts-ignore */
@@ -3850,14 +5827,118 @@ class KptDataTable {
3850
5827
  ...(ngDevMode ? [{ debugName: "pageIndex" }] : /* istanbul ignore next */ []));
3851
5828
  pageSizeState = linkedSignal(() => this.pageSize() || 10, /* @ts-ignore */
3852
5829
  ...(ngDevMode ? [{ debugName: "pageSizeState" }] : /* istanbul ignore next */ []));
5830
+ hasColumnFilters = computed(() => this.columns().some((c) => c.filter), /* @ts-ignore */
5831
+ ...(ngDevMode ? [{ debugName: "hasColumnFilters" }] : /* istanbul ignore next */ []));
5832
+ // ── Filtry kolumn ──
5833
+ setColumnFilter(field, value) {
5834
+ this.columnFilters.update((cur) => ({ ...cur, [field]: value }));
5835
+ this.pageIndex.set(0);
5836
+ }
5837
+ /** Input liczbowy — pozostaw tylko cyfry i zsynchronizuj DOM z wartością. */
5838
+ onNumberFilter(field, event) {
5839
+ const el = event.target;
5840
+ const digits = el.value.replace(/\D/g, '');
5841
+ el.value = digits;
5842
+ this.setColumnFilter(field, digits);
5843
+ }
5844
+ /** Bieżąca wartość filtra zakresu liczbowego (min/max) dla kolumny. */
5845
+ rangeVal(field) {
5846
+ const v = this.columnFilters()[field];
5847
+ return { min: v?.min ?? '', max: v?.max ?? '' };
5848
+ }
5849
+ /** Aktualizuj jedną granicę zakresu (min/max), pozostawiając tylko cyfry. */
5850
+ setRangeFilter(field, bound, event) {
5851
+ const el = event.target;
5852
+ const digits = el.value.replace(/\D/g, '');
5853
+ el.value = digits;
5854
+ this.setColumnFilter(field, { ...this.rangeVal(field), [bound]: digits });
5855
+ }
5856
+ /** Bieżąca para `[lo, hi]` filtra suwakowego dla kolumny (domyślnie pełen zakres). */
5857
+ sliderVal(col) {
5858
+ const mn = col.filter?.min ?? 0;
5859
+ const mx = col.filter?.max ?? 100;
5860
+ const v = this.columnFilters()[col.field];
5861
+ return v ?? [mn, mx];
5862
+ }
5863
+ static toIso(value) {
5864
+ if (value instanceof Date) {
5865
+ const p = (n) => String(n).padStart(2, '0');
5866
+ return `${value.getFullYear()}-${p(value.getMonth() + 1)}-${p(value.getDate())}`;
5867
+ }
5868
+ return String(value ?? '');
5869
+ }
5870
+ matchesColumnFilters(row) {
5871
+ const filters = this.columnFilters();
5872
+ return this.columns().every((col) => {
5873
+ const f = col.filter;
5874
+ if (!f)
5875
+ return true;
5876
+ const fv = filters[col.field];
5877
+ if (fv == null || fv === '' || (Array.isArray(fv) && fv.length === 0))
5878
+ return true;
5879
+ const cell = row[col.field];
5880
+ switch (f.type) {
5881
+ case 'text':
5882
+ return String(cell ?? '').toLowerCase().includes(String(fv).toLowerCase());
5883
+ case 'number':
5884
+ return String(cell ?? '').includes(String(fv));
5885
+ case 'select': {
5886
+ const vals = Array.isArray(fv) ? fv : [fv];
5887
+ // Komórka-tablica (np. lista tagów/członków) → dopasuj, gdy zawiera dowolną z wybranych wartości.
5888
+ if (Array.isArray(cell))
5889
+ return cell.some((c) => vals.includes(c));
5890
+ return vals.includes(cell);
5891
+ }
5892
+ case 'numberRange': {
5893
+ const { min, max } = fv ?? {};
5894
+ const hasMin = min != null && min !== '';
5895
+ const hasMax = max != null && max !== '';
5896
+ if (!hasMin && !hasMax)
5897
+ return true;
5898
+ const num = typeof cell === 'number' ? cell : parseFloat(String(cell ?? ''));
5899
+ if (Number.isNaN(num))
5900
+ return false;
5901
+ if (hasMin && num < parseFloat(min))
5902
+ return false;
5903
+ if (hasMax && num > parseFloat(max))
5904
+ return false;
5905
+ return true;
5906
+ }
5907
+ case 'slider': {
5908
+ const [lo, hi] = fv;
5909
+ const num = typeof cell === 'number' ? cell : parseFloat(String(cell ?? ''));
5910
+ if (Number.isNaN(num))
5911
+ return false;
5912
+ return num >= lo && num <= hi;
5913
+ }
5914
+ case 'dateRange': {
5915
+ const { start, end } = fv ?? { start: '', end: '' };
5916
+ if (!start && !end)
5917
+ return true;
5918
+ const iso = KptDataTable.toIso(cell);
5919
+ if (start && iso < start)
5920
+ return false;
5921
+ if (end && iso > end)
5922
+ return false;
5923
+ return true;
5924
+ }
5925
+ default:
5926
+ return true;
5927
+ }
5928
+ });
5929
+ }
3853
5930
  // ── Potok przetwarzania danych ──
3854
5931
  filtered = computed(() => {
3855
5932
  const query = this.filterText().trim().toLowerCase();
3856
- const rows = this.data();
3857
- if (!query)
3858
- return rows;
3859
5933
  const cols = this.columns();
3860
- return rows.filter((row) => cols.some((col) => String(row[col.field] ?? '').toLowerCase().includes(query)));
5934
+ let rows = this.data();
5935
+ if (query) {
5936
+ rows = rows.filter((row) => cols.some((col) => String(row[col.field] ?? '').toLowerCase().includes(query)));
5937
+ }
5938
+ if (this.hasColumnFilters()) {
5939
+ rows = rows.filter((row) => this.matchesColumnFilters(row));
5940
+ }
5941
+ return rows;
3861
5942
  }, /* @ts-ignore */
3862
5943
  ...(ngDevMode ? [{ debugName: "filtered" }] : /* istanbul ignore next */ []));
3863
5944
  sorted = computed(() => {
@@ -3893,7 +5974,9 @@ class KptDataTable {
3893
5974
  return rows.slice(start, start + size);
3894
5975
  }, /* @ts-ignore */
3895
5976
  ...(ngDevMode ? [{ debugName: "paged" }] : /* istanbul ignore next */ []));
3896
- colspan = computed(() => this.columns().length + (this.selectable() !== 'none' ? 1 : 0), /* @ts-ignore */
5977
+ colspan = computed(() => this.columns().length +
5978
+ (this.selectable() !== 'none' ? 1 : 0) +
5979
+ (this.hasRowDetail() ? 1 : 0), /* @ts-ignore */
3897
5980
  ...(ngDevMode ? [{ debugName: "colspan" }] : /* istanbul ignore next */ []));
3898
5981
  displayCount = computed(() => this.virtualScroll() ? this.sorted().length : this.paged().length, /* @ts-ignore */
3899
5982
  ...(ngDevMode ? [{ debugName: "displayCount" }] : /* istanbul ignore next */ []));
@@ -3907,9 +5990,19 @@ class KptDataTable {
3907
5990
  return width.trim().endsWith('px') ? n : n * REM_PX;
3908
5991
  }
3909
5992
  /** Mapa pole → przesunięcie left (px) dla wiodących zamrożonych kolumn. */
5993
+ /** Suma szerokości wiodących kolumn systemowych (rozwijanie + zaznaczanie) w px. */
5994
+ leadingStickyWidth = computed(() => {
5995
+ let acc = 0;
5996
+ if (this.hasRowDetail())
5997
+ acc += EXPANDER_FROZEN_W * REM_PX;
5998
+ if (this.selectable() !== 'none')
5999
+ acc += CHECKBOX_FROZEN_W * REM_PX;
6000
+ return acc;
6001
+ }, /* @ts-ignore */
6002
+ ...(ngDevMode ? [{ debugName: "leadingStickyWidth" }] : /* istanbul ignore next */ []));
3910
6003
  frozenOffsets = computed(() => {
3911
6004
  const map = new Map();
3912
- let acc = this.selectable() !== 'none' ? CHECKBOX_FROZEN_W * REM_PX : 0;
6005
+ let acc = this.leadingStickyWidth();
3913
6006
  for (const col of this.orderedColumns()) {
3914
6007
  if (!col.frozen)
3915
6008
  break; // tylko wiodące, sąsiadujące
@@ -3921,6 +6014,16 @@ class KptDataTable {
3921
6014
  ...(ngDevMode ? [{ debugName: "frozenOffsets" }] : /* istanbul ignore next */ []));
3922
6015
  hasFrozen = computed(() => this.frozenOffsets().size > 0, /* @ts-ignore */
3923
6016
  ...(ngDevMode ? [{ debugName: "hasFrozen" }] : /* istanbul ignore next */ []));
6017
+ /** Sticky-left kolumny rozwijania (px) — 0, gdy tabela ma kolumny zamrożone. */
6018
+ expanderStickyLeft = computed(() => (this.hasFrozen() ? 0 : null), /* @ts-ignore */
6019
+ ...(ngDevMode ? [{ debugName: "expanderStickyLeft" }] : /* istanbul ignore next */ []));
6020
+ /** Sticky-left kolumny zaznaczania (px) — za kolumną rozwijania, jeśli obecna. */
6021
+ checkboxStickyLeft = computed(() => {
6022
+ if (!this.hasFrozen())
6023
+ return null;
6024
+ return this.hasRowDetail() ? EXPANDER_FROZEN_W * REM_PX : 0;
6025
+ }, /* @ts-ignore */
6026
+ ...(ngDevMode ? [{ debugName: "checkboxStickyLeft" }] : /* istanbul ignore next */ []));
3924
6027
  frozenLeft(field) {
3925
6028
  return this.frozenOffsets().get(field) ?? null;
3926
6029
  }
@@ -3985,6 +6088,11 @@ class KptDataTable {
3985
6088
  return page.length > 0 && page.every((r) => this.isSelected(r));
3986
6089
  }, /* @ts-ignore */
3987
6090
  ...(ngDevMode ? [{ debugName: "pageAllSelected" }] : /* istanbul ignore next */ []));
6091
+ pageSomeSelected = computed(() => {
6092
+ const page = this.paged();
6093
+ return page.some((r) => this.isSelected(r)) && !this.pageAllSelected();
6094
+ }, /* @ts-ignore */
6095
+ ...(ngDevMode ? [{ debugName: "pageSomeSelected" }] : /* istanbul ignore next */ []));
3988
6096
  toggleAllOnPage() {
3989
6097
  const page = this.paged();
3990
6098
  if (this.pageAllSelected()) {
@@ -4007,12 +6115,15 @@ class KptDataTable {
4007
6115
  return key ? row[key] : row;
4008
6116
  };
4009
6117
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptDataTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
4010
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptDataTable, isStandalone: true, selector: "kpt-data-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, filterable: { classPropertyName: "filterable", publicName: "filterable", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, rowKey: { classPropertyName: "rowKey", publicName: "rowKey", isSignal: true, isRequired: false, transformFunction: null }, scrollHeight: { classPropertyName: "scrollHeight", publicName: "scrollHeight", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, reorderable: { classPropertyName: "reorderable", publicName: "reorderable", isSignal: true, isRequired: false, transformFunction: null }, exportable: { classPropertyName: "exportable", publicName: "exportable", isSignal: true, isRequired: false, transformFunction: null }, exportFilename: { classPropertyName: "exportFilename", publicName: "exportFilename", isSignal: true, isRequired: false, transformFunction: null }, lazy: { classPropertyName: "lazy", publicName: "lazy", isSignal: true, isRequired: false, transformFunction: null }, totalRecords: { classPropertyName: "totalRecords", publicName: "totalRecords", isSignal: true, isRequired: false, transformFunction: null }, selection: { classPropertyName: "selection", publicName: "selection", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selection: "selectionChange", rowClick: "rowClick", lazyLoad: "lazyLoad" }, host: { classAttribute: "kpt-data-table" }, queries: [{ propertyName: "cellDefs", predicate: KptCellDef, isSignal: true }], viewQueries: [{ propertyName: "scrollEl", first: true, predicate: ["scrollEl"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (filterable() || exportable()) {\n <div class=\"kpt-data-table__toolbar\">\n @if (filterable()) {\n <input\n class=\"kpt-data-table__filter\"\n type=\"search\"\n placeholder=\"Szukaj\u2026\"\n [value]=\"filterText()\"\n (input)=\"onFilter($event)\"\n />\n }\n @if (exportable()) {\n <kpt-button variant=\"outline\" size=\"sm\" (click)=\"exportCsv()\">Eksport CSV</kpt-button>\n }\n </div>\n}\n\n<div class=\"kpt-data-table__scroll\" #scrollEl [style.max-height]=\"scrollHeight()\" (scroll)=\"onScroll($event)\">\n <table\n class=\"kpt-data-table__table\"\n [class.kpt-data-table__table--frozen]=\"hasFrozen()\"\n [class.kpt-data-table__table--virtual]=\"virtualScroll()\"\n >\n <thead>\n <tr>\n @if (selectable() === 'multiple') {\n <th class=\"kpt-data-table__checkbox\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"hasFrozen() ? 0 : null\">\n <input type=\"checkbox\" [checked]=\"pageAllSelected()\" (change)=\"toggleAllOnPage()\" aria-label=\"Zaznacz wszystkie\" />\n </th>\n } @else if (selectable() === 'single') {\n <th class=\"kpt-data-table__checkbox\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"hasFrozen() ? 0 : null\"></th>\n }\n @for (col of orderedColumns(); track col.field; let i = $index) {\n <th\n [attr.draggable]=\"reorderable() ? true : null\"\n [style.width]=\"col.width\"\n [style.left.px]=\"frozenLeft(col.field)\"\n [attr.data-align]=\"col.align ?? 'start'\"\n [class.kpt-data-table__cell--frozen]=\"isFrozen(col.field)\"\n [class.kpt-data-table__th--sortable]=\"col.sortable\"\n [class.kpt-data-table__th--draggable]=\"reorderable()\"\n [class.kpt-data-table__th--dragover]=\"dragIndex() !== null && dragIndex() !== i\"\n [attr.aria-sort]=\"ariaSort(col)\"\n (click)=\"toggleSort(col)\"\n (dragstart)=\"reorderable() ? onColDragStart(i, $event) : null\"\n (dragover)=\"reorderable() ? onColDragOver($event) : null\"\n (drop)=\"reorderable() ? onColDrop(i, $event) : null\"\n (dragend)=\"onColDragEnd()\"\n >\n @if (reorderable()) {\n <kpt-icon class=\"kpt-data-table__grip\" name=\"grip-vertical\" />\n }\n <span>{{ col.header }}</span>\n @if (col.sortable) {\n <kpt-icon\n class=\"kpt-data-table__sort\"\n [class.kpt-data-table__sort--active]=\"ariaSort(col) !== 'none'\"\n [name]=\"sortIconName(col)\"\n />\n }\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (loading()) {\n <tr><td class=\"kpt-data-table__state\" [attr.colspan]=\"colspan()\">\u0141adowanie\u2026</td></tr>\n } @else if (displayCount() === 0) {\n <tr><td class=\"kpt-data-table__state\" [attr.colspan]=\"colspan()\">{{ emptyMessage() }}</td></tr>\n } @else if (virtualScroll()) {\n @if (topPad() > 0) {\n <tr class=\"kpt-data-table__spacer\" aria-hidden=\"true\"><td [attr.colspan]=\"colspan()\" [style.height.px]=\"topPad()\"></td></tr>\n }\n @for (row of virtualRows(); track trackRow(row)) {\n <ng-container [ngTemplateOutlet]=\"rowTpl\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n @if (bottomPad() > 0) {\n <tr class=\"kpt-data-table__spacer\" aria-hidden=\"true\"><td [attr.colspan]=\"colspan()\" [style.height.px]=\"bottomPad()\"></td></tr>\n }\n } @else {\n @for (row of paged(); track trackRow(row)) {\n <ng-container [ngTemplateOutlet]=\"rowTpl\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n }\n </tbody>\n </table>\n</div>\n\n<ng-template #rowTpl let-row>\n <tr\n [class.kpt-data-table__row--selected]=\"isSelected(row)\"\n [style.height.px]=\"virtualScroll() ? rowHeight() : null\"\n (click)=\"onRowClick(row)\"\n >\n @if (selectable() !== 'none') {\n <td class=\"kpt-data-table__checkbox\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"hasFrozen() ? 0 : null\">\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(row)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n aria-label=\"Zaznacz wiersz\"\n />\n </td>\n }\n @for (col of orderedColumns(); track col.field) {\n <td\n [attr.data-align]=\"col.align ?? 'start'\"\n [style.left.px]=\"frozenLeft(col.field)\"\n [class.kpt-data-table__cell--frozen]=\"isFrozen(col.field)\"\n >\n @if (cellTemplate(col.field); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: row, value: getValue(row, col.field) }\"\n />\n } @else {\n {{ getValue(row, col.field) }}\n }\n </td>\n }\n </tr>\n</ng-template>\n\n@if (pageSize() > 0 && !virtualScroll()) {\n <kpt-paginator\n [length]=\"filteredCount()\"\n [pageIndex]=\"pageIndex()\"\n (pageIndexChange)=\"pageIndex.set($event)\"\n [pageSize]=\"pageSizeState()\"\n (pageSizeChange)=\"pageSizeState.set($event)\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n />\n}\n", styles: ["@layer kpt.components{.kpt-data-table{display:flex;flex-direction:column;background:var(--kpt-table-bg);color:var(--kpt-table-fg);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border);border-radius:var(--kpt-table-radius, .75rem);overflow:hidden}.kpt-data-table__toolbar{display:flex;align-items:center;justify-content:space-between;gap:var(--kpt-space-3, .75rem);padding:var(--kpt-space-3, .75rem);border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border)}.kpt-data-table__filter{width:100%;max-width:20rem;height:2.25rem;padding-inline:var(--kpt-space-3, .75rem);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text)}.kpt-data-table__filter:focus-visible{outline:none;border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-data-table__scroll{overflow:auto}.kpt-data-table__table{width:100%;border-collapse:collapse;font-size:var(--kpt-font-size-sm, .875rem)}.kpt-data-table__table--frozen{width:max-content;min-width:100%}.kpt-data-table__table th,.kpt-data-table__table td{padding:var(--kpt-table-cell-padding, .75rem);text-align:start;border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border)}.kpt-data-table__table th[data-align=center],.kpt-data-table__table td[data-align=center]{text-align:center}.kpt-data-table__table th[data-align=end],.kpt-data-table__table td[data-align=end]{text-align:end}.kpt-data-table__table thead th{position:sticky;top:0;z-index:1;background:var(--kpt-table-header-bg);color:var(--kpt-table-header-fg);font-weight:var(--kpt-font-weight-semibold, 600);white-space:nowrap;-webkit-user-select:none;user-select:none}.kpt-data-table__th--sortable{cursor:pointer}.kpt-data-table__th--sortable:hover{color:var(--kpt-color-on-surface)}.kpt-data-table__sort{margin-inline-start:.35em;opacity:.35}.kpt-data-table__sort--active{opacity:1}.kpt-data-table__th--draggable{cursor:grab}.kpt-data-table__th--draggable:active{cursor:grabbing}.kpt-data-table__th--dragover{box-shadow:inset 2px 0 0 0 var(--kpt-color-primary)}.kpt-data-table__grip{margin-inline-end:.4em;opacity:.45}.kpt-data-table__checkbox{width:1px;white-space:nowrap;text-align:center}.kpt-data-table tbody tr{transition:background-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-data-table tbody tr:hover{background:var(--kpt-table-row-hover)}.kpt-data-table__row--selected{background:var(--kpt-table-row-selected)!important}.kpt-data-table__table--frozen .kpt-data-table__checkbox{width:3rem;min-width:3rem}.kpt-data-table__cell--frozen{position:sticky;z-index:1;background:var(--kpt-table-bg);border-inline-end:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border)}.kpt-data-table thead th.kpt-data-table__cell--frozen{z-index:3;background:var(--kpt-table-header-bg)}.kpt-data-table tbody tr:hover .kpt-data-table__cell--frozen{background:var(--kpt-table-row-hover)}.kpt-data-table__row--selected.kpt-data-table__row--selected .kpt-data-table__cell--frozen,.kpt-data-table tbody tr.kpt-data-table__row--selected .kpt-data-table__cell--frozen{background:var(--kpt-table-row-selected)}.kpt-data-table__state{padding:var(--kpt-space-8, 2rem)!important;text-align:center!important;color:var(--kpt-color-on-surface-muted)}.kpt-data-table__table--virtual td{padding-block:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.kpt-data-table__spacer td{padding:0!important;border:0!important}.kpt-data-table tbody tr:last-child td{border-bottom:0}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: KptButton, selector: "kpt-button", inputs: ["variant", "size", "type", "disabled", "loading", "fullWidth"] }, { kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }, { kind: "component", type: KptPaginator, selector: "kpt-paginator", inputs: ["length", "pageSize", "pageIndex", "pageSizeOptions"], outputs: ["pageSizeChange", "pageIndexChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
6118
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptDataTable, isStandalone: true, selector: "kpt-data-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, filterable: { classPropertyName: "filterable", publicName: "filterable", isSignal: true, isRequired: false, transformFunction: null }, filterRowPosition: { classPropertyName: "filterRowPosition", publicName: "filterRowPosition", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, rowKey: { classPropertyName: "rowKey", publicName: "rowKey", isSignal: true, isRequired: false, transformFunction: null }, scrollHeight: { classPropertyName: "scrollHeight", publicName: "scrollHeight", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, reorderable: { classPropertyName: "reorderable", publicName: "reorderable", isSignal: true, isRequired: false, transformFunction: null }, exportable: { classPropertyName: "exportable", publicName: "exportable", isSignal: true, isRequired: false, transformFunction: null }, exportFilename: { classPropertyName: "exportFilename", publicName: "exportFilename", isSignal: true, isRequired: false, transformFunction: null }, lazy: { classPropertyName: "lazy", publicName: "lazy", isSignal: true, isRequired: false, transformFunction: null }, totalRecords: { classPropertyName: "totalRecords", publicName: "totalRecords", isSignal: true, isRequired: false, transformFunction: null }, expandable: { classPropertyName: "expandable", publicName: "expandable", isSignal: true, isRequired: false, transformFunction: null }, multiExpand: { classPropertyName: "multiExpand", publicName: "multiExpand", isSignal: true, isRequired: false, transformFunction: null }, selection: { classPropertyName: "selection", publicName: "selection", isSignal: true, isRequired: false, transformFunction: null }, expandedRows: { classPropertyName: "expandedRows", publicName: "expandedRows", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selection: "selectionChange", expandedRows: "expandedRowsChange", rowClick: "rowClick", lazyLoad: "lazyLoad" }, host: { properties: { "style.--kpt-thead-offset": "theadOffset() + 'px'" }, classAttribute: "kpt-data-table" }, queries: [{ propertyName: "cellDefs", predicate: KptCellDef, isSignal: true }, { propertyName: "rowDetailDef", first: true, predicate: KptRowDetailDef, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "scrollEl", first: true, predicate: ["scrollEl"], descendants: true, isSignal: true }, { propertyName: "theadEl", first: true, predicate: ["theadEl"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (filterable() || exportable()) {\n <div class=\"kpt-data-table__toolbar\">\n @if (filterable()) {\n <input\n class=\"kpt-data-table__filter\"\n type=\"search\"\n placeholder=\"Szukaj\u2026\"\n [value]=\"filterText()\"\n (input)=\"onFilter($event)\"\n />\n }\n @if (exportable()) {\n <kpt-button variant=\"outline\" size=\"sm\" (click)=\"exportCsv()\">Eksport CSV</kpt-button>\n }\n </div>\n}\n\n<div class=\"kpt-data-table__scroll\" #scrollEl [style.max-height]=\"scrollHeight()\" (scroll)=\"onScroll($event)\">\n <table\n class=\"kpt-data-table__table\"\n [class.kpt-data-table__table--frozen]=\"hasFrozen()\"\n [class.kpt-data-table__table--virtual]=\"virtualScroll()\"\n >\n <thead #theadEl>\n @if (hasColumnFilters() && filterRowPosition() === 'top') {\n <ng-container [ngTemplateOutlet]=\"filterRowTpl\" />\n }\n <tr>\n @if (hasRowDetail()) {\n <th class=\"kpt-data-table__expander\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"expanderStickyLeft()\"></th>\n }\n @if (selectable() === 'multiple') {\n <th class=\"kpt-data-table__checkbox\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"checkboxStickyLeft()\">\n <input\n type=\"checkbox\"\n [checked]=\"pageAllSelected()\"\n [indeterminate]=\"pageSomeSelected()\"\n (change)=\"toggleAllOnPage()\"\n aria-label=\"Zaznacz wszystkie\"\n />\n </th>\n } @else if (selectable() === 'single') {\n <th class=\"kpt-data-table__checkbox\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"checkboxStickyLeft()\"></th>\n }\n @for (col of orderedColumns(); track col.field; let i = $index) {\n <th\n [attr.draggable]=\"isColDraggable(col) ? true : null\"\n [style.width]=\"col.width\"\n [style.left.px]=\"frozenLeft(col.field)\"\n [attr.data-align]=\"col.align ?? 'start'\"\n [class.kpt-data-table__cell--frozen]=\"isFrozen(col.field)\"\n [class.kpt-data-table__th--sortable]=\"col.sortable\"\n [class.kpt-data-table__th--draggable]=\"isColDraggable(col)\"\n [class.kpt-data-table__th--dragover]=\"dragIndex() !== null && dragIndex() !== i && !col.frozen\"\n [attr.aria-sort]=\"ariaSort(col)\"\n (click)=\"toggleSort(col)\"\n (dragstart)=\"onColDragStart(i, $event)\"\n (dragover)=\"reorderable() ? onColDragOver(i, $event) : null\"\n (drop)=\"reorderable() ? onColDrop(i, $event) : null\"\n (dragend)=\"onColDragEnd()\"\n >\n @if (isColDraggable(col)) {\n <kpt-icon class=\"kpt-data-table__grip\" name=\"grip-vertical\" />\n }\n <span>{{ col.header }}</span>\n @if (col.sortable) {\n <kpt-icon\n class=\"kpt-data-table__sort\"\n [class.kpt-data-table__sort--active]=\"ariaSort(col) !== 'none'\"\n [name]=\"sortIconName(col)\"\n />\n }\n </th>\n }\n </tr>\n @if (hasColumnFilters() && filterRowPosition() === 'bottom') {\n <ng-container [ngTemplateOutlet]=\"filterRowTpl\" />\n }\n </thead>\n <tbody>\n @if (loading()) {\n <tr><td class=\"kpt-data-table__state\" [attr.colspan]=\"colspan()\">\u0141adowanie\u2026</td></tr>\n } @else if (displayCount() === 0) {\n <tr><td class=\"kpt-data-table__state\" [attr.colspan]=\"colspan()\">{{ emptyMessage() }}</td></tr>\n } @else if (virtualScroll()) {\n @if (topPad() > 0) {\n <tr class=\"kpt-data-table__spacer\" aria-hidden=\"true\"><td [attr.colspan]=\"colspan()\" [style.height.px]=\"topPad()\"></td></tr>\n }\n @for (row of virtualRows(); track trackRow(row)) {\n <ng-container [ngTemplateOutlet]=\"rowTpl\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n @if (bottomPad() > 0) {\n <tr class=\"kpt-data-table__spacer\" aria-hidden=\"true\"><td [attr.colspan]=\"colspan()\" [style.height.px]=\"bottomPad()\"></td></tr>\n }\n } @else {\n @for (row of paged(); track trackRow(row)) {\n <ng-container [ngTemplateOutlet]=\"rowTpl\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n }\n </tbody>\n </table>\n</div>\n\n<ng-template #rowTpl let-row>\n <tr\n [class.kpt-data-table__row--selected]=\"isSelected(row)\"\n [class.kpt-data-table__row--expanded]=\"hasRowDetail() && isExpanded(row)\"\n [style.height.px]=\"virtualScroll() ? rowHeight() : null\"\n (click)=\"onRowClick(row)\"\n >\n @if (hasRowDetail()) {\n <td class=\"kpt-data-table__expander\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"expanderStickyLeft()\">\n <button\n type=\"button\"\n class=\"kpt-data-table__expander-btn\"\n [class.kpt-data-table__expander-btn--open]=\"isExpanded(row)\"\n [attr.aria-expanded]=\"isExpanded(row)\"\n aria-label=\"Rozwi\u0144 wiersz\"\n (click)=\"$event.stopPropagation(); toggleExpand(row)\"\n >\n <kpt-icon name=\"chevron-right\" />\n </button>\n </td>\n }\n @if (selectable() !== 'none') {\n <td class=\"kpt-data-table__checkbox\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"checkboxStickyLeft()\">\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(row)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n aria-label=\"Zaznacz wiersz\"\n />\n </td>\n }\n @for (col of orderedColumns(); track col.field) {\n <td\n [attr.data-align]=\"col.align ?? 'start'\"\n [style.left.px]=\"frozenLeft(col.field)\"\n [class.kpt-data-table__cell--frozen]=\"isFrozen(col.field)\"\n >\n @if (cellTemplate(col.field); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: row, value: getValue(row, col.field) }\"\n />\n } @else {\n {{ getValue(row, col.field) }}\n }\n </td>\n }\n </tr>\n @if (hasRowDetail() && isExpanded(row) && !virtualScroll()) {\n <tr class=\"kpt-data-table__detail-row\">\n <td class=\"kpt-data-table__detail\" [attr.colspan]=\"colspan()\">\n <ng-container [ngTemplateOutlet]=\"rowDetailTpl()\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n </td>\n </tr>\n }\n</ng-template>\n\n<ng-template #filterRowTpl>\n <tr class=\"kpt-data-table__filter-row\">\n @if (hasRowDetail()) {\n <th class=\"kpt-data-table__expander\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"expanderStickyLeft()\"></th>\n }\n @if (selectable() !== 'none') {\n <th class=\"kpt-data-table__checkbox\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"checkboxStickyLeft()\"></th>\n }\n @for (col of orderedColumns(); track col.field) {\n <th\n [style.width]=\"col.width\"\n [style.left.px]=\"frozenLeft(col.field)\"\n [attr.data-align]=\"col.align ?? 'start'\"\n [class.kpt-data-table__cell--frozen]=\"isFrozen(col.field)\"\n >\n @switch (col.filter?.type) {\n @case ('text') {\n <input\n class=\"kpt-data-table__fcell\"\n type=\"search\"\n [attr.placeholder]=\"col.filter?.placeholder || ''\"\n [attr.aria-label]=\"'Filtr: ' + col.header\"\n [value]=\"$any(columnFilters()[col.field]) || ''\"\n (input)=\"setColumnFilter(col.field, $any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n @case ('number') {\n <input\n class=\"kpt-data-table__fcell\"\n type=\"text\"\n inputmode=\"numeric\"\n [attr.placeholder]=\"col.filter?.placeholder || ''\"\n [attr.aria-label]=\"'Filtr: ' + col.header\"\n [value]=\"$any(columnFilters()[col.field]) || ''\"\n (input)=\"onNumberFilter(col.field, $event)\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n @case ('select') {\n <kpt-select\n [options]=\"col.filter?.options || []\"\n [multiple]=\"!!col.filter?.multiple\"\n filter\n [placeholder]=\"col.filter?.placeholder || 'Wszystkie'\"\n [value]=\"columnFilters()[col.field] ?? null\"\n (valueChange)=\"setColumnFilter(col.field, $event)\"\n />\n }\n @case ('numberRange') {\n <div class=\"kpt-data-table__frange\">\n <input\n class=\"kpt-data-table__fcell\"\n type=\"text\"\n inputmode=\"numeric\"\n placeholder=\"min\"\n [attr.aria-label]=\"'Filtr min: ' + col.header\"\n [value]=\"rangeVal(col.field).min\"\n (input)=\"setRangeFilter(col.field, 'min', $event)\"\n (click)=\"$event.stopPropagation()\"\n />\n <input\n class=\"kpt-data-table__fcell\"\n type=\"text\"\n inputmode=\"numeric\"\n placeholder=\"max\"\n [attr.aria-label]=\"'Filtr max: ' + col.header\"\n [value]=\"rangeVal(col.field).max\"\n (input)=\"setRangeFilter(col.field, 'max', $event)\"\n (click)=\"$event.stopPropagation()\"\n />\n </div>\n }\n @case ('slider') {\n <div class=\"kpt-data-table__fslider\" (click)=\"$event.stopPropagation()\">\n <kpt-slider\n range\n [min]=\"col.filter?.min ?? 0\"\n [max]=\"col.filter?.max ?? 100\"\n [step]=\"col.filter?.step ?? 1\"\n [value]=\"sliderVal(col)\"\n (valueChange)=\"setColumnFilter(col.field, $event)\"\n showValue\n />\n </div>\n }\n @case ('dateRange') {\n <kpt-date-range\n [placeholder]=\"col.filter?.placeholder || 'Zakres dat'\"\n [value]=\"$any(columnFilters()[col.field]) || { start: '', end: '' }\"\n (valueChange)=\"setColumnFilter(col.field, $event)\"\n />\n }\n }\n </th>\n }\n </tr>\n</ng-template>\n\n@if (pageSize() > 0 && !virtualScroll()) {\n <kpt-paginator\n [length]=\"filteredCount()\"\n [pageIndex]=\"pageIndex()\"\n (pageIndexChange)=\"pageIndex.set($event)\"\n [pageSize]=\"pageSizeState()\"\n (pageSizeChange)=\"pageSizeState.set($event)\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n />\n}\n", styles: ["@layer kpt.components{.kpt-data-table{display:flex;flex-direction:column;background:var(--kpt-table-bg);color:var(--kpt-table-fg);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border);border-radius:var(--kpt-table-radius, .75rem);overflow:hidden}.kpt-data-table__toolbar{display:flex;align-items:center;justify-content:space-between;gap:var(--kpt-space-3, .75rem);padding:var(--kpt-space-3, .75rem);border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border)}.kpt-data-table__filter{width:100%;max-width:20rem;height:2.25rem;padding-inline:var(--kpt-space-3, .75rem);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text)}.kpt-data-table__filter:focus-visible{outline:none;border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-data-table__scroll{overflow:auto}.kpt-data-table__table{width:100%;border-collapse:collapse;font-size:var(--kpt-font-size-sm, .875rem)}.kpt-data-table__table--frozen{width:max-content;min-width:100%}.kpt-data-table__table th,.kpt-data-table__table td{padding:var(--kpt-table-cell-padding, .75rem);text-align:start;border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border)}.kpt-data-table__table th[data-align=center],.kpt-data-table__table td[data-align=center]{text-align:center}.kpt-data-table__table th[data-align=end],.kpt-data-table__table td[data-align=end]{text-align:end}.kpt-data-table__table thead th{position:sticky;top:0;z-index:1;background:var(--kpt-table-header-bg);color:var(--kpt-table-header-fg);font-weight:var(--kpt-font-weight-semibold, 600);white-space:nowrap;-webkit-user-select:none;user-select:none}.kpt-data-table__table thead tr:nth-child(2) th{top:var(--kpt-thead-offset, 0px)}.kpt-data-table__filter-row th{padding:var(--kpt-space-2, .5rem);font-weight:var(--kpt-font-weight-normal, 400);cursor:auto}.kpt-data-table__fcell{width:100%;height:2rem;padding-inline:var(--kpt-space-2, .5rem);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text);font:inherit}.kpt-data-table__fcell:focus-visible{outline:none;border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-data-table__filter-row kpt-select,.kpt-data-table__filter-row kpt-date-range{display:block;width:100%;font-weight:var(--kpt-font-weight-normal, 400)}.kpt-data-table__frange{display:flex;gap:var(--kpt-space-2, .5rem)}.kpt-data-table__frange .kpt-data-table__fcell{min-width:0}.kpt-data-table__fslider .kpt-slider-host{width:100%}.kpt-data-table__fslider .kpt-slider__value{min-width:auto;font-size:var(--kpt-font-size-xs, .75rem);color:var(--kpt-color-on-surface-muted)}.kpt-data-table__th--sortable{cursor:pointer}.kpt-data-table__th--sortable:hover{color:var(--kpt-color-on-surface)}.kpt-data-table__sort{margin-inline-start:.35em;opacity:.35}.kpt-data-table__sort--active{opacity:1}.kpt-data-table__th--draggable{cursor:grab}.kpt-data-table__th--draggable:active{cursor:grabbing}.kpt-data-table__th--dragover{box-shadow:inset 2px 0 0 0 var(--kpt-color-primary)}.kpt-data-table__grip{margin-inline-end:.4em;opacity:.45}.kpt-data-table__checkbox{width:1px;white-space:nowrap;text-align:center}.kpt-data-table__checkbox input[type=checkbox]{appearance:none;-webkit-appearance:none;position:relative;display:inline-block;width:1.15rem;height:1.15rem;margin:0;vertical-align:middle;cursor:pointer;border:var(--kpt-border-width-medium, 2px) solid var(--kpt-form-field-border);border-radius:var(--kpt-radius-sm, .25rem);background:var(--kpt-form-field-bg);transition:background-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard),border-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-data-table__checkbox input[type=checkbox]:after{content:\"\";position:absolute;inset:0;opacity:0;background-color:var(--kpt-color-on-primary);transition:opacity var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard);-webkit-mask:no-repeat center/.85rem;mask:no-repeat center/.85rem}.kpt-data-table__checkbox input[type=checkbox]:checked,.kpt-data-table__checkbox input[type=checkbox]:indeterminate{background:var(--kpt-color-primary);border-color:var(--kpt-color-primary)}.kpt-data-table__checkbox input[type=checkbox]:checked:after{opacity:1;-webkit-mask-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M13 4.5 6.5 11 3 7.5' fill='none' stroke='%23000' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");mask-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M13 4.5 6.5 11 3 7.5' fill='none' stroke='%23000' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\")}.kpt-data-table__checkbox input[type=checkbox]:indeterminate:after{opacity:1;-webkit-mask-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8h9' fill='none' stroke='%23000' stroke-width='2.25' stroke-linecap='round'/%3E%3C/svg%3E\");mask-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8h9' fill='none' stroke='%23000' stroke-width='2.25' stroke-linecap='round'/%3E%3C/svg%3E\")}.kpt-data-table__checkbox input[type=checkbox]:focus-visible{outline:var(--kpt-border-width-medium, 2px) solid var(--kpt-color-focus-ring);outline-offset:2px}.kpt-data-table__expander{width:2.5rem;min-width:2.5rem;text-align:center;white-space:nowrap}.kpt-data-table__expander-btn{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;padding:0;border:none;border-radius:var(--kpt-radius-sm, .25rem);background:transparent;color:var(--kpt-color-on-surface-muted);cursor:pointer;transition:background-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard),color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-data-table__expander-btn kpt-icon{display:inline-flex;transition:transform var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-data-table__expander-btn:hover{background:var(--kpt-table-row-hover);color:var(--kpt-color-on-surface)}.kpt-data-table__expander-btn:focus-visible{outline:var(--kpt-border-width-medium, 2px) solid var(--kpt-color-focus-ring);outline-offset:2px}.kpt-data-table__expander-btn--open{color:var(--kpt-color-primary)}.kpt-data-table__expander-btn--open kpt-icon{transform:rotate(90deg)}.kpt-data-table__detail-row>.kpt-data-table__detail{padding:var(--kpt-space-4, 1rem);background:var(--kpt-table-detail-bg, var(--kpt-color-surface-variant, var(--kpt-table-row-hover)));border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border);box-shadow:inset 3px 0 0 0 var(--kpt-color-primary)}.kpt-data-table tbody tr{transition:background-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-data-table tbody tr:hover{background:var(--kpt-table-row-hover)}.kpt-data-table tbody tr.kpt-data-table__detail-row:hover{background:transparent}.kpt-data-table__row--selected{background:var(--kpt-table-row-selected)!important}.kpt-data-table__row--expanded{background:var(--kpt-table-row-hover)}.kpt-data-table__table--frozen .kpt-data-table__checkbox{width:3rem;min-width:3rem}.kpt-data-table__table--frozen .kpt-data-table__expander{width:2.5rem;min-width:2.5rem}.kpt-data-table__cell--frozen{position:sticky;z-index:1;background:var(--kpt-table-bg);border-inline-end:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border)}.kpt-data-table thead th.kpt-data-table__cell--frozen{z-index:3;background:var(--kpt-table-header-bg)}.kpt-data-table tbody tr:hover .kpt-data-table__cell--frozen{background:var(--kpt-table-row-hover)}.kpt-data-table__row--selected.kpt-data-table__row--selected .kpt-data-table__cell--frozen,.kpt-data-table tbody tr.kpt-data-table__row--selected .kpt-data-table__cell--frozen{background:var(--kpt-table-row-selected)}.kpt-data-table__state{padding:var(--kpt-space-8, 2rem)!important;text-align:center!important;color:var(--kpt-color-on-surface-muted)}.kpt-data-table__table--virtual td{padding-block:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.kpt-data-table__spacer td{padding:0!important;border:0!important}.kpt-data-table tbody tr:last-child td{border-bottom:0}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: KptButton, selector: "kpt-button", inputs: ["variant", "size", "type", "disabled", "loading", "fullWidth"] }, { kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }, { kind: "component", type: KptPaginator, selector: "kpt-paginator", inputs: ["length", "pageSize", "pageIndex", "pageSizeOptions"], outputs: ["pageSizeChange", "pageIndexChange"] }, { kind: "component", type: KptSelect, selector: "kpt-select", inputs: ["options", "placeholder", "multiple", "filter", "disabled", "invalid", "touched", "value"], outputs: ["valueChange", "touch"] }, { kind: "component", type: KptDateRange, selector: "kpt-date-range", inputs: ["value", "disabled", "invalid", "touched", "placeholder", "displayFormat", "mode", "hourFormat", "minuteStep"], outputs: ["valueChange", "touch"] }, { kind: "component", type: KptSlider, selector: "kpt-slider", inputs: ["value", "range", "min", "max", "step", "showValue", "disabled", "invalid", "touched"], outputs: ["valueChange", "touch"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
4011
6119
  }
4012
6120
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptDataTable, decorators: [{
4013
6121
  type: Component,
4014
- args: [{ selector: 'kpt-data-table', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [NgTemplateOutlet, KptButton, KptIcon, KptPaginator], host: { class: 'kpt-data-table' }, template: "@if (filterable() || exportable()) {\n <div class=\"kpt-data-table__toolbar\">\n @if (filterable()) {\n <input\n class=\"kpt-data-table__filter\"\n type=\"search\"\n placeholder=\"Szukaj\u2026\"\n [value]=\"filterText()\"\n (input)=\"onFilter($event)\"\n />\n }\n @if (exportable()) {\n <kpt-button variant=\"outline\" size=\"sm\" (click)=\"exportCsv()\">Eksport CSV</kpt-button>\n }\n </div>\n}\n\n<div class=\"kpt-data-table__scroll\" #scrollEl [style.max-height]=\"scrollHeight()\" (scroll)=\"onScroll($event)\">\n <table\n class=\"kpt-data-table__table\"\n [class.kpt-data-table__table--frozen]=\"hasFrozen()\"\n [class.kpt-data-table__table--virtual]=\"virtualScroll()\"\n >\n <thead>\n <tr>\n @if (selectable() === 'multiple') {\n <th class=\"kpt-data-table__checkbox\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"hasFrozen() ? 0 : null\">\n <input type=\"checkbox\" [checked]=\"pageAllSelected()\" (change)=\"toggleAllOnPage()\" aria-label=\"Zaznacz wszystkie\" />\n </th>\n } @else if (selectable() === 'single') {\n <th class=\"kpt-data-table__checkbox\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"hasFrozen() ? 0 : null\"></th>\n }\n @for (col of orderedColumns(); track col.field; let i = $index) {\n <th\n [attr.draggable]=\"reorderable() ? true : null\"\n [style.width]=\"col.width\"\n [style.left.px]=\"frozenLeft(col.field)\"\n [attr.data-align]=\"col.align ?? 'start'\"\n [class.kpt-data-table__cell--frozen]=\"isFrozen(col.field)\"\n [class.kpt-data-table__th--sortable]=\"col.sortable\"\n [class.kpt-data-table__th--draggable]=\"reorderable()\"\n [class.kpt-data-table__th--dragover]=\"dragIndex() !== null && dragIndex() !== i\"\n [attr.aria-sort]=\"ariaSort(col)\"\n (click)=\"toggleSort(col)\"\n (dragstart)=\"reorderable() ? onColDragStart(i, $event) : null\"\n (dragover)=\"reorderable() ? onColDragOver($event) : null\"\n (drop)=\"reorderable() ? onColDrop(i, $event) : null\"\n (dragend)=\"onColDragEnd()\"\n >\n @if (reorderable()) {\n <kpt-icon class=\"kpt-data-table__grip\" name=\"grip-vertical\" />\n }\n <span>{{ col.header }}</span>\n @if (col.sortable) {\n <kpt-icon\n class=\"kpt-data-table__sort\"\n [class.kpt-data-table__sort--active]=\"ariaSort(col) !== 'none'\"\n [name]=\"sortIconName(col)\"\n />\n }\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (loading()) {\n <tr><td class=\"kpt-data-table__state\" [attr.colspan]=\"colspan()\">\u0141adowanie\u2026</td></tr>\n } @else if (displayCount() === 0) {\n <tr><td class=\"kpt-data-table__state\" [attr.colspan]=\"colspan()\">{{ emptyMessage() }}</td></tr>\n } @else if (virtualScroll()) {\n @if (topPad() > 0) {\n <tr class=\"kpt-data-table__spacer\" aria-hidden=\"true\"><td [attr.colspan]=\"colspan()\" [style.height.px]=\"topPad()\"></td></tr>\n }\n @for (row of virtualRows(); track trackRow(row)) {\n <ng-container [ngTemplateOutlet]=\"rowTpl\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n @if (bottomPad() > 0) {\n <tr class=\"kpt-data-table__spacer\" aria-hidden=\"true\"><td [attr.colspan]=\"colspan()\" [style.height.px]=\"bottomPad()\"></td></tr>\n }\n } @else {\n @for (row of paged(); track trackRow(row)) {\n <ng-container [ngTemplateOutlet]=\"rowTpl\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n }\n </tbody>\n </table>\n</div>\n\n<ng-template #rowTpl let-row>\n <tr\n [class.kpt-data-table__row--selected]=\"isSelected(row)\"\n [style.height.px]=\"virtualScroll() ? rowHeight() : null\"\n (click)=\"onRowClick(row)\"\n >\n @if (selectable() !== 'none') {\n <td class=\"kpt-data-table__checkbox\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"hasFrozen() ? 0 : null\">\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(row)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n aria-label=\"Zaznacz wiersz\"\n />\n </td>\n }\n @for (col of orderedColumns(); track col.field) {\n <td\n [attr.data-align]=\"col.align ?? 'start'\"\n [style.left.px]=\"frozenLeft(col.field)\"\n [class.kpt-data-table__cell--frozen]=\"isFrozen(col.field)\"\n >\n @if (cellTemplate(col.field); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: row, value: getValue(row, col.field) }\"\n />\n } @else {\n {{ getValue(row, col.field) }}\n }\n </td>\n }\n </tr>\n</ng-template>\n\n@if (pageSize() > 0 && !virtualScroll()) {\n <kpt-paginator\n [length]=\"filteredCount()\"\n [pageIndex]=\"pageIndex()\"\n (pageIndexChange)=\"pageIndex.set($event)\"\n [pageSize]=\"pageSizeState()\"\n (pageSizeChange)=\"pageSizeState.set($event)\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n />\n}\n", styles: ["@layer kpt.components{.kpt-data-table{display:flex;flex-direction:column;background:var(--kpt-table-bg);color:var(--kpt-table-fg);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border);border-radius:var(--kpt-table-radius, .75rem);overflow:hidden}.kpt-data-table__toolbar{display:flex;align-items:center;justify-content:space-between;gap:var(--kpt-space-3, .75rem);padding:var(--kpt-space-3, .75rem);border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border)}.kpt-data-table__filter{width:100%;max-width:20rem;height:2.25rem;padding-inline:var(--kpt-space-3, .75rem);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text)}.kpt-data-table__filter:focus-visible{outline:none;border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-data-table__scroll{overflow:auto}.kpt-data-table__table{width:100%;border-collapse:collapse;font-size:var(--kpt-font-size-sm, .875rem)}.kpt-data-table__table--frozen{width:max-content;min-width:100%}.kpt-data-table__table th,.kpt-data-table__table td{padding:var(--kpt-table-cell-padding, .75rem);text-align:start;border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border)}.kpt-data-table__table th[data-align=center],.kpt-data-table__table td[data-align=center]{text-align:center}.kpt-data-table__table th[data-align=end],.kpt-data-table__table td[data-align=end]{text-align:end}.kpt-data-table__table thead th{position:sticky;top:0;z-index:1;background:var(--kpt-table-header-bg);color:var(--kpt-table-header-fg);font-weight:var(--kpt-font-weight-semibold, 600);white-space:nowrap;-webkit-user-select:none;user-select:none}.kpt-data-table__th--sortable{cursor:pointer}.kpt-data-table__th--sortable:hover{color:var(--kpt-color-on-surface)}.kpt-data-table__sort{margin-inline-start:.35em;opacity:.35}.kpt-data-table__sort--active{opacity:1}.kpt-data-table__th--draggable{cursor:grab}.kpt-data-table__th--draggable:active{cursor:grabbing}.kpt-data-table__th--dragover{box-shadow:inset 2px 0 0 0 var(--kpt-color-primary)}.kpt-data-table__grip{margin-inline-end:.4em;opacity:.45}.kpt-data-table__checkbox{width:1px;white-space:nowrap;text-align:center}.kpt-data-table tbody tr{transition:background-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-data-table tbody tr:hover{background:var(--kpt-table-row-hover)}.kpt-data-table__row--selected{background:var(--kpt-table-row-selected)!important}.kpt-data-table__table--frozen .kpt-data-table__checkbox{width:3rem;min-width:3rem}.kpt-data-table__cell--frozen{position:sticky;z-index:1;background:var(--kpt-table-bg);border-inline-end:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border)}.kpt-data-table thead th.kpt-data-table__cell--frozen{z-index:3;background:var(--kpt-table-header-bg)}.kpt-data-table tbody tr:hover .kpt-data-table__cell--frozen{background:var(--kpt-table-row-hover)}.kpt-data-table__row--selected.kpt-data-table__row--selected .kpt-data-table__cell--frozen,.kpt-data-table tbody tr.kpt-data-table__row--selected .kpt-data-table__cell--frozen{background:var(--kpt-table-row-selected)}.kpt-data-table__state{padding:var(--kpt-space-8, 2rem)!important;text-align:center!important;color:var(--kpt-color-on-surface-muted)}.kpt-data-table__table--virtual td{padding-block:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.kpt-data-table__spacer td{padding:0!important;border:0!important}.kpt-data-table tbody tr:last-child td{border-bottom:0}}\n"] }]
4015
- }], ctorParameters: () => [], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], filterable: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterable", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], pageSizeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizeOptions", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], rowKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowKey", required: false }] }], scrollHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollHeight", required: false }] }], virtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScroll", required: false }] }], rowHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowHeight", required: false }] }], reorderable: [{ type: i0.Input, args: [{ isSignal: true, alias: "reorderable", required: false }] }], exportable: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportable", required: false }] }], exportFilename: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportFilename", required: false }] }], lazy: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazy", required: false }] }], totalRecords: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalRecords", required: false }] }], selection: [{ type: i0.Input, args: [{ isSignal: true, alias: "selection", required: false }] }, { type: i0.Output, args: ["selectionChange"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], lazyLoad: [{ type: i0.Output, args: ["lazyLoad"] }], scrollEl: [{ type: i0.ViewChild, args: ['scrollEl', { isSignal: true }] }], cellDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => KptCellDef), { isSignal: true }] }] } });
6122
+ args: [{ selector: 'kpt-data-table', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [NgTemplateOutlet, KptButton, KptIcon, KptPaginator, KptSelect, KptDateRange, KptSlider], host: {
6123
+ 'class': 'kpt-data-table',
6124
+ '[style.--kpt-thead-offset]': "theadOffset() + 'px'",
6125
+ }, template: "@if (filterable() || exportable()) {\n <div class=\"kpt-data-table__toolbar\">\n @if (filterable()) {\n <input\n class=\"kpt-data-table__filter\"\n type=\"search\"\n placeholder=\"Szukaj\u2026\"\n [value]=\"filterText()\"\n (input)=\"onFilter($event)\"\n />\n }\n @if (exportable()) {\n <kpt-button variant=\"outline\" size=\"sm\" (click)=\"exportCsv()\">Eksport CSV</kpt-button>\n }\n </div>\n}\n\n<div class=\"kpt-data-table__scroll\" #scrollEl [style.max-height]=\"scrollHeight()\" (scroll)=\"onScroll($event)\">\n <table\n class=\"kpt-data-table__table\"\n [class.kpt-data-table__table--frozen]=\"hasFrozen()\"\n [class.kpt-data-table__table--virtual]=\"virtualScroll()\"\n >\n <thead #theadEl>\n @if (hasColumnFilters() && filterRowPosition() === 'top') {\n <ng-container [ngTemplateOutlet]=\"filterRowTpl\" />\n }\n <tr>\n @if (hasRowDetail()) {\n <th class=\"kpt-data-table__expander\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"expanderStickyLeft()\"></th>\n }\n @if (selectable() === 'multiple') {\n <th class=\"kpt-data-table__checkbox\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"checkboxStickyLeft()\">\n <input\n type=\"checkbox\"\n [checked]=\"pageAllSelected()\"\n [indeterminate]=\"pageSomeSelected()\"\n (change)=\"toggleAllOnPage()\"\n aria-label=\"Zaznacz wszystkie\"\n />\n </th>\n } @else if (selectable() === 'single') {\n <th class=\"kpt-data-table__checkbox\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"checkboxStickyLeft()\"></th>\n }\n @for (col of orderedColumns(); track col.field; let i = $index) {\n <th\n [attr.draggable]=\"isColDraggable(col) ? true : null\"\n [style.width]=\"col.width\"\n [style.left.px]=\"frozenLeft(col.field)\"\n [attr.data-align]=\"col.align ?? 'start'\"\n [class.kpt-data-table__cell--frozen]=\"isFrozen(col.field)\"\n [class.kpt-data-table__th--sortable]=\"col.sortable\"\n [class.kpt-data-table__th--draggable]=\"isColDraggable(col)\"\n [class.kpt-data-table__th--dragover]=\"dragIndex() !== null && dragIndex() !== i && !col.frozen\"\n [attr.aria-sort]=\"ariaSort(col)\"\n (click)=\"toggleSort(col)\"\n (dragstart)=\"onColDragStart(i, $event)\"\n (dragover)=\"reorderable() ? onColDragOver(i, $event) : null\"\n (drop)=\"reorderable() ? onColDrop(i, $event) : null\"\n (dragend)=\"onColDragEnd()\"\n >\n @if (isColDraggable(col)) {\n <kpt-icon class=\"kpt-data-table__grip\" name=\"grip-vertical\" />\n }\n <span>{{ col.header }}</span>\n @if (col.sortable) {\n <kpt-icon\n class=\"kpt-data-table__sort\"\n [class.kpt-data-table__sort--active]=\"ariaSort(col) !== 'none'\"\n [name]=\"sortIconName(col)\"\n />\n }\n </th>\n }\n </tr>\n @if (hasColumnFilters() && filterRowPosition() === 'bottom') {\n <ng-container [ngTemplateOutlet]=\"filterRowTpl\" />\n }\n </thead>\n <tbody>\n @if (loading()) {\n <tr><td class=\"kpt-data-table__state\" [attr.colspan]=\"colspan()\">\u0141adowanie\u2026</td></tr>\n } @else if (displayCount() === 0) {\n <tr><td class=\"kpt-data-table__state\" [attr.colspan]=\"colspan()\">{{ emptyMessage() }}</td></tr>\n } @else if (virtualScroll()) {\n @if (topPad() > 0) {\n <tr class=\"kpt-data-table__spacer\" aria-hidden=\"true\"><td [attr.colspan]=\"colspan()\" [style.height.px]=\"topPad()\"></td></tr>\n }\n @for (row of virtualRows(); track trackRow(row)) {\n <ng-container [ngTemplateOutlet]=\"rowTpl\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n @if (bottomPad() > 0) {\n <tr class=\"kpt-data-table__spacer\" aria-hidden=\"true\"><td [attr.colspan]=\"colspan()\" [style.height.px]=\"bottomPad()\"></td></tr>\n }\n } @else {\n @for (row of paged(); track trackRow(row)) {\n <ng-container [ngTemplateOutlet]=\"rowTpl\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n }\n </tbody>\n </table>\n</div>\n\n<ng-template #rowTpl let-row>\n <tr\n [class.kpt-data-table__row--selected]=\"isSelected(row)\"\n [class.kpt-data-table__row--expanded]=\"hasRowDetail() && isExpanded(row)\"\n [style.height.px]=\"virtualScroll() ? rowHeight() : null\"\n (click)=\"onRowClick(row)\"\n >\n @if (hasRowDetail()) {\n <td class=\"kpt-data-table__expander\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"expanderStickyLeft()\">\n <button\n type=\"button\"\n class=\"kpt-data-table__expander-btn\"\n [class.kpt-data-table__expander-btn--open]=\"isExpanded(row)\"\n [attr.aria-expanded]=\"isExpanded(row)\"\n aria-label=\"Rozwi\u0144 wiersz\"\n (click)=\"$event.stopPropagation(); toggleExpand(row)\"\n >\n <kpt-icon name=\"chevron-right\" />\n </button>\n </td>\n }\n @if (selectable() !== 'none') {\n <td class=\"kpt-data-table__checkbox\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"checkboxStickyLeft()\">\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(row)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n aria-label=\"Zaznacz wiersz\"\n />\n </td>\n }\n @for (col of orderedColumns(); track col.field) {\n <td\n [attr.data-align]=\"col.align ?? 'start'\"\n [style.left.px]=\"frozenLeft(col.field)\"\n [class.kpt-data-table__cell--frozen]=\"isFrozen(col.field)\"\n >\n @if (cellTemplate(col.field); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: row, value: getValue(row, col.field) }\"\n />\n } @else {\n {{ getValue(row, col.field) }}\n }\n </td>\n }\n </tr>\n @if (hasRowDetail() && isExpanded(row) && !virtualScroll()) {\n <tr class=\"kpt-data-table__detail-row\">\n <td class=\"kpt-data-table__detail\" [attr.colspan]=\"colspan()\">\n <ng-container [ngTemplateOutlet]=\"rowDetailTpl()\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n </td>\n </tr>\n }\n</ng-template>\n\n<ng-template #filterRowTpl>\n <tr class=\"kpt-data-table__filter-row\">\n @if (hasRowDetail()) {\n <th class=\"kpt-data-table__expander\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"expanderStickyLeft()\"></th>\n }\n @if (selectable() !== 'none') {\n <th class=\"kpt-data-table__checkbox\" [class.kpt-data-table__cell--frozen]=\"hasFrozen()\" [style.left.px]=\"checkboxStickyLeft()\"></th>\n }\n @for (col of orderedColumns(); track col.field) {\n <th\n [style.width]=\"col.width\"\n [style.left.px]=\"frozenLeft(col.field)\"\n [attr.data-align]=\"col.align ?? 'start'\"\n [class.kpt-data-table__cell--frozen]=\"isFrozen(col.field)\"\n >\n @switch (col.filter?.type) {\n @case ('text') {\n <input\n class=\"kpt-data-table__fcell\"\n type=\"search\"\n [attr.placeholder]=\"col.filter?.placeholder || ''\"\n [attr.aria-label]=\"'Filtr: ' + col.header\"\n [value]=\"$any(columnFilters()[col.field]) || ''\"\n (input)=\"setColumnFilter(col.field, $any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n @case ('number') {\n <input\n class=\"kpt-data-table__fcell\"\n type=\"text\"\n inputmode=\"numeric\"\n [attr.placeholder]=\"col.filter?.placeholder || ''\"\n [attr.aria-label]=\"'Filtr: ' + col.header\"\n [value]=\"$any(columnFilters()[col.field]) || ''\"\n (input)=\"onNumberFilter(col.field, $event)\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n @case ('select') {\n <kpt-select\n [options]=\"col.filter?.options || []\"\n [multiple]=\"!!col.filter?.multiple\"\n filter\n [placeholder]=\"col.filter?.placeholder || 'Wszystkie'\"\n [value]=\"columnFilters()[col.field] ?? null\"\n (valueChange)=\"setColumnFilter(col.field, $event)\"\n />\n }\n @case ('numberRange') {\n <div class=\"kpt-data-table__frange\">\n <input\n class=\"kpt-data-table__fcell\"\n type=\"text\"\n inputmode=\"numeric\"\n placeholder=\"min\"\n [attr.aria-label]=\"'Filtr min: ' + col.header\"\n [value]=\"rangeVal(col.field).min\"\n (input)=\"setRangeFilter(col.field, 'min', $event)\"\n (click)=\"$event.stopPropagation()\"\n />\n <input\n class=\"kpt-data-table__fcell\"\n type=\"text\"\n inputmode=\"numeric\"\n placeholder=\"max\"\n [attr.aria-label]=\"'Filtr max: ' + col.header\"\n [value]=\"rangeVal(col.field).max\"\n (input)=\"setRangeFilter(col.field, 'max', $event)\"\n (click)=\"$event.stopPropagation()\"\n />\n </div>\n }\n @case ('slider') {\n <div class=\"kpt-data-table__fslider\" (click)=\"$event.stopPropagation()\">\n <kpt-slider\n range\n [min]=\"col.filter?.min ?? 0\"\n [max]=\"col.filter?.max ?? 100\"\n [step]=\"col.filter?.step ?? 1\"\n [value]=\"sliderVal(col)\"\n (valueChange)=\"setColumnFilter(col.field, $event)\"\n showValue\n />\n </div>\n }\n @case ('dateRange') {\n <kpt-date-range\n [placeholder]=\"col.filter?.placeholder || 'Zakres dat'\"\n [value]=\"$any(columnFilters()[col.field]) || { start: '', end: '' }\"\n (valueChange)=\"setColumnFilter(col.field, $event)\"\n />\n }\n }\n </th>\n }\n </tr>\n</ng-template>\n\n@if (pageSize() > 0 && !virtualScroll()) {\n <kpt-paginator\n [length]=\"filteredCount()\"\n [pageIndex]=\"pageIndex()\"\n (pageIndexChange)=\"pageIndex.set($event)\"\n [pageSize]=\"pageSizeState()\"\n (pageSizeChange)=\"pageSizeState.set($event)\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n />\n}\n", styles: ["@layer kpt.components{.kpt-data-table{display:flex;flex-direction:column;background:var(--kpt-table-bg);color:var(--kpt-table-fg);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border);border-radius:var(--kpt-table-radius, .75rem);overflow:hidden}.kpt-data-table__toolbar{display:flex;align-items:center;justify-content:space-between;gap:var(--kpt-space-3, .75rem);padding:var(--kpt-space-3, .75rem);border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border)}.kpt-data-table__filter{width:100%;max-width:20rem;height:2.25rem;padding-inline:var(--kpt-space-3, .75rem);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text)}.kpt-data-table__filter:focus-visible{outline:none;border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-data-table__scroll{overflow:auto}.kpt-data-table__table{width:100%;border-collapse:collapse;font-size:var(--kpt-font-size-sm, .875rem)}.kpt-data-table__table--frozen{width:max-content;min-width:100%}.kpt-data-table__table th,.kpt-data-table__table td{padding:var(--kpt-table-cell-padding, .75rem);text-align:start;border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border)}.kpt-data-table__table th[data-align=center],.kpt-data-table__table td[data-align=center]{text-align:center}.kpt-data-table__table th[data-align=end],.kpt-data-table__table td[data-align=end]{text-align:end}.kpt-data-table__table thead th{position:sticky;top:0;z-index:1;background:var(--kpt-table-header-bg);color:var(--kpt-table-header-fg);font-weight:var(--kpt-font-weight-semibold, 600);white-space:nowrap;-webkit-user-select:none;user-select:none}.kpt-data-table__table thead tr:nth-child(2) th{top:var(--kpt-thead-offset, 0px)}.kpt-data-table__filter-row th{padding:var(--kpt-space-2, .5rem);font-weight:var(--kpt-font-weight-normal, 400);cursor:auto}.kpt-data-table__fcell{width:100%;height:2rem;padding-inline:var(--kpt-space-2, .5rem);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-form-field-border);border-radius:var(--kpt-form-field-radius, .5rem);background:var(--kpt-form-field-bg);color:var(--kpt-form-field-text);font:inherit}.kpt-data-table__fcell:focus-visible{outline:none;border-color:var(--kpt-form-field-border-focus);box-shadow:0 0 0 2px color-mix(in oklch,var(--kpt-form-field-border-focus) 30%,transparent)}.kpt-data-table__filter-row kpt-select,.kpt-data-table__filter-row kpt-date-range{display:block;width:100%;font-weight:var(--kpt-font-weight-normal, 400)}.kpt-data-table__frange{display:flex;gap:var(--kpt-space-2, .5rem)}.kpt-data-table__frange .kpt-data-table__fcell{min-width:0}.kpt-data-table__fslider .kpt-slider-host{width:100%}.kpt-data-table__fslider .kpt-slider__value{min-width:auto;font-size:var(--kpt-font-size-xs, .75rem);color:var(--kpt-color-on-surface-muted)}.kpt-data-table__th--sortable{cursor:pointer}.kpt-data-table__th--sortable:hover{color:var(--kpt-color-on-surface)}.kpt-data-table__sort{margin-inline-start:.35em;opacity:.35}.kpt-data-table__sort--active{opacity:1}.kpt-data-table__th--draggable{cursor:grab}.kpt-data-table__th--draggable:active{cursor:grabbing}.kpt-data-table__th--dragover{box-shadow:inset 2px 0 0 0 var(--kpt-color-primary)}.kpt-data-table__grip{margin-inline-end:.4em;opacity:.45}.kpt-data-table__checkbox{width:1px;white-space:nowrap;text-align:center}.kpt-data-table__checkbox input[type=checkbox]{appearance:none;-webkit-appearance:none;position:relative;display:inline-block;width:1.15rem;height:1.15rem;margin:0;vertical-align:middle;cursor:pointer;border:var(--kpt-border-width-medium, 2px) solid var(--kpt-form-field-border);border-radius:var(--kpt-radius-sm, .25rem);background:var(--kpt-form-field-bg);transition:background-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard),border-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-data-table__checkbox input[type=checkbox]:after{content:\"\";position:absolute;inset:0;opacity:0;background-color:var(--kpt-color-on-primary);transition:opacity var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard);-webkit-mask:no-repeat center/.85rem;mask:no-repeat center/.85rem}.kpt-data-table__checkbox input[type=checkbox]:checked,.kpt-data-table__checkbox input[type=checkbox]:indeterminate{background:var(--kpt-color-primary);border-color:var(--kpt-color-primary)}.kpt-data-table__checkbox input[type=checkbox]:checked:after{opacity:1;-webkit-mask-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M13 4.5 6.5 11 3 7.5' fill='none' stroke='%23000' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");mask-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M13 4.5 6.5 11 3 7.5' fill='none' stroke='%23000' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\")}.kpt-data-table__checkbox input[type=checkbox]:indeterminate:after{opacity:1;-webkit-mask-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8h9' fill='none' stroke='%23000' stroke-width='2.25' stroke-linecap='round'/%3E%3C/svg%3E\");mask-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8h9' fill='none' stroke='%23000' stroke-width='2.25' stroke-linecap='round'/%3E%3C/svg%3E\")}.kpt-data-table__checkbox input[type=checkbox]:focus-visible{outline:var(--kpt-border-width-medium, 2px) solid var(--kpt-color-focus-ring);outline-offset:2px}.kpt-data-table__expander{width:2.5rem;min-width:2.5rem;text-align:center;white-space:nowrap}.kpt-data-table__expander-btn{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;padding:0;border:none;border-radius:var(--kpt-radius-sm, .25rem);background:transparent;color:var(--kpt-color-on-surface-muted);cursor:pointer;transition:background-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard),color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-data-table__expander-btn kpt-icon{display:inline-flex;transition:transform var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-data-table__expander-btn:hover{background:var(--kpt-table-row-hover);color:var(--kpt-color-on-surface)}.kpt-data-table__expander-btn:focus-visible{outline:var(--kpt-border-width-medium, 2px) solid var(--kpt-color-focus-ring);outline-offset:2px}.kpt-data-table__expander-btn--open{color:var(--kpt-color-primary)}.kpt-data-table__expander-btn--open kpt-icon{transform:rotate(90deg)}.kpt-data-table__detail-row>.kpt-data-table__detail{padding:var(--kpt-space-4, 1rem);background:var(--kpt-table-detail-bg, var(--kpt-color-surface-variant, var(--kpt-table-row-hover)));border-bottom:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border);box-shadow:inset 3px 0 0 0 var(--kpt-color-primary)}.kpt-data-table tbody tr{transition:background-color var(--kpt-motion-duration-fast, .12s) var(--kpt-motion-easing-standard)}.kpt-data-table tbody tr:hover{background:var(--kpt-table-row-hover)}.kpt-data-table tbody tr.kpt-data-table__detail-row:hover{background:transparent}.kpt-data-table__row--selected{background:var(--kpt-table-row-selected)!important}.kpt-data-table__row--expanded{background:var(--kpt-table-row-hover)}.kpt-data-table__table--frozen .kpt-data-table__checkbox{width:3rem;min-width:3rem}.kpt-data-table__table--frozen .kpt-data-table__expander{width:2.5rem;min-width:2.5rem}.kpt-data-table__cell--frozen{position:sticky;z-index:1;background:var(--kpt-table-bg);border-inline-end:var(--kpt-border-width-thin, 1px) solid var(--kpt-table-border)}.kpt-data-table thead th.kpt-data-table__cell--frozen{z-index:3;background:var(--kpt-table-header-bg)}.kpt-data-table tbody tr:hover .kpt-data-table__cell--frozen{background:var(--kpt-table-row-hover)}.kpt-data-table__row--selected.kpt-data-table__row--selected .kpt-data-table__cell--frozen,.kpt-data-table tbody tr.kpt-data-table__row--selected .kpt-data-table__cell--frozen{background:var(--kpt-table-row-selected)}.kpt-data-table__state{padding:var(--kpt-space-8, 2rem)!important;text-align:center!important;color:var(--kpt-color-on-surface-muted)}.kpt-data-table__table--virtual td{padding-block:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.kpt-data-table__spacer td{padding:0!important;border:0!important}.kpt-data-table tbody tr:last-child td{border-bottom:0}}\n"] }]
6126
+ }], ctorParameters: () => [], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], filterable: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterable", required: false }] }], filterRowPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterRowPosition", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], pageSizeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizeOptions", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], rowKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowKey", required: false }] }], scrollHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollHeight", required: false }] }], virtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScroll", required: false }] }], rowHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowHeight", required: false }] }], reorderable: [{ type: i0.Input, args: [{ isSignal: true, alias: "reorderable", required: false }] }], exportable: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportable", required: false }] }], exportFilename: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportFilename", required: false }] }], lazy: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazy", required: false }] }], totalRecords: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalRecords", required: false }] }], expandable: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandable", required: false }] }], multiExpand: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiExpand", required: false }] }], selection: [{ type: i0.Input, args: [{ isSignal: true, alias: "selection", required: false }] }, { type: i0.Output, args: ["selectionChange"] }], expandedRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedRows", required: false }] }, { type: i0.Output, args: ["expandedRowsChange"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], lazyLoad: [{ type: i0.Output, args: ["lazyLoad"] }], scrollEl: [{ type: i0.ViewChild, args: ['scrollEl', { isSignal: true }] }], theadEl: [{ type: i0.ViewChild, args: ['theadEl', { isSignal: true }] }], cellDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => KptCellDef), { isSignal: true }] }], rowDetailDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KptRowDetailDef), { isSignal: true }] }] } });
4016
6127
 
4017
6128
  /**
4018
6129
  * Drzewo hierarchiczne (rozwijanie, zaznaczanie, ikony). Dane przez `nodes`.
@@ -4841,90 +6952,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
4841
6952
  `, host: { class: 'kpt-toast-container-host' }, styles: ["@layer kpt.components{.kpt-toast-container{position:fixed;inset-block-end:var(--kpt-space-4, 1rem);inset-inline-end:var(--kpt-space-4, 1rem);z-index:var(--kpt-z-toast, 1300);display:flex;flex-direction:column;gap:var(--kpt-space-2, .5rem);max-width:min(24rem,100vw - 2rem);pointer-events:none}.kpt-toast{--_accent: var(--kpt-color-info);pointer-events:auto;display:flex;align-items:flex-start;gap:var(--kpt-space-3, .75rem);padding:var(--kpt-space-3, .75rem) var(--kpt-space-4, 1rem);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-inline-start:3px solid var(--_accent);border-radius:var(--kpt-radius-md, .5rem);background:var(--kpt-color-surface-raised);color:var(--kpt-color-on-surface);box-shadow:var(--kpt-elevation-3);font-size:var(--kpt-font-size-sm, .875rem);animation:kpt-toast-in var(--kpt-motion-duration-base, .2s) var(--kpt-motion-easing-emphasized)}.kpt-toast[data-variant=success]{--_accent: var(--kpt-color-success)}.kpt-toast[data-variant=warning]{--_accent: var(--kpt-color-warning)}.kpt-toast[data-variant=danger]{--_accent: var(--kpt-color-danger)}.kpt-toast__icon{color:var(--_accent);font-weight:700}.kpt-toast__content{flex:1;min-width:0}.kpt-toast__title{font-weight:var(--kpt-font-weight-semibold, 600);margin-bottom:.1rem}.kpt-toast__close{background:none;border:0;cursor:pointer;color:var(--kpt-color-on-surface-muted);font-size:1.15rem;line-height:1;padding:0}.kpt-toast__close:hover{color:var(--kpt-color-on-surface)}@keyframes kpt-toast-in{0%{opacity:0;transform:translateY(.5rem)}to{opacity:1;transform:translateY(0)}}@media(prefers-reduced-motion:reduce){.kpt-toast{animation:none}}}\n"] }]
4842
6953
  }] });
4843
6954
 
4844
- /**
4845
- * Dymek podpowiedzi (tooltip) pokazywany na hover/focus hosta. Lekki — element dodawany
4846
- * do `body` i pozycjonowany względem hosta (działa w trybie zoneless).
4847
- *
4848
- * @example
4849
- * <kpt-button kptTooltip="Zapisz zmiany" kptTooltipPosition="bottom">Zapisz</kpt-button>
4850
- */
4851
- class KptTooltip {
4852
- text = input.required({ ...(ngDevMode ? { debugName: "text" } : /* istanbul ignore next */ {}), alias: 'kptTooltip' });
4853
- position = input('top', { ...(ngDevMode ? { debugName: "position" } : /* istanbul ignore next */ {}), alias: 'kptTooltipPosition' });
4854
- host = inject(ElementRef);
4855
- tip;
4856
- show() {
4857
- if (this.tip || !this.text())
4858
- return;
4859
- const tip = document.createElement('div');
4860
- tip.className = 'kpt-tooltip';
4861
- tip.setAttribute('role', 'tooltip');
4862
- tip.textContent = this.text();
4863
- tip.style.cssText =
4864
- 'position:fixed;z-index:1400;max-width:16rem;padding:0.35rem 0.6rem;' +
4865
- 'border-radius:var(--kpt-radius-sm,0.25rem);font-size:var(--kpt-font-size-xs,0.75rem);' +
4866
- 'line-height:1.4;background:var(--kpt-color-on-surface);color:var(--kpt-color-surface);' +
4867
- 'box-shadow:var(--kpt-elevation-2);pointer-events:none;opacity:0;transition:opacity 120ms;';
4868
- document.body.appendChild(tip);
4869
- this.tip = tip;
4870
- this.reposition();
4871
- requestAnimationFrame(() => {
4872
- if (this.tip)
4873
- this.tip.style.opacity = '1';
4874
- });
4875
- }
4876
- hide() {
4877
- this.tip?.remove();
4878
- this.tip = undefined;
4879
- }
4880
- reposition() {
4881
- const tip = this.tip;
4882
- if (!tip)
4883
- return;
4884
- const r = this.host.nativeElement.getBoundingClientRect();
4885
- const t = tip.getBoundingClientRect();
4886
- const gap = 8;
4887
- let top;
4888
- let left;
4889
- switch (this.position()) {
4890
- case 'bottom':
4891
- top = r.bottom + gap;
4892
- left = r.left + r.width / 2 - t.width / 2;
4893
- break;
4894
- case 'left':
4895
- top = r.top + r.height / 2 - t.height / 2;
4896
- left = r.left - t.width - gap;
4897
- break;
4898
- case 'right':
4899
- top = r.top + r.height / 2 - t.height / 2;
4900
- left = r.right + gap;
4901
- break;
4902
- default:
4903
- top = r.top - t.height - gap;
4904
- left = r.left + r.width / 2 - t.width / 2;
4905
- }
4906
- tip.style.top = `${Math.max(4, top)}px`;
4907
- tip.style.left = `${Math.max(4, left)}px`;
4908
- }
4909
- ngOnDestroy() {
4910
- this.hide();
4911
- }
4912
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptTooltip, deps: [], target: i0.ɵɵFactoryTarget.Directive });
4913
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.0", type: KptTooltip, isStandalone: true, selector: "[kptTooltip]", inputs: { text: { classPropertyName: "text", publicName: "kptTooltip", isSignal: true, isRequired: true, transformFunction: null }, position: { classPropertyName: "position", publicName: "kptTooltipPosition", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "show()", "mouseleave": "hide()", "focus": "show()", "blur": "hide()" } }, ngImport: i0 });
4914
- }
4915
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptTooltip, decorators: [{
4916
- type: Directive,
4917
- args: [{
4918
- selector: '[kptTooltip]',
4919
- host: {
4920
- '(mouseenter)': 'show()',
4921
- '(mouseleave)': 'hide()',
4922
- '(focus)': 'show()',
4923
- '(blur)': 'hide()',
4924
- },
4925
- }]
4926
- }], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "kptTooltip", required: true }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "kptTooltipPosition", required: false }] }] } });
4927
-
4928
6955
  /**
4929
6956
  * Menu rozwijane (dropdown) na CDK Overlay. Trigger przez projekcję, pozycje przez `items`.
4930
6957
  * Wymaga stylów overlay CDK: `import '@angular/cdk/overlay-prebuilt.css';`
@@ -5430,6 +7457,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
5430
7457
 
5431
7458
  /**
5432
7459
  * Pozioma belka menu z rozwijanymi pod-menu. Pozycje bez `items` działają jak akcje/linki.
7460
+ * Pod-menu renderowane przez CDK Overlay (doczepiane do `body`), więc nie są przycinane
7461
+ * przez rodzica z `overflow: hidden`. Wymaga stylów overlay CDK:
7462
+ * `import '@angular/cdk/overlay-prebuilt.css';`
5433
7463
  *
5434
7464
  * @example
5435
7465
  * <kpt-menubar [items]="items" (select)="onSelect($event)" />
@@ -5440,6 +7470,10 @@ class KptMenubar {
5440
7470
  select = output();
5441
7471
  openIndex = signal(null, /* @ts-ignore */
5442
7472
  ...(ngDevMode ? [{ debugName: "openIndex" }] : /* istanbul ignore next */ []));
7473
+ positions = [
7474
+ { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
7475
+ { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
7476
+ ];
5443
7477
  toggle(i, item) {
5444
7478
  if (item.disabled)
5445
7479
  return;
@@ -5469,6 +7503,8 @@ class KptMenubar {
5469
7503
  type="button"
5470
7504
  class="kpt-menubar__top"
5471
7505
  role="menuitem"
7506
+ cdkOverlayOrigin
7507
+ #origin="cdkOverlayOrigin"
5472
7508
  [class.is-open]="openIndex() === i"
5473
7509
  [disabled]="item.disabled"
5474
7510
  (click)="toggle(i, item)"
@@ -5478,7 +7514,16 @@ class KptMenubar {
5478
7514
  @if (item.items?.length) { <kpt-icon name="chevron-down" class="kpt-menubar__caret" /> }
5479
7515
  </button>
5480
7516
 
5481
- @if (openIndex() === i && item.items?.length) {
7517
+ <ng-template
7518
+ cdkConnectedOverlay
7519
+ [cdkConnectedOverlayOrigin]="origin"
7520
+ [cdkConnectedOverlayOpen]="openIndex() === i && !!item.items?.length"
7521
+ [cdkConnectedOverlayPositions]="positions"
7522
+ [cdkConnectedOverlayHasBackdrop]="true"
7523
+ cdkConnectedOverlayBackdropClass="cdk-overlay-transparent-backdrop"
7524
+ (backdropClick)="closeAll()"
7525
+ (detach)="closeAll()"
7526
+ >
5482
7527
  <div class="kpt-menubar__dropdown" role="menu">
5483
7528
  @for (sub of item.items; track $index) {
5484
7529
  @if (sub.separator) {
@@ -5498,18 +7543,15 @@ class KptMenubar {
5498
7543
  }
5499
7544
  }
5500
7545
  </div>
5501
- }
7546
+ </ng-template>
5502
7547
  </div>
5503
7548
  }
5504
7549
  </nav>
5505
- @if (openIndex() !== null) {
5506
- <div class="kpt-menubar__backdrop" (click)="closeAll()"></div>
5507
- }
5508
- `, isInline: true, styles: ["@layer kpt.components{.kpt-menubar-host{display:block}.kpt-menubar{display:flex;align-items:center;gap:var(--kpt-space-1, .25rem);padding:var(--kpt-space-1, .25rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem)}.kpt-menubar__group{position:relative}.kpt-menubar__top{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-menubar__top:hover:not(:disabled),.kpt-menubar__top.is-open{background:var(--kpt-color-muted)}.kpt-menubar__top:disabled{opacity:.5;cursor:not-allowed}.kpt-menubar__caret{opacity:.6}.kpt-menubar__dropdown{position:absolute;top:calc(100% + 4px);left:0;z-index:calc(var(--kpt-z-overlay, 1000) + 1);min-width:12rem;padding:var(--kpt-space-1, .25rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3)}.kpt-menubar__item{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);width:100%;padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem);text-align:left;cursor:pointer}.kpt-menubar__item:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-menubar__item:disabled{opacity:.5;cursor:not-allowed}.kpt-menubar__item--danger{color:var(--kpt-color-danger)}.kpt-menubar__separator{height:1px;margin:var(--kpt-space-1, .25rem) 0;background:var(--kpt-color-border)}.kpt-menubar__backdrop{position:fixed;inset:0;z-index:var(--kpt-z-overlay, 1000)}}\n"], dependencies: [{ kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
7550
+ `, isInline: true, styles: ["@layer kpt.components{.kpt-menubar-host{display:block}.kpt-menubar{display:flex;align-items:center;gap:var(--kpt-space-1, .25rem);padding:var(--kpt-space-1, .25rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem)}.kpt-menubar__group{display:inline-flex}.kpt-menubar__top{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-menubar__top:hover:not(:disabled),.kpt-menubar__top.is-open{background:var(--kpt-color-muted)}.kpt-menubar__top:disabled{opacity:.5;cursor:not-allowed}.kpt-menubar__caret{opacity:.6}.kpt-menubar__dropdown{min-width:12rem;padding:var(--kpt-space-1, .25rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3)}.kpt-menubar__item{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);width:100%;padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem);text-align:left;cursor:pointer}.kpt-menubar__item:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-menubar__item:disabled{opacity:.5;cursor:not-allowed}.kpt-menubar__item--danger{color:var(--kpt-color-danger)}.kpt-menubar__separator{height:1px;margin:var(--kpt-space-1, .25rem) 0;background:var(--kpt-color-border)}}\n"], dependencies: [{ kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
5509
7551
  }
5510
7552
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptMenubar, decorators: [{
5511
7553
  type: Component,
5512
- args: [{ selector: 'kpt-menubar', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [KptIcon], template: `
7554
+ args: [{ selector: 'kpt-menubar', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [CdkOverlayOrigin, CdkConnectedOverlay, KptIcon], template: `
5513
7555
  <nav class="kpt-menubar" role="menubar">
5514
7556
  @for (item of items(); track $index; let i = $index) {
5515
7557
  <div class="kpt-menubar__group">
@@ -5517,6 +7559,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
5517
7559
  type="button"
5518
7560
  class="kpt-menubar__top"
5519
7561
  role="menuitem"
7562
+ cdkOverlayOrigin
7563
+ #origin="cdkOverlayOrigin"
5520
7564
  [class.is-open]="openIndex() === i"
5521
7565
  [disabled]="item.disabled"
5522
7566
  (click)="toggle(i, item)"
@@ -5526,7 +7570,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
5526
7570
  @if (item.items?.length) { <kpt-icon name="chevron-down" class="kpt-menubar__caret" /> }
5527
7571
  </button>
5528
7572
 
5529
- @if (openIndex() === i && item.items?.length) {
7573
+ <ng-template
7574
+ cdkConnectedOverlay
7575
+ [cdkConnectedOverlayOrigin]="origin"
7576
+ [cdkConnectedOverlayOpen]="openIndex() === i && !!item.items?.length"
7577
+ [cdkConnectedOverlayPositions]="positions"
7578
+ [cdkConnectedOverlayHasBackdrop]="true"
7579
+ cdkConnectedOverlayBackdropClass="cdk-overlay-transparent-backdrop"
7580
+ (backdropClick)="closeAll()"
7581
+ (detach)="closeAll()"
7582
+ >
5530
7583
  <div class="kpt-menubar__dropdown" role="menu">
5531
7584
  @for (sub of item.items; track $index) {
5532
7585
  @if (sub.separator) {
@@ -5546,19 +7599,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
5546
7599
  }
5547
7600
  }
5548
7601
  </div>
5549
- }
7602
+ </ng-template>
5550
7603
  </div>
5551
7604
  }
5552
7605
  </nav>
5553
- @if (openIndex() !== null) {
5554
- <div class="kpt-menubar__backdrop" (click)="closeAll()"></div>
5555
- }
5556
- `, host: { class: 'kpt-menubar-host' }, styles: ["@layer kpt.components{.kpt-menubar-host{display:block}.kpt-menubar{display:flex;align-items:center;gap:var(--kpt-space-1, .25rem);padding:var(--kpt-space-1, .25rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem)}.kpt-menubar__group{position:relative}.kpt-menubar__top{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-menubar__top:hover:not(:disabled),.kpt-menubar__top.is-open{background:var(--kpt-color-muted)}.kpt-menubar__top:disabled{opacity:.5;cursor:not-allowed}.kpt-menubar__caret{opacity:.6}.kpt-menubar__dropdown{position:absolute;top:calc(100% + 4px);left:0;z-index:calc(var(--kpt-z-overlay, 1000) + 1);min-width:12rem;padding:var(--kpt-space-1, .25rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3)}.kpt-menubar__item{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);width:100%;padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem);text-align:left;cursor:pointer}.kpt-menubar__item:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-menubar__item:disabled{opacity:.5;cursor:not-allowed}.kpt-menubar__item--danger{color:var(--kpt-color-danger)}.kpt-menubar__separator{height:1px;margin:var(--kpt-space-1, .25rem) 0;background:var(--kpt-color-border)}.kpt-menubar__backdrop{position:fixed;inset:0;z-index:var(--kpt-z-overlay, 1000)}}\n"] }]
7606
+ `, host: { class: 'kpt-menubar-host' }, styles: ["@layer kpt.components{.kpt-menubar-host{display:block}.kpt-menubar{display:flex;align-items:center;gap:var(--kpt-space-1, .25rem);padding:var(--kpt-space-1, .25rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem)}.kpt-menubar__group{display:inline-flex}.kpt-menubar__top{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-menubar__top:hover:not(:disabled),.kpt-menubar__top.is-open{background:var(--kpt-color-muted)}.kpt-menubar__top:disabled{opacity:.5;cursor:not-allowed}.kpt-menubar__caret{opacity:.6}.kpt-menubar__dropdown{min-width:12rem;padding:var(--kpt-space-1, .25rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3)}.kpt-menubar__item{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);width:100%;padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem);text-align:left;cursor:pointer}.kpt-menubar__item:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-menubar__item:disabled{opacity:.5;cursor:not-allowed}.kpt-menubar__item--danger{color:var(--kpt-color-danger)}.kpt-menubar__separator{height:1px;margin:var(--kpt-space-1, .25rem) 0;background:var(--kpt-color-border)}}\n"] }]
5557
7607
  }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], select: [{ type: i0.Output, args: ["select"] }] } });
5558
7608
 
5559
7609
  /**
5560
7610
  * Mega-menu — pozioma belka z szerokim, wielokolumnowym panelem.
5561
7611
  * Struktura: pozycja górna → `items` (kolumny) → każda kolumna `items` (odnośniki).
7612
+ * Panel renderowany przez CDK Overlay (doczepiony do `body`), więc nie jest przycinany
7613
+ * przez rodzica z `overflow: hidden`. Wymaga stylów overlay CDK:
7614
+ * `import '@angular/cdk/overlay-prebuilt.css';`
5562
7615
  *
5563
7616
  * @example
5564
7617
  * <kpt-megamenu [items]="items" (select)="onSelect($event)" />
@@ -5569,6 +7622,10 @@ class KptMegamenu {
5569
7622
  select = output();
5570
7623
  openIndex = signal(null, /* @ts-ignore */
5571
7624
  ...(ngDevMode ? [{ debugName: "openIndex" }] : /* istanbul ignore next */ []));
7625
+ positions = [
7626
+ { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
7627
+ { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
7628
+ ];
5572
7629
  activeColumns() {
5573
7630
  const i = this.openIndex();
5574
7631
  return i === null ? [] : this.items()[i]?.items ?? [];
@@ -5587,7 +7644,7 @@ class KptMegamenu {
5587
7644
  }
5588
7645
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptMegamenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
5589
7646
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: KptMegamenu, isStandalone: true, selector: "kpt-megamenu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { select: "select" }, host: { classAttribute: "kpt-megamenu-host" }, ngImport: i0, template: `
5590
- <nav class="kpt-megamenu" role="menubar">
7647
+ <nav class="kpt-megamenu" role="menubar" cdkOverlayOrigin #origin="cdkOverlayOrigin">
5591
7648
  @for (item of items(); track $index; let i = $index) {
5592
7649
  <button
5593
7650
  type="button"
@@ -5601,32 +7658,38 @@ class KptMegamenu {
5601
7658
  <kpt-icon name="chevron-down" class="kpt-megamenu__caret" />
5602
7659
  </button>
5603
7660
  }
5604
-
5605
- @if (activeColumns().length) {
5606
- <div class="kpt-megamenu__panel" role="menu">
5607
- @for (col of activeColumns(); track $index) {
5608
- <div class="kpt-megamenu__column">
5609
- @if (col.label) { <div class="kpt-megamenu__col-title">{{ col.label }}</div> }
5610
- @for (link of col.items ?? []; track $index) {
5611
- <button type="button" class="kpt-megamenu__link" [disabled]="link.disabled" (click)="pick(link)">
5612
- @if (link.icon) { <kpt-icon [name]="link.icon" /> }
5613
- <span>{{ link.label }}</span>
5614
- </button>
5615
- }
5616
- </div>
5617
- }
5618
- </div>
5619
- }
5620
7661
  </nav>
5621
- @if (openIndex() !== null) {
5622
- <div class="kpt-megamenu__backdrop" (click)="closeAll()"></div>
5623
- }
5624
- `, isInline: true, styles: ["@layer kpt.components{.kpt-megamenu-host{display:block}.kpt-megamenu{position:relative;display:flex;align-items:center;gap:var(--kpt-space-1, .25rem);padding:var(--kpt-space-1, .25rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem)}.kpt-megamenu__top{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-megamenu__top:hover,.kpt-megamenu__top.is-open{background:var(--kpt-color-muted)}.kpt-megamenu__caret{opacity:.6}.kpt-megamenu__panel{position:absolute;top:calc(100% + 4px);left:0;z-index:calc(var(--kpt-z-overlay, 1000) + 1);display:flex;gap:var(--kpt-space-6, 1.5rem);min-width:min(40rem,90vw);padding:var(--kpt-space-4, 1rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3)}.kpt-megamenu__column{min-width:9rem}.kpt-megamenu__col-title{margin-bottom:var(--kpt-space-2, .5rem);font-size:var(--kpt-font-size-xs, .75rem);font-weight:var(--kpt-font-weight-semibold, 600);text-transform:uppercase;letter-spacing:.04em;color:var(--kpt-color-on-surface-muted)}.kpt-megamenu__link{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);width:100%;padding:var(--kpt-space-2, .5rem);border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem);text-align:left;cursor:pointer}.kpt-megamenu__link:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-megamenu__link:disabled{opacity:.5;cursor:not-allowed}.kpt-megamenu__backdrop{position:fixed;inset:0;z-index:var(--kpt-z-overlay, 1000)}}\n"], dependencies: [{ kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
7662
+
7663
+ <ng-template
7664
+ cdkConnectedOverlay
7665
+ [cdkConnectedOverlayOrigin]="origin"
7666
+ [cdkConnectedOverlayOpen]="openIndex() !== null"
7667
+ [cdkConnectedOverlayPositions]="positions"
7668
+ [cdkConnectedOverlayHasBackdrop]="true"
7669
+ cdkConnectedOverlayBackdropClass="cdk-overlay-transparent-backdrop"
7670
+ (backdropClick)="closeAll()"
7671
+ (detach)="closeAll()"
7672
+ >
7673
+ <div class="kpt-megamenu__panel" role="menu">
7674
+ @for (col of activeColumns(); track $index) {
7675
+ <div class="kpt-megamenu__column">
7676
+ @if (col.label) { <div class="kpt-megamenu__col-title">{{ col.label }}</div> }
7677
+ @for (link of col.items ?? []; track $index) {
7678
+ <button type="button" class="kpt-megamenu__link" [disabled]="link.disabled" (click)="pick(link)">
7679
+ @if (link.icon) { <kpt-icon [name]="link.icon" /> }
7680
+ <span>{{ link.label }}</span>
7681
+ </button>
7682
+ }
7683
+ </div>
7684
+ }
7685
+ </div>
7686
+ </ng-template>
7687
+ `, isInline: true, styles: ["@layer kpt.components{.kpt-megamenu-host{display:block}.kpt-megamenu{position:relative;display:flex;align-items:center;gap:var(--kpt-space-1, .25rem);padding:var(--kpt-space-1, .25rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem)}.kpt-megamenu__top{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-megamenu__top:hover,.kpt-megamenu__top.is-open{background:var(--kpt-color-muted)}.kpt-megamenu__caret{opacity:.6}.kpt-megamenu__panel{display:flex;gap:var(--kpt-space-6, 1.5rem);min-width:min(40rem,90vw);padding:var(--kpt-space-4, 1rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3)}.kpt-megamenu__column{min-width:9rem}.kpt-megamenu__col-title{margin-bottom:var(--kpt-space-2, .5rem);font-size:var(--kpt-font-size-xs, .75rem);font-weight:var(--kpt-font-weight-semibold, 600);text-transform:uppercase;letter-spacing:.04em;color:var(--kpt-color-on-surface-muted)}.kpt-megamenu__link{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);width:100%;padding:var(--kpt-space-2, .5rem);border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem);text-align:left;cursor:pointer}.kpt-megamenu__link:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-megamenu__link:disabled{opacity:.5;cursor:not-allowed}}\n"], dependencies: [{ kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "component", type: KptIcon, selector: "kpt-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
5625
7688
  }
5626
7689
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: KptMegamenu, decorators: [{
5627
7690
  type: Component,
5628
- args: [{ selector: 'kpt-megamenu', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [KptIcon], template: `
5629
- <nav class="kpt-megamenu" role="menubar">
7691
+ args: [{ selector: 'kpt-megamenu', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [CdkOverlayOrigin, CdkConnectedOverlay, KptIcon], template: `
7692
+ <nav class="kpt-megamenu" role="menubar" cdkOverlayOrigin #origin="cdkOverlayOrigin">
5630
7693
  @for (item of items(); track $index; let i = $index) {
5631
7694
  <button
5632
7695
  type="button"
@@ -5640,27 +7703,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
5640
7703
  <kpt-icon name="chevron-down" class="kpt-megamenu__caret" />
5641
7704
  </button>
5642
7705
  }
5643
-
5644
- @if (activeColumns().length) {
5645
- <div class="kpt-megamenu__panel" role="menu">
5646
- @for (col of activeColumns(); track $index) {
5647
- <div class="kpt-megamenu__column">
5648
- @if (col.label) { <div class="kpt-megamenu__col-title">{{ col.label }}</div> }
5649
- @for (link of col.items ?? []; track $index) {
5650
- <button type="button" class="kpt-megamenu__link" [disabled]="link.disabled" (click)="pick(link)">
5651
- @if (link.icon) { <kpt-icon [name]="link.icon" /> }
5652
- <span>{{ link.label }}</span>
5653
- </button>
5654
- }
5655
- </div>
5656
- }
5657
- </div>
5658
- }
5659
7706
  </nav>
5660
- @if (openIndex() !== null) {
5661
- <div class="kpt-megamenu__backdrop" (click)="closeAll()"></div>
5662
- }
5663
- `, host: { class: 'kpt-megamenu-host' }, styles: ["@layer kpt.components{.kpt-megamenu-host{display:block}.kpt-megamenu{position:relative;display:flex;align-items:center;gap:var(--kpt-space-1, .25rem);padding:var(--kpt-space-1, .25rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem)}.kpt-megamenu__top{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-megamenu__top:hover,.kpt-megamenu__top.is-open{background:var(--kpt-color-muted)}.kpt-megamenu__caret{opacity:.6}.kpt-megamenu__panel{position:absolute;top:calc(100% + 4px);left:0;z-index:calc(var(--kpt-z-overlay, 1000) + 1);display:flex;gap:var(--kpt-space-6, 1.5rem);min-width:min(40rem,90vw);padding:var(--kpt-space-4, 1rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3)}.kpt-megamenu__column{min-width:9rem}.kpt-megamenu__col-title{margin-bottom:var(--kpt-space-2, .5rem);font-size:var(--kpt-font-size-xs, .75rem);font-weight:var(--kpt-font-weight-semibold, 600);text-transform:uppercase;letter-spacing:.04em;color:var(--kpt-color-on-surface-muted)}.kpt-megamenu__link{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);width:100%;padding:var(--kpt-space-2, .5rem);border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem);text-align:left;cursor:pointer}.kpt-megamenu__link:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-megamenu__link:disabled{opacity:.5;cursor:not-allowed}.kpt-megamenu__backdrop{position:fixed;inset:0;z-index:var(--kpt-z-overlay, 1000)}}\n"] }]
7707
+
7708
+ <ng-template
7709
+ cdkConnectedOverlay
7710
+ [cdkConnectedOverlayOrigin]="origin"
7711
+ [cdkConnectedOverlayOpen]="openIndex() !== null"
7712
+ [cdkConnectedOverlayPositions]="positions"
7713
+ [cdkConnectedOverlayHasBackdrop]="true"
7714
+ cdkConnectedOverlayBackdropClass="cdk-overlay-transparent-backdrop"
7715
+ (backdropClick)="closeAll()"
7716
+ (detach)="closeAll()"
7717
+ >
7718
+ <div class="kpt-megamenu__panel" role="menu">
7719
+ @for (col of activeColumns(); track $index) {
7720
+ <div class="kpt-megamenu__column">
7721
+ @if (col.label) { <div class="kpt-megamenu__col-title">{{ col.label }}</div> }
7722
+ @for (link of col.items ?? []; track $index) {
7723
+ <button type="button" class="kpt-megamenu__link" [disabled]="link.disabled" (click)="pick(link)">
7724
+ @if (link.icon) { <kpt-icon [name]="link.icon" /> }
7725
+ <span>{{ link.label }}</span>
7726
+ </button>
7727
+ }
7728
+ </div>
7729
+ }
7730
+ </div>
7731
+ </ng-template>
7732
+ `, host: { class: 'kpt-megamenu-host' }, styles: ["@layer kpt.components{.kpt-megamenu-host{display:block}.kpt-megamenu{position:relative;display:flex;align-items:center;gap:var(--kpt-space-1, .25rem);padding:var(--kpt-space-1, .25rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem)}.kpt-megamenu__top{display:inline-flex;align-items:center;gap:var(--kpt-space-2, .5rem);padding:var(--kpt-space-2, .5rem) var(--kpt-space-3, .75rem);border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem);cursor:pointer}.kpt-megamenu__top:hover,.kpt-megamenu__top.is-open{background:var(--kpt-color-muted)}.kpt-megamenu__caret{opacity:.6}.kpt-megamenu__panel{display:flex;gap:var(--kpt-space-6, 1.5rem);min-width:min(40rem,90vw);padding:var(--kpt-space-4, 1rem);background:var(--kpt-color-surface-raised);border:var(--kpt-border-width-thin, 1px) solid var(--kpt-color-border);border-radius:var(--kpt-radius-md, .5rem);box-shadow:var(--kpt-elevation-3)}.kpt-megamenu__column{min-width:9rem}.kpt-megamenu__col-title{margin-bottom:var(--kpt-space-2, .5rem);font-size:var(--kpt-font-size-xs, .75rem);font-weight:var(--kpt-font-weight-semibold, 600);text-transform:uppercase;letter-spacing:.04em;color:var(--kpt-color-on-surface-muted)}.kpt-megamenu__link{display:flex;align-items:center;gap:var(--kpt-space-2, .5rem);width:100%;padding:var(--kpt-space-2, .5rem);border:0;border-radius:var(--kpt-radius-sm, .25rem);background:none;color:var(--kpt-color-on-surface);font-size:var(--kpt-font-size-sm, .875rem);text-align:left;cursor:pointer}.kpt-megamenu__link:hover:not(:disabled){background:var(--kpt-color-muted)}.kpt-megamenu__link:disabled{opacity:.5;cursor:not-allowed}}\n"] }]
5664
7733
  }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], select: [{ type: i0.Output, args: ["select"] }] } });
5665
7734
 
5666
7735
  /**
@@ -5859,5 +7928,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
5859
7928
  * Generated bundle index. Do not edit.
5860
7929
  */
5861
7930
 
5862
- export { KptAccordion, KptAccordionPanel, KptAlert, KptAppShell, KptAutocomplete, KptAvatar, KptAvatarGroup, KptBadge, KptBottomSheet, KptBreadcrumb, KptButton, KptButtonGroup, KptCard, KptCarousel, KptCellDef, KptCheckbox, KptChip, KptChipsInput, KptColorPicker, KptConfirmContainer, KptConfirmService, KptContextMenu, KptDataTable, KptDataView, KptDateRange, KptDatepicker, KptDialog, KptDivider, KptDrawer, KptEmpty, KptFab, KptFieldset, KptFileUpload, KptFormField, KptGalleria, KptIcon, KptIconButton, KptIconRegistry, KptImage, KptInput, KptInputMask, KptInputNumber, KptInputOtp, KptKnob, KptListbox, KptMegamenu, KptMenu, KptMenubar, KptMeterGroup, KptOrderList, KptPaginator, KptPanel, KptPassword, KptPickList, KptPopover, KptProgress, KptRadioGroup, KptRating, KptRichText, KptScrollTop, KptSelect, KptSidenav, KptSkeleton, KptSlider, KptSpeedDial, KptSpinner, KptSplitButton, KptSplitter, KptStep, KptStepper, KptSwitch, KptTab, KptTabs, KptTextarea, KptTimeline, KptToastContainer, KptToastService, KptToolbar, KptTooltip, KptTree };
7931
+ export { KptAccordion, KptAccordionPanel, KptAlert, KptAppShell, KptAutocomplete, KptAvatar, KptAvatarGroup, KptBadge, KptBottomSheet, KptBreadcrumb, KptButton, KptButtonGroup, KptCard, KptCarousel, KptCellDef, KptCheckbox, KptChip, KptChipsInput, KptClock, KptColorPicker, KptConfirmContainer, KptConfirmService, KptContextMenu, KptDataTable, KptDataView, KptDateRange, KptDatepicker, KptDialog, KptDivider, KptDrawer, KptEmpty, KptFab, KptFieldset, KptFileUpload, KptFormField, KptGalleria, KptIcon, KptIconButton, KptIconRegistry, KptImage, KptInput, KptInputMask, KptInputNumber, KptInputOtp, KptKnob, KptListbox, KptMegamenu, KptMenu, KptMenubar, KptMeterGroup, KptOrderList, KptPaginator, KptPanel, KptPassword, KptPickList, KptPopover, KptProgress, KptRadioGroup, KptRating, KptRichText, KptRowDetailDef, KptScrollTop, KptSelect, KptSidenav, KptSkeleton, KptSlider, KptSpeedDial, KptSpinner, KptSplitButton, KptSplitter, KptStep, KptStepper, KptSwitch, KptSwitchGroup, KptTab, KptTabs, KptTextarea, KptTimeline, KptToastContainer, KptToastService, KptToolbar, KptTooltip, KptTree };
5863
7932
  //# sourceMappingURL=konce-pt-angular.mjs.map