codexly-ui 0.22.1 → 0.23.1
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 +259 -34
- package/fesm2022/codexly-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/codexly-ui.d.ts +92 -22
package/fesm2022/codexly-ui.mjs
CHANGED
|
@@ -14075,11 +14075,6 @@ class ClxPaginationComponent {
|
|
|
14075
14075
|
_destroyRef = inject(DestroyRef);
|
|
14076
14076
|
// ── FormControl interno para el select de pageSize ─────────────────────────
|
|
14077
14077
|
_pageSizeCtrl = new FormControl(null);
|
|
14078
|
-
/** True once the user has explicitly picked a pageSize from the select — after that, their
|
|
14079
|
-
* choice is respected even if a later filter shrinks totalItems below it. Until then, a
|
|
14080
|
-
* caller-provided default (e.g. 20) that exceeds a small totalItems is auto-corrected down
|
|
14081
|
-
* to the smallest available option, so the select never opens pre-selected on the largest value. */
|
|
14082
|
-
_userTouchedPageSize = false;
|
|
14083
14078
|
constructor() {
|
|
14084
14079
|
// Sincroniza el pageSize model → FormControl cada vez que cambia desde afuera
|
|
14085
14080
|
effect(() => {
|
|
@@ -14088,31 +14083,14 @@ class ClxPaginationComponent {
|
|
|
14088
14083
|
this._pageSizeCtrl.setValue(ps, { emitEvent: false });
|
|
14089
14084
|
}
|
|
14090
14085
|
});
|
|
14091
|
-
//
|
|
14092
|
-
//
|
|
14093
|
-
//
|
|
14094
|
-
// selección manual — si no, el consumidor (ej. clx-table → su padre real) nunca se entera
|
|
14095
|
-
// del nuevo tamaño y sigue pidiendo datos al backend con el size viejo.
|
|
14096
|
-
effect(() => {
|
|
14097
|
-
if (this._userTouchedPageSize)
|
|
14098
|
-
return;
|
|
14099
|
-
const total = this.totalItems();
|
|
14100
|
-
if (!total || total <= 0)
|
|
14101
|
-
return;
|
|
14102
|
-
const smallest = this._pageSizeOptions()[0]?.value;
|
|
14103
|
-
if (smallest != null && this.pageSize() > total && smallest !== this.pageSize()) {
|
|
14104
|
-
this.pageSize.set(smallest);
|
|
14105
|
-
this.currentPage.set(1);
|
|
14106
|
-
this.sizeChange.emit({ pageSize: smallest });
|
|
14107
|
-
this.pageChange.emit({ page: 1, pageSize: smallest });
|
|
14108
|
-
}
|
|
14109
|
-
});
|
|
14086
|
+
// El pageSize solo cambia cuando el usuario lo elige: nunca se ajusta solo según totalItems.
|
|
14087
|
+
// Antes se reducía a la opción más pequeña cuando había menos registros que el pageSize, lo
|
|
14088
|
+
// que mostraba 5 por página donde cabían todos y obligaba al consumidor a pedir los datos de nuevo.
|
|
14110
14089
|
// Sincroniza el FormControl → pageSize model cuando el usuario elige
|
|
14111
14090
|
this._pageSizeCtrl.valueChanges.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(val => {
|
|
14112
14091
|
const newSize = Number(val);
|
|
14113
14092
|
if (!val || !Number.isFinite(newSize) || newSize <= 0 || newSize === this.pageSize())
|
|
14114
14093
|
return;
|
|
14115
|
-
this._userTouchedPageSize = true;
|
|
14116
14094
|
this.pageSize.set(newSize);
|
|
14117
14095
|
this.currentPage.set(1);
|
|
14118
14096
|
this.sizeChange.emit({ pageSize: newSize });
|
|
@@ -19732,9 +19710,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
|
|
|
19732
19710
|
let _clxSearchIdCounter = 0;
|
|
19733
19711
|
/** Storefront search bar — same color/size/CVA conventions as ClxInputComponent, but styled as
|
|
19734
19712
|
* 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.
|
|
19713
|
+
* a detached button, matching how e-commerce header search boxes are typically laid out.
|
|
19714
|
+
*
|
|
19715
|
+
* Optional autocomplete: the host listens to (queryChange) — the text, debounced, once it has
|
|
19716
|
+
* `minChars` — and feeds [suggestions] back (product rows with image and price, shortcuts, past
|
|
19717
|
+
* searches, a "¿Quisiste decir…?" correction, the result total). The panel opens under the bar,
|
|
19718
|
+
* supports ↑ ↓ Enter Esc, and reports picks through (suggestionSelect); Enter without a picked row,
|
|
19719
|
+
* the button, the correction and "Ver todos" emit (search). With [openOnFocus] the panel also shows
|
|
19720
|
+
* for an empty box (e.g. recent searches). */
|
|
19736
19721
|
class ClxSearchComponent {
|
|
19737
19722
|
_themeSvc = inject(ClxThemeService);
|
|
19723
|
+
_el = inject((ElementRef));
|
|
19724
|
+
_sso = inject(ScrollStrategyOptions);
|
|
19738
19725
|
color = input(undefined, ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
|
|
19739
19726
|
_color = computed(() => this.color() ?? this._themeSvc.config().primaryColor, ...(ngDevMode ? [{ debugName: "_color" }] : /* istanbul ignore next */ []));
|
|
19740
19727
|
/** Overrides only the search button's text color — see ClxButtonComponent's textColor input. */
|
|
@@ -19747,13 +19734,45 @@ class ClxSearchComponent {
|
|
|
19747
19734
|
value = input('', ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
19748
19735
|
/** Disabled state for standalone use (without FormControl) */
|
|
19749
19736
|
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
19737
|
+
/** Autocomplete content for the current text; null = no panel. */
|
|
19738
|
+
suggestions = input(null, ...(ngDevMode ? [{ debugName: "suggestions" }] : /* istanbul ignore next */ []));
|
|
19739
|
+
/** The host is fetching suggestions. */
|
|
19740
|
+
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
19741
|
+
/** (queryChange) waits this long after the last keystroke. */
|
|
19742
|
+
debounceMs = input(250, ...(ngDevMode ? [{ debugName: "debounceMs" }] : /* istanbul ignore next */ []));
|
|
19743
|
+
/** (queryChange) only from this many characters (0 = also for an empty box). */
|
|
19744
|
+
minChars = input(2, ...(ngDevMode ? [{ debugName: "minChars" }] : /* istanbul ignore next */ []));
|
|
19745
|
+
/** Show the panel when focusing an empty box (recent searches…). */
|
|
19746
|
+
openOnFocus = input(false, ...(ngDevMode ? [{ debugName: "openOnFocus" }] : /* istanbul ignore next */ []));
|
|
19750
19747
|
search = output();
|
|
19748
|
+
/** Debounced text for the host to fetch suggestions for ('' when cleared). */
|
|
19749
|
+
queryChange = output();
|
|
19750
|
+
suggestionSelect = output();
|
|
19751
19751
|
_inputId = `clx-search-${++_clxSearchIdCounter}`;
|
|
19752
19752
|
_value = signal('', ...(ngDevMode ? [{ debugName: "_value" }] : /* istanbul ignore next */ []));
|
|
19753
19753
|
_cvaDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_cvaDisabled" }] : /* istanbul ignore next */ []));
|
|
19754
19754
|
_cvaConnected = false;
|
|
19755
19755
|
_cardDisabled = inject(CLX_CARD_DISABLED_CONTEXT, { optional: true });
|
|
19756
|
+
_focused = signal(false, ...(ngDevMode ? [{ debugName: "_focused" }] : /* istanbul ignore next */ []));
|
|
19757
|
+
_dismissed = signal(false, ...(ngDevMode ? [{ debugName: "_dismissed" }] : /* istanbul ignore next */ []));
|
|
19758
|
+
_active = signal(null, ...(ngDevMode ? [{ debugName: "_active" }] : /* istanbul ignore next */ []));
|
|
19759
|
+
_panelWidth = signal(0, ...(ngDevMode ? [{ debugName: "_panelWidth" }] : /* istanbul ignore next */ []));
|
|
19760
|
+
_debounce;
|
|
19756
19761
|
_disabled = computed(() => this._cvaDisabled() || this.disabled() || !!this._cardDisabled?.(), ...(ngDevMode ? [{ debugName: "_disabled" }] : /* istanbul ignore next */ []));
|
|
19762
|
+
_scrollStrategy = this._sso.reposition();
|
|
19763
|
+
_positions = [
|
|
19764
|
+
{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 6 },
|
|
19765
|
+
];
|
|
19766
|
+
/** Flat list of the panel's rows, for ↑ ↓. */
|
|
19767
|
+
_rows = computed(() => (this.suggestions()?.groups ?? [])
|
|
19768
|
+
.flatMap(g => g.items.map(item => ({ group: g.key, item }))), ...(ngDevMode ? [{ debugName: "_rows" }] : /* istanbul ignore next */ []));
|
|
19769
|
+
_panelOpen = computed(() => {
|
|
19770
|
+
if (!this._focused() || this._dismissed() || this._disabled())
|
|
19771
|
+
return false;
|
|
19772
|
+
const s = this.suggestions();
|
|
19773
|
+
const hasContent = !!s && (!!s.correction || s.groups.some(g => g.items.length > 0));
|
|
19774
|
+
return hasContent && (this._value().trim().length > 0 || this.openOnFocus());
|
|
19775
|
+
}, ...(ngDevMode ? [{ debugName: "_panelOpen" }] : /* istanbul ignore next */ []));
|
|
19757
19776
|
_valueEffect = effect(() => {
|
|
19758
19777
|
const v = this.value();
|
|
19759
19778
|
if (!this._cvaConnected)
|
|
@@ -19761,6 +19780,9 @@ class ClxSearchComponent {
|
|
|
19761
19780
|
}, ...(ngDevMode ? [{ debugName: "_valueEffect" }] : /* istanbul ignore next */ []));
|
|
19762
19781
|
_onChange = () => { };
|
|
19763
19782
|
_onTouched = () => { };
|
|
19783
|
+
constructor() {
|
|
19784
|
+
inject(DestroyRef).onDestroy(() => clearTimeout(this._debounce));
|
|
19785
|
+
}
|
|
19764
19786
|
_sizeConfig = computed(() => INPUT_SIZE_MAP[this._size()], ...(ngDevMode ? [{ debugName: "_sizeConfig" }] : /* istanbul ignore next */ []));
|
|
19765
19787
|
_buttonSize = computed(() => {
|
|
19766
19788
|
switch (this._size()) {
|
|
@@ -19769,6 +19791,7 @@ class ClxSearchComponent {
|
|
|
19769
19791
|
default: return 'md';
|
|
19770
19792
|
}
|
|
19771
19793
|
}, ...(ngDevMode ? [{ debugName: "_buttonSize" }] : /* istanbul ignore next */ []));
|
|
19794
|
+
_accentText = computed(() => resolveColor(this._color()).textEmphasis, ...(ngDevMode ? [{ debugName: "_accentText" }] : /* istanbul ignore next */ []));
|
|
19772
19795
|
_wrapperClass = computed(() => {
|
|
19773
19796
|
const focusCls = this._disabled() ? '' : resolveColor(this._color()).focusWithin;
|
|
19774
19797
|
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 +19820,106 @@ class ClxSearchComponent {
|
|
|
19797
19820
|
const val = event.target.value;
|
|
19798
19821
|
this._value.set(val);
|
|
19799
19822
|
this._onChange(val);
|
|
19823
|
+
this._dismissed.set(false);
|
|
19824
|
+
this._active.set(null);
|
|
19825
|
+
this._emitQuery(val);
|
|
19826
|
+
}
|
|
19827
|
+
_handleFocus() {
|
|
19828
|
+
this._panelWidth.set(Math.round(this._el.nativeElement.getBoundingClientRect().width));
|
|
19829
|
+
this._focused.set(true);
|
|
19830
|
+
this._dismissed.set(false);
|
|
19831
|
+
if (this.openOnFocus() && !this._value().trim())
|
|
19832
|
+
this.queryChange.emit('');
|
|
19800
19833
|
}
|
|
19801
19834
|
_handleBlur() {
|
|
19802
19835
|
this._onTouched();
|
|
19836
|
+
this._focused.set(false);
|
|
19837
|
+
}
|
|
19838
|
+
_handleKeydown(event) {
|
|
19839
|
+
const rows = this._rows();
|
|
19840
|
+
if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
|
|
19841
|
+
if (!this._panelOpen() || !rows.length)
|
|
19842
|
+
return;
|
|
19843
|
+
event.preventDefault();
|
|
19844
|
+
const current = this._active();
|
|
19845
|
+
const index = current ? rows.findIndex(r => r.group === current.group && r.item.id === current.id) : -1;
|
|
19846
|
+
const next = event.key === 'ArrowDown'
|
|
19847
|
+
? (index + 1) % rows.length
|
|
19848
|
+
: (index <= 0 ? rows.length - 1 : index - 1);
|
|
19849
|
+
this._active.set({ group: rows[next].group, id: rows[next].item.id });
|
|
19850
|
+
}
|
|
19851
|
+
else if (event.key === 'Enter') {
|
|
19852
|
+
event.preventDefault();
|
|
19853
|
+
const current = this._active();
|
|
19854
|
+
const row = current && this._panelOpen()
|
|
19855
|
+
? rows.find(r => r.group === current.group && r.item.id === current.id)
|
|
19856
|
+
: undefined;
|
|
19857
|
+
if (row)
|
|
19858
|
+
this._select(row.group, row.item);
|
|
19859
|
+
else
|
|
19860
|
+
this._handleSubmit();
|
|
19861
|
+
}
|
|
19862
|
+
else if (event.key === 'Escape') {
|
|
19863
|
+
this._close();
|
|
19864
|
+
}
|
|
19865
|
+
}
|
|
19866
|
+
_isActive(group, item) {
|
|
19867
|
+
const a = this._active();
|
|
19868
|
+
return !!a && a.group === group && a.id === item.id;
|
|
19869
|
+
}
|
|
19870
|
+
_activate(group, item) {
|
|
19871
|
+
this._active.set({ group, id: item.id });
|
|
19872
|
+
}
|
|
19873
|
+
_select(group, item) {
|
|
19874
|
+
this._close();
|
|
19875
|
+
this.suggestionSelect.emit({ group, item });
|
|
19876
|
+
}
|
|
19877
|
+
_searchFor(text) {
|
|
19878
|
+
this._value.set(text);
|
|
19879
|
+
this._onChange(text);
|
|
19880
|
+
this._handleSubmit();
|
|
19881
|
+
}
|
|
19882
|
+
_close() {
|
|
19883
|
+
this._dismissed.set(true);
|
|
19884
|
+
this._active.set(null);
|
|
19803
19885
|
}
|
|
19804
19886
|
_handleSubmit() {
|
|
19805
19887
|
if (this._disabled())
|
|
19806
19888
|
return;
|
|
19889
|
+
this._close();
|
|
19890
|
+
clearTimeout(this._debounce);
|
|
19807
19891
|
this.search.emit(this._value());
|
|
19808
19892
|
}
|
|
19893
|
+
_emitQuery(val) {
|
|
19894
|
+
clearTimeout(this._debounce);
|
|
19895
|
+
const text = val.trim();
|
|
19896
|
+
if (text.length > 0 && text.length < this.minChars())
|
|
19897
|
+
return;
|
|
19898
|
+
this._debounce = setTimeout(() => this.queryChange.emit(text), text ? this.debounceMs() : 0);
|
|
19899
|
+
}
|
|
19809
19900
|
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.
|
|
19901
|
+
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
19902
|
{
|
|
19812
19903
|
provide: NG_VALUE_ACCESSOR,
|
|
19813
19904
|
useExisting: forwardRef(() => ClxSearchComponent),
|
|
19814
19905
|
multi: true,
|
|
19815
19906
|
},
|
|
19816
19907
|
], ngImport: i0, template: `
|
|
19817
|
-
<div [class]="_wrapperClass()">
|
|
19908
|
+
<div [class]="_wrapperClass()" cdkOverlayOrigin #origin="cdkOverlayOrigin">
|
|
19818
19909
|
<input
|
|
19819
19910
|
[id]="_inputId"
|
|
19820
19911
|
type="search"
|
|
19912
|
+
role="combobox"
|
|
19913
|
+
[attr.aria-expanded]="_panelOpen()"
|
|
19914
|
+
[attr.aria-controls]="_inputId + '-panel'"
|
|
19821
19915
|
[placeholder]="placeholder()"
|
|
19822
19916
|
[disabled]="_disabled()"
|
|
19823
19917
|
[value]="_value()"
|
|
19824
19918
|
[class]="_inputClass()"
|
|
19825
19919
|
autocomplete="off"
|
|
19826
19920
|
(input)="_handleInput($event)"
|
|
19827
|
-
(
|
|
19921
|
+
(focus)="_handleFocus()"
|
|
19922
|
+
(keydown)="_handleKeydown($event)"
|
|
19828
19923
|
(blur)="_handleBlur()"
|
|
19829
19924
|
/>
|
|
19830
19925
|
<button
|
|
@@ -19841,14 +19936,77 @@ class ClxSearchComponent {
|
|
|
19841
19936
|
{{ buttonLabel() }}
|
|
19842
19937
|
</button>
|
|
19843
19938
|
</div>
|
|
19844
|
-
|
|
19939
|
+
|
|
19940
|
+
<ng-template
|
|
19941
|
+
cdkConnectedOverlay
|
|
19942
|
+
[cdkConnectedOverlayOrigin]="origin"
|
|
19943
|
+
[cdkConnectedOverlayOpen]="_panelOpen()"
|
|
19944
|
+
[cdkConnectedOverlayPositions]="_positions"
|
|
19945
|
+
[cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
|
|
19946
|
+
[cdkConnectedOverlayWidth]="_panelWidth()"
|
|
19947
|
+
[cdkConnectedOverlayPush]="true"
|
|
19948
|
+
(overlayOutsideClick)="_close()"
|
|
19949
|
+
(detach)="_close()">
|
|
19950
|
+
<div [id]="_inputId + '-panel'" role="listbox"
|
|
19951
|
+
class="w-full max-h-[70vh] overflow-y-auto bg-clx-surface rounded-xl shadow-xl border border-clx-border py-2"
|
|
19952
|
+
(mousedown)="$event.preventDefault()">
|
|
19953
|
+
@if (loading()) {
|
|
19954
|
+
<div class="flex items-center gap-2 px-4 py-2 text-xs text-clx-text-subtle">
|
|
19955
|
+
<clx-spinner size="xs" [color]="_color()" /> Buscando…
|
|
19956
|
+
</div>
|
|
19957
|
+
}
|
|
19958
|
+
@if (suggestions()?.correction; as correction) {
|
|
19959
|
+
<button type="button" class="w-full text-left px-4 py-2 text-sm text-clx-text-muted hover:bg-clx-surface-2"
|
|
19960
|
+
(click)="_searchFor(correction)">
|
|
19961
|
+
¿Quisiste decir <span class="font-semibold" [class]="_accentText()">{{ correction }}</span>?
|
|
19962
|
+
</button>
|
|
19963
|
+
}
|
|
19964
|
+
@for (group of suggestions()?.groups ?? []; track group.key) {
|
|
19965
|
+
@if (group.items.length) {
|
|
19966
|
+
<p class="px-4 pt-2 pb-1 text-[11px] font-semibold uppercase tracking-wide text-clx-text-subtle">{{ group.title }}</p>
|
|
19967
|
+
@for (item of group.items; track item.id) {
|
|
19968
|
+
<button type="button" role="option"
|
|
19969
|
+
[attr.aria-selected]="_isActive(group.key, item)"
|
|
19970
|
+
class="w-full flex items-center gap-3 px-4 py-2 text-left transition-colors"
|
|
19971
|
+
[class]="_isActive(group.key, item) ? 'bg-clx-surface-2' : 'hover:bg-clx-surface-2'"
|
|
19972
|
+
(mouseenter)="_activate(group.key, item)"
|
|
19973
|
+
(click)="_select(group.key, item)">
|
|
19974
|
+
@if (item.image) {
|
|
19975
|
+
<img [src]="item.image" [alt]="item.label" class="w-10 h-10 rounded-lg object-cover shrink-0 bg-clx-surface-2" />
|
|
19976
|
+
} @else if (item.icon) {
|
|
19977
|
+
<span class="w-8 h-8 rounded-lg bg-clx-surface-2 flex items-center justify-center shrink-0">
|
|
19978
|
+
<span clx-icon [name]="item.icon" size="sm" class="text-clx-text-muted"></span>
|
|
19979
|
+
</span>
|
|
19980
|
+
}
|
|
19981
|
+
<span class="flex-1 min-w-0">
|
|
19982
|
+
<span class="block text-sm text-clx-text-label truncate">{{ item.label }}</span>
|
|
19983
|
+
@if (item.sublabel) {
|
|
19984
|
+
<span class="block text-xs text-clx-text-subtle truncate">{{ item.sublabel }}</span>
|
|
19985
|
+
}
|
|
19986
|
+
</span>
|
|
19987
|
+
@if (item.meta) {
|
|
19988
|
+
<span class="text-sm font-semibold text-clx-text-label shrink-0">{{ item.meta }}</span>
|
|
19989
|
+
}
|
|
19990
|
+
</button>
|
|
19991
|
+
}
|
|
19992
|
+
}
|
|
19993
|
+
}
|
|
19994
|
+
@if (_value().trim() && suggestions()?.total) {
|
|
19995
|
+
<button type="button" class="w-full text-left px-4 pt-3 pb-1 text-sm font-semibold" [class]="_accentText()"
|
|
19996
|
+
(click)="_handleSubmit()">
|
|
19997
|
+
Ver los {{ suggestions()!.total }} resultados de “{{ _value().trim() }}”
|
|
19998
|
+
</button>
|
|
19999
|
+
}
|
|
20000
|
+
</div>
|
|
20001
|
+
</ng-template>
|
|
20002
|
+
`, 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
20003
|
}
|
|
19846
20004
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxSearchComponent, decorators: [{
|
|
19847
20005
|
type: Component,
|
|
19848
20006
|
args: [{
|
|
19849
20007
|
selector: 'clx-search',
|
|
19850
20008
|
standalone: true,
|
|
19851
|
-
imports: [ClxButtonComponent],
|
|
20009
|
+
imports: [OverlayModule, ClxButtonComponent, ClxIconComponent, ClxSpinnerComponent],
|
|
19852
20010
|
providers: [
|
|
19853
20011
|
{
|
|
19854
20012
|
provide: NG_VALUE_ACCESSOR,
|
|
@@ -19857,17 +20015,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
|
|
|
19857
20015
|
},
|
|
19858
20016
|
],
|
|
19859
20017
|
template: `
|
|
19860
|
-
<div [class]="_wrapperClass()">
|
|
20018
|
+
<div [class]="_wrapperClass()" cdkOverlayOrigin #origin="cdkOverlayOrigin">
|
|
19861
20019
|
<input
|
|
19862
20020
|
[id]="_inputId"
|
|
19863
20021
|
type="search"
|
|
20022
|
+
role="combobox"
|
|
20023
|
+
[attr.aria-expanded]="_panelOpen()"
|
|
20024
|
+
[attr.aria-controls]="_inputId + '-panel'"
|
|
19864
20025
|
[placeholder]="placeholder()"
|
|
19865
20026
|
[disabled]="_disabled()"
|
|
19866
20027
|
[value]="_value()"
|
|
19867
20028
|
[class]="_inputClass()"
|
|
19868
20029
|
autocomplete="off"
|
|
19869
20030
|
(input)="_handleInput($event)"
|
|
19870
|
-
(
|
|
20031
|
+
(focus)="_handleFocus()"
|
|
20032
|
+
(keydown)="_handleKeydown($event)"
|
|
19871
20033
|
(blur)="_handleBlur()"
|
|
19872
20034
|
/>
|
|
19873
20035
|
<button
|
|
@@ -19884,6 +20046,69 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
|
|
|
19884
20046
|
{{ buttonLabel() }}
|
|
19885
20047
|
</button>
|
|
19886
20048
|
</div>
|
|
20049
|
+
|
|
20050
|
+
<ng-template
|
|
20051
|
+
cdkConnectedOverlay
|
|
20052
|
+
[cdkConnectedOverlayOrigin]="origin"
|
|
20053
|
+
[cdkConnectedOverlayOpen]="_panelOpen()"
|
|
20054
|
+
[cdkConnectedOverlayPositions]="_positions"
|
|
20055
|
+
[cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
|
|
20056
|
+
[cdkConnectedOverlayWidth]="_panelWidth()"
|
|
20057
|
+
[cdkConnectedOverlayPush]="true"
|
|
20058
|
+
(overlayOutsideClick)="_close()"
|
|
20059
|
+
(detach)="_close()">
|
|
20060
|
+
<div [id]="_inputId + '-panel'" role="listbox"
|
|
20061
|
+
class="w-full max-h-[70vh] overflow-y-auto bg-clx-surface rounded-xl shadow-xl border border-clx-border py-2"
|
|
20062
|
+
(mousedown)="$event.preventDefault()">
|
|
20063
|
+
@if (loading()) {
|
|
20064
|
+
<div class="flex items-center gap-2 px-4 py-2 text-xs text-clx-text-subtle">
|
|
20065
|
+
<clx-spinner size="xs" [color]="_color()" /> Buscando…
|
|
20066
|
+
</div>
|
|
20067
|
+
}
|
|
20068
|
+
@if (suggestions()?.correction; as correction) {
|
|
20069
|
+
<button type="button" class="w-full text-left px-4 py-2 text-sm text-clx-text-muted hover:bg-clx-surface-2"
|
|
20070
|
+
(click)="_searchFor(correction)">
|
|
20071
|
+
¿Quisiste decir <span class="font-semibold" [class]="_accentText()">{{ correction }}</span>?
|
|
20072
|
+
</button>
|
|
20073
|
+
}
|
|
20074
|
+
@for (group of suggestions()?.groups ?? []; track group.key) {
|
|
20075
|
+
@if (group.items.length) {
|
|
20076
|
+
<p class="px-4 pt-2 pb-1 text-[11px] font-semibold uppercase tracking-wide text-clx-text-subtle">{{ group.title }}</p>
|
|
20077
|
+
@for (item of group.items; track item.id) {
|
|
20078
|
+
<button type="button" role="option"
|
|
20079
|
+
[attr.aria-selected]="_isActive(group.key, item)"
|
|
20080
|
+
class="w-full flex items-center gap-3 px-4 py-2 text-left transition-colors"
|
|
20081
|
+
[class]="_isActive(group.key, item) ? 'bg-clx-surface-2' : 'hover:bg-clx-surface-2'"
|
|
20082
|
+
(mouseenter)="_activate(group.key, item)"
|
|
20083
|
+
(click)="_select(group.key, item)">
|
|
20084
|
+
@if (item.image) {
|
|
20085
|
+
<img [src]="item.image" [alt]="item.label" class="w-10 h-10 rounded-lg object-cover shrink-0 bg-clx-surface-2" />
|
|
20086
|
+
} @else if (item.icon) {
|
|
20087
|
+
<span class="w-8 h-8 rounded-lg bg-clx-surface-2 flex items-center justify-center shrink-0">
|
|
20088
|
+
<span clx-icon [name]="item.icon" size="sm" class="text-clx-text-muted"></span>
|
|
20089
|
+
</span>
|
|
20090
|
+
}
|
|
20091
|
+
<span class="flex-1 min-w-0">
|
|
20092
|
+
<span class="block text-sm text-clx-text-label truncate">{{ item.label }}</span>
|
|
20093
|
+
@if (item.sublabel) {
|
|
20094
|
+
<span class="block text-xs text-clx-text-subtle truncate">{{ item.sublabel }}</span>
|
|
20095
|
+
}
|
|
20096
|
+
</span>
|
|
20097
|
+
@if (item.meta) {
|
|
20098
|
+
<span class="text-sm font-semibold text-clx-text-label shrink-0">{{ item.meta }}</span>
|
|
20099
|
+
}
|
|
20100
|
+
</button>
|
|
20101
|
+
}
|
|
20102
|
+
}
|
|
20103
|
+
}
|
|
20104
|
+
@if (_value().trim() && suggestions()?.total) {
|
|
20105
|
+
<button type="button" class="w-full text-left px-4 pt-3 pb-1 text-sm font-semibold" [class]="_accentText()"
|
|
20106
|
+
(click)="_handleSubmit()">
|
|
20107
|
+
Ver los {{ suggestions()!.total }} resultados de “{{ _value().trim() }}”
|
|
20108
|
+
</button>
|
|
20109
|
+
}
|
|
20110
|
+
</div>
|
|
20111
|
+
</ng-template>
|
|
19887
20112
|
`,
|
|
19888
20113
|
encapsulation: ViewEncapsulation.None,
|
|
19889
20114
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
@@ -19891,7 +20116,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
|
|
|
19891
20116
|
class: 'block w-full',
|
|
19892
20117
|
},
|
|
19893
20118
|
}]
|
|
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"] }] } });
|
|
20119
|
+
}], 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
20120
|
|
|
19896
20121
|
class ClxAnimateGroupDirective {
|
|
19897
20122
|
stagger = input(100, { ...(ngDevMode ? { debugName: "stagger" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|