@tailng-ui/primitives 0.19.0 → 0.20.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tailng-ui/primitives",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -16,7 +16,7 @@
16
16
  }
17
17
  },
18
18
  "dependencies": {
19
- "@tailng-ui/cdk": "^0.15.0"
19
+ "@tailng-ui/cdk": "^0.16.0"
20
20
  },
21
21
  "peerDependencies": {
22
22
  "@angular/core": "^21.1.0",
@@ -1,12 +1,12 @@
1
1
  import * as i0 from "@angular/core";
2
2
  export declare class TngPrefix {
3
- readonly hostElement: any;
3
+ readonly hostElement: HTMLElement;
4
4
  protected readonly dataSlot: "input-leading";
5
5
  static ɵfac: i0.ɵɵFactoryDeclaration<TngPrefix, never>;
6
6
  static ɵdir: i0.ɵɵDirectiveDeclaration<TngPrefix, "[tngPrefix], [tngInputLeading]", ["tngPrefix"], {}, {}, never, never, true, never>;
7
7
  }
8
8
  export declare class TngSuffix {
9
- readonly hostElement: any;
9
+ readonly hostElement: HTMLElement;
10
10
  protected readonly dataSlot: "input-trailing";
11
11
  static ɵfac: i0.ɵɵFactoryDeclaration<TngSuffix, never>;
12
12
  static ɵdir: i0.ɵɵDirectiveDeclaration<TngSuffix, "[tngSuffix], [tngInputTrailing]", ["tngSuffix"], {}, {}, never, never, true, never>;
@@ -1 +1 @@
1
- {"version":3,"file":"tng-adornment.d.ts","sourceRoot":"","sources":["../../../../../../../../libs/tailng-ui/primitives/src/lib/form/input/tng-adornment.ts"],"names":[],"mappings":";AAEA,qBAIa,SAAS;IACpB,QAAQ,CAAC,WAAW,MAAiD;IAGrE,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAG,eAAe,CAAU;yCAJ5C,SAAS;2CAAT,SAAS;CAKrB;AAED,qBAIa,SAAS;IACpB,QAAQ,CAAC,WAAW,MAAiD;IAGrE,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAG,gBAAgB,CAAU;yCAJ7C,SAAS;2CAAT,SAAS;CAKrB"}
1
+ {"version":3,"file":"tng-adornment.d.ts","sourceRoot":"","sources":["../../../../../../../../libs/tailng-ui/primitives/src/lib/form/input/tng-adornment.ts"],"names":[],"mappings":";AAEA,qBAIa,SAAS;IACpB,SAAgB,WAAW,EAAE,WAAW,CAAgE;IAGxG,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAG,eAAe,CAAU;yCAJ5C,SAAS;2CAAT,SAAS;CAKrB;AAED,qBAIa,SAAS;IACpB,SAAgB,WAAW,EAAE,WAAW,CAAgE;IAGxG,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAG,gBAAgB,CAAU;yCAJ7C,SAAS;2CAAT,SAAS;CAKrB"}
@@ -1,4 +1,4 @@
1
- import { Directive, ElementRef, HostBinding, inject } from "@angular/core";
1
+ import { Directive, ElementRef, HostBinding, inject } from '@angular/core';
2
2
  import * as i0 from "@angular/core";
3
3
  export class TngPrefix {
4
4
  hostElement = inject((ElementRef)).nativeElement;
@@ -1 +1 @@
1
- {"version":3,"file":"tng-adornment.js","sourceRoot":"","sources":["../../../../../../../../libs/tailng-ui/primitives/src/lib/form/input/tng-adornment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;;AAM3E,MAAM,OAAO,SAAS;IACX,WAAW,GAAG,MAAM,CAAC,CAAA,UAAuB,CAAA,CAAC,CAAC,aAAa,CAAC;IAGlD,QAAQ,GAAG,eAAwB,CAAC;uGAJ5C,SAAS;2FAAT,SAAS;;2FAAT,SAAS;kBAJrB,SAAS;mBAAC;oBACT,QAAQ,EAAE,gCAAgC;oBAC1C,QAAQ,EAAE,WAAW;iBACtB;;sBAIE,WAAW;uBAAC,gBAAgB;;AAQ/B,MAAM,OAAO,SAAS;IACX,WAAW,GAAG,MAAM,CAAC,CAAA,UAAuB,CAAA,CAAC,CAAC,aAAa,CAAC;IAGlD,QAAQ,GAAG,gBAAyB,CAAC;uGAJ7C,SAAS;2FAAT,SAAS;;2FAAT,SAAS;kBAJrB,SAAS;mBAAC;oBACT,QAAQ,EAAE,iCAAiC;oBAC3C,QAAQ,EAAE,WAAW;iBACtB;;sBAIE,WAAW;uBAAC,gBAAgB","sourcesContent":["import { Directive, ElementRef, HostBinding, inject } from \"@angular/core\";\n\n@Directive({\n selector: '[tngPrefix], [tngInputLeading]',\n exportAs: 'tngPrefix',\n})\nexport class TngPrefix {\n readonly hostElement = inject(ElementRef<HTMLElement>).nativeElement;\n\n @HostBinding('attr.data-slot')\n protected readonly dataSlot = 'input-leading' as const;\n}\n\n@Directive({\n selector: '[tngSuffix], [tngInputTrailing]',\n exportAs: 'tngSuffix',\n})\nexport class TngSuffix {\n readonly hostElement = inject(ElementRef<HTMLElement>).nativeElement;\n\n @HostBinding('attr.data-slot')\n protected readonly dataSlot = 'input-trailing' as const;\n}\n\n"]}
1
+ {"version":3,"file":"tng-adornment.js","sourceRoot":"","sources":["../../../../../../../../libs/tailng-ui/primitives/src/lib/form/input/tng-adornment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;;AAM3E,MAAM,OAAO,SAAS;IACJ,WAAW,GAAgB,MAAM,CAAC,CAAA,UAAuB,CAAA,CAAC,CAAC,aAA4B,CAAC;IAGrF,QAAQ,GAAG,eAAwB,CAAC;uGAJ5C,SAAS;2FAAT,SAAS;;2FAAT,SAAS;kBAJrB,SAAS;mBAAC;oBACT,QAAQ,EAAE,gCAAgC;oBAC1C,QAAQ,EAAE,WAAW;iBACtB;;sBAIE,WAAW;uBAAC,gBAAgB;;AAQ/B,MAAM,OAAO,SAAS;IACJ,WAAW,GAAgB,MAAM,CAAC,CAAA,UAAuB,CAAA,CAAC,CAAC,aAA4B,CAAC;IAGrF,QAAQ,GAAG,gBAAyB,CAAC;uGAJ7C,SAAS;2FAAT,SAAS;;2FAAT,SAAS;kBAJrB,SAAS;mBAAC;oBACT,QAAQ,EAAE,iCAAiC;oBAC3C,QAAQ,EAAE,WAAW;iBACtB;;sBAIE,WAAW;uBAAC,gBAAgB","sourcesContent":["import { Directive, ElementRef, HostBinding, inject } from '@angular/core';\n\n@Directive({\n selector: '[tngPrefix], [tngInputLeading]',\n exportAs: 'tngPrefix',\n})\nexport class TngPrefix {\n public readonly hostElement: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement as HTMLElement;\n\n @HostBinding('attr.data-slot')\n protected readonly dataSlot = 'input-leading' as const;\n}\n\n@Directive({\n selector: '[tngSuffix], [tngInputTrailing]',\n exportAs: 'tngSuffix',\n})\nexport class TngSuffix {\n public readonly hostElement: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement as HTMLElement;\n\n @HostBinding('attr.data-slot')\n protected readonly dataSlot = 'input-trailing' as const;\n}\n"]}
@@ -26,7 +26,7 @@ export declare class TngInputGroup implements AfterContentInit, OnDestroy {
26
26
  protected get dataReadonly(): '' | null;
27
27
  protected get dataFocused(): '' | null;
28
28
  protected onFocusIn(): void;
29
- protected onFocusOut(event: FocusEvent): void;
29
+ protected onFocusOut(nextTarget: Readonly<EventTarget> | null): void;
30
30
  protected hasLeadingSlot(): boolean;
31
31
  protected hasTrailingSlot(): boolean;
32
32
  protected effectiveHasLeading(): boolean;
@@ -34,6 +34,6 @@ export declare class TngInputGroup implements AfterContentInit, OnDestroy {
34
34
  protected primaryControl(): TngInput | null;
35
35
  protected primaryControlElement(): HTMLInputElement | HTMLTextAreaElement | null;
36
36
  static ɵfac: i0.ɵɵFactoryDeclaration<TngInputGroup, never>;
37
- static ɵcmp: i0.ɵɵComponentDeclaration<TngInputGroup, "tng-input-group, [tngInputGroup]", ["tngInputGroup"], { "hasLeading": { "alias": "hasLeading"; "required": false; "isSignal": true; }; "hasTrailing": { "alias": "hasTrailing"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "controlCount": { "alias": "controlCount"; "required": false; "isSignal": true; }; }, {}, ["controls", "prefixSlots", "suffixSlots"], ["[tngPrefix], [tngInputLeading], [data-tng-input-prefix-proxy]", "input[tngInput], textarea[tngInput], [data-tng-input-control-proxy]", "[tngSuffix], [tngInputTrailing], [data-tng-input-suffix-proxy]"], true, never>;
37
+ static ɵcmp: i0.ɵɵComponentDeclaration<TngInputGroup, "tng-input-group, [tngInputGroup]", ["tngInputGroup"], { "hasLeading": { "alias": "hasLeading"; "required": false; "isSignal": true; }; "hasTrailing": { "alias": "hasTrailing"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "controlCount": { "alias": "controlCount"; "required": false; "isSignal": true; }; }, {}, ["controls", "prefixSlots", "suffixSlots"], ["[tngPrefix], [tngInputLeading], [data-tng-input-prefix-proxy]", "input[tngInput], textarea[tngInput], textarea[tngTextarea], [data-tng-input-control-proxy]", "[tngSuffix], [tngInputTrailing], [data-tng-input-suffix-proxy]"], true, never>;
38
38
  }
39
39
  //# sourceMappingURL=tng-input-group.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tng-input-group.d.ts","sourceRoot":"","sources":["../../../../../../../../libs/tailng-ui/primitives/src/lib/form/input/tng-input-group.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAa5E,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;;AAgBvC,qBA6Ca,aAAc,YAAW,gBAAgB,EAAE,SAAS;IAC/D,SAAgB,UAAU,sDAA+B;IACzD,SAAgB,WAAW,sDAA+B;IAC1D,SAAgB,QAAQ,sDAA+B;IACvD,SAAgB,OAAO,sDAA+B;IACtD,SAAgB,QAAQ,sDAA+B;IACvD,SAAgB,YAAY,qDAA8B;IAG1D,SAAS,CAAC,QAAQ,EAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAGzC,SAAS,CAAC,WAAW,EAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IAG7C,SAAS,CAAC,WAAW,EAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IAE7C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAiD;IAC7E,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuB;IAElD,OAAO,CAAC,qBAAqB;IAmBtB,kBAAkB,IAAI,IAAI;IAM1B,WAAW,IAAI,IAAI;IAM1B,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAG,aAAa,CAAU;IAGrD,SAAS,KAAK,cAAc,IAAI,EAAE,GAAG,IAAI,CAExC;IAGD,SAAS,KAAK,eAAe,IAAI,EAAE,GAAG,IAAI,CAEzC;IAGD,SAAS,KAAK,YAAY,IAAI,EAAE,GAAG,IAAI,CAUtC;IAGD,SAAS,KAAK,WAAW,IAAI,EAAE,GAAG,IAAI,CAWrC;IAGD,SAAS,KAAK,YAAY,IAAI,EAAE,GAAG,IAAI,CAUtC;IAGD,SAAS,KAAK,WAAW,IAAI,EAAE,GAAG,IAAI,CAErC;IAGD,SAAS,CAAC,SAAS,IAAI,IAAI;IAK3B,SAAS,CAAC,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAO7C,SAAS,CAAC,cAAc,IAAI,OAAO;IAQnC,SAAS,CAAC,eAAe,IAAI,OAAO;IAQpC,SAAS,CAAC,mBAAmB,IAAI,OAAO;IAMxC,SAAS,CAAC,oBAAoB,IAAI,OAAO;IAMzC,SAAS,CAAC,cAAc,IAAI,QAAQ,GAAG,IAAI;IAK3C,SAAS,CAAC,qBAAqB,IAAI,gBAAgB,GAAG,mBAAmB,GAAG,IAAI;yCA3JrE,aAAa;2CAAb,aAAa;CAsKzB"}
1
+ {"version":3,"file":"tng-input-group.d.ts","sourceRoot":"","sources":["../../../../../../../../libs/tailng-ui/primitives/src/lib/form/input/tng-input-group.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAa5E,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;;AAMvC,qBA6Ca,aAAc,YAAW,gBAAgB,EAAE,SAAS;IAC/D,SAAgB,UAAU,sDAA+B;IACzD,SAAgB,WAAW,sDAA+B;IAC1D,SAAgB,QAAQ,sDAA+B;IACvD,SAAgB,OAAO,sDAA+B;IACtD,SAAgB,QAAQ,sDAA+B;IACvD,SAAgB,YAAY,qDAA8B;IAG1D,SAAS,CAAC,QAAQ,EAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAGzC,SAAS,CAAC,WAAW,EAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IAG7C,SAAS,CAAC,WAAW,EAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IAE7C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6E;IACzG,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuB;IAElD,OAAO,CAAC,qBAAqB;IAmBtB,kBAAkB,IAAI,IAAI;IAM1B,WAAW,IAAI,IAAI;IAM1B,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAG,aAAa,CAAU;IAGrD,SAAS,KAAK,cAAc,IAAI,EAAE,GAAG,IAAI,CAExC;IAGD,SAAS,KAAK,eAAe,IAAI,EAAE,GAAG,IAAI,CAEzC;IAGD,SAAS,KAAK,YAAY,IAAI,EAAE,GAAG,IAAI,CAUtC;IAGD,SAAS,KAAK,WAAW,IAAI,EAAE,GAAG,IAAI,CAWrC;IAGD,SAAS,KAAK,YAAY,IAAI,EAAE,GAAG,IAAI,CAUtC;IAGD,SAAS,KAAK,WAAW,IAAI,EAAE,GAAG,IAAI,CAErC;IAGD,SAAS,CAAC,SAAS,IAAI,IAAI;IAK3B,SAAS,CAAC,UAAU,CAAC,UAAU,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,IAAI,GAAG,IAAI;IAMpE,SAAS,CAAC,cAAc,IAAI,OAAO;IAoBnC,SAAS,CAAC,eAAe,IAAI,OAAO;IAoBpC,SAAS,CAAC,mBAAmB,IAAI,OAAO;IAMxC,SAAS,CAAC,oBAAoB,IAAI,OAAO;IAMzC,SAAS,CAAC,cAAc,IAAI,QAAQ,GAAG,IAAI;IAK3C,SAAS,CAAC,qBAAqB,IAAI,gBAAgB,GAAG,mBAAmB,GAAG,IAAI;yCAlLrE,aAAa;2CAAb,aAAa;CA6LzB"}
@@ -3,16 +3,8 @@ import { Subject, takeUntil } from 'rxjs';
3
3
  import { TngPrefix, TngSuffix } from './tng-adornment';
4
4
  import { TngInput } from './tng-input';
5
5
  import * as i0 from "@angular/core";
6
- function hasProjectedContent(element) {
7
- return Array.from(element.childNodes).some((node) => {
8
- if (node.nodeType === Node.ELEMENT_NODE) {
9
- return true;
10
- }
11
- if (node.nodeType === Node.TEXT_NODE) {
12
- return (node.textContent ?? '').trim().length > 0;
13
- }
14
- return false;
15
- });
6
+ function containsProjectedContent(childElementCount, textContent) {
7
+ return childElementCount > 0 || (textContent ?? '').trim().length > 0;
16
8
  }
17
9
  export class TngInputGroup {
18
10
  hasLeading = input(null, ...(ngDevMode ? [{ debugName: "hasLeading" }] : []));
@@ -33,10 +25,10 @@ export class TngInputGroup {
33
25
  if (!this.controls)
34
26
  return;
35
27
  const queriedCount = this.controls.length;
36
- const domCount = this.hostElement.querySelectorAll('[data-tng-input-control-proxy] input, [data-tng-input-control-proxy] textarea, input[tngInput], textarea[tngInput]').length;
28
+ const domCount = this.hostElement.querySelectorAll('[data-tng-input-control-proxy] input, [data-tng-input-control-proxy] textarea, input[tngInput], textarea[tngInput], textarea[tngTextarea]').length;
37
29
  const count = this.controlCount() ?? (queriedCount > 0 ? queriedCount : domCount);
38
30
  if (count !== 1) {
39
- console.warn(`[tngInputGroup] Expected exactly 1 control (input/textarea with tngInput), but found ${count}.`, this.hostElement);
31
+ globalThis.console.warn(`[tngInputGroup] Expected exactly 1 control (input/textarea with tngInput or textarea with tngTextarea), but found ${count}.`, this.hostElement);
40
32
  }
41
33
  }
42
34
  ngAfterContentInit() {
@@ -98,25 +90,40 @@ export class TngInputGroup {
98
90
  onFocusIn() {
99
91
  this.focused = true;
100
92
  }
101
- onFocusOut(event) {
102
- const nextTarget = event.relatedTarget;
93
+ onFocusOut(nextTarget) {
103
94
  if (nextTarget instanceof Node && this.hostElement.contains(nextTarget))
104
95
  return;
105
96
  this.focused = false;
106
97
  }
107
98
  hasLeadingSlot() {
108
99
  const proxy = this.hostElement.querySelector('[data-tng-input-prefix-proxy]');
109
- if (proxy instanceof HTMLElement)
110
- return hasProjectedContent(proxy);
100
+ if (proxy instanceof HTMLElement &&
101
+ containsProjectedContent(proxy.childElementCount, proxy.textContent)) {
102
+ return true;
103
+ }
111
104
  const slots = this.prefixSlots?.toArray() ?? [];
112
- return slots.some((slot) => hasProjectedContent(slot.hostElement));
105
+ for (const slot of slots) {
106
+ const hostElement = slot.hostElement;
107
+ if (containsProjectedContent(hostElement.childElementCount, hostElement.textContent)) {
108
+ return true;
109
+ }
110
+ }
111
+ return false;
113
112
  }
114
113
  hasTrailingSlot() {
115
114
  const proxy = this.hostElement.querySelector('[data-tng-input-suffix-proxy]');
116
- if (proxy instanceof HTMLElement)
117
- return hasProjectedContent(proxy);
115
+ if (proxy instanceof HTMLElement &&
116
+ containsProjectedContent(proxy.childElementCount, proxy.textContent)) {
117
+ return true;
118
+ }
118
119
  const slots = this.suffixSlots?.toArray() ?? [];
119
- return slots.some((slot) => hasProjectedContent(slot.hostElement));
120
+ for (const slot of slots) {
121
+ const hostElement = slot.hostElement;
122
+ if (containsProjectedContent(hostElement.childElementCount, hostElement.textContent)) {
123
+ return true;
124
+ }
125
+ }
126
+ return false;
120
127
  }
121
128
  effectiveHasLeading() {
122
129
  const override = this.hasLeading();
@@ -135,14 +142,14 @@ export class TngInputGroup {
135
142
  return controls[0] ?? null;
136
143
  }
137
144
  primaryControlElement() {
138
- const element = this.hostElement.querySelector('[data-tng-input-control-proxy] input, [data-tng-input-control-proxy] textarea, input[tngInput], textarea[tngInput]');
145
+ const element = this.hostElement.querySelector('[data-tng-input-control-proxy] input, [data-tng-input-control-proxy] textarea, input[tngInput], textarea[tngInput], textarea[tngTextarea]');
139
146
  if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
140
147
  return element;
141
148
  }
142
149
  return null;
143
150
  }
144
151
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: TngInputGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
145
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: TngInputGroup, isStandalone: true, selector: "tng-input-group, [tngInputGroup]", inputs: { hasLeading: { classPropertyName: "hasLeading", publicName: "hasLeading", isSignal: true, isRequired: false, transformFunction: null }, hasTrailing: { classPropertyName: "hasTrailing", publicName: "hasTrailing", 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 }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, controlCount: { classPropertyName: "controlCount", publicName: "controlCount", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "focusin": "onFocusIn()", "focusout": "onFocusOut($event)" }, properties: { "attr.data-slot": "this.dataSlot", "attr.data-has-leading": "this.dataHasLeading", "attr.data-has-trailing": "this.dataHasTrailing", "attr.data-disabled": "this.dataDisabled", "attr.data-invalid": "this.dataInvalid", "attr.data-readonly": "this.dataReadonly", "attr.data-focused": "this.dataFocused" } }, queries: [{ propertyName: "controls", predicate: TngInput, descendants: true }, { propertyName: "prefixSlots", predicate: TngPrefix, descendants: true }, { propertyName: "suffixSlots", predicate: TngSuffix, descendants: true }], exportAs: ["tngInputGroup"], ngImport: i0, template: `
152
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: TngInputGroup, isStandalone: true, selector: "tng-input-group, [tngInputGroup]", inputs: { hasLeading: { classPropertyName: "hasLeading", publicName: "hasLeading", isSignal: true, isRequired: false, transformFunction: null }, hasTrailing: { classPropertyName: "hasTrailing", publicName: "hasTrailing", 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 }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, controlCount: { classPropertyName: "controlCount", publicName: "controlCount", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "focusin": "onFocusIn()", "focusout": "onFocusOut($event.relatedTarget)" }, properties: { "attr.data-slot": "this.dataSlot", "attr.data-has-leading": "this.dataHasLeading", "attr.data-has-trailing": "this.dataHasTrailing", "attr.data-disabled": "this.dataDisabled", "attr.data-invalid": "this.dataInvalid", "attr.data-readonly": "this.dataReadonly", "attr.data-focused": "this.dataFocused" } }, queries: [{ propertyName: "controls", predicate: TngInput, descendants: true }, { propertyName: "prefixSlots", predicate: TngPrefix, descendants: true }, { propertyName: "suffixSlots", predicate: TngSuffix, descendants: true }], exportAs: ["tngInputGroup"], ngImport: i0, template: `
146
153
  @if (hasLeadingSlot()) {
147
154
  <span class="tng-input-group-leading" data-slot="input-group-leading">
148
155
  <ng-content select="[tngPrefix], [tngInputLeading], [data-tng-input-prefix-proxy]"></ng-content>
@@ -150,7 +157,7 @@ export class TngInputGroup {
150
157
  }
151
158
 
152
159
  <span class="tng-input-group-control" data-slot="input-group-control">
153
- <ng-content select="input[tngInput], textarea[tngInput], [data-tng-input-control-proxy]"></ng-content>
160
+ <ng-content select="input[tngInput], textarea[tngInput], textarea[tngTextarea], [data-tng-input-control-proxy]"></ng-content>
154
161
  </span>
155
162
 
156
163
  @if (hasTrailingSlot()) {
@@ -170,7 +177,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
170
177
  }
171
178
 
172
179
  <span class="tng-input-group-control" data-slot="input-group-control">
173
- <ng-content select="input[tngInput], textarea[tngInput], [data-tng-input-control-proxy]"></ng-content>
180
+ <ng-content select="input[tngInput], textarea[tngInput], textarea[tngTextarea], [data-tng-input-control-proxy]"></ng-content>
174
181
  </span>
175
182
 
176
183
  @if (hasTrailingSlot()) {
@@ -214,6 +221,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
214
221
  args: ['focusin']
215
222
  }], onFocusOut: [{
216
223
  type: HostListener,
217
- args: ['focusout', ['$event']]
224
+ args: ['focusout', ['$event.relatedTarget']]
218
225
  }] } });
219
226
  //# sourceMappingURL=tng-input-group.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tng-input-group.js","sourceRoot":"","sources":["../../../../../../../../libs/tailng-ui/primitives/src/lib/form/input/tng-input-group.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AfterContentInit, OnDestroy, QueryList } from '@angular/core';\nimport {\n Component,\n ContentChildren,\n ElementRef,\n HostBinding,\n HostListener,\n inject,\n input,\n isDevMode,\n} from '@angular/core';\nimport { Subject, takeUntil } from 'rxjs';\n\nimport { TngPrefix, TngSuffix } from './tng-adornment';\nimport { TngInput } from './tng-input';\n\nfunction hasProjectedContent(element: HTMLElement): boolean {\n return Array.from(element.childNodes).some((node) => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n return true;\n }\n\n if (node.nodeType === Node.TEXT_NODE) {\n return (node.textContent ?? '').trim().length > 0;\n }\n\n return false;\n });\n}\n\n@Component({\n selector: 'tng-input-group, [tngInputGroup]',\n exportAs: 'tngInputGroup',\n template: `\n @if (hasLeadingSlot()) {\n <span class=\"tng-input-group-leading\" data-slot=\"input-group-leading\">\n <ng-content select=\"[tngPrefix], [tngInputLeading], [data-tng-input-prefix-proxy]\"></ng-content>\n </span>\n }\n\n <span class=\"tng-input-group-control\" data-slot=\"input-group-control\">\n <ng-content select=\"input[tngInput], textarea[tngInput], [data-tng-input-control-proxy]\"></ng-content>\n </span>\n\n @if (hasTrailingSlot()) {\n <span class=\"tng-input-group-trailing\" data-slot=\"input-group-trailing\">\n <ng-content select=\"[tngSuffix], [tngInputTrailing], [data-tng-input-suffix-proxy]\"></ng-content>\n </span>\n }\n `,\n styles: [\n `\n :host {\n display: flex;\n align-items: center;\n min-width: 0;\n }\n\n .tng-input-group-leading,\n .tng-input-group-trailing {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n min-width: 0;\n }\n\n .tng-input-group-control {\n flex: 1 1 auto;\n display: flex;\n align-items: center;\n min-width: 0;\n }\n `,\n ],\n})\nexport class TngInputGroup implements AfterContentInit, OnDestroy {\n public readonly hasLeading = input<boolean | null>(null);\n public readonly hasTrailing = input<boolean | null>(null);\n public readonly disabled = input<boolean | null>(null);\n public readonly invalid = input<boolean | null>(null);\n public readonly readonly = input<boolean | null>(null);\n public readonly controlCount = input<number | null>(null);\n\n @ContentChildren(TngInput, { descendants: true })\n protected controls!: QueryList<TngInput>;\n\n @ContentChildren(TngPrefix, { descendants: true })\n protected prefixSlots!: QueryList<TngPrefix>;\n\n @ContentChildren(TngSuffix, { descendants: true })\n protected suffixSlots!: QueryList<TngSuffix>;\n\n private readonly hostElement = inject(ElementRef<HTMLElement>).nativeElement;\n private focused = false;\n private readonly destroyed$ = new Subject<void>();\n\n private validateSingleControl(): void {\n if (!isDevMode()) return;\n if (!this.controls) return;\n\n const queriedCount = this.controls.length;\n const domCount = this.hostElement.querySelectorAll(\n '[data-tng-input-control-proxy] input, [data-tng-input-control-proxy] textarea, input[tngInput], textarea[tngInput]',\n ).length;\n\n const count = this.controlCount() ?? (queriedCount > 0 ? queriedCount : domCount);\n\n if (count !== 1) {\n console.warn(\n `[tngInputGroup] Expected exactly 1 control (input/textarea with tngInput), but found ${count}.`,\n this.hostElement,\n );\n }\n }\n\n public ngAfterContentInit(): void {\n queueMicrotask(() => this.validateSingleControl());\n\n this.controls.changes.pipe(takeUntil(this.destroyed$)).subscribe(() => this.validateSingleControl());\n }\n\n public ngOnDestroy(): void {\n this.destroyed$.next();\n this.destroyed$.complete();\n }\n\n @HostBinding('attr.data-slot')\n protected readonly dataSlot = 'input-group' as const;\n\n @HostBinding('attr.data-has-leading')\n protected get dataHasLeading(): '' | null {\n return this.effectiveHasLeading() ? '' : null;\n }\n\n @HostBinding('attr.data-has-trailing')\n protected get dataHasTrailing(): '' | null {\n return this.effectiveHasTrailing() ? '' : null;\n }\n\n @HostBinding('attr.data-disabled')\n protected get dataDisabled(): '' | null {\n const override = this.disabled();\n if (override !== null) return override ? '' : null;\n\n const control = this.primaryControl();\n if (control !== null) return control.disabled() ? '' : null;\n\n const element = this.primaryControlElement();\n if (element === null) return null;\n return element.hasAttribute('disabled') ? '' : null;\n }\n\n @HostBinding('attr.data-invalid')\n protected get dataInvalid(): '' | null {\n const override = this.invalid();\n if (override !== null) return override ? '' : null;\n\n const control = this.primaryControl();\n if (control !== null) return control.isInvalid() ? '' : null;\n\n const element = this.primaryControlElement();\n if (element === null) return null;\n if (element.getAttribute('aria-invalid') === 'true') return '';\n return element.matches(':invalid') ? '' : null;\n }\n\n @HostBinding('attr.data-readonly')\n protected get dataReadonly(): '' | null {\n const override = this.readonly();\n if (override !== null) return override ? '' : null;\n\n const control = this.primaryControl();\n if (control !== null) return control.readonly() ? '' : null;\n\n const element = this.primaryControlElement();\n if (element === null) return null;\n return element.hasAttribute('readonly') ? '' : null;\n }\n\n @HostBinding('attr.data-focused')\n protected get dataFocused(): '' | null {\n return this.focused ? '' : null;\n }\n\n @HostListener('focusin')\n protected onFocusIn(): void {\n this.focused = true;\n }\n\n @HostListener('focusout', ['$event'])\n protected onFocusOut(event: FocusEvent): void {\n const nextTarget = event.relatedTarget;\n if (nextTarget instanceof Node && this.hostElement.contains(nextTarget)) return;\n\n this.focused = false;\n }\n\n protected hasLeadingSlot(): boolean {\n const proxy = this.hostElement.querySelector('[data-tng-input-prefix-proxy]');\n if (proxy instanceof HTMLElement) return hasProjectedContent(proxy);\n\n const slots = this.prefixSlots?.toArray() ?? [];\n return slots.some((slot) => hasProjectedContent(slot.hostElement));\n }\n\n protected hasTrailingSlot(): boolean {\n const proxy = this.hostElement.querySelector('[data-tng-input-suffix-proxy]');\n if (proxy instanceof HTMLElement) return hasProjectedContent(proxy);\n\n const slots = this.suffixSlots?.toArray() ?? [];\n return slots.some((slot) => hasProjectedContent(slot.hostElement));\n }\n\n protected effectiveHasLeading(): boolean {\n const override = this.hasLeading();\n if (override !== null) return override;\n return this.hasLeadingSlot();\n }\n\n protected effectiveHasTrailing(): boolean {\n const override = this.hasTrailing();\n if (override !== null) return override;\n return this.hasTrailingSlot();\n }\n\n protected primaryControl(): TngInput | null {\n const controls = this.controls?.toArray() ?? [];\n return controls[0] ?? null;\n }\n\n protected primaryControlElement(): HTMLInputElement | HTMLTextAreaElement | null {\n const element = this.hostElement.querySelector(\n '[data-tng-input-control-proxy] input, [data-tng-input-control-proxy] textarea, input[tngInput], textarea[tngInput]',\n );\n\n if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {\n return element;\n }\n\n return null;\n }\n}"]}
1
+ {"version":3,"file":"tng-input-group.js","sourceRoot":"","sources":["../../../../../../../../libs/tailng-ui/primitives/src/lib/form/input/tng-input-group.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AfterContentInit, OnDestroy, QueryList } from '@angular/core';\nimport {\n Component,\n ContentChildren,\n ElementRef,\n HostBinding,\n HostListener,\n inject,\n input,\n isDevMode,\n} from '@angular/core';\nimport { Subject, takeUntil } from 'rxjs';\n\nimport { TngPrefix, TngSuffix } from './tng-adornment';\nimport { TngInput } from './tng-input';\n\nfunction containsProjectedContent(childElementCount: number, textContent: string | null): boolean {\n return childElementCount > 0 || (textContent ?? '').trim().length > 0;\n}\n\n@Component({\n selector: 'tng-input-group, [tngInputGroup]',\n exportAs: 'tngInputGroup',\n template: `\n @if (hasLeadingSlot()) {\n <span class=\"tng-input-group-leading\" data-slot=\"input-group-leading\">\n <ng-content select=\"[tngPrefix], [tngInputLeading], [data-tng-input-prefix-proxy]\"></ng-content>\n </span>\n }\n\n <span class=\"tng-input-group-control\" data-slot=\"input-group-control\">\n <ng-content select=\"input[tngInput], textarea[tngInput], textarea[tngTextarea], [data-tng-input-control-proxy]\"></ng-content>\n </span>\n\n @if (hasTrailingSlot()) {\n <span class=\"tng-input-group-trailing\" data-slot=\"input-group-trailing\">\n <ng-content select=\"[tngSuffix], [tngInputTrailing], [data-tng-input-suffix-proxy]\"></ng-content>\n </span>\n }\n `,\n styles: [\n `\n :host {\n display: flex;\n align-items: center;\n min-width: 0;\n }\n\n .tng-input-group-leading,\n .tng-input-group-trailing {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n min-width: 0;\n }\n\n .tng-input-group-control {\n flex: 1 1 auto;\n display: flex;\n align-items: center;\n min-width: 0;\n }\n `,\n ],\n})\nexport class TngInputGroup implements AfterContentInit, OnDestroy {\n public readonly hasLeading = input<boolean | null>(null);\n public readonly hasTrailing = input<boolean | null>(null);\n public readonly disabled = input<boolean | null>(null);\n public readonly invalid = input<boolean | null>(null);\n public readonly readonly = input<boolean | null>(null);\n public readonly controlCount = input<number | null>(null);\n\n @ContentChildren(TngInput, { descendants: true })\n protected controls!: QueryList<TngInput>;\n\n @ContentChildren(TngPrefix, { descendants: true })\n protected prefixSlots!: QueryList<TngPrefix>;\n\n @ContentChildren(TngSuffix, { descendants: true })\n protected suffixSlots!: QueryList<TngSuffix>;\n\n private readonly hostElement: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement as HTMLElement;\n private focused = false;\n private readonly destroyed$ = new Subject<void>();\n\n private validateSingleControl(): void {\n if (!isDevMode()) return;\n if (!this.controls) return;\n\n const queriedCount = this.controls.length;\n const domCount = this.hostElement.querySelectorAll(\n '[data-tng-input-control-proxy] input, [data-tng-input-control-proxy] textarea, input[tngInput], textarea[tngInput], textarea[tngTextarea]',\n ).length;\n\n const count = this.controlCount() ?? (queriedCount > 0 ? queriedCount : domCount);\n\n if (count !== 1) {\n globalThis.console.warn(\n `[tngInputGroup] Expected exactly 1 control (input/textarea with tngInput or textarea with tngTextarea), but found ${count}.`,\n this.hostElement,\n );\n }\n }\n\n public ngAfterContentInit(): void {\n queueMicrotask(() => this.validateSingleControl());\n\n this.controls.changes.pipe(takeUntil(this.destroyed$)).subscribe(() => this.validateSingleControl());\n }\n\n public ngOnDestroy(): void {\n this.destroyed$.next();\n this.destroyed$.complete();\n }\n\n @HostBinding('attr.data-slot')\n protected readonly dataSlot = 'input-group' as const;\n\n @HostBinding('attr.data-has-leading')\n protected get dataHasLeading(): '' | null {\n return this.effectiveHasLeading() ? '' : null;\n }\n\n @HostBinding('attr.data-has-trailing')\n protected get dataHasTrailing(): '' | null {\n return this.effectiveHasTrailing() ? '' : null;\n }\n\n @HostBinding('attr.data-disabled')\n protected get dataDisabled(): '' | null {\n const override = this.disabled();\n if (override !== null) return override ? '' : null;\n\n const control = this.primaryControl();\n if (control !== null) return control.disabled() ? '' : null;\n\n const element = this.primaryControlElement();\n if (element === null) return null;\n return element.hasAttribute('disabled') ? '' : null;\n }\n\n @HostBinding('attr.data-invalid')\n protected get dataInvalid(): '' | null {\n const override = this.invalid();\n if (override !== null) return override ? '' : null;\n\n const control = this.primaryControl();\n if (control !== null) return control.isInvalid() ? '' : null;\n\n const element = this.primaryControlElement();\n if (element === null) return null;\n if (element.getAttribute('aria-invalid') === 'true') return '';\n return element.matches(':invalid') ? '' : null;\n }\n\n @HostBinding('attr.data-readonly')\n protected get dataReadonly(): '' | null {\n const override = this.readonly();\n if (override !== null) return override ? '' : null;\n\n const control = this.primaryControl();\n if (control !== null) return control.readonly() ? '' : null;\n\n const element = this.primaryControlElement();\n if (element === null) return null;\n return element.hasAttribute('readonly') ? '' : null;\n }\n\n @HostBinding('attr.data-focused')\n protected get dataFocused(): '' | null {\n return this.focused ? '' : null;\n }\n\n @HostListener('focusin')\n protected onFocusIn(): void {\n this.focused = true;\n }\n\n @HostListener('focusout', ['$event.relatedTarget'])\n protected onFocusOut(nextTarget: Readonly<EventTarget> | null): void {\n if (nextTarget instanceof Node && this.hostElement.contains(nextTarget)) return;\n\n this.focused = false;\n }\n\n protected hasLeadingSlot(): boolean {\n const proxy = this.hostElement.querySelector('[data-tng-input-prefix-proxy]');\n if (\n proxy instanceof HTMLElement &&\n containsProjectedContent(proxy.childElementCount, proxy.textContent)\n ) {\n return true;\n }\n\n const slots = this.prefixSlots?.toArray() ?? [];\n for (const slot of slots) {\n const hostElement = slot.hostElement;\n if (containsProjectedContent(hostElement.childElementCount, hostElement.textContent)) {\n return true;\n }\n }\n\n return false;\n }\n\n protected hasTrailingSlot(): boolean {\n const proxy = this.hostElement.querySelector('[data-tng-input-suffix-proxy]');\n if (\n proxy instanceof HTMLElement &&\n containsProjectedContent(proxy.childElementCount, proxy.textContent)\n ) {\n return true;\n }\n\n const slots = this.suffixSlots?.toArray() ?? [];\n for (const slot of slots) {\n const hostElement = slot.hostElement;\n if (containsProjectedContent(hostElement.childElementCount, hostElement.textContent)) {\n return true;\n }\n }\n\n return false;\n }\n\n protected effectiveHasLeading(): boolean {\n const override = this.hasLeading();\n if (override !== null) return override;\n return this.hasLeadingSlot();\n }\n\n protected effectiveHasTrailing(): boolean {\n const override = this.hasTrailing();\n if (override !== null) return override;\n return this.hasTrailingSlot();\n }\n\n protected primaryControl(): TngInput | null {\n const controls = this.controls?.toArray() ?? [];\n return controls[0] ?? null;\n }\n\n protected primaryControlElement(): HTMLInputElement | HTMLTextAreaElement | null {\n const element = this.hostElement.querySelector(\n '[data-tng-input-control-proxy] input, [data-tng-input-control-proxy] textarea, input[tngInput], textarea[tngInput], textarea[tngTextarea]',\n );\n\n if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {\n return element;\n }\n\n return null;\n }\n}\n"]}