diff --git a/src/app/components/autocomplete/autocomplete.css b/src/app/components/autocomplete/autocomplete.css
deleted file mode 100755
index aa8619eff26..00000000000
--- a/src/app/components/autocomplete/autocomplete.css
+++ /dev/null
@@ -1,104 +0,0 @@
-@layer primeng {
- .p-autocomplete {
- display: inline-flex;
- position: relative;
- }
-
- .p-autocomplete-loader {
- position: absolute;
- top: 50%;
- margin-top: -0.5rem;
- }
-
- .p-autocomplete-dd .p-autocomplete-input {
- flex: 1 1 auto;
- width: 1%;
- }
-
- .p-autocomplete-dd .p-autocomplete-input,
- .p-autocomplete-dd .p-autocomplete-multiple-container {
- border-top-right-radius: 0;
- border-bottom-right-radius: 0;
- }
-
- .p-autocomplete-dd .p-autocomplete-dropdown {
- border-top-left-radius: 0;
- border-bottom-left-radius: 0px;
- }
-
- .p-autocomplete-panel {
- overflow: auto;
- }
-
- .p-autocomplete-items {
- margin: 0;
- padding: 0;
- list-style-type: none;
- }
-
- .p-autocomplete-item {
- cursor: pointer;
- white-space: nowrap;
- position: relative;
- overflow: hidden;
- }
-
- .p-autocomplete-multiple-container {
- margin: 0;
- padding: 0;
- list-style-type: none;
- cursor: text;
- overflow: hidden;
- display: flex;
- align-items: center;
- flex-wrap: wrap;
- }
-
- .p-autocomplete-token {
- width: fit-content;
- cursor: default;
- display: inline-flex;
- align-items: center;
- flex: 0 0 auto;
- }
-
- .p-autocomplete-token-icon {
- display: flex;
- cursor: pointer;
- }
-
- .p-autocomplete-input-token {
- flex: 1 1 auto;
- display: inline-flex;
- }
-
- .p-autocomplete-input-token input {
- border: 0 none;
- outline: 0 none;
- background-color: transparent;
- margin: 0;
- padding: 0;
- box-shadow: none;
- border-radius: 0;
- width: 100%;
- }
-
- .p-fluid .p-autocomplete {
- display: flex;
- }
-
- .p-fluid .p-autocomplete-dd .p-autocomplete-input {
- width: 1%;
- }
-
- .p-autocomplete-clear-icon {
- position: absolute;
- top: 50%;
- margin-top: -0.5rem;
- cursor: pointer;
- }
-
- .p-autocomplete-clearable {
- position: relative;
- }
-}
diff --git a/src/app/components/autocomplete/autocomplete.ts b/src/app/components/autocomplete/autocomplete.ts
index 90ef3c12a23..eeecb7c3ba3 100755
--- a/src/app/components/autocomplete/autocomplete.ts
+++ b/src/app/components/autocomplete/autocomplete.ts
@@ -13,6 +13,7 @@ import {
ElementRef,
EventEmitter,
forwardRef,
+ inject,
Inject,
Input,
NgModule,
@@ -45,6 +46,8 @@ import { ChevronDownIcon } from 'primeng/icons/chevrondown';
import { Nullable, VoidListener } from 'primeng/ts-helpers';
import { AutoCompleteCompleteEvent, AutoCompleteDropdownClickEvent, AutoCompleteLazyLoadEvent, AutoCompleteSelectEvent, AutoCompleteUnselectEvent } from './autocomplete.interface';
import { ChipModule, ChipProps } from 'primeng/chip';
+import { AutoCompleteStyle } from './style/autocompletestyle';
+import { BaseComponent } from 'primeng/basecomponent';
export const AUTOCOMPLETE_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
@@ -58,14 +61,14 @@ export const AUTOCOMPLETE_VALUE_ACCESSOR: any = {
@Component({
selector: 'p-autoComplete',
template: `
-
+
`,
- host: {
- class: 'p-element p-inputwrapper',
- '[class.p-inputwrapper-filled]': 'filled',
- '[class.p-inputwrapper-focus]': '((focused && !disabled) || autofocus) || overlayVisible',
- '[class.p-autocomplete-clearable]': 'showClear && !disabled'
- },
- providers: [AUTOCOMPLETE_VALUE_ACCESSOR],
+ providers: [AUTOCOMPLETE_VALUE_ACCESSOR, AutoCompleteStyle],
changeDetection: ChangeDetectionStrategy.OnPush,
- encapsulation: ViewEncapsulation.None,
- styleUrls: ['./autocomplete.css']
+ encapsulation: ViewEncapsulation.None
})
-export class AutoComplete implements AfterViewChecked, AfterContentInit, OnDestroy, ControlValueAccessor {
+export class AutoComplete extends BaseComponent implements AfterViewChecked, AfterContentInit, OnDestroy, ControlValueAccessor {
/**
* Minimum number of characters to initiate a search.
* @group Props
@@ -629,6 +614,12 @@ export class AutoComplete implements AfterViewChecked, AfterContentInit, OnDestr
* @group Props
*/
@Input({ transform: booleanAttribute }) focusOnHover: boolean | undefined;
+ /**
+ * Whether typeahead is active or not.
+ * @defaultValue true
+ * @group Props
+ */
+ @Input({ transform: booleanAttribute }) typeahead: boolean = true;
/**
* Specifies the input variant of the component.
* @group Props
@@ -818,26 +809,37 @@ export class AutoComplete implements AfterViewChecked, AfterContentInit, OnDestr
get focusedOptionId() {
return this.focusedOptionIndex() !== -1 ? `${this.id}_${this.focusedOptionIndex()}` : null;
}
+ // host: {
+ // class: 'p-element p-inputwrapper',
+ // '[class.p-inputwrapper-filled]': 'filled',
+ // '[class.p-inputwrapper-focus]': '((focused && !disabled) || autofocus) || overlayVisible',
+ // '[class.p-autocomplete-clearable]': 'showClear && !disabled'
+ // },
+ _componentStyle = inject(AutoCompleteStyle);
- get containerClass() {
- return {
- 'p-autocomplete p-component p-inputwrapper': true,
- 'p-disabled': this.disabled,
- 'p-focus': this.focused,
- 'p-autocomplete-dd': this.dropdown,
- 'p-autocomplete-multiple': this.multiple,
- 'p-inputwrapper-focus': this.focused,
- 'p-overlay-open': this.overlayVisible
- };
+ get rootClass() {
+ return this._componentStyle.classes.root({ instance: this });
}
- get multiContainerClass() {
- return { 'p-autocomplete-multiple-container p-component p-inputtext': true, 'p-variant-filled': this.variant === 'filled' || this.config.inputStyle() === 'filled' };
+ get inputMultipleClass() {
+ return this._componentStyle.classes.inputMultiple({ instance: this });
}
+ chipItemClass(index) {
+ return this._componentStyle.classes.chipItem({ instance: this, i: index });
+ }
+
+ optionClass(option, i, scrollerOptions) {
+ return { 'p-autocomplete-option': true, 'p-autocomplete-option-selected': this.isSelected(option), 'p-focus': this.focusedOptionIndex() === this.getOptionIndex(i, scrollerOptions), 'p-disabled': this.isOptionDisabled(option) };
+ }
+
+ // get multiContainerClass() {
+ // return { 'p-autocomplete-multiple-container p-component p-inputtext': true, 'p-variant-filled': this.variant === 'filled' || this.config.inputStyle() === 'filled' };
+ // }
+
get panelClass() {
return {
- 'p-autocomplete-panel p-component': true,
+ 'p-autocomplete-overlay p-component': true,
'p-input-filled': this.config.inputStyle() === 'filled',
'p-ripple-disabled': this.config.ripple === false
};
@@ -890,21 +892,15 @@ export class AutoComplete implements AfterViewChecked, AfterContentInit, OnDestr
return typeof this.modelValue() === 'string' && this.optionValue;
}
- constructor(
- @Inject(DOCUMENT) private document: Document,
- public el: ElementRef,
- public renderer: Renderer2,
- public cd: ChangeDetectorRef,
- public config: PrimeNGConfig,
- public overlayService: OverlayService,
- private zone: NgZone
- ) {
+ constructor(public overlayService: OverlayService, private zone: NgZone) {
+ super();
effect(() => {
this.filled = ObjectUtils.isNotEmpty(this.modelValue());
});
}
ngOnInit() {
+ super.ngOnInit();
this.id = this.id || UniqueComponentId();
this.cd.detectChanges();
}
@@ -1105,34 +1101,36 @@ export class AutoComplete implements AfterViewChecked, AfterContentInit, OnDestr
}
onInput(event) {
- if (this.searchTimeout) {
- clearTimeout(this.searchTimeout);
- }
-
- let query = event.target.value;
- if (this.maxlength !== null) {
- query = query.split('').slice(0, this.maxlength).join('');
- }
+ if (this.typeahead) {
+ if (this.searchTimeout) {
+ clearTimeout(this.searchTimeout);
+ }
- if (!this.multiple && !this.forceSelection) {
- this.updateModel(query);
- }
+ let query = event.target.value;
+ if (this.maxlength !== null) {
+ query = query.split('').slice(0, this.maxlength).join('');
+ }
- if (query.length === 0 && !this.multiple) {
- this.onClear.emit();
+ if (!this.multiple && !this.forceSelection) {
+ this.updateModel(query);
+ }
- setTimeout(() => {
- this.hide();
- }, this.delay / 2);
- } else {
- if (query.length >= this.minLength) {
- this.focusedOptionIndex.set(-1);
+ if (query.length === 0 && !this.multiple) {
+ this.onClear.emit();
- this.searchTimeout = setTimeout(() => {
- this.search(event, query, 'input');
- }, this.delay);
+ setTimeout(() => {
+ this.hide();
+ }, this.delay / 2);
} else {
- this.hide();
+ if (query.length >= this.minLength) {
+ this.focusedOptionIndex.set(-1);
+
+ this.searchTimeout = setTimeout(() => {
+ this.search(event, query, 'input');
+ }, this.delay);
+ } else {
+ this.hide();
+ }
}
}
}
@@ -1381,6 +1379,12 @@ export class AutoComplete implements AfterViewChecked, AfterContentInit, OnDestr
}
onEnterKey(event) {
+ if (!this.typeahead) {
+ if (this.multiple) {
+ this.updateModel([...(this.modelValue() || []), event.target.value]);
+ this.inputEL.nativeElement.value = '';
+ }
+ }
if (!this.overlayVisible) {
this.onArrowDownKey(event);
} else {
@@ -1668,6 +1672,8 @@ export class AutoComplete implements AfterViewChecked, AfterContentInit, OnDestr
this.scrollHandler.destroy();
this.scrollHandler = null;
}
+
+ super.ngOnDestroy();
}
}
diff --git a/src/app/components/autocomplete/style/autocompletestyle.ts b/src/app/components/autocomplete/style/autocompletestyle.ts
new file mode 100644
index 00000000000..1bfa93fd4d4
--- /dev/null
+++ b/src/app/components/autocomplete/style/autocompletestyle.ts
@@ -0,0 +1,309 @@
+import { Injectable } from '@angular/core';
+import { BaseStyle } from 'primeng/base';
+import { ObjectUtils } from 'primeng/utils';
+
+const theme = ({ dt }) => `
+.p-autocomplete {
+ display: inline-flex;
+}
+
+.p-autocomplete-loader {
+ position: absolute;
+ top: 50%;
+ margin-top: -0.5rem;
+ right: ${dt('autocomplete.padding.x')};
+}
+
+.p-autocomplete:has(.p-autocomplete-dropdown) .p-autocomplete-loader {
+ right: calc(${dt('autocomplete.dropdown.width')} + ${dt('autocomplete.padding.x')});
+}
+
+.p-autocomplete:has(.p-autocomplete-dropdown) .p-autocomplete-input {
+ flex: 1 1 auto;
+ width: 1%;
+}
+
+.p-autocomplete:has(.p-autocomplete-dropdown) .p-autocomplete-input,
+.p-autocomplete:has(.p-autocomplete-dropdown) .p-autocomplete-input-multiple {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.p-autocomplete-dropdown {
+ cursor: pointer;
+ display: inline-flex;
+ cursor: pointer;
+ user-select: none;
+ align-items: center;
+ justify-content: center;
+ overflow: hidden;
+ position: relative;
+ width: ${dt('autocomplete.dropdown.width')};
+ border-top-right-radius: ${dt('autocomplete.dropdown.border.radius')};
+ border-bottom-right-radius: ${dt('autocomplete.dropdown.border.radius')};
+ background: ${dt('autocomplete.dropdown.background')};
+ border: 1px solid ${dt('autocomplete.dropdown.border.color')};
+ border-left: 0 none;
+ color: ${dt('autocomplete.dropdown.color')};
+ transition: background ${dt('autocomplete.transition.duration')}, color ${dt('autocomplete.transition.duration')}, border-color ${dt('autocomplete.transition.duration')}, outline-color ${dt('autocomplete.transition.duration')}, box-shadow ${dt(
+ 'autocomplete.transition.duration'
+)};
+ outline-color: transparent;
+}
+
+.p-autocomplete-dropdown:not(:disabled):hover {
+ background: ${dt('autocomplete.dropdown.hover.background')};
+ border-color: ${dt('autocomplete.dropdown.hover.border.color')};
+ color: ${dt('autocomplete.dropdown.hover.color')};
+}
+
+.p-autocomplete-dropdown:not(:disabled):active {
+ background: ${dt('autocomplete.dropdown.active.background')};
+ border-color: ${dt('autocomplete.dropdown.active.border.color')};
+ color: ${dt('autocomplete.dropdown.active.color')};
+}
+
+.p-autocomplete-dropdown:focus-visible {
+ box-shadow: ${dt('autocomplete.dropdown.focus.ring.shadow')};
+ outline: ${dt('autocomplete.dropdown.focus.ring.width')} ${dt('autocomplete.dropdown.focus.ring.style')} ${dt('autocomplete.dropdown.focus.ring.color')};
+ outline-offset: ${dt('autocomplete.dropdown.focus.ring.offset')};
+}
+
+.p-autocomplete .p-autocomplete-overlay {
+ min-width: 100%;
+}
+
+.p-autocomplete-overlay {
+ position: absolute;
+ overflow: auto;
+ top: 0;
+ left: 0;
+ background: ${dt('autocomplete.overlay.background')};
+ color: ${dt('autocomplete.overlay.color')};
+ border: 1px solid ${dt('autocomplete.overlay.border.color')};
+ border-radius: ${dt('autocomplete.overlay.border.radius')};
+ box-shadow: ${dt('autocomplete.overlay.shadow')};
+}
+
+.p-autocomplete-list {
+ margin: 0;
+ padding: 0;
+ list-style-type: none;
+ display: flex;
+ flex-direction: column;
+ gap: ${dt('autocomplete.list.gap')};
+ padding: ${dt('autocomplete.list.padding')};
+}
+
+.p-autocomplete-option {
+ cursor: pointer;
+ white-space: nowrap;
+ position: relative;
+ overflow: hidden;
+ display: flex;
+ align-items: center;
+ padding: ${dt('autocomplete.option.padding')};
+ border: 0 none;
+ color: ${dt('autocomplete.option.color')};
+ background: transparent;
+ transition: background ${dt('autocomplete.transition.duration')}, color ${dt('autocomplete.transition.duration')}, border-color ${dt('autocomplete.transition.duration')};
+ border-radius: ${dt('autocomplete.option.border.radius')};
+}
+
+.p-autocomplete-option:not(.p-autocomplete-option-selected):not(.p-disabled).p-focus {
+ background: ${dt('autocomplete.option.focus.background')};
+ color: ${dt('autocomplete.option.focus.color')};
+}
+
+.p-autocomplete-option-selected {
+ background: ${dt('autocomplete.option.selected.background')};
+ color: ${dt('autocomplete.option.selected.color')};
+}
+
+.p-autocomplete-option-selected.p-focus {
+ background: ${dt('autocomplete.option.selected.focus.background')};
+ color: ${dt('autocomplete.option.selected.focus.color')};
+}
+
+.p-autocomplete-option-group {
+ margin: 0;
+ padding: ${dt('autocomplete.option.group.padding')};
+ color: ${dt('autocomplete.option.group.color')};
+ background: ${dt('autocomplete.option.group.background')};
+ font-weight: ${dt('autocomplete.option.group.font.weight')};
+}
+
+.p-autocomplete-input-multiple {
+ margin: 0;
+ list-style-type: none;
+ cursor: text;
+ overflow: hidden;
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ padding: calc(${dt('autocomplete.padding.y')} / 2) ${dt('autocomplete.padding.x')};
+ gap: calc(${dt('autocomplete.padding.y')} / 2);
+ color: ${dt('autocomplete.color')};
+ background: ${dt('autocomplete.background')};
+ border: 1px solid ${dt('autocomplete.border.color')};
+ border-radius: ${dt('autocomplete.border.radius')};
+ width: 100%;
+ transition: background ${dt('autocomplete.transition.duration')}, color ${dt('autocomplete.transition.duration')}, border-color ${dt('autocomplete.transition.duration')}, outline-color ${dt('autocomplete.transition.duration')}, box-shadow ${dt(
+ 'autocomplete.transition.duration'
+)};
+ outline-color: transparent;
+ box-shadow: ${dt('autocomplete.shadow')};
+}
+
+.p-autocomplete:not(.p-disabled):hover .p-autocomplete-input-multiple {
+ border-color: ${dt('autocomplete.hover.border.color')};
+}
+
+.p-autocomplete:not(.p-disabled).p-focus .p-autocomplete-input-multiple {
+ border-color: ${dt('autocomplete.focus.border.color')};
+ box-shadow: ${dt('autocomplete.focus.ring.shadow')};
+ outline: ${dt('autocomplete.focus.ring.width')} ${dt('autocomplete.focus.ring.style')} ${dt('autocomplete.focus.ring.color')};
+ outline-offset: ${dt('autocomplete.focus.ring.offset')};
+}
+
+.p-variant-filled.p-autocomplete-input-multiple {
+ background: ${dt('autocomplete.filled.background')};
+}
+
+.p-autocomplete:not(.p-disabled).p-focus .p-variant-filled.p-autocomplete-input-multiple {
+ background: ${dt('autocomplete.filled.focus.background')};
+}
+
+.p-autocomplete.p-disabled .p-autocomplete-input-multiple {
+ opacity: 1;
+ background: ${dt('autocomplete.disabled.background')};
+ color: ${dt('autocomplete.disabled.color')};
+}
+
+.p-autocomplete-chip.p-chip {
+ padding-top: calc(${dt('autocomplete.padding.y')} / 2);
+ padding-bottom: calc(${dt('autocomplete.padding.y')} / 2);
+ border-radius: ${dt('autocomplete.chip.border.radius')};
+}
+
+.p-autocomplete-input-multiple:has(.p-autocomplete-chip) {
+ padding-left: calc(${dt('autocomplete.padding.y')} / 2);
+ padding-right: calc(${dt('autocomplete.padding.y')} / 2);
+}
+
+.p-autocomplete-chip-item.p-focus .p-autocomplete-chip {
+ background: ${dt('inputchips.chip.focus.background')};
+ color: ${dt('inputchips.chip.focus.color')};
+}
+
+.p-autocomplete-input-chip {
+ flex: 1 1 auto;
+ display: inline-flex;
+ padding-top: calc(${dt('autocomplete.padding.y')} / 2);
+ padding-bottom: calc(${dt('autocomplete.padding.y')} / 2);
+}
+
+.p-autocomplete-input-chip input {
+ border: 0 none;
+ outline: 0 none;
+ background: transparent;
+ margin: 0;
+ padding: 0;
+ box-shadow: none;
+ border-radius: 0;
+ width: 100%;
+ font-family: inherit;
+ font-feature-settings: inherit;
+ font-size: 1rem;
+ color: inherit;
+}
+
+.p-autocomplete-input-chip input::placeholder {
+ color: ${dt('autocomplete.placeholder.color')};
+}
+
+.p-autocomplete-empty-message {
+ padding: ${dt('autocomplete.empty.message.padding')};
+}
+
+.p-autocomplete-fluid {
+ display: flex;
+}
+
+.p-autocomplete-fluid:has(.p-autocomplete-dropdown) .p-autocomplete-input {
+ width: 1%;
+}
+
+/* For PrimeNG */
+p-autocomplete.ng-invalid.ng-dirty > .p-autocomplete.p-inputwrapper > .p-autocomplete-input.p-inputtext {
+ border-color: ${dt('autocomplete.invalid.border.color')};
+}
+
+p-autocomplete.ng-invalid.ng-dirty > .p-autocomplete.p-inputwrapper > .p-autocomplete-input-multiple {
+ border-color: ${dt('autocomplete.invalid.border.color')};
+}
+
+.p-autocomplete-clear-icon {
+ position: absolute;
+ top: 50%;
+ margin-top: -0.5rem;
+ cursor: pointer;
+ right: ${dt('autocomplete.padding.x')};
+ color: ${dt('autocomplete.dropdown.color')};
+}
+`;
+
+const inlineStyles = {
+ root: { position: 'relative' }
+};
+
+const classes = {
+ root: ({ instance }) => ({
+ 'p-autocomplete p-component p-inputwrapper': true,
+ 'p-disabled': instance.disabled,
+ 'p-focus': instance.focused,
+ 'p-inputwrapper-filled': instance.filled,
+ 'p-inputwrapper-focus': (instance.focused && !instance.disabled) || instance.autofocus || instance.overlayVisible,
+ 'p-autocomplete-open': instance.overlayVisible,
+ 'p-autocomplete-clearable': instance.showClear && !instance.disabled
+ // 'p-invalid': instance.invalid,
+ // 'p-autocomplete-fluid': instance.fluid
+ }),
+ pcInput: 'p-autocomplete-input',
+ inputMultiple: ({ instance }) => ({
+ 'p-autocomplete-input-multiple': true,
+ 'p-variant-filled': instance.variant ? instance.variant === 'filled' : instance.config.inputStyle() === 'filled'
+ }),
+ chipItem: ({ instance, i }) => [
+ 'p-autocomplete-chip-item',
+ {
+ 'p-focus': instance.focusedMultipleOptionIndex === i
+ }
+ ],
+ pcChip: 'p-autocomplete-chip',
+ chipIcon: 'p-autocomplete-chip-icon',
+ inputChip: 'p-autocomplete-input-chip',
+ loader: 'p-autocomplete-loader',
+ dropdown: 'p-autocomplete-dropdown',
+ overlay: 'p-autocomplete-overlay p-component',
+ list: 'p-autocomplete-list',
+ optionGroup: 'p-autocomplete-option-group',
+ option: ({ instance, option, i, getItemOptions }) => ({
+ 'p-autocomplete-option': true,
+ 'p-autocomplete-option-selected': instance.isSelected(option),
+ 'p-focus': instance.focusedOptionIndex === instance.getOptionIndex(i, getItemOptions),
+ 'p-disabled': instance.isOptionDisabled(option)
+ }),
+ emptyMessage: 'p-autocomplete-empty-message'
+};
+
+@Injectable()
+export class AutoCompleteStyle extends BaseStyle {
+ name = 'autocomplete';
+
+ theme = theme;
+
+ classes = classes;
+
+ inlineStyles = inlineStyles;
+}