@star-ng/ui 0.1.0 → 0.2.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/README.md CHANGED
@@ -139,6 +139,20 @@ The package follows semantic versioning. In `0.x` versions, the API can change b
139
139
  - There are no screen-reader, zoom, reflow or forced-colors tests.
140
140
  - The editor and the file upload do not protect your server. See [SECURITY.md](SECURITY.md).
141
141
 
142
+ ## Community
143
+
144
+ Contributions are welcome and appreciated.
145
+
146
+ - Start with issues that have the label [help wanted](https://github.com/ramanacr/star-ng/labels/help%20wanted) or `good first issue`.
147
+ - Four requests are open now:
148
+ - [Review of the German text pack by a native speaker](https://github.com/ramanacr/star-ng/issues/33)
149
+ - [Review of the Spanish text pack by a native speaker](https://github.com/ramanacr/star-ng/issues/34)
150
+ - [A check in Firefox and Safari](https://github.com/ramanacr/star-ng/issues/35)
151
+ - [A check with a screen reader](https://github.com/ramanacr/star-ng/issues/36)
152
+ - Ask questions and share ideas in [GitHub Discussions](https://github.com/ramanacr/star-ng/discussions).
153
+ - Read [CONTRIBUTING.md](CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) before you start.
154
+ - To support the project, use the Sponsor button on the repository page when it is shown.
155
+
142
156
  ## Links
143
157
 
144
158
  - [Documentation site](https://ramanacr.github.io/star-ng/)
@@ -46,7 +46,10 @@ var StarAutoCompleteBase = class StarAutoCompleteBase extends StarOptionListBase
46
46
  inject(DestroyRef).onDestroy(() => clearTimeout(this.searchTimer));
47
47
  effect(() => {
48
48
  this.visibleOptions();
49
- untracked(() => this.activeIndex.set(this.autoHighlight() ? this.firstEnabledFrom(0, 1) : -1));
49
+ untracked(() => {
50
+ this.resetScroll();
51
+ this.activeIndex.set(this.autoHighlight() ? this.firstEnabledFrom(0, 1) : -1);
52
+ });
50
53
  });
51
54
  }
52
55
  initialActiveIndex() {
@@ -340,6 +343,7 @@ const TEMPLATE = `
340
343
  [cdkConnectedOverlayOrigin]="origin"
341
344
  [cdkConnectedOverlayOpen]="panelVisible()"
342
345
  [cdkConnectedOverlayPositions]="positions"
346
+ (attach)="onPanelAttached()"
343
347
  (detach)="closePanel(false)"
344
348
  (overlayOutsideClick)="onOutsideClick($event)"
345
349
  >
@@ -373,7 +377,7 @@ const TEMPLATE = `
373
377
  [class.star-listbox__option--active]="activeIndex() === i"
374
378
  [attr.aria-selected]="activeIndex() === i"
375
379
  [attr.aria-disabled]="isDisabled(option) || null"
376
- [attr.aria-describedby]="row.groupId"
380
+ [attr.aria-describedby]="describedBy(row)"
377
381
  [attr.aria-setsize]="virtualScroll() ? visibleOptions().length : null"
378
382
  [attr.aria-posinset]="virtualScroll() ? i + 1 : null"
379
383
  (click)="onOptionClick(option, i)"
@@ -482,7 +486,7 @@ var StarAutoComplete = class StarAutoComplete extends StarAutoCompleteBase {
482
486
  },
483
487
  usesInheritance: true,
484
488
  ngImport: i0,
485
- template: "\n <div #control class=\"star-select__control star-ac__control\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n @if (isMultiple) {\n @for (chip of chips(); track $index) {\n <span class=\"star-chip star-chip--sm\">\n {{ chip.label }}\n @if (interactive()) {\n <button\n type=\"button\"\n class=\"star-chip__remove\"\n tabindex=\"-1\"\n [attr.aria-label]=\"text.removeItem(chip.label)\"\n (click)=\"removeValue(chip.value)\"\n >\n <i class=\"ph-bold ph-x\" aria-hidden=\"true\"></i>\n </button>\n }\n </span>\n }\n }\n <input\n #trigger\n type=\"text\"\n class=\"star-ac__input\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n autocomplete=\"off\"\n [id]=\"inputId()\"\n [attr.name]=\"name() || null\"\n [value]=\"query()\"\n [attr.placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"showInvalid() || null\"\n [attr.aria-expanded]=\"panelVisible()\"\n [attr.aria-controls]=\"panelVisible() ? listId : null\"\n [attr.aria-activedescendant]=\"panelVisible() ? activeId() : null\"\n (input)=\"onQuery(trigger.value)\"\n (keydown)=\"onKeydown($event)\"\n (blur)=\"onInputBlur()\"\n />\n @if (loading()) {\n <i class=\"ph-bold ph-spinner-gap star-spin star-select__caret\" aria-hidden=\"true\"></i>\n }\n @if (showClear() && hasValue() && interactive()) {\n <button type=\"button\" class=\"star-select__icon-btn\" [attr.aria-label]=\"text.clear\" (click)=\"clear()\">\n <i class=\"ph-bold ph-x\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (dropdown()) {\n <button\n type=\"button\"\n class=\"star-select__icon-btn\"\n tabindex=\"-1\"\n [attr.aria-label]=\"text.showOptions\"\n [disabled]=\"!interactive()\"\n (click)=\"showAllOptions()\"\n >\n <i class=\"ph-bold ph-caret-down\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n <span class=\"star-sr-only\" aria-live=\"polite\">{{ liveText() }}</span>\n\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayUsePopover=\"inline\"\n cdkConnectedOverlayMatchWidth\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"panelVisible()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n (detach)=\"closePanel(false)\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n >\n <div class=\"star-panel\" (mousedown)=\"onPanelMousedown($event)\">\n <ul\n class=\"star-listbox\"\n role=\"listbox\"\n [id]=\"listId\"\n [class.star-listbox--virtual]=\"virtualScroll()\"\n [style.--star-item-size.px]=\"virtualScroll() ? virtualItemSize() : null\"\n [style.max-height]=\"scrollHeight()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n (scroll)=\"onListScroll($event)\"\n >\n @if (virtualWindow().before) {\n <li class=\"star-listbox__spacer\" role=\"presentation\" [style.height.px]=\"virtualWindow().before\"></li>\n }\n @for (row of renderedRows(); track row.key) {\n @if (row.kind === 'group') {\n <li class=\"star-listbox__group\" role=\"presentation\" [id]=\"row.id\">{{ row.label }}</li>\n } @else {\n @let option = row.option;\n @let i = row.index;\n <!-- Keyboard is handled on the combobox via aria-activedescendant (WAI-ARIA combobox pattern). -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <li\n class=\"star-listbox__option\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [class.star-listbox__option--active]=\"activeIndex() === i\"\n [attr.aria-selected]=\"activeIndex() === i\"\n [attr.aria-disabled]=\"isDisabled(option) || null\"\n [attr.aria-describedby]=\"row.groupId\"\n [attr.aria-setsize]=\"virtualScroll() ? visibleOptions().length : null\"\n [attr.aria-posinset]=\"virtualScroll() ? i + 1 : null\"\n (click)=\"onOptionClick(option, i)\"\n (mousemove)=\"isDisabled(option) || activeIndex.set(i)\"\n >\n <span class=\"star-listbox__label\">\n @if (optionTemplate(); as custom) {\n <ng-container *ngTemplateOutlet=\"custom.template; context: optionContext(option, i)\" />\n } @else {\n @let parts = highlight(labelOf(option));\n {{ parts[0] }}<mark class=\"star-ac__match\">{{ parts[1] }}</mark>{{ parts[2] }}\n }\n </span>\n </li>\n }\n } @empty {\n <li class=\"star-listbox__empty\" role=\"presentation\">\n {{ loading() ? text.searching : emptyText() }}\n </li>\n }\n @if (virtualWindow().after) {\n <li class=\"star-listbox__spacer\" role=\"presentation\" [style.height.px]=\"virtualWindow().after\"></li>\n }\n </ul>\n </div>\n </ng-template>\n",
489
+ template: "\n <div #control class=\"star-select__control star-ac__control\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n @if (isMultiple) {\n @for (chip of chips(); track $index) {\n <span class=\"star-chip star-chip--sm\">\n {{ chip.label }}\n @if (interactive()) {\n <button\n type=\"button\"\n class=\"star-chip__remove\"\n tabindex=\"-1\"\n [attr.aria-label]=\"text.removeItem(chip.label)\"\n (click)=\"removeValue(chip.value)\"\n >\n <i class=\"ph-bold ph-x\" aria-hidden=\"true\"></i>\n </button>\n }\n </span>\n }\n }\n <input\n #trigger\n type=\"text\"\n class=\"star-ac__input\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n autocomplete=\"off\"\n [id]=\"inputId()\"\n [attr.name]=\"name() || null\"\n [value]=\"query()\"\n [attr.placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"showInvalid() || null\"\n [attr.aria-expanded]=\"panelVisible()\"\n [attr.aria-controls]=\"panelVisible() ? listId : null\"\n [attr.aria-activedescendant]=\"panelVisible() ? activeId() : null\"\n (input)=\"onQuery(trigger.value)\"\n (keydown)=\"onKeydown($event)\"\n (blur)=\"onInputBlur()\"\n />\n @if (loading()) {\n <i class=\"ph-bold ph-spinner-gap star-spin star-select__caret\" aria-hidden=\"true\"></i>\n }\n @if (showClear() && hasValue() && interactive()) {\n <button type=\"button\" class=\"star-select__icon-btn\" [attr.aria-label]=\"text.clear\" (click)=\"clear()\">\n <i class=\"ph-bold ph-x\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (dropdown()) {\n <button\n type=\"button\"\n class=\"star-select__icon-btn\"\n tabindex=\"-1\"\n [attr.aria-label]=\"text.showOptions\"\n [disabled]=\"!interactive()\"\n (click)=\"showAllOptions()\"\n >\n <i class=\"ph-bold ph-caret-down\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n <span class=\"star-sr-only\" aria-live=\"polite\">{{ liveText() }}</span>\n\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayUsePopover=\"inline\"\n cdkConnectedOverlayMatchWidth\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"panelVisible()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n (attach)=\"onPanelAttached()\"\n (detach)=\"closePanel(false)\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n >\n <div class=\"star-panel\" (mousedown)=\"onPanelMousedown($event)\">\n <ul\n class=\"star-listbox\"\n role=\"listbox\"\n [id]=\"listId\"\n [class.star-listbox--virtual]=\"virtualScroll()\"\n [style.--star-item-size.px]=\"virtualScroll() ? virtualItemSize() : null\"\n [style.max-height]=\"scrollHeight()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n (scroll)=\"onListScroll($event)\"\n >\n @if (virtualWindow().before) {\n <li class=\"star-listbox__spacer\" role=\"presentation\" [style.height.px]=\"virtualWindow().before\"></li>\n }\n @for (row of renderedRows(); track row.key) {\n @if (row.kind === 'group') {\n <li class=\"star-listbox__group\" role=\"presentation\" [id]=\"row.id\">{{ row.label }}</li>\n } @else {\n @let option = row.option;\n @let i = row.index;\n <!-- Keyboard is handled on the combobox via aria-activedescendant (WAI-ARIA combobox pattern). -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <li\n class=\"star-listbox__option\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [class.star-listbox__option--active]=\"activeIndex() === i\"\n [attr.aria-selected]=\"activeIndex() === i\"\n [attr.aria-disabled]=\"isDisabled(option) || null\"\n [attr.aria-describedby]=\"describedBy(row)\"\n [attr.aria-setsize]=\"virtualScroll() ? visibleOptions().length : null\"\n [attr.aria-posinset]=\"virtualScroll() ? i + 1 : null\"\n (click)=\"onOptionClick(option, i)\"\n (mousemove)=\"isDisabled(option) || activeIndex.set(i)\"\n >\n <span class=\"star-listbox__label\">\n @if (optionTemplate(); as custom) {\n <ng-container *ngTemplateOutlet=\"custom.template; context: optionContext(option, i)\" />\n } @else {\n @let parts = highlight(labelOf(option));\n {{ parts[0] }}<mark class=\"star-ac__match\">{{ parts[1] }}</mark>{{ parts[2] }}\n }\n </span>\n </li>\n }\n } @empty {\n <li class=\"star-listbox__empty\" role=\"presentation\">\n {{ loading() ? text.searching : emptyText() }}\n </li>\n }\n @if (virtualWindow().after) {\n <li class=\"star-listbox__spacer\" role=\"presentation\" [style.height.px]=\"virtualWindow().after\"></li>\n }\n </ul>\n </div>\n </ng-template>\n",
486
490
  isInline: true,
487
491
  dependencies: [
488
492
  {
@@ -669,7 +673,7 @@ var StarMultiAutoComplete = class StarMultiAutoComplete extends StarAutoComplete
669
673
  },
670
674
  usesInheritance: true,
671
675
  ngImport: i0,
672
- template: "\n <div #control class=\"star-select__control star-ac__control\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n @if (isMultiple) {\n @for (chip of chips(); track $index) {\n <span class=\"star-chip star-chip--sm\">\n {{ chip.label }}\n @if (interactive()) {\n <button\n type=\"button\"\n class=\"star-chip__remove\"\n tabindex=\"-1\"\n [attr.aria-label]=\"text.removeItem(chip.label)\"\n (click)=\"removeValue(chip.value)\"\n >\n <i class=\"ph-bold ph-x\" aria-hidden=\"true\"></i>\n </button>\n }\n </span>\n }\n }\n <input\n #trigger\n type=\"text\"\n class=\"star-ac__input\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n autocomplete=\"off\"\n [id]=\"inputId()\"\n [attr.name]=\"name() || null\"\n [value]=\"query()\"\n [attr.placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"showInvalid() || null\"\n [attr.aria-expanded]=\"panelVisible()\"\n [attr.aria-controls]=\"panelVisible() ? listId : null\"\n [attr.aria-activedescendant]=\"panelVisible() ? activeId() : null\"\n (input)=\"onQuery(trigger.value)\"\n (keydown)=\"onKeydown($event)\"\n (blur)=\"onInputBlur()\"\n />\n @if (loading()) {\n <i class=\"ph-bold ph-spinner-gap star-spin star-select__caret\" aria-hidden=\"true\"></i>\n }\n @if (showClear() && hasValue() && interactive()) {\n <button type=\"button\" class=\"star-select__icon-btn\" [attr.aria-label]=\"text.clear\" (click)=\"clear()\">\n <i class=\"ph-bold ph-x\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (dropdown()) {\n <button\n type=\"button\"\n class=\"star-select__icon-btn\"\n tabindex=\"-1\"\n [attr.aria-label]=\"text.showOptions\"\n [disabled]=\"!interactive()\"\n (click)=\"showAllOptions()\"\n >\n <i class=\"ph-bold ph-caret-down\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n <span class=\"star-sr-only\" aria-live=\"polite\">{{ liveText() }}</span>\n\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayUsePopover=\"inline\"\n cdkConnectedOverlayMatchWidth\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"panelVisible()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n (detach)=\"closePanel(false)\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n >\n <div class=\"star-panel\" (mousedown)=\"onPanelMousedown($event)\">\n <ul\n class=\"star-listbox\"\n role=\"listbox\"\n [id]=\"listId\"\n [class.star-listbox--virtual]=\"virtualScroll()\"\n [style.--star-item-size.px]=\"virtualScroll() ? virtualItemSize() : null\"\n [style.max-height]=\"scrollHeight()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n (scroll)=\"onListScroll($event)\"\n >\n @if (virtualWindow().before) {\n <li class=\"star-listbox__spacer\" role=\"presentation\" [style.height.px]=\"virtualWindow().before\"></li>\n }\n @for (row of renderedRows(); track row.key) {\n @if (row.kind === 'group') {\n <li class=\"star-listbox__group\" role=\"presentation\" [id]=\"row.id\">{{ row.label }}</li>\n } @else {\n @let option = row.option;\n @let i = row.index;\n <!-- Keyboard is handled on the combobox via aria-activedescendant (WAI-ARIA combobox pattern). -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <li\n class=\"star-listbox__option\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [class.star-listbox__option--active]=\"activeIndex() === i\"\n [attr.aria-selected]=\"activeIndex() === i\"\n [attr.aria-disabled]=\"isDisabled(option) || null\"\n [attr.aria-describedby]=\"row.groupId\"\n [attr.aria-setsize]=\"virtualScroll() ? visibleOptions().length : null\"\n [attr.aria-posinset]=\"virtualScroll() ? i + 1 : null\"\n (click)=\"onOptionClick(option, i)\"\n (mousemove)=\"isDisabled(option) || activeIndex.set(i)\"\n >\n <span class=\"star-listbox__label\">\n @if (optionTemplate(); as custom) {\n <ng-container *ngTemplateOutlet=\"custom.template; context: optionContext(option, i)\" />\n } @else {\n @let parts = highlight(labelOf(option));\n {{ parts[0] }}<mark class=\"star-ac__match\">{{ parts[1] }}</mark>{{ parts[2] }}\n }\n </span>\n </li>\n }\n } @empty {\n <li class=\"star-listbox__empty\" role=\"presentation\">\n {{ loading() ? text.searching : emptyText() }}\n </li>\n }\n @if (virtualWindow().after) {\n <li class=\"star-listbox__spacer\" role=\"presentation\" [style.height.px]=\"virtualWindow().after\"></li>\n }\n </ul>\n </div>\n </ng-template>\n",
676
+ template: "\n <div #control class=\"star-select__control star-ac__control\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n @if (isMultiple) {\n @for (chip of chips(); track $index) {\n <span class=\"star-chip star-chip--sm\">\n {{ chip.label }}\n @if (interactive()) {\n <button\n type=\"button\"\n class=\"star-chip__remove\"\n tabindex=\"-1\"\n [attr.aria-label]=\"text.removeItem(chip.label)\"\n (click)=\"removeValue(chip.value)\"\n >\n <i class=\"ph-bold ph-x\" aria-hidden=\"true\"></i>\n </button>\n }\n </span>\n }\n }\n <input\n #trigger\n type=\"text\"\n class=\"star-ac__input\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n autocomplete=\"off\"\n [id]=\"inputId()\"\n [attr.name]=\"name() || null\"\n [value]=\"query()\"\n [attr.placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"showInvalid() || null\"\n [attr.aria-expanded]=\"panelVisible()\"\n [attr.aria-controls]=\"panelVisible() ? listId : null\"\n [attr.aria-activedescendant]=\"panelVisible() ? activeId() : null\"\n (input)=\"onQuery(trigger.value)\"\n (keydown)=\"onKeydown($event)\"\n (blur)=\"onInputBlur()\"\n />\n @if (loading()) {\n <i class=\"ph-bold ph-spinner-gap star-spin star-select__caret\" aria-hidden=\"true\"></i>\n }\n @if (showClear() && hasValue() && interactive()) {\n <button type=\"button\" class=\"star-select__icon-btn\" [attr.aria-label]=\"text.clear\" (click)=\"clear()\">\n <i class=\"ph-bold ph-x\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (dropdown()) {\n <button\n type=\"button\"\n class=\"star-select__icon-btn\"\n tabindex=\"-1\"\n [attr.aria-label]=\"text.showOptions\"\n [disabled]=\"!interactive()\"\n (click)=\"showAllOptions()\"\n >\n <i class=\"ph-bold ph-caret-down\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n <span class=\"star-sr-only\" aria-live=\"polite\">{{ liveText() }}</span>\n\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayUsePopover=\"inline\"\n cdkConnectedOverlayMatchWidth\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"panelVisible()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n (attach)=\"onPanelAttached()\"\n (detach)=\"closePanel(false)\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n >\n <div class=\"star-panel\" (mousedown)=\"onPanelMousedown($event)\">\n <ul\n class=\"star-listbox\"\n role=\"listbox\"\n [id]=\"listId\"\n [class.star-listbox--virtual]=\"virtualScroll()\"\n [style.--star-item-size.px]=\"virtualScroll() ? virtualItemSize() : null\"\n [style.max-height]=\"scrollHeight()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n (scroll)=\"onListScroll($event)\"\n >\n @if (virtualWindow().before) {\n <li class=\"star-listbox__spacer\" role=\"presentation\" [style.height.px]=\"virtualWindow().before\"></li>\n }\n @for (row of renderedRows(); track row.key) {\n @if (row.kind === 'group') {\n <li class=\"star-listbox__group\" role=\"presentation\" [id]=\"row.id\">{{ row.label }}</li>\n } @else {\n @let option = row.option;\n @let i = row.index;\n <!-- Keyboard is handled on the combobox via aria-activedescendant (WAI-ARIA combobox pattern). -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <li\n class=\"star-listbox__option\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [class.star-listbox__option--active]=\"activeIndex() === i\"\n [attr.aria-selected]=\"activeIndex() === i\"\n [attr.aria-disabled]=\"isDisabled(option) || null\"\n [attr.aria-describedby]=\"describedBy(row)\"\n [attr.aria-setsize]=\"virtualScroll() ? visibleOptions().length : null\"\n [attr.aria-posinset]=\"virtualScroll() ? i + 1 : null\"\n (click)=\"onOptionClick(option, i)\"\n (mousemove)=\"isDisabled(option) || activeIndex.set(i)\"\n >\n <span class=\"star-listbox__label\">\n @if (optionTemplate(); as custom) {\n <ng-container *ngTemplateOutlet=\"custom.template; context: optionContext(option, i)\" />\n } @else {\n @let parts = highlight(labelOf(option));\n {{ parts[0] }}<mark class=\"star-ac__match\">{{ parts[1] }}</mark>{{ parts[2] }}\n }\n </span>\n </li>\n }\n } @empty {\n <li class=\"star-listbox__empty\" role=\"presentation\">\n {{ loading() ? text.searching : emptyText() }}\n </li>\n }\n @if (virtualWindow().after) {\n <li class=\"star-listbox__spacer\" role=\"presentation\" [style.height.px]=\"virtualWindow().after\"></li>\n }\n </ul>\n </div>\n </ng-template>\n",
673
677
  isInline: true,
674
678
  dependencies: [
675
679
  {
@@ -1 +1 @@
1
- {"version":3,"file":"star-ng-ui-autocomplete.mjs","names":[],"sources":["../../../projects/star-ng/autocomplete/autocomplete.ts"],"sourcesContent":["import { CdkConnectedOverlay, CdkOverlayOrigin } from '@angular/cdk/overlay';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n inject,\n input,\n linkedSignal,\n model,\n output,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\nimport { matchesFilter } from '@star-ng/ui/core';\nimport { StarOptionListBase } from '@star-ng/ui/select';\n\nexport interface StarAutoCompleteSearch {\n readonly query: string;\n}\n\ninterface Chip<TValue> {\n readonly value: TValue;\n readonly label: string;\n}\n\n/**\n * Shared behaviour of the autocomplete controls (WAI-ARIA combobox with list autocomplete):\n * local filtering of `options`, or server search through `(completeMethod)` + `[suggestions]` with a\n * debounce, minimum query length, loading state, match highlighting, dropdown button and a\n * screen-reader result count.\n */\n@Directive()\nexport abstract class StarAutoCompleteBase<TOption, TValue> extends StarOptionListBase<\n TOption,\n TValue\n> {\n /** Server results. When set, the control shows these instead of filtering `options`. */\n readonly suggestions = input<readonly TOption[] | null>(null);\n readonly minQueryLength = input(1);\n /** Debounce in ms before `(completeMethod)` fires. */\n readonly delay = input(300);\n /** Shows a button that lists all options (local) or searches with an empty query. */\n readonly dropdown = input(false, { transform: booleanAttribute });\n /** Highlights the first result, so Enter picks it. */\n readonly autoHighlight = input(false, { transform: booleanAttribute });\n readonly showEmptyMessage = input(true, { transform: booleanAttribute });\n\n /** Fires (debounced) when the user types; load `suggestions` in reply (PrimeNG `completeMethod`). */\n readonly completeMethod = output<StarAutoCompleteSearch>();\n\n protected readonly closeOnChoose = true;\n protected abstract readonly isMultiple: boolean;\n protected readonly control = viewChild.required<ElementRef<HTMLElement>>('control');\n\n /** Options the user picked, so labels survive when the result list changes. */\n protected readonly known = signal<readonly TOption[]>([]);\n private readonly showAll = signal(false);\n private searchTimer: ReturnType<typeof setTimeout> | undefined;\n\n protected abstract queryFromValue(): string;\n /** Typed text. Resets to the selected label when the value changes. */\n protected readonly query = linkedSignal(() => this.queryFromValue());\n\n protected override readonly visibleOptions = computed(() => {\n const remote = this.suggestions();\n const query = this.query();\n const candidates =\n remote ??\n (this.showAll() || !query\n ? this.options()\n : this.options().filter((option) => matchesFilter(this.labelOf(option), query)));\n return this.groupedOrder(\n this.isMultiple ? candidates.filter((option) => !this.isSelected(option)) : candidates,\n );\n });\n\n protected readonly queryLongEnough = computed(\n () => this.showAll() || this.query().length >= this.minQueryLength(),\n );\n\n protected readonly panelVisible = computed(\n () =>\n this.open() &&\n this.queryLongEnough() &&\n (this.visibleOptions().length > 0 || this.loading() || this.showEmptyMessage()),\n );\n\n protected readonly liveText = computed(() => {\n if (!this.panelVisible()) return '';\n if (this.loading()) return this.text.searching;\n const count = this.visibleOptions().length;\n return count ? this.text.resultsAvailable(count) : this.emptyText();\n });\n\n constructor() {\n super();\n inject(DestroyRef).onDestroy(() => clearTimeout(this.searchTimer));\n // New results: highlight the first one (autoHighlight) or nothing.\n effect(() => {\n this.visibleOptions();\n untracked(() =>\n this.activeIndex.set(this.autoHighlight() ? this.firstEnabledFrom(0, 1) : -1),\n );\n });\n }\n\n protected initialActiveIndex(): number {\n return this.autoHighlight() ? this.firstEnabledFrom(0, 1) : -1;\n }\n\n /** Finds the option behind a stored value, for labels. */\n protected optionForValue(value: TValue): TOption | undefined {\n const pools = [this.known(), this.suggestions() ?? [], this.options()];\n for (const pool of pools) {\n const match = pool.find((option) => this.equals(this.valueOf(option), value));\n if (match !== undefined) return match;\n }\n return undefined;\n }\n\n protected labelForValue(value: TValue): string {\n const option = this.optionForValue(value);\n if (option !== undefined) return this.labelOf(option);\n return this.optionValue() === null ? this.labelOf(value as unknown as TOption) : String(value);\n }\n\n protected remember(option: TOption): void {\n this.known.update((known) => (known.includes(option) ? known : [...known, option]));\n }\n\n protected onQuery(text: string): void {\n this.query.set(text);\n this.showAll.set(false);\n clearTimeout(this.searchTimer);\n if (text.length < this.minQueryLength()) {\n this.closePanel(false);\n return;\n }\n this.openPanel();\n this.searchTimer = setTimeout(() => this.completeMethod.emit({ query: text }), this.delay());\n }\n\n protected showAllOptions(): void {\n if (!this.interactive()) return;\n if (this.panelVisible()) {\n this.closePanel();\n return;\n }\n this.showAll.set(true);\n this.completeMethod.emit({ query: '' });\n this.openPanel();\n this.focus();\n }\n\n protected override onOutsideClick(event: MouseEvent): void {\n if (this.control().nativeElement.contains(event.target as Node)) return;\n this.closePanel(false);\n this.onBlurCommit();\n this.touch.emit();\n }\n\n protected onInputBlur(): void {\n if (this.panelVisible()) return;\n this.onBlurCommit();\n this.touch.emit();\n }\n\n /** Called on blur: subclasses apply force-selection rules. */\n protected abstract onBlurCommit(): void;\n\n protected override onKeydown(event: KeyboardEvent): void {\n // Home / End move the caret in the text field; Enter on a closed list submits the form.\n if (event.key === 'Home' || event.key === 'End') return;\n if (event.key === 'Enter' && !this.panelVisible()) return;\n if (event.key === 'ArrowDown' && !this.open() && !this.queryLongEnough()) return;\n super.onKeydown(event);\n }\n\n /**\n * Sets the field text. Also writes the DOM: the `[value]` binding does not update when the\n * signal returns to the value it last rendered (typed text in between is not a signal write).\n */\n protected setText(text: string): void {\n this.query.set(text);\n (this.trigger().nativeElement as HTMLInputElement).value = text;\n }\n\n /** Splits a label around the typed text for `<mark>` highlighting. */\n protected highlight(label: string): readonly [string, string, string] {\n const query = this.query().trim();\n const index = query ? label.toLocaleLowerCase().indexOf(query.toLocaleLowerCase()) : -1;\n if (index < 0) return [label, '', ''];\n return [\n label.slice(0, index),\n label.slice(index, index + query.length),\n label.slice(index + query.length),\n ];\n }\n\n protected chips(): readonly Chip<TValue>[] {\n return [];\n }\n}\n\nconst TEMPLATE = `\n <div #control class=\"star-select__control star-ac__control\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n @if (isMultiple) {\n @for (chip of chips(); track $index) {\n <span class=\"star-chip star-chip--sm\">\n {{ chip.label }}\n @if (interactive()) {\n <button\n type=\"button\"\n class=\"star-chip__remove\"\n tabindex=\"-1\"\n [attr.aria-label]=\"text.removeItem(chip.label)\"\n (click)=\"removeValue(chip.value)\"\n >\n <i class=\"ph-bold ph-x\" aria-hidden=\"true\"></i>\n </button>\n }\n </span>\n }\n }\n <input\n #trigger\n type=\"text\"\n class=\"star-ac__input\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n autocomplete=\"off\"\n [id]=\"inputId()\"\n [attr.name]=\"name() || null\"\n [value]=\"query()\"\n [attr.placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"showInvalid() || null\"\n [attr.aria-expanded]=\"panelVisible()\"\n [attr.aria-controls]=\"panelVisible() ? listId : null\"\n [attr.aria-activedescendant]=\"panelVisible() ? activeId() : null\"\n (input)=\"onQuery(trigger.value)\"\n (keydown)=\"onKeydown($event)\"\n (blur)=\"onInputBlur()\"\n />\n @if (loading()) {\n <i class=\"ph-bold ph-spinner-gap star-spin star-select__caret\" aria-hidden=\"true\"></i>\n }\n @if (showClear() && hasValue() && interactive()) {\n <button type=\"button\" class=\"star-select__icon-btn\" [attr.aria-label]=\"text.clear\" (click)=\"clear()\">\n <i class=\"ph-bold ph-x\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (dropdown()) {\n <button\n type=\"button\"\n class=\"star-select__icon-btn\"\n tabindex=\"-1\"\n [attr.aria-label]=\"text.showOptions\"\n [disabled]=\"!interactive()\"\n (click)=\"showAllOptions()\"\n >\n <i class=\"ph-bold ph-caret-down\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n <span class=\"star-sr-only\" aria-live=\"polite\">{{ liveText() }}</span>\n\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayUsePopover=\"inline\"\n cdkConnectedOverlayMatchWidth\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"panelVisible()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n (detach)=\"closePanel(false)\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n >\n <div class=\"star-panel\" (mousedown)=\"onPanelMousedown($event)\">\n <ul\n class=\"star-listbox\"\n role=\"listbox\"\n [id]=\"listId\"\n [class.star-listbox--virtual]=\"virtualScroll()\"\n [style.--star-item-size.px]=\"virtualScroll() ? virtualItemSize() : null\"\n [style.max-height]=\"scrollHeight()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n (scroll)=\"onListScroll($event)\"\n >\n @if (virtualWindow().before) {\n <li class=\"star-listbox__spacer\" role=\"presentation\" [style.height.px]=\"virtualWindow().before\"></li>\n }\n @for (row of renderedRows(); track row.key) {\n @if (row.kind === 'group') {\n <li class=\"star-listbox__group\" role=\"presentation\" [id]=\"row.id\">{{ row.label }}</li>\n } @else {\n @let option = row.option;\n @let i = row.index;\n <!-- Keyboard is handled on the combobox via aria-activedescendant (WAI-ARIA combobox pattern). -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <li\n class=\"star-listbox__option\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [class.star-listbox__option--active]=\"activeIndex() === i\"\n [attr.aria-selected]=\"activeIndex() === i\"\n [attr.aria-disabled]=\"isDisabled(option) || null\"\n [attr.aria-describedby]=\"row.groupId\"\n [attr.aria-setsize]=\"virtualScroll() ? visibleOptions().length : null\"\n [attr.aria-posinset]=\"virtualScroll() ? i + 1 : null\"\n (click)=\"onOptionClick(option, i)\"\n (mousemove)=\"isDisabled(option) || activeIndex.set(i)\"\n >\n <span class=\"star-listbox__label\">\n @if (optionTemplate(); as custom) {\n <ng-container *ngTemplateOutlet=\"custom.template; context: optionContext(option, i)\" />\n } @else {\n @let parts = highlight(labelOf(option));\n {{ parts[0] }}<mark class=\"star-ac__match\">{{ parts[1] }}</mark>{{ parts[2] }}\n }\n </span>\n </li>\n }\n } @empty {\n <li class=\"star-listbox__empty\" role=\"presentation\">\n {{ loading() ? text.searching : emptyText() }}\n </li>\n }\n @if (virtualWindow().after) {\n <li class=\"star-listbox__spacer\" role=\"presentation\" [style.height.px]=\"virtualWindow().after\"></li>\n }\n </ul>\n </div>\n </ng-template>\n`;\n\nconst HOST = {\n class: 'star-select star-ac',\n '[class.star-select--open]': 'panelVisible()',\n '[class.star-select--disabled]': 'disabled()',\n '[class.star-select--invalid]': 'showInvalid()',\n '[class.star-select--sm]': \"size() === 'sm'\",\n};\n\n/**\n * Autocomplete (PrimeNG `p-autocomplete`). Local mode filters `options`; server mode listens\n * to `(completeMethod)` and shows `[suggestions]`. Only listed options can be chosen\n * (force selection): unmatched text reverts on blur, an exact label match is taken.\n *\n * ```html\n * <star-autocomplete [suggestions]=\"results()\" (completeMethod)=\"find($event.query)\" [loading]=\"busy()\"\n * optionLabel=\"name\" [formField]=\"form.assignee\" />\n * ```\n */\n@Component({\n selector: 'star-autocomplete',\n imports: [CdkConnectedOverlay, CdkOverlayOrigin, NgTemplateOutlet],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: HOST,\n template: TEMPLATE,\n})\nexport class StarAutoComplete<TOption = unknown, TValue = TOption>\n extends StarAutoCompleteBase<TOption, TValue>\n implements FormValueControl<TValue | null>\n{\n readonly value = model<TValue | null>(null);\n readonly selected = output<TOption>();\n\n protected readonly isMultiple = false;\n protected readonly hasValue = computed(() => this.value() !== null || !!this.query());\n\n protected queryFromValue(): string {\n const value = this.value();\n return value === null ? '' : this.labelForValue(value);\n }\n\n protected isSelected(option: TOption): boolean {\n const value = this.value();\n return value !== null && this.equals(this.valueOf(option), value);\n }\n\n protected choose(option: TOption): void {\n this.remember(option);\n this.value.set(this.valueOf(option));\n this.setText(this.labelOf(option));\n this.selected.emit(option);\n }\n\n protected onBlurCommit(): void {\n const text = this.query().trim();\n if (!text) {\n if (this.value() !== null) this.value.set(null);\n return;\n }\n if (text === this.queryFromValue()) return;\n const exact = this.visibleOptions().find(\n (option) =>\n !this.isDisabled(option) &&\n this.labelOf(option).toLocaleLowerCase() === text.toLocaleLowerCase(),\n );\n if (exact !== undefined) this.choose(exact);\n else this.setText(this.queryFromValue());\n }\n\n /** Single mode shows no chips; kept so both components share one template. */\n protected removeValue(_value: TValue): void {\n this.clear();\n }\n\n clear(): void {\n this.value.set(null);\n this.setText('');\n this.focus();\n }\n}\n\n/**\n * Multiple-value autocomplete (PrimeNG `p-autocomplete [multiple]`): chosen items become\n * removable chips, Backspace in an empty field removes the last chip, chosen options leave\n * the result list.\n */\n@Component({\n selector: 'star-multi-autocomplete',\n imports: [CdkConnectedOverlay, CdkOverlayOrigin, NgTemplateOutlet],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { ...HOST, class: 'star-select star-ac star-ac--multi' },\n template: TEMPLATE,\n})\nexport class StarMultiAutoComplete<TOption = unknown, TValue = TOption>\n extends StarAutoCompleteBase<TOption, TValue>\n implements FormValueControl<readonly TValue[]>\n{\n readonly value = model<readonly TValue[]>([]);\n /** Maximum number of chips (0 = no limit). */\n readonly selectionLimit = input(0);\n\n protected readonly isMultiple = true;\n protected readonly hasValue = computed(() => this.value().length > 0);\n\n protected queryFromValue(): string {\n return '';\n }\n\n protected override chips(): readonly Chip<TValue>[] {\n return this.value().map((value) => ({ value, label: this.labelForValue(value) }));\n }\n\n protected isSelected(option: TOption): boolean {\n const optionValue = this.valueOf(option);\n return this.value().some((value) => this.equals(value, optionValue));\n }\n\n protected choose(option: TOption): void {\n const limit = this.selectionLimit();\n if (this.isSelected(option) || (limit > 0 && this.value().length >= limit)) return;\n this.remember(option);\n this.value.update((values) => [...values, this.valueOf(option)]);\n this.setText('');\n }\n\n protected onBlurCommit(): void {\n this.setText('');\n }\n\n protected override onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Backspace' && !this.query() && this.value().length && this.interactive()) {\n this.value.update((values) => values.slice(0, -1));\n return;\n }\n super.onKeydown(event);\n }\n\n protected removeValue(value: TValue): void {\n this.value.update((values) => values.filter((v) => !this.equals(v, value)));\n this.focus();\n }\n\n clear(): void {\n this.value.set([]);\n this.setText('');\n this.focus();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"star-ng-ui-autocomplete.mjs","names":[],"sources":["../../../projects/star-ng/autocomplete/autocomplete.ts"],"sourcesContent":["import { CdkConnectedOverlay, CdkOverlayOrigin } from '@angular/cdk/overlay';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n inject,\n input,\n linkedSignal,\n model,\n output,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\nimport { matchesFilter } from '@star-ng/ui/core';\nimport { StarOptionListBase } from '@star-ng/ui/select';\n\nexport interface StarAutoCompleteSearch {\n readonly query: string;\n}\n\ninterface Chip<TValue> {\n readonly value: TValue;\n readonly label: string;\n}\n\n/**\n * Shared behaviour of the autocomplete controls (WAI-ARIA combobox with list autocomplete):\n * local filtering of `options`, or server search through `(completeMethod)` + `[suggestions]` with a\n * debounce, minimum query length, loading state, match highlighting, dropdown button and a\n * screen-reader result count.\n */\n@Directive()\nexport abstract class StarAutoCompleteBase<TOption, TValue> extends StarOptionListBase<\n TOption,\n TValue\n> {\n /** Server results. When set, the control shows these instead of filtering `options`. */\n readonly suggestions = input<readonly TOption[] | null>(null);\n readonly minQueryLength = input(1);\n /** Debounce in ms before `(completeMethod)` fires. */\n readonly delay = input(300);\n /** Shows a button that lists all options (local) or searches with an empty query. */\n readonly dropdown = input(false, { transform: booleanAttribute });\n /** Highlights the first result, so Enter picks it. */\n readonly autoHighlight = input(false, { transform: booleanAttribute });\n readonly showEmptyMessage = input(true, { transform: booleanAttribute });\n\n /** Fires (debounced) when the user types; load `suggestions` in reply (PrimeNG `completeMethod`). */\n readonly completeMethod = output<StarAutoCompleteSearch>();\n\n protected readonly closeOnChoose = true;\n protected abstract readonly isMultiple: boolean;\n protected readonly control = viewChild.required<ElementRef<HTMLElement>>('control');\n\n /** Options the user picked, so labels survive when the result list changes. */\n protected readonly known = signal<readonly TOption[]>([]);\n private readonly showAll = signal(false);\n private searchTimer: ReturnType<typeof setTimeout> | undefined;\n\n protected abstract queryFromValue(): string;\n /** Typed text. Resets to the selected label when the value changes. */\n protected readonly query = linkedSignal(() => this.queryFromValue());\n\n protected override readonly visibleOptions = computed(() => {\n const remote = this.suggestions();\n const query = this.query();\n const candidates =\n remote ??\n (this.showAll() || !query\n ? this.options()\n : this.options().filter((option) => matchesFilter(this.labelOf(option), query)));\n return this.groupedOrder(\n this.isMultiple ? candidates.filter((option) => !this.isSelected(option)) : candidates,\n );\n });\n\n protected readonly queryLongEnough = computed(\n () => this.showAll() || this.query().length >= this.minQueryLength(),\n );\n\n protected readonly panelVisible = computed(\n () =>\n this.open() &&\n this.queryLongEnough() &&\n (this.visibleOptions().length > 0 || this.loading() || this.showEmptyMessage()),\n );\n\n protected readonly liveText = computed(() => {\n if (!this.panelVisible()) return '';\n if (this.loading()) return this.text.searching;\n const count = this.visibleOptions().length;\n return count ? this.text.resultsAvailable(count) : this.emptyText();\n });\n\n constructor() {\n super();\n inject(DestroyRef).onDestroy(() => clearTimeout(this.searchTimer));\n // New results: show them from the top and highlight the first one (autoHighlight) or nothing.\n effect(() => {\n this.visibleOptions();\n untracked(() => {\n this.resetScroll();\n this.activeIndex.set(this.autoHighlight() ? this.firstEnabledFrom(0, 1) : -1);\n });\n });\n }\n\n protected initialActiveIndex(): number {\n return this.autoHighlight() ? this.firstEnabledFrom(0, 1) : -1;\n }\n\n /** Finds the option behind a stored value, for labels. */\n protected optionForValue(value: TValue): TOption | undefined {\n const pools = [this.known(), this.suggestions() ?? [], this.options()];\n for (const pool of pools) {\n const match = pool.find((option) => this.equals(this.valueOf(option), value));\n if (match !== undefined) return match;\n }\n return undefined;\n }\n\n protected labelForValue(value: TValue): string {\n const option = this.optionForValue(value);\n if (option !== undefined) return this.labelOf(option);\n return this.optionValue() === null ? this.labelOf(value as unknown as TOption) : String(value);\n }\n\n protected remember(option: TOption): void {\n this.known.update((known) => (known.includes(option) ? known : [...known, option]));\n }\n\n protected onQuery(text: string): void {\n this.query.set(text);\n this.showAll.set(false);\n clearTimeout(this.searchTimer);\n if (text.length < this.minQueryLength()) {\n this.closePanel(false);\n return;\n }\n this.openPanel();\n this.searchTimer = setTimeout(() => this.completeMethod.emit({ query: text }), this.delay());\n }\n\n protected showAllOptions(): void {\n if (!this.interactive()) return;\n if (this.panelVisible()) {\n this.closePanel();\n return;\n }\n this.showAll.set(true);\n this.completeMethod.emit({ query: '' });\n this.openPanel();\n this.focus();\n }\n\n protected override onOutsideClick(event: MouseEvent): void {\n if (this.control().nativeElement.contains(event.target as Node)) return;\n this.closePanel(false);\n this.onBlurCommit();\n this.touch.emit();\n }\n\n protected onInputBlur(): void {\n if (this.panelVisible()) return;\n this.onBlurCommit();\n this.touch.emit();\n }\n\n /** Called on blur: subclasses apply force-selection rules. */\n protected abstract onBlurCommit(): void;\n\n protected override onKeydown(event: KeyboardEvent): void {\n // Home / End move the caret in the text field; Enter on a closed list submits the form.\n if (event.key === 'Home' || event.key === 'End') return;\n if (event.key === 'Enter' && !this.panelVisible()) return;\n if (event.key === 'ArrowDown' && !this.open() && !this.queryLongEnough()) return;\n super.onKeydown(event);\n }\n\n /**\n * Sets the field text. Also writes the DOM: the `[value]` binding does not update when the\n * signal returns to the value it last rendered (typed text in between is not a signal write).\n */\n protected setText(text: string): void {\n this.query.set(text);\n (this.trigger().nativeElement as HTMLInputElement).value = text;\n }\n\n /** Splits a label around the typed text for `<mark>` highlighting. */\n protected highlight(label: string): readonly [string, string, string] {\n const query = this.query().trim();\n const index = query ? label.toLocaleLowerCase().indexOf(query.toLocaleLowerCase()) : -1;\n if (index < 0) return [label, '', ''];\n return [\n label.slice(0, index),\n label.slice(index, index + query.length),\n label.slice(index + query.length),\n ];\n }\n\n protected chips(): readonly Chip<TValue>[] {\n return [];\n }\n}\n\nconst TEMPLATE = `\n <div #control class=\"star-select__control star-ac__control\" cdkOverlayOrigin #origin=\"cdkOverlayOrigin\">\n @if (isMultiple) {\n @for (chip of chips(); track $index) {\n <span class=\"star-chip star-chip--sm\">\n {{ chip.label }}\n @if (interactive()) {\n <button\n type=\"button\"\n class=\"star-chip__remove\"\n tabindex=\"-1\"\n [attr.aria-label]=\"text.removeItem(chip.label)\"\n (click)=\"removeValue(chip.value)\"\n >\n <i class=\"ph-bold ph-x\" aria-hidden=\"true\"></i>\n </button>\n }\n </span>\n }\n }\n <input\n #trigger\n type=\"text\"\n class=\"star-ac__input\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n autocomplete=\"off\"\n [id]=\"inputId()\"\n [attr.name]=\"name() || null\"\n [value]=\"query()\"\n [attr.placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"showInvalid() || null\"\n [attr.aria-expanded]=\"panelVisible()\"\n [attr.aria-controls]=\"panelVisible() ? listId : null\"\n [attr.aria-activedescendant]=\"panelVisible() ? activeId() : null\"\n (input)=\"onQuery(trigger.value)\"\n (keydown)=\"onKeydown($event)\"\n (blur)=\"onInputBlur()\"\n />\n @if (loading()) {\n <i class=\"ph-bold ph-spinner-gap star-spin star-select__caret\" aria-hidden=\"true\"></i>\n }\n @if (showClear() && hasValue() && interactive()) {\n <button type=\"button\" class=\"star-select__icon-btn\" [attr.aria-label]=\"text.clear\" (click)=\"clear()\">\n <i class=\"ph-bold ph-x\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (dropdown()) {\n <button\n type=\"button\"\n class=\"star-select__icon-btn\"\n tabindex=\"-1\"\n [attr.aria-label]=\"text.showOptions\"\n [disabled]=\"!interactive()\"\n (click)=\"showAllOptions()\"\n >\n <i class=\"ph-bold ph-caret-down\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n <span class=\"star-sr-only\" aria-live=\"polite\">{{ liveText() }}</span>\n\n <ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayUsePopover=\"inline\"\n cdkConnectedOverlayMatchWidth\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"panelVisible()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n (attach)=\"onPanelAttached()\"\n (detach)=\"closePanel(false)\"\n (overlayOutsideClick)=\"onOutsideClick($event)\"\n >\n <div class=\"star-panel\" (mousedown)=\"onPanelMousedown($event)\">\n <ul\n class=\"star-listbox\"\n role=\"listbox\"\n [id]=\"listId\"\n [class.star-listbox--virtual]=\"virtualScroll()\"\n [style.--star-item-size.px]=\"virtualScroll() ? virtualItemSize() : null\"\n [style.max-height]=\"scrollHeight()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n (scroll)=\"onListScroll($event)\"\n >\n @if (virtualWindow().before) {\n <li class=\"star-listbox__spacer\" role=\"presentation\" [style.height.px]=\"virtualWindow().before\"></li>\n }\n @for (row of renderedRows(); track row.key) {\n @if (row.kind === 'group') {\n <li class=\"star-listbox__group\" role=\"presentation\" [id]=\"row.id\">{{ row.label }}</li>\n } @else {\n @let option = row.option;\n @let i = row.index;\n <!-- Keyboard is handled on the combobox via aria-activedescendant (WAI-ARIA combobox pattern). -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <li\n class=\"star-listbox__option\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [class.star-listbox__option--active]=\"activeIndex() === i\"\n [attr.aria-selected]=\"activeIndex() === i\"\n [attr.aria-disabled]=\"isDisabled(option) || null\"\n [attr.aria-describedby]=\"describedBy(row)\"\n [attr.aria-setsize]=\"virtualScroll() ? visibleOptions().length : null\"\n [attr.aria-posinset]=\"virtualScroll() ? i + 1 : null\"\n (click)=\"onOptionClick(option, i)\"\n (mousemove)=\"isDisabled(option) || activeIndex.set(i)\"\n >\n <span class=\"star-listbox__label\">\n @if (optionTemplate(); as custom) {\n <ng-container *ngTemplateOutlet=\"custom.template; context: optionContext(option, i)\" />\n } @else {\n @let parts = highlight(labelOf(option));\n {{ parts[0] }}<mark class=\"star-ac__match\">{{ parts[1] }}</mark>{{ parts[2] }}\n }\n </span>\n </li>\n }\n } @empty {\n <li class=\"star-listbox__empty\" role=\"presentation\">\n {{ loading() ? text.searching : emptyText() }}\n </li>\n }\n @if (virtualWindow().after) {\n <li class=\"star-listbox__spacer\" role=\"presentation\" [style.height.px]=\"virtualWindow().after\"></li>\n }\n </ul>\n </div>\n </ng-template>\n`;\n\nconst HOST = {\n class: 'star-select star-ac',\n '[class.star-select--open]': 'panelVisible()',\n '[class.star-select--disabled]': 'disabled()',\n '[class.star-select--invalid]': 'showInvalid()',\n '[class.star-select--sm]': \"size() === 'sm'\",\n};\n\n/**\n * Autocomplete (PrimeNG `p-autocomplete`). Local mode filters `options`; server mode listens\n * to `(completeMethod)` and shows `[suggestions]`. Only listed options can be chosen\n * (force selection): unmatched text reverts on blur, an exact label match is taken.\n *\n * ```html\n * <star-autocomplete [suggestions]=\"results()\" (completeMethod)=\"find($event.query)\" [loading]=\"busy()\"\n * optionLabel=\"name\" [formField]=\"form.assignee\" />\n * ```\n */\n@Component({\n selector: 'star-autocomplete',\n imports: [CdkConnectedOverlay, CdkOverlayOrigin, NgTemplateOutlet],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: HOST,\n template: TEMPLATE,\n})\nexport class StarAutoComplete<TOption = unknown, TValue = TOption>\n extends StarAutoCompleteBase<TOption, TValue>\n implements FormValueControl<TValue | null>\n{\n readonly value = model<TValue | null>(null);\n readonly selected = output<TOption>();\n\n protected readonly isMultiple = false;\n protected readonly hasValue = computed(() => this.value() !== null || !!this.query());\n\n protected queryFromValue(): string {\n const value = this.value();\n return value === null ? '' : this.labelForValue(value);\n }\n\n protected isSelected(option: TOption): boolean {\n const value = this.value();\n return value !== null && this.equals(this.valueOf(option), value);\n }\n\n protected choose(option: TOption): void {\n this.remember(option);\n this.value.set(this.valueOf(option));\n this.setText(this.labelOf(option));\n this.selected.emit(option);\n }\n\n protected onBlurCommit(): void {\n const text = this.query().trim();\n if (!text) {\n if (this.value() !== null) this.value.set(null);\n return;\n }\n if (text === this.queryFromValue()) return;\n const exact = this.visibleOptions().find(\n (option) =>\n !this.isDisabled(option) &&\n this.labelOf(option).toLocaleLowerCase() === text.toLocaleLowerCase(),\n );\n if (exact !== undefined) this.choose(exact);\n else this.setText(this.queryFromValue());\n }\n\n /** Single mode shows no chips; kept so both components share one template. */\n protected removeValue(_value: TValue): void {\n this.clear();\n }\n\n clear(): void {\n this.value.set(null);\n this.setText('');\n this.focus();\n }\n}\n\n/**\n * Multiple-value autocomplete (PrimeNG `p-autocomplete [multiple]`): chosen items become\n * removable chips, Backspace in an empty field removes the last chip, chosen options leave\n * the result list.\n */\n@Component({\n selector: 'star-multi-autocomplete',\n imports: [CdkConnectedOverlay, CdkOverlayOrigin, NgTemplateOutlet],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { ...HOST, class: 'star-select star-ac star-ac--multi' },\n template: TEMPLATE,\n})\nexport class StarMultiAutoComplete<TOption = unknown, TValue = TOption>\n extends StarAutoCompleteBase<TOption, TValue>\n implements FormValueControl<readonly TValue[]>\n{\n readonly value = model<readonly TValue[]>([]);\n /** Maximum number of chips (0 = no limit). */\n readonly selectionLimit = input(0);\n\n protected readonly isMultiple = true;\n protected readonly hasValue = computed(() => this.value().length > 0);\n\n protected queryFromValue(): string {\n return '';\n }\n\n protected override chips(): readonly Chip<TValue>[] {\n return this.value().map((value) => ({ value, label: this.labelForValue(value) }));\n }\n\n protected isSelected(option: TOption): boolean {\n const optionValue = this.valueOf(option);\n return this.value().some((value) => this.equals(value, optionValue));\n }\n\n protected choose(option: TOption): void {\n const limit = this.selectionLimit();\n if (this.isSelected(option) || (limit > 0 && this.value().length >= limit)) return;\n this.remember(option);\n this.value.update((values) => [...values, this.valueOf(option)]);\n this.setText('');\n }\n\n protected onBlurCommit(): void {\n this.setText('');\n }\n\n protected override onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Backspace' && !this.query() && this.value().length && this.interactive()) {\n this.value.update((values) => values.slice(0, -1));\n return;\n }\n super.onKeydown(event);\n }\n\n protected removeValue(value: TValue): void {\n this.value.update((values) => values.filter((v) => !this.equals(v, value)));\n this.focus();\n }\n\n clear(): void {\n this.value.set([]);\n this.setText('');\n this.focus();\n }\n}\n"],"mappings":"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"}
@@ -85,6 +85,98 @@ function provideStarDirection() {
85
85
  inject(StarDirectionService);
86
86
  });
87
87
  }
88
+ function starListLayout(options, groupOf, idPrefix) {
89
+ const rows = [];
90
+ const rowOfOption = [];
91
+ let current = null;
92
+ let groupId = null;
93
+ let groupRow = -1;
94
+ options.forEach((option, index) => {
95
+ if (groupOf) {
96
+ const label = groupOf(option);
97
+ if (index === 0 || label !== current) {
98
+ current = label;
99
+ groupId = `${idPrefix}-group-${index}`;
100
+ groupRow = rows.length;
101
+ rows.push({
102
+ kind: "group",
103
+ key: `g:${index}`,
104
+ label,
105
+ id: groupId
106
+ });
107
+ }
108
+ }
109
+ rowOfOption.push(rows.length);
110
+ rows.push({
111
+ kind: "option",
112
+ key: `o:${index}`,
113
+ option,
114
+ index,
115
+ groupId,
116
+ groupRow
117
+ });
118
+ });
119
+ return {
120
+ rows,
121
+ rowOfOption
122
+ };
123
+ }
124
+ function starListPageSize(viewportHeight, itemSize) {
125
+ const lines = Math.floor(viewportHeight / Math.max(1, itemSize));
126
+ return Math.max(1, lines - 1);
127
+ }
128
+ function starListKeyboardTarget(key, active, count, page) {
129
+ if (count <= 0) return -1;
130
+ const last = count - 1;
131
+ let target;
132
+ switch (key) {
133
+ case "ArrowDown":
134
+ target = active + 1;
135
+ break;
136
+ case "ArrowUp":
137
+ target = active - 1;
138
+ break;
139
+ case "Home":
140
+ target = 0;
141
+ break;
142
+ case "End":
143
+ target = last;
144
+ break;
145
+ case "PageDown":
146
+ target = (active < 0 ? 0 : active) + page;
147
+ break;
148
+ case "PageUp": target = (active < 0 ? last : active) - page;
149
+ }
150
+ return Math.min(Math.max(target, 0), last);
151
+ }
152
+ function starListTypeaheadIndex(count, labelAt, typed) {
153
+ for (let i = 0; i < count; i++) if (labelAt(i).toLowerCase().startsWith(typed)) return i;
154
+ return -1;
155
+ }
156
+ function starListRevealRows(layout, index) {
157
+ const row = layout.rowOfOption[index];
158
+ if (row === void 0) return [0, 0];
159
+ return [layout.rows[row - 1]?.kind === "group" ? row - 1 : row, row];
160
+ }
161
+ function starListRevealOffset(first, last, itemSize, scrollOffset, viewportHeight, inset = 0) {
162
+ const top = inset + first * itemSize;
163
+ const bottom = inset + (last + 1) * itemSize;
164
+ if (top < scrollOffset) return first === 0 ? 0 : top;
165
+ if (viewportHeight > 0 && bottom > scrollOffset + viewportHeight) return bottom - viewportHeight;
166
+ return null;
167
+ }
168
+ function starListAriaPosition(index, count) {
169
+ return {
170
+ setsize: count,
171
+ posinset: index + 1
172
+ };
173
+ }
174
+ function starListHeight(scrollHeight, rowCount, itemSize) {
175
+ return `min(${scrollHeight}, ${rowCount * Math.max(1, itemSize)}px)`;
176
+ }
177
+ function starListRowRendered(row, range) {
178
+ return row >= range.start && row < range.end;
179
+ }
88
180
  function readOption(option, key) {
89
181
  if (key === null || key === void 0) return option;
90
182
  if (typeof key === "function") return key(option);
@@ -387,6 +479,6 @@ function provideStarUiTextFromSignal(source) {
387
479
  useFactory: () => starUiTextFromSignal(source)
388
480
  };
389
481
  }
390
- export { STAR_UI_TEXT, STAR_UI_TEXT_DEFAULTS, STAR_UI_TEXT_PARAMS, StarDirectionService, compareValues, matchesFilter, optionText, provideStarDirection, provideStarUiText, provideStarUiTextFromSignal, readOption, starDirectionOf, starInlineKey, starIsRtl, starUiTextFromSignal, syncSignalFormControls };
482
+ export { STAR_UI_TEXT, STAR_UI_TEXT_DEFAULTS, STAR_UI_TEXT_PARAMS, StarDirectionService, compareValues, matchesFilter, optionText, provideStarDirection, provideStarUiText, provideStarUiTextFromSignal, readOption, starDirectionOf, starInlineKey, starIsRtl, starListAriaPosition, starListHeight, starListKeyboardTarget, starListLayout, starListPageSize, starListRevealOffset, starListRevealRows, starListRowRendered, starListTypeaheadIndex, starUiTextFromSignal, syncSignalFormControls };
391
483
 
392
484
  //# sourceMappingURL=star-ng-ui-core.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"star-ng-ui-core.mjs","names":[],"sources":["../../../projects/star-ng/core/direction.ts","../../../projects/star-ng/core/options.ts","../../../projects/star-ng/core/reactive-forms.ts","../../../projects/star-ng/core/ui-text.ts"],"sourcesContent":["import { Directionality } from '@angular/cdk/bidi';\nimport { DOCUMENT } from '@angular/common';\nimport {\n DestroyRef,\n EnvironmentProviders,\n Injectable,\n inject,\n provideEnvironmentInitializer,\n signal,\n} from '@angular/core';\n\n/** Text direction of an element: left-to-right or right-to-left. */\nexport type StarDirection = 'ltr' | 'rtl';\n\n/**\n * Text direction in force at one element. A `dir` attribute on the element or on an ancestor\n * decides; with `dir=\"auto\"` or no attribute the computed `direction` decides. The function\n * reads the DOM each time it is called, so a handler that calls it follows a direction change at\n * run time, and a part of the page that has its own `dir` attribute is respected.\n *\n * Controls use it in key handlers and pointer math: the horizontal arrow keys follow the visual\n * direction, so in `rtl` the left arrow means \"next\".\n */\nexport function starDirectionOf(element: Element | null | undefined): StarDirection {\n if (!element) return 'ltr';\n const attribute = element.closest('[dir]')?.getAttribute('dir')?.toLowerCase();\n if (attribute === 'rtl' || attribute === 'ltr') return attribute;\n const view = element.ownerDocument.defaultView;\n return view?.getComputedStyle(element).direction === 'rtl' ? 'rtl' : 'ltr';\n}\n\n/** `true` when the element is laid out right-to-left. See `starDirectionOf`. */\nexport function starIsRtl(element: Element | null | undefined): boolean {\n return starDirectionOf(element) === 'rtl';\n}\n\n/**\n * Key of a keyboard event in \"inline\" terms: `'ArrowRight'` means toward the end of the line and\n * `'ArrowLeft'` toward the start, whatever the direction. In right-to-left the two arrow keys are\n * swapped; every other key is returned as it is. A handler can then be written once, as for\n * left-to-right text:\n *\n * ```ts\n * switch (starInlineKey(event)) {\n * case 'ArrowRight': // next item in reading order\n * }\n * ```\n *\n * The element decides the direction; it defaults to `event.currentTarget`.\n */\nexport function starInlineKey(event: KeyboardEvent, element?: Element | null): string {\n if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return event.key;\n const target = element ?? (event.currentTarget instanceof Element ? event.currentTarget : null);\n if (!starIsRtl(target ?? (event.target instanceof Element ? event.target : null)))\n return event.key;\n return event.key === 'ArrowLeft' ? 'ArrowRight' : 'ArrowLeft';\n}\n\n/**\n * Direction of the application: the `dir` attribute of `<html>` (or `<body>`), followed at run\n * time. Controls that open an overlay or a menu (CDK `Overlay`, `CdkMenu`) inject it. It does\n * two things:\n *\n * 1. `value` is a signal, so a control can react when the application switches the direction.\n * 2. It keeps the root `Directionality` of `@angular/cdk/bidi` in step with the page. That\n * service reads the attribute once when it is created; without this, overlays and menus\n * would keep the old direction after a switch.\n *\n * The application only sets `dir` on `<html>`: `document.documentElement.dir = 'rtl'`.\n */\n@Injectable({ providedIn: 'root' })\nexport class StarDirectionService {\n private readonly document = inject(DOCUMENT);\n private readonly directionality = inject(Directionality, { optional: true });\n\n private readonly current = signal<StarDirection>(this.read());\n /** The direction of the page now. */\n readonly value = this.current.asReadonly();\n\n constructor() {\n this.sync();\n const view = this.document.defaultView;\n if (!view || typeof view.MutationObserver !== 'function') return;\n const observer = new view.MutationObserver(() => this.refresh());\n const options = { attributes: true, attributeFilter: ['dir'] };\n observer.observe(this.document.documentElement, options);\n if (this.document.body) observer.observe(this.document.body, options);\n inject(DestroyRef).onDestroy(() => observer.disconnect());\n }\n\n /** Reads the attribute again. The observer calls it; call it by hand after a change that the observer cannot see. */\n refresh(): void {\n const next = this.read();\n if (next === this.current()) return;\n this.current.set(next);\n this.sync();\n }\n\n private read(): StarDirection {\n const raw = (\n this.document.body?.dir ||\n this.document.documentElement.dir ||\n 'ltr'\n ).toLowerCase();\n if (raw === 'auto') {\n return this.document.defaultView?.getComputedStyle(this.document.documentElement)\n .direction === 'rtl'\n ? 'rtl'\n : 'ltr';\n }\n return raw === 'rtl' ? 'rtl' : 'ltr';\n }\n\n private sync(): void {\n const target = this.directionality;\n if (!target || target.valueSignal() === this.current()) return;\n target.valueSignal.set(this.current());\n target.change.emit(this.current());\n }\n}\n\n/**\n * Starts `StarDirectionService` when the application starts. Optional: the controls that open\n * an overlay start the service themselves. Use it when the direction changes at run time before\n * any such control exists, or when your own code reads `StarDirectionService.value`.\n *\n * ```ts\n * bootstrapApplication(App, { providers: [provideStarDirection()] });\n * ```\n */\nexport function provideStarDirection(): EnvironmentProviders {\n return provideEnvironmentInitializer(() => {\n inject(StarDirectionService);\n });\n}\n","/**\n * How a list control reads a property from an option: a property name or an accessor function.\n * Same idea as PrimeNG `optionLabel` / `optionValue` / `optionDisabled`, but type safe.\n */\nexport type StarOptionKey<T, R = unknown> = (keyof T & string) | ((option: T) => R);\n\nexport type StarSeverity = 'primary' | 'secondary' | 'success' | 'info' | 'warn' | 'danger';\n\nexport type StarSize = 'sm' | 'md' | 'lg';\n\nexport function readOption<T, R>(option: T, key: StarOptionKey<T, R> | null | undefined): unknown {\n if (key === null || key === undefined) return option;\n if (typeof key === 'function') return key(option);\n return option !== null && typeof option === 'object'\n ? (option as Record<string, unknown>)[key]\n : undefined;\n}\n\n/** Text shown for an option. Falls back to the option itself for primitive options. */\nexport function optionText<T>(option: T, key: StarOptionKey<T> | null | undefined): string {\n const value = readOption(option, key ?? null);\n return value === null || value === undefined ? '' : String(value);\n}\n\nconst collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });\n\n/** Locale-aware compare used by sorting: numbers and dates numerically, text with Intl.Collator. */\nexport function compareValues(a: unknown, b: unknown): number {\n const aEmpty = a === null || a === undefined;\n const bEmpty = b === null || b === undefined;\n if (aEmpty && bEmpty) return 0;\n if (aEmpty) return -1;\n if (bEmpty) return 1;\n if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();\n if (typeof a === 'number' && typeof b === 'number') return a - b;\n return collator.compare(String(a), String(b));\n}\n\n/** Case- and accent-insensitive \"contains\" match used by filters. */\nexport function matchesFilter(text: string, query: string): boolean {\n if (!query) return true;\n const normalize = (value: string) =>\n value\n .normalize('NFD')\n .replace(/\\p{Diacritic}/gu, '')\n .toLocaleLowerCase();\n return normalize(text).includes(normalize(query.trim()));\n}\n","import { effect, EffectRef, inject, Injector, untracked } from '@angular/core';\nimport { AbstractControl, FormArray, FormGroup } from '@angular/forms';\nimport { SignalFormControl } from '@angular/forms/signals/compat';\n\nfunction signalControls(control: AbstractControl): SignalFormControl<unknown>[] {\n if (control instanceof SignalFormControl) return [control as SignalFormControl<unknown>];\n if (control instanceof FormGroup || control instanceof FormArray) {\n return Object.values(control.controls).flatMap(signalControls);\n }\n return [];\n}\n\n/**\n * Keeps a Reactive `FormGroup` (or `FormArray`) in step with the `SignalFormControl`s inside it.\n *\n * Angular 22 updates a parent group when a `SignalFormControl` value changes, but not when a\n * Signal Forms rule (for example `disabled({ when })` or a conditional `required`) changes the\n * child's status without a value change. The group then reports a stale `valid` / `status`.\n * This effect watches every signal control's validity, disabled and pending state and calls\n * `updateValueAndValidity()` on the group when one changes.\n *\n * Call it in an injection context (a field initializer or constructor):\n * ```ts\n * readonly form = new FormGroup({ country: new SignalFormControl<string | null>(null, rules) });\n * private readonly sync = syncSignalFormControls(this.form);\n * ```\n */\nexport function syncSignalFormControls(\n group: FormGroup | FormArray,\n injector: Injector = inject(Injector),\n): EffectRef {\n const controls = signalControls(group);\n return effect(\n () => {\n for (const control of controls) {\n const state = control.fieldTree();\n state.valid();\n state.disabled();\n state.pending();\n }\n untracked(() => group.updateValueAndValidity());\n },\n { injector },\n );\n}\n","import { InjectionToken, Provider } from '@angular/core';\n\n/**\n * Built-in texts of the StarNG UI controls (screen-reader labels, empty states, reports).\n * Defaults are English. Override them once at app level:\n * - `provideStarUiTextFromTransloco()` reads them from the active Transloco language (`ui.*` keys)\n * and updates the controls live when the language changes.\n * - `provideStarUiText({...})` sets fixed texts.\n *\n * Function entries take values (for example a count) and return the full sentence, so word order\n * can change per language. Their parameter names are listed in `STAR_UI_TEXT_PARAMS`.\n */\nexport interface StarUiText {\n // General\n readonly close: string;\n readonly clear: string;\n readonly loading: string;\n readonly actions: string;\n readonly moreActions: string;\n readonly ofTotal: (index: number, total: number) => string;\n readonly expandItem: (label: string) => string;\n readonly collapseItem: (label: string) => string;\n readonly removeItem: (label: string) => string;\n // Tags field\n readonly tagsHint: string;\n readonly tagAdded: (label: string) => string;\n readonly tagRemoved: (label: string) => string;\n readonly tagInvalid: (label: string) => string;\n readonly tagDuplicate: (label: string) => string;\n readonly tagLimit: (max: number) => string;\n readonly notifications: string;\n readonly accept: string;\n readonly reject: string;\n // Select, listbox, autocomplete\n readonly selectPlaceholder: string;\n readonly filterPlaceholder: string;\n readonly emptyMessage: string;\n readonly emptyFilterMessage: string;\n readonly selectAll: string;\n readonly selectedItems: (count: number) => string;\n readonly searching: string;\n readonly showOptions: string;\n readonly resultsAvailable: (count: number) => string;\n // Table, paginator, data view\n readonly pagination: string;\n readonly firstPage: string;\n readonly previousPage: string;\n readonly nextPage: string;\n readonly lastPage: string;\n readonly page: (page: number) => string;\n readonly rowsPerPage: string;\n readonly pageReport: (first: number, last: number, total: number) => string;\n readonly noData: string;\n readonly selectRow: string;\n readonly selectAllRows: string;\n readonly filterBy: (column: string) => string;\n readonly filterAll: string;\n readonly filterMin: (column: string) => string;\n readonly filterMax: (column: string) => string;\n readonly filterMinShort: string;\n readonly filterMaxShort: string;\n readonly expandRow: string;\n readonly collapseRow: string;\n readonly rowDetails: string;\n readonly reorderRows: string;\n readonly sortMultiHint: string;\n readonly terminalCommand: string;\n readonly compareImages: string;\n readonly editCell: (column: string) => string;\n readonly columns: string;\n readonly resizeColumn: (column: string) => string;\n readonly moveColumnEarlier: (column: string) => string;\n readonly moveColumnLater: (column: string) => string;\n readonly layout: string;\n readonly layoutList: string;\n readonly layoutGrid: string;\n // Order list, pick list\n readonly moveSelectedItem: string;\n readonly orderListHint: string;\n readonly moveTop: string;\n readonly moveUp: string;\n readonly moveDown: string;\n readonly moveBottom: string;\n readonly itemPosition: (label: string, position: number, total: number) => string;\n readonly transfer: string;\n readonly moveSelectedToTarget: string;\n readonly moveAllToTarget: string;\n readonly moveSelectedToSource: string;\n readonly moveAllToSource: string;\n readonly pickListSource: string;\n readonly pickListTarget: string;\n // Dates\n readonly chooseDate: string;\n readonly chooseMonth: string;\n readonly chooseYear: string;\n readonly previousMonth: string;\n readonly nextMonth: string;\n readonly previousYears: string;\n readonly nextYears: string;\n readonly today: string;\n readonly time: string;\n readonly startTime: string;\n readonly weekNumber: string;\n readonly weekShort: string;\n readonly endTime: string;\n readonly done: string;\n // Inputs\n readonly increase: string;\n readonly decrease: string;\n readonly showPassword: string;\n readonly hidePassword: string;\n readonly passwordWeak: string;\n readonly passwordFair: string;\n readonly passwordGood: string;\n readonly passwordStrong: string;\n readonly passwordRuleLength: (min: number) => string;\n readonly passwordRuleUpper: string;\n readonly passwordRuleLower: string;\n readonly passwordRuleNumber: string;\n readonly passwordRuleSymbol: string;\n readonly ruleMet: string;\n readonly ruleNotMet: string;\n readonly otpLabel: string;\n readonly otpCharacter: (position: number, total: number) => string;\n readonly ratingLabel: string;\n readonly sliderMinimum: (label: string) => string;\n readonly sliderMaximum: (label: string) => string;\n readonly colorLabel: string;\n readonly customColor: string;\n readonly hexValue: (label: string) => string;\n // File upload\n readonly chooseFiles: string;\n readonly dropFiles: string;\n readonly fileMaxSize: (size: string) => string;\n readonly fileUpTo: (count: number) => string;\n readonly uploadingFile: (name: string) => string;\n readonly uploaded: string;\n readonly fileTypeNotAllowed: (name: string) => string;\n readonly fileTooLarge: (name: string, max: string) => string;\n readonly fileLimitReached: (limit: number) => string;\n // Editor\n readonly editorLabel: string;\n readonly editorFormatting: (label: string) => string;\n readonly editorBold: string;\n readonly editorItalic: string;\n readonly editorUnderline: string;\n readonly editorHeading: string;\n readonly editorBulletList: string;\n readonly editorNumberedList: string;\n readonly editorClearFormatting: string;\n readonly editorLink: string;\n readonly editorLinkPrompt: string;\n // Navigation and layout\n readonly breadcrumb: string;\n readonly stepperLabel: string;\n readonly stepCompleted: string;\n readonly resizePanes: string;\n readonly dock: string;\n readonly scrollToTop: string;\n readonly theme: string;\n readonly themeSystem: string;\n readonly themeLight: string;\n readonly themeDark: string;\n // Media\n readonly pauseSlides: string;\n readonly playSlides: string;\n readonly previousSlides: string;\n readonly nextSlides: string;\n readonly galleryLabel: string;\n readonly previousImage: string;\n readonly nextImage: string;\n readonly showImage: (alt: string) => string;\n readonly previewImage: (alt: string) => string;\n readonly zoomIn: string;\n readonly zoomOut: string;\n // Charts and meters\n readonly chartView: string;\n readonly tableView: string;\n readonly chartTotal: string;\n readonly chartOther: string;\n readonly chartCategory: string;\n readonly chartValue: string;\n readonly chartShare: string;\n readonly chartSeries: string;\n readonly chartX: string;\n readonly chartY: string;\n readonly chartTypeBar: string;\n readonly chartTypeStackedBar: string;\n readonly chartTypeLine: string;\n readonly chartTypeArea: string;\n readonly chartTypeDoughnut: string;\n readonly chartTypePie: string;\n readonly chartTypeRadar: string;\n readonly chartTypePolarArea: string;\n readonly chartTypeScatter: string;\n readonly chartDescription: (\n kind: string,\n series: number,\n items: number,\n min: string,\n max: string,\n ) => string;\n readonly meterValue: (value: string, total: number) => string;\n}\n\nexport const STAR_UI_TEXT_DEFAULTS: StarUiText = {\n close: 'Close',\n clear: 'Clear',\n loading: 'Loading',\n actions: 'Actions',\n moreActions: 'More actions',\n ofTotal: (index, total) => `${index} of ${total}`,\n expandItem: (label) => `Expand ${label}`,\n collapseItem: (label) => `Collapse ${label}`,\n removeItem: (label) => `Remove ${label}`,\n tagsHint: 'Press Enter or comma to add. Backspace removes the last item.',\n tagAdded: (label) => `${label} added`,\n tagRemoved: (label) => `${label} removed`,\n tagInvalid: (label) => `${label} is not valid.`,\n tagDuplicate: (label) => `${label} is already added.`,\n tagLimit: (max) => `You can add up to ${max} items.`,\n notifications: 'Notifications',\n accept: 'Confirm',\n reject: 'Cancel',\n\n selectPlaceholder: 'Select',\n filterPlaceholder: 'Search',\n emptyMessage: 'No options available',\n emptyFilterMessage: 'No results found',\n selectAll: 'Select all',\n selectedItems: (count) => `${count} items selected`,\n searching: 'Searching…',\n showOptions: 'Show options',\n resultsAvailable: (count) => (count === 1 ? '1 result available' : `${count} results available`),\n\n pagination: 'Pagination',\n firstPage: 'First page',\n previousPage: 'Previous page',\n nextPage: 'Next page',\n lastPage: 'Last page',\n page: (page) => `Page ${page}`,\n rowsPerPage: 'Rows per page',\n pageReport: (first, last, total) => `${first}–${last} of ${total}`,\n noData: 'No records found',\n selectRow: 'Select row',\n selectAllRows: 'Select all rows',\n filterBy: (column) => `Filter by ${column}`,\n filterAll: 'All',\n filterMin: (column) => `${column} from`,\n filterMax: (column) => `${column} to`,\n filterMinShort: 'Min',\n filterMaxShort: 'Max',\n expandRow: 'Expand row',\n collapseRow: 'Collapse row',\n rowDetails: 'Details',\n reorderRows: 'Order',\n sortMultiHint: 'Shift + click adds this column to the sort',\n terminalCommand: 'Command',\n compareImages: 'Compare images',\n editCell: (column) => `Edit ${column}`,\n columns: 'Columns',\n resizeColumn: (column) => `Resize ${column}`,\n moveColumnEarlier: (column) => `Move ${column} earlier`,\n moveColumnLater: (column) => `Move ${column} later`,\n layout: 'Layout',\n layoutList: 'List',\n layoutGrid: 'Grid',\n\n moveSelectedItem: 'Move selected item',\n orderListHint: 'Use Alt and the arrow keys to move the selected item.',\n moveTop: 'Move to top',\n moveUp: 'Move up',\n moveDown: 'Move down',\n moveBottom: 'Move to bottom',\n itemPosition: (label, position, total) => `${label}, position ${position} of ${total}`,\n transfer: 'Transfer',\n moveSelectedToTarget: 'Move selected to target',\n moveAllToTarget: 'Move all to target',\n moveSelectedToSource: 'Move selected to source',\n moveAllToSource: 'Move all to source',\n pickListSource: 'Available',\n pickListTarget: 'Selected',\n\n chooseDate: 'Choose date',\n chooseMonth: 'Choose month',\n chooseYear: 'Choose year',\n previousMonth: 'Previous month',\n nextMonth: 'Next month',\n previousYears: 'Previous years',\n nextYears: 'Next years',\n today: 'Today',\n time: 'Time',\n startTime: 'Start time',\n weekNumber: 'Week number',\n weekShort: 'Wk',\n endTime: 'End time',\n done: 'Done',\n\n increase: 'Increase',\n decrease: 'Decrease',\n showPassword: 'Show password',\n hidePassword: 'Hide password',\n passwordWeak: 'Password strength: weak',\n passwordFair: 'Password strength: fair',\n passwordGood: 'Password strength: good',\n passwordStrong: 'Password strength: strong',\n passwordRuleLength: (min) => `At least ${min} characters`,\n passwordRuleUpper: 'An uppercase letter',\n passwordRuleLower: 'A lowercase letter',\n passwordRuleNumber: 'A number',\n passwordRuleSymbol: 'A symbol',\n ruleMet: 'met',\n ruleNotMet: 'not met',\n otpLabel: 'Verification code',\n otpCharacter: (position, total) => `Character ${position} of ${total}`,\n ratingLabel: 'Rating',\n sliderMinimum: (label) => `${label} minimum`.trim(),\n sliderMaximum: (label) => `${label} maximum`.trim(),\n colorLabel: 'Color',\n customColor: 'Custom color',\n hexValue: (label) => `${label} hex value`,\n\n chooseFiles: 'Choose files',\n dropFiles: 'Drag files here, or',\n fileMaxSize: (size) => `max ${size}`,\n fileUpTo: (count) => `up to ${count} files`,\n uploadingFile: (name) => `Uploading ${name}`,\n uploaded: 'Uploaded',\n fileTypeNotAllowed: (name) => `${name}: this file type is not allowed.`,\n fileTooLarge: (name, max) => `${name}: the file is larger than ${max}.`,\n fileLimitReached: (limit) => `You can add up to ${limit} files.`,\n\n editorLabel: 'Editor',\n editorFormatting: (label) => `${label} formatting`,\n editorBold: 'Bold',\n editorItalic: 'Italic',\n editorUnderline: 'Underline',\n editorHeading: 'Heading',\n editorBulletList: 'Bulleted list',\n editorNumberedList: 'Numbered list',\n editorClearFormatting: 'Clear formatting',\n editorLink: 'Link',\n editorLinkPrompt: 'Link address (https://…)',\n\n breadcrumb: 'Breadcrumb',\n stepperLabel: 'Progress',\n stepCompleted: '(completed)',\n resizePanes: 'Resize panes',\n dock: 'Dock',\n scrollToTop: 'Scroll to top',\n theme: 'Theme',\n themeSystem: 'System',\n themeLight: 'Light',\n themeDark: 'Dark',\n\n pauseSlides: 'Pause slides',\n playSlides: 'Play slides',\n previousSlides: 'Previous slides',\n nextSlides: 'Next slides',\n galleryLabel: 'Gallery',\n previousImage: 'Previous image',\n nextImage: 'Next image',\n showImage: (alt) => `Show ${alt}`,\n previewImage: (alt) => `Preview: ${alt}`,\n zoomIn: 'Zoom in',\n zoomOut: 'Zoom out',\n\n chartView: 'Chart',\n tableView: 'Table',\n chartTotal: 'Total',\n chartOther: 'Other',\n chartCategory: 'Category',\n chartValue: 'Value',\n chartShare: 'Share',\n chartSeries: 'Series',\n chartX: 'X',\n chartY: 'Y',\n chartTypeBar: 'Bar chart',\n chartTypeStackedBar: 'Stacked bar chart',\n chartTypeLine: 'Line chart',\n chartTypeArea: 'Area chart',\n chartTypeDoughnut: 'Doughnut chart',\n chartTypePie: 'Pie chart',\n chartTypeRadar: 'Radar chart',\n chartTypePolarArea: 'Polar area chart',\n chartTypeScatter: 'Scatter chart',\n chartDescription: (kind, series, items, min, max) =>\n `${kind} with ${series} series and ${items} ${items === 1 ? 'item' : 'items'}, values from ${min} to ${max}. The same data is in the table.`,\n meterValue: (value, total) => `${value} of ${total}`,\n};\n\n/** Parameter names of the function entries, in call order (used for `{{ name }}` in translations). */\nexport const STAR_UI_TEXT_PARAMS: { readonly [K in keyof StarUiText]?: readonly string[] } = {\n ofTotal: ['index', 'total'],\n expandItem: ['label'],\n collapseItem: ['label'],\n removeItem: ['label'],\n tagAdded: ['label'],\n tagRemoved: ['label'],\n tagInvalid: ['label'],\n tagDuplicate: ['label'],\n tagLimit: ['max'],\n selectedItems: ['count'],\n resultsAvailable: ['count'],\n page: ['page'],\n pageReport: ['first', 'last', 'total'],\n filterBy: ['column'],\n filterMin: ['column'],\n filterMax: ['column'],\n editCell: ['column'],\n resizeColumn: ['column'],\n moveColumnEarlier: ['column'],\n moveColumnLater: ['column'],\n itemPosition: ['label', 'position', 'total'],\n passwordRuleLength: ['min'],\n otpCharacter: ['position', 'total'],\n sliderMinimum: ['label'],\n sliderMaximum: ['label'],\n hexValue: ['label'],\n fileMaxSize: ['size'],\n fileUpTo: ['count'],\n uploadingFile: ['name'],\n fileTypeNotAllowed: ['name'],\n fileTooLarge: ['name', 'max'],\n fileLimitReached: ['limit'],\n editorFormatting: ['label'],\n showImage: ['alt'],\n previewImage: ['alt'],\n meterValue: ['value', 'total'],\n chartDescription: ['kind', 'series', 'items', 'min', 'max'],\n};\n\nexport const STAR_UI_TEXT = new InjectionToken<StarUiText>('STAR_UI_TEXT', {\n providedIn: 'root',\n factory: () => STAR_UI_TEXT_DEFAULTS,\n});\n\n/** Overrides some or all built-in control texts with fixed values. */\nexport function provideStarUiText(overrides: Partial<StarUiText>): Provider {\n return { provide: STAR_UI_TEXT, useValue: { ...STAR_UI_TEXT_DEFAULTS, ...overrides } };\n}\n\n/**\n * Builds a `StarUiText` whose entries read `source()` on every access. When `source` reads a\n * signal, every OnPush control that renders a built-in text updates when that signal changes.\n * Entries that `source()` does not return fall back to the English default.\n *\n * Use it in a factory when the signal lives in a service:\n * `{ provide: STAR_UI_TEXT, useFactory: () => starUiTextFromSignal(inject(Language).text) }`.\n */\nexport function starUiTextFromSignal(source: () => Partial<StarUiText>): StarUiText {\n const text = {} as Record<string, unknown>;\n for (const name of Object.keys(STAR_UI_TEXT_DEFAULTS) as (keyof StarUiText)[]) {\n if (typeof STAR_UI_TEXT_DEFAULTS[name] === 'function') {\n text[name] = (...args: unknown[]) => {\n const entry = (source()[name] ?? STAR_UI_TEXT_DEFAULTS[name]) as (\n ...a: unknown[]\n ) => string;\n return entry(...args);\n };\n } else {\n Object.defineProperty(text, name, {\n enumerable: true,\n get: () => source()[name] ?? STAR_UI_TEXT_DEFAULTS[name],\n });\n }\n }\n return text as unknown as StarUiText;\n}\n\n/**\n * Provides the control texts from a function that reads a signal, so the language can change at\n * run time without a translation library:\n *\n * ```ts\n * const language = signal<'en' | 'de'>('en');\n * provideStarUiTextFromSignal(() => (language() === 'de' ? STAR_UI_TEXT_DE : STAR_UI_TEXT_DEFAULTS));\n * ```\n *\n * Do not spread a pack with getters into an object (`{ ...text }`): that reads every getter once and\n * freezes the result. Pass a function, as shown above.\n */\nexport function provideStarUiTextFromSignal(source: () => Partial<StarUiText>): Provider {\n return { provide: STAR_UI_TEXT, useFactory: () => starUiTextFromSignal(source) };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"star-ng-ui-core.mjs","names":[],"sources":["../../../projects/star-ng/core/direction.ts","../../../projects/star-ng/core/list-windowing.ts","../../../projects/star-ng/core/options.ts","../../../projects/star-ng/core/reactive-forms.ts","../../../projects/star-ng/core/ui-text.ts"],"sourcesContent":["import { Directionality } from '@angular/cdk/bidi';\nimport { DOCUMENT } from '@angular/common';\nimport {\n DestroyRef,\n EnvironmentProviders,\n Injectable,\n inject,\n provideEnvironmentInitializer,\n signal,\n} from '@angular/core';\n\n/** Text direction of an element: left-to-right or right-to-left. */\nexport type StarDirection = 'ltr' | 'rtl';\n\n/**\n * Text direction in force at one element. A `dir` attribute on the element or on an ancestor\n * decides; with `dir=\"auto\"` or no attribute the computed `direction` decides. The function\n * reads the DOM each time it is called, so a handler that calls it follows a direction change at\n * run time, and a part of the page that has its own `dir` attribute is respected.\n *\n * Controls use it in key handlers and pointer math: the horizontal arrow keys follow the visual\n * direction, so in `rtl` the left arrow means \"next\".\n */\nexport function starDirectionOf(element: Element | null | undefined): StarDirection {\n if (!element) return 'ltr';\n const attribute = element.closest('[dir]')?.getAttribute('dir')?.toLowerCase();\n if (attribute === 'rtl' || attribute === 'ltr') return attribute;\n const view = element.ownerDocument.defaultView;\n return view?.getComputedStyle(element).direction === 'rtl' ? 'rtl' : 'ltr';\n}\n\n/** `true` when the element is laid out right-to-left. See `starDirectionOf`. */\nexport function starIsRtl(element: Element | null | undefined): boolean {\n return starDirectionOf(element) === 'rtl';\n}\n\n/**\n * Key of a keyboard event in \"inline\" terms: `'ArrowRight'` means toward the end of the line and\n * `'ArrowLeft'` toward the start, whatever the direction. In right-to-left the two arrow keys are\n * swapped; every other key is returned as it is. A handler can then be written once, as for\n * left-to-right text:\n *\n * ```ts\n * switch (starInlineKey(event)) {\n * case 'ArrowRight': // next item in reading order\n * }\n * ```\n *\n * The element decides the direction; it defaults to `event.currentTarget`.\n */\nexport function starInlineKey(event: KeyboardEvent, element?: Element | null): string {\n if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return event.key;\n const target = element ?? (event.currentTarget instanceof Element ? event.currentTarget : null);\n if (!starIsRtl(target ?? (event.target instanceof Element ? event.target : null)))\n return event.key;\n return event.key === 'ArrowLeft' ? 'ArrowRight' : 'ArrowLeft';\n}\n\n/**\n * Direction of the application: the `dir` attribute of `<html>` (or `<body>`), followed at run\n * time. Controls that open an overlay or a menu (CDK `Overlay`, `CdkMenu`) inject it. It does\n * two things:\n *\n * 1. `value` is a signal, so a control can react when the application switches the direction.\n * 2. It keeps the root `Directionality` of `@angular/cdk/bidi` in step with the page. That\n * service reads the attribute once when it is created; without this, overlays and menus\n * would keep the old direction after a switch.\n *\n * The application only sets `dir` on `<html>`: `document.documentElement.dir = 'rtl'`.\n */\n@Injectable({ providedIn: 'root' })\nexport class StarDirectionService {\n private readonly document = inject(DOCUMENT);\n private readonly directionality = inject(Directionality, { optional: true });\n\n private readonly current = signal<StarDirection>(this.read());\n /** The direction of the page now. */\n readonly value = this.current.asReadonly();\n\n constructor() {\n this.sync();\n const view = this.document.defaultView;\n if (!view || typeof view.MutationObserver !== 'function') return;\n const observer = new view.MutationObserver(() => this.refresh());\n const options = { attributes: true, attributeFilter: ['dir'] };\n observer.observe(this.document.documentElement, options);\n if (this.document.body) observer.observe(this.document.body, options);\n inject(DestroyRef).onDestroy(() => observer.disconnect());\n }\n\n /** Reads the attribute again. The observer calls it; call it by hand after a change that the observer cannot see. */\n refresh(): void {\n const next = this.read();\n if (next === this.current()) return;\n this.current.set(next);\n this.sync();\n }\n\n private read(): StarDirection {\n const raw = (\n this.document.body?.dir ||\n this.document.documentElement.dir ||\n 'ltr'\n ).toLowerCase();\n if (raw === 'auto') {\n return this.document.defaultView?.getComputedStyle(this.document.documentElement)\n .direction === 'rtl'\n ? 'rtl'\n : 'ltr';\n }\n return raw === 'rtl' ? 'rtl' : 'ltr';\n }\n\n private sync(): void {\n const target = this.directionality;\n if (!target || target.valueSignal() === this.current()) return;\n target.valueSignal.set(this.current());\n target.change.emit(this.current());\n }\n}\n\n/**\n * Starts `StarDirectionService` when the application starts. Optional: the controls that open\n * an overlay start the service themselves. Use it when the direction changes at run time before\n * any such control exists, or when your own code reads `StarDirectionService.value`.\n *\n * ```ts\n * bootstrapApplication(App, { providers: [provideStarDirection()] });\n * ```\n */\nexport function provideStarDirection(): EnvironmentProviders {\n return provideEnvironmentInitializer(() => {\n inject(StarDirectionService);\n });\n}\n","/**\n * Pure helpers of the windowed option lists: row model, index math, keyboard target and ARIA\n * values. `star-listbox` and the select family (`star-select`, `star-multi-select`,\n * `star-autocomplete`) use them. They have no DOM access, so unit tests can check them without\n * layout. They are exported because entry points import each other by package name. They are\n * helpers of the library, not a stable extension point.\n */\n\n/** One row of a windowed list. Group headings and options have the same height. */\nexport type StarWindowRow<T> =\n | { readonly kind: 'group'; readonly key: string; readonly label: string; readonly id: string }\n | {\n readonly kind: 'option';\n readonly key: string;\n readonly option: T;\n /** Index in the visible options (keyboard order). */\n readonly index: number;\n /** Id of the heading row of the group, or null without groups. */\n readonly groupId: string | null;\n /** Index of the heading row of the group, or -1 without groups. */\n readonly groupRow: number;\n };\n\n/** The rows, and for each visible option the index of its row. */\nexport interface StarWindowLayout<T> {\n readonly rows: readonly StarWindowRow<T>[];\n readonly rowOfOption: readonly number[];\n}\n\n/**\n * Flattens headings and options into one list of rows of equal height. `options` must already be\n * in display order (each group together). A heading comes before the first option of each group.\n * The heading id has the form `<idPrefix>-group-<index of the first option of the group>`.\n */\nexport function starListLayout<T>(\n options: readonly T[],\n groupOf: ((option: T) => string) | null,\n idPrefix: string,\n): StarWindowLayout<T> {\n const rows: StarWindowRow<T>[] = [];\n const rowOfOption: number[] = [];\n let current: string | null = null;\n let groupId: string | null = null;\n let groupRow = -1;\n options.forEach((option, index) => {\n if (groupOf) {\n const label = groupOf(option);\n if (index === 0 || label !== current) {\n current = label;\n groupId = `${idPrefix}-group-${index}`;\n groupRow = rows.length;\n rows.push({ kind: 'group', key: `g:${index}`, label, id: groupId });\n }\n }\n rowOfOption.push(rows.length);\n rows.push({ kind: 'option', key: `o:${index}`, option, index, groupId, groupRow });\n });\n return { rows, rowOfOption };\n}\n\n/** Number of options a Page up / Page down key moves: the lines in view, minus one for overlap. */\nexport function starListPageSize(viewportHeight: number, itemSize: number): number {\n const lines = Math.floor(viewportHeight / Math.max(1, itemSize));\n return Math.max(1, lines - 1);\n}\n\nexport type StarListNavigationKey =\n 'ArrowDown' | 'ArrowUp' | 'Home' | 'End' | 'PageDown' | 'PageUp';\n\n/** Index of the option a navigation key moves to, limited to the list. -1 for an empty list. */\nexport function starListKeyboardTarget(\n key: StarListNavigationKey,\n active: number,\n count: number,\n page: number,\n): number {\n if (count <= 0) return -1;\n const last = count - 1;\n let target: number;\n switch (key) {\n case 'ArrowDown':\n target = active + 1;\n break;\n case 'ArrowUp':\n target = active - 1;\n break;\n case 'Home':\n target = 0;\n break;\n case 'End':\n target = last;\n break;\n case 'PageDown':\n target = (active < 0 ? 0 : active) + page;\n break;\n case 'PageUp':\n target = (active < 0 ? last : active) - page;\n break;\n }\n return Math.min(Math.max(target, 0), last);\n}\n\n/** Index of the first option whose label starts with the typed text (compared in lower case). */\nexport function starListTypeaheadIndex(\n count: number,\n labelAt: (index: number) => string,\n typed: string,\n): number {\n for (let i = 0; i < count; i++) {\n if (labelAt(i).toLowerCase().startsWith(typed)) return i;\n }\n return -1;\n}\n\n/** First and last row to bring into view for an option: its heading row comes with the first option. */\nexport function starListRevealRows<T>(\n layout: StarWindowLayout<T>,\n index: number,\n): [number, number] {\n const row = layout.rowOfOption[index];\n if (row === undefined) return [0, 0];\n const above = layout.rows[row - 1];\n return [above?.kind === 'group' ? row - 1 : row, row];\n}\n\n/**\n * Scroll offset that brings rows `first` to `last` into view with the least movement, or null when\n * they are in view. Rows have the height `itemSize`. `inset` is the space above the first row\n * (the padding of the scroll container): a row below the view is moved by it, and the first row\n * scrolls to the very top so that the padding shows.\n */\nexport function starListRevealOffset(\n first: number,\n last: number,\n itemSize: number,\n scrollOffset: number,\n viewportHeight: number,\n inset = 0,\n): number | null {\n const top = inset + first * itemSize;\n const bottom = inset + (last + 1) * itemSize;\n if (top < scrollOffset) return first === 0 ? 0 : top;\n if (viewportHeight > 0 && bottom > scrollOffset + viewportHeight) return bottom - viewportHeight;\n return null;\n}\n\n/** `aria-setsize` and `aria-posinset` of an option, for the whole list. */\nexport function starListAriaPosition(\n index: number,\n count: number,\n): { setsize: number; posinset: number } {\n return { setsize: count, posinset: index + 1 };\n}\n\n/** CSS height of the list: `scrollHeight` at most, and no taller than the rows need. */\nexport function starListHeight(scrollHeight: string, rowCount: number, itemSize: number): string {\n return `min(${scrollHeight}, ${rowCount * Math.max(1, itemSize)}px)`;\n}\n\n/** True when a row is inside the rendered range `[start, end)`. */\nexport function starListRowRendered(row: number, range: { start: number; end: number }): boolean {\n return row >= range.start && row < range.end;\n}\n","/**\n * How a list control reads a property from an option: a property name or an accessor function.\n * Same idea as PrimeNG `optionLabel` / `optionValue` / `optionDisabled`, but type safe.\n */\nexport type StarOptionKey<T, R = unknown> = (keyof T & string) | ((option: T) => R);\n\nexport type StarSeverity = 'primary' | 'secondary' | 'success' | 'info' | 'warn' | 'danger';\n\nexport type StarSize = 'sm' | 'md' | 'lg';\n\nexport function readOption<T, R>(option: T, key: StarOptionKey<T, R> | null | undefined): unknown {\n if (key === null || key === undefined) return option;\n if (typeof key === 'function') return key(option);\n return option !== null && typeof option === 'object'\n ? (option as Record<string, unknown>)[key]\n : undefined;\n}\n\n/** Text shown for an option. Falls back to the option itself for primitive options. */\nexport function optionText<T>(option: T, key: StarOptionKey<T> | null | undefined): string {\n const value = readOption(option, key ?? null);\n return value === null || value === undefined ? '' : String(value);\n}\n\nconst collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });\n\n/** Locale-aware compare used by sorting: numbers and dates numerically, text with Intl.Collator. */\nexport function compareValues(a: unknown, b: unknown): number {\n const aEmpty = a === null || a === undefined;\n const bEmpty = b === null || b === undefined;\n if (aEmpty && bEmpty) return 0;\n if (aEmpty) return -1;\n if (bEmpty) return 1;\n if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();\n if (typeof a === 'number' && typeof b === 'number') return a - b;\n return collator.compare(String(a), String(b));\n}\n\n/** Case- and accent-insensitive \"contains\" match used by filters. */\nexport function matchesFilter(text: string, query: string): boolean {\n if (!query) return true;\n const normalize = (value: string) =>\n value\n .normalize('NFD')\n .replace(/\\p{Diacritic}/gu, '')\n .toLocaleLowerCase();\n return normalize(text).includes(normalize(query.trim()));\n}\n","import { effect, EffectRef, inject, Injector, untracked } from '@angular/core';\nimport { AbstractControl, FormArray, FormGroup } from '@angular/forms';\nimport { SignalFormControl } from '@angular/forms/signals/compat';\n\nfunction signalControls(control: AbstractControl): SignalFormControl<unknown>[] {\n if (control instanceof SignalFormControl) return [control as SignalFormControl<unknown>];\n if (control instanceof FormGroup || control instanceof FormArray) {\n return Object.values(control.controls).flatMap(signalControls);\n }\n return [];\n}\n\n/**\n * Keeps a Reactive `FormGroup` (or `FormArray`) in step with the `SignalFormControl`s inside it.\n *\n * Angular 22 updates a parent group when a `SignalFormControl` value changes, but not when a\n * Signal Forms rule (for example `disabled({ when })` or a conditional `required`) changes the\n * child's status without a value change. The group then reports a stale `valid` / `status`.\n * This effect watches every signal control's validity, disabled and pending state and calls\n * `updateValueAndValidity()` on the group when one changes.\n *\n * Call it in an injection context (a field initializer or constructor):\n * ```ts\n * readonly form = new FormGroup({ country: new SignalFormControl<string | null>(null, rules) });\n * private readonly sync = syncSignalFormControls(this.form);\n * ```\n */\nexport function syncSignalFormControls(\n group: FormGroup | FormArray,\n injector: Injector = inject(Injector),\n): EffectRef {\n const controls = signalControls(group);\n return effect(\n () => {\n for (const control of controls) {\n const state = control.fieldTree();\n state.valid();\n state.disabled();\n state.pending();\n }\n untracked(() => group.updateValueAndValidity());\n },\n { injector },\n );\n}\n","import { InjectionToken, Provider } from '@angular/core';\n\n/**\n * Built-in texts of the StarNG UI controls (screen-reader labels, empty states, reports).\n * Defaults are English. Override them once at app level:\n * - `provideStarUiTextFromTransloco()` reads them from the active Transloco language (`ui.*` keys)\n * and updates the controls live when the language changes.\n * - `provideStarUiText({...})` sets fixed texts.\n *\n * Function entries take values (for example a count) and return the full sentence, so word order\n * can change per language. Their parameter names are listed in `STAR_UI_TEXT_PARAMS`.\n */\nexport interface StarUiText {\n // General\n readonly close: string;\n readonly clear: string;\n readonly loading: string;\n readonly actions: string;\n readonly moreActions: string;\n readonly ofTotal: (index: number, total: number) => string;\n readonly expandItem: (label: string) => string;\n readonly collapseItem: (label: string) => string;\n readonly removeItem: (label: string) => string;\n // Tags field\n readonly tagsHint: string;\n readonly tagAdded: (label: string) => string;\n readonly tagRemoved: (label: string) => string;\n readonly tagInvalid: (label: string) => string;\n readonly tagDuplicate: (label: string) => string;\n readonly tagLimit: (max: number) => string;\n readonly notifications: string;\n readonly accept: string;\n readonly reject: string;\n // Select, listbox, autocomplete\n readonly selectPlaceholder: string;\n readonly filterPlaceholder: string;\n readonly emptyMessage: string;\n readonly emptyFilterMessage: string;\n readonly selectAll: string;\n readonly selectedItems: (count: number) => string;\n readonly searching: string;\n readonly showOptions: string;\n readonly resultsAvailable: (count: number) => string;\n // Table, paginator, data view\n readonly pagination: string;\n readonly firstPage: string;\n readonly previousPage: string;\n readonly nextPage: string;\n readonly lastPage: string;\n readonly page: (page: number) => string;\n readonly rowsPerPage: string;\n readonly pageReport: (first: number, last: number, total: number) => string;\n readonly noData: string;\n readonly selectRow: string;\n readonly selectAllRows: string;\n readonly filterBy: (column: string) => string;\n readonly filterAll: string;\n readonly filterMin: (column: string) => string;\n readonly filterMax: (column: string) => string;\n readonly filterMinShort: string;\n readonly filterMaxShort: string;\n readonly expandRow: string;\n readonly collapseRow: string;\n readonly rowDetails: string;\n readonly reorderRows: string;\n readonly sortMultiHint: string;\n readonly terminalCommand: string;\n readonly compareImages: string;\n readonly editCell: (column: string) => string;\n readonly columns: string;\n readonly resizeColumn: (column: string) => string;\n readonly moveColumnEarlier: (column: string) => string;\n readonly moveColumnLater: (column: string) => string;\n readonly layout: string;\n readonly layoutList: string;\n readonly layoutGrid: string;\n // Order list, pick list\n readonly moveSelectedItem: string;\n readonly orderListHint: string;\n readonly moveTop: string;\n readonly moveUp: string;\n readonly moveDown: string;\n readonly moveBottom: string;\n readonly itemPosition: (label: string, position: number, total: number) => string;\n readonly transfer: string;\n readonly moveSelectedToTarget: string;\n readonly moveAllToTarget: string;\n readonly moveSelectedToSource: string;\n readonly moveAllToSource: string;\n readonly pickListSource: string;\n readonly pickListTarget: string;\n // Dates\n readonly chooseDate: string;\n readonly chooseMonth: string;\n readonly chooseYear: string;\n readonly previousMonth: string;\n readonly nextMonth: string;\n readonly previousYears: string;\n readonly nextYears: string;\n readonly today: string;\n readonly time: string;\n readonly startTime: string;\n readonly weekNumber: string;\n readonly weekShort: string;\n readonly endTime: string;\n readonly done: string;\n // Inputs\n readonly increase: string;\n readonly decrease: string;\n readonly showPassword: string;\n readonly hidePassword: string;\n readonly passwordWeak: string;\n readonly passwordFair: string;\n readonly passwordGood: string;\n readonly passwordStrong: string;\n readonly passwordRuleLength: (min: number) => string;\n readonly passwordRuleUpper: string;\n readonly passwordRuleLower: string;\n readonly passwordRuleNumber: string;\n readonly passwordRuleSymbol: string;\n readonly ruleMet: string;\n readonly ruleNotMet: string;\n readonly otpLabel: string;\n readonly otpCharacter: (position: number, total: number) => string;\n readonly ratingLabel: string;\n readonly sliderMinimum: (label: string) => string;\n readonly sliderMaximum: (label: string) => string;\n readonly colorLabel: string;\n readonly customColor: string;\n readonly hexValue: (label: string) => string;\n // File upload\n readonly chooseFiles: string;\n readonly dropFiles: string;\n readonly fileMaxSize: (size: string) => string;\n readonly fileUpTo: (count: number) => string;\n readonly uploadingFile: (name: string) => string;\n readonly uploaded: string;\n readonly fileTypeNotAllowed: (name: string) => string;\n readonly fileTooLarge: (name: string, max: string) => string;\n readonly fileLimitReached: (limit: number) => string;\n // Editor\n readonly editorLabel: string;\n readonly editorFormatting: (label: string) => string;\n readonly editorBold: string;\n readonly editorItalic: string;\n readonly editorUnderline: string;\n readonly editorHeading: string;\n readonly editorBulletList: string;\n readonly editorNumberedList: string;\n readonly editorClearFormatting: string;\n readonly editorLink: string;\n readonly editorLinkPrompt: string;\n // Navigation and layout\n readonly breadcrumb: string;\n readonly stepperLabel: string;\n readonly stepCompleted: string;\n readonly resizePanes: string;\n readonly dock: string;\n readonly scrollToTop: string;\n readonly theme: string;\n readonly themeSystem: string;\n readonly themeLight: string;\n readonly themeDark: string;\n // Media\n readonly pauseSlides: string;\n readonly playSlides: string;\n readonly previousSlides: string;\n readonly nextSlides: string;\n readonly galleryLabel: string;\n readonly previousImage: string;\n readonly nextImage: string;\n readonly showImage: (alt: string) => string;\n readonly previewImage: (alt: string) => string;\n readonly zoomIn: string;\n readonly zoomOut: string;\n // Charts and meters\n readonly chartView: string;\n readonly tableView: string;\n readonly chartTotal: string;\n readonly chartOther: string;\n readonly chartCategory: string;\n readonly chartValue: string;\n readonly chartShare: string;\n readonly chartSeries: string;\n readonly chartX: string;\n readonly chartY: string;\n readonly chartTypeBar: string;\n readonly chartTypeStackedBar: string;\n readonly chartTypeLine: string;\n readonly chartTypeArea: string;\n readonly chartTypeDoughnut: string;\n readonly chartTypePie: string;\n readonly chartTypeRadar: string;\n readonly chartTypePolarArea: string;\n readonly chartTypeScatter: string;\n readonly chartDescription: (\n kind: string,\n series: number,\n items: number,\n min: string,\n max: string,\n ) => string;\n readonly meterValue: (value: string, total: number) => string;\n}\n\nexport const STAR_UI_TEXT_DEFAULTS: StarUiText = {\n close: 'Close',\n clear: 'Clear',\n loading: 'Loading',\n actions: 'Actions',\n moreActions: 'More actions',\n ofTotal: (index, total) => `${index} of ${total}`,\n expandItem: (label) => `Expand ${label}`,\n collapseItem: (label) => `Collapse ${label}`,\n removeItem: (label) => `Remove ${label}`,\n tagsHint: 'Press Enter or comma to add. Backspace removes the last item.',\n tagAdded: (label) => `${label} added`,\n tagRemoved: (label) => `${label} removed`,\n tagInvalid: (label) => `${label} is not valid.`,\n tagDuplicate: (label) => `${label} is already added.`,\n tagLimit: (max) => `You can add up to ${max} items.`,\n notifications: 'Notifications',\n accept: 'Confirm',\n reject: 'Cancel',\n\n selectPlaceholder: 'Select',\n filterPlaceholder: 'Search',\n emptyMessage: 'No options available',\n emptyFilterMessage: 'No results found',\n selectAll: 'Select all',\n selectedItems: (count) => `${count} items selected`,\n searching: 'Searching…',\n showOptions: 'Show options',\n resultsAvailable: (count) => (count === 1 ? '1 result available' : `${count} results available`),\n\n pagination: 'Pagination',\n firstPage: 'First page',\n previousPage: 'Previous page',\n nextPage: 'Next page',\n lastPage: 'Last page',\n page: (page) => `Page ${page}`,\n rowsPerPage: 'Rows per page',\n pageReport: (first, last, total) => `${first}–${last} of ${total}`,\n noData: 'No records found',\n selectRow: 'Select row',\n selectAllRows: 'Select all rows',\n filterBy: (column) => `Filter by ${column}`,\n filterAll: 'All',\n filterMin: (column) => `${column} from`,\n filterMax: (column) => `${column} to`,\n filterMinShort: 'Min',\n filterMaxShort: 'Max',\n expandRow: 'Expand row',\n collapseRow: 'Collapse row',\n rowDetails: 'Details',\n reorderRows: 'Order',\n sortMultiHint: 'Shift + click adds this column to the sort',\n terminalCommand: 'Command',\n compareImages: 'Compare images',\n editCell: (column) => `Edit ${column}`,\n columns: 'Columns',\n resizeColumn: (column) => `Resize ${column}`,\n moveColumnEarlier: (column) => `Move ${column} earlier`,\n moveColumnLater: (column) => `Move ${column} later`,\n layout: 'Layout',\n layoutList: 'List',\n layoutGrid: 'Grid',\n\n moveSelectedItem: 'Move selected item',\n orderListHint: 'Use Alt and the arrow keys to move the selected item.',\n moveTop: 'Move to top',\n moveUp: 'Move up',\n moveDown: 'Move down',\n moveBottom: 'Move to bottom',\n itemPosition: (label, position, total) => `${label}, position ${position} of ${total}`,\n transfer: 'Transfer',\n moveSelectedToTarget: 'Move selected to target',\n moveAllToTarget: 'Move all to target',\n moveSelectedToSource: 'Move selected to source',\n moveAllToSource: 'Move all to source',\n pickListSource: 'Available',\n pickListTarget: 'Selected',\n\n chooseDate: 'Choose date',\n chooseMonth: 'Choose month',\n chooseYear: 'Choose year',\n previousMonth: 'Previous month',\n nextMonth: 'Next month',\n previousYears: 'Previous years',\n nextYears: 'Next years',\n today: 'Today',\n time: 'Time',\n startTime: 'Start time',\n weekNumber: 'Week number',\n weekShort: 'Wk',\n endTime: 'End time',\n done: 'Done',\n\n increase: 'Increase',\n decrease: 'Decrease',\n showPassword: 'Show password',\n hidePassword: 'Hide password',\n passwordWeak: 'Password strength: weak',\n passwordFair: 'Password strength: fair',\n passwordGood: 'Password strength: good',\n passwordStrong: 'Password strength: strong',\n passwordRuleLength: (min) => `At least ${min} characters`,\n passwordRuleUpper: 'An uppercase letter',\n passwordRuleLower: 'A lowercase letter',\n passwordRuleNumber: 'A number',\n passwordRuleSymbol: 'A symbol',\n ruleMet: 'met',\n ruleNotMet: 'not met',\n otpLabel: 'Verification code',\n otpCharacter: (position, total) => `Character ${position} of ${total}`,\n ratingLabel: 'Rating',\n sliderMinimum: (label) => `${label} minimum`.trim(),\n sliderMaximum: (label) => `${label} maximum`.trim(),\n colorLabel: 'Color',\n customColor: 'Custom color',\n hexValue: (label) => `${label} hex value`,\n\n chooseFiles: 'Choose files',\n dropFiles: 'Drag files here, or',\n fileMaxSize: (size) => `max ${size}`,\n fileUpTo: (count) => `up to ${count} files`,\n uploadingFile: (name) => `Uploading ${name}`,\n uploaded: 'Uploaded',\n fileTypeNotAllowed: (name) => `${name}: this file type is not allowed.`,\n fileTooLarge: (name, max) => `${name}: the file is larger than ${max}.`,\n fileLimitReached: (limit) => `You can add up to ${limit} files.`,\n\n editorLabel: 'Editor',\n editorFormatting: (label) => `${label} formatting`,\n editorBold: 'Bold',\n editorItalic: 'Italic',\n editorUnderline: 'Underline',\n editorHeading: 'Heading',\n editorBulletList: 'Bulleted list',\n editorNumberedList: 'Numbered list',\n editorClearFormatting: 'Clear formatting',\n editorLink: 'Link',\n editorLinkPrompt: 'Link address (https://…)',\n\n breadcrumb: 'Breadcrumb',\n stepperLabel: 'Progress',\n stepCompleted: '(completed)',\n resizePanes: 'Resize panes',\n dock: 'Dock',\n scrollToTop: 'Scroll to top',\n theme: 'Theme',\n themeSystem: 'System',\n themeLight: 'Light',\n themeDark: 'Dark',\n\n pauseSlides: 'Pause slides',\n playSlides: 'Play slides',\n previousSlides: 'Previous slides',\n nextSlides: 'Next slides',\n galleryLabel: 'Gallery',\n previousImage: 'Previous image',\n nextImage: 'Next image',\n showImage: (alt) => `Show ${alt}`,\n previewImage: (alt) => `Preview: ${alt}`,\n zoomIn: 'Zoom in',\n zoomOut: 'Zoom out',\n\n chartView: 'Chart',\n tableView: 'Table',\n chartTotal: 'Total',\n chartOther: 'Other',\n chartCategory: 'Category',\n chartValue: 'Value',\n chartShare: 'Share',\n chartSeries: 'Series',\n chartX: 'X',\n chartY: 'Y',\n chartTypeBar: 'Bar chart',\n chartTypeStackedBar: 'Stacked bar chart',\n chartTypeLine: 'Line chart',\n chartTypeArea: 'Area chart',\n chartTypeDoughnut: 'Doughnut chart',\n chartTypePie: 'Pie chart',\n chartTypeRadar: 'Radar chart',\n chartTypePolarArea: 'Polar area chart',\n chartTypeScatter: 'Scatter chart',\n chartDescription: (kind, series, items, min, max) =>\n `${kind} with ${series} series and ${items} ${items === 1 ? 'item' : 'items'}, values from ${min} to ${max}. The same data is in the table.`,\n meterValue: (value, total) => `${value} of ${total}`,\n};\n\n/** Parameter names of the function entries, in call order (used for `{{ name }}` in translations). */\nexport const STAR_UI_TEXT_PARAMS: { readonly [K in keyof StarUiText]?: readonly string[] } = {\n ofTotal: ['index', 'total'],\n expandItem: ['label'],\n collapseItem: ['label'],\n removeItem: ['label'],\n tagAdded: ['label'],\n tagRemoved: ['label'],\n tagInvalid: ['label'],\n tagDuplicate: ['label'],\n tagLimit: ['max'],\n selectedItems: ['count'],\n resultsAvailable: ['count'],\n page: ['page'],\n pageReport: ['first', 'last', 'total'],\n filterBy: ['column'],\n filterMin: ['column'],\n filterMax: ['column'],\n editCell: ['column'],\n resizeColumn: ['column'],\n moveColumnEarlier: ['column'],\n moveColumnLater: ['column'],\n itemPosition: ['label', 'position', 'total'],\n passwordRuleLength: ['min'],\n otpCharacter: ['position', 'total'],\n sliderMinimum: ['label'],\n sliderMaximum: ['label'],\n hexValue: ['label'],\n fileMaxSize: ['size'],\n fileUpTo: ['count'],\n uploadingFile: ['name'],\n fileTypeNotAllowed: ['name'],\n fileTooLarge: ['name', 'max'],\n fileLimitReached: ['limit'],\n editorFormatting: ['label'],\n showImage: ['alt'],\n previewImage: ['alt'],\n meterValue: ['value', 'total'],\n chartDescription: ['kind', 'series', 'items', 'min', 'max'],\n};\n\nexport const STAR_UI_TEXT = new InjectionToken<StarUiText>('STAR_UI_TEXT', {\n providedIn: 'root',\n factory: () => STAR_UI_TEXT_DEFAULTS,\n});\n\n/** Overrides some or all built-in control texts with fixed values. */\nexport function provideStarUiText(overrides: Partial<StarUiText>): Provider {\n return { provide: STAR_UI_TEXT, useValue: { ...STAR_UI_TEXT_DEFAULTS, ...overrides } };\n}\n\n/**\n * Builds a `StarUiText` whose entries read `source()` on every access. When `source` reads a\n * signal, every OnPush control that renders a built-in text updates when that signal changes.\n * Entries that `source()` does not return fall back to the English default.\n *\n * Use it in a factory when the signal lives in a service:\n * `{ provide: STAR_UI_TEXT, useFactory: () => starUiTextFromSignal(inject(Language).text) }`.\n */\nexport function starUiTextFromSignal(source: () => Partial<StarUiText>): StarUiText {\n const text = {} as Record<string, unknown>;\n for (const name of Object.keys(STAR_UI_TEXT_DEFAULTS) as (keyof StarUiText)[]) {\n if (typeof STAR_UI_TEXT_DEFAULTS[name] === 'function') {\n text[name] = (...args: unknown[]) => {\n const entry = (source()[name] ?? STAR_UI_TEXT_DEFAULTS[name]) as (\n ...a: unknown[]\n ) => string;\n return entry(...args);\n };\n } else {\n Object.defineProperty(text, name, {\n enumerable: true,\n get: () => source()[name] ?? STAR_UI_TEXT_DEFAULTS[name],\n });\n }\n }\n return text as unknown as StarUiText;\n}\n\n/**\n * Provides the control texts from a function that reads a signal, so the language can change at\n * run time without a translation library:\n *\n * ```ts\n * const language = signal<'en' | 'de'>('en');\n * provideStarUiTextFromSignal(() => (language() === 'de' ? STAR_UI_TEXT_DE : STAR_UI_TEXT_DEFAULTS));\n * ```\n *\n * Do not spread a pack with getters into an object (`{ ...text }`): that reads every getter once and\n * freezes the result. Pass a function, as shown above.\n */\nexport function provideStarUiTextFromSignal(source: () => Partial<StarUiText>): Provider {\n return { provide: STAR_UI_TEXT, useFactory: () => starUiTextFromSignal(source) };\n}\n"],"mappings":"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"}