wox-gui 0.1.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.
@@ -0,0 +1,3551 @@
1
+ var at = Object.defineProperty;
2
+ var lt = (d, p, t) => p in d ? at(d, p, { enumerable: !0, configurable: !0, writable: !0, value: t }) : d[p] = t;
3
+ var n = (d, p, t) => lt(d, typeof p != "symbol" ? p + "" : p, t);
4
+ const dt = `
5
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
6
+ :host { display: inline-block; font-family: var(--wox-font, 'Inter', sans-serif); color: var(--wox-text-primary, #eee); font-size: var(--wox-font-size-base, 12px); }
7
+ :host([hidden]) { display: none !important; }
8
+ `, F = class F extends HTMLElement {
9
+ constructor() {
10
+ super();
11
+ /**
12
+ * Sets the shadow root innerHTML from CSS + HTML strings.
13
+ * @param {string} css - Component-specific CSS
14
+ * @param {string} html - Component markup
15
+ */
16
+ n(this, "render", (t, e) => {
17
+ this.shadowRoot.innerHTML = `<style>${F.BASE_STYLES}${t}</style>${e}`;
18
+ });
19
+ /**
20
+ * Dispatches a composed, bubbling CustomEvent.
21
+ * @param {string} name - Event name
22
+ * @param {*} detail - Event payload
23
+ */
24
+ n(this, "emit", (t, e) => {
25
+ this.dispatchEvent(new CustomEvent(t, { detail: e, bubbles: !0, composed: !0 }));
26
+ });
27
+ /**
28
+ * Query shortcut for a single element inside the shadow root.
29
+ * @param {string} sel - CSS selector
30
+ * @returns {Element|null}
31
+ */
32
+ n(this, "$", (t) => this.shadowRoot.querySelector(t));
33
+ /**
34
+ * Query shortcut for all matching elements inside the shadow root.
35
+ * @param {string} sel - CSS selector
36
+ * @returns {NodeList}
37
+ */
38
+ n(this, "$$", (t) => this.shadowRoot.querySelectorAll(t));
39
+ this.attachShadow({ mode: "open" });
40
+ }
41
+ };
42
+ /** Common CSS reset applied inside every component's Shadow DOM */
43
+ n(F, "BASE_STYLES", dt);
44
+ let v = F;
45
+ const R = `
46
+ /* glow: neon glow effect using --wox-fx-color */
47
+ .glow {
48
+ border-color: var(--wox-fx-color);
49
+ color: var(--wox-fx-color);
50
+ background: color-mix(in srgb, var(--wox-fx-color), transparent 90%);
51
+ box-shadow: 0 0 20px color-mix(in srgb, var(--wox-fx-color), transparent 60%),
52
+ 0 0 40px color-mix(in srgb, var(--wox-fx-color), transparent 85%),
53
+ inset 0 0 15px color-mix(in srgb, var(--wox-fx-color), transparent 90%);
54
+ animation: wox-glow-pulse 2s ease-in-out infinite alternate;
55
+ }
56
+ .glow svg, .glow .material-icons {
57
+ filter: drop-shadow(0 0 6px var(--wox-fx-color)); opacity: 1;
58
+ }
59
+ .glow span { text-shadow: 0 0 8px var(--wox-fx-color); }
60
+ @keyframes wox-glow-pulse {
61
+ from { box-shadow: 0 0 15px color-mix(in srgb, var(--wox-fx-color), transparent 65%), 0 0 30px color-mix(in srgb, var(--wox-fx-color), transparent 88%), inset 0 0 12px color-mix(in srgb, var(--wox-fx-color), transparent 92%); }
62
+ to { box-shadow: 0 0 25px color-mix(in srgb, var(--wox-fx-color), transparent 50%), 0 0 50px color-mix(in srgb, var(--wox-fx-color), transparent 80%), inset 0 0 20px color-mix(in srgb, var(--wox-fx-color), transparent 88%); }
63
+ }
64
+
65
+ /* pulse: opacity pulse animation */
66
+ .pulse { animation: wox-pulse-fade 1.5s ease-in-out infinite alternate; }
67
+ .glow.pulse { animation: wox-glow-pulse 2s ease-in-out infinite alternate, wox-pulse-fade 1.5s ease-in-out infinite alternate; }
68
+ @keyframes wox-pulse-fade {
69
+ from { opacity: 1; }
70
+ to { opacity: 0.4; }
71
+ }
72
+ `, ct = `
73
+ :host { display: inline-flex; align-items: center; justify-content: center; vertical-align: middle; }
74
+ .material-icons { font-family: 'Material Icons'; font-weight: normal; font-style: normal; font-size: var(--size, 18px); display: inline-block; line-height: 1; text-transform: none; letter-spacing: normal; word-wrap: normal; white-space: nowrap; direction: ltr; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; -moz-osx-font-smoothing: grayscale; color: inherit; }
75
+ ::slotted(svg) { width: var(--size, 18px); height: var(--size, 18px); }
76
+ slot { display: inline-flex; align-items: center; justify-content: center; }
77
+ .fx-wrap { display: inline-flex; align-items: center; justify-content: center; border-radius: var(--wox-radius-sm, 3px); padding: 4px; }
78
+ `;
79
+ class pt extends v {
80
+ constructor() {
81
+ super(...arguments);
82
+ /** @private */
83
+ n(this, "_render", () => {
84
+ const t = this.getAttribute("name"), e = this.getAttribute("size") || "18", o = this.getAttribute("color") || "", i = this.hasAttribute("glow"), s = this.hasAttribute("pulse"), r = i || s, a = t ? `<span class="material-icons" style="--size:${e}px">${t}</span>` : "<slot></slot>", l = r ? `<span class="fx-wrap${i ? " glow" : ""}${s ? " pulse" : ""}" style="--wox-fx-color:${o};color:${o}">${a}</span>` : a;
85
+ this.render(`${ct} ${R} :host { --size: ${e}px; }`, l);
86
+ });
87
+ }
88
+ connectedCallback() {
89
+ this._render();
90
+ }
91
+ attributeChangedCallback() {
92
+ this.isConnected && this._render();
93
+ }
94
+ }
95
+ n(pt, "observedAttributes", ["name", "size", "color", "glow", "pulse"]);
96
+ const ht = `
97
+ :host { display: block; flex-shrink: 0; }
98
+ :host([direction="v"]) { display: inline-block; }
99
+ .sep { background: var(--wox-border, #333); }
100
+ .h { width: 100%; height: 1px; margin: var(--spacing, 0) 0; }
101
+ .v { height: 100%; width: 1px; margin: 0 var(--spacing, 0); display: inline-block; vertical-align: middle; min-height: 16px; }
102
+ `;
103
+ class ut extends v {
104
+ constructor() {
105
+ super(...arguments);
106
+ /** @private */
107
+ n(this, "_render", () => {
108
+ const t = this.getAttribute("direction") || "h", e = this.getAttribute("spacing") || "0";
109
+ this.render(
110
+ `${ht} :host { --spacing: ${e}; }`,
111
+ `<div class="sep ${t}"></div>`
112
+ );
113
+ });
114
+ }
115
+ connectedCallback() {
116
+ this._render();
117
+ }
118
+ attributeChangedCallback() {
119
+ this.isConnected && this._render();
120
+ }
121
+ }
122
+ n(ut, "observedAttributes", ["direction", "spacing"]);
123
+ const xt = `
124
+ :host { display: inline-flex; align-items: center; justify-content: center; }
125
+ .badge { display: inline-flex; align-items: center; justify-content: center; }
126
+ .dot { width: 8px; height: 8px; border-radius: var(--wox-radius-round, 50%); background: var(--color, var(--wox-accent, #00e5ff)); }
127
+ .diamond { width: 8px; height: 8px; background: var(--color, var(--wox-accent, #00e5ff)); transform: rotate(45deg); box-shadow: 0 0 10px color-mix(in srgb, var(--color, var(--wox-accent, #00e5ff)), transparent 50%); }
128
+ .text { background: color-mix(in srgb, var(--color, var(--wox-accent, #00e5ff)), transparent 85%); color: var(--color, var(--wox-accent, #00e5ff)); padding: 3px 8px; border-radius: var(--wox-radius-sm, 3px); font-weight: 600; font-size: var(--wox-font-size-sm, 10px); text-transform: uppercase; letter-spacing: 0.5px; }
129
+ `;
130
+ class gt extends v {
131
+ constructor() {
132
+ super(...arguments);
133
+ /** @private */
134
+ n(this, "_render", () => {
135
+ const t = this.getAttribute("variant") || "dot", e = this.getAttribute("text") || "", o = this.getAttribute("color") || "", i = o ? `--color: ${o};` : "";
136
+ let s = "";
137
+ t === "dot" ? s = `<span class="badge dot" style="${i}"></span>` : t === "diamond" ? s = `<span class="badge diamond" style="${i}"></span>` : s = `<span class="badge text" style="${i}">${e}</span>`, this.render(xt, s);
138
+ });
139
+ }
140
+ connectedCallback() {
141
+ this._render();
142
+ }
143
+ attributeChangedCallback() {
144
+ this.isConnected && this._render();
145
+ }
146
+ }
147
+ n(gt, "observedAttributes", ["variant", "text", "color"]);
148
+ const bt = `
149
+ :host { display: inline-block; }
150
+ button {
151
+ display: flex; align-items: center; justify-content: center; gap: 6px;
152
+ background: transparent; border: 1px solid transparent; color: var(--wox-text-secondary, #999);
153
+ cursor: pointer; font-family: var(--wox-font, sans-serif); font-size: var(--wox-font-size-base, 12px);
154
+ transition: all var(--wox-transition-fast, 0.12s); border-radius: var(--wox-radius-sm, 3px);
155
+ padding: 0; margin: 0; line-height: 1; user-select: none;
156
+ }
157
+ button:hover { background: var(--wox-bg-hover, #2a2a2e); color: var(--wox-text-hi, #fff); }
158
+ button:disabled { opacity: 0.4; cursor: not-allowed; pointer-events: none; }
159
+ button.active { background: var(--wox-bg-hover, #2a2a2e); color: var(--wox-accent, #00e5ff); border-color: var(--wox-border-light, #444); }
160
+
161
+ /* icon variant */
162
+ button.v-icon { width: 34px; height: 32px; border-radius: var(--wox-radius-sm, 3px); }
163
+ button.v-icon .material-icons { font-size: 18px; }
164
+
165
+ /* text variant */
166
+ button.v-text { padding: 6px 12px; border-radius: var(--wox-radius-md, 6px); font-size: var(--wox-font-size-base, 12px); }
167
+
168
+ /* tile variant */
169
+ button.v-tile {
170
+ flex-direction: column; gap: 6px; background: var(--wox-bg-toolbar, #1e1e22);
171
+ border: 1px solid var(--wox-border, #333); border-radius: var(--wox-radius-xl, 10px);
172
+ padding: 12px 10px; min-width: 68px; font-size: var(--wox-font-size-sm, 10px);
173
+ font-weight: 500; text-transform: uppercase;
174
+ transition: all var(--wox-transition-smooth, 0.25s cubic-bezier(0.4, 0, 0.2, 1));
175
+ position: relative; overflow: hidden;
176
+ }
177
+ button.v-tile:hover { background: var(--wox-bg-hover, #2a2a2e); border-color: #555; color: var(--wox-text-primary, #eee); transform: translateY(-1px); }
178
+ button.v-tile:hover svg, button.v-tile:hover .material-icons { transform: scale(1.05); opacity: 1; }
179
+ button.v-tile svg, button.v-tile .material-icons { display: block; width: 32px; height: 32px; transition: transform 0.2s; opacity: 0.8; font-size: 28px; }
180
+ button.v-tile.delete:hover { border-color: var(--wox-danger, #f72585); color: var(--wox-danger, #f72585); background: rgba(247, 37, 133, 0.05); }
181
+
182
+ /* tile with custom color accent */
183
+ button.v-tile[data-color] { --wox-fx-color: var(--wox-text-secondary, #999); }
184
+ button.v-tile[data-color]:hover {
185
+ background: color-mix(in srgb, var(--wox-fx-color), transparent 92%);
186
+ border-color: var(--wox-fx-color); color: var(--wox-fx-color);
187
+ box-shadow: 0 0 15px color-mix(in srgb, var(--wox-fx-color), transparent 80%);
188
+ }
189
+ button.v-tile[data-color]:hover svg { filter: drop-shadow(0 0 4px var(--wox-fx-color)); }
190
+
191
+ /* dash variant */
192
+ button.v-dash {
193
+ width: 42px; height: 26px; background: #1c1c21;
194
+ border: 1px solid var(--wox-border, #333); border-radius: var(--wox-radius-lg, 8px);
195
+ transition: all 0.2s;
196
+ }
197
+ button.v-dash:hover { background: var(--wox-bg-hover, #2a2a2e); border-color: #555; transform: translateY(-1px); }
198
+ button.v-dash.active { border-color: var(--wox-accent, #00e5ff); box-shadow: var(--wox-shadow-accent, 0 0 10px rgba(0, 229, 255, 0.3)); }
199
+ .dash-line { width: 16px; height: 3px; background: #666; border-radius: 1px; }
200
+ button.v-dash.active .dash-line { background: var(--wox-accent, #00e5ff); }
201
+ .dash-line.dotted { background: radial-gradient(circle, currentColor 1px, transparent 1px); background-size: 4px 100%; color: #666; }
202
+ button.v-dash.active .dash-line.dotted { color: var(--wox-accent, #00e5ff); }
203
+ .dash-line.dashed { background: linear-gradient(to right, currentColor 6px, transparent 6px); background-size: 10px 100%; color: #666; }
204
+ button.v-dash.active .dash-line.dashed { color: var(--wox-accent, #00e5ff); }
205
+ .dash-line.longdash { background: linear-gradient(to right, currentColor 12px, transparent 4px); background-size: 16px 100%; color: #666; }
206
+ button.v-dash.active .dash-line.longdash { color: var(--wox-accent, #00e5ff); }
207
+ .dash-line.dotdash { background: linear-gradient(to right, currentColor 8px, transparent 4px, currentColor 2px, transparent 4px); background-size: 18px 100%; color: #666; }
208
+ button.v-dash.active .dash-line.dotdash { color: var(--wox-accent, #00e5ff); }
209
+ .dash-line.zigzag { background: repeating-linear-gradient(45deg, currentColor, currentColor 2px, transparent 2px, transparent 4px); color: #666; }
210
+ button.v-dash.active .dash-line.zigzag { color: var(--wox-accent, #00e5ff); }
211
+
212
+ .material-icons { font-family: 'Material Icons'; font-weight: normal; font-style: normal; display: inline-block; line-height: 1; text-transform: none; letter-spacing: normal; word-wrap: normal; white-space: nowrap; direction: ltr; -webkit-font-smoothing: antialiased; }
213
+ `;
214
+ class ft extends v {
215
+ constructor() {
216
+ super(...arguments);
217
+ /** @private */
218
+ n(this, "_render", () => {
219
+ const t = this.getAttribute("variant") || "icon", e = this.getAttribute("icon") || "", o = this.getAttribute("label") || "", i = this.hasAttribute("active"), s = this.hasAttribute("disabled"), r = this.getAttribute("dash") || "solid", a = this.getAttribute("color") || "", l = this.hasAttribute("glow"), c = this.hasAttribute("pulse"), x = [`v-${t}`, i ? "active" : "", l ? "glow" : "", c ? "pulse" : ""].filter(Boolean).join(" ");
220
+ let h = "";
221
+ t === "icon" ? h = e ? `<span class="material-icons">${e}</span>` : "<slot></slot>" : t === "text" ? h = (e ? `<span class="material-icons" style="font-size:14px">${e}</span>` : "") + (o || "<slot></slot>") : t === "tile" ? h = (e ? `<span class="material-icons">${e}</span>` : '<slot name="icon"></slot>') + `<span>${o}</span>` : t === "dash" && (h = `<div class="dash-line${r === "solid" ? "" : ` ${r}`}"></div>`);
222
+ const u = a ? ` data-color style="--wox-fx-color:${a}"` : "";
223
+ this.render(
224
+ bt + R,
225
+ `<button class="${x}"${u} ${s ? "disabled" : ""}>${h}</button>`
226
+ ), this.$("button").addEventListener("click", (g) => {
227
+ s || this.emit("wox-click", { originalEvent: g });
228
+ });
229
+ });
230
+ }
231
+ connectedCallback() {
232
+ this._render();
233
+ }
234
+ attributeChangedCallback() {
235
+ this.isConnected && this._render();
236
+ }
237
+ }
238
+ n(ft, "observedAttributes", ["variant", "icon", "label", "active", "disabled", "color", "size", "dash", "glow", "pulse"]);
239
+ const vt = `
240
+ :host { display: inline-block; }
241
+ .wrapper { display: flex; flex-direction: column; gap: 3px; }
242
+ label {
243
+ font-size: var(--wox-font-size-sm, 10px); color: var(--wox-text-secondary, #999);
244
+ display: flex; justify-content: space-between; cursor: default; user-select: none;
245
+ }
246
+ label.scrub { cursor: ew-resize; }
247
+ .unit { color: var(--wox-text-secondary, #999); font-size: var(--wox-font-size-sm, 10px); }
248
+ .input-wrap { position: relative; display: flex; align-items: center; }
249
+ input {
250
+ background: var(--wox-bg-input, #1a1a1d); border: 1px solid var(--wox-border, #333);
251
+ color: var(--wox-text-primary, #eee); padding: 6px 8px; border-radius: var(--wox-radius-md, 6px);
252
+ font-size: var(--wox-font-size-md, 11px); font-family: var(--wox-font, sans-serif);
253
+ width: 100%; transition: all var(--wox-transition-normal, 0.2s);
254
+ box-shadow: var(--wox-shadow-input, inset 0 1px 3px rgba(0, 0, 0, 0.2));
255
+ }
256
+ input[type="number"] { text-align: right; }
257
+ input:focus { outline: none; border-color: var(--wox-accent, #00e5ff); background: #222; box-shadow: 0 0 0 2px rgba(0, 229, 255, 0.1), var(--wox-shadow-input, inset 0 1px 3px rgba(0, 0, 0, 0.2)); }
258
+ input:disabled { opacity: 0.4; cursor: not-allowed; }
259
+ input.has-unit { padding-right: 28px; }
260
+ .suffix { position: absolute; right: 8px; font-size: var(--wox-font-size-sm, 10px); color: var(--wox-text-secondary, #999); pointer-events: none; }
261
+ `;
262
+ class wt extends v {
263
+ constructor() {
264
+ super(...arguments);
265
+ /** @private */
266
+ n(this, "_render", () => {
267
+ const t = this.getAttribute("type") || "text", e = this.getAttribute("value") || "", o = this.getAttribute("unit") || "", i = this.getAttribute("label") || "", s = this.getAttribute("min"), r = this.getAttribute("max"), a = this.getAttribute("step"), l = this.getAttribute("placeholder") || "", c = this.hasAttribute("disabled"), x = t === "number", h = x ? `${s !== null ? ` min="${s}"` : ""}${r !== null ? ` max="${r}"` : ""}${a !== null ? ` step="${a}"` : ""}` : "";
268
+ this.render(vt, `
269
+ <div class="wrapper">
270
+ ${i ? `<label class="${x ? "scrub" : ""}">${i}${o ? `<span class="unit">${o}</span>` : ""}</label>` : ""}
271
+ <div class="input-wrap">
272
+ <input type="${x ? "number" : "text"}" value="${e}" placeholder="${l}" ${h} ${c ? "disabled" : ""} class="${o && !i ? "has-unit" : ""}">
273
+ ${o && !i ? `<span class="suffix">${o}</span>` : ""}
274
+ </div>
275
+ </div>
276
+ `);
277
+ const u = this.$("input");
278
+ if (u.addEventListener("input", () => {
279
+ const g = x ? parseFloat(u.value) : u.value;
280
+ this.emit("wox-input", { value: g });
281
+ }), u.addEventListener("change", () => {
282
+ const g = x ? parseFloat(u.value) : u.value;
283
+ this.emit("wox-change", { value: g });
284
+ }), u.addEventListener("keydown", (g) => {
285
+ g.key === "Enter" && u.blur();
286
+ }), x && i) {
287
+ const g = this.$("label");
288
+ let b = 0, f = 0;
289
+ const w = (S) => {
290
+ const M = S.clientX - b, _ = parseFloat(a) || 1;
291
+ let k = f + Math.round(M / 2) * _;
292
+ s !== null && (k = Math.max(parseFloat(s), k)), r !== null && (k = Math.min(parseFloat(r), k)), u.value = k, this.emit("wox-input", { value: k });
293
+ }, y = () => {
294
+ document.removeEventListener("mousemove", w), document.removeEventListener("mouseup", y), this.emit("wox-change", { value: parseFloat(u.value) });
295
+ };
296
+ g.addEventListener("mousedown", (S) => {
297
+ c || (b = S.clientX, f = parseFloat(u.value) || 0, document.addEventListener("mousemove", w), document.addEventListener("mouseup", y), S.preventDefault());
298
+ });
299
+ }
300
+ });
301
+ }
302
+ connectedCallback() {
303
+ this._render();
304
+ }
305
+ attributeChangedCallback(t) {
306
+ if (this.isConnected) {
307
+ if (t === "value") {
308
+ const e = this.$("input");
309
+ e && document.activeElement !== this && (e.value = this.getAttribute("value") || "");
310
+ return;
311
+ }
312
+ this._render();
313
+ }
314
+ }
315
+ get value() {
316
+ const t = this.$("input");
317
+ return t ? t.value : this.getAttribute("value") || "";
318
+ }
319
+ set value(t) {
320
+ this.setAttribute("value", t);
321
+ const e = this.$("input");
322
+ e && (e.value = t);
323
+ }
324
+ }
325
+ n(wt, "observedAttributes", ["type", "value", "unit", "label", "min", "max", "step", "placeholder", "disabled"]);
326
+ const mt = `
327
+ :host {
328
+ display: inline-block;
329
+ position: relative;
330
+ min-width: 200px;
331
+ font-family: var(--wox-font, 'Inter', sans-serif);
332
+ font-size: var(--wox-font-size-base, 12px);
333
+ outline: none;
334
+ }
335
+
336
+ :host(:focus) .trigger,
337
+ :host(:focus-within) .trigger {
338
+ border-color: var(--wox-accent, #00e5ff);
339
+ box-shadow: 0 0 0 2px rgba(0, 229, 255, 0.1);
340
+ }
341
+
342
+ :host([disabled]) {
343
+ opacity: 0.4;
344
+ cursor: not-allowed;
345
+ pointer-events: none;
346
+ }
347
+
348
+ .trigger {
349
+ display: flex;
350
+ align-items: center;
351
+ justify-content: space-between;
352
+ gap: 6px;
353
+ background: var(--wox-bg-input, #1a1a1d);
354
+ border: 1px solid var(--wox-border, #333);
355
+ border-radius: var(--wox-radius-md, 6px);
356
+ padding: 6px 8px;
357
+ cursor: pointer;
358
+ min-height: 30px;
359
+ box-sizing: border-box;
360
+ color: var(--wox-text-primary, #eee);
361
+ user-select: none;
362
+ transition: border-color var(--wox-transition-fast, 0.12s);
363
+ }
364
+
365
+ .trigger:focus { outline: none; }
366
+
367
+ .selected-content {
368
+ display: flex;
369
+ align-items: center;
370
+ gap: 4px;
371
+ flex-wrap: wrap;
372
+ flex: 1;
373
+ min-width: 0;
374
+ }
375
+
376
+ .placeholder {
377
+ color: var(--wox-text-secondary, #999);
378
+ white-space: nowrap;
379
+ overflow: hidden;
380
+ text-overflow: ellipsis;
381
+ }
382
+
383
+ .single-value {
384
+ display: flex;
385
+ align-items: center;
386
+ gap: 6px;
387
+ white-space: nowrap;
388
+ overflow: hidden;
389
+ text-overflow: ellipsis;
390
+ }
391
+
392
+ .single-img {
393
+ width: 18px;
394
+ height: 18px;
395
+ border-radius: var(--wox-radius-round, 50%);
396
+ object-fit: cover;
397
+ flex-shrink: 0;
398
+ }
399
+
400
+ .tag {
401
+ display: inline-flex;
402
+ align-items: center;
403
+ gap: 3px;
404
+ padding: 1px 6px;
405
+ background: var(--wox-bg-hover, #2a2a2e);
406
+ border: 1px solid var(--wox-border-light, #444);
407
+ border-radius: var(--wox-radius-sm, 3px);
408
+ font-size: var(--wox-font-size-sm, 10px);
409
+ color: var(--wox-text-primary, #eee);
410
+ user-select: none;
411
+ }
412
+
413
+ .tag-img {
414
+ width: 14px;
415
+ height: 14px;
416
+ border-radius: var(--wox-radius-round, 50%);
417
+ object-fit: cover;
418
+ flex-shrink: 0;
419
+ }
420
+
421
+ .remove-tag {
422
+ cursor: pointer;
423
+ color: var(--wox-text-secondary, #999);
424
+ font-size: 12px;
425
+ line-height: 1;
426
+ padding: 0 1px;
427
+ }
428
+
429
+ .remove-tag:hover { color: var(--wox-danger, #f72585); }
430
+
431
+ .arrow {
432
+ width: 0;
433
+ height: 0;
434
+ border-left: 4px solid transparent;
435
+ border-right: 4px solid transparent;
436
+ border-top: 5px solid var(--wox-text-secondary, #999);
437
+ flex-shrink: 0;
438
+ transition: transform var(--wox-transition-fast, 0.12s);
439
+ }
440
+
441
+ .arrow.open { transform: rotate(180deg); }
442
+
443
+ .dropdown {
444
+ position: fixed;
445
+ z-index: var(--wox-z-dropdown, 1000);
446
+ background: var(--wox-bg-panel, #17171a);
447
+ border: 1px solid var(--wox-border, #333);
448
+ border-radius: var(--wox-radius-md, 6px);
449
+ box-shadow: var(--wox-shadow-md, 0 4px 16px rgba(0, 0, 0, 0.4));
450
+ max-height: 200px;
451
+ overflow-y: auto;
452
+ scroll-behavior: smooth;
453
+ }
454
+
455
+ .search-input {
456
+ width: 100%;
457
+ padding: 6px 10px;
458
+ background: var(--wox-bg-input, #1a1a1d);
459
+ border: none;
460
+ border-bottom: 1px solid var(--wox-border, #333);
461
+ color: var(--wox-text-primary, #eee);
462
+ font-size: var(--wox-font-size-base, 12px);
463
+ font-family: var(--wox-font, sans-serif);
464
+ outline: none;
465
+ box-sizing: border-box;
466
+ }
467
+
468
+ .option {
469
+ display: flex;
470
+ align-items: center;
471
+ gap: 8px;
472
+ padding: 6px 10px;
473
+ cursor: pointer;
474
+ color: var(--wox-text-primary, #eee);
475
+ font-size: var(--wox-font-size-base, 12px);
476
+ transition: background var(--wox-transition-fast, 0.12s);
477
+ user-select: none;
478
+ }
479
+
480
+ .option:hover { background: var(--wox-bg-hover, #2a2a2e); }
481
+
482
+ .option.focused {
483
+ background: rgba(0, 229, 255, 0.1);
484
+ color: var(--wox-accent, #00e5ff);
485
+ }
486
+
487
+ .option.selected { color: var(--wox-accent, #00e5ff); }
488
+
489
+ .option-img {
490
+ width: 20px;
491
+ height: 20px;
492
+ border-radius: var(--wox-radius-round, 50%);
493
+ object-fit: cover;
494
+ flex-shrink: 0;
495
+ }
496
+
497
+ .no-options {
498
+ padding: 8px 10px;
499
+ color: var(--wox-text-secondary, #999);
500
+ font-style: italic;
501
+ font-size: var(--wox-font-size-base, 12px);
502
+ }
503
+ `, $ = (d) => String(d).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
504
+ class _t extends v {
505
+ constructor() {
506
+ super(...arguments);
507
+ /** @type {boolean} */
508
+ n(this, "_isOpen", !1);
509
+ /** @type {boolean} */
510
+ n(this, "_openUpward", !1);
511
+ /** @type {Array<{value:string,label:string,image?:string}>} */
512
+ n(this, "_selectedOptions", []);
513
+ /** @type {Array<{value:string,label:string,image?:string}>} */
514
+ n(this, "_filteredOptions", []);
515
+ /** @type {number} */
516
+ n(this, "_focusedIndex", -1);
517
+ /** @type {string} */
518
+ n(this, "_searchValue", "");
519
+ /** @type {boolean} */
520
+ n(this, "_keyboardNavigating", !1);
521
+ /** @type {number|undefined} */
522
+ n(this, "_keyboardTimer");
523
+ /** @type {Array<{value:string,label:string,image?:string}>|null} */
524
+ n(this, "_parsedOptions", null);
525
+ // ── Private ────────────────────────────────────────────────────────────────
526
+ /** @private */
527
+ n(this, "_handleSearch", (t) => {
528
+ this._searchValue = t, this._filteredOptions = this.options.filter(
529
+ (e) => e.label.toLowerCase().includes(t.toLowerCase())
530
+ ), this._focusedIndex = -1, this._render(), this.emit("wox-search", { query: t });
531
+ });
532
+ /** @private */
533
+ n(this, "_updateFocusedOption", () => {
534
+ const t = this.$$(".option");
535
+ t.forEach((e) => e.classList.remove("focused")), this._focusedIndex >= 0 && this._focusedIndex < t.length && t[this._focusedIndex].classList.add("focused"), this._scrollToFocused();
536
+ });
537
+ /** @private */
538
+ n(this, "_scrollToFocused", () => {
539
+ this._focusedIndex < 0 || requestAnimationFrame(() => {
540
+ const t = this.$(".dropdown"), e = this.$(".option.focused");
541
+ if (!t || !e) return;
542
+ const o = t.getBoundingClientRect(), i = e.getBoundingClientRect();
543
+ i.top < o.top ? t.scrollTop -= o.top - i.top : i.bottom > o.bottom && (t.scrollTop += i.bottom - o.bottom);
544
+ });
545
+ });
546
+ /** @private */
547
+ n(this, "_calculateDropdownPosition", () => {
548
+ const t = this.$(".trigger");
549
+ if (!t) return null;
550
+ const e = t.getBoundingClientRect(), o = window.innerHeight, i = window.innerWidth, s = 200, r = 2, a = 10, l = o - e.bottom, c = e.top, x = e.width, h = Math.max(0, Math.min(e.left, i - x));
551
+ return this._openUpward ? {
552
+ bottom: o - e.top + r,
553
+ left: h,
554
+ width: x,
555
+ maxHeight: Math.max(100, Math.min(s, c - a))
556
+ } : {
557
+ top: e.bottom + r,
558
+ left: h,
559
+ width: x,
560
+ maxHeight: Math.max(100, Math.min(s, l - a))
561
+ };
562
+ });
563
+ /** @private */
564
+ n(this, "_updateDropdownPosition", () => {
565
+ requestAnimationFrame(() => {
566
+ const t = this.$(".dropdown");
567
+ if (!t) return;
568
+ const e = this._calculateDropdownPosition();
569
+ e && (t.style.top = "", t.style.bottom = "", e.top !== void 0 && (t.style.top = `${e.top}px`), e.bottom !== void 0 && (t.style.bottom = `${e.bottom}px`), t.style.left = `${e.left}px`, t.style.width = `${e.width}px`, t.style.maxHeight = `${e.maxHeight}px`);
570
+ });
571
+ });
572
+ /** @private */
573
+ n(this, "_handleKeydown", (t) => {
574
+ if (!this.disabled)
575
+ switch (t.key) {
576
+ case "ArrowDown":
577
+ if (t.preventDefault(), this._keyboardNavigating = !0, clearTimeout(this._keyboardTimer), this._keyboardTimer = window.setTimeout(() => {
578
+ this._keyboardNavigating = !1;
579
+ }, 100), !this._isOpen)
580
+ this.open();
581
+ else {
582
+ const e = this.$(".search-input");
583
+ if (this.searchable && e === this.shadowRoot.activeElement) {
584
+ this._focusedIndex = 0, e.blur(), this.focus(), this._updateFocusedOption();
585
+ return;
586
+ }
587
+ this._focusedIndex = Math.min(this._focusedIndex + 1, this._filteredOptions.length - 1), this._updateFocusedOption();
588
+ }
589
+ break;
590
+ case "ArrowUp":
591
+ if (t.preventDefault(), this._keyboardNavigating = !0, clearTimeout(this._keyboardTimer), this._keyboardTimer = window.setTimeout(() => {
592
+ this._keyboardNavigating = !1;
593
+ }, 100), this._isOpen) {
594
+ if (this._focusedIndex === 0 && this.searchable) {
595
+ this._focusedIndex = -1, this._updateFocusedOption(), requestAnimationFrame(() => {
596
+ const o = this.$(".search-input");
597
+ o && (o.focus(), o.setSelectionRange(o.value.length, o.value.length));
598
+ });
599
+ return;
600
+ }
601
+ const e = this.$(".search-input");
602
+ if (this.searchable && e === this.shadowRoot.activeElement) return;
603
+ this._focusedIndex = Math.max(this._focusedIndex - 1, -1), this._updateFocusedOption();
604
+ }
605
+ break;
606
+ case "Enter":
607
+ t.preventDefault(), this._isOpen && this._focusedIndex >= 0 && this._focusedIndex < this._filteredOptions.length ? this.selectOption(this._filteredOptions[this._focusedIndex].value) : this._isOpen || this.open();
608
+ break;
609
+ case "Escape":
610
+ t.preventDefault(), this.close();
611
+ break;
612
+ case "Tab":
613
+ this.close();
614
+ break;
615
+ }
616
+ });
617
+ /** @private */
618
+ n(this, "_render", () => {
619
+ this._filteredOptions.length === 0 && this.options.length > 0 && (this._filteredOptions = [...this.options]);
620
+ const t = this.$(".search-input") === this.shadowRoot.activeElement;
621
+ let e = "";
622
+ if (this.multiple && this._selectedOptions.length > 0)
623
+ e = this._selectedOptions.map((i) => `
624
+ <span class="tag">
625
+ ${i.image ? `<img src="${$(i.image)}" class="tag-img" alt="">` : ""}
626
+ ${$(i.label)}
627
+ <span class="remove-tag" data-value="${$(i.value)}">×</span>
628
+ </span>
629
+ `).join("");
630
+ else if (this._selectedOptions.length > 0) {
631
+ const i = this._selectedOptions[0];
632
+ e = `<span class="single-value">
633
+ ${i.image ? `<img src="${$(i.image)}" class="single-img" alt="">` : ""}
634
+ <span>${$(i.label)}</span>
635
+ </span>`;
636
+ } else
637
+ e = `<span class="placeholder">${$(this.placeholder)}</span>`;
638
+ let o = "";
639
+ if (this._isOpen) {
640
+ const i = this.searchable ? `<input type="text" class="search-input" placeholder="Search..." value="${$(this._searchValue)}">` : "", s = this._filteredOptions.length > 0 ? this._filteredOptions.map((r, a) => {
641
+ const l = this._selectedOptions.some((x) => x.value === r.value), c = a === this._focusedIndex;
642
+ return `<div
643
+ class="option${l ? " selected" : ""}${c ? " focused" : ""}"
644
+ data-value="${$(r.value)}"
645
+ >
646
+ ${r.image ? `<img src="${$(r.image)}" class="option-img" alt="">` : ""}
647
+ <span>${$(r.label)}</span>
648
+ </div>`;
649
+ }).join("") : '<div class="no-options">No options found</div>';
650
+ o = `<div class="dropdown">${i}${s}</div>`;
651
+ }
652
+ if (this.render(mt, `
653
+ <div class="trigger" tabindex="-1">
654
+ <div class="selected-content">${e}</div>
655
+ <div class="arrow${this._isOpen ? " open" : ""}"></div>
656
+ </div>
657
+ ${o}
658
+ `), this._isOpen) {
659
+ const i = this.$(".dropdown");
660
+ i && i.addEventListener("mouseleave", () => {
661
+ var s;
662
+ this._keyboardNavigating || ((s = this.$(".option.focused")) == null || s.classList.remove("focused"), this._focusedIndex = -1);
663
+ });
664
+ }
665
+ t && this.searchable && this._isOpen && requestAnimationFrame(() => {
666
+ const i = this.$(".search-input");
667
+ i && (i.focus(), i.setSelectionRange(i.value.length, i.value.length));
668
+ }), this._isOpen && this._updateDropdownPosition();
669
+ });
670
+ }
671
+ connectedCallback() {
672
+ this.hasAttribute("tabindex") || this.setAttribute("tabindex", "0"), this._boundDocumentClick = (t) => {
673
+ this.contains(t.target) || this.close();
674
+ }, this._boundWindowResize = () => {
675
+ this._isOpen && this._updateDropdownPosition();
676
+ }, this._boundWindowScroll = () => {
677
+ this._isOpen && this._updateDropdownPosition();
678
+ }, this._boundShadowClick = (t) => {
679
+ t.stopPropagation();
680
+ const e = t.target.closest(".remove-tag");
681
+ if (e) {
682
+ this.deselectOption(e.dataset.value);
683
+ return;
684
+ }
685
+ const o = t.target.closest(".option");
686
+ if (o) {
687
+ this.selectOption(o.dataset.value);
688
+ return;
689
+ }
690
+ t.target.closest(".trigger") && this.toggle();
691
+ }, this._boundShadowMouseover = (t) => {
692
+ var s;
693
+ if (this._keyboardNavigating) return;
694
+ const e = t.target.closest(".option");
695
+ if (!e) return;
696
+ const i = Array.from(this.$$(".option")).indexOf(e);
697
+ this._focusedIndex !== i && ((s = this.$(".option.focused")) == null || s.classList.remove("focused"), e.classList.add("focused"), this._focusedIndex = i);
698
+ }, this._boundShadowInput = (t) => {
699
+ t.target.classList.contains("search-input") && this._handleSearch(t.target.value);
700
+ }, document.addEventListener("click", this._boundDocumentClick), window.addEventListener("resize", this._boundWindowResize), window.addEventListener("scroll", this._boundWindowScroll, !0), this.addEventListener("keydown", this._handleKeydown), this.shadowRoot.addEventListener("click", this._boundShadowClick), this.shadowRoot.addEventListener("mouseover", this._boundShadowMouseover), this.shadowRoot.addEventListener("input", this._boundShadowInput), this._render();
701
+ }
702
+ disconnectedCallback() {
703
+ clearTimeout(this._keyboardTimer), document.removeEventListener("click", this._boundDocumentClick), window.removeEventListener("resize", this._boundWindowResize), window.removeEventListener("scroll", this._boundWindowScroll, !0), this.removeEventListener("keydown", this._handleKeydown), this.shadowRoot.removeEventListener("click", this._boundShadowClick), this.shadowRoot.removeEventListener("mouseover", this._boundShadowMouseover), this.shadowRoot.removeEventListener("input", this._boundShadowInput);
704
+ }
705
+ attributeChangedCallback(t, e, o) {
706
+ if (!(e === o || !this.isConnected)) {
707
+ if (t === "options") {
708
+ this._parsedOptions = null;
709
+ const i = this.options;
710
+ this._filteredOptions = [...i], this._selectedOptions = this._selectedOptions.filter(
711
+ (s) => i.some((r) => r.value === s.value)
712
+ );
713
+ } else if (t === "value" && o !== null) {
714
+ const i = this.options.find((s) => s.value === o);
715
+ this._selectedOptions = i ? [i] : [];
716
+ }
717
+ this._render();
718
+ }
719
+ }
720
+ // ── Getters / setters ──────────────────────────────────────────────────────
721
+ get multiple() {
722
+ return this.hasAttribute("multiple");
723
+ }
724
+ set multiple(t) {
725
+ t ? this.setAttribute("multiple", "") : this.removeAttribute("multiple");
726
+ }
727
+ get searchable() {
728
+ return this.hasAttribute("searchable");
729
+ }
730
+ set searchable(t) {
731
+ t ? this.setAttribute("searchable", "") : this.removeAttribute("searchable");
732
+ }
733
+ get placeholder() {
734
+ return this.getAttribute("placeholder") || "Select an option";
735
+ }
736
+ set placeholder(t) {
737
+ this.setAttribute("placeholder", t);
738
+ }
739
+ get disabled() {
740
+ return this.hasAttribute("disabled");
741
+ }
742
+ set disabled(t) {
743
+ t ? this.setAttribute("disabled", "") : this.removeAttribute("disabled");
744
+ }
745
+ get value() {
746
+ return this.multiple ? this._selectedOptions.map((t) => t.value) : this._selectedOptions.length > 0 ? this._selectedOptions[0].value : "";
747
+ }
748
+ set value(t) {
749
+ if (this.multiple && Array.isArray(t))
750
+ this._selectedOptions = this.options.filter((e) => t.includes(e.value));
751
+ else {
752
+ const e = this.options.find((o) => o.value === t);
753
+ this._selectedOptions = e ? [e] : [];
754
+ }
755
+ this._render();
756
+ }
757
+ get options() {
758
+ if (this._parsedOptions !== null) return this._parsedOptions;
759
+ const t = this.getAttribute("options");
760
+ if (t)
761
+ try {
762
+ return this._parsedOptions = JSON.parse(t), this._parsedOptions;
763
+ } catch (e) {
764
+ return console.error("wox-select: invalid options JSON", e), [];
765
+ }
766
+ return [];
767
+ }
768
+ set options(t) {
769
+ this._parsedOptions = null, this.setAttribute("options", JSON.stringify(t));
770
+ }
771
+ // ── Public API ─────────────────────────────────────────────────────────────
772
+ /** Opens the dropdown */
773
+ open() {
774
+ if (this.disabled) return;
775
+ this._isOpen = !0, this._focusedIndex = -1, this._filteredOptions = [...this.options];
776
+ const t = this.$(".trigger");
777
+ if (t) {
778
+ const e = t.getBoundingClientRect(), o = window.innerHeight - e.bottom, i = e.top;
779
+ this._openUpward = o < 210 && i > o;
780
+ }
781
+ this._render(), this._updateDropdownPosition(), this.searchable && requestAnimationFrame(() => {
782
+ const e = this.$(".search-input");
783
+ e && e.focus();
784
+ }), this.emit("wox-open", null);
785
+ }
786
+ /** Closes the dropdown */
787
+ close() {
788
+ this._isOpen = !1, this._openUpward = !1, this._focusedIndex = -1, this._searchValue = "", this._filteredOptions = [...this.options];
789
+ const t = this.$(".dropdown");
790
+ t && (t.style.top = "", t.style.left = "", t.style.width = "", t.style.maxHeight = ""), this._render(), this.emit("wox-close", null);
791
+ }
792
+ /** Toggles the dropdown open/closed */
793
+ toggle() {
794
+ this._isOpen ? this.close() : this.open();
795
+ }
796
+ /**
797
+ * Selects an option by value
798
+ * @param {string} value
799
+ */
800
+ selectOption(t) {
801
+ const e = this.options.find((o) => o.value === t);
802
+ e && (this.multiple ? (this._selectedOptions.find((o) => o.value === t) || this._selectedOptions.push(e), this._render()) : (this._selectedOptions = [e], this.close()), this.emit("wox-change", { value: this.value }));
803
+ }
804
+ /**
805
+ * Deselects an option by value
806
+ * @param {string} value
807
+ */
808
+ deselectOption(t) {
809
+ this._selectedOptions = this._selectedOptions.filter((e) => e.value !== t), this._render(), this.emit("wox-change", { value: this.value });
810
+ }
811
+ /**
812
+ * Returns a copy of the currently selected options
813
+ * @returns {Array<{value:string,label:string,image?:string}>}
814
+ */
815
+ getSelectedOptions() {
816
+ return [...this._selectedOptions];
817
+ }
818
+ /**
819
+ * Replaces all options and clears the selection
820
+ * @param {Array<{value:string,label:string,image?:string}>} opts
821
+ */
822
+ setOptions(t) {
823
+ this._selectedOptions = [], this._filteredOptions = [...t], this._parsedOptions = null, this.setAttribute("options", JSON.stringify(t));
824
+ }
825
+ }
826
+ n(_t, "observedAttributes", ["multiple", "searchable", "placeholder", "disabled", "value", "options"]);
827
+ const yt = `
828
+ :host { display: inline-block; width: 100%; }
829
+ .wrapper { display: flex; align-items: center; gap: var(--wox-space-lg, 12px); }
830
+ .label {
831
+ font-size: var(--wox-font-size-sm, 10px); color: var(--wox-text-secondary, #999);
832
+ font-weight: 800; letter-spacing: 0.5px; text-transform: uppercase; min-width: 50px;
833
+ user-select: none;
834
+ }
835
+ .track-wrap { flex: 1; position: relative; height: 20px; display: flex; align-items: center; cursor: pointer; }
836
+ .track { width: 100%; height: 4px; background: var(--wox-border, #333); border-radius: 2px; position: relative; overflow: hidden; }
837
+ .fill { height: 100%; background: var(--wox-accent, #00e5ff); border-radius: 2px; }
838
+ .thumb {
839
+ position: absolute; top: 50%; width: 14px; height: 14px; border-radius: 50%;
840
+ background: var(--wox-text-hi, #fff); border: 2px solid var(--wox-accent, #00e5ff);
841
+ transform: translate(-50%, -50%); box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
842
+ transition: box-shadow 0.15s; pointer-events: none;
843
+ }
844
+ .thumb.dragging { box-shadow: 0 0 8px rgba(0, 229, 255, 0.4); }
845
+ .value {
846
+ font-size: var(--wox-font-size-base, 12px); color: var(--wox-text-secondary, #999);
847
+ font-weight: 600; min-width: 35px; text-align: right; user-select: none;
848
+ }
849
+ .fill.custom-color { background: var(--wox-fx-color); }
850
+ .thumb.glow { width: 16px; height: 16px; }
851
+ `;
852
+ class kt extends v {
853
+ constructor() {
854
+ super();
855
+ /** @private — Reads config attrs (not value) */
856
+ n(this, "_getConfig", () => ({
857
+ min: parseFloat(this.getAttribute("min") ?? 0),
858
+ max: parseFloat(this.getAttribute("max") ?? 100),
859
+ step: parseFloat(this.getAttribute("step") ?? 1),
860
+ unit: this.getAttribute("unit") || ""
861
+ }));
862
+ /** @private — Format a numeric value for display */
863
+ n(this, "_formatVal", (t) => {
864
+ const { unit: e, step: o } = this._getConfig();
865
+ return e === "%" ? Math.round(t * 100) + "%" : o < 1 ? t.toFixed(2) : String(t);
866
+ });
867
+ /** @private — Update fill/thumb/value text without rebuilding DOM */
868
+ n(this, "_updateVisuals", () => {
869
+ const { min: t, max: e } = this._getConfig(), o = parseFloat(this.getAttribute("value") ?? t), i = (o - t) / (e - t) * 100, s = this.$(".fill"), r = this.$(".thumb"), a = this.$(".value");
870
+ s && (s.style.width = i + "%"), r && (r.style.left = i + "%"), a && (a.textContent = this._formatVal(o));
871
+ });
872
+ /** @private — Full DOM build (only on structural attr changes or first connect) */
873
+ n(this, "_build", () => {
874
+ const { min: t, max: e } = this._getConfig(), o = parseFloat(this.getAttribute("value") ?? t), i = this.getAttribute("label") || "", s = this.hasAttribute("show-value"), r = (o - t) / (e - t) * 100, a = this.getAttribute("color") || "", l = this.hasAttribute("glow"), c = this.hasAttribute("pulse"), x = [l ? "glow" : "", c ? "pulse" : ""].filter(Boolean).join(" "), h = a ? `--wox-fx-color:${a};border-color:${a}` : "", u = a ? " custom-color" : "";
875
+ this.render(yt + R, `
876
+ <div class="wrapper">
877
+ ${i ? `<span class="label">${i}</span>` : ""}
878
+ <div class="track-wrap">
879
+ <div class="track"><div class="fill${u}" style="width:${r}%;${a ? "--wox-fx-color:" + a : ""}"></div></div>
880
+ <div class="thumb ${x}" style="${h};left:${r}%"></div>
881
+ </div>
882
+ ${s ? `<span class="value">${this._formatVal(o)}</span>` : ""}
883
+ </div>
884
+ `), this._attachDrag();
885
+ });
886
+ /** @private — Wire up drag interaction on the track */
887
+ n(this, "_attachDrag", () => {
888
+ const { min: t, max: e, step: o, unit: i } = this._getConfig(), s = this.$(".track-wrap"), r = this.$(".fill"), a = this.$(".thumb"), l = this.$(".value"), c = (u) => {
889
+ const g = s.getBoundingClientRect();
890
+ let b = (u - g.left) / g.width;
891
+ b = Math.max(0, Math.min(1, b));
892
+ let f = t + b * (e - t);
893
+ f = Math.round(f / o) * o, f = Math.max(t, Math.min(e, f));
894
+ const w = (f - t) / (e - t) * 100;
895
+ return r.style.width = w + "%", a.style.left = w + "%", l && (i === "%" ? l.textContent = Math.round(f * 100) + "%" : l.textContent = o < 1 ? f.toFixed(2) : String(f)), f;
896
+ }, x = (u) => {
897
+ const g = c(u.clientX);
898
+ this.emit("wox-input", { value: g });
899
+ }, h = (u) => {
900
+ this._dragging = !1, a.classList.remove("dragging"), document.removeEventListener("mousemove", x), document.removeEventListener("mouseup", h);
901
+ const g = c(u.clientX);
902
+ this.setAttribute("value", g), this.emit("wox-change", { value: g });
903
+ };
904
+ s.addEventListener("mousedown", (u) => {
905
+ this._dragging = !0, a.classList.add("dragging");
906
+ const g = c(u.clientX);
907
+ this.emit("wox-input", { value: g }), document.addEventListener("mousemove", x), document.addEventListener("mouseup", h), u.preventDefault();
908
+ });
909
+ });
910
+ this._dragging = !1;
911
+ }
912
+ connectedCallback() {
913
+ this._build();
914
+ }
915
+ attributeChangedCallback(t) {
916
+ this.isConnected && (this._dragging || (t === "value" ? this._updateVisuals() : this._build()));
917
+ }
918
+ }
919
+ n(kt, "observedAttributes", ["value", "min", "max", "step", "label", "unit", "show-value", "color", "glow", "pulse"]);
920
+ const $t = `
921
+ :host { display: inline-block; }
922
+ .swatch {
923
+ width: var(--size, 24px); height: var(--size, 24px);
924
+ border-radius: var(--wox-radius-sm, 3px); cursor: pointer;
925
+ border: 1px solid rgba(0, 0, 0, 0.5);
926
+ box-shadow: var(--wox-shadow-sm, 0 2px 4px rgba(0, 0, 0, 0.3));
927
+ transition: all var(--wox-transition-fast, 0.12s);
928
+ position: relative; overflow: hidden;
929
+ }
930
+ .swatch:hover { transform: scale(1.1); border-color: var(--wox-accent, #00e5ff); }
931
+ .swatch.selected { border-color: var(--wox-text-hi, #fff); border-width: 2px; box-shadow: 0 0 15px rgba(255, 255, 255, 0.2); }
932
+ .checker {
933
+ position: absolute; inset: 0;
934
+ background: repeating-conic-gradient(#888 0% 25%, #fff 0% 50%) 0 0 / 8px 8px;
935
+ }
936
+ .color { position: absolute; inset: 0; }
937
+ `;
938
+ class Et extends v {
939
+ constructor() {
940
+ super(...arguments);
941
+ /** @private */
942
+ n(this, "_render", () => {
943
+ const t = this.getAttribute("color") || "transparent", e = this.getAttribute("size") || "24", o = this.hasAttribute("selected"), i = this.hasAttribute("glow"), s = this.hasAttribute("pulse"), r = [o ? "selected" : "", i ? "glow" : "", s ? "pulse" : ""].filter(Boolean).join(" "), a = i || s ? ` style="--wox-fx-color:${t}"` : "";
944
+ this.render(
945
+ `${$t} ${R} :host { --size: ${e}px; }`,
946
+ `<div class="swatch ${r}"${a}>
947
+ <div class="checker"></div>
948
+ <div class="color" style="background:${t}"></div>
949
+ </div>`
950
+ ), this.$(".swatch").addEventListener("click", () => {
951
+ this.emit("wox-click", { color: t });
952
+ });
953
+ });
954
+ }
955
+ connectedCallback() {
956
+ this._render();
957
+ }
958
+ attributeChangedCallback() {
959
+ this.isConnected && this._render();
960
+ }
961
+ }
962
+ n(Et, "observedAttributes", ["color", "size", "selected", "glow", "pulse"]);
963
+ const Ct = `
964
+ :host { display: inline-block; position: relative; }
965
+ .tip {
966
+ position: fixed; z-index: var(--wox-z-overlay, 10000);
967
+ background: #222; color: var(--wox-text-hi, #fff); border: 1px solid var(--wox-border-light, #444);
968
+ border-radius: var(--wox-radius-sm, 3px); padding: 4px 8px; font-size: var(--wox-font-size-md, 11px);
969
+ white-space: nowrap; pointer-events: none;
970
+ opacity: 0; transition: opacity var(--wox-transition-fast, 0.12s);
971
+ box-shadow: var(--wox-shadow-md, 0 4px 16px rgba(0, 0, 0, 0.4));
972
+ }
973
+ :host(:hover) .tip { opacity: 1; }
974
+ `;
975
+ class At extends v {
976
+ constructor() {
977
+ super(...arguments);
978
+ /** @private */
979
+ n(this, "_render", () => {
980
+ const t = this.getAttribute("text") || "";
981
+ this.render(Ct, `
982
+ <slot></slot>
983
+ ${t ? `<div class="tip">${t}</div>` : ""}
984
+ `), t && this.addEventListener("mouseenter", this._position);
985
+ });
986
+ /** @private Positions the tooltip relative to the host, flipping if it would overflow the viewport */
987
+ n(this, "_position", () => {
988
+ const t = this.shadowRoot.querySelector(".tip");
989
+ if (!t) return;
990
+ const e = 6, o = this.getAttribute("position") || "top", i = this.getBoundingClientRect(), s = t.getBoundingClientRect(), r = window.innerWidth, a = window.innerHeight, l = {
991
+ top: i.top - e - s.height >= 0,
992
+ bottom: i.bottom + e + s.height <= a,
993
+ left: i.left - e - s.width >= 0,
994
+ right: i.right + e + s.width <= r
995
+ }, c = { top: "bottom", bottom: "top", left: "right", right: "left" }, h = [o, c[o], ...["top", "bottom", "left", "right"].filter((b) => b !== o && b !== c[o])].find((b) => l[b]) || o;
996
+ let u, g;
997
+ h === "top" ? (u = i.top - e - s.height, g = i.left + i.width / 2 - s.width / 2) : h === "bottom" ? (u = i.bottom + e, g = i.left + i.width / 2 - s.width / 2) : h === "left" ? (u = i.top + i.height / 2 - s.height / 2, g = i.left - e - s.width) : (u = i.top + i.height / 2 - s.height / 2, g = i.right + e), g = Math.max(4, Math.min(g, r - s.width - 4)), u = Math.max(4, Math.min(u, a - s.height - 4)), t.style.top = `${u}px`, t.style.left = `${g}px`;
998
+ });
999
+ }
1000
+ connectedCallback() {
1001
+ this._render();
1002
+ }
1003
+ attributeChangedCallback() {
1004
+ this.isConnected && this._render();
1005
+ }
1006
+ }
1007
+ n(At, "observedAttributes", ["text", "position", "delay"]);
1008
+ const A = 220, O = 104, z = 78, D = 104, E = 192, L = 14, St = `
1009
+ :host { display: block; }
1010
+ .cp-popup {
1011
+ position: fixed; z-index: var(--wox-z-modal, 20000);
1012
+ flex-direction: column; align-items: center; gap: 12px;
1013
+ background: var(--wox-bg-panel, #17171a); border: 1px solid var(--wox-border, #333);
1014
+ border-radius: var(--wox-radius-2xl, 12px); padding: 16px;
1015
+ box-shadow: var(--wox-shadow-xl), 0 0 0 1px rgba(255, 255, 255, 0.04);
1016
+ width: 252px; user-select: none; overflow: hidden; display: none;
1017
+ }
1018
+ .cp-popup.open { display: flex; }
1019
+ .cp-header {
1020
+ width: calc(100% + 32px); margin: -16px -16px 12px -16px; padding: 10px 16px;
1021
+ background: var(--wox-bg-section-header, #22222a); border-bottom: 1px solid var(--wox-border-section, #2e2e2e);
1022
+ display: flex; justify-content: space-between; align-items: center; cursor: move;
1023
+ }
1024
+ .cp-title { font-size: var(--wox-font-size-base, 12px); font-weight: 600; color: #c0c0c0; letter-spacing: 0.5px; text-transform: uppercase; }
1025
+ .cp-close {
1026
+ background: none; border: none; color: #666; cursor: pointer; font-size: 14px;
1027
+ padding: 2px 6px; border-radius: var(--wox-radius-sm, 3px); transition: all var(--wox-transition-fast);
1028
+ }
1029
+ .cp-close:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }
1030
+ .cp-wheel { border-radius: 50%; cursor: crosshair; display: block; }
1031
+ .cp-alpha-wrap { width: ${E}px; position: relative; height: ${L}px; border-radius: 7px; cursor: pointer; }
1032
+ .cp-alpha-canvas { display: block; border-radius: 7px; width: ${E}px; height: ${L}px; }
1033
+ .cp-alpha-knob {
1034
+ position: absolute; top: -3px; width: 20px; height: 20px; border-radius: 50%;
1035
+ border: 2.5px solid #fff; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.7);
1036
+ background: transparent; pointer-events: none;
1037
+ }
1038
+ .cp-bottom { width: 100%; display: flex; align-items: center; gap: 10px; }
1039
+ .cp-preview {
1040
+ width: 34px; height: 34px; border-radius: var(--wox-radius-lg, 8px);
1041
+ border: 2px solid rgba(255, 255, 255, 0.12); flex-shrink: 0;
1042
+ background: repeating-conic-gradient(#888 0% 25%, #fff 0% 50%) 0 0 / 8px 8px;
1043
+ }
1044
+ .cp-hexwrap { flex: 1; display: flex; flex-direction: column; gap: 3px; }
1045
+ .cp-hex {
1046
+ background: #27272b; border: 1px solid var(--wox-border-light, #444);
1047
+ border-radius: var(--wox-radius-md, 6px); color: #e8e8e8;
1048
+ font-size: var(--wox-font-size-base, 12px); font-family: var(--wox-font-mono, monospace);
1049
+ padding: 6px 8px; width: 100%; transition: border var(--wox-transition-fast);
1050
+ }
1051
+ .cp-hex:focus { outline: none; border-color: var(--wox-accent, #00e5ff); }
1052
+ .cp-hex-label { font-size: var(--wox-font-size-xs, 9px); color: #555; letter-spacing: 1px; text-align: center; text-transform: uppercase; }
1053
+ `;
1054
+ class Lt extends v {
1055
+ constructor() {
1056
+ super();
1057
+ /** @private */
1058
+ n(this, "_initFromAttrs", () => {
1059
+ const t = this.getAttribute("color");
1060
+ if (t && /^#[0-9a-fA-F]{6}$/.test(t)) {
1061
+ const [o, i, s] = this._hexToRgb(t);
1062
+ [this._hue, this._sat, this._val] = this._rgbToHsv(o, i, s);
1063
+ }
1064
+ const e = this.getAttribute("alpha");
1065
+ e !== null && (this._alpha = parseFloat(e));
1066
+ });
1067
+ /** @private */
1068
+ n(this, "_build", () => {
1069
+ this._built || (this._built = !0, this.render(St, `
1070
+ <div class="cp-popup">
1071
+ <div class="cp-header">
1072
+ <span class="cp-title">Color</span>
1073
+ <button class="cp-close">&#x2715;</button>
1074
+ </div>
1075
+ <canvas class="cp-wheel" width="${A}" height="${A}"></canvas>
1076
+ <div class="cp-alpha-wrap">
1077
+ <canvas class="cp-alpha-canvas" width="${E}" height="${L}"></canvas>
1078
+ <div class="cp-alpha-knob"></div>
1079
+ </div>
1080
+ <div class="cp-bottom">
1081
+ <div class="cp-preview"></div>
1082
+ <div class="cp-hexwrap">
1083
+ <input class="cp-hex" type="text" maxlength="9" spellcheck="false">
1084
+ <span class="cp-hex-label">HEX</span>
1085
+ </div>
1086
+ </div>
1087
+ </div>
1088
+ `), this._wheelCanvas = this.$(".cp-wheel"), this._wCtx = this._wheelCanvas.getContext("2d"), this._alphaCanvas = this.$(".cp-alpha-canvas"), this._aCtx = this._alphaCanvas.getContext("2d"), this._alphaKnob = this.$(".cp-alpha-knob"), this._preview = this.$(".cp-preview"), this._hexInput = this.$(".cp-hex"), this._popup = this.$(".cp-popup"), this.$(".cp-close").addEventListener("click", () => {
1089
+ this.removeAttribute("open"), this.emit("wox-color-close", {});
1090
+ }), this._popup.addEventListener("mousedown", (t) => t.stopPropagation()), this._wheelCanvas.addEventListener("mousedown", (t) => this._wheelDown(t)), this.$(".cp-alpha-wrap").addEventListener("mousedown", (t) => {
1091
+ this._dragging = "alpha", this._doAlpha(t), t.preventDefault();
1092
+ }), document.addEventListener("mousemove", (t) => {
1093
+ this._mouseMove(t), this._dragState && (this._popup.style.left = t.clientX - this._dragState.dx + "px", this._popup.style.top = t.clientY - this._dragState.dy + "px");
1094
+ }), document.addEventListener("mouseup", () => {
1095
+ this._dragging = null, this._dragState = null;
1096
+ }), this.$(".cp-header").addEventListener("mousedown", (t) => {
1097
+ if (t.target.closest(".cp-close")) return;
1098
+ const e = this._popup.getBoundingClientRect();
1099
+ this._dragState = { dx: t.clientX - e.left, dy: t.clientY - e.top }, t.preventDefault();
1100
+ }), this._hexInput.addEventListener("input", (t) => {
1101
+ const e = t.target.value.trim();
1102
+ if (/^#[0-9a-fA-F]{6}$/.test(e)) {
1103
+ const [o, i, s] = this._hexToRgb(e);
1104
+ [this._hue, this._sat, this._val] = this._rgbToHsv(o, i, s), this._redraw(), this._emitColor();
1105
+ }
1106
+ }), this.hasAttribute("open") && (this._popup.classList.add("open"), this._initFromAttrs(), this._redraw()));
1107
+ });
1108
+ /**
1109
+ * Positions and opens the picker near an anchor element.
1110
+ * @param {HTMLElement} anchorEl - Element to anchor near
1111
+ */
1112
+ n(this, "showAt", (t) => {
1113
+ const e = t.getBoundingClientRect(), o = 252, i = 320;
1114
+ let s = e.left + e.width / 2 - o / 2, r = e.top - i - 10;
1115
+ r < 10 && (r = e.bottom + 10), s < 10 && (s = 10), s + o > window.innerWidth - 10 && (s = window.innerWidth - o - 10), r + i > window.innerHeight - 10 && (r = window.innerHeight - i - 10), this._popup.style.left = s + "px", this._popup.style.top = r + "px", this.setAttribute("open", "");
1116
+ });
1117
+ /** @private */
1118
+ n(this, "_redraw", () => {
1119
+ this._drawWheel(), this._drawAlpha(), this._updatePreview();
1120
+ });
1121
+ /** @private */
1122
+ n(this, "_drawWheel", () => {
1123
+ const t = this._wCtx, e = A, o = e / 2, i = e / 2;
1124
+ t.clearRect(0, 0, e, e);
1125
+ const s = t.createConicGradient(-Math.PI / 2, o, i);
1126
+ for (let y = 0; y <= 36; y++) s.addColorStop(y / 36, `hsl(${y * 10},100%,50%)`);
1127
+ t.fillStyle = s, t.beginPath(), t.arc(o, i, O, 0, Math.PI * 2), t.fill(), t.save(), t.globalCompositeOperation = "destination-out", t.beginPath(), t.arc(o, i, z, 0, Math.PI * 2), t.fill(), t.restore(), t.strokeStyle = "rgba(0,0,0,0.25)", t.lineWidth = 1, t.beginPath(), t.arc(o, i, O - 0.5, 0, Math.PI * 2), t.stroke(), t.beginPath(), t.arc(o, i, z + 0.5, 0, Math.PI * 2), t.stroke();
1128
+ const r = this._hue * Math.PI * 2 - Math.PI / 2, a = (O + z) / 2, l = o + Math.cos(r) * a, c = i + Math.sin(r) * a;
1129
+ t.strokeStyle = "#fff", t.lineWidth = 2.5, t.beginPath(), t.arc(l, c, 8, 0, Math.PI * 2), t.stroke(), t.strokeStyle = "rgba(0,0,0,0.4)", t.lineWidth = 1, t.beginPath(), t.arc(l, c, 8, 0, Math.PI * 2), t.stroke();
1130
+ const x = D, h = o - x / 2, u = i - x / 2, g = t.createLinearGradient(h, 0, h + x, 0);
1131
+ g.addColorStop(0, "#fff"), g.addColorStop(1, `hsl(${this._hue * 360},100%,50%)`), t.fillStyle = g, t.fillRect(h, u, x, x);
1132
+ const b = t.createLinearGradient(0, u, 0, u + x);
1133
+ b.addColorStop(0, "rgba(0,0,0,0)"), b.addColorStop(1, "rgba(0,0,0,1)"), t.fillStyle = b, t.fillRect(h, u, x, x);
1134
+ const f = h + this._sat * x, w = u + (1 - this._val) * x;
1135
+ t.strokeStyle = "#fff", t.lineWidth = 2.5, t.beginPath(), t.arc(f, w, 7, 0, Math.PI * 2), t.stroke(), t.strokeStyle = "rgba(0,0,0,0.4)", t.lineWidth = 1, t.beginPath(), t.arc(f, w, 7, 0, Math.PI * 2), t.stroke();
1136
+ });
1137
+ /** @private */
1138
+ n(this, "_drawAlpha", () => {
1139
+ const t = this._aCtx;
1140
+ t.clearRect(0, 0, E, L);
1141
+ for (let r = 0; r < E; r += 8) for (let a = 0; a < L; a += 8)
1142
+ t.fillStyle = (r / 8 + a / 8) % 2 === 0 ? "#aaa" : "#fff", t.fillRect(r, a, 8, 8);
1143
+ const [e, o, i] = this._hsvToRgb(this._hue, this._sat, this._val), s = t.createLinearGradient(0, 0, E, 0);
1144
+ s.addColorStop(0, `rgba(${e},${o},${i},0)`), s.addColorStop(1, `rgba(${e},${o},${i},1)`), t.fillStyle = s, t.fillRect(0, 0, E, L), this._alphaKnob.style.left = this._alpha * E - 7 + "px";
1145
+ });
1146
+ /** @private */
1147
+ n(this, "_updatePreview", () => {
1148
+ const [t, e, o] = this._hsvToRgb(this._hue, this._sat, this._val);
1149
+ this._preview.style.background = `rgba(${t},${e},${o},${this._alpha})`, this._hexInput.value = this._rgbToHex(t, e, o);
1150
+ });
1151
+ /** @private */
1152
+ n(this, "_wheelDown", (t) => {
1153
+ const e = this._wheelCanvas.getBoundingClientRect(), o = t.clientX - e.left, i = t.clientY - e.top, s = A / 2, r = A / 2, a = Math.hypot(o - s, i - r);
1154
+ a >= z - 2 && a <= O + 2 ? this._dragging = "ring" : a < z && (this._dragging = "sq"), this._handleWheel(o, i);
1155
+ });
1156
+ /** @private */
1157
+ n(this, "_mouseMove", (t) => {
1158
+ if (this._dragging)
1159
+ if (this._dragging === "ring" || this._dragging === "sq") {
1160
+ const e = this._wheelCanvas.getBoundingClientRect();
1161
+ this._handleWheel(t.clientX - e.left, t.clientY - e.top);
1162
+ } else this._dragging === "alpha" && this._doAlpha(t);
1163
+ });
1164
+ /** @private */
1165
+ n(this, "_handleWheel", (t, e) => {
1166
+ const o = A / 2, i = A / 2;
1167
+ if (this._dragging === "ring") {
1168
+ const s = Math.atan2(e - i, t - o) + Math.PI / 2;
1169
+ this._hue = (s / (Math.PI * 2) % 1 + 1) % 1;
1170
+ } else if (this._dragging === "sq") {
1171
+ const s = o - D / 2, r = i - D / 2;
1172
+ this._sat = Math.max(0, Math.min(1, (t - s) / D)), this._val = Math.max(0, Math.min(1, 1 - (e - r) / D));
1173
+ }
1174
+ this._redraw(), this._emitColor();
1175
+ });
1176
+ /** @private */
1177
+ n(this, "_doAlpha", (t) => {
1178
+ const e = this.$(".cp-alpha-wrap").getBoundingClientRect();
1179
+ this._alpha = Math.max(0, Math.min(1, (t.clientX - e.left) / E)), this._drawAlpha(), this._updatePreview(), this._emitColor();
1180
+ });
1181
+ /** @private */
1182
+ n(this, "_emitColor", () => {
1183
+ const [t, e, o] = this._hsvToRgb(this._hue, this._sat, this._val);
1184
+ this.emit("wox-color-change", { color: [t / 255, e / 255, o / 255, this._alpha] });
1185
+ });
1186
+ // ── Color math ──
1187
+ /** @private */
1188
+ n(this, "_hsvToRgb", (t, e, o) => {
1189
+ const i = (s) => {
1190
+ const r = (s + t * 6) % 6;
1191
+ return o - o * e * Math.max(0, Math.min(r, 4 - r, 1));
1192
+ };
1193
+ return [Math.round(i(5) * 255), Math.round(i(3) * 255), Math.round(i(1) * 255)];
1194
+ });
1195
+ /** @private */
1196
+ n(this, "_rgbToHsv", (t, e, o) => {
1197
+ t /= 255, e /= 255, o /= 255;
1198
+ const i = Math.max(t, e, o), s = i - Math.min(t, e, o);
1199
+ let r = 0;
1200
+ return s && (i === t ? r = ((e - o) / s % 6 + 6) % 6 : i === e ? r = (o - t) / s + 2 : r = (t - e) / s + 4), [r / 6, i ? s / i : 0, i];
1201
+ });
1202
+ /** @private */
1203
+ n(this, "_hexToRgb", (t) => {
1204
+ const e = parseInt(t.slice(1), 16);
1205
+ return [e >> 16 & 255, e >> 8 & 255, e & 255];
1206
+ });
1207
+ /** @private */
1208
+ n(this, "_rgbToHex", (t, e, o) => "#" + [t, e, o].map((i) => i.toString(16).padStart(2, "0")).join(""));
1209
+ this._hue = 0, this._sat = 0.8, this._val = 0.9, this._alpha = 1, this._dragging = null, this._dragState = null, this._built = !1;
1210
+ }
1211
+ connectedCallback() {
1212
+ this._build();
1213
+ }
1214
+ attributeChangedCallback(t) {
1215
+ if (this.isConnected)
1216
+ if (t === "open") {
1217
+ const e = this.$(".cp-popup");
1218
+ e && (this.hasAttribute("open") ? (e.classList.add("open"), this._initFromAttrs(), this._redraw()) : e.classList.remove("open"));
1219
+ } else (t === "color" || t === "alpha") && (this._initFromAttrs(), this.hasAttribute("open") && this._redraw());
1220
+ }
1221
+ }
1222
+ n(Lt, "observedAttributes", ["color", "alpha", "open"]);
1223
+ const H = `
1224
+ :host { display: block; }
1225
+ .item {
1226
+ color: var(--wox-text-primary, #eee); padding: 8px 12px; display: flex; align-items: center;
1227
+ gap: 8px; cursor: pointer; font-size: 11.5px; font-family: var(--wox-font, sans-serif);
1228
+ transition: all 0.2s; border-radius: var(--wox-radius-sm, 3px); user-select: none;
1229
+ }
1230
+ .item:hover { background-color: rgba(0, 229, 255, 0.1); color: var(--wox-accent, #00e5ff); }
1231
+ .item.disabled { opacity: 0.4; pointer-events: none; }
1232
+ .label { flex: 1; }
1233
+ .shortcut { font-size: var(--wox-font-size-sm, 10px); color: var(--wox-text-secondary, #999); margin-left: auto; }
1234
+ .item:hover .shortcut { color: rgba(0, 229, 255, 0.6); }
1235
+ .icon { font-size: 14px; width: 18px; text-align: center; }
1236
+ .arrow { font-size: 10px; color: var(--wox-text-secondary, #999); margin-left: 4px; }
1237
+ .separator { height: 1px; background: var(--wox-border, #333); margin: 4px 0; }
1238
+ .header {
1239
+ padding: 8px 12px; font-size: var(--wox-font-size-sm, 10px); color: var(--wox-text-secondary, #999);
1240
+ text-transform: uppercase; letter-spacing: 0.5px; font-weight: 600; cursor: default;
1241
+ }
1242
+ .material-icons { font-family: 'Material Icons'; font-weight: normal; font-style: normal; display: inline-block; line-height: 1; text-transform: none; letter-spacing: normal; word-wrap: normal; white-space: nowrap; direction: ltr; -webkit-font-smoothing: antialiased; }
1243
+ `;
1244
+ class zt extends v {
1245
+ constructor() {
1246
+ super(...arguments);
1247
+ /** @private */
1248
+ n(this, "_render", () => {
1249
+ const t = this.getAttribute("type") || "item", e = this.getAttribute("label") || "", o = this.getAttribute("shortcut") || "", i = this.getAttribute("icon") || "", s = this.hasAttribute("disabled"), r = this.hasAttribute("submenu");
1250
+ if (t === "separator") {
1251
+ this.render(H, '<div class="separator"></div>');
1252
+ return;
1253
+ }
1254
+ if (t === "header") {
1255
+ this.render(H, `<div class="header">${e}</div>`);
1256
+ return;
1257
+ }
1258
+ this.render(H, `
1259
+ <div class="item ${s ? "disabled" : ""}">
1260
+ ${i ? `<span class="icon material-icons">${i}</span>` : ""}
1261
+ <span class="label">${e}</span>
1262
+ ${o ? `<span class="shortcut">${o}</span>` : ""}
1263
+ ${r ? '<span class="arrow">&#9654;</span>' : ""}
1264
+ </div>
1265
+ `), s || this.$(".item").addEventListener("click", () => {
1266
+ this.emit("wox-select", { label: e });
1267
+ });
1268
+ });
1269
+ }
1270
+ connectedCallback() {
1271
+ this._render();
1272
+ }
1273
+ attributeChangedCallback() {
1274
+ this.isConnected && this._render();
1275
+ }
1276
+ }
1277
+ n(zt, "observedAttributes", ["label", "shortcut", "icon", "disabled", "type", "submenu"]);
1278
+ const Dt = `
1279
+ :host { display: inline-block; position: relative; }
1280
+ .trigger { color: var(--wox-text-primary, #eee); padding: 3px 8px; border-radius: var(--wox-radius-sm, 3px); cursor: pointer; font-size: var(--wox-font-size-base, 12px); display: block; user-select: none; }
1281
+ .trigger:hover { background: var(--wox-bg-hover, #2a2a2e); color: var(--wox-text-hi, #fff); }
1282
+ .dropdown {
1283
+ display: none; position: fixed; z-index: var(--wox-z-dropdown, 1000);
1284
+ background: var(--wox-bg-panel, #17171a); min-width: 160px;
1285
+ box-shadow: var(--wox-shadow-lg, 0 12px 32px rgba(0, 0, 0, 0.6));
1286
+ border: 1px solid var(--wox-border, #333); border-radius: var(--wox-radius-lg, 8px);
1287
+ overflow: hidden; padding: 4px;
1288
+ }
1289
+ .dropdown.open { display: block; }
1290
+ /* Invisible bridge to keep menu open while moving mouse */
1291
+ .dropdown::before { content: ''; position: absolute; top: -10px; left: 0; right: 0; height: 10px; }
1292
+ `;
1293
+ class Rt extends v {
1294
+ constructor() {
1295
+ super(...arguments);
1296
+ /** @private */
1297
+ n(this, "_render", () => {
1298
+ const t = this.getAttribute("label") || "", e = this.hasAttribute("open"), o = this.getAttribute("trigger") || "click";
1299
+ this.render(Dt, `
1300
+ <span class="trigger">${t}</span>
1301
+ <div class="dropdown ${e ? "open" : ""}">
1302
+ <slot></slot>
1303
+ </div>
1304
+ `);
1305
+ const i = this.$(".trigger");
1306
+ this.$(".dropdown"), o === "click" ? i.addEventListener("click", (s) => {
1307
+ s.stopPropagation(), this._toggle();
1308
+ }) : o === "hover" && (this.addEventListener("mouseenter", () => this._open()), this.addEventListener("mouseleave", () => this._close())), this._outsideClick = (s) => {
1309
+ !this.contains(s.target) && this.hasAttribute("open") && this._close();
1310
+ }, document.addEventListener("mousedown", this._outsideClick), this.addEventListener("wox-select", () => this._close());
1311
+ });
1312
+ /** @private */
1313
+ n(this, "_toggle", () => {
1314
+ this.hasAttribute("open") ? this._close() : this._open();
1315
+ });
1316
+ /** @private */
1317
+ n(this, "_open", () => {
1318
+ this.setAttribute("open", ""), this._positionDropdown();
1319
+ });
1320
+ /** @private — Position the fixed dropdown relative to the trigger, flipping if needed. */
1321
+ n(this, "_positionDropdown", () => {
1322
+ requestAnimationFrame(() => {
1323
+ const t = this.$(".trigger"), e = this.$(".dropdown");
1324
+ if (!t || !e) return;
1325
+ const o = t.getBoundingClientRect(), i = window.innerWidth, s = window.innerHeight, r = e.getBoundingClientRect();
1326
+ o.left + r.width > i ? e.style.left = `${o.right - r.width}px` : e.style.left = `${o.left}px`;
1327
+ const a = s - o.bottom, l = o.top;
1328
+ a >= r.height || a >= l ? (e.style.top = `${o.bottom}px`, e.style.bottom = "") : (e.style.top = "", e.style.bottom = `${s - o.top}px`);
1329
+ });
1330
+ });
1331
+ /** @private */
1332
+ n(this, "_close", () => {
1333
+ this.removeAttribute("open");
1334
+ });
1335
+ }
1336
+ connectedCallback() {
1337
+ this._render();
1338
+ }
1339
+ attributeChangedCallback(t) {
1340
+ if (this.isConnected) {
1341
+ if (t === "open") {
1342
+ const e = this.$(".dropdown");
1343
+ if (!e) return;
1344
+ this.hasAttribute("open") ? (e.classList.add("open"), this._positionDropdown(), this.emit("wox-open", {})) : (e.classList.remove("open"), this.emit("wox-close", {}));
1345
+ return;
1346
+ }
1347
+ this._render();
1348
+ }
1349
+ }
1350
+ disconnectedCallback() {
1351
+ this._outsideClick && document.removeEventListener("mousedown", this._outsideClick);
1352
+ }
1353
+ }
1354
+ n(Rt, "observedAttributes", ["label", "open", "trigger"]);
1355
+ const Mt = `
1356
+ :host { display: block; }
1357
+ .layer {
1358
+ display: flex; align-items: center; gap: 6px; padding: 6px 10px 6px 12px;
1359
+ margin: 4px 8px 0 8px; border-radius: var(--wox-radius-md, 6px);
1360
+ background: rgba(255, 255, 255, 0.04); border: 1px solid transparent;
1361
+ cursor: pointer; user-select: none; font-size: var(--wox-font-size-md, 11px);
1362
+ font-weight: 600; color: var(--wox-text-secondary, #999); text-transform: uppercase;
1363
+ letter-spacing: 0.5px; transition: background 0.1s, border-color 0.1s;
1364
+ }
1365
+ :host([depth="1"]) .layer { margin-left: 24px; }
1366
+ :host([depth="2"]) .layer { margin-left: 40px; }
1367
+ .layer:hover { background: rgba(255, 255, 255, 0.07); }
1368
+ .layer.selected { border-color: var(--wox-accent, #00e5ff); color: var(--wox-accent, #00e5ff); background: rgba(0, 229, 255, 0.06); }
1369
+ .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--wox-font-size-lg, 13px); color: #ccc; font-weight: 400; text-transform: none; letter-spacing: 0; }
1370
+ .layer.selected .name { color: var(--wox-text-hi, #fff); }
1371
+ .name-input {
1372
+ flex: 1; background: rgba(0, 0, 0, 0.4); border: 1px solid #4A8CFF;
1373
+ color: #fff; font-size: var(--wox-font-size-lg, 13px); font-family: var(--wox-font, sans-serif);
1374
+ padding: 2px 4px; border-radius: var(--wox-radius-sm, 3px); outline: none; width: 100%;
1375
+ }
1376
+ .type-icon { font-size: 14px; opacity: 0.6; width: 18px; text-align: center; }
1377
+ .material-icons { font-family: 'Material Icons'; font-weight: normal; font-style: normal; display: inline-block; line-height: 1; text-transform: none; letter-spacing: normal; word-wrap: normal; white-space: nowrap; direction: ltr; -webkit-font-smoothing: antialiased; }
1378
+ .toggle { display: flex; align-items: center; opacity: 0.4; cursor: pointer; transition: opacity 0.15s, color 0.15s; padding: 0 2px; font-size: 16px; }
1379
+ .toggle:hover, .toggle.on { opacity: 1; color: var(--wox-accent, #00e5ff); }
1380
+ `, Ot = {
1381
+ rectangle: "crop_square",
1382
+ ellipse: "radio_button_unchecked",
1383
+ path: "timeline",
1384
+ image: "image",
1385
+ text: "text_fields",
1386
+ group: "folder",
1387
+ layer: "layers"
1388
+ };
1389
+ class Tt extends v {
1390
+ constructor() {
1391
+ super(...arguments);
1392
+ /** @private */
1393
+ n(this, "_render", () => {
1394
+ const t = this.getAttribute("name") || "Layer", e = this.getAttribute("type") || "layer", o = this.hasAttribute("visible"), i = this.hasAttribute("locked"), s = this.hasAttribute("selected"), r = Ot[e] || "layers";
1395
+ this.render(Mt, `
1396
+ <div class="layer ${s ? "selected" : ""}">
1397
+ <span class="type-icon material-icons">${r}</span>
1398
+ <span class="name">${t}</span>
1399
+ <span class="toggle eye ${o ? "on" : ""} material-icons">${o ? "visibility" : "visibility_off"}</span>
1400
+ <span class="toggle lock ${i ? "on" : ""} material-icons">${i ? "lock" : "lock_open"}</span>
1401
+ </div>
1402
+ `), this.$(".layer").addEventListener("click", (a) => {
1403
+ a.target.closest(".toggle") || this.emit("wox-select", { name: t });
1404
+ }), this.$(".name").addEventListener("dblclick", () => this._startEditing()), this.$(".eye").addEventListener("click", (a) => {
1405
+ a.stopPropagation();
1406
+ const l = !o;
1407
+ l ? this.setAttribute("visible", "") : this.removeAttribute("visible"), this.emit("wox-visibility", { visible: l });
1408
+ }), this.$(".lock").addEventListener("click", (a) => {
1409
+ a.stopPropagation();
1410
+ const l = !i;
1411
+ l ? this.setAttribute("locked", "") : this.removeAttribute("locked"), this.emit("wox-lock", { locked: l });
1412
+ });
1413
+ });
1414
+ /** @private */
1415
+ n(this, "_startEditing", () => {
1416
+ this._editing = !0;
1417
+ const t = this.$(".name"), e = this.getAttribute("name") || "Layer", o = document.createElement("input");
1418
+ o.className = "name-input", o.value = e, t.replaceWith(o), o.focus(), o.select();
1419
+ const i = () => {
1420
+ this._editing = !1;
1421
+ const s = o.value.trim() || e;
1422
+ this.setAttribute("name", s), this._render();
1423
+ };
1424
+ o.addEventListener("blur", i), o.addEventListener("keydown", (s) => {
1425
+ s.key === "Enter" && o.blur(), s.key === "Escape" && (o.value = e, o.blur());
1426
+ });
1427
+ });
1428
+ }
1429
+ connectedCallback() {
1430
+ this._editing = !1, this._render();
1431
+ }
1432
+ attributeChangedCallback() {
1433
+ this.isConnected && !this._editing && this._render();
1434
+ }
1435
+ }
1436
+ n(Tt, "observedAttributes", ["name", "type", "visible", "locked", "selected", "depth"]);
1437
+ const It = `
1438
+ :host { display: block; border-bottom: 1px solid var(--wox-border-section, #2e2e2e); }
1439
+ .header {
1440
+ background: var(--wox-bg-section-header, #22222a); padding: 8px 16px;
1441
+ display: flex; align-items: center; gap: 10px;
1442
+ border-bottom: 1px solid var(--wox-border-section, #2e2e2e);
1443
+ font-size: var(--wox-font-size-md, 11px); color: var(--wox-text-primary, #eee);
1444
+ font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px;
1445
+ cursor: pointer; user-select: none;
1446
+ }
1447
+ .diamond {
1448
+ display: flex; align-items: center; color: var(--wox-accent, #00e5ff); font-size: 13px;
1449
+ }
1450
+ .diamond::before {
1451
+ content: ''; display: block; width: 8px; height: 8px;
1452
+ background: var(--wox-accent, #00e5ff); transform: rotate(45deg); flex-shrink: 0;
1453
+ box-shadow: 0 0 10px rgba(0, 229, 255, 0.5);
1454
+ }
1455
+ .title { font-size: var(--wox-font-size-md, 11px); font-weight: 600; text-transform: uppercase; letter-spacing: 0.8px; margin-left: 8px; }
1456
+ .chevron { margin-left: auto; font-size: 16px; transition: transform 0.2s; color: var(--wox-text-secondary, #999); }
1457
+ .chevron.collapsed { transform: rotate(-90deg); }
1458
+ .actions { margin-left: auto; display: flex; gap: 4px; align-items: center; }
1459
+ .body {
1460
+ padding: var(--wox-space-xl, 16px); overflow: hidden;
1461
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.02) 0%, rgba(255, 255, 255, 0) 100%);
1462
+ box-shadow: var(--wox-shadow-section);
1463
+ }
1464
+ .body.collapsed { display: none; }
1465
+ .material-icons { font-family: 'Material Icons'; font-weight: normal; font-style: normal; display: inline-block; line-height: 1; text-transform: none; letter-spacing: normal; word-wrap: normal; white-space: nowrap; direction: ltr; -webkit-font-smoothing: antialiased; }
1466
+ `;
1467
+ class Nt extends v {
1468
+ constructor() {
1469
+ super(...arguments);
1470
+ /** @private */
1471
+ n(this, "_render", () => {
1472
+ const t = this.getAttribute("title") || "", e = this.hasAttribute("collapsed");
1473
+ this.render(It, `
1474
+ <div class="header">
1475
+ <div class="diamond"></div>
1476
+ <span class="title">${t}</span>
1477
+ <div class="actions"><slot name="header-actions"></slot></div>
1478
+ <span class="chevron material-icons ${e ? "collapsed" : ""}">expand_more</span>
1479
+ </div>
1480
+ <div class="body ${e ? "collapsed" : ""}">
1481
+ <slot></slot>
1482
+ </div>
1483
+ `), this.$(".header").addEventListener("click", () => {
1484
+ const o = !this.hasAttribute("collapsed");
1485
+ o ? this.setAttribute("collapsed", "") : this.removeAttribute("collapsed"), this.emit("wox-toggle", { collapsed: o });
1486
+ });
1487
+ });
1488
+ }
1489
+ connectedCallback() {
1490
+ this._render();
1491
+ }
1492
+ attributeChangedCallback() {
1493
+ this.isConnected && this._render();
1494
+ }
1495
+ }
1496
+ n(Nt, "observedAttributes", ["title", "collapsed", "icon"]);
1497
+ const Pt = `
1498
+ :host { display: none; flex: 1; overflow-y: auto; overflow-x: hidden; flex-direction: column; }
1499
+ :host([active]) { display: flex; }
1500
+ `;
1501
+ class Ft extends v {
1502
+ connectedCallback() {
1503
+ this.render(Pt, "<slot></slot>");
1504
+ }
1505
+ }
1506
+ n(Ft, "observedAttributes", ["name", "label", "icon", "active"]);
1507
+ const Ht = `
1508
+ :host { display: flex; flex-direction: column; flex: 1; overflow: hidden; }
1509
+ .tab-headers {
1510
+ background: var(--wox-bg-section-header, #22222a); display: flex;
1511
+ padding: 0 4px; border-bottom: 1px solid var(--wox-border-section, #2e2e2e); flex-shrink: 0;
1512
+ }
1513
+ .tab-btn {
1514
+ flex: 1; padding: 8px 4px; background: transparent; border: none;
1515
+ border-bottom: 2px solid transparent; color: var(--wox-text-secondary, #999);
1516
+ cursor: pointer; font-size: var(--wox-font-size-base, 12px); font-family: var(--wox-font, sans-serif);
1517
+ transition: all var(--wox-transition-fast, 0.12s); margin-bottom: -1px;
1518
+ }
1519
+ .tab-btn.active { color: var(--wox-text-hi, #fff); border-bottom-color: var(--wox-accent, #00e5ff); }
1520
+ .tab-btn:hover { color: var(--wox-text-primary, #eee); }
1521
+ .body { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
1522
+
1523
+ /* Vertical left placement */
1524
+ :host([placement="left"]) { flex-direction: row; }
1525
+ :host([placement="left"]) .tab-headers {
1526
+ flex-direction: column; padding: 4px 0; border-bottom: none;
1527
+ border-right: 1px solid var(--wox-border-section, #2e2e2e);
1528
+ }
1529
+ :host([placement="left"]) .tab-btn {
1530
+ flex: none; border-bottom: none; margin-bottom: 0;
1531
+ border-right: 2px solid transparent; margin-right: -1px;
1532
+ writing-mode: vertical-rl; transform: rotate(180deg); padding: 8px 6px;
1533
+ }
1534
+ :host([placement="left"]) .tab-btn.active { border-right-color: var(--wox-accent, #00e5ff); }
1535
+
1536
+ /* Vertical right placement */
1537
+ :host([placement="right"]) { flex-direction: row-reverse; }
1538
+ :host([placement="right"]) .tab-headers {
1539
+ flex-direction: column; padding: 4px 0; border-bottom: none;
1540
+ border-left: 1px solid var(--wox-border-section, #2e2e2e);
1541
+ }
1542
+ :host([placement="right"]) .tab-btn {
1543
+ flex: none; border-bottom: none; margin-bottom: 0;
1544
+ border-left: 2px solid transparent; margin-left: -1px;
1545
+ writing-mode: vertical-rl; padding: 8px 6px;
1546
+ }
1547
+ :host([placement="right"]) .tab-btn.active { border-left-color: var(--wox-accent, #00e5ff); }
1548
+ `;
1549
+ class Bt extends v {
1550
+ constructor() {
1551
+ super(...arguments);
1552
+ /** @private */
1553
+ n(this, "_render", () => {
1554
+ this.render(Ht, `
1555
+ <div class="tab-headers"></div>
1556
+ <div class="body"><slot></slot></div>
1557
+ `), this.$("slot").addEventListener("slotchange", () => this._buildHeaders()), this._buildHeaders();
1558
+ });
1559
+ /** @private */
1560
+ n(this, "_buildHeaders", () => {
1561
+ var i;
1562
+ const t = this.$(".tab-headers");
1563
+ t.innerHTML = "";
1564
+ const e = this._getTabs(), o = this.getAttribute("active") || ((i = e[0]) == null ? void 0 : i.getAttribute("name")) || "";
1565
+ e.forEach((s) => {
1566
+ const r = s.getAttribute("name") || "", a = s.getAttribute("label") || r, l = document.createElement("button");
1567
+ l.className = "tab-btn" + (r === o ? " active" : ""), l.textContent = a, l.addEventListener("click", () => {
1568
+ this.setAttribute("active", r), this.emit("wox-tab-change", { name: r });
1569
+ }), t.appendChild(l);
1570
+ }), this._updateActive();
1571
+ });
1572
+ /** @private */
1573
+ n(this, "_updateActive", () => {
1574
+ var o;
1575
+ const t = this._getTabs(), e = this.getAttribute("active") || ((o = t[0]) == null ? void 0 : o.getAttribute("name")) || "";
1576
+ t.forEach((i) => {
1577
+ (i.getAttribute("name") || "") === e ? i.setAttribute("active", "") : i.removeAttribute("active");
1578
+ }), this.$$(".tab-btn").forEach((i, s) => {
1579
+ var a;
1580
+ const r = ((a = t[s]) == null ? void 0 : a.getAttribute("name")) || "";
1581
+ i.classList.toggle("active", r === e);
1582
+ });
1583
+ });
1584
+ /** @private */
1585
+ n(this, "_getTabs", () => [...this.querySelectorAll(":scope > wox-tab")]);
1586
+ }
1587
+ connectedCallback() {
1588
+ this._render();
1589
+ }
1590
+ attributeChangedCallback() {
1591
+ this.isConnected && this._updateActive();
1592
+ }
1593
+ }
1594
+ n(Bt, "observedAttributes", ["active", "placement"]);
1595
+ const Yt = `
1596
+ :host { display: flex; flex-direction: column; align-items: center; padding: 4px 0; border-bottom: 1px solid var(--wox-border, #333); width: 100%; }
1597
+ :host(:last-of-type) { border-bottom: none; }
1598
+ .label { font-size: var(--wox-font-size-xs, 9px); color: var(--wox-text-secondary, #999); text-transform: uppercase; letter-spacing: 0.5px; margin-top: 2px; }
1599
+ `;
1600
+ class jt extends v {
1601
+ constructor() {
1602
+ super(...arguments);
1603
+ /** @private */
1604
+ n(this, "_render", () => {
1605
+ const t = this.getAttribute("label") || "";
1606
+ this.render(Yt, `
1607
+ <slot></slot>
1608
+ ${t ? `<span class="label">${t}</span>` : ""}
1609
+ `);
1610
+ });
1611
+ }
1612
+ connectedCallback() {
1613
+ this._render();
1614
+ }
1615
+ attributeChangedCallback() {
1616
+ this.isConnected && this._render();
1617
+ }
1618
+ }
1619
+ n(jt, "observedAttributes", ["label"]);
1620
+ const Gt = `
1621
+ :host {
1622
+ display: flex; flex-direction: column; align-items: center;
1623
+ background: var(--wox-bg-toolbar, #1e1e22);
1624
+ border-right: 1px solid var(--wox-border, #333);
1625
+ padding: 6px 0; flex-shrink: 0;
1626
+ width: var(--width, 44px);
1627
+ }
1628
+ :host([position="right"]) { border-right: none; border-left: 1px solid var(--wox-border, #333); }
1629
+ `;
1630
+ class Wt extends v {
1631
+ constructor() {
1632
+ super(...arguments);
1633
+ /** @private */
1634
+ n(this, "_render", () => {
1635
+ const t = this.getAttribute("width") || "44px";
1636
+ this.render(
1637
+ `${Gt} :host { --width: ${t}; }`,
1638
+ "<slot></slot>"
1639
+ );
1640
+ });
1641
+ }
1642
+ connectedCallback() {
1643
+ this._render();
1644
+ }
1645
+ attributeChangedCallback() {
1646
+ this.isConnected && this._render();
1647
+ }
1648
+ }
1649
+ n(Wt, "observedAttributes", ["width", "position"]);
1650
+ const Xt = `
1651
+ :host {
1652
+ display: flex; flex-direction: column; flex-shrink: 0; position: relative;
1653
+ width: var(--width, 280px); height: 100%;
1654
+ background: var(--wox-bg-panel, #17171a);
1655
+ border-left: 1px solid var(--wox-border-light, #444);
1656
+ z-index: var(--wox-z-base, 1);
1657
+ }
1658
+ :host([position="left"]) { border-left: none; border-right: 1px solid var(--wox-border-light, #444); }
1659
+ .resizer {
1660
+ position: absolute; top: 0; bottom: 0; width: 5px; cursor: col-resize;
1661
+ z-index: 2; transition: background 0.2s;
1662
+ }
1663
+ :host([position="left"]) .resizer { right: -2px; }
1664
+ :host(:not([position="left"])) .resizer { left: -2px; }
1665
+ .resizer:hover { background: rgba(0, 229, 255, 0.4); }
1666
+ .content { flex: 1; overflow-y: auto; overflow-x: hidden; display: flex; flex-direction: column; }
1667
+ `;
1668
+ class qt extends v {
1669
+ constructor() {
1670
+ super(...arguments);
1671
+ /** @private */
1672
+ n(this, "_render", () => {
1673
+ const t = this.getAttribute("width") || "280px", e = this.hasAttribute("resizable");
1674
+ if (this.render(
1675
+ `${Xt} :host { --width: ${t}; }`,
1676
+ `${e ? '<div class="resizer"></div>' : ""}<div class="content"><slot></slot></div>`
1677
+ ), e) {
1678
+ const o = this.$(".resizer");
1679
+ if (!o) return;
1680
+ let i = 0, s = 0;
1681
+ const r = this.getAttribute("position") === "left", a = (c) => {
1682
+ const x = r ? c.clientX - i : i - c.clientX, h = Math.max(180, Math.min(600, s + x));
1683
+ this.style.width = h + "px";
1684
+ }, l = () => {
1685
+ document.removeEventListener("mousemove", a), document.removeEventListener("mouseup", l);
1686
+ };
1687
+ o.addEventListener("mousedown", (c) => {
1688
+ i = c.clientX, s = this.getBoundingClientRect().width, document.addEventListener("mousemove", a), document.addEventListener("mouseup", l), c.preventDefault();
1689
+ });
1690
+ }
1691
+ });
1692
+ }
1693
+ connectedCallback() {
1694
+ this._render();
1695
+ }
1696
+ attributeChangedCallback() {
1697
+ this.isConnected && this._render();
1698
+ }
1699
+ }
1700
+ n(qt, "observedAttributes", ["width", "position", "resizable"]);
1701
+ const Jt = `
1702
+ :host {
1703
+ display: flex; align-items: center; flex-shrink: 0;
1704
+ height: var(--height, 32px); background: var(--wox-bg-toolbar, #1e1e22);
1705
+ border-bottom: 1px solid var(--wox-border, #333); padding: 0 12px; gap: 2px;
1706
+ }
1707
+ ::slotted(.logo) { display: flex; align-items: center; gap: 6px; margin-right: 18px; }
1708
+ `;
1709
+ class Kt extends v {
1710
+ constructor() {
1711
+ super(...arguments);
1712
+ /** @private */
1713
+ n(this, "_render", () => {
1714
+ const t = this.getAttribute("height") || "32px";
1715
+ this.render(
1716
+ `${Jt} :host { --height: ${t}; }`,
1717
+ "<slot></slot>"
1718
+ ), this.addEventListener("keydown", (e) => {
1719
+ if (e.key !== "ArrowLeft" && e.key !== "ArrowRight") return;
1720
+ const o = [...this.querySelectorAll("wox-menu")], i = o.findIndex((r) => r.hasAttribute("open"));
1721
+ if (i < 0) return;
1722
+ o[i].removeAttribute("open");
1723
+ const s = e.key === "ArrowRight" ? (i + 1) % o.length : (i - 1 + o.length) % o.length;
1724
+ o[s].setAttribute("open", "");
1725
+ });
1726
+ });
1727
+ }
1728
+ connectedCallback() {
1729
+ this._render();
1730
+ }
1731
+ attributeChangedCallback() {
1732
+ this.isConnected && this._render();
1733
+ }
1734
+ }
1735
+ n(Kt, "observedAttributes", ["height"]);
1736
+ const Vt = `
1737
+ :host {
1738
+ display: flex; align-items: center; flex-shrink: 0;
1739
+ height: var(--height, 24px); background: var(--wox-accent, #00e5ff);
1740
+ border-top: 1px solid var(--wox-border, #333); padding: 0 12px;
1741
+ }
1742
+ .left, .center, .right { display: flex; align-items: center; gap: 8px; }
1743
+ .left { flex: 1; justify-content: flex-start; }
1744
+ .center { flex: 1; justify-content: center; }
1745
+ .right { flex: 1; justify-content: flex-end; }
1746
+ ::slotted(*) { font-size: var(--wox-font-size-md, 11px); color: rgba(255, 255, 255, 0.9); }
1747
+ `;
1748
+ class Ut extends v {
1749
+ constructor() {
1750
+ super(...arguments);
1751
+ /** @private */
1752
+ n(this, "_render", () => {
1753
+ const t = this.getAttribute("height") || "24px";
1754
+ this.render(
1755
+ `${Vt} :host { --height: ${t}; }`,
1756
+ `<div class="left"><slot name="left"></slot></div>
1757
+ <div class="center"><slot name="center"></slot></div>
1758
+ <div class="right"><slot name="right"></slot></div>`
1759
+ );
1760
+ });
1761
+ }
1762
+ connectedCallback() {
1763
+ this._render();
1764
+ }
1765
+ attributeChangedCallback() {
1766
+ this.isConnected && this._render();
1767
+ }
1768
+ }
1769
+ n(Ut, "observedAttributes", ["height"]);
1770
+ const Zt = `
1771
+ :host { display: none; }
1772
+ :host([open]) { display: block; }
1773
+ .overlay {
1774
+ position: fixed; top: 0; left: 0; right: 0; bottom: 0;
1775
+ background: rgba(0, 0, 0, 0.6); backdrop-filter: blur(2px);
1776
+ z-index: var(--wox-z-modal, 20000); display: flex;
1777
+ align-items: center; justify-content: center;
1778
+ opacity: 1; transition: opacity 0.2s ease;
1779
+ }
1780
+ .box {
1781
+ background: #1e1e24; border: 1px solid var(--wox-border, #333);
1782
+ border-radius: var(--wox-radius-2xl, 12px); padding: 24px;
1783
+ min-width: 300px; max-width: var(--width, 400px);
1784
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
1785
+ transform: translateY(0) scale(1);
1786
+ transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
1787
+ }
1788
+ .header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
1789
+ .title { font-size: var(--wox-font-size-2xl, 16px); color: var(--wox-text-hi, #fff); font-weight: 500; }
1790
+ .close-btn {
1791
+ background: none; border: none; color: #666; font-size: 18px; cursor: pointer;
1792
+ padding: 4px 8px; border-radius: var(--wox-radius-sm, 3px); transition: all 0.12s;
1793
+ }
1794
+ .close-btn:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }
1795
+ .body { color: #bbb; font-size: var(--wox-font-size-xl, 14px); margin-bottom: 24px; line-height: 1.5; }
1796
+ .footer { display: flex; justify-content: flex-end; gap: 12px; }
1797
+ .btn {
1798
+ padding: 8px 16px; border-radius: var(--wox-radius-md, 6px);
1799
+ font-family: var(--wox-font, sans-serif); font-size: var(--wox-font-size-lg, 13px);
1800
+ font-weight: 500; cursor: pointer; border: none; transition: background 0.15s;
1801
+ }
1802
+ .btn-secondary { background: var(--wox-border, #333); color: var(--wox-text-primary, #eee); }
1803
+ .btn-secondary:hover { background: var(--wox-border-light, #444); }
1804
+ .btn-primary { background: var(--wox-accent, #00e5ff); color: var(--wox-text-hi, #fff); }
1805
+ .btn-primary:hover { background: #3bb3d9; }
1806
+ `;
1807
+ class Qt extends v {
1808
+ constructor() {
1809
+ super(...arguments);
1810
+ /** @private */
1811
+ n(this, "_render", () => {
1812
+ const t = this.getAttribute("title") || "", e = !this.hasAttribute("closable") || this.getAttribute("closable") !== "false", o = this.getAttribute("width") || "400px", i = this.getAttribute("color") || "", s = this.hasAttribute("glow"), r = this.hasAttribute("pulse"), a = [s ? "glow" : "", r ? "pulse" : ""].filter(Boolean).join(" "), l = i ? ` style="--wox-fx-color:${i}"` : "";
1813
+ this.render(`${Zt} ${R} .box { --width: ${o}; }`, `
1814
+ <div class="overlay">
1815
+ <div class="box ${a}"${l}>
1816
+ <div class="header">
1817
+ <span class="title">${t}</span>
1818
+ ${e ? '<button class="close-btn">&#x2715;</button>' : ""}
1819
+ </div>
1820
+ <div class="body"><slot></slot></div>
1821
+ <div class="footer">
1822
+ <slot name="footer">
1823
+ <button class="btn btn-secondary cancel-btn">Cancel</button>
1824
+ <button class="btn btn-primary ok-btn">OK</button>
1825
+ </slot>
1826
+ </div>
1827
+ </div>
1828
+ </div>
1829
+ `), this.$(".overlay").addEventListener("click", (u) => {
1830
+ u.target === this.$(".overlay") && (this.removeAttribute("open"), this.emit("wox-close", {}));
1831
+ });
1832
+ const c = this.$(".close-btn");
1833
+ c && c.addEventListener("click", () => {
1834
+ this.removeAttribute("open"), this.emit("wox-close", {});
1835
+ });
1836
+ const x = this.$(".cancel-btn");
1837
+ x && x.addEventListener("click", () => {
1838
+ this.removeAttribute("open"), this.emit("wox-cancel", {});
1839
+ });
1840
+ const h = this.$(".ok-btn");
1841
+ h && h.addEventListener("click", () => {
1842
+ this.removeAttribute("open"), this.emit("wox-confirm", {});
1843
+ });
1844
+ });
1845
+ /** @private */
1846
+ n(this, "_keyHandler", (t) => {
1847
+ t.key === "Escape" && (this.removeAttribute("open"), this.emit("wox-close", {}));
1848
+ });
1849
+ /** @private */
1850
+ n(this, "_attachKeyHandler", () => {
1851
+ document.addEventListener("keydown", this._keyHandler);
1852
+ });
1853
+ /** @private */
1854
+ n(this, "_detachKeyHandler", () => {
1855
+ document.removeEventListener("keydown", this._keyHandler);
1856
+ });
1857
+ }
1858
+ connectedCallback() {
1859
+ this._render();
1860
+ }
1861
+ attributeChangedCallback(t) {
1862
+ this.isConnected && (t === "open" && (this.hasAttribute("open") ? this._attachKeyHandler() : this._detachKeyHandler()), this._render());
1863
+ }
1864
+ disconnectedCallback() {
1865
+ this._detachKeyHandler();
1866
+ }
1867
+ open() {
1868
+ this.setAttribute("open", "");
1869
+ }
1870
+ close() {
1871
+ this.removeAttribute("open");
1872
+ }
1873
+ get openState() {
1874
+ return this.hasAttribute("open");
1875
+ }
1876
+ set openState(t) {
1877
+ t ? this.setAttribute("open", "") : this.removeAttribute("open");
1878
+ }
1879
+ }
1880
+ n(Qt, "observedAttributes", ["open", "title", "closable", "width", "color", "glow", "pulse"]);
1881
+ const te = `
1882
+ :host { display: block; overflow: hidden; border: 1px solid var(--wox-border, #333); border-radius: var(--wox-radius-md, 6px); background: var(--wox-bg-panel, #17171a); }
1883
+
1884
+ .grid-wrapper { display: flex; flex-direction: column; height: 100%; overflow: hidden; }
1885
+
1886
+ /* ── Header ── */
1887
+ .header {
1888
+ display: flex; flex-shrink: 0;
1889
+ background: var(--wox-bg-section-header, #22222a);
1890
+ border-bottom: 1px solid var(--wox-border, #333);
1891
+ user-select: none;
1892
+ }
1893
+ .header-cell {
1894
+ position: relative; display: flex; align-items: center; gap: 4px;
1895
+ padding: 0 12px; height: 32px; flex-shrink: 0; overflow: hidden;
1896
+ font-size: var(--wox-font-size-sm, 10px); font-weight: 600;
1897
+ text-transform: uppercase; letter-spacing: 0.5px;
1898
+ color: var(--wox-text-secondary, #999); cursor: pointer;
1899
+ transition: color var(--wox-transition-fast, 0.12s);
1900
+ }
1901
+ .header-cell:hover { color: var(--wox-text-hi, #fff); }
1902
+ .header-cell.sorted { color: var(--wox-accent, #00e5ff); }
1903
+
1904
+ /* Sort arrow */
1905
+ .sort-arrow { font-size: 14px; opacity: 0; transition: opacity 0.15s, transform 0.15s; line-height: 1; }
1906
+ .header-cell:hover .sort-arrow { opacity: 0.4; }
1907
+ .header-cell.sorted .sort-arrow { opacity: 1; }
1908
+ .header-cell.sorted.desc .sort-arrow { transform: rotate(180deg); }
1909
+
1910
+ /* Resize handle */
1911
+ .resize-handle {
1912
+ position: absolute; top: 0; right: 0; width: 5px; height: 100%;
1913
+ cursor: col-resize; z-index: 1;
1914
+ }
1915
+ .resize-handle::after {
1916
+ content: ''; position: absolute; top: 6px; bottom: 6px; right: 2px; width: 1px;
1917
+ background: var(--wox-border-light, #444);
1918
+ transition: background var(--wox-transition-fast, 0.12s);
1919
+ }
1920
+ .resize-handle:hover::after, .resize-handle.active::after {
1921
+ background: var(--wox-accent, #00e5ff);
1922
+ }
1923
+
1924
+ .header-cell.dragging { opacity: 0.4; background: var(--wox-bg-hover, #2a2a2e); }
1925
+ .header-cell.drag-over { border-left: 2px solid var(--wox-accent, #00e5ff); }
1926
+
1927
+ /* ── Body ── */
1928
+ .body {
1929
+ flex: 1; overflow-y: auto; overflow-x: hidden;
1930
+ scrollbar-width: thin; scrollbar-color: var(--wox-border, #333) transparent;
1931
+ }
1932
+ .body::-webkit-scrollbar { width: 6px; }
1933
+ .body::-webkit-scrollbar-thumb { background: var(--wox-border, #333); border-radius: 3px; }
1934
+
1935
+ /* ── Rows ── */
1936
+ .row {
1937
+ display: flex; border-bottom: 1px solid var(--wox-border-section, #2e2e2e);
1938
+ transition: background var(--wox-transition-fast, 0.12s);
1939
+ cursor: default;
1940
+ }
1941
+ .row.even { background: var(--wox-bg-panel, #17171a); }
1942
+ .row.odd { background: var(--wox-bg-toolbar, #1e1e22); }
1943
+ .row:hover { background: var(--wox-bg-hover, #2a2a2e); }
1944
+
1945
+ .cell {
1946
+ display: flex; align-items: center;
1947
+ padding: 0 12px; height: 30px; flex-shrink: 0; overflow: hidden;
1948
+ font-size: var(--wox-font-size-base, 12px); color: var(--wox-text-primary, #eee);
1949
+ white-space: nowrap; text-overflow: ellipsis;
1950
+ }
1951
+ .cell.align-right { justify-content: flex-end; }
1952
+ .cell.align-center { justify-content: center; }
1953
+
1954
+ .cell-input {
1955
+ width: 100%; height: 24px; background: #222; border: 1px solid var(--wox-accent, #00e5ff);
1956
+ color: #fff; padding: 2px 4px; border-radius: 4px; font-size: 11px; outline: none;
1957
+ }
1958
+
1959
+ /* ── Empty state ── */
1960
+ .empty {
1961
+ display: flex; align-items: center; justify-content: center;
1962
+ height: 80px; color: var(--wox-text-secondary, #999);
1963
+ font-size: var(--wox-font-size-md, 11px); font-style: italic;
1964
+ }
1965
+ `, ee = 120, oe = 40;
1966
+ class Ee extends v {
1967
+ constructor() {
1968
+ super(...arguments);
1969
+ /** @private */
1970
+ n(this, "_columns", []);
1971
+ /** @private */
1972
+ n(this, "_rows", []);
1973
+ /** @private */
1974
+ n(this, "_sortKey", null);
1975
+ /** @private */
1976
+ n(this, "_sortDir", "asc");
1977
+ /** @private */
1978
+ n(this, "_colWidths", []);
1979
+ /** @private */
1980
+ n(this, "_editingCell", null);
1981
+ /** @private */
1982
+ n(this, "_getSortedRows", () => {
1983
+ if (!this._sortKey) return this._rows;
1984
+ const t = this._sortKey, e = this._sortDir === "asc" ? 1 : -1;
1985
+ return [...this._rows].sort((o, i) => {
1986
+ const s = o[t], r = i[t];
1987
+ return s == null && r == null ? 0 : s == null ? e : r == null ? -e : typeof s == "number" && typeof r == "number" ? (s - r) * e : String(s).localeCompare(String(r)) * e;
1988
+ });
1989
+ });
1990
+ /** @private */
1991
+ n(this, "_render", () => {
1992
+ const t = this._getSortedRows(), e = this._columns.map((i, s) => {
1993
+ const r = this._sortKey === i.key, a = [r ? "sorted" : "", r && this._sortDir === "desc" ? "desc" : ""].filter(Boolean).join(" "), l = i.sortable !== !1;
1994
+ return `<div class="header-cell ${a}" data-col="${s}" style="width:${this._colWidths[s]}px" draggable="true">
1995
+ <span class="label-text">${i.label || i.key}</span>
1996
+ ${l ? '<span class="sort-arrow">&#9650;</span>' : ""}
1997
+ <div class="resize-handle" data-col="${s}"></div>
1998
+ </div>`;
1999
+ }).join(""), o = t.length === 0 ? '<div class="empty">No data</div>' : t.map((i, s) => {
2000
+ const r = s % 2 === 0 ? "even" : "odd", a = this._columns.map((l, c) => {
2001
+ const x = l.align ? ` align-${l.align}` : "", h = this._editingCell && this._editingCell.rowIndex === s && this._editingCell.key === l.key, u = i[l.key] != null ? i[l.key] : "";
2002
+ return h ? `<div class="cell${x}" style="width:${this._colWidths[c]}px" data-key="${l.key}">
2003
+ <input class="cell-input" spellcheck="false">
2004
+ </div>` : `<div class="cell${x}" style="width:${this._colWidths[c]}px" data-key="${l.key}">${u}</div>`;
2005
+ }).join("");
2006
+ return `<div class="row ${r}" data-row="${s}">${a}</div>`;
2007
+ }).join("");
2008
+ if (this.render(te, `
2009
+ <div class="grid-wrapper">
2010
+ <div class="header">${e}</div>
2011
+ <div class="body">${o}</div>
2012
+ </div>
2013
+ `), this._bindEvents(), this._editingCell) {
2014
+ const i = this.$(".cell-input");
2015
+ if (i) {
2016
+ const { rowIndex: s, key: r } = this._editingCell, a = this._getSortedRows();
2017
+ let l = a[s][r] != null ? a[s][r] : "";
2018
+ const c = document.createElement("div");
2019
+ c.innerHTML = l;
2020
+ const x = c.textContent || c.innerText || l;
2021
+ i.value = x, i.dataset.oldValue = x, i.focus(), i.select(), i.addEventListener("keydown", (h) => {
2022
+ h.key === "Enter" ? this._commitEdit(i.value) : h.key === "Escape" && (this._editingCell = null, this._render());
2023
+ }), i.addEventListener("blur", () => {
2024
+ this._commitEdit(i.value);
2025
+ });
2026
+ }
2027
+ }
2028
+ });
2029
+ /** @private */
2030
+ n(this, "_commitEdit", (t) => {
2031
+ if (!this._editingCell) return;
2032
+ const { rowIndex: e, key: o } = this._editingCell, i = this.$(".cell-input"), s = i ? i.dataset.oldValue : "", a = this._getSortedRows()[e];
2033
+ s !== t && (this.emit("wox-cell-change", { row: a, key: o, oldValue: s, newValue: t }), a[o] = t), this._editingCell = null, this._render();
2034
+ });
2035
+ /** @private */
2036
+ n(this, "_bindEvents", () => {
2037
+ this.$$(".header-cell").forEach((t) => {
2038
+ t.addEventListener("click", (e) => {
2039
+ if (e.target.closest(".resize-handle")) return;
2040
+ const o = Number(t.dataset.col), i = this._columns[o];
2041
+ i.sortable !== !1 && (this._sortKey === i.key ? this._sortDir = this._sortDir === "asc" ? "desc" : "asc" : (this._sortKey = i.key, this._sortDir = "asc"), this.emit("wox-sort", { key: this._sortKey, direction: this._sortDir }), this._render());
2042
+ }), t.addEventListener("dragstart", (e) => {
2043
+ const o = t.dataset.col;
2044
+ e.dataTransfer.setData("text/plain", o), t.classList.add("dragging");
2045
+ }), t.addEventListener("dragover", (e) => {
2046
+ e.preventDefault(), t.classList.add("drag-over");
2047
+ }), t.addEventListener("dragleave", () => {
2048
+ t.classList.remove("drag-over");
2049
+ }), t.addEventListener("drop", (e) => {
2050
+ e.preventDefault(), t.classList.remove("drag-over");
2051
+ const o = parseInt(e.dataTransfer.getData("text/plain"), 10), i = parseInt(t.dataset.col, 10);
2052
+ o !== i && this._swapColumns(o, i);
2053
+ }), t.addEventListener("dragend", () => {
2054
+ t.classList.remove("dragging");
2055
+ });
2056
+ }), this.$$(".row").forEach((t) => {
2057
+ t.addEventListener("click", () => {
2058
+ const e = Number(t.dataset.row), o = this._getSortedRows();
2059
+ this.emit("wox-row-click", { row: o[e], index: e });
2060
+ }), t.querySelectorAll(".cell").forEach((e) => {
2061
+ e.addEventListener("dblclick", (o) => {
2062
+ o.stopPropagation();
2063
+ const i = Number(t.dataset.row), s = e.dataset.key, r = this._columns.findIndex((a) => a.key === s);
2064
+ this._columns[r].editable !== !1 && (this._editingCell = { rowIndex: i, key: s }, this._render());
2065
+ });
2066
+ });
2067
+ }), this.$$(".resize-handle").forEach((t) => {
2068
+ t.addEventListener("mousedown", (e) => {
2069
+ e.preventDefault(), e.stopPropagation();
2070
+ const o = Number(t.dataset.col), i = e.clientX, s = this._colWidths[o];
2071
+ t.classList.add("active");
2072
+ const r = (l) => {
2073
+ const c = l.clientX - i;
2074
+ this._colWidths[o] = Math.max(oe, s + c), this._applyWidths();
2075
+ }, a = () => {
2076
+ t.classList.remove("active"), document.removeEventListener("mousemove", r), document.removeEventListener("mouseup", a);
2077
+ };
2078
+ document.addEventListener("mousemove", r), document.addEventListener("mouseup", a);
2079
+ });
2080
+ });
2081
+ });
2082
+ /**
2083
+ * Updates column widths in-place without full re-render (for smooth resize).
2084
+ * @private
2085
+ */
2086
+ n(this, "_applyWidths", () => {
2087
+ this.$$(".header-cell").forEach((t, e) => {
2088
+ t.style.width = `${this._colWidths[e]}px`;
2089
+ }), this.$$(".row").forEach((t) => {
2090
+ t.querySelectorAll(".cell").forEach((o, i) => {
2091
+ o.style.width = `${this._colWidths[i]}px`;
2092
+ });
2093
+ });
2094
+ });
2095
+ /** @private */
2096
+ n(this, "_swapColumns", (t, e) => {
2097
+ const o = [...this._columns], i = [...this._colWidths], [s] = o.splice(t, 1);
2098
+ o.splice(e, 0, s);
2099
+ const [r] = i.splice(t, 1);
2100
+ i.splice(e, 0, r), this._columns = o, this._colWidths = i, this._render();
2101
+ });
2102
+ }
2103
+ // { rowIndex: number, key: string }
2104
+ connectedCallback() {
2105
+ this._render();
2106
+ }
2107
+ /**
2108
+ * Sets the column definitions.
2109
+ * @param {Array<{key: string, label: string, width?: number, align?: string, sortable?: boolean}>} cols
2110
+ */
2111
+ set columns(t) {
2112
+ this._columns = t || [], this._colWidths = this._columns.map((e) => e.width || ee), this._sortKey = null, this._sortDir = "asc", this._render();
2113
+ }
2114
+ /** @returns {Array} current column definitions */
2115
+ get columns() {
2116
+ return this._columns;
2117
+ }
2118
+ /**
2119
+ * Sets the row data.
2120
+ * @param {Array<Object>} data
2121
+ */
2122
+ set rows(t) {
2123
+ this._rows = t || [], this._render();
2124
+ }
2125
+ /** @returns {Array} current row data */
2126
+ get rows() {
2127
+ return this._rows;
2128
+ }
2129
+ }
2130
+ const ie = 4e3, G = 300, se = 200, ne = 8, re = 99999, nt = {
2131
+ TL: { top: "16px", left: "16px" },
2132
+ TC: { top: "16px", left: "50%", transform: "translateX(-50%)" },
2133
+ TR: { top: "16px", right: "16px" },
2134
+ BL: { bottom: "16px", left: "16px" },
2135
+ BC: { bottom: "16px", left: "50%", transform: "translateX(-50%)" },
2136
+ BR: { bottom: "16px", right: "16px" }
2137
+ }, ae = {
2138
+ TL: "translateX(-120%)",
2139
+ TC: "translateY(-120%)",
2140
+ TR: "translateX(120%)",
2141
+ BL: "translateX(-120%)",
2142
+ BC: "translateY(120%)",
2143
+ BR: "translateX(120%)"
2144
+ }, W = {
2145
+ success: { bg: "#1a2e1a", border: "#4CAF50", icon: "#66BB6A", progress: "#4CAF50", text: "#c8e6c9" },
2146
+ error: { bg: "#2e1a1a", border: "#f44336", icon: "#ef5350", progress: "#f44336", text: "#ffcdd2" },
2147
+ warning: { bg: "#2e2a1a", border: "#FF9800", icon: "#FFA726", progress: "#FF9800", text: "#ffe0b2" },
2148
+ info: { bg: "#1a222e", border: "#2196F3", icon: "#42A5F5", progress: "#2196F3", text: "#bbdefb" }
2149
+ }, X = {
2150
+ success: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>',
2151
+ error: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>',
2152
+ warning: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',
2153
+ info: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>'
2154
+ };
2155
+ let q = !1;
2156
+ const le = () => {
2157
+ if (q) return;
2158
+ q = !0;
2159
+ const d = document.createElement("style");
2160
+ d.textContent = `
2161
+ .wox-toast-container {
2162
+ position: fixed;
2163
+ display: flex;
2164
+ flex-direction: column;
2165
+ gap: ${ne}px;
2166
+ z-index: ${re};
2167
+ pointer-events: none;
2168
+ }
2169
+ .wox-toast {
2170
+ pointer-events: auto;
2171
+ display: flex;
2172
+ align-items: flex-start;
2173
+ gap: 10px;
2174
+ min-width: 280px;
2175
+ max-width: 420px;
2176
+ padding: 12px 14px;
2177
+ border-radius: var(--wox-radius-md, 6px);
2178
+ border-left: 4px solid transparent;
2179
+ box-shadow: var(--wox-shadow-md, 0 4px 16px rgba(0,0,0,.4));
2180
+ font-family: var(--wox-font, 'Inter', sans-serif);
2181
+ font-size: 14px;
2182
+ line-height: 1.4;
2183
+ overflow: hidden;
2184
+ position: relative;
2185
+ }
2186
+ .wox-toast-icon {
2187
+ flex-shrink: 0;
2188
+ display: flex;
2189
+ align-items: center;
2190
+ margin-top: 1px;
2191
+ }
2192
+ .wox-toast-message {
2193
+ flex: 1;
2194
+ word-break: break-word;
2195
+ }
2196
+ .wox-toast-close {
2197
+ flex-shrink: 0;
2198
+ background: none;
2199
+ border: none;
2200
+ cursor: pointer;
2201
+ padding: 0 0 0 4px;
2202
+ color: #666;
2203
+ font-size: 18px;
2204
+ line-height: 1;
2205
+ transition: color .15s;
2206
+ }
2207
+ .wox-toast-progress {
2208
+ position: absolute;
2209
+ bottom: 0;
2210
+ left: 0;
2211
+ height: 3px;
2212
+ border-radius: 0 0 0 var(--wox-radius-md, 6px);
2213
+ }
2214
+ `, document.head.appendChild(d);
2215
+ }, B = /* @__PURE__ */ new Set(), Y = {}, de = (d) => {
2216
+ if (Y[d]) return Y[d];
2217
+ const p = document.createElement("div");
2218
+ p.className = `wox-toast-container wox-toast-container-${d}`;
2219
+ const t = nt[d];
2220
+ return Object.assign(p.style, t), d.startsWith("B") && (p.style.flexDirection = "column-reverse"), document.body.appendChild(p), Y[d] = p, p;
2221
+ }, T = (d, p, t = {}) => {
2222
+ le();
2223
+ const e = `${d}::${p}`;
2224
+ if (B.has(e)) return;
2225
+ B.add(e);
2226
+ const {
2227
+ duration: o = ie,
2228
+ closable: i = !0,
2229
+ position: s = "BR"
2230
+ } = t, r = W[d] || W.info, a = nt[s] ? s : "BR", l = de(a), c = document.createElement("div");
2231
+ c.className = `wox-toast wox-toast-${d}`, c.style.backgroundColor = r.bg, c.style.borderLeftColor = r.border, c.style.color = r.text;
2232
+ let x = `
2233
+ <span class="wox-toast-icon" style="color:${r.icon}">${X[d] || X.info}</span>
2234
+ <span class="wox-toast-message">${p}</span>
2235
+ `;
2236
+ if (i && (x += '<button class="wox-toast-close" aria-label="Close">&times;</button>'), c.innerHTML = x, i) {
2237
+ const _ = c.querySelector(".wox-toast-close");
2238
+ _ && (_.addEventListener("mouseenter", () => {
2239
+ _.style.color = r.icon;
2240
+ }), _.addEventListener("mouseleave", () => {
2241
+ _.style.color = "#666";
2242
+ }));
2243
+ }
2244
+ let h = null;
2245
+ o > 0 && (h = document.createElement("div"), h.className = "wox-toast-progress", h.style.backgroundColor = r.progress, h.style.width = "100%", c.appendChild(h));
2246
+ const u = ae[a];
2247
+ c.animate(
2248
+ [
2249
+ { transform: u, opacity: 0 },
2250
+ { transform: "translateX(0) translateY(0)", opacity: 1 }
2251
+ ],
2252
+ { duration: G, easing: "cubic-bezier(.22,1,.36,1)", fill: "forwards" }
2253
+ ), l.appendChild(c);
2254
+ let g = null, b = o, f = 0, w = null;
2255
+ const y = () => {
2256
+ o <= 0 || (f = Date.now(), h && (w = h.animate(
2257
+ [
2258
+ { width: h.style.width },
2259
+ { width: "0%" }
2260
+ ],
2261
+ { duration: b, easing: "linear", fill: "forwards" }
2262
+ )), g = setTimeout(() => M(), b));
2263
+ }, S = () => {
2264
+ g && (clearTimeout(g), g = null), w && w.pause();
2265
+ const _ = Date.now() - f;
2266
+ if (b = Math.max(b - _, 0), h && w) {
2267
+ const k = o > 0 ? b / o * 100 : 0;
2268
+ h.style.width = `${k}%`;
2269
+ }
2270
+ }, M = () => {
2271
+ B.delete(e), g && (clearTimeout(g), g = null), w && w.cancel();
2272
+ const _ = c.animate(
2273
+ [
2274
+ { transform: "translateX(0) translateY(0)", opacity: 1 },
2275
+ { transform: u, opacity: 0 }
2276
+ ],
2277
+ { duration: G, easing: "cubic-bezier(.22,1,.36,1)", fill: "forwards" }
2278
+ );
2279
+ _.onfinish = () => {
2280
+ const k = c.offsetHeight;
2281
+ c.style.minHeight = "0", c.style.padding = "0", c.style.margin = "0", c.style.overflow = "hidden";
2282
+ const rt = c.animate(
2283
+ [{ height: `${k}px` }, { height: "0px" }],
2284
+ { duration: se, easing: "ease" }
2285
+ );
2286
+ rt.onfinish = () => c.remove();
2287
+ };
2288
+ };
2289
+ if (c.addEventListener("mouseenter", S), c.addEventListener("mouseleave", y), i) {
2290
+ const _ = c.querySelector(".wox-toast-close");
2291
+ _ && _.addEventListener("click", M);
2292
+ }
2293
+ y();
2294
+ };
2295
+ class I extends v {
2296
+ }
2297
+ /**
2298
+ * Show a success toast notification.
2299
+ * @param {string} message - Message to display
2300
+ * @param {object} [options] - { duration?: number, closable?: boolean, position?: string }
2301
+ */
2302
+ n(I, "success", (p, t) => T("success", p, t)), /**
2303
+ * Show an error toast notification.
2304
+ * @param {string} message - Message to display
2305
+ * @param {object} [options] - { duration?: number, closable?: boolean, position?: string }
2306
+ */
2307
+ n(I, "error", (p, t) => T("error", p, t)), /**
2308
+ * Show a warning toast notification.
2309
+ * @param {string} message - Message to display
2310
+ * @param {object} [options] - { duration?: number, closable?: boolean, position?: string }
2311
+ */
2312
+ n(I, "warning", (p, t) => T("warning", p, t)), /**
2313
+ * Show an info toast notification.
2314
+ * @param {string} message - Message to display
2315
+ * @param {object} [options] - { duration?: number, closable?: boolean, position?: string }
2316
+ */
2317
+ n(I, "info", (p, t) => T("info", p, t));
2318
+ const J = "wox-ctx-menu-styles", ce = "wox-ctx-menu", K = 4, pe = 3e4, he = `
2319
+ .wox-ctx-menu {
2320
+ position: fixed;
2321
+ background: var(--wox-bg-panel, #17171a);
2322
+ border: 1px solid var(--wox-border, #333);
2323
+ border-radius: var(--wox-radius-md, 6px);
2324
+ box-shadow: var(--wox-shadow-lg);
2325
+ padding: var(--wox-space-sm, 4px);
2326
+ min-width: 180px;
2327
+ z-index: ${pe};
2328
+ font-family: var(--wox-font, 'Inter', sans-serif);
2329
+ font-size: var(--wox-font-size-base, 12px);
2330
+ color: var(--wox-text-primary, #eee);
2331
+ display: none;
2332
+ }
2333
+ .wox-ctx-menu-item {
2334
+ display: flex; align-items: center; gap: 8px;
2335
+ padding: 6px 12px; border-radius: var(--wox-radius-sm, 3px);
2336
+ cursor: pointer; transition: background var(--wox-transition-fast, 0.12s ease);
2337
+ user-select: none;
2338
+ }
2339
+ .wox-ctx-menu-item:hover { background: var(--wox-bg-hover, #2a2a2e); }
2340
+ .wox-ctx-menu-item--disabled { opacity: 0.4; pointer-events: none; }
2341
+ .wox-ctx-menu-icon { width: 18px; text-align: center; flex-shrink: 0; font-size: 16px; color: var(--wox-text-secondary, #999); }
2342
+ .wox-ctx-menu-label { flex: 1; }
2343
+ .wox-ctx-menu-shortcut { font-size: var(--wox-font-size-sm, 10px); color: var(--wox-text-secondary, #999); margin-left: 16px; }
2344
+ .wox-ctx-menu-divider { height: 1px; background: var(--wox-border, #333); margin: 4px 8px; }
2345
+ `, ue = () => {
2346
+ if (document.getElementById(J)) return;
2347
+ const d = document.createElement("style");
2348
+ d.id = J, d.textContent = he, document.head.appendChild(d);
2349
+ }, m = class m extends v {
2350
+ };
2351
+ /* ── Singleton state ── */
2352
+ /** @type {HTMLDivElement|null} */
2353
+ n(m, "_el", null), /** @type {boolean} */
2354
+ n(m, "_listenersReady", !1), /**
2355
+ * Show the context menu at the pointer position.
2356
+ * @param {MouseEvent} event - The triggering mouse event (used for clientX / clientY).
2357
+ * @param {Array<{label?: string, icon?: string, action?: Function, disabled?: boolean, divider?: boolean, shortcut?: string}>} items
2358
+ */
2359
+ n(m, "show", (p, t) => {
2360
+ if (!p || !t) return;
2361
+ p.preventDefault(), p.stopPropagation(), ue();
2362
+ let e = m._el;
2363
+ e || (e = document.createElement("div"), e.id = ce, e.className = "wox-ctx-menu", document.body.appendChild(e), m._el = e), e.innerHTML = "", t.forEach((o) => {
2364
+ if (o.divider) {
2365
+ const a = document.createElement("div");
2366
+ a.className = "wox-ctx-menu-divider", e.appendChild(a);
2367
+ return;
2368
+ }
2369
+ const i = document.createElement("div");
2370
+ i.className = "wox-ctx-menu-item", o.disabled && i.classList.add("wox-ctx-menu-item--disabled");
2371
+ const s = document.createElement("i");
2372
+ s.className = "material-icons wox-ctx-menu-icon", s.textContent = o.icon || "", i.appendChild(s);
2373
+ const r = document.createElement("span");
2374
+ if (r.className = "wox-ctx-menu-label", r.textContent = o.label || "", i.appendChild(r), o.shortcut) {
2375
+ const a = document.createElement("span");
2376
+ a.className = "wox-ctx-menu-shortcut", a.textContent = o.shortcut, i.appendChild(a);
2377
+ }
2378
+ o.disabled || i.addEventListener("click", () => {
2379
+ m.hide(), o.action && o.action();
2380
+ }), e.appendChild(i);
2381
+ }), e.style.display = "block", e.style.left = `${p.clientX}px`, e.style.top = `${p.clientY}px`, requestAnimationFrame(() => {
2382
+ const o = e.getBoundingClientRect(), i = window.innerWidth, s = window.innerHeight;
2383
+ o.right > i && (e.style.left = `${i - o.width - K}px`), o.bottom > s && (e.style.top = `${s - o.height - K}px`);
2384
+ }), m._listenersReady || (document.addEventListener("click", m._onClickOutside, !0), document.addEventListener("contextmenu", m._onClickOutside, !0), document.addEventListener("keydown", m._onKeyDown, !0), m._listenersReady = !0);
2385
+ }), /**
2386
+ * Hide the context menu if it is currently visible.
2387
+ */
2388
+ n(m, "hide", () => {
2389
+ m._el && (m._el.style.display = "none");
2390
+ }), /* ── Private global handlers ── */
2391
+ /**
2392
+ * Closes the menu when clicking outside of it.
2393
+ * @param {MouseEvent} e
2394
+ * @private
2395
+ */
2396
+ n(m, "_onClickOutside", (p) => {
2397
+ m._el && m._el.style.display !== "none" && (m._el.contains(p.target) || m.hide());
2398
+ }), /**
2399
+ * Closes the menu on Escape key press.
2400
+ * @param {KeyboardEvent} e
2401
+ * @private
2402
+ */
2403
+ n(m, "_onKeyDown", (p) => {
2404
+ p.key === "Escape" && m.hide();
2405
+ });
2406
+ let V = m;
2407
+ const U = 2, Z = 40, Q = 3, C = (d) => {
2408
+ if (!d || !d.stops || d.stops.length < 2) return "";
2409
+ const t = [...d.stops].sort((e, o) => e.position - o.position).map((e) => `${e.color} ${e.position}%`).join(", ");
2410
+ return d.type === "linear" ? `linear-gradient(${d.angle}deg, ${t})` : `radial-gradient(circle, ${t})`;
2411
+ }, tt = (d) => {
2412
+ if (!d) return null;
2413
+ let p = null, t = 90, e = null;
2414
+ const o = d.match(/^linear-gradient\(\s*(\d+)deg\s*,\s*(.+)\)$/i);
2415
+ if (o && (p = "linear", t = parseInt(o[1], 10), e = o[2]), !p) {
2416
+ const a = d.match(/^radial-gradient\(\s*(?:circle|ellipse)?\s*,?\s*(.+)\)$/i);
2417
+ a && (p = "radial", e = a[1]);
2418
+ }
2419
+ if (!p || !e) return null;
2420
+ const i = [], s = /(#[0-9a-fA-F]{3,8}|rgba?\([^)]+\))\s+(\d+(?:\.\d+)?)%/g;
2421
+ let r;
2422
+ for (; (r = s.exec(e)) !== null; )
2423
+ i.push({
2424
+ color: r[1],
2425
+ position: parseFloat(r[2])
2426
+ });
2427
+ return i.length < 2 ? null : { type: p, angle: t, stops: i };
2428
+ }, xe = `
2429
+ :host { display: block; }
2430
+ .editor { padding: var(--wox-space-md, 8px) 0; }
2431
+ .bar-wrapper { position: relative; margin-bottom: var(--wox-space-md, 8px); }
2432
+ .bar {
2433
+ height: 24px; border-radius: var(--wox-radius-sm, 3px);
2434
+ border: 1px solid var(--wox-border, #333); cursor: crosshair;
2435
+ }
2436
+ .stops { position: absolute; top: 0; left: 0; right: 0; bottom: 0; pointer-events: none; }
2437
+ .handle {
2438
+ position: absolute; top: 50%; width: 14px; height: 14px;
2439
+ border: 2px solid var(--wox-bg-panel, #17171a);
2440
+ border-radius: 2px; cursor: grab; transform: translate(-50%, -50%);
2441
+ pointer-events: auto; transition: box-shadow 0.15s, transform 0.15s;
2442
+ box-shadow: 0 1px 3px rgba(0,0,0,0.6); z-index: 1;
2443
+ }
2444
+ .handle:hover { box-shadow: 0 2px 6px rgba(0,0,0,0.7); transform: translate(-50%,-50%) scale(1.15); }
2445
+ .handle.dragging { cursor: grabbing; box-shadow: 0 3px 8px rgba(0,0,0,0.8); transform: translate(-50%,-50%) scale(1.2); z-index: 10; }
2446
+ .handle.removing { opacity: 0.4; border-color: var(--wox-danger, #f72585); box-shadow: 0 2px 6px rgba(247,37,133,0.4); }
2447
+ .color-input { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; pointer-events: none; }
2448
+ .hint { font-size: var(--wox-font-size-xs, 9px); color: var(--wox-text-secondary, #999); text-align: center; margin-top: var(--wox-space-sm, 4px); }
2449
+ `;
2450
+ class Ce extends v {
2451
+ constructor() {
2452
+ super(...arguments);
2453
+ /** @private */
2454
+ n(this, "_gradient", null);
2455
+ /** @private */
2456
+ n(this, "_dragging", null);
2457
+ /** @private */
2458
+ n(this, "_justDragged", !1);
2459
+ /**
2460
+ * Builds the full editor DOM and binds all events.
2461
+ * @private
2462
+ */
2463
+ n(this, "_build", () => {
2464
+ if (!this._gradient) return;
2465
+ const t = C(this._gradient);
2466
+ this.render(xe, `
2467
+ <div class="editor">
2468
+ <div class="bar-wrapper">
2469
+ <div class="bar" style="background: ${t}"></div>
2470
+ <div class="stops"></div>
2471
+ </div>
2472
+ <div class="hint">Double-click bar to add stop &middot; Drag down to remove</div>
2473
+ </div>
2474
+ `), this._renderStops(), this._bindBarEvents();
2475
+ });
2476
+ /**
2477
+ * Updates the gradient bar preview background.
2478
+ * @private
2479
+ */
2480
+ n(this, "_updatePreview", () => {
2481
+ const t = this.$(".bar");
2482
+ t && (t.style.background = C(this._gradient));
2483
+ });
2484
+ /**
2485
+ * Emits a gradient event with current state.
2486
+ * @private
2487
+ * @param {string} eventName - Event name to dispatch
2488
+ */
2489
+ n(this, "_emitGradient", (t) => {
2490
+ this.emit(t, {
2491
+ gradient: this.gradient,
2492
+ css: C(this._gradient)
2493
+ });
2494
+ });
2495
+ /**
2496
+ * Renders all color stop handles into the stops container.
2497
+ * @private
2498
+ */
2499
+ n(this, "_renderStops", () => {
2500
+ const t = this.$(".stops");
2501
+ if (!t) return;
2502
+ t.innerHTML = "", [...this._gradient.stops].sort((o, i) => o.position - i.position).forEach((o) => {
2503
+ const i = this._gradient.stops.indexOf(o), s = document.createElement("div");
2504
+ s.className = "handle", s.style.left = o.position + "%", s.style.backgroundColor = o.color, s.dataset.index = i;
2505
+ const r = document.createElement("input");
2506
+ r.type = "color", r.value = o.color, r.className = "color-input", s.appendChild(r), s.addEventListener("click", (a) => {
2507
+ if (this._justDragged) {
2508
+ this._justDragged = !1;
2509
+ return;
2510
+ }
2511
+ a.stopPropagation(), r.click();
2512
+ }), r.addEventListener("input", (a) => {
2513
+ const l = parseInt(s.dataset.index, 10);
2514
+ this._gradient.stops[l].color = a.target.value, s.style.backgroundColor = a.target.value, this._updatePreview(), this._emitGradient("wox-gradient-input");
2515
+ }), r.addEventListener("change", () => {
2516
+ this._emitGradient("wox-gradient-change");
2517
+ }), r.addEventListener("click", (a) => a.stopPropagation()), s.addEventListener("mousedown", (a) => {
2518
+ if (a.target === r) return;
2519
+ a.preventDefault(), a.stopPropagation();
2520
+ const l = this.$(".bar");
2521
+ if (!l) return;
2522
+ const c = l.getBoundingClientRect(), x = parseInt(s.dataset.index, 10);
2523
+ this._dragging = { idx: x, startY: a.clientY }, s.classList.add("dragging");
2524
+ const h = (g) => {
2525
+ const b = (g.clientX - c.left) / c.width * 100, f = Math.max(0, Math.min(100, Math.round(b * 10) / 10));
2526
+ this._gradient.stops[x].position = f, s.style.left = f + "%", Math.abs(g.clientY - this._dragging.startY) > Z && this._gradient.stops.length > U ? s.classList.add("removing") : s.classList.remove("removing"), this._updatePreview(), this._emitGradient("wox-gradient-input");
2527
+ }, u = (g) => {
2528
+ var w;
2529
+ document.removeEventListener("mousemove", h), document.removeEventListener("mouseup", u), s.classList.remove("dragging");
2530
+ const b = Math.abs(g.clientY - this._dragging.startY);
2531
+ b > Z && this._gradient.stops.length > U ? (this._gradient.stops.splice(x, 1), this._renderStops(), this._updatePreview(), this._emitGradient("wox-gradient-change")) : this._emitGradient("wox-gradient-change");
2532
+ const f = Math.abs(g.clientX - (c.left + (((w = this._gradient.stops[x]) == null ? void 0 : w.position) || 0) * c.width / 100));
2533
+ (b > Q || f > Q) && (this._justDragged = !0), this._dragging = null;
2534
+ };
2535
+ document.addEventListener("mousemove", h), document.addEventListener("mouseup", u);
2536
+ }), t.appendChild(s);
2537
+ });
2538
+ });
2539
+ /**
2540
+ * Binds the double-click event on the gradient bar to add new stops.
2541
+ * @private
2542
+ */
2543
+ n(this, "_bindBarEvents", () => {
2544
+ const t = this.$(".bar");
2545
+ t && t.addEventListener("dblclick", (e) => {
2546
+ const o = t.getBoundingClientRect(), i = Math.round((e.clientX - o.left) / o.width * 100), s = Math.max(0, Math.min(100, i)), r = [...this._gradient.stops].sort((l, c) => l.position - c.position);
2547
+ let a = "#888888";
2548
+ for (let l = 0; l < r.length - 1; l++)
2549
+ if (s >= r[l].position && s <= r[l + 1].position) {
2550
+ a = r[l].color;
2551
+ break;
2552
+ }
2553
+ this._gradient.stops.push({ color: a, position: s }), this._renderStops(), this._updatePreview(), this._emitGradient("wox-gradient-change");
2554
+ });
2555
+ });
2556
+ }
2557
+ connectedCallback() {
2558
+ this._gradient && this._build();
2559
+ }
2560
+ /**
2561
+ * Sets the gradient data and re-renders the editor.
2562
+ * @param {{ type: string, angle: number, stops: Array<{color: string, position: number}> }} g
2563
+ */
2564
+ set gradient(t) {
2565
+ this._gradient = JSON.parse(JSON.stringify(t)), this.isConnected && this._build();
2566
+ }
2567
+ /**
2568
+ * Returns a deep copy of the current gradient data.
2569
+ * @returns {{ type: string, angle: number, stops: Array<{color: string, position: number}> }|null}
2570
+ */
2571
+ get gradient() {
2572
+ return this._gradient ? JSON.parse(JSON.stringify(this._gradient)) : null;
2573
+ }
2574
+ }
2575
+ const et = "wox_gradients", ge = "grad_preset_", be = [
2576
+ { id: "grad_preset_sunset", name: "Sunset", type: "linear", angle: 135, stops: [{ color: "#ff512f", position: 0 }, { color: "#f09819", position: 100 }] },
2577
+ { id: "grad_preset_ocean", name: "Ocean", type: "linear", angle: 135, stops: [{ color: "#2193b0", position: 0 }, { color: "#6dd5ed", position: 100 }] },
2578
+ { id: "grad_preset_forest", name: "Forest", type: "linear", angle: 135, stops: [{ color: "#11998e", position: 0 }, { color: "#38ef7d", position: 100 }] },
2579
+ { id: "grad_preset_purple_haze", name: "Purple Haze", type: "linear", angle: 135, stops: [{ color: "#7b4397", position: 0 }, { color: "#dc2430", position: 100 }] },
2580
+ { id: "grad_preset_midnight", name: "Midnight", type: "linear", angle: 135, stops: [{ color: "#232526", position: 0 }, { color: "#414345", position: 100 }] },
2581
+ { id: "grad_preset_peach", name: "Peach", type: "linear", angle: 135, stops: [{ color: "#ffecd2", position: 0 }, { color: "#fcb69f", position: 100 }] }
2582
+ ], fe = `
2583
+ :host { display: block; }
2584
+ .selector { position: relative; }
2585
+ .current {
2586
+ display: flex; align-items: center; gap: 8px;
2587
+ padding: 6px 8px; border: 1px solid var(--wox-border, #333);
2588
+ border-radius: var(--wox-radius-sm, 3px); cursor: pointer;
2589
+ background: var(--wox-bg-input, #1a1a1d); transition: border-color var(--wox-transition-fast);
2590
+ }
2591
+ .current:hover { border-color: var(--wox-accent, #00e5ff); }
2592
+ .selector.open .current { border-color: var(--wox-accent, #00e5ff); }
2593
+ .preview { width: 32px; height: 20px; border-radius: 3px; border: 1px solid var(--wox-border, #333); flex-shrink: 0; }
2594
+ .label { flex: 1; font-size: var(--wox-font-size-lg, 13px); color: var(--wox-text-primary, #eee); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
2595
+ .chevron { font-size: 10px; color: var(--wox-text-secondary, #999); flex-shrink: 0; }
2596
+ .dropdown {
2597
+ display: none; position: fixed;
2598
+ z-index: var(--wox-z-dropdown, 1000); background: var(--wox-bg-panel, #17171a);
2599
+ border: 1px solid var(--wox-border, #333);
2600
+ border-radius: var(--wox-radius-sm, 3px);
2601
+ box-shadow: var(--wox-shadow-md); max-height: 280px; overflow-y: auto;
2602
+ }
2603
+ .selector.open .dropdown { display: block; }
2604
+ .dropdown-item {
2605
+ display: flex; align-items: center; gap: 8px; padding: 8px 10px;
2606
+ cursor: pointer; transition: background var(--wox-transition-fast);
2607
+ }
2608
+ .dropdown-item:hover { background: var(--wox-bg-hover, #2a2a2e); }
2609
+ .dropdown-item-preview { width: 40px; height: 20px; border-radius: 3px; border: 1px solid var(--wox-border, #333); flex-shrink: 0; }
2610
+ .dropdown-item-label { flex: 1; font-size: var(--wox-font-size-lg, 13px); color: var(--wox-text-primary, #eee); }
2611
+ .dropdown-item-btn {
2612
+ display: none; background: none; border: none; color: var(--wox-text-secondary, #999);
2613
+ font-size: 14px; cursor: pointer; padding: 0 4px; line-height: 1; transition: color var(--wox-transition-fast);
2614
+ }
2615
+ .dropdown-item-btn.delete-btn { font-size: 16px; }
2616
+ .dropdown-item:hover .dropdown-item-btn { display: block; }
2617
+ .dropdown-item-btn:hover { color: var(--wox-accent, #00e5ff); }
2618
+ .dropdown-item-btn.delete-btn:hover { color: var(--wox-danger, #f72585); }
2619
+ .dropdown-custom { border-top: 1px solid var(--wox-border, #333); }
2620
+ .dropdown-custom .dropdown-item-label { color: var(--wox-accent, #00e5ff); font-weight: 500; }
2621
+ .solid-input { position: absolute; opacity: 0; pointer-events: none; }
2622
+
2623
+ /* Controls */
2624
+ .controls { margin-top: 10px; display: none; }
2625
+ .controls.visible { display: block; }
2626
+ .ctrl-label { font-size: var(--wox-font-size-sm, 10px); color: var(--wox-text-secondary, #999); font-weight: 800; letter-spacing: 0.5px; text-transform: uppercase; min-width: 40px; }
2627
+ .type-row { display: flex; align-items: center; gap: 8px; margin-bottom: var(--wox-space-lg, 12px); }
2628
+ .type-toggle { display: flex; gap: var(--wox-space-sm, 4px); background: var(--wox-bg-input, #1a1a1d); padding: 3px; border-radius: var(--wox-radius-sm, 3px); }
2629
+ .type-btn {
2630
+ background: transparent; border: none; padding: 4px 14px; cursor: pointer;
2631
+ border-radius: 3px; font-size: var(--wox-font-size-base, 12px); font-weight: 500;
2632
+ color: var(--wox-text-secondary, #999); transition: all var(--wox-transition-fast);
2633
+ font-family: var(--wox-font, 'Inter', sans-serif);
2634
+ }
2635
+ .type-btn:hover { color: var(--wox-text-primary, #eee); background: var(--wox-bg-hover, #2a2a2e); }
2636
+ .type-btn.active { background: var(--wox-accent, #00e5ff); color: var(--wox-text-hi, #fff); }
2637
+ .angle-row, .speed-row { margin-bottom: var(--wox-space-lg, 12px); }
2638
+ .anim-type-row { display: flex; align-items: center; gap: 8px; margin-bottom: var(--wox-space-lg, 12px); }
2639
+ .anim-select {
2640
+ flex: 1; padding: 4px 8px; border: 1px solid var(--wox-border, #333);
2641
+ border-radius: var(--wox-radius-sm, 3px); font-size: var(--wox-font-size-base, 12px);
2642
+ background: var(--wox-bg-input, #1a1a1d); color: var(--wox-text-primary, #eee); cursor: pointer;
2643
+ font-family: var(--wox-font, 'Inter', sans-serif);
2644
+ }
2645
+
2646
+ /* Modal body */
2647
+ .editor-body { min-width: 400px; }
2648
+ .name-row { display: flex; align-items: center; gap: 8px; margin-top: var(--wox-space-xl, 16px); }
2649
+ .name-input {
2650
+ flex: 1; padding: 6px 8px; border: 1px solid var(--wox-border, #333);
2651
+ border-radius: var(--wox-radius-sm, 3px); font-size: var(--wox-font-size-base, 12px);
2652
+ background: var(--wox-bg-input, #1a1a1d); color: var(--wox-text-primary, #eee);
2653
+ font-family: var(--wox-font, 'Inter', sans-serif);
2654
+ }
2655
+ .name-input:focus { outline: none; border-color: var(--wox-accent, #00e5ff); }
2656
+
2657
+ /* Footer buttons */
2658
+ .btn {
2659
+ padding: 8px 16px; border-radius: var(--wox-radius-md, 6px);
2660
+ font-family: var(--wox-font, sans-serif); font-size: var(--wox-font-size-lg, 13px);
2661
+ font-weight: 500; cursor: pointer; border: none; transition: background var(--wox-transition-fast);
2662
+ }
2663
+ .btn-secondary { background: var(--wox-border, #333); color: var(--wox-text-primary, #eee); }
2664
+ .btn-secondary:hover { background: var(--wox-border-light, #444); }
2665
+ .btn-primary { background: var(--wox-accent, #00e5ff); color: var(--wox-text-hi, #fff); }
2666
+ .btn-primary:hover { background: #3bb3d9; }
2667
+ `, N = () => "grad_" + Date.now().toString(36) + "_" + Math.random().toString(36).slice(2, 7), ot = (d) => d ? d.startsWith("linear-gradient") || d.startsWith("radial-gradient") : !1;
2668
+ class ve extends v {
2669
+ constructor() {
2670
+ super(...arguments);
2671
+ /** @private — Current CSS value (hex or gradient string) */
2672
+ n(this, "_value", "#ffffff");
2673
+ /** @private — Parsed gradient object or null for solid colors */
2674
+ n(this, "_gradient", null);
2675
+ /** @private — Animation speed 0-10 */
2676
+ n(this, "_animationSpeed", 0);
2677
+ /** @private — Animation type: 'pingpong' or 'cycle' */
2678
+ n(this, "_animationType", "pingpong");
2679
+ /** @private — Whether the dropdown is currently open */
2680
+ n(this, "_open", !1);
2681
+ /** @private — Saved gradients array */
2682
+ n(this, "_gradients", []);
2683
+ /** @private — Gradient currently being edited in the modal */
2684
+ n(this, "_editingGradient", null);
2685
+ /** @private — Name captured from the modal name input */
2686
+ n(this, "_editingName", "");
2687
+ /**
2688
+ * Read attributes and update internal state.
2689
+ * @private
2690
+ */
2691
+ n(this, "_syncFromAttributes", () => {
2692
+ const t = this.getAttribute("value");
2693
+ t && (this._value = t, this._gradient = ot(t) ? tt(t) : null);
2694
+ const e = this.getAttribute("animation-speed");
2695
+ e !== null && (this._animationSpeed = parseInt(e, 10) || 0);
2696
+ const o = this.getAttribute("animation-type");
2697
+ o && (this._animationType = o);
2698
+ });
2699
+ /**
2700
+ * Load gradients from localStorage, or seed with defaults.
2701
+ * @private
2702
+ */
2703
+ n(this, "_loadGradients", () => {
2704
+ try {
2705
+ const t = localStorage.getItem(et);
2706
+ if (t) {
2707
+ this._gradients = JSON.parse(t);
2708
+ return;
2709
+ }
2710
+ } catch {
2711
+ }
2712
+ this._gradients = be.map((t) => ({ ...t, stops: t.stops.map((e) => ({ ...e })) })), this._persistGradients();
2713
+ });
2714
+ /**
2715
+ * Persist gradients array to localStorage.
2716
+ * @private
2717
+ */
2718
+ n(this, "_persistGradients", () => {
2719
+ try {
2720
+ localStorage.setItem(et, JSON.stringify(this._gradients));
2721
+ } catch {
2722
+ }
2723
+ });
2724
+ /**
2725
+ * Upsert a gradient (update if id exists, insert otherwise) and persist.
2726
+ * @private
2727
+ * @param {Object} gradient - Gradient object with id, name, type, angle, stops
2728
+ */
2729
+ n(this, "_save", (t) => {
2730
+ const e = this._gradients.findIndex((o) => o.id === t.id);
2731
+ e >= 0 ? this._gradients[e] = t : this._gradients.push(t), this._persistGradients();
2732
+ });
2733
+ /**
2734
+ * Delete a gradient by ID and persist.
2735
+ * @private
2736
+ * @param {string} id - Gradient ID to remove
2737
+ */
2738
+ n(this, "_delete", (t) => {
2739
+ this._gradients = this._gradients.filter((e) => e.id !== t), this._persistGradients();
2740
+ });
2741
+ /**
2742
+ * Find a gradient by its ID.
2743
+ * @private
2744
+ * @param {string} id
2745
+ * @returns {Object|undefined}
2746
+ */
2747
+ n(this, "_getById", (t) => this._gradients.find((e) => e.id === t));
2748
+ /**
2749
+ * Derive a human-readable label from a CSS value.
2750
+ * @private
2751
+ * @param {string} value
2752
+ * @returns {string}
2753
+ */
2754
+ n(this, "_labelForValue", (t) => {
2755
+ if (!t) return "None";
2756
+ if (ot(t)) {
2757
+ for (const e of this._gradients)
2758
+ if (C(e) === t) return e.name;
2759
+ return "Custom Gradient";
2760
+ }
2761
+ return t;
2762
+ });
2763
+ /**
2764
+ * Build the full shadow DOM and bind events.
2765
+ * @private
2766
+ */
2767
+ n(this, "_build", () => {
2768
+ const t = !!this._gradient, e = this._gradient ? this._gradient.type : "linear", o = this._gradient ? this._gradient.angle : 90, i = e !== "radial";
2769
+ this.render(fe, `
2770
+ <div class="selector">
2771
+ <div class="current">
2772
+ <div class="preview"></div>
2773
+ <span class="label">${this._labelForValue(this._value)}</span>
2774
+ <span class="chevron">&#9662;</span>
2775
+ </div>
2776
+ <div class="dropdown"></div>
2777
+ </div>
2778
+ <div class="controls${t ? " visible" : ""}">
2779
+ <div class="type-row">
2780
+ <span class="ctrl-label">Type</span>
2781
+ <div class="type-toggle">
2782
+ <button class="type-btn${i ? " active" : ""}" data-type="linear">Linear</button>
2783
+ <button class="type-btn${i ? "" : " active"}" data-type="radial">Radial</button>
2784
+ </div>
2785
+ </div>
2786
+ <div class="angle-row" ${i ? "" : 'style="display:none"'}>
2787
+ <wox-slider label="ANGLE" value="${o}" min="0" max="360" step="1" show-value></wox-slider>
2788
+ </div>
2789
+ <div class="speed-row">
2790
+ <wox-slider label="SPEED" value="${this._animationSpeed}" min="0" max="10" step="1" show-value></wox-slider>
2791
+ </div>
2792
+ <div class="anim-type-row" ${this._animationSpeed <= 0 ? 'style="display:none"' : ""}>
2793
+ <span class="ctrl-label">Anim</span>
2794
+ <select class="anim-select">
2795
+ <option value="pingpong"${this._animationType === "pingpong" ? " selected" : ""}>Ping Pong</option>
2796
+ <option value="cycle"${this._animationType === "cycle" ? " selected" : ""}>Cycle</option>
2797
+ </select>
2798
+ </div>
2799
+ </div>
2800
+ <wox-modal class="editor-modal" title="Custom Gradient" width="480px">
2801
+ <div class="editor-body">
2802
+ <wox-gradient-editor class="modal-editor"></wox-gradient-editor>
2803
+ <div class="name-row">
2804
+ <span class="ctrl-label">Name</span>
2805
+ <input type="text" class="name-input" placeholder="Gradient name">
2806
+ </div>
2807
+ </div>
2808
+ <div slot="footer">
2809
+ <button class="btn btn-secondary cancel-btn">Cancel</button>
2810
+ <button class="btn btn-primary apply-btn">Apply</button>
2811
+ <button class="btn btn-primary save-btn">Save &amp; Apply</button>
2812
+ </div>
2813
+ </wox-modal>
2814
+ `), this._updatePreview(), this._bindEvents();
2815
+ });
2816
+ /**
2817
+ * Update the preview swatch and label text.
2818
+ * @private
2819
+ */
2820
+ n(this, "_updatePreview", () => {
2821
+ const t = this.$(".preview"), e = this.$(".label");
2822
+ t && (t.style.background = this._value), e && (e.textContent = this._labelForValue(this._value));
2823
+ });
2824
+ /**
2825
+ * Sync all controls (type toggle, angle, speed, anim type) to current state.
2826
+ * @private
2827
+ */
2828
+ n(this, "_syncControls", () => {
2829
+ const t = this.$(".controls");
2830
+ if (!t) return;
2831
+ if (!this._gradient) {
2832
+ t.classList.remove("visible");
2833
+ return;
2834
+ }
2835
+ t.classList.add("visible");
2836
+ const e = this._gradient.type !== "radial";
2837
+ this.$$(".type-btn").forEach((l) => {
2838
+ l.classList.toggle("active", l.dataset.type === this._gradient.type);
2839
+ });
2840
+ const o = this.$(".angle-row");
2841
+ o && (o.style.display = e ? "" : "none");
2842
+ const i = this.$(".angle-row wox-slider");
2843
+ i && i.setAttribute("value", this._gradient.angle);
2844
+ const s = this.$(".speed-row wox-slider");
2845
+ s && s.setAttribute("value", this._animationSpeed);
2846
+ const r = this.$(".anim-type-row");
2847
+ r && (r.style.display = this._animationSpeed > 0 ? "" : "none");
2848
+ const a = this.$(".anim-select");
2849
+ a && (a.value = this._animationType);
2850
+ });
2851
+ /**
2852
+ * Bind all interactive event listeners.
2853
+ * @private
2854
+ */
2855
+ n(this, "_bindEvents", () => {
2856
+ this.$(".current").addEventListener("click", (h) => {
2857
+ h.stopPropagation(), this._open ? this._closeDropdown() : this._openDropdown();
2858
+ }), this.$$(".type-btn").forEach((h) => {
2859
+ h.addEventListener("click", () => {
2860
+ if (!this._gradient) return;
2861
+ this.$$(".type-btn").forEach((g) => g.classList.remove("active")), h.classList.add("active"), this._gradient.type = h.dataset.type;
2862
+ const u = this.$(".angle-row");
2863
+ u && (u.style.display = h.dataset.type === "linear" ? "" : "none"), this._applyGradient();
2864
+ });
2865
+ });
2866
+ const e = this.$(".angle-row wox-slider");
2867
+ e && (e.addEventListener("wox-input", (h) => {
2868
+ this._gradient && (this._gradient.angle = h.detail.value, this._applyGradient());
2869
+ }), e.addEventListener("wox-change", (h) => {
2870
+ this._gradient && (this._gradient.angle = h.detail.value, this._applyGradient());
2871
+ }));
2872
+ const o = this.$(".speed-row wox-slider");
2873
+ o && (o.addEventListener("wox-input", (h) => {
2874
+ this._animationSpeed = h.detail.value;
2875
+ const u = this.$(".anim-type-row");
2876
+ u && (u.style.display = this._animationSpeed > 0 ? "" : "none"), this._emitChange();
2877
+ }), o.addEventListener("wox-change", (h) => {
2878
+ this._animationSpeed = h.detail.value;
2879
+ const u = this.$(".anim-type-row");
2880
+ u && (u.style.display = this._animationSpeed > 0 ? "" : "none"), this._emitChange();
2881
+ }));
2882
+ const i = this.$(".anim-select");
2883
+ i && i.addEventListener("change", (h) => {
2884
+ this._animationType = h.target.value, this._emitChange();
2885
+ });
2886
+ const s = this.$(".cancel-btn");
2887
+ s && s.addEventListener("click", () => {
2888
+ this._closeModal();
2889
+ });
2890
+ const r = this.$(".apply-btn");
2891
+ r && r.addEventListener("click", () => {
2892
+ this._applyFromEditor(!1);
2893
+ });
2894
+ const a = this.$(".save-btn");
2895
+ a && a.addEventListener("click", () => {
2896
+ this._applyFromEditor(!0);
2897
+ });
2898
+ const l = this.$(".name-input");
2899
+ l && l.addEventListener("input", (h) => {
2900
+ this._editingName = h.target.value.trim();
2901
+ });
2902
+ const c = this.$(".modal-editor");
2903
+ c && (c.addEventListener("wox-gradient-input", (h) => {
2904
+ this._editingGradient = h.detail.gradient;
2905
+ }), c.addEventListener("wox-gradient-change", (h) => {
2906
+ this._editingGradient = h.detail.gradient;
2907
+ }));
2908
+ const x = this.$(".editor-modal");
2909
+ x && x.addEventListener("wox-close", () => {
2910
+ this._editingGradient = null, this._editingName = "";
2911
+ });
2912
+ });
2913
+ /**
2914
+ * Open the dropdown and populate its items.
2915
+ * @private
2916
+ */
2917
+ n(this, "_openDropdown", () => {
2918
+ this._open = !0, this.$(".selector").classList.add("open"), this._populateDropdown(), this._positionDropdown();
2919
+ });
2920
+ /**
2921
+ * Position the fixed dropdown relative to the trigger, flipping up if needed.
2922
+ * @private
2923
+ */
2924
+ n(this, "_positionDropdown", () => {
2925
+ const t = this.$(".current"), e = this.$(".dropdown");
2926
+ if (!t || !e) return;
2927
+ const o = t.getBoundingClientRect(), i = window.innerHeight;
2928
+ e.style.left = `${o.left}px`, e.style.width = `${o.width}px`;
2929
+ const s = i - o.bottom, r = o.top, a = 280;
2930
+ s >= a || s >= r ? (e.style.top = `${o.bottom}px`, e.style.bottom = "", e.style.maxHeight = `${Math.min(a, s - 4)}px`) : (e.style.top = "", e.style.bottom = `${i - o.top}px`, e.style.maxHeight = `${Math.min(a, r - 4)}px`);
2931
+ });
2932
+ /**
2933
+ * Close the dropdown.
2934
+ * @private
2935
+ */
2936
+ n(this, "_closeDropdown", () => {
2937
+ this._open = !1, this.$(".selector").classList.remove("open");
2938
+ });
2939
+ /**
2940
+ * Build dropdown items: solid color, saved gradients, custom option.
2941
+ * @private
2942
+ */
2943
+ n(this, "_populateDropdown", () => {
2944
+ const t = this.$(".dropdown");
2945
+ if (!t) return;
2946
+ let e = "";
2947
+ const o = this._value.startsWith("#") ? this._value : "#ffffff";
2948
+ e += `
2949
+ <div class="dropdown-item" data-action="solid">
2950
+ <div class="dropdown-item-preview" style="background: #ffffff"></div>
2951
+ <span class="dropdown-item-label">Solid Color</span>
2952
+ <input type="color" class="solid-input" value="${o}">
2953
+ </div>
2954
+ `, this._gradients.forEach((i) => {
2955
+ const s = C(i), r = i.id.startsWith(ge), a = r ? `<button class="dropdown-item-btn" data-dup-id="${i.id}" title="Duplicate gradient">&#x2398;</button>` : "", l = r ? "" : `<button class="dropdown-item-btn" data-edit-id="${i.id}" title="Edit gradient">&#9998;</button>`, c = r ? "" : `<button class="dropdown-item-btn delete-btn" data-delete-id="${i.id}" title="Delete gradient">&times;</button>`;
2956
+ e += `
2957
+ <div class="dropdown-item" data-gradient-id="${i.id}">
2958
+ <div class="dropdown-item-preview" style="background: ${s}"></div>
2959
+ <span class="dropdown-item-label">${i.name}</span>
2960
+ ${a}
2961
+ ${l}
2962
+ ${c}
2963
+ </div>
2964
+ `;
2965
+ }), e += `
2966
+ <div class="dropdown-item dropdown-custom" data-action="custom">
2967
+ <span class="dropdown-item-label">Custom Gradient...</span>
2968
+ </div>
2969
+ `, t.innerHTML = e, this._bindDropdown();
2970
+ });
2971
+ /**
2972
+ * Bind event listeners for dropdown items.
2973
+ * @private
2974
+ */
2975
+ n(this, "_bindDropdown", () => {
2976
+ const t = this.$(".dropdown");
2977
+ if (!t) return;
2978
+ const e = t.querySelector('[data-action="solid"]'), o = t.querySelector(".solid-input");
2979
+ e && o && (e.addEventListener("click", (s) => {
2980
+ s.stopPropagation(), o.style.pointerEvents = "auto", o.click();
2981
+ }), o.addEventListener("input", (s) => {
2982
+ this._value = s.target.value, this._gradient = null, this._animationSpeed = 0, this._updatePreview(), this._syncControls(), this._emitChange();
2983
+ }), o.addEventListener("change", () => {
2984
+ o.style.pointerEvents = "none";
2985
+ }), o.addEventListener("click", (s) => s.stopPropagation())), t.querySelectorAll("[data-gradient-id]").forEach((s) => {
2986
+ s.addEventListener("click", (r) => {
2987
+ if (r.target.hasAttribute("data-delete-id") || r.target.hasAttribute("data-edit-id") || r.target.hasAttribute("data-dup-id")) return;
2988
+ const a = this._getById(s.dataset.gradientId);
2989
+ a && (this._gradient = JSON.parse(JSON.stringify(a)), this._value = C(this._gradient), this._updatePreview(), this._syncControls(), this._emitChange(), this._closeDropdown());
2990
+ });
2991
+ }), t.querySelectorAll("[data-dup-id]").forEach((s) => {
2992
+ s.addEventListener("click", (r) => {
2993
+ r.stopPropagation();
2994
+ const a = this._getById(s.dataset.dupId);
2995
+ if (!a) return;
2996
+ const l = {
2997
+ id: N(),
2998
+ name: a.name + " Copy",
2999
+ type: a.type,
3000
+ angle: a.angle,
3001
+ stops: a.stops.map((c) => ({ ...c }))
3002
+ };
3003
+ this._closeDropdown(), this._openEditorDialog(l);
3004
+ });
3005
+ }), t.querySelectorAll("[data-edit-id]").forEach((s) => {
3006
+ s.addEventListener("click", (r) => {
3007
+ r.stopPropagation();
3008
+ const a = this._getById(s.dataset.editId);
3009
+ a && (this._closeDropdown(), this._openEditorDialog(JSON.parse(JSON.stringify(a))));
3010
+ });
3011
+ }), t.querySelectorAll("[data-delete-id]").forEach((s) => {
3012
+ s.addEventListener("click", (r) => {
3013
+ r.stopPropagation(), this._delete(s.dataset.deleteId), this._populateDropdown();
3014
+ });
3015
+ });
3016
+ const i = t.querySelector('[data-action="custom"]');
3017
+ i && i.addEventListener("click", (s) => {
3018
+ s.stopPropagation(), this._closeDropdown(), this._openEditorDialog();
3019
+ });
3020
+ });
3021
+ /**
3022
+ * Open the editor modal with a gradient to edit.
3023
+ * @private
3024
+ * @param {Object} [existingGradient] - Gradient to edit; omit to create new
3025
+ */
3026
+ n(this, "_openEditorDialog", (t) => {
3027
+ let e;
3028
+ t ? e = JSON.parse(JSON.stringify(t)) : (e = tt(this._value), e ? (e.id = e.id || N(), e.name = e.name || "Custom Gradient") : e = {
3029
+ id: N(),
3030
+ name: "Custom Gradient",
3031
+ type: "linear",
3032
+ angle: 90,
3033
+ stops: [
3034
+ { color: this._value.startsWith("#") ? this._value : "#000000", position: 0 },
3035
+ { color: "#ffffff", position: 100 }
3036
+ ]
3037
+ }), this._editingGradient = JSON.parse(JSON.stringify(e)), this._editingName = e.name;
3038
+ const o = this.$(".modal-editor");
3039
+ o && (o.gradient = this._editingGradient);
3040
+ const i = this.$(".name-input");
3041
+ i && (i.value = e.name), this._editingOriginalId = e.id;
3042
+ const s = this.$(".editor-modal");
3043
+ s && s.setAttribute("open", "");
3044
+ });
3045
+ /**
3046
+ * Apply the edited gradient from the modal.
3047
+ * @private
3048
+ * @param {boolean} save - Whether to persist to localStorage
3049
+ */
3050
+ n(this, "_applyFromEditor", (t) => {
3051
+ if (!this._editingGradient) return;
3052
+ const e = JSON.parse(JSON.stringify(this._editingGradient));
3053
+ this._editingName && (e.name = this._editingName), e.id = this._editingOriginalId || e.id || N(), t && this._save(e), this._gradient = JSON.parse(JSON.stringify(e)), this._value = C(this._gradient), this._updatePreview(), this._syncControls(), this._emitChange(), this._closeModal();
3054
+ });
3055
+ /**
3056
+ * Close the editor modal.
3057
+ * @private
3058
+ */
3059
+ n(this, "_closeModal", () => {
3060
+ const t = this.$(".editor-modal");
3061
+ t && t.removeAttribute("open"), this._editingGradient = null, this._editingName = "", this._editingOriginalId = null;
3062
+ });
3063
+ /**
3064
+ * Recompute CSS from the current gradient object and emit change.
3065
+ * @private
3066
+ */
3067
+ n(this, "_applyGradient", () => {
3068
+ this._gradient && (this._value = C(this._gradient), this._updatePreview(), this._emitChange());
3069
+ });
3070
+ /**
3071
+ * Emit the wox-gradient-change event with current state.
3072
+ * @private
3073
+ */
3074
+ n(this, "_emitChange", () => {
3075
+ this.emit("wox-gradient-change", {
3076
+ value: this._value,
3077
+ animationSpeed: this._animationSpeed,
3078
+ animationType: this._animationType
3079
+ });
3080
+ });
3081
+ }
3082
+ connectedCallback() {
3083
+ this._loadGradients(), this._syncFromAttributes(), this._build(), this._outsideClickHandler = (t) => {
3084
+ !this._open || this.contains(t.target) || t.composedPath().includes(this) || this._closeDropdown();
3085
+ }, document.addEventListener("click", this._outsideClickHandler);
3086
+ }
3087
+ disconnectedCallback() {
3088
+ this._outsideClickHandler && document.removeEventListener("click", this._outsideClickHandler);
3089
+ }
3090
+ attributeChangedCallback(t) {
3091
+ this.isConnected && (this._syncFromAttributes(), this._updatePreview(), this._syncControls());
3092
+ }
3093
+ }
3094
+ n(ve, "observedAttributes", ["value", "animation-speed", "animation-type"]);
3095
+ const we = [
3096
+ "January",
3097
+ "February",
3098
+ "March",
3099
+ "April",
3100
+ "May",
3101
+ "June",
3102
+ "July",
3103
+ "August",
3104
+ "September",
3105
+ "October",
3106
+ "November",
3107
+ "December"
3108
+ ], me = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], it = 10, _e = `
3109
+ :host {
3110
+ display: block;
3111
+ width: 280px;
3112
+ background: var(--wox-bg-panel, #17171a);
3113
+ border: 1px solid var(--wox-border, #333);
3114
+ border-radius: var(--wox-radius-md, 6px);
3115
+ box-shadow: var(--wox-shadow-md, 0 4px 16px rgba(0,0,0,0.4));
3116
+ padding: 12px;
3117
+ user-select: none;
3118
+ font-family: var(--wox-font, 'Inter', sans-serif);
3119
+ font-size: var(--wox-font-size-base, 12px);
3120
+ color: var(--wox-text-primary, #eee);
3121
+ }
3122
+
3123
+ .header {
3124
+ display: flex;
3125
+ align-items: center;
3126
+ justify-content: space-between;
3127
+ margin-bottom: 10px;
3128
+ }
3129
+
3130
+ .month-year {
3131
+ display: flex;
3132
+ align-items: center;
3133
+ gap: 4px;
3134
+ font-weight: 600;
3135
+ font-size: 13px;
3136
+ color: var(--wox-text-primary, #eee);
3137
+ }
3138
+
3139
+ .year-select {
3140
+ background: transparent;
3141
+ border: none;
3142
+ color: var(--wox-text-primary, #eee);
3143
+ font-size: 13px;
3144
+ font-weight: 600;
3145
+ font-family: var(--wox-font, sans-serif);
3146
+ cursor: pointer;
3147
+ padding: 2px 4px;
3148
+ border-radius: var(--wox-radius-md, 6px);
3149
+ outline: none;
3150
+ }
3151
+
3152
+ .year-select:hover {
3153
+ background: var(--wox-bg-hover, #2a2a2e);
3154
+ }
3155
+
3156
+ .year-select option {
3157
+ background: var(--wox-bg-panel, #17171a);
3158
+ color: var(--wox-text-primary, #eee);
3159
+ }
3160
+
3161
+ .nav-btn {
3162
+ background: none;
3163
+ border: none;
3164
+ cursor: pointer;
3165
+ color: var(--wox-text-secondary, #999);
3166
+ width: 26px;
3167
+ height: 26px;
3168
+ border-radius: var(--wox-radius-md, 6px);
3169
+ display: flex;
3170
+ align-items: center;
3171
+ justify-content: center;
3172
+ font-size: 16px;
3173
+ line-height: 1;
3174
+ transition: background 0.12s, color 0.12s;
3175
+ padding: 0;
3176
+ }
3177
+
3178
+ .nav-btn:hover {
3179
+ background: var(--wox-bg-hover, #2a2a2e);
3180
+ color: var(--wox-text-primary, #eee);
3181
+ }
3182
+
3183
+ .day-headers {
3184
+ display: grid;
3185
+ grid-template-columns: repeat(7, 1fr);
3186
+ margin-bottom: 2px;
3187
+ }
3188
+
3189
+ .day-header {
3190
+ text-align: center;
3191
+ font-size: 10px;
3192
+ font-weight: 600;
3193
+ color: var(--wox-text-secondary, #999);
3194
+ padding: 4px 0;
3195
+ }
3196
+
3197
+ .calendar-grid {
3198
+ display: grid;
3199
+ grid-template-columns: repeat(7, 1fr);
3200
+ gap: 1px;
3201
+ }
3202
+
3203
+ .day-cell {
3204
+ aspect-ratio: 1;
3205
+ display: flex;
3206
+ align-items: center;
3207
+ justify-content: center;
3208
+ font-size: 11px;
3209
+ border-radius: var(--wox-radius-md, 6px);
3210
+ cursor: pointer;
3211
+ transition: background 0.1s, color 0.1s;
3212
+ color: var(--wox-text-primary, #eee);
3213
+ position: relative;
3214
+ }
3215
+
3216
+ .day-cell:hover {
3217
+ background: var(--wox-bg-hover, #2a2a2e);
3218
+ }
3219
+
3220
+ .day-cell.other-month {
3221
+ color: var(--wox-text-secondary, #999);
3222
+ opacity: 0.4;
3223
+ }
3224
+
3225
+ .day-cell.today {
3226
+ outline: 1px solid var(--wox-accent, #00e5ff);
3227
+ outline-offset: -1px;
3228
+ color: var(--wox-accent, #00e5ff);
3229
+ font-weight: 600;
3230
+ }
3231
+
3232
+ .day-cell.selected {
3233
+ background: var(--wox-accent, #00e5ff);
3234
+ color: #000;
3235
+ font-weight: 600;
3236
+ }
3237
+
3238
+ .day-cell.selected:hover {
3239
+ background: var(--wox-accent, #00e5ff);
3240
+ }
3241
+
3242
+ .day-cell.range-start,
3243
+ .day-cell.range-end {
3244
+ background: var(--wox-accent, #00e5ff);
3245
+ color: #000;
3246
+ font-weight: 600;
3247
+ }
3248
+
3249
+ .day-cell.range-start:hover,
3250
+ .day-cell.range-end:hover {
3251
+ background: var(--wox-accent, #00e5ff);
3252
+ }
3253
+
3254
+ .day-cell.in-range {
3255
+ background: rgba(0, 229, 255, 0.15);
3256
+ border-radius: 0;
3257
+ }
3258
+
3259
+ .day-cell.range-start { border-radius: var(--wox-radius-md, 6px) 0 0 var(--wox-radius-md, 6px); }
3260
+ .day-cell.range-end { border-radius: 0 var(--wox-radius-md, 6px) var(--wox-radius-md, 6px) 0; }
3261
+
3262
+ .day-cell.range-hover {
3263
+ background: rgba(0, 229, 255, 0.08);
3264
+ }
3265
+
3266
+ .day-cell.disabled {
3267
+ pointer-events: none;
3268
+ opacity: 0.25;
3269
+ }
3270
+
3271
+ .footer {
3272
+ display: flex;
3273
+ justify-content: space-between;
3274
+ align-items: center;
3275
+ margin-top: 10px;
3276
+ gap: 8px;
3277
+ }
3278
+
3279
+ .mode-hint {
3280
+ font-size: 10px;
3281
+ color: var(--wox-text-secondary, #999);
3282
+ flex: 1;
3283
+ }
3284
+
3285
+ .today-btn {
3286
+ background: none;
3287
+ border: 1px solid var(--wox-border, #333);
3288
+ border-radius: var(--wox-radius-md, 6px);
3289
+ color: var(--wox-text-secondary, #999);
3290
+ font-size: 10px;
3291
+ font-family: var(--wox-font, sans-serif);
3292
+ cursor: pointer;
3293
+ padding: 3px 8px;
3294
+ transition: background 0.12s, color 0.12s, border-color 0.12s;
3295
+ }
3296
+
3297
+ .today-btn:hover {
3298
+ background: var(--wox-bg-hover, #2a2a2e);
3299
+ color: var(--wox-accent, #00e5ff);
3300
+ border-color: var(--wox-accent, #00e5ff);
3301
+ }
3302
+
3303
+ :host([disabled]) {
3304
+ opacity: 0.4;
3305
+ pointer-events: none;
3306
+ }
3307
+ `;
3308
+ class ye extends v {
3309
+ constructor() {
3310
+ super(...arguments);
3311
+ /** @type {Date} Currently viewed month/year */
3312
+ n(this, "_currentDate", /* @__PURE__ */ new Date());
3313
+ /** @type {string|null} Selected date in single mode (YYYY-MM-DD) */
3314
+ n(this, "_selectedDate", null);
3315
+ /** @type {{ start: string|null, end: string|null }} */
3316
+ n(this, "_selectedRange", { start: null, end: null });
3317
+ // ── Private ─────────────────────────────────────────────────────────────────
3318
+ /** @private */
3319
+ n(this, "_navigateMonth", (t) => {
3320
+ const e = this._currentDate.getFullYear(), o = this._currentDate.getMonth() + t;
3321
+ this._currentDate = new Date(e, o, 1), this._render();
3322
+ });
3323
+ /** @private */
3324
+ n(this, "_navigateToYear", (t) => {
3325
+ this._currentDate = new Date(t, this._currentDate.getMonth(), 1), this._render();
3326
+ });
3327
+ /** @private */
3328
+ n(this, "_goToday", () => {
3329
+ const t = /* @__PURE__ */ new Date(), e = st(t);
3330
+ this._currentDate = new Date(t.getFullYear(), t.getMonth(), 1), this.rangeMode ? this._selectedRange = { start: e, end: null } : (this._selectedDate = e, this.emit("wox-change", { date: e })), this._render();
3331
+ });
3332
+ /** @private */
3333
+ n(this, "_handleDayClick", (t) => {
3334
+ const e = t.dataset.date;
3335
+ if (e) {
3336
+ if (t.classList.contains("other-month")) {
3337
+ const o = P(e);
3338
+ this._currentDate = new Date(o.getFullYear(), o.getMonth(), 1);
3339
+ }
3340
+ this.rangeMode ? this._handleRangeSelection(e) : (this._selectedDate = e, this.emit("wox-change", { date: e }), this._render());
3341
+ }
3342
+ });
3343
+ /** @private */
3344
+ n(this, "_handleRangeSelection", (t) => {
3345
+ !this._selectedRange.start || this._selectedRange.end ? this._selectedRange = { start: t, end: null } : (t < this._selectedRange.start ? this._selectedRange = { start: t, end: this._selectedRange.start } : this._selectedRange.end = t, this.emit("wox-change", { start: this._selectedRange.start, end: this._selectedRange.end })), this._render();
3346
+ });
3347
+ /** @private DOM manipulation only — no re-render */
3348
+ n(this, "_updateRangeHover", (t) => {
3349
+ if (!t) return;
3350
+ const e = this._selectedRange.start;
3351
+ this.$$(".day-cell:not(.other-month)").forEach((o) => {
3352
+ const i = o.dataset.date;
3353
+ o.classList.toggle("range-hover", i > e && i <= t);
3354
+ });
3355
+ });
3356
+ /** @private */
3357
+ n(this, "_clearRangeHover", () => {
3358
+ this.$$(".day-cell.range-hover").forEach((t) => t.classList.remove("range-hover"));
3359
+ });
3360
+ /** @private */
3361
+ n(this, "_generateYearOptions", (t) => {
3362
+ let e = "";
3363
+ for (let o = t - it; o <= t + it; o++)
3364
+ e += `<option value="${o}"${o === t ? " selected" : ""}>${o}</option>`;
3365
+ return e;
3366
+ });
3367
+ /** @private */
3368
+ n(this, "_generateGrid", (t, e) => {
3369
+ const i = st(/* @__PURE__ */ new Date()), s = new Date(t, e, 1).getDay(), r = new Date(t, e + 1, 0).getDate();
3370
+ let a = "";
3371
+ const l = e === 0 ? t - 1 : t, c = e === 0 ? 11 : e - 1, x = new Date(l, c + 1, 0).getDate();
3372
+ for (let b = s - 1; b >= 0; b--) {
3373
+ const f = x - b, w = j(l, c, f);
3374
+ a += `<div class="day-cell other-month" data-date="${w}">${f}</div>`;
3375
+ }
3376
+ for (let b = 1; b <= r; b++) {
3377
+ const f = j(t, e, b);
3378
+ let w = "day-cell";
3379
+ f === i && (w += " today"), this.rangeMode ? this._selectedRange.start && f === this._selectedRange.start ? w += " range-start" : this._selectedRange.end && f === this._selectedRange.end ? w += " range-end" : ke(f, this._selectedRange.start, this._selectedRange.end) && (w += " in-range") : this._selectedDate && f === this._selectedDate && (w += " selected"), a += `<div class="${w}" data-date="${f}">${b}</div>`;
3380
+ }
3381
+ const h = Math.ceil((s + r) / 7) * 7, u = e === 11 ? t + 1 : t, g = e === 11 ? 0 : e + 1;
3382
+ for (let b = 1; b <= h - s - r; b++) {
3383
+ const f = j(u, g, b);
3384
+ a += `<div class="day-cell other-month" data-date="${f}">${b}</div>`;
3385
+ }
3386
+ return a;
3387
+ });
3388
+ /** @private */
3389
+ n(this, "_getModeHint", () => this.rangeMode ? this._selectedRange.start ? this._selectedRange.end ? `${this._selectedRange.start} → ${this._selectedRange.end}` : "Select end date" : "Select start date" : "Select a date");
3390
+ /** @private */
3391
+ n(this, "_render", () => {
3392
+ const t = this._currentDate.getFullYear(), e = this._currentDate.getMonth();
3393
+ this.render(_e, `
3394
+ <div class="header">
3395
+ <button class="nav-btn" id="prev-month">&#8249;</button>
3396
+ <div class="month-year">
3397
+ ${we[e]}
3398
+ <select class="year-select">${this._generateYearOptions(t)}</select>
3399
+ </div>
3400
+ <button class="nav-btn" id="next-month">&#8250;</button>
3401
+ </div>
3402
+ <div class="day-headers">
3403
+ ${me.map((o) => `<div class="day-header">${o}</div>`).join("")}
3404
+ </div>
3405
+ <div class="calendar-grid">
3406
+ ${this._generateGrid(t, e)}
3407
+ </div>
3408
+ <div class="footer">
3409
+ <span class="mode-hint">${this._getModeHint()}</span>
3410
+ <button class="today-btn">Today</button>
3411
+ </div>
3412
+ `);
3413
+ });
3414
+ }
3415
+ connectedCallback() {
3416
+ this._boundShadowClick = (t) => {
3417
+ if (this.hasAttribute("disabled")) return;
3418
+ const e = t.target.closest("button");
3419
+ if (e) {
3420
+ if (e.id === "prev-month") {
3421
+ this._navigateMonth(-1);
3422
+ return;
3423
+ }
3424
+ if (e.id === "next-month") {
3425
+ this._navigateMonth(1);
3426
+ return;
3427
+ }
3428
+ if (e.classList.contains("today-btn")) {
3429
+ this._goToday();
3430
+ return;
3431
+ }
3432
+ }
3433
+ const o = t.target.closest(".day-cell");
3434
+ if (o) {
3435
+ this._handleDayClick(o);
3436
+ return;
3437
+ }
3438
+ }, this._boundShadowChange = (t) => {
3439
+ t.target.classList.contains("year-select") && this._navigateToYear(parseInt(t.target.value, 10));
3440
+ }, this._boundShadowMouseover = (t) => {
3441
+ if (!this.hasAttribute("range-mode")) return;
3442
+ const e = t.target.closest(".day-cell");
3443
+ e && this._selectedRange.start && !this._selectedRange.end && this._updateRangeHover(e.dataset.date);
3444
+ }, this._boundShadowMouseleave = () => {
3445
+ this._clearRangeHover();
3446
+ }, this.shadowRoot.addEventListener("click", this._boundShadowClick), this.shadowRoot.addEventListener("change", this._boundShadowChange), this.shadowRoot.addEventListener("mouseover", this._boundShadowMouseover), this.addEventListener("mouseleave", this._boundShadowMouseleave), this._render();
3447
+ }
3448
+ disconnectedCallback() {
3449
+ this.shadowRoot.removeEventListener("click", this._boundShadowClick), this.shadowRoot.removeEventListener("change", this._boundShadowChange), this.shadowRoot.removeEventListener("mouseover", this._boundShadowMouseover), this.removeEventListener("mouseleave", this._boundShadowMouseleave);
3450
+ }
3451
+ attributeChangedCallback(t, e, o) {
3452
+ if (!(e === o || !this.isConnected)) {
3453
+ if (t === "range-mode")
3454
+ this._selectedDate = null, this._selectedRange = { start: null, end: null };
3455
+ else if (t === "value" && o !== null) {
3456
+ this._selectedDate = o;
3457
+ const i = P(o);
3458
+ isNaN(i) || (this._currentDate = new Date(i.getFullYear(), i.getMonth(), 1));
3459
+ } else t === "range-start" ? this._selectedRange.start = o : t === "range-end" && (this._selectedRange.end = o);
3460
+ this._render();
3461
+ }
3462
+ }
3463
+ // ── Getters / Setters ───────────────────────────────────────────────────────
3464
+ /** @type {boolean} Enables range selection mode. */
3465
+ get rangeMode() {
3466
+ return this.hasAttribute("range-mode");
3467
+ }
3468
+ set rangeMode(t) {
3469
+ t ? this.setAttribute("range-mode", "") : this.removeAttribute("range-mode");
3470
+ }
3471
+ /** @type {boolean} Disables all interaction. */
3472
+ get disabled() {
3473
+ return this.hasAttribute("disabled");
3474
+ }
3475
+ set disabled(t) {
3476
+ t ? this.setAttribute("disabled", "") : this.removeAttribute("disabled");
3477
+ }
3478
+ // ── Public API ──────────────────────────────────────────────────────────────
3479
+ /**
3480
+ * Selects a date in single mode and navigates to its month.
3481
+ * @param {string} dateStr - YYYY-MM-DD
3482
+ */
3483
+ setDate(t) {
3484
+ if (this.rangeMode) return;
3485
+ this._selectedDate = t;
3486
+ const e = P(t);
3487
+ isNaN(e) || (this._currentDate = new Date(e.getFullYear(), e.getMonth(), 1)), this._render();
3488
+ }
3489
+ /**
3490
+ * Sets both range endpoints and navigates to the start month.
3491
+ * @param {string} start - YYYY-MM-DD
3492
+ * @param {string} end - YYYY-MM-DD
3493
+ */
3494
+ setRange(t, e) {
3495
+ if (!this.rangeMode) return;
3496
+ this._selectedRange = { start: t, end: e };
3497
+ const o = P(t);
3498
+ this._currentDate = new Date(o.getFullYear(), o.getMonth(), 1), this._render();
3499
+ }
3500
+ /** @returns {string|null} */
3501
+ getSelectedDate() {
3502
+ return this._selectedDate;
3503
+ }
3504
+ /** @returns {{ start: string|null, end: string|null }} */
3505
+ getSelectedRange() {
3506
+ return { ...this._selectedRange };
3507
+ }
3508
+ /** Clears selection and re-renders. */
3509
+ clear() {
3510
+ this._selectedDate = null, this._selectedRange = { start: null, end: null }, this._render();
3511
+ }
3512
+ }
3513
+ n(ye, "observedAttributes", ["range-mode", "value", "range-start", "range-end", "disabled"]);
3514
+ const st = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`, P = (d) => {
3515
+ const [p, t, e] = d.split("-").map(Number);
3516
+ return new Date(p, t - 1, e);
3517
+ }, j = (d, p, t) => `${d}-${String(p + 1).padStart(2, "0")}-${String(t).padStart(2, "0")}`, ke = (d, p, t) => !p || !t ? !1 : d > p && d < t;
3518
+ export {
3519
+ R as FX_STYLES,
3520
+ gt as WoxBadge,
3521
+ ft as WoxButton,
3522
+ Lt as WoxColorPicker,
3523
+ Et as WoxColorSwatch,
3524
+ V as WoxContextMenu,
3525
+ Ee as WoxDatagrid,
3526
+ ye as WoxDatePicker,
3527
+ v as WoxElement,
3528
+ Ce as WoxGradientEditor,
3529
+ ve as WoxGradientSelector,
3530
+ pt as WoxIcon,
3531
+ wt as WoxInput,
3532
+ Tt as WoxLayerItem,
3533
+ Rt as WoxMenu,
3534
+ zt as WoxMenuItem,
3535
+ Kt as WoxMenubar,
3536
+ Qt as WoxModal,
3537
+ qt as WoxPanel,
3538
+ Nt as WoxSection,
3539
+ _t as WoxSelect,
3540
+ ut as WoxSeparator,
3541
+ kt as WoxSlider,
3542
+ Ut as WoxStatusbar,
3543
+ Ft as WoxTab,
3544
+ Bt as WoxTabs,
3545
+ I as WoxToast,
3546
+ Wt as WoxToolbar,
3547
+ jt as WoxToolbarGroup,
3548
+ At as WoxTooltip,
3549
+ tt as cssToGradient,
3550
+ C as gradientToCSS
3551
+ };