@erplora/outfitkit 0.1.17 → 0.1.18
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/dist/cdn.d.ts +1 -0
- package/dist/components/ok-spotlight-search/ok-spotlight-search.d.ts +27 -0
- package/dist/components/ok-spotlight-search/ok-spotlight-search.test.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/ok-spotlight-search.js +211 -0
- package/dist/outfitkit.bundle.js +1765 -1583
- package/dist/outfitkit.js +1 -0
- package/package.json +2 -1
package/dist/cdn.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ import './components/ok-invoice/ok-invoice.js';
|
|
|
38
38
|
import './components/ok-timeline/ok-timeline.js';
|
|
39
39
|
import './components/ok-qty-stepper/ok-qty-stepper.js';
|
|
40
40
|
import './components/ok-command-palette/ok-command-palette.js';
|
|
41
|
+
import './components/ok-spotlight-search/ok-spotlight-search.js';
|
|
41
42
|
import './components/ok-color-picker/ok-color-picker.js';
|
|
42
43
|
import './components/ok-avatar/ok-avatar.js';
|
|
43
44
|
import './components/ok-status-pill/ok-status-pill.js';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
export declare class OkSpotlightSearch extends LitElement {
|
|
3
|
+
static styles: import("lit").CSSResult;
|
|
4
|
+
/** Abierto/cerrado (reflejado para CSS externo). */
|
|
5
|
+
open: boolean;
|
|
6
|
+
/** Texto guía del input de búsqueda. */
|
|
7
|
+
placeholder: string;
|
|
8
|
+
/** Texto de búsqueda actual (el consumidor puede resetearlo). */
|
|
9
|
+
value: string;
|
|
10
|
+
/** Icono (Iconify/ionicon) del botón-trigger propio; si vacío, no se pinta trigger. */
|
|
11
|
+
triggerIcon: string;
|
|
12
|
+
/** Nombre accesible del botón-trigger (aria-label). */
|
|
13
|
+
triggerLabel: string;
|
|
14
|
+
private input?;
|
|
15
|
+
openSearch(): void;
|
|
16
|
+
close(): void;
|
|
17
|
+
toggle(): void;
|
|
18
|
+
private emitOpen;
|
|
19
|
+
private onInput;
|
|
20
|
+
protected updated(): void;
|
|
21
|
+
render(): unknown;
|
|
22
|
+
}
|
|
23
|
+
declare global {
|
|
24
|
+
interface HTMLElementTagNameMap {
|
|
25
|
+
'ok-spotlight-search': OkSpotlightSearch;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import './ok-spotlight-search.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -59,6 +59,7 @@ export type { OkTimelineItem } from './components/ok-timeline/ok-timeline.js';
|
|
|
59
59
|
export { OkQtyStepper } from './components/ok-qty-stepper/ok-qty-stepper.js';
|
|
60
60
|
export { OkCommandPalette } from './components/ok-command-palette/ok-command-palette.js';
|
|
61
61
|
export type { OkCommand } from './components/ok-command-palette/ok-command-palette.js';
|
|
62
|
+
export { OkSpotlightSearch } from './components/ok-spotlight-search/ok-spotlight-search.js';
|
|
62
63
|
export { OkColorPicker } from './components/ok-color-picker/ok-color-picker.js';
|
|
63
64
|
export type { OkRgb } from './components/ok-color-picker/ok-color-picker.js';
|
|
64
65
|
export { OkAvatar } from './components/ok-avatar/ok-avatar.js';
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,7 @@ import { OkInvoice } from "./ok-invoice.js";
|
|
|
39
39
|
import { OkTimeline } from "./ok-timeline.js";
|
|
40
40
|
import { OkQtyStepper } from "./ok-qty-stepper.js";
|
|
41
41
|
import { OkCommandPalette } from "./ok-command-palette.js";
|
|
42
|
+
import { OkSpotlightSearch } from "./ok-spotlight-search.js";
|
|
42
43
|
import { OkColorPicker } from "./ok-color-picker.js";
|
|
43
44
|
import { OkAvatar } from "./ok-avatar.js";
|
|
44
45
|
import { OkStatusPill } from "./ok-status-pill.js";
|
|
@@ -180,6 +181,7 @@ export {
|
|
|
180
181
|
OkSparkline,
|
|
181
182
|
OkSplitButton,
|
|
182
183
|
OkSplitter,
|
|
184
|
+
OkSpotlightSearch,
|
|
183
185
|
OkStat,
|
|
184
186
|
OkStatusDot,
|
|
185
187
|
OkStatusPill,
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { LitElement, css, nothing, html } from "lit";
|
|
2
|
+
import { property, query } from "lit/decorators.js";
|
|
3
|
+
import { define } from "./define.js";
|
|
4
|
+
import { L as iconSearchOutline, v as iconCloseOutline, o as okIcon } from "./shared/icons.js";
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
7
|
+
var result = void 0;
|
|
8
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
9
|
+
if (decorator = decorators[i])
|
|
10
|
+
result = decorator(target, key, result) || result;
|
|
11
|
+
if (result) __defProp(target, key, result);
|
|
12
|
+
return result;
|
|
13
|
+
};
|
|
14
|
+
class OkSpotlightSearch extends LitElement {
|
|
15
|
+
constructor() {
|
|
16
|
+
super(...arguments);
|
|
17
|
+
this.open = false;
|
|
18
|
+
this.placeholder = "";
|
|
19
|
+
this.value = "";
|
|
20
|
+
this.triggerIcon = "";
|
|
21
|
+
this.triggerLabel = "";
|
|
22
|
+
}
|
|
23
|
+
static {
|
|
24
|
+
this.styles = css`
|
|
25
|
+
:host {
|
|
26
|
+
--color: var(--ok-text, var(--ion-text-color, #1c1b17));
|
|
27
|
+
--color-muted: var(--ok-text-muted, rgba(var(--ion-text-color-rgb, 28, 27, 23), 0.6));
|
|
28
|
+
--panel-bg: var(--ok-surface, var(--ion-background-color, #ffffff));
|
|
29
|
+
--scrim-bg: var(--ok-scrim, rgba(0, 0, 0, 0.28));
|
|
30
|
+
--border-soft: var(--ok-border-soft, rgba(var(--ion-text-color-rgb, 28, 27, 23), 0.1));
|
|
31
|
+
--radius: var(--ok-radius, 16px);
|
|
32
|
+
--shadow: var(--ok-shadow, 0 24px 80px rgba(0, 0, 0, 0.35));
|
|
33
|
+
--font: var(--ok-font, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif);
|
|
34
|
+
display: contents;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Botón-trigger opcional (icon-only). */
|
|
38
|
+
button.trigger {
|
|
39
|
+
display: inline-flex;
|
|
40
|
+
align-items: center;
|
|
41
|
+
justify-content: center;
|
|
42
|
+
width: 2.4rem;
|
|
43
|
+
height: 2.4rem;
|
|
44
|
+
padding: 0;
|
|
45
|
+
border: 0;
|
|
46
|
+
border-radius: 10px;
|
|
47
|
+
background: none;
|
|
48
|
+
color: var(--color-muted);
|
|
49
|
+
cursor: pointer;
|
|
50
|
+
}
|
|
51
|
+
button.trigger[data-assigned] { color: var(--ok-primary, var(--ion-color-primary, #3880ff)); }
|
|
52
|
+
button.trigger ion-icon { font-size: 1.35rem; }
|
|
53
|
+
|
|
54
|
+
/* El <dialog> flota arriba-centro, translúcido con blur (Spotlight). El top layer lo saca de
|
|
55
|
+
cualquier containing block. */
|
|
56
|
+
dialog {
|
|
57
|
+
margin: 10vh auto auto;
|
|
58
|
+
width: min(92vw, 36rem);
|
|
59
|
+
max-height: 72vh;
|
|
60
|
+
padding: 0;
|
|
61
|
+
border: none;
|
|
62
|
+
border-radius: var(--radius);
|
|
63
|
+
overflow: hidden;
|
|
64
|
+
color: var(--color);
|
|
65
|
+
font-family: var(--font);
|
|
66
|
+
background: color-mix(in srgb, var(--panel-bg) 80%, transparent);
|
|
67
|
+
-webkit-backdrop-filter: blur(22px) saturate(180%);
|
|
68
|
+
backdrop-filter: blur(22px) saturate(180%);
|
|
69
|
+
box-shadow: var(--shadow), 0 0 0 1px rgba(128, 128, 128, 0.18);
|
|
70
|
+
}
|
|
71
|
+
dialog::backdrop {
|
|
72
|
+
background: var(--scrim-bg);
|
|
73
|
+
-webkit-backdrop-filter: blur(3px);
|
|
74
|
+
backdrop-filter: blur(3px);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Fila del input hero + cierre. */
|
|
78
|
+
.top {
|
|
79
|
+
display: flex;
|
|
80
|
+
align-items: center;
|
|
81
|
+
gap: 0.5rem;
|
|
82
|
+
padding: 0.7rem 0.85rem;
|
|
83
|
+
border-bottom: 1px solid var(--border-soft);
|
|
84
|
+
}
|
|
85
|
+
.top .lupa { flex: 0 0 auto; font-size: 1.25rem; color: var(--color-muted); }
|
|
86
|
+
.top input {
|
|
87
|
+
flex: 1 1 auto;
|
|
88
|
+
min-width: 0;
|
|
89
|
+
border: 0;
|
|
90
|
+
outline: none;
|
|
91
|
+
background: none;
|
|
92
|
+
color: inherit;
|
|
93
|
+
font: inherit;
|
|
94
|
+
font-size: 1.05rem;
|
|
95
|
+
}
|
|
96
|
+
.top input::placeholder { color: var(--color-muted); }
|
|
97
|
+
.top .close {
|
|
98
|
+
flex: 0 0 auto;
|
|
99
|
+
display: inline-flex;
|
|
100
|
+
align-items: center;
|
|
101
|
+
justify-content: center;
|
|
102
|
+
width: 2rem;
|
|
103
|
+
height: 2rem;
|
|
104
|
+
padding: 0;
|
|
105
|
+
border: 0;
|
|
106
|
+
border-radius: 8px;
|
|
107
|
+
background: none;
|
|
108
|
+
color: var(--color-muted);
|
|
109
|
+
cursor: pointer;
|
|
110
|
+
}
|
|
111
|
+
.top .close ion-icon { font-size: 1.2rem; }
|
|
112
|
+
|
|
113
|
+
/* Cuerpo scrollable: aquí caen los resultados del consumidor (slot por defecto). */
|
|
114
|
+
.results { max-height: 56vh; overflow-y: auto; padding: 0.35rem; }
|
|
115
|
+
.footer:not(:empty) { border-top: 1px solid var(--border-soft); padding: 0.3rem 0.6rem; }
|
|
116
|
+
|
|
117
|
+
@media (max-width: 560px) {
|
|
118
|
+
dialog { margin: 0 auto auto; width: 100vw; max-width: 100vw; max-height: 100vh; height: auto; border-radius: 0; }
|
|
119
|
+
}
|
|
120
|
+
`;
|
|
121
|
+
}
|
|
122
|
+
// ── API pública ──────────────────────────────────────────────────────────
|
|
123
|
+
openSearch() {
|
|
124
|
+
if (this.open) return;
|
|
125
|
+
this.open = true;
|
|
126
|
+
this.emitOpen(true);
|
|
127
|
+
}
|
|
128
|
+
close() {
|
|
129
|
+
if (!this.open) return;
|
|
130
|
+
this.open = false;
|
|
131
|
+
this.emitOpen(false);
|
|
132
|
+
}
|
|
133
|
+
toggle() {
|
|
134
|
+
this.open ? this.close() : this.openSearch();
|
|
135
|
+
}
|
|
136
|
+
emitOpen(open) {
|
|
137
|
+
this.dispatchEvent(new CustomEvent("ok-open", { detail: { open }, bubbles: true, composed: true }));
|
|
138
|
+
}
|
|
139
|
+
onInput(e) {
|
|
140
|
+
this.value = e.target.value;
|
|
141
|
+
this.dispatchEvent(new CustomEvent("ok-input", { detail: { value: this.value }, bubbles: true, composed: true }));
|
|
142
|
+
}
|
|
143
|
+
// Sincroniza `open` ↔ el <dialog> nativo (top layer). try/catch porque happy-dom (tests) no
|
|
144
|
+
// implementa showModal/close; ahí `open` sigue siendo la verdad.
|
|
145
|
+
updated() {
|
|
146
|
+
const d = this.renderRoot.querySelector("dialog");
|
|
147
|
+
if (!d) return;
|
|
148
|
+
try {
|
|
149
|
+
if (this.open && !d.open) {
|
|
150
|
+
d.showModal();
|
|
151
|
+
this.input?.focus();
|
|
152
|
+
} else if (!this.open && d.open) {
|
|
153
|
+
d.close();
|
|
154
|
+
}
|
|
155
|
+
} catch {
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
render() {
|
|
159
|
+
return html`
|
|
160
|
+
${this.triggerIcon ? html`<button class="trigger" ?data-assigned=${this.open} aria-label=${this.triggerLabel || this.placeholder}
|
|
161
|
+
title=${this.triggerLabel || this.placeholder} @click=${() => this.openSearch()}>
|
|
162
|
+
<ion-icon .icon=${okIcon(this.triggerIcon)}></ion-icon>
|
|
163
|
+
</button>` : nothing}
|
|
164
|
+
|
|
165
|
+
<dialog aria-label=${this.triggerLabel || this.placeholder}
|
|
166
|
+
@close=${() => {
|
|
167
|
+
if (this.open) {
|
|
168
|
+
this.open = false;
|
|
169
|
+
this.emitOpen(false);
|
|
170
|
+
}
|
|
171
|
+
}}
|
|
172
|
+
@click=${(e) => {
|
|
173
|
+
if (e.target === e.currentTarget) this.close();
|
|
174
|
+
}}>
|
|
175
|
+
<div class="top">
|
|
176
|
+
<ion-icon class="lupa" .icon=${iconSearchOutline}></ion-icon>
|
|
177
|
+
<input type="text" .value=${this.value} placeholder=${this.placeholder}
|
|
178
|
+
aria-label=${this.placeholder} autocomplete="off" spellcheck="false"
|
|
179
|
+
@input=${(e) => this.onInput(e)} />
|
|
180
|
+
<button class="close" aria-label="Cerrar" @click=${() => this.close()}>
|
|
181
|
+
<ion-icon .icon=${iconCloseOutline}></ion-icon>
|
|
182
|
+
</button>
|
|
183
|
+
</div>
|
|
184
|
+
<div class="results"><slot></slot></div>
|
|
185
|
+
<div class="footer"><slot name="footer"></slot></div>
|
|
186
|
+
</dialog>
|
|
187
|
+
`;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
__decorateClass([
|
|
191
|
+
property({ type: Boolean, reflect: true })
|
|
192
|
+
], OkSpotlightSearch.prototype, "open");
|
|
193
|
+
__decorateClass([
|
|
194
|
+
property()
|
|
195
|
+
], OkSpotlightSearch.prototype, "placeholder");
|
|
196
|
+
__decorateClass([
|
|
197
|
+
property()
|
|
198
|
+
], OkSpotlightSearch.prototype, "value");
|
|
199
|
+
__decorateClass([
|
|
200
|
+
property({ attribute: "trigger-icon" })
|
|
201
|
+
], OkSpotlightSearch.prototype, "triggerIcon");
|
|
202
|
+
__decorateClass([
|
|
203
|
+
property({ attribute: "trigger-label" })
|
|
204
|
+
], OkSpotlightSearch.prototype, "triggerLabel");
|
|
205
|
+
__decorateClass([
|
|
206
|
+
query(".top input")
|
|
207
|
+
], OkSpotlightSearch.prototype, "input");
|
|
208
|
+
define("ok-spotlight-search", OkSpotlightSearch);
|
|
209
|
+
export {
|
|
210
|
+
OkSpotlightSearch
|
|
211
|
+
};
|