Skip to content

Commit c3e673d

Browse files
authored
Merge branch 'ng-select:master' into master
2 parents 7995ffe + a20e5fb commit c3e673d

File tree

3 files changed

+158
-58
lines changed

3 files changed

+158
-58
lines changed

eslint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ module.exports = defineConfig([
3434
'@angular-eslint/no-output-rename': 'off',
3535
'@angular-eslint/no-output-native': 'off',
3636
'@angular-eslint/prefer-standalone': 'off',
37+
"@angular-eslint/no-input-rename": 'off',
3738
'@angular-eslint/component-selector': [
3839
'error',
3940
{

src/ng-select/lib/ng-select.component.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5505,7 +5505,7 @@ describe('User defined keyDown handler', () => {
55055505
};
55065506

55075507
it('should execute user function if any of defined keys was pressed', () => {
5508-
const spy = spyOn(fixture.componentInstance.select().keyDownFn[SIGNAL], 'value');
5508+
const spy = spyOn(fixture.componentInstance.select()._keyDownFn[SIGNAL], 'value');
55095509

55105510
expectSpyToBeCalledAfterKeyDown(spy, Object.keys(KeyCode).length);
55115511
});

src/ng-select/lib/ng-select.component.ts

Lines changed: 156 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
InjectionToken,
1818
Injector,
1919
input,
20+
linkedSignal,
2021
model,
2122
numberAttribute,
2223
OnChanges,
@@ -105,63 +106,161 @@ export class NgSelectComponent implements OnChanges, OnInit, AfterViewInit, Cont
105106

106107
// signals
107108
public readonly _disabled = signal<boolean>(false);
108-
// inputs
109-
readonly ariaLabelDropdown = input<string>(undefined);
110-
readonly ariaLabel = input<string | undefined>(undefined);
111-
readonly markFirst = input(true, { transform: booleanAttribute });
112-
readonly placeholder = input<string>(this.config.placeholder);
113-
readonly fixedPlaceholder = input<boolean>(true);
114-
readonly notFoundText = input<string>(undefined);
115-
readonly typeToSearchText = input<string>(undefined);
116-
readonly preventToggleOnRightClick = input<boolean>(false);
117-
readonly addTagText = input<string>(undefined);
118-
readonly loadingText = input<string>(undefined);
119-
readonly clearAllText = input<string>(undefined);
120-
readonly dropdownPosition = input<DropdownPosition>('auto');
121-
readonly appendTo = input<string>(undefined);
122-
readonly outsideClickEvent = input<'click' | 'mousedown'>(this.config.outsideClickEvent);
123-
readonly loading = input(false, { transform: booleanAttribute });
124-
readonly closeOnSelect = input(true, { transform: booleanAttribute });
125-
readonly hideSelected = input(false, { transform: booleanAttribute });
126-
readonly selectOnTab = input(false, { transform: booleanAttribute });
127-
readonly openOnEnter = input(undefined, { transform: booleanAttribute });
128-
readonly maxSelectedItems = input<number, unknown>(undefined, { transform: numberAttribute });
129-
readonly groupBy = input<string | ((value: any) => any)>(undefined);
130-
readonly groupValue = input<GroupValueFn>(undefined);
131-
readonly bufferAmount = input(4, { transform: numberAttribute });
132-
readonly virtualScroll = input<boolean, unknown>(undefined, { transform: booleanAttribute });
133-
readonly selectableGroup = input(false, { transform: booleanAttribute });
134-
readonly tabFocusOnClearButton = input<boolean | undefined>();
135-
readonly selectableGroupAsModel = input(true, { transform: booleanAttribute });
136-
readonly searchFn = input(null);
137-
readonly trackByFn = input(null);
138-
readonly clearOnBackspace = input(true, { transform: booleanAttribute });
139-
readonly labelForId = input(null);
140-
readonly inputAttrs = input<Record<string, string>>({});
141-
readonly tabIndex = input<number, unknown>(undefined, { transform: numberAttribute });
142-
readonly readonly = input(false, { transform: booleanAttribute });
143-
readonly searchWhileComposing = input(true, { transform: booleanAttribute });
144-
readonly minTermLength = input(0, { transform: numberAttribute });
145-
readonly editableSearchTerm = input(false, { transform: booleanAttribute });
146-
readonly ngClass = input(null);
147-
readonly typeahead = input<Subject<string>>(undefined);
148-
readonly multiple = input(false, { transform: booleanAttribute });
149-
readonly addTag = input<boolean | AddTagFn>(false);
150-
readonly searchable = input(true, { transform: booleanAttribute });
151-
readonly clearable = input(true, { transform: booleanAttribute });
152-
readonly clearKeepsDisabledOptions = input(true, { transform: booleanAttribute });
153-
readonly deselectOnClick = input<boolean>();
154-
readonly clearSearchOnAdd = input(undefined);
155-
readonly compareWith = input(undefined, {
109+
// inputs: underscored input() + alias + linkedSignal() for stable public names (back compat)
110+
readonly _ariaLabelDropdown = input<string>(undefined, { alias: 'ariaLabelDropdown' });
111+
readonly ariaLabelDropdown = linkedSignal(() => this._ariaLabelDropdown());
112+
113+
readonly _ariaLabel = input<string | undefined>(undefined, { alias: 'ariaLabel' });
114+
readonly ariaLabel = linkedSignal(() => this._ariaLabel());
115+
116+
readonly _markFirst = input(true, { alias: 'markFirst', transform: booleanAttribute });
117+
readonly markFirst = linkedSignal(() => this._markFirst());
118+
119+
readonly _placeholder = input<string>(this.config.placeholder, { alias: 'placeholder' });
120+
readonly placeholder = linkedSignal(() => this._placeholder());
121+
122+
readonly _fixedPlaceholder = input<boolean>(true, { alias: 'fixedPlaceholder' });
123+
readonly fixedPlaceholder = linkedSignal(() => this._fixedPlaceholder());
124+
125+
readonly _notFoundText = input<string>(undefined, { alias: 'notFoundText' });
126+
readonly notFoundText = linkedSignal(() => this._notFoundText());
127+
128+
readonly _typeToSearchText = input<string>(undefined, { alias: 'typeToSearchText' });
129+
readonly typeToSearchText = linkedSignal(() => this._typeToSearchText());
130+
131+
readonly _preventToggleOnRightClick = input<boolean>(false, { alias: 'preventToggleOnRightClick' });
132+
readonly preventToggleOnRightClick = linkedSignal(() => this._preventToggleOnRightClick());
133+
134+
readonly _addTagText = input<string>(undefined, { alias: 'addTagText' });
135+
readonly addTagText = linkedSignal(() => this._addTagText());
136+
137+
readonly _loadingText = input<string>(undefined, { alias: 'loadingText' });
138+
readonly loadingText = linkedSignal(() => this._loadingText());
139+
140+
readonly _clearAllText = input<string>(undefined, { alias: 'clearAllText' });
141+
readonly clearAllText = linkedSignal(() => this._clearAllText());
142+
143+
readonly _dropdownPosition = input<DropdownPosition>('auto', { alias: 'dropdownPosition' });
144+
readonly dropdownPosition = linkedSignal(() => this._dropdownPosition());
145+
146+
readonly _appendTo = input<string>(undefined, { alias: 'appendTo' });
147+
readonly appendTo = linkedSignal(() => this._appendTo());
148+
149+
readonly _outsideClickEvent = input<'click' | 'mousedown'>(this.config.outsideClickEvent, { alias: 'outsideClickEvent' });
150+
readonly outsideClickEvent = linkedSignal(() => this._outsideClickEvent());
151+
152+
readonly _loading = input(false, { alias: 'loading', transform: booleanAttribute });
153+
readonly loading = linkedSignal(() => this._loading());
154+
155+
readonly _closeOnSelect = input(true, { alias: 'closeOnSelect', transform: booleanAttribute });
156+
readonly closeOnSelect = linkedSignal(() => this._closeOnSelect());
157+
158+
readonly _hideSelected = input(false, { alias: 'hideSelected', transform: booleanAttribute });
159+
readonly hideSelected = linkedSignal(() => this._hideSelected());
160+
161+
readonly _selectOnTab = input(false, { alias: 'selectOnTab', transform: booleanAttribute });
162+
readonly selectOnTab = linkedSignal(() => this._selectOnTab());
163+
164+
readonly _openOnEnter = input(undefined, { alias: 'openOnEnter', transform: booleanAttribute });
165+
readonly openOnEnter = linkedSignal(() => this._openOnEnter());
166+
167+
readonly _maxSelectedItems = input<number, unknown>(undefined, { alias: 'maxSelectedItems', transform: numberAttribute });
168+
readonly maxSelectedItems = linkedSignal(() => this._maxSelectedItems());
169+
170+
readonly _groupBy = input<string | ((value: any) => any)>(undefined, { alias: 'groupBy' });
171+
readonly groupBy = linkedSignal(() => this._groupBy());
172+
173+
readonly _groupValue = input<GroupValueFn>(undefined, { alias: 'groupValue' });
174+
readonly groupValue = linkedSignal(() => this._groupValue());
175+
176+
readonly _bufferAmount = input(4, { alias: 'bufferAmount', transform: numberAttribute });
177+
readonly bufferAmount = linkedSignal(() => this._bufferAmount());
178+
179+
readonly _virtualScroll = input<boolean, unknown>(undefined, { alias: 'virtualScroll', transform: booleanAttribute });
180+
readonly virtualScroll = linkedSignal(() => this._virtualScroll());
181+
182+
readonly _selectableGroup = input(false, { alias: 'selectableGroup', transform: booleanAttribute });
183+
readonly selectableGroup = linkedSignal(() => this._selectableGroup());
184+
185+
readonly _tabFocusOnClearButton = input<boolean | undefined>(undefined, { alias: 'tabFocusOnClearButton' });
186+
readonly tabFocusOnClearButton = linkedSignal(() => this._tabFocusOnClearButton());
187+
188+
readonly _selectableGroupAsModel = input(true, { alias: 'selectableGroupAsModel', transform: booleanAttribute });
189+
readonly selectableGroupAsModel = linkedSignal(() => this._selectableGroupAsModel());
190+
191+
readonly _searchFn = input(null, { alias: 'searchFn' });
192+
readonly searchFn = linkedSignal(() => this._searchFn());
193+
194+
readonly _trackByFn = input(null, { alias: 'trackByFn' });
195+
readonly trackByFn = linkedSignal(() => this._trackByFn());
196+
197+
readonly _clearOnBackspace = input(true, { alias: 'clearOnBackspace', transform: booleanAttribute });
198+
readonly clearOnBackspace = linkedSignal(() => this._clearOnBackspace());
199+
200+
readonly _labelForId = input(null, { alias: 'labelForId' });
201+
readonly labelForId = linkedSignal(() => this._labelForId());
202+
203+
readonly _inputAttrs = input<Record<string, string>>({}, { alias: 'inputAttrs' });
204+
readonly inputAttrs = linkedSignal(() => this._inputAttrs());
205+
206+
readonly _tabIndex = input<number, unknown>(undefined, { alias: 'tabIndex', transform: numberAttribute });
207+
readonly tabIndex = linkedSignal(() => this._tabIndex());
208+
209+
readonly _readonly = input(false, { alias: 'readonly', transform: booleanAttribute });
210+
readonly readonly = linkedSignal(() => this._readonly());
211+
212+
readonly _searchWhileComposing = input(true, { alias: 'searchWhileComposing', transform: booleanAttribute });
213+
readonly searchWhileComposing = linkedSignal(() => this._searchWhileComposing());
214+
215+
readonly _minTermLength = input(0, { alias: 'minTermLength', transform: numberAttribute });
216+
readonly minTermLength = linkedSignal(() => this._minTermLength());
217+
218+
readonly _editableSearchTerm = input(false, { alias: 'editableSearchTerm', transform: booleanAttribute });
219+
readonly editableSearchTerm = linkedSignal(() => this._editableSearchTerm());
220+
221+
readonly _ngClass = input(null, { alias: 'ngClass' });
222+
readonly ngClass = linkedSignal(() => this._ngClass());
223+
224+
readonly _typeahead = input<Subject<string>>(undefined, { alias: 'typeahead' });
225+
readonly typeahead = linkedSignal(() => this._typeahead());
226+
227+
readonly _multiple = input(false, { alias: 'multiple', transform: booleanAttribute });
228+
readonly multiple = linkedSignal(() => this._multiple());
229+
230+
readonly _addTag = input<boolean | AddTagFn>(false, { alias: 'addTag' });
231+
readonly addTag = linkedSignal(() => this._addTag());
232+
233+
readonly _searchable = input(true, { alias: 'searchable', transform: booleanAttribute });
234+
readonly searchable = linkedSignal(() => this._searchable());
235+
236+
readonly _clearable = input(true, { alias: 'clearable', transform: booleanAttribute });
237+
readonly clearable = linkedSignal(() => this._clearable());
238+
239+
readonly _clearKeepsDisabledOptions = input(true, { alias: 'clearKeepsDisabledOptions', transform: booleanAttribute });
240+
readonly clearKeepsDisabledOptions = linkedSignal(() => this._clearKeepsDisabledOptions());
241+
242+
readonly _deselectOnClick = input<boolean>(undefined, { alias: 'deselectOnClick' });
243+
readonly deselectOnClick = linkedSignal(() => this._deselectOnClick());
244+
245+
readonly _clearSearchOnAdd = input(undefined, { alias: 'clearSearchOnAdd' });
246+
readonly clearSearchOnAdd = linkedSignal(() => this._clearSearchOnAdd());
247+
248+
readonly _compareWith = input(undefined, {
249+
alias: 'compareWith',
156250
transform: (fn: CompareWithFn | undefined) => {
157251
if (fn !== undefined && fn !== null && !isFunction(fn)) {
158252
throw Error('`compareWith` must be a function.');
159253
}
160254
return fn;
161255
},
162256
});
163-
readonly keyDownFn = input<(_: KeyboardEvent) => boolean>((_: KeyboardEvent) => true);
164-
readonly popover = input(false, { transform: booleanAttribute });
257+
readonly compareWith = linkedSignal(() => this._compareWith());
258+
259+
readonly _keyDownFn = input<(_: KeyboardEvent) => boolean>((_: KeyboardEvent) => true, { alias: 'keyDownFn' });
260+
readonly keyDownFn = linkedSignal(() => this._keyDownFn());
261+
262+
readonly _popover = input(false, { alias: 'popover', transform: booleanAttribute });
263+
readonly popover = linkedSignal(() => this._popover());
165264

166265
// models
167266
readonly bindLabel = model<string>(undefined);
@@ -241,7 +340,7 @@ export class NgSelectComponent implements OnChanges, OnInit, AfterViewInit, Cont
241340
private readonly autoFocus = inject(new HostAttributeToken('autofocus'), { optional: true });
242341
// private variables
243342
private readonly _defaultLabel = 'label';
244-
private readonly _editableSearchTerm = computed(() => this.editableSearchTerm() && !this.multiple());
343+
private readonly _editableSearchTermActive = computed(() => this.editableSearchTerm() && !this.multiple());
245344
private _focused: boolean;
246345
private _injector = inject(Injector);
247346
private _isComposing = false;
@@ -482,7 +581,7 @@ export class NgSelectComponent implements OnChanges, OnInit, AfterViewInit, Cont
482581
writeValue(value: any | any[]): void {
483582
this.itemsList.clearSelected(false);
484583
this._handleWriteValue(value);
485-
if (this._editableSearchTerm()) {
584+
if (this._editableSearchTermActive()) {
486585
this._setSearchTermFromItems();
487586
}
488587
this._cd.markForCheck();
@@ -532,7 +631,7 @@ export class NgSelectComponent implements OnChanges, OnInit, AfterViewInit, Cont
532631
}
533632
this.isOpen.set(false);
534633
this._isComposing = false;
535-
if (!this._editableSearchTerm()) {
634+
if (!this._editableSearchTermActive()) {
536635
this._clearSearch();
537636
} else {
538637
this.itemsList.resetFilteredItems();
@@ -554,15 +653,15 @@ export class NgSelectComponent implements OnChanges, OnInit, AfterViewInit, Cont
554653
this.select(item);
555654
}
556655

557-
if (this._editableSearchTerm()) {
656+
if (this._editableSearchTermActive()) {
558657
this._setSearchTermFromItems();
559658
}
560659
}
561660

562661
select(item: NgOption) {
563662
if (!item.selected) {
564663
this.itemsList.select(item);
565-
if (this.clearSearchOnAddValue() && !this._editableSearchTerm()) {
664+
if (this.clearSearchOnAddValue() && !this._editableSearchTermActive()) {
566665
this._clearSearch();
567666
}
568667

@@ -688,7 +787,7 @@ export class NgSelectComponent implements OnChanges, OnInit, AfterViewInit, Cont
688787
return;
689788
}
690789

691-
if (this._editableSearchTerm()) {
790+
if (this._editableSearchTermActive()) {
692791
this._setSearchTermFromItems();
693792
}
694793

@@ -703,7 +802,7 @@ export class NgSelectComponent implements OnChanges, OnInit, AfterViewInit, Cont
703802
if (!this.isOpen() && !this.disabled()) {
704803
this._onTouched();
705804
}
706-
if (this._editableSearchTerm()) {
805+
if (this._editableSearchTermActive()) {
707806
this._setSearchTermFromItems();
708807
}
709808
this._focused = false;

0 commit comments

Comments
 (0)