@ngstarter-ui/components 21.0.41 → 21.0.42

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.
@@ -2892,15 +2892,23 @@
2892
2892
  "purpose": "Let users choose a country from the built-in country list and store its ISO country code.",
2893
2893
  "useWhen": "Use in addresses, user profiles, billing, shipping, legal forms, tax forms, tenant settings, and locale settings where the form value should be a country code such as US, PL, or DE. The component shows country flags and names, supports search by name or ISO code, and integrates with FormField. Do not use for phone dialing codes; use PhoneInput. Do not use for currency selection; use CurrencySelect. Do not use for custom region, city, office, or location lists; use Select or Autocomplete.",
2894
2894
  "exampleTopics": [
2895
- "Basic country select"
2895
+ "Unselected country",
2896
+ "Basic country select",
2897
+ "Unselected country select"
2896
2898
  ],
2897
- "minimalExample": "<ngs-form-field class=\"w-1/2\">\n <ngs-label>Country</ngs-label>\n <ngs-country-select [(ngModel)]=\"country\" placeholder=\"Select a country\"/>\n</ngs-form-field>\n<p>\n Selected country: {{ country() }}\n</p>",
2899
+ "minimalExample": "<ngs-form-field class=\"w-1/2\">\n <ngs-label>Country</ngs-label>\n <ngs-country-select [(ngModel)]=\"country\" placeholder=\"Select a country\" clearable/>\n</ngs-form-field>\n<p>\n Selected country: {{ country() }}\n</p>",
2898
2900
  "exampleFiles": [
2899
2901
  {
2900
2902
  "name": "basic-country-select-example",
2901
2903
  "title": "Basic country select",
2902
2904
  "file": "projects/docs/src/app/forms/country/_examples/basic-country-select-example/basic-country-select-example.html",
2903
- "source": "<ngs-form-field class=\"w-1/2\">\n <ngs-label>Country</ngs-label>\n <ngs-country-select [(ngModel)]=\"country\" placeholder=\"Select a country\"/>\n</ngs-form-field>\n<p>\n Selected country: {{ country() }}\n</p>"
2905
+ "source": "<ngs-form-field class=\"w-1/2\">\n <ngs-label>Country</ngs-label>\n <ngs-country-select [(ngModel)]=\"country\" placeholder=\"Select a country\" clearable/>\n</ngs-form-field>\n<p>\n Selected country: {{ country() }}\n</p>"
2906
+ },
2907
+ {
2908
+ "name": "unselected-country-select-example",
2909
+ "title": "Unselected country select",
2910
+ "file": "projects/docs/src/app/forms/country/_examples/unselected-country-select-example/unselected-country-select-example.html",
2911
+ "source": "<ngs-form-field class=\"w-1/2\">\n <ngs-label>Country</ngs-label>\n <ngs-country-select [(ngModel)]=\"country\" placeholder=\"Select a country\" clearable/>\n</ngs-form-field>\n<p>\n Selected country: {{ country() || 'No country selected' }}\n</p>"
2904
2912
  }
2905
2913
  ],
2906
2914
  "previewAsset": "projects/components/country-select/preview.svg",
@@ -2910,18 +2918,28 @@
2910
2918
  "exportedSymbols": [
2911
2919
  "countries",
2912
2920
  "Country",
2913
- "CountrySelect"
2921
+ "CountrySelect",
2922
+ "CountrySelectValue"
2914
2923
  ],
2915
2924
  "inputs": [
2925
+ "aria-describedby",
2926
+ "aria-label",
2927
+ "clearable",
2916
2928
  "disabled",
2929
+ "hideCheckIcon",
2930
+ "id",
2931
+ "multiple",
2917
2932
  "placeholder",
2918
2933
  "required",
2919
2934
  "searchTerm",
2920
- "showCountryCode"
2935
+ "showCountryCode",
2936
+ "tabIndex",
2937
+ "value"
2921
2938
  ],
2922
2939
  "outputs": [
2923
2940
  "closed",
2924
- "opened"
2941
+ "opened",
2942
+ "selectionChange"
2925
2943
  ],
