codexly-ui 0.22.1 → 0.23.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/fesm2022/codexly-ui.mjs +256 -9
- package/fesm2022/codexly-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/codexly-ui.d.ts +78 -3
package/fesm2022/codexly-ui.mjs
CHANGED
|
@@ -19732,9 +19732,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
|
|
|
19732
19732
|
let _clxSearchIdCounter = 0;
|
|
19733
19733
|
/** Storefront search bar — same color/size/CVA conventions as ClxInputComponent, but styled as
|
|
19734
19734
|
* one continuous pill (input fused with a solid search button) rather than a bordered field with
|
|
19735
|
-
* a detached button, matching how e-commerce header search boxes are typically laid out.
|
|
19735
|
+
* a detached button, matching how e-commerce header search boxes are typically laid out.
|
|
19736
|
+
*
|
|
19737
|
+
* Optional autocomplete: the host listens to (queryChange) — the text, debounced, once it has
|
|
19738
|
+
* `minChars` — and feeds [suggestions] back (product rows with image and price, shortcuts, past
|
|
19739
|
+
* searches, a "¿Quisiste decir…?" correction, the result total). The panel opens under the bar,
|
|
19740
|
+
* supports ↑ ↓ Enter Esc, and reports picks through (suggestionSelect); Enter without a picked row,
|
|
19741
|
+
* the button, the correction and "Ver todos" emit (search). With [openOnFocus] the panel also shows
|
|
19742
|
+
* for an empty box (e.g. recent searches). */
|
|
19736
19743
|
class ClxSearchComponent {
|
|
19737
19744
|
_themeSvc = inject(ClxThemeService);
|
|
19745
|
+
_el = inject((ElementRef));
|
|
19746
|
+
_sso = inject(ScrollStrategyOptions);
|
|
19738
19747
|
color = input(undefined, ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
|
|
19739
19748
|
_color = computed(() => this.color() ?? this._themeSvc.config().primaryColor, ...(ngDevMode ? [{ debugName: "_color" }] : /* istanbul ignore next */ []));
|
|
19740
19749
|
/** Overrides only the search button's text color — see ClxButtonComponent's textColor input. */
|
|
@@ -19747,13 +19756,45 @@ class ClxSearchComponent {
|
|
|
19747
19756
|
value = input('', ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
19748
19757
|
/** Disabled state for standalone use (without FormControl) */
|
|
19749
19758
|
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
19759
|
+
/** Autocomplete content for the current text; null = no panel. */
|
|
19760
|
+
suggestions = input(null, ...(ngDevMode ? [{ debugName: "suggestions" }] : /* istanbul ignore next */ []));
|
|
19761
|
+
/** The host is fetching suggestions. */
|
|
19762
|
+
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
19763
|
+
/** (queryChange) waits this long after the last keystroke. */
|
|
19764
|
+
debounceMs = input(250, ...(ngDevMode ? [{ debugName: "debounceMs" }] : /* istanbul ignore next */ []));
|
|
19765
|
+
/** (queryChange) only from this many characters (0 = also for an empty box). */
|
|
19766
|
+
minChars = input(2, ...(ngDevMode ? [{ debugName: "minChars" }] : /* istanbul ignore next */ []));
|
|
19767
|
+
/** Show the panel when focusing an empty box (recent searches…). */
|
|
19768
|
+
openOnFocus = input(false, ...(ngDevMode ? [{ debugName: "openOnFocus" }] : /* istanbul ignore next */ []));
|
|
19750
19769
|
search = output();
|
|
19770
|
+
/** Debounced text for the host to fetch suggestions for ('' when cleared). */
|
|
19771
|
+
queryChange = output();
|
|
19772
|
+
suggestionSelect = output();
|
|
19751
19773
|
_inputId = `clx-search-${++_clxSearchIdCounter}`;
|
|
19752
19774
|
_value = signal('', ...(ngDevMode ? [{ debugName: "_value" }] : /* istanbul ignore next */ []));
|
|
19753
19775
|
_cvaDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_cvaDisabled" }] : /* istanbul ignore next */ []));
|
|
19754
19776
|
_cvaConnected = false;
|
|
19755
19777
|
_cardDisabled = inject(CLX_CARD_DISABLED_CONTEXT, { optional: true });
|
|
19778
|
+
_focused = signal(false, ...(ngDevMode ? [{ debugName: "_focused" }] : /* istanbul ignore next */ []));
|
|
19779
|
+
_dismissed = signal(false, ...(ngDevMode ? [{ debugName: "_dismissed" }] : /* istanbul ignore next */ []));
|
|
19780
|
+
_active = signal(null, ...(ngDevMode ? [{ debugName: "_active" }] : /* istanbul ignore next */ []));
|
|
19781
|
+
_panelWidth = signal(0, ...(ngDevMode ? [{ debugName: "_panelWidth" }] : /* istanbul ignore next */ []));
|
|
19782
|
+
_debounce;
|
|
19756
19783
|
_disabled = computed(() => this._cvaDisabled() || this.disabled() || !!this._cardDisabled?.(), ...(ngDevMode ? [{ debugName: "_disabled" }] : /* istanbul ignore next */ []));
|
|
19784
|
+
_scrollStrategy = this._sso.reposition();
|
|
19785
|
+
_positions = [
|
|
19786
|
+
{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 6 },
|
|
19787
|
+
];
|
|
19788
|
+
/** Flat list of the panel's rows, for ↑ ↓. */
|
|
19789
|
+
_rows = computed(() => (this.suggestions()?.groups ?? [])
|
|
19790
|
+
.flatMap(g => g.items.map(item => ({ group: g.key, item }))), ...(ngDevMode ? [{ debugName: "_rows" }] : /* istanbul ignore next */ []));
|
|
19791
|
+
_panelOpen = computed(() => {
|
|
19792
|
+
if (!this._focused() || this._dismissed() || this._disabled())
|
|
19793
|
+
return false;
|
|
19794
|
+
const s = this.suggestions();
|
|
19795
|
+
const hasContent = !!s && (!!s.correction || s.groups.some(g => g.items.length > 0));
|
|
19796
|
+
return hasContent && (this._value().trim().length > 0 || this.openOnFocus());
|
|
19797
|
+
}, ...(ngDevMode ? [{ debugName: "_panelOpen" }] : /* istanbul ignore next */ []));
|
|
19757
19798
|
_valueEffect = effect(() => {
|
|
19758
19799
|
const v = this.value();
|
|
19759
19800
|
if (!this._cvaConnected)
|
|
@@ -19761,6 +19802,9 @@ class ClxSearchComponent {
|
|
|
19761
19802
|
}, ...(ngDevMode ? [{ debugName: "_valueEffect" }] : /* istanbul ignore next */ []));
|
|
19762
19803
|
_onChange = () => { };
|
|
19763
19804
|
_onTouched = () => { };
|
|
19805
|
+
constructor() {
|
|
19806
|
+
inject(DestroyRef).onDestroy(() => clearTimeout(this._debounce));
|
|
19807
|
+
}
|
|
19764
19808
|
_sizeConfig = computed(() => INPUT_SIZE_MAP[this._size()], ...(ngDevMode ? [{ debugName: "_sizeConfig" }] : /* istanbul ignore next */ []));
|
|
19765
19809
|
_buttonSize = computed(() => {
|
|
19766
19810
|
switch (this._size()) {
|
|
@@ -19769,6 +19813,7 @@ class ClxSearchComponent {
|
|
|
19769
19813
|
default: return 'md';
|
|
19770
19814
|
}
|
|
19771
19815
|
}, ...(ngDevMode ? [{ debugName: "_buttonSize" }] : /* istanbul ignore next */ []));
|
|
19816
|
+
_accentText = computed(() => resolveColor(this._color()).textEmphasis, ...(ngDevMode ? [{ debugName: "_accentText" }] : /* istanbul ignore next */ []));
|
|
19772
19817
|
_wrapperClass = computed(() => {
|
|
19773
19818
|
const focusCls = this._disabled() ? '' : resolveColor(this._color()).focusWithin;
|
|
19774
19819
|
return `relative flex items-stretch ${resolveRadius(this._themeSvc.config().borderRadius)} border border-clx-border ${focusCls} overflow-hidden transition-[border-color,box-shadow] duration-200`;
|
|
@@ -19797,34 +19842,106 @@ class ClxSearchComponent {
|
|
|
19797
19842
|
const val = event.target.value;
|
|
19798
19843
|
this._value.set(val);
|
|
19799
19844
|
this._onChange(val);
|
|
19845
|
+
this._dismissed.set(false);
|
|
19846
|
+
this._active.set(null);
|
|
19847
|
+
this._emitQuery(val);
|
|
19848
|
+
}
|
|
19849
|
+
_handleFocus() {
|
|
19850
|
+
this._panelWidth.set(Math.round(this._el.nativeElement.getBoundingClientRect().width));
|
|
19851
|
+
this._focused.set(true);
|
|
19852
|
+
this._dismissed.set(false);
|
|
19853
|
+
if (this.openOnFocus() && !this._value().trim())
|
|
19854
|
+
this.queryChange.emit('');
|
|
19800
19855
|
}
|
|
19801
19856
|
_handleBlur() {
|
|
19802
19857
|
this._onTouched();
|
|
19858
|
+
this._focused.set(false);
|
|
19859
|
+
}
|
|
19860
|
+
_handleKeydown(event) {
|
|
19861
|
+
const rows = this._rows();
|
|
19862
|
+
if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
|
|
19863
|
+
if (!this._panelOpen() || !rows.length)
|
|
19864
|
+
return;
|
|
19865
|
+
event.preventDefault();
|
|
19866
|
+
const current = this._active();
|
|
19867
|
+
const index = current ? rows.findIndex(r => r.group === current.group && r.item.id === current.id) : -1;
|
|
19868
|
+
const next = event.key === 'ArrowDown'
|
|
19869
|
+
? (index + 1) % rows.length
|
|
19870
|
+
: (index <= 0 ? rows.length - 1 : index - 1);
|
|
19871
|
+
this._active.set({ group: rows[next].group, id: rows[next].item.id });
|
|
19872
|
+
}
|
|
19873
|
+
else if (event.key === 'Enter') {
|
|
19874
|
+
event.preventDefault();
|
|
19875
|
+
const current = this._active();
|
|
19876
|
+
const row = current && this._panelOpen()
|
|
19877
|
+
? rows.find(r => r.group === current.group && r.item.id === current.id)
|
|
19878
|
+
: undefined;
|
|
19879
|
+
if (row)
|
|
19880
|
+
this._select(row.group, row.item);
|
|
19881
|
+
else
|
|
19882
|
+
this._handleSubmit();
|
|
19883
|
+
}
|
|
19884
|
+
else if (event.key === 'Escape') {
|
|
19885
|
+
this._close();
|
|
19886
|
+
}
|
|
19887
|
+
}
|
|
19888
|
+
_isActive(group, item) {
|
|
19889
|
+
const a = this._active();
|
|
19890
|
+
return !!a && a.group === group && a.id === item.id;
|
|
19891
|
+
}
|
|
19892
|
+
_activate(group, item) {
|
|
19893
|
+
this._active.set({ group, id: item.id });
|
|
19894
|
+
}
|
|
19895
|
+
_select(group, item) {
|
|
19896
|
+
this._close();
|
|
19897
|
+
this.suggestionSelect.emit({ group, item });
|
|
19898
|
+
}
|
|
19899
|
+
_searchFor(text) {
|
|
19900
|
+
this._value.set(text);
|
|
19901
|
+
this._onChange(text);
|
|
19902
|
+
this._handleSubmit();
|
|
19903
|
+
}
|
|
19904
|
+
_close() {
|
|
19905
|
+
this._dismissed.set(true);
|
|
19906
|
+
this._active.set(null);
|
|
19803
19907
|
}
|
|
19804
19908
|
_handleSubmit() {
|
|
19805
19909
|
if (this._disabled())
|
|
19806
19910
|
return;
|
|
19911
|
+
this._close();
|
|
19912
|
+
clearTimeout(this._debounce);
|
|
19807
19913
|
this.search.emit(this._value());
|
|
19808
19914
|
}
|
|
19915
|
+
_emitQuery(val) {
|
|
19916
|
+
clearTimeout(this._debounce);
|
|
19917
|
+
const text = val.trim();
|
|
19918
|
+
if (text.length > 0 && text.length < this.minChars())
|
|
19919
|
+
return;
|
|
19920
|
+
this._debounce = setTimeout(() => this.queryChange.emit(text), text ? this.debounceMs() : 0);
|
|
19921
|
+
}
|
|
19809
19922
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxSearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
19810
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.
|
|
19923
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxSearchComponent, isStandalone: true, selector: "clx-search", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, buttonTextColor: { classPropertyName: "buttonTextColor", publicName: "buttonTextColor", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, buttonLabel: { classPropertyName: "buttonLabel", publicName: "buttonLabel", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, debounceMs: { classPropertyName: "debounceMs", publicName: "debounceMs", isSignal: true, isRequired: false, transformFunction: null }, minChars: { classPropertyName: "minChars", publicName: "minChars", isSignal: true, isRequired: false, transformFunction: null }, openOnFocus: { classPropertyName: "openOnFocus", publicName: "openOnFocus", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { search: "search", queryChange: "queryChange", suggestionSelect: "suggestionSelect" }, host: { classAttribute: "block w-full" }, providers: [
|
|
19811
19924
|
{
|
|
19812
19925
|
provide: NG_VALUE_ACCESSOR,
|
|
19813
19926
|
useExisting: forwardRef(() => ClxSearchComponent),
|
|
19814
19927
|
multi: true,
|
|
19815
19928
|
},
|
|
19816
19929
|
], ngImport: i0, template: `
|
|
19817
|
-
<div [class]="_wrapperClass()">
|
|
19930
|
+
<div [class]="_wrapperClass()" cdkOverlayOrigin #origin="cdkOverlayOrigin">
|
|
19818
19931
|
<input
|
|
19819
19932
|
[id]="_inputId"
|
|
19820
19933
|
type="search"
|
|
19934
|
+
role="combobox"
|
|
19935
|
+
[attr.aria-expanded]="_panelOpen()"
|
|
19936
|
+
[attr.aria-controls]="_inputId + '-panel'"
|
|
19821
19937
|
[placeholder]="placeholder()"
|
|
19822
19938
|
[disabled]="_disabled()"
|
|
19823
19939
|
[value]="_value()"
|
|
19824
19940
|
[class]="_inputClass()"
|
|
19825
19941
|
autocomplete="off"
|
|
19826
19942
|
(input)="_handleInput($event)"
|
|
19827
|
-
(
|
|
19943
|
+
(focus)="_handleFocus()"
|
|
19944
|
+
(keydown)="_handleKeydown($event)"
|
|
19828
19945
|
(blur)="_handleBlur()"
|
|
19829
19946
|
/>
|
|
19830
19947
|
<button
|
|
@@ -19841,14 +19958,77 @@ class ClxSearchComponent {
|
|
|
19841
19958
|
{{ buttonLabel() }}
|
|
19842
19959
|
</button>
|
|
19843
19960
|
</div>
|
|
19844
|
-
|
|
19961
|
+
|
|
19962
|
+
<ng-template
|
|
19963
|
+
cdkConnectedOverlay
|
|
19964
|
+
[cdkConnectedOverlayOrigin]="origin"
|
|
19965
|
+
[cdkConnectedOverlayOpen]="_panelOpen()"
|
|
19966
|
+
[cdkConnectedOverlayPositions]="_positions"
|
|
19967
|
+
[cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
|
|
19968
|
+
[cdkConnectedOverlayWidth]="_panelWidth()"
|
|
19969
|
+
[cdkConnectedOverlayPush]="true"
|
|
19970
|
+
(overlayOutsideClick)="_close()"
|
|
19971
|
+
(detach)="_close()">
|
|
19972
|
+
<div [id]="_inputId + '-panel'" role="listbox"
|
|
19973
|
+
class="w-full max-h-[70vh] overflow-y-auto bg-clx-surface rounded-xl shadow-xl border border-clx-border py-2"
|
|
19974
|
+
(mousedown)="$event.preventDefault()">
|
|
19975
|
+
@if (loading()) {
|
|
19976
|
+
<div class="flex items-center gap-2 px-4 py-2 text-xs text-clx-text-subtle">
|
|
19977
|
+
<clx-spinner size="xs" [color]="_color()" /> Buscando…
|
|
19978
|
+
</div>
|
|
19979
|
+
}
|
|
19980
|
+
@if (suggestions()?.correction; as correction) {
|
|
19981
|
+
<button type="button" class="w-full text-left px-4 py-2 text-sm text-clx-text-muted hover:bg-clx-surface-2"
|
|
19982
|
+
(click)="_searchFor(correction)">
|
|
19983
|
+
¿Quisiste decir <span class="font-semibold" [class]="_accentText()">{{ correction }}</span>?
|
|
19984
|
+
</button>
|
|
19985
|
+
}
|
|
19986
|
+
@for (group of suggestions()?.groups ?? []; track group.key) {
|
|
19987
|
+
@if (group.items.length) {
|
|
19988
|
+
<p class="px-4 pt-2 pb-1 text-[11px] font-semibold uppercase tracking-wide text-clx-text-subtle">{{ group.title }}</p>
|
|
19989
|
+
@for (item of group.items; track item.id) {
|
|
19990
|
+
<button type="button" role="option"
|
|
19991
|
+
[attr.aria-selected]="_isActive(group.key, item)"
|
|
19992
|
+
class="w-full flex items-center gap-3 px-4 py-2 text-left transition-colors"
|
|
19993
|
+
[class]="_isActive(group.key, item) ? 'bg-clx-surface-2' : 'hover:bg-clx-surface-2'"
|
|
19994
|
+
(mouseenter)="_activate(group.key, item)"
|
|
19995
|
+
(click)="_select(group.key, item)">
|
|
19996
|
+
@if (item.image) {
|
|
19997
|
+
<img [src]="item.image" [alt]="item.label" class="w-10 h-10 rounded-lg object-cover shrink-0 bg-clx-surface-2" />
|
|
19998
|
+
} @else if (item.icon) {
|
|
19999
|
+
<span class="w-8 h-8 rounded-lg bg-clx-surface-2 flex items-center justify-center shrink-0">
|
|
20000
|
+
<span clx-icon [name]="item.icon" size="sm" class="text-clx-text-muted"></span>
|
|
20001
|
+
</span>
|
|
20002
|
+
}
|
|
20003
|
+
<span class="flex-1 min-w-0">
|
|
20004
|
+
<span class="block text-sm text-clx-text-label truncate">{{ item.label }}</span>
|
|
20005
|
+
@if (item.sublabel) {
|
|
20006
|
+
<span class="block text-xs text-clx-text-subtle truncate">{{ item.sublabel }}</span>
|
|
20007
|
+
}
|
|
20008
|
+
</span>
|
|
20009
|
+
@if (item.meta) {
|
|
20010
|
+
<span class="text-sm font-semibold text-clx-text-label shrink-0">{{ item.meta }}</span>
|
|
20011
|
+
}
|
|
20012
|
+
</button>
|
|
20013
|
+
}
|
|
20014
|
+
}
|
|
20015
|
+
}
|
|
20016
|
+
@if (_value().trim() && suggestions()?.total) {
|
|
20017
|
+
<button type="button" class="w-full text-left px-4 pt-3 pb-1 text-sm font-semibold" [class]="_accentText()"
|
|
20018
|
+
(click)="_handleSubmit()">
|
|
20019
|
+
Ver los {{ suggestions()!.total }} resultados de “{{ _value().trim() }}”
|
|
20020
|
+
</button>
|
|
20021
|
+
}
|
|
20022
|
+
</div>
|
|
20023
|
+
</ng-template>
|
|
20024
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: ClxButtonComponent, selector: "button[clx-button], a[clx-button]", inputs: ["variant", "color", "emphasis", "textColor", "size", "shape", "loading", "disabled", "block", "icon", "iconPosition", "iconOnly", "badge", "badgeColor"] }, { kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxSpinnerComponent, selector: "clx-spinner", inputs: ["size", "color", "variant"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
19845
20025
|
}
|
|
19846
20026
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxSearchComponent, decorators: [{
|
|
19847
20027
|
type: Component,
|
|
19848
20028
|
args: [{
|
|
19849
20029
|
selector: 'clx-search',
|
|
19850
20030
|
standalone: true,
|
|
19851
|
-
imports: [ClxButtonComponent],
|
|
20031
|
+
imports: [OverlayModule, ClxButtonComponent, ClxIconComponent, ClxSpinnerComponent],
|
|
19852
20032
|
providers: [
|
|
19853
20033
|
{
|
|
19854
20034
|
provide: NG_VALUE_ACCESSOR,
|
|
@@ -19857,17 +20037,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
|
|
|
19857
20037
|
},
|
|
19858
20038
|
],
|
|
19859
20039
|
template: `
|
|
19860
|
-
<div [class]="_wrapperClass()">
|
|
20040
|
+
<div [class]="_wrapperClass()" cdkOverlayOrigin #origin="cdkOverlayOrigin">
|
|
19861
20041
|
<input
|
|
19862
20042
|
[id]="_inputId"
|
|
19863
20043
|
type="search"
|
|
20044
|
+
role="combobox"
|
|
20045
|
+
[attr.aria-expanded]="_panelOpen()"
|
|
20046
|
+
[attr.aria-controls]="_inputId + '-panel'"
|
|
19864
20047
|
[placeholder]="placeholder()"
|
|
19865
20048
|
[disabled]="_disabled()"
|
|
19866
20049
|
[value]="_value()"
|
|
19867
20050
|
[class]="_inputClass()"
|
|
19868
20051
|
autocomplete="off"
|
|
19869
20052
|
(input)="_handleInput($event)"
|
|
19870
|
-
(
|
|
20053
|
+
(focus)="_handleFocus()"
|
|
20054
|
+
(keydown)="_handleKeydown($event)"
|
|
19871
20055
|
(blur)="_handleBlur()"
|
|
19872
20056
|
/>
|
|
19873
20057
|
<button
|
|
@@ -19884,6 +20068,69 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
|
|
|
19884
20068
|
{{ buttonLabel() }}
|
|
19885
20069
|
</button>
|
|
19886
20070
|
</div>
|
|
20071
|
+
|
|
20072
|
+
<ng-template
|
|
20073
|
+
cdkConnectedOverlay
|
|
20074
|
+
[cdkConnectedOverlayOrigin]="origin"
|
|
20075
|
+
[cdkConnectedOverlayOpen]="_panelOpen()"
|
|
20076
|
+
[cdkConnectedOverlayPositions]="_positions"
|
|
20077
|
+
[cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
|
|
20078
|
+
[cdkConnectedOverlayWidth]="_panelWidth()"
|
|
20079
|
+
[cdkConnectedOverlayPush]="true"
|
|
20080
|
+
(overlayOutsideClick)="_close()"
|
|
20081
|
+
(detach)="_close()">
|
|
20082
|
+
<div [id]="_inputId + '-panel'" role="listbox"
|
|
20083
|
+
class="w-full max-h-[70vh] overflow-y-auto bg-clx-surface rounded-xl shadow-xl border border-clx-border py-2"
|
|
20084
|
+
(mousedown)="$event.preventDefault()">
|
|
20085
|
+
@if (loading()) {
|
|
20086
|
+
<div class="flex items-center gap-2 px-4 py-2 text-xs text-clx-text-subtle">
|
|
20087
|
+
<clx-spinner size="xs" [color]="_color()" /> Buscando…
|
|
20088
|
+
</div>
|
|
20089
|
+
}
|
|
20090
|
+
@if (suggestions()?.correction; as correction) {
|
|
20091
|
+
<button type="button" class="w-full text-left px-4 py-2 text-sm text-clx-text-muted hover:bg-clx-surface-2"
|
|
20092
|
+
(click)="_searchFor(correction)">
|
|
20093
|
+
¿Quisiste decir <span class="font-semibold" [class]="_accentText()">{{ correction }}</span>?
|
|
20094
|
+
</button>
|
|
20095
|
+
}
|
|
20096
|
+
@for (group of suggestions()?.groups ?? []; track group.key) {
|
|
20097
|
+
@if (group.items.length) {
|
|
20098
|
+
<p class="px-4 pt-2 pb-1 text-[11px] font-semibold uppercase tracking-wide text-clx-text-subtle">{{ group.title }}</p>
|
|
20099
|
+
@for (item of group.items; track item.id) {
|
|
20100
|
+
<button type="button" role="option"
|
|
20101
|
+
[attr.aria-selected]="_isActive(group.key, item)"
|
|
20102
|
+
class="w-full flex items-center gap-3 px-4 py-2 text-left transition-colors"
|
|
20103
|
+
[class]="_isActive(group.key, item) ? 'bg-clx-surface-2' : 'hover:bg-clx-surface-2'"
|
|
20104
|
+
(mouseenter)="_activate(group.key, item)"
|
|
20105
|
+
(click)="_select(group.key, item)">
|
|
20106
|
+
@if (item.image) {
|
|
20107
|
+
<img [src]="item.image" [alt]="item.label" class="w-10 h-10 rounded-lg object-cover shrink-0 bg-clx-surface-2" />
|
|
20108
|
+
} @else if (item.icon) {
|
|
20109
|
+
<span class="w-8 h-8 rounded-lg bg-clx-surface-2 flex items-center justify-center shrink-0">
|
|
20110
|
+
<span clx-icon [name]="item.icon" size="sm" class="text-clx-text-muted"></span>
|
|
20111
|
+
</span>
|
|
20112
|
+
}
|
|
20113
|
+
<span class="flex-1 min-w-0">
|
|
20114
|
+
<span class="block text-sm text-clx-text-label truncate">{{ item.label }}</span>
|
|
20115
|
+
@if (item.sublabel) {
|
|
20116
|
+
<span class="block text-xs text-clx-text-subtle truncate">{{ item.sublabel }}</span>
|
|
20117
|
+
}
|
|
20118
|
+
</span>
|
|
20119
|
+
@if (item.meta) {
|
|
20120
|
+
<span class="text-sm font-semibold text-clx-text-label shrink-0">{{ item.meta }}</span>
|
|
20121
|
+
}
|
|
20122
|
+
</button>
|
|
20123
|
+
}
|
|
20124
|
+
}
|
|
20125
|
+
}
|
|
20126
|
+
@if (_value().trim() && suggestions()?.total) {
|
|
20127
|
+
<button type="button" class="w-full text-left px-4 pt-3 pb-1 text-sm font-semibold" [class]="_accentText()"
|
|
20128
|
+
(click)="_handleSubmit()">
|
|
20129
|
+
Ver los {{ suggestions()!.total }} resultados de “{{ _value().trim() }}”
|
|
20130
|
+
</button>
|
|
20131
|
+
}
|
|
20132
|
+
</div>
|
|
20133
|
+
</ng-template>
|
|
19887
20134
|
`,
|
|
19888
20135
|
encapsulation: ViewEncapsulation.None,
|
|
19889
20136
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
@@ -19891,7 +20138,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
|
|
|
19891
20138
|
class: 'block w-full',
|
|
19892
20139
|
},
|
|
19893
20140
|
}]
|
|
19894
|
-
}], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], buttonTextColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "buttonTextColor", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], buttonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "buttonLabel", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], search: [{ type: i0.Output, args: ["search"] }] } });
|
|
20141
|
+
}], ctorParameters: () => [], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], buttonTextColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "buttonTextColor", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], buttonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "buttonLabel", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], suggestions: [{ type: i0.Input, args: [{ isSignal: true, alias: "suggestions", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], debounceMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "debounceMs", required: false }] }], minChars: [{ type: i0.Input, args: [{ isSignal: true, alias: "minChars", required: false }] }], openOnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "openOnFocus", required: false }] }], search: [{ type: i0.Output, args: ["search"] }], queryChange: [{ type: i0.Output, args: ["queryChange"] }], suggestionSelect: [{ type: i0.Output, args: ["suggestionSelect"] }] } });
|
|
19895
20142
|
|
|
19896
20143
|
class ClxAnimateGroupDirective {
|
|
19897
20144
|
stagger = input(100, { ...(ngDevMode ? { debugName: "stagger" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|