2926
2944
  "cssTokens": [
2927
2945
  "--ngs-color-neutral-500",
@@ -7533,6 +7551,7 @@
7533
7551
  "useWhen": "Use ngs-radio-group with ngs-radio-button for simple text options in forms, settings, filters, and preference screens where all options should be visible and the user can choose only one. Put value on each radio button and bind the group value with value, ngModel, or formControlName. Use name when native form grouping matters, disabled on the group or individual radio button when needed, and change when the screen must react to selection changes. Do not use Radio for multiple selection; use Checkbox. Do not use for long option lists; use Select or Autocomplete. Do not use for rich options with descriptions, icons, or large clickable blocks; use RadioCard. Do not use as a segmented view switcher; use Segmented or ButtonToggle. Do not use for yes/no boolean settings when SlideToggle or Checkbox better matches the meaning.",
7534
7552
  "exampleTopics": [
7535
7553
  "Basic Radios",
7554
+ "Radio Orientation",
7536
7555
  "Radio Card",
7537
7556
  "Basic radio"
7538
7557
  ],
@@ -7549,6 +7568,12 @@
7549
7568
  "title": "Radio card",
7550
7569
  "file": "projects/docs/src/app/forms/radio/_examples/radio-card-example/radio-card-example.html",
7551
7570
  "source": "<form [formGroup]=\"form\">\n <ngs-radio-card-group formControlName=\"privacy\">\n <ngs-radio-card value=\"open\">\n <ngs-radio-card-title>\n <ngs-icon name=\"fluent:globe-24-regular\"/>\n Open\n </ngs-radio-card-title>\n <ngs-radio-card-content>\n Posts and community members are public and visible to search engines.\n </ngs-radio-card-content>\n </ngs-radio-card>\n <ngs-radio-card value=\"closed\">\n <ngs-radio-card-title>\n <ngs-icon name=\"fluent:lock-closed-24-regular\"/>\n Closed\n </ngs-radio-card-title>\n <ngs-radio-card-content>\n Only members can view community members and posts. Content is not visible to search engines.\n </ngs-radio-card-content>\n </ngs-radio-card>\n </ngs-radio-card-group>\n</form>\n<div class=\"mt-10\">\n <p>\n <button ngsButton=\"filled\" (click)=\"toggleDisabled()\">\n {{ form.get('privacy')?.disabled ? 'Enable' : 'Disable' }} Control\n </button>\n </p>\n <p>Control value: {{ form.get('privacy')?.value }}</p>\n</div>"
7571
+ },
7572
+ {
7573
+ "name": "radio-orientation-example",
7574
+ "title": "Radio orientation",
7575
+ "file": "projects/docs/src/app/forms/radio/_examples/radio-orientation-example/radio-orientation-example.html",
7576
+ "source": "<div class=\"grid gap-8 md:grid-cols-2\">\n <div class=\"flex flex-col gap-4\">\n <h4 class=\"text-sm font-medium\">Vertical</h4>\n <ngs-radio-group orientation=\"vertical\" aria-label=\"Notification frequency\">\n <ngs-radio-button value=\"instant\">Instant</ngs-radio-button>\n <ngs-radio-button value=\"daily\">Daily summary</ngs-radio-button>\n <ngs-radio-button value=\"weekly\">Weekly digest</ngs-radio-button>\n </ngs-radio-group>\n </div>\n <div class=\"flex flex-col gap-4\">\n <h4 class=\"text-sm font-medium\">Horizontal</h4>\n <ngs-radio-group orientation=\"horizontal\" aria-label=\"Billing cycle\">\n <ngs-radio-button value=\"monthly\">Monthly</ngs-radio-button>\n <ngs-radio-button value=\"annual\">Annual</ngs-radio-button>\n </ngs-radio-group>\n </div>\n</div>"
7552
7577
  }
7553
7578
  ],
7554
7579
  "previewAsset": "projects/components/radio/preview.svg",
@@ -7558,13 +7583,15 @@
7558
7583
  ],
7559
7584
  "exportedSymbols": [
7560
7585
  "RadioButton",
7561
- "RadioGroup"
7586
+ "RadioGroup",
7587
+ "RadioGroupOrientation"
7562
7588
  ],
7563
7589
  "inputs": [
7564
7590
  "checked",
7565
7591
  "disabled",
7566
7592
  "id",
7567
7593
  "name",
7594
+ "orientation",
7568
7595
  "value"
7569
7596
  ],
7570
7597
  "outputs": [
@@ -7583,7 +7610,8 @@
7583
7610
  "--ngs-radio-button-inner-circle-size",
7584
7611
  "--ngs-radio-button-label-color",
7585
7612
  "--ngs-radio-button-size",
7586
- "--ngs-radio-button-unchecked-color"
7613
+ "--ngs-radio-button-unchecked-color",
7614
+ "--ngs-radio-group-gap"
7587
7615
  ],
7588
7616
  "example": null
7589
7617
  },
@@ -8676,11 +8704,13 @@
8676
8704
  ],
8677
8705
  "previewAsset": "projects/components/slide-toggle/preview.svg",
8678
8706
  "selectors": [
8679
- "ngs-slide-toggle"
8707
+ "ngs-slide-toggle",
8708
+ "ngs-slide-toggle-group"
8680
8709
  ],
8681
8710
  "exportedSymbols": [
8682
8711
  "SlideToggle",
8683
- "SlideToggleChange"
8712
+ "SlideToggleChange",
8713
+ "SlideToggleGroup"
8684
8714
  ],
8685
8715
  "inputs": [
8686
8716
  "aria-describedby",
@@ -8708,6 +8738,7 @@
8708
8738
  "--ngs-color-surface-container-highest",
8709
8739
  "--ngs-slide-toggle-bar-checked-color",
8710
8740
  "--ngs-slide-toggle-bar-color",
8741
+ "--ngs-slide-toggle-group-gap",
8711
8742
  "--ngs-slide-toggle-height",
8712
8743
  "--ngs-slide-toggle-thumb-checked-color",
8713
8744
  "--ngs-slide-toggle-thumb-color",
@@ -269,16 +269,22 @@ class CountrySelect {
269
269
  _renderer = inject(Renderer2);
270
270
  _formField = inject(FORM_FIELD, { optional: true });
271
271
  static nextId = 0;
272
- id = `ngs-country-select-${CountrySelect.nextId++}`;
273
272
  stateChanges = new Subject();
274
273
  searchTerm = model('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : /* istanbul ignore next */ []));
275
274
  visibleCountryCount = signal(CountrySelect.COUNTRY_RENDER_CHUNK_SIZE, ...(ngDevMode ? [{ debugName: "visibleCountryCount" }] : /* istanbul ignore next */ []));
276
- _valueSignal = signal(null, ...(ngDevMode ? [{ debugName: "_valueSignal" }] : /* istanbul ignore next */ []));
275
+ valueSignal = model(null, { ...(ngDevMode ? { debugName: "valueSignal" } : /* istanbul ignore next */ {}), alias: 'value' });
277
276
  _focusedSignal = signal(false, ...(ngDevMode ? [{ debugName: "_focusedSignal" }] : /* istanbul ignore next */ []));
278
277
  _touched = false;
278
+ idSignal = input(`ngs-country-select-${CountrySelect.nextId++}`, { ...(ngDevMode ? { debugName: "idSignal" } : /* istanbul ignore next */ {}), alias: 'id' });
279
279
  placeholderInputSignal = input('', { ...(ngDevMode ? { debugName: "placeholderInputSignal" } : /* istanbul ignore next */ {}), alias: 'placeholder' });
280
280
  isRequiredSignal = model(false, { ...(ngDevMode ? { debugName: "isRequiredSignal" } : /* istanbul ignore next */ {}), alias: 'required' });
281
281
  isDisabledSignal = model(false, { ...(ngDevMode ? { debugName: "isDisabledSignal" } : /* istanbul ignore next */ {}), alias: 'disabled' });
282
+ multiple = input(false, { ...(ngDevMode ? { debugName: "multiple" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
283
+ hideCheckIcon = input(false, { ...(ngDevMode ? { debugName: "hideCheckIcon" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
284
+ clearable = input(false, { ...(ngDevMode ? { debugName: "clearable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
285
+ ariaLabel = input(null, { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
286
+ tabIndex = input(0, { ...(ngDevMode ? { debugName: "tabIndex" } : /* istanbul ignore next */ {}), transform: (value) => value == null ? 0 : parseInt(value + '', 10) });
287
+ ariaDescribedby = input(null, { ...(ngDevMode ? { debugName: "ariaDescribedby" } : /* istanbul ignore next */ {}), alias: 'aria-describedby' });
282
288
  showCountryCode = input(false, { ...(ngDevMode ? { debugName: "showCountryCode" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
283
289
  internalCountries = countries;
284
290
  filteredCountries = computed(() => {
@@ -294,9 +300,30 @@ class CountrySelect {
294
300
  visibleCountries = computed(() => {
295
301
  return this.filteredCountries().slice(0, this.visibleCountryCount());
296
302
  }, ...(ngDevMode ? [{ debugName: "visibleCountries" }] : /* istanbul ignore next */ []));
303
+ selectedCountryDisplays = computed(() => {
304
+ const value = this.valueSignal();
305
+ const selectedCodes = Array.isArray(value)
306
+ ? value
307
+ : value
308
+ ? [value]
309
+ : [];
310
+ return selectedCodes
311
+ .map((code) => this.internalCountries.find((country) => country.code === code))
312
+ .filter((country) => !!country);
313
+ }, ...(ngDevMode ? [{ debugName: "selectedCountryDisplays" }] : /* istanbul ignore next */ []));
297
314
  selectedCountryDisplay = computed(() => {
298
- return this.internalCountries.find(c => c.code === this._valueSignal());
315
+ return this.selectedCountryDisplays()[0] ?? null;
299
316
  }, ...(ngDevMode ? [{ debugName: "selectedCountryDisplay" }] : /* istanbul ignore next */ []));
317
+ selectedCountriesText = computed(() => {
318
+ return this.selectedCountryDisplays()
319
+ .map((country) => {
320
+ if (this.showCountryCode()) {
321
+ return `${country.name} (${country.code})`;
322
+ }
323
+ return country.name;
324
+ })
325
+ .join(', ');
326
+ }, ...(ngDevMode ? [{ debugName: "selectedCountriesText" }] : /* istanbul ignore next */ []));
300
327
  ngsSelect = viewChild.required('ngsSelect');
301
328
  searchInput = viewChild.required('searchInput');
302
329
  fm = inject(FocusMonitor);
@@ -305,6 +332,7 @@ class CountrySelect {
305
332
  destroyRef = inject(DestroyRef);
306
333
  opened = output();
307
334
  closed = output();
335
+ selectionChange = output();
308
336
  onChangeFn = () => { };
309
337
  onTouchedFn = () => { };
310
338
  _countryRenderTimeout;
@@ -319,14 +347,20 @@ class CountrySelect {
319
347
  this.stateChanges.complete();
320
348
  });
321
349
  effect(() => {
322
- this.onChangeFn(this._valueSignal());
350
+ this.onChangeFn(this.valueSignal());
323
351
  });
324
352
  effect(() => {
325
- this._valueSignal();
353
+ this.valueSignal();
326
354
  this._focusedSignal();
327
355
  this.isRequiredSignal();
328
356
  this.isDisabledSignal();
329
357
  this.placeholderInputSignal();
358
+ this.multiple();
359
+ this.hideCheckIcon();
360
+ this.clearable();
361
+ this.ariaLabel();
362
+ this.tabIndex();
363
+ this.ariaDescribedby();
330
364
  this.ngControl?.control?.status;
331
365
  this.stateChanges.next();
332
366
  });
@@ -349,11 +383,14 @@ class CountrySelect {
349
383
  ngOnDestroy() {
350
384
  this.clearCountrySelectTimeouts();
351
385
  }
386
+ get id() {
387
+ return this.idSignal();
388
+ }
352
389
  get value() {
353
- return this._valueSignal();
390
+ return this.valueSignal();
354
391
  }
355
392
  set value(val) {
356
- this._valueSignal.set(val);
393
+ this.valueSignal.set(val);
357
394
  }
358
395
  get focused() {
359
396
  return this._focusedSignal() || (this.ngsSelect?.()?.panelOpen() ?? false);
@@ -391,10 +428,14 @@ class CountrySelect {
391
428
  this.isDisabledSignal.set(coerceBooleanProperty(dis));
392
429
  }
393
430
  get empty() {
394
- return !this._valueSignal();
431
+ const value = this.valueSignal();
432
+ if (Array.isArray(value)) {
433
+ return value.length === 0;
434
+ }
435
+ return !value;
395
436
  }
396
437
  get shouldLabelFloat() {
397
- return this._focusedSignal() || !this.empty;
438
+ return this.focused || !this.empty;
398
439
  }
399
440
  get errorState() {
400
441
  return !!(this.ngControl?.invalid && (this.ngControl?.touched || this._touched));
@@ -416,7 +457,7 @@ class CountrySelect {
416
457
  this.ngsSelect().open();
417
458
  }
418
459
  writeValue(value) {
419
- this._valueSignal.set(value);
460
+ this.valueSignal.set(value);
420
461
  }
421
462
  registerOnChange(fn) {
422
463
  this.onChangeFn = fn;
@@ -434,6 +475,7 @@ class CountrySelect {
434
475
  onSelectionChange(event) {
435
476
  this.value = event.value;
436
477
  this.onTouchedFn();
478
+ this.selectionChange.emit(event);
437
479
  }
438
480
  clearSearch(event) {
439
481
  event.stopPropagation();
@@ -468,7 +510,8 @@ class CountrySelect {
468
510
  }
469
511
  getInitialVisibleCountryCount() {
470
512
  const countries = this.filteredCountries();
471
- const selectedCountryCode = this._valueSignal();
513
+ const value = this.valueSignal();
514
+ const selectedCountryCode = Array.isArray(value) ? value[0] : value;
472
515
  if (!selectedCountryCode) {
473
516
  return CountrySelect.COUNTRY_RENDER_CHUNK_SIZE;
474
517
  }
@@ -509,12 +552,12 @@ class CountrySelect {
509
552
  this._countrySearchFocusTimeout = undefined;
510
553
  }
511
554
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CountrySelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
512
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: CountrySelect, isStandalone: true, selector: "ngs-country-select", inputs: { searchTerm: { classPropertyName: "searchTerm", publicName: "searchTerm", isSignal: true, isRequired: false, transformFunction: null }, placeholderInputSignal: { classPropertyName: "placeholderInputSignal", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, isRequiredSignal: { classPropertyName: "isRequiredSignal", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, isDisabledSignal: { classPropertyName: "isDisabledSignal", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showCountryCode: { classPropertyName: "showCountryCode", publicName: "showCountryCode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { searchTerm: "searchTermChange", isRequiredSignal: "requiredChange", isDisabledSignal: "disabledChange", opened: "opened", closed: "closed" }, host: { listeners: { "focus": "onFocusIn()", "blur": "onFocusOut($event)" }, properties: { "class.floating": "shouldLabelFloat", "id": "id", "attr.tabindex": "disabled ? -1 : 0" }, classAttribute: "ngs-country-select" }, providers: [
555
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: CountrySelect, isStandalone: true, selector: "ngs-country-select", inputs: { searchTerm: { classPropertyName: "searchTerm", publicName: "searchTerm", isSignal: true, isRequired: false, transformFunction: null }, valueSignal: { classPropertyName: "valueSignal", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, idSignal: { classPropertyName: "idSignal", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, placeholderInputSignal: { classPropertyName: "placeholderInputSignal", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, isRequiredSignal: { classPropertyName: "isRequiredSignal", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, isDisabledSignal: { classPropertyName: "isDisabledSignal", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, hideCheckIcon: { classPropertyName: "hideCheckIcon", publicName: "hideCheckIcon", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedby: { classPropertyName: "ariaDescribedby", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, showCountryCode: { classPropertyName: "showCountryCode", publicName: "showCountryCode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { searchTerm: "searchTermChange", valueSignal: "valueChange", isRequiredSignal: "requiredChange", isDisabledSignal: "disabledChange", opened: "opened", closed: "closed", selectionChange: "selectionChange" }, host: { listeners: { "focus": "onFocusIn()", "blur": "onFocusOut($event)" }, properties: { "class.floating": "shouldLabelFloat", "id": "id", "attr.tabindex": "disabled ? -1 : tabIndex()" }, classAttribute: "ngs-country-select" }, providers: [
513
556
  {
514
557
  provide: FormFieldControl,
515
558
  useExisting: forwardRef(() => CountrySelect),
516
559
  },
517
- ], viewQueries: [{ propertyName: "ngsSelect", first: true, predicate: ["ngsSelect"], descendants: true, isSignal: true }, { propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], exportAs: ["ngsCountrySelect"], ngImport: i0, template: "<ngs-select\n #ngsSelect\n [value]=\"value\"\n (selectionChange)=\"onSelectionChange($event)\"\n (opened)=\"onSelectOpened()\"\n (closed)=\"onSelectClosed()\"\n [placeholder]=\"placeholder\"\n [required]=\"isRequiredSignal()\"\n [disabled]=\"isDisabledSignal()\">\n <ngs-select-trigger class=\"select-trigger\">\n @let selectedCountry = selectedCountryDisplay();\n @if (selectedCountry) {\n <span class=\"ngs-select-trigger-content\">\n <span class=\"flag-icon\" aria-hidden=\"true\">{{ selectedCountry.flag }}</span>\n <span class=\"ngs-select-trigger-text\">\n {{ selectedCountry.name }}\n @if (showCountryCode()) {\n <span class=\"code\">({{ selectedCountry.code }})</span>\n }\n </span>\n </span>\n }\n\n @if (!selectedCountryDisplay() && placeholder) {\n <span class=\"ngs-select-trigger-text placeholder-text\">\n {{ placeholder }}\n </span>\n }\n </ngs-select-trigger>\n\n <ngs-select-header>\n <div class=\"sticky top-0 z-1 bg-surface-container-lowest\">\n <input #searchInput\n type=\"text\"\n placeholder=\"Search...\"\n autocomplete=\"off\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onCountrySearch($event)\"\n class=\"w-full text-sm focus:outline-none border-b border-surface-container-high focus:border-b-primary h-14 px-3\">\n @if (searchTerm().trim()) {\n <div class=\"absolute end-1 top-1/2 -translate-y-1/2\">\n <button\n ngsIconButton\n (click)=\"clearSearch($event)\"\n class=\"clear-button\"\n type=\"button\"\n aria-label=\"Clear search\">\n <ngs-icon name=\"fluent:dismiss-24-regular\"/>\n </button>\n </div>\n }\n </div>\n </ngs-select-header>\n\n @for (country of visibleCountries(); track country.code) {\n <ngs-option [value]=\"country.code\">\n <div class=\"flex items-center gap-2\">\n <span class=\"select-option-icon text-2xl\" aria-hidden=\"true\">{{ country.flag }}</span>\n <span class=\"select-option-text\">\n {{ country.name }}\n @if (showCountryCode()) {\n <span class=\"code\">({{ country.code }})</span>\n }\n </span>\n </div>\n </ngs-option>\n } @empty {\n @if (searchTerm()) {\n <div class=\"text-sm px-4 py-3\">\n <span i18n>Country not found</span>.\n </div>\n }\n }\n\n @if (visibleCountryCount() < filteredCountries().length) {\n <div class=\"select-loading\">\n Loading more countries...\n </div>\n }\n</ngs-select>\n", styles: [":host{display:block}:host .flag-icon{display:inline-flex;align-items:center;justify-content:center;width:22px;font-size:22px;line-height:1}:host .select-option-content{display:flex;align-items:center;gap:var(--ngs-dropdown-item-gap);min-width:0;width:100%;height:100%;overflow:hidden;white-space:nowrap}:host .select-option-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host .code{text-transform:uppercase;color:var(--ngs-color-neutral-500)}:host .select-loading{padding:calc(var(--spacing, .25rem) * 2) calc(var(--spacing, .25rem) * 4);color:var(--ngs-color-on-surface-variant);font-size:var(--ngs-font-size-sm)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "component", type: Option, selector: "ngs-option", inputs: ["value", "data", "disabled", "selected"], outputs: ["onSelectionChange"], exportAs: ["ngsOption"] }, { kind: "component", type: Icon, selector: "ngs-icon", inputs: ["name"], exportAs: ["ngsIcon"] }, { kind: "component", type: Select, selector: "ngs-select", inputs: ["id", "placeholder", "disabled", "required", "multiple", "hideCheckIcon", "clearable", "aria-label", "tabIndex", "aria-describedby", "value"], outputs: ["selectionChange", "opened", "closed", "valueChange"], exportAs: ["ngsSelect"] }, { kind: "directive", type: SelectTrigger, selector: "ngs-select-trigger" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "component", type: Button, selector: " button[ngsButton], button[ngsIconButton], a[ngsButton], a[ngsIconButton] ", inputs: ["ngsButton", "ngsIconButton", "loading", "disabled", "disabledInteractive", "disableRipple", "reverse", "fullWidth", "hideTextOnMobile"], exportAs: ["ngsButton"] }, { kind: "component", type: SelectHeader, selector: "ngs-select-header" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
560
+ ], viewQueries: [{ propertyName: "ngsSelect", first: true, predicate: ["ngsSelect"], descendants: true, isSignal: true }, { propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], exportAs: ["ngsCountrySelect"], ngImport: i0, template: "<ngs-select\n #ngsSelect\n [value]=\"value\"\n (selectionChange)=\"onSelectionChange($event)\"\n (opened)=\"onSelectOpened()\"\n (closed)=\"onSelectClosed()\"\n [id]=\"id + '-select'\"\n [placeholder]=\"placeholder\"\n [required]=\"isRequiredSignal()\"\n [disabled]=\"isDisabledSignal()\"\n [multiple]=\"multiple()\"\n [hideCheckIcon]=\"hideCheckIcon()\"\n [clearable]=\"clearable()\"\n [aria-label]=\"ariaLabel()\"\n [tabIndex]=\"tabIndex()\"\n [aria-describedby]=\"ariaDescribedby()\">\n <ngs-select-trigger class=\"select-trigger\">\n @let selectedCountries = selectedCountryDisplays();\n @if (selectedCountries.length === 1) {\n @let selectedCountry = selectedCountries[0];\n <span class=\"ngs-select-trigger-content\">\n <span class=\"flag-icon\" aria-hidden=\"true\">{{ selectedCountry.flag }}</span>\n <span class=\"ngs-select-trigger-text\">\n {{ selectedCountry.name }}\n @if (showCountryCode()) {\n <span class=\"code\">({{ selectedCountry.code }})</span>\n }\n </span>\n </span>\n } @else if (selectedCountries.length > 1) {\n <span class=\"ngs-select-trigger-content\">\n <span class=\"ngs-select-trigger-text\">\n {{ selectedCountriesText() }}\n </span>\n </span>\n }\n\n </ngs-select-trigger>\n\n <ngs-select-header>\n <div class=\"sticky top-0 z-1 bg-surface-container-lowest\">\n <input #searchInput\n type=\"text\"\n placeholder=\"Search...\"\n autocomplete=\"off\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onCountrySearch($event)\"\n class=\"w-full text-sm focus:outline-none border-b border-surface-container-high focus:border-b-primary h-14 px-3\">\n @if (searchTerm().trim()) {\n <div class=\"absolute end-1 top-1/2 -translate-y-1/2\">\n <button\n ngsIconButton\n (click)=\"clearSearch($event)\"\n class=\"clear-button\"\n type=\"button\"\n aria-label=\"Clear search\">\n <ngs-icon name=\"fluent:dismiss-24-regular\"/>\n </button>\n </div>\n }\n </div>\n </ngs-select-header>\n\n @for (country of visibleCountries(); track country.code) {\n <ngs-option [value]=\"country.code\">\n <div class=\"flex items-center gap-2\">\n <span class=\"select-option-icon text-2xl\" aria-hidden=\"true\">{{ country.flag }}</span>\n <span class=\"select-option-text\">\n {{ country.name }}\n @if (showCountryCode()) {\n <span class=\"code\">({{ country.code }})</span>\n }\n </span>\n </div>\n </ngs-option>\n } @empty {\n @if (searchTerm()) {\n <div class=\"text-sm px-4 py-3\">\n <span i18n>Country not found</span>.\n </div>\n }\n }\n\n @if (visibleCountryCount() < filteredCountries().length) {\n <div class=\"select-loading\">\n Loading more countries...\n </div>\n }\n</ngs-select>\n", styles: [":host{display:block}:host .flag-icon{display:inline-flex;align-items:center;justify-content:center;width:22px;font-size:22px;line-height:1}:host .select-option-content{display:flex;align-items:center;gap:var(--ngs-dropdown-item-gap);min-width:0;width:100%;height:100%;overflow:hidden;white-space:nowrap}:host .select-option-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host .code{text-transform:uppercase;color:var(--ngs-color-neutral-500)}:host .select-loading{padding:calc(var(--spacing, .25rem) * 2) calc(var(--spacing, .25rem) * 4);color:var(--ngs-color-on-surface-variant);font-size:var(--ngs-font-size-sm)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "component", type: Option, selector: "ngs-option", inputs: ["value", "data", "disabled", "selected"], outputs: ["onSelectionChange"], exportAs: ["ngsOption"] }, { kind: "component", type: Icon, selector: "ngs-icon", inputs: ["name"], exportAs: ["ngsIcon"] }, { kind: "component", type: Select, selector: "ngs-select", inputs: ["id", "placeholder", "disabled", "required", "multiple", "hideCheckIcon", "clearable", "aria-label", "tabIndex", "aria-describedby", "value"], outputs: ["selectionChange", "opened", "closed", "valueChange"], exportAs: ["ngsSelect"] }, { kind: "directive", type: SelectTrigger, selector: "ngs-select-trigger" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "component", type: Button, selector: " button[ngsButton], button[ngsIconButton], a[ngsButton], a[ngsIconButton] ", inputs: ["ngsButton", "ngsIconButton", "loading", "disabled", "disabledInteractive", "disableRipple", "reverse", "fullWidth", "hideTextOnMobile"], exportAs: ["ngsButton"] }, { kind: "component", type: SelectHeader, selector: "ngs-select-header" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
518
561
  }
519
562
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CountrySelect, decorators: [{
520
563
  type: Component,
@@ -536,11 +579,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
536
579
  'class': 'ngs-country-select',
537
580
  '[class.floating]': 'shouldLabelFloat',
538
581
  '[id]': 'id',
539
- '[attr.tabindex]': 'disabled ? -1 : 0',
582
+ '[attr.tabindex]': 'disabled ? -1 : tabIndex()',
540
583
  '(focus)': 'onFocusIn()',
541
584
  '(blur)': 'onFocusOut($event)',
542
- }, template: "<ngs-select\n #ngsSelect\n [value]=\"value\"\n (selectionChange)=\"onSelectionChange($event)\"\n (opened)=\"onSelectOpened()\"\n (closed)=\"onSelectClosed()\"\n [placeholder]=\"placeholder\"\n [required]=\"isRequiredSignal()\"\n [disabled]=\"isDisabledSignal()\">\n <ngs-select-trigger class=\"select-trigger\">\n @let selectedCountry = selectedCountryDisplay();\n @if (selectedCountry) {\n <span class=\"ngs-select-trigger-content\">\n <span class=\"flag-icon\" aria-hidden=\"true\">{{ selectedCountry.flag }}</span>\n <span class=\"ngs-select-trigger-text\">\n {{ selectedCountry.name }}\n @if (showCountryCode()) {\n <span class=\"code\">({{ selectedCountry.code }})</span>\n }\n </span>\n </span>\n }\n\n @if (!selectedCountryDisplay() && placeholder) {\n <span class=\"ngs-select-trigger-text placeholder-text\">\n {{ placeholder }}\n </span>\n }\n </ngs-select-trigger>\n\n <ngs-select-header>\n <div class=\"sticky top-0 z-1 bg-surface-container-lowest\">\n <input #searchInput\n type=\"text\"\n placeholder=\"Search...\"\n autocomplete=\"off\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onCountrySearch($event)\"\n class=\"w-full text-sm focus:outline-none border-b border-surface-container-high focus:border-b-primary h-14 px-3\">\n @if (searchTerm().trim()) {\n <div class=\"absolute end-1 top-1/2 -translate-y-1/2\">\n <button\n ngsIconButton\n (click)=\"clearSearch($event)\"\n class=\"clear-button\"\n type=\"button\"\n aria-label=\"Clear search\">\n <ngs-icon name=\"fluent:dismiss-24-regular\"/>\n </button>\n </div>\n }\n </div>\n </ngs-select-header>\n\n @for (country of visibleCountries(); track country.code) {\n <ngs-option [value]=\"country.code\">\n <div class=\"flex items-center gap-2\">\n <span class=\"select-option-icon text-2xl\" aria-hidden=\"true\">{{ country.flag }}</span>\n <span class=\"select-option-text\">\n {{ country.name }}\n @if (showCountryCode()) {\n <span class=\"code\">({{ country.code }})</span>\n }\n </span>\n </div>\n </ngs-option>\n } @empty {\n @if (searchTerm()) {\n <div class=\"text-sm px-4 py-3\">\n <span i18n>Country not found</span>.\n </div>\n }\n }\n\n @if (visibleCountryCount() < filteredCountries().length) {\n <div class=\"select-loading\">\n Loading more countries...\n </div>\n }\n</ngs-select>\n", styles: [":host{display:block}:host .flag-icon{display:inline-flex;align-items:center;justify-content:center;width:22px;font-size:22px;line-height:1}:host .select-option-content{display:flex;align-items:center;gap:var(--ngs-dropdown-item-gap);min-width:0;width:100%;height:100%;overflow:hidden;white-space:nowrap}:host .select-option-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host .code{text-transform:uppercase;color:var(--ngs-color-neutral-500)}:host .select-loading{padding:calc(var(--spacing, .25rem) * 2) calc(var(--spacing, .25rem) * 4);color:var(--ngs-color-on-surface-variant);font-size:var(--ngs-font-size-sm)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"] }]
543
- }], ctorParameters: () => [], propDecorators: { searchTerm: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchTerm", required: false }] }, { type: i0.Output, args: ["searchTermChange"] }], placeholderInputSignal: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], isRequiredSignal: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }, { type: i0.Output, args: ["requiredChange"] }], isDisabledSignal: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], showCountryCode: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCountryCode", required: false }] }], ngsSelect: [{ type: i0.ViewChild, args: ['ngsSelect', { isSignal: true }] }], searchInput: [{ type: i0.ViewChild, args: ['searchInput', { isSignal: true }] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
585
+ }, template: "<ngs-select\n #ngsSelect\n [value]=\"value\"\n (selectionChange)=\"onSelectionChange($event)\"\n (opened)=\"onSelectOpened()\"\n (closed)=\"onSelectClosed()\"\n [id]=\"id + '-select'\"\n [placeholder]=\"placeholder\"\n [required]=\"isRequiredSignal()\"\n [disabled]=\"isDisabledSignal()\"\n [multiple]=\"multiple()\"\n [hideCheckIcon]=\"hideCheckIcon()\"\n [clearable]=\"clearable()\"\n [aria-label]=\"ariaLabel()\"\n [tabIndex]=\"tabIndex()\"\n [aria-describedby]=\"ariaDescribedby()\">\n <ngs-select-trigger class=\"select-trigger\">\n @let selectedCountries = selectedCountryDisplays();\n @if (selectedCountries.length === 1) {\n @let selectedCountry = selectedCountries[0];\n <span class=\"ngs-select-trigger-content\">\n <span class=\"flag-icon\" aria-hidden=\"true\">{{ selectedCountry.flag }}</span>\n <span class=\"ngs-select-trigger-text\">\n {{ selectedCountry.name }}\n @if (showCountryCode()) {\n <span class=\"code\">({{ selectedCountry.code }})</span>\n }\n </span>\n </span>\n } @else if (selectedCountries.length > 1) {\n <span class=\"ngs-select-trigger-content\">\n <span class=\"ngs-select-trigger-text\">\n {{ selectedCountriesText() }}\n </span>\n </span>\n }\n\n </ngs-select-trigger>\n\n <ngs-select-header>\n <div class=\"sticky top-0 z-1 bg-surface-container-lowest\">\n <input #searchInput\n type=\"text\"\n placeholder=\"Search...\"\n autocomplete=\"off\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onCountrySearch($event)\"\n class=\"w-full text-sm focus:outline-none border-b border-surface-container-high focus:border-b-primary h-14 px-3\">\n @if (searchTerm().trim()) {\n <div class=\"absolute end-1 top-1/2 -translate-y-1/2\">\n <button\n ngsIconButton\n (click)=\"clearSearch($event)\"\n class=\"clear-button\"\n type=\"button\"\n aria-label=\"Clear search\">\n <ngs-icon name=\"fluent:dismiss-24-regular\"/>\n </button>\n </div>\n }\n </div>\n </ngs-select-header>\n\n @for (country of visibleCountries(); track country.code) {\n <ngs-option [value]=\"country.code\">\n <div class=\"flex items-center gap-2\">\n <span class=\"select-option-icon text-2xl\" aria-hidden=\"true\">{{ country.flag }}</span>\n <span class=\"select-option-text\">\n {{ country.name }}\n @if (showCountryCode()) {\n <span class=\"code\">({{ country.code }})</span>\n }\n </span>\n </div>\n </ngs-option>\n } @empty {\n @if (searchTerm()) {\n <div class=\"text-sm px-4 py-3\">\n <span i18n>Country not found</span>.\n </div>\n }\n }\n\n @if (visibleCountryCount() < filteredCountries().length) {\n <div class=\"select-loading\">\n Loading more countries...\n </div>\n }\n</ngs-select>\n", styles: [":host{display:block}:host .flag-icon{display:inline-flex;align-items:center;justify-content:center;width:22px;font-size:22px;line-height:1}:host .select-option-content{display:flex;align-items:center;gap:var(--ngs-dropdown-item-gap);min-width:0;width:100%;height:100%;overflow:hidden;white-space:nowrap}:host .select-option-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host .code{text-transform:uppercase;color:var(--ngs-color-neutral-500)}:host .select-loading{padding:calc(var(--spacing, .25rem) * 2) calc(var(--spacing, .25rem) * 4);color:var(--ngs-color-on-surface-variant);font-size:var(--ngs-font-size-sm)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"] }]
586
+ }], ctorParameters: () => [], propDecorators: { searchTerm: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchTerm", required: false }] }, { type: i0.Output, args: ["searchTermChange"] }], valueSignal: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], idSignal: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], placeholderInputSignal: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], isRequiredSignal: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }, { type: i0.Output, args: ["requiredChange"] }], isDisabledSignal: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], hideCheckIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideCheckIcon", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], ariaDescribedby: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-describedby", required: false }] }], showCountryCode: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCountryCode", required: false }] }], ngsSelect: [{ type: i0.ViewChild, args: ['ngsSelect', { isSignal: true }] }], searchInput: [{ type: i0.ViewChild, args: ['searchInput', { isSignal: true }] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }] } });
544
587
 
545
588
  /**
546
589
  * Generated bundle index. Do not edit.