dsh-cool-theme 0.6.1 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -28,6 +28,7 @@ window.__ModuleLoader__.load({
28
28
  //#endregion
29
29
  let react = require("react");
30
30
  react = __toESM(react, 1);
31
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
31
32
  //#region src/contract.ts
32
33
  /**
33
34
  * Shared contract for dsh-cool-theme.
@@ -2301,6 +2302,432 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
2301
2302
  };
2302
2303
  }
2303
2304
  //#endregion
2305
+ //#region node_modules/.pnpm/react-colorful@5.8.1_react-dom@19.3.0_react@18.3.1__react@18.3.1/node_modules/react-colorful/dist/index.mjs
2306
+ function l() {
2307
+ return (l = Object.assign || function(e) {
2308
+ for (var r = 1; r < arguments.length; r++) {
2309
+ var n = arguments[r];
2310
+ for (var t in n) Object.prototype.hasOwnProperty.call(n, t) && (e[t] = n[t]);
2311
+ }
2312
+ return e;
2313
+ }).apply(this, arguments);
2314
+ }
2315
+ function c(e, r) {
2316
+ if (null == e) return {};
2317
+ var n, t, o = {}, a = Object.keys(e);
2318
+ for (t = 0; t < a.length; t++) r.indexOf(n = a[t]) >= 0 || (o[n] = e[n]);
2319
+ return o;
2320
+ }
2321
+ function i(e) {
2322
+ var n = (0, react.useRef)(e), t = (0, react.useRef)(function(e) {
2323
+ n.current && n.current(e);
2324
+ });
2325
+ return n.current = e, t.current;
2326
+ }
2327
+ var s = function(e, r, n) {
2328
+ return void 0 === r && (r = 0), void 0 === n && (n = 1), e > n ? n : e < r ? r : e;
2329
+ };
2330
+ var f = function(e) {
2331
+ return "touches" in e;
2332
+ };
2333
+ var d = function(e) {
2334
+ return e && e.ownerDocument.defaultView || self;
2335
+ };
2336
+ var v = function(e, r, n) {
2337
+ var t = e.getBoundingClientRect(), o = f(r) ? function(e, r) {
2338
+ for (var n = 0; n < e.length; n++) if (e[n].identifier === r) return e[n];
2339
+ return e[0];
2340
+ }(r.touches, n) : r;
2341
+ return {
2342
+ left: s((o.pageX - (t.left + d(e).pageXOffset)) / t.width),
2343
+ top: s((o.pageY - (t.top + d(e).pageYOffset)) / t.height)
2344
+ };
2345
+ };
2346
+ var h = function(e) {
2347
+ !f(e) && e.preventDefault();
2348
+ };
2349
+ var g = react.default.memo(function(o) {
2350
+ var a = o.onMove, u = o.onKey, s = o.onEnd, g = c(o, [
2351
+ "onMove",
2352
+ "onKey",
2353
+ "onEnd"
2354
+ ]), m = (0, react.useRef)(null), p = i(a), b = i(u), _ = i(s), E = (0, react.useRef)(null), C = (0, react.useRef)(!1), x = (0, react.useMemo)(function() {
2355
+ var e = function(e) {
2356
+ h(e), (f(e) ? e.touches.length > 0 : e.buttons > 0) && m.current ? p(v(m.current, e, E.current)) : (n(!1), _());
2357
+ }, r = function() {
2358
+ n(!1), _();
2359
+ };
2360
+ function n(n) {
2361
+ var t = C.current, o = d(m.current), a = n ? o.addEventListener : o.removeEventListener;
2362
+ a(t ? "touchmove" : "mousemove", e), a(t ? "touchend" : "mouseup", r);
2363
+ }
2364
+ return [
2365
+ function(e) {
2366
+ var r = e.nativeEvent, t = m.current;
2367
+ if (t && (h(r), !function(e, r) {
2368
+ return r && !f(e);
2369
+ }(r, C.current) && t)) {
2370
+ if (f(r)) {
2371
+ C.current = !0;
2372
+ var o = r.changedTouches || [];
2373
+ o.length && (E.current = o[0].identifier);
2374
+ }
2375
+ t.focus(), p(v(t, r, E.current)), n(!0);
2376
+ }
2377
+ },
2378
+ function(e) {
2379
+ var r = e.which || e.keyCode;
2380
+ r < 37 || r > 40 || (e.preventDefault(), b({
2381
+ left: 39 === r ? .05 : 37 === r ? -.05 : 0,
2382
+ top: 40 === r ? .05 : 38 === r ? -.05 : 0
2383
+ }));
2384
+ },
2385
+ function(e) {
2386
+ var r = e.which || e.keyCode;
2387
+ r >= 37 && r <= 40 && _();
2388
+ },
2389
+ n
2390
+ ];
2391
+ }, [
2392
+ b,
2393
+ p,
2394
+ _
2395
+ ]), H = x[0], M = x[1], N = x[2], w = x[3];
2396
+ return (0, react.useEffect)(function() {
2397
+ return w;
2398
+ }, [w]), react.default.createElement("div", l({}, g, {
2399
+ onTouchStart: H,
2400
+ onMouseDown: H,
2401
+ className: "react-colorful__interactive",
2402
+ ref: m,
2403
+ onKeyDown: M,
2404
+ onKeyUp: N,
2405
+ tabIndex: 0,
2406
+ role: "slider"
2407
+ }));
2408
+ });
2409
+ var m = function(e) {
2410
+ return e.filter(Boolean).join(" ");
2411
+ };
2412
+ var p = function(r) {
2413
+ var n = r.color, t = r.left, o = r.top, a = void 0 === o ? .5 : o, u = m(["react-colorful__pointer", r.className]);
2414
+ return react.default.createElement("div", {
2415
+ className: u,
2416
+ style: {
2417
+ top: 100 * a + "%",
2418
+ left: 100 * t + "%"
2419
+ }
2420
+ }, react.default.createElement("div", {
2421
+ className: "react-colorful__pointer-fill",
2422
+ style: { backgroundColor: n }
2423
+ }));
2424
+ };
2425
+ var b = function(e, r, n) {
2426
+ return void 0 === r && (r = 0), void 0 === n && (n = Math.pow(10, r)), Math.round(n * e) / n;
2427
+ };
2428
+ 360 / (2 * Math.PI);
2429
+ var E = function(e) {
2430
+ return L(C(e));
2431
+ };
2432
+ var C = function(e) {
2433
+ return "#" === e[0] && (e = e.substring(1)), e.length < 6 ? {
2434
+ r: parseInt(e[0] + e[0], 16),
2435
+ g: parseInt(e[1] + e[1], 16),
2436
+ b: parseInt(e[2] + e[2], 16),
2437
+ a: 4 === e.length ? b(parseInt(e[3] + e[3], 16) / 255, 2) : 1
2438
+ } : {
2439
+ r: parseInt(e.substring(0, 2), 16),
2440
+ g: parseInt(e.substring(2, 4), 16),
2441
+ b: parseInt(e.substring(4, 6), 16),
2442
+ a: 8 === e.length ? b(parseInt(e.substring(6, 8), 16) / 255, 2) : 1
2443
+ };
2444
+ };
2445
+ var w = function(e) {
2446
+ return B(I(e));
2447
+ };
2448
+ var y = function(e) {
2449
+ var r = e.s, n = e.v, t = e.a, o = (200 - r) * n / 100;
2450
+ return {
2451
+ h: b(e.h),
2452
+ s: b(o > 0 && o < 200 ? r * n / 100 / (o <= 100 ? o : 200 - o) * 100 : 0),
2453
+ l: b(o / 2),
2454
+ a: b(t, 2)
2455
+ };
2456
+ };
2457
+ var k = function(e) {
2458
+ var r = y(e);
2459
+ return "hsl(" + r.h + ", " + r.s + "%, " + r.l + "%)";
2460
+ };
2461
+ var I = function(e) {
2462
+ var r = e.h, n = e.s, t = e.v, o = e.a;
2463
+ r = r / 360 * 6, n /= 100, t /= 100;
2464
+ var a = Math.floor(r), u = t * (1 - n), l = t * (1 - (r - a) * n), c = t * (1 - (1 - r + a) * n), i = a % 6;
2465
+ return {
2466
+ r: b(255 * [
2467
+ t,
2468
+ l,
2469
+ u,
2470
+ u,
2471
+ c,
2472
+ t
2473
+ ][i]),
2474
+ g: b(255 * [
2475
+ c,
2476
+ t,
2477
+ t,
2478
+ l,
2479
+ u,
2480
+ u
2481
+ ][i]),
2482
+ b: b(255 * [
2483
+ u,
2484
+ u,
2485
+ c,
2486
+ t,
2487
+ t,
2488
+ l
2489
+ ][i]),
2490
+ a: b(o, 2)
2491
+ };
2492
+ };
2493
+ var K = function(e) {
2494
+ var r = e.toString(16);
2495
+ return r.length < 2 ? "0" + r : r;
2496
+ };
2497
+ var B = function(e) {
2498
+ var r = e.r, n = e.g, t = e.b, o = e.a, a = o < 1 ? K(b(255 * o)) : "";
2499
+ return "#" + K(r) + K(n) + K(t) + a;
2500
+ };
2501
+ var L = function(e) {
2502
+ var r = e.r, n = e.g, t = e.b, o = e.a, a = Math.max(r, n, t), u = a - Math.min(r, n, t), l = u ? a === r ? (n - t) / u : a === n ? 2 + (t - r) / u : 4 + (r - n) / u : 0;
2503
+ return {
2504
+ h: 60 * (l < 0 ? l + 6 : l),
2505
+ s: a ? u / a * 100 : 0,
2506
+ v: a / 255 * 100,
2507
+ a: o
2508
+ };
2509
+ };
2510
+ var R = react.default.memo(function(r) {
2511
+ var n = r.hue, t = r.onChange, o = r.onChangeEnd, a = m(["react-colorful__hue", r.className]);
2512
+ return react.default.createElement("div", { className: a }, react.default.createElement(g, {
2513
+ onMove: function(e) {
2514
+ t({ h: 360 * e.left });
2515
+ },
2516
+ onKey: function(e) {
2517
+ t({ h: s(n + 360 * e.left, 0, 360) });
2518
+ },
2519
+ onEnd: o,
2520
+ "aria-label": "Hue",
2521
+ "aria-valuenow": b(n),
2522
+ "aria-valuemax": "360",
2523
+ "aria-valuemin": "0"
2524
+ }, react.default.createElement(p, {
2525
+ className: "react-colorful__hue-pointer",
2526
+ left: n / 360,
2527
+ color: k({
2528
+ h: n,
2529
+ s: 100,
2530
+ v: 100,
2531
+ a: 1
2532
+ })
2533
+ })));
2534
+ });
2535
+ var S = react.default.memo(function(r) {
2536
+ var n = r.hsva, t = r.onChange, o = r.onChangeEnd, a = { backgroundColor: k({
2537
+ h: n.h,
2538
+ s: 100,
2539
+ v: 100,
2540
+ a: 1
2541
+ }) };
2542
+ return react.default.createElement("div", {
2543
+ className: "react-colorful__saturation",
2544
+ style: a
2545
+ }, react.default.createElement(g, {
2546
+ onMove: function(e) {
2547
+ t({
2548
+ s: 100 * e.left,
2549
+ v: 100 - 100 * e.top
2550
+ });
2551
+ },
2552
+ onKey: function(e) {
2553
+ t({
2554
+ s: s(n.s + 100 * e.left, 0, 100),
2555
+ v: s(n.v - 100 * e.top, 0, 100)
2556
+ });
2557
+ },
2558
+ onEnd: o,
2559
+ "aria-label": "Color",
2560
+ "aria-valuetext": "Saturation " + b(n.s) + "%, Brightness " + b(n.v) + "%"
2561
+ }, react.default.createElement(p, {
2562
+ className: "react-colorful__saturation-pointer",
2563
+ top: 1 - n.v / 100,
2564
+ left: n.s / 100,
2565
+ color: k(n)
2566
+ })));
2567
+ });
2568
+ var T = function(e, r) {
2569
+ if (e === r) return !0;
2570
+ for (var n in e) if (e[n] !== r[n]) return !1;
2571
+ return !0;
2572
+ };
2573
+ var P = function(e, r) {
2574
+ return e.toLowerCase() === r.toLowerCase() || T(C(e), C(r));
2575
+ };
2576
+ function X(e, n, u, l) {
2577
+ var c = i(u), s = i(l), f = (0, react.useState)(function() {
2578
+ return e.toHsva(n);
2579
+ }), d = f[0], v = f[1], h = (0, react.useRef)({
2580
+ color: n,
2581
+ hsva: d
2582
+ }), g = (0, react.useRef)(!1);
2583
+ (0, react.useEffect)(function() {
2584
+ if (!e.equal(n, h.current.color)) {
2585
+ var r = e.toHsva(n);
2586
+ h.current = {
2587
+ hsva: r,
2588
+ color: n
2589
+ }, v(r), g.current = !1;
2590
+ }
2591
+ }, [n, e]), (0, react.useEffect)(function() {
2592
+ var r;
2593
+ T(d, h.current.hsva) || e.equal(r = e.fromHsva(d), h.current.color) || (h.current = {
2594
+ hsva: d,
2595
+ color: r
2596
+ }, c(r), g.current = !0);
2597
+ }, [
2598
+ d,
2599
+ e,
2600
+ c
2601
+ ]);
2602
+ return [
2603
+ d,
2604
+ (0, react.useCallback)(function(e) {
2605
+ v(function(r) {
2606
+ return Object.assign({}, r, e);
2607
+ });
2608
+ }, []),
2609
+ (0, react.useCallback)(function() {
2610
+ g.current && (g.current = !1, s(h.current.color));
2611
+ }, [s])
2612
+ ];
2613
+ }
2614
+ var Y;
2615
+ var U = "undefined" != typeof window ? react.useLayoutEffect : react.useEffect;
2616
+ var V = function() {
2617
+ return Y || ("undefined" != typeof __webpack_nonce__ ? __webpack_nonce__ : void 0);
2618
+ };
2619
+ var $ = /* @__PURE__ */ new WeakMap();
2620
+ var G = function(e) {
2621
+ U(function() {
2622
+ var r = e.current;
2623
+ if ("undefined" != typeof document && r) {
2624
+ var n = r.getRootNode ? r.getRootNode() : r.ownerDocument, t = n && ("head" in n || "host" in n) ? n : r.ownerDocument;
2625
+ if (!$.has(t)) {
2626
+ var o = "head" in t ? t.head : t, a = (o.ownerDocument || document).createElement("style");
2627
+ a.innerHTML = ".react-colorful{position:relative;display:flex;flex-direction:column;width:200px;height:200px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.react-colorful__saturation{position:relative;flex-grow:1;border-color:transparent;border-bottom:12px solid #000;border-radius:8px 8px 0 0;background-image:linear-gradient(0deg,#000,transparent),linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.react-colorful__alpha-gradient,.react-colorful__pointer-fill{content:\"\";position:absolute;left:0;top:0;right:0;bottom:0;pointer-events:none;border-radius:inherit}.react-colorful__alpha-gradient,.react-colorful__saturation{box-shadow:inset 0 0 0 1px rgba(0,0,0,.05)}.react-colorful__alpha,.react-colorful__hue{position:relative;height:24px}.react-colorful__hue{background:linear-gradient(90deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red)}.react-colorful__last-control{border-radius:0 0 8px 8px}.react-colorful__interactive{position:absolute;left:0;top:0;right:0;bottom:0;border-radius:inherit;outline:none;touch-action:none}.react-colorful__pointer{position:absolute;z-index:1;box-sizing:border-box;width:28px;height:28px;transform:translate(-50%,-50%);background-color:#fff;border:2px solid #fff;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.2)}.react-colorful__interactive:focus .react-colorful__pointer{transform:translate(-50%,-50%) scale(1.1)}.react-colorful__alpha,.react-colorful__alpha-pointer{background-color:#fff;background-image:url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill-opacity=\".05\"><path d=\"M8 0h8v8H8zM0 8h8v8H0z\"/></svg>')}.react-colorful__saturation-pointer{z-index:3}.react-colorful__hue-pointer{z-index:2}";
2628
+ var u = V();
2629
+ u && a.setAttribute("nonce", u), $.set(t, a), o.appendChild(a);
2630
+ }
2631
+ }
2632
+ }, []);
2633
+ };
2634
+ var J = function(n) {
2635
+ var t = n.className, o = n.colorModel, a = n.color, u = void 0 === a ? o.defaultColor : a, i = n.onChange, s = n.onChangeEnd, f = c(n, [
2636
+ "className",
2637
+ "colorModel",
2638
+ "color",
2639
+ "onChange",
2640
+ "onChangeEnd"
2641
+ ]), d = (0, react.useRef)(null);
2642
+ G(d);
2643
+ var v = X(o, u, i, s), h = v[0], g = v[1], p = v[2], b = m(["react-colorful", t]);
2644
+ return react.default.createElement("div", l({}, f, {
2645
+ ref: d,
2646
+ className: b
2647
+ }), react.default.createElement(S, {
2648
+ hsva: h,
2649
+ onChange: g,
2650
+ onChangeEnd: p
2651
+ }), react.default.createElement(R, {
2652
+ hue: h.h,
2653
+ onChange: g,
2654
+ onChangeEnd: p,
2655
+ className: "react-colorful__last-control"
2656
+ }));
2657
+ };
2658
+ var Q = {
2659
+ defaultColor: "000",
2660
+ toHsva: E,
2661
+ fromHsva: function(e) {
2662
+ return w({
2663
+ h: e.h,
2664
+ s: e.s,
2665
+ v: e.v,
2666
+ a: 1
2667
+ });
2668
+ },
2669
+ equal: P
2670
+ };
2671
+ var Z = function(r) {
2672
+ return react.default.createElement(J, l({}, r, { colorModel: Q }));
2673
+ };
2674
+ var ke = /^#?([0-9A-F]{3,8})$/i;
2675
+ var qe = function(r) {
2676
+ var n = r.color, u = void 0 === n ? "" : n, s = r.onChange, f = r.onBlur, d = r.escape, v = r.validate, h = r.format, g = r.process, m = c(r, [
2677
+ "color",
2678
+ "onChange",
2679
+ "onBlur",
2680
+ "escape",
2681
+ "validate",
2682
+ "format",
2683
+ "process"
2684
+ ]), p = (0, react.useState)(function() {
2685
+ return d(u);
2686
+ }), b = p[0], _ = p[1], E = i(s), C = i(f), x = (0, react.useCallback)(function(e) {
2687
+ var r = d(e.target.value);
2688
+ _(r), v(r) && E(g ? g(r) : r);
2689
+ }, [
2690
+ d,
2691
+ g,
2692
+ v,
2693
+ E
2694
+ ]), H = (0, react.useCallback)(function(e) {
2695
+ v(e.target.value) || _(d(u)), C(e);
2696
+ }, [
2697
+ u,
2698
+ d,
2699
+ v,
2700
+ C
2701
+ ]);
2702
+ return (0, react.useEffect)(function() {
2703
+ _(d(u));
2704
+ }, [u, d]), react.default.createElement("input", l({}, m, {
2705
+ value: h ? h(b) : b,
2706
+ spellCheck: "false",
2707
+ onChange: x,
2708
+ onBlur: H
2709
+ }));
2710
+ };
2711
+ var Ie = function(e) {
2712
+ return "#" + e;
2713
+ };
2714
+ var Oe = function(r) {
2715
+ var n = r.prefixed, t = r.alpha, o = c(r, ["prefixed", "alpha"]), u = (0, react.useCallback)(function(e) {
2716
+ return e.replace(/([^0-9A-F]+)/gi, "").substring(0, t ? 8 : 6);
2717
+ }, [t]), i = (0, react.useCallback)(function(e) {
2718
+ return function(e, r) {
2719
+ var n = ke.exec(e), t = n ? n[1].length : 0;
2720
+ return 3 === t || 6 === t || !!r && 4 === t || !!r && 8 === t;
2721
+ }(e, t);
2722
+ }, [t]);
2723
+ return react.default.createElement(qe, l({}, o, {
2724
+ escape: u,
2725
+ format: n ? Ie : void 0,
2726
+ process: Ie,
2727
+ validate: i
2728
+ }));
2729
+ };
2730
+ //#endregion
2304
2731
  //#region src/client/custom.ts
2305
2732
  /** The nine `--shiki-token-*` slots, in stylesheet order. */
2306
2733
  const SHIKI_KEYS = [
@@ -2809,6 +3236,22 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
2809
3236
  /** Reserved menu value that switches to the user-defined theme. */
2810
3237
  const CUSTOM_SELECTION = CUSTOM_PRESET_ID;
2811
3238
  /**
3239
+ * Base id of the light/dark control in the colour editor — and the only place
3240
+ * that string is written. The shell's `SegmentedControl` derives both the tab
3241
+ * ids (`<id>-<value>`) and the panel ids (`<id>-<value>-panel`) from it, so the
3242
+ * tabpanel that answers them has to be built from the same value: a second
3243
+ * literal would drift silently and leave `aria-controls` pointing at nothing.
3244
+ */
3245
+ const SEED_MODE_CONTROL_ID = "ct-seed-mode";
3246
+ /**
3247
+ * The one glyph size this panel draws at. Every icon here is explicit about it
3248
+ * because the shell's artwork does not default uniformly — the chevron falls
3249
+ * back to 14, the edit/share/trash/add/import glyphs to 16 — so passing no size
3250
+ * silently picks a different scale per icon. 14 is what the shell's own
3251
+ * settings pages pass.
3252
+ */
3253
+ const ICON_SIZE = 14;
3254
+ /**
2812
3255
  * Which message an import failure deserves. The Host answers with its own
2813
3256
  * reason, so the shape of that reason is what selects the localized text; an
2814
3257
  * unrecognised failure keeps the Host's own words rather than hiding them.
@@ -2854,114 +3297,54 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
2854
3297
  if (open.id === null) return true;
2855
3298
  return open.name.trim() !== open.originName.trim() || !sameSeeds(current, open.originTheme);
2856
3299
  }
2857
- function IconChevron() {
2858
- return react.createElement("svg", {
2859
- width: 14,
2860
- height: 14,
2861
- viewBox: "0 0 14 14",
2862
- fill: "none",
2863
- xmlns: "http://www.w3.org/2000/svg"
2864
- }, react.createElement("path", {
2865
- d: "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z",
2866
- fill: "currentColor"
2867
- }));
2868
- }
2869
- /** The menu's selected-row tick: 16px, pushed to the trailing edge. */
2870
- function IconCheck(props) {
2871
- const { size = 16, className } = props;
2872
- return react.createElement("svg", {
2873
- width: size,
2874
- height: size,
2875
- viewBox: "0 0 16 16",
2876
- fill: "none",
2877
- xmlns: "http://www.w3.org/2000/svg",
2878
- className
2879
- }, react.createElement("path", {
2880
- d: "M15.0498 3.92579L8.49512 12.3818C8.25774 12.6881 8.04517 12.9645 7.84668 13.1689C7.63957 13.3823 7.38732 13.5841 7.04492 13.6719C6.86373 13.7183 6.6757 13.7346 6.48926 13.7197C6.13666 13.6915 5.8528 13.5355 5.6123 13.3604C5.38201 13.1926 5.12573 12.9567 4.83984 12.6953L1.03125 9.21289L1.96875 8.1875L5.77734 11.6699C6.08684 11.9529 6.27773 12.1249 6.43066 12.2363C6.50183 12.2882 6.54699 12.3135 6.57324 12.3252C6.58525 12.3305 6.59269 12.3322 6.5957 12.333C6.59802 12.3336 6.59961 12.334 6.59961 12.334C6.63317 12.3367 6.66758 12.3335 6.7002 12.3252C6.7002 12.3252 6.70211 12.3251 6.7041 12.3242C6.70698 12.3229 6.71348 12.319 6.72461 12.3115C6.74849 12.2956 6.78843 12.2642 6.84961 12.2012C6.98138 12.0654 7.13957 11.8628 7.39648 11.5313L13.9502 3.07422L15.0498 3.92579Z",
2881
- fill: "currentColor"
2882
- }));
2883
- }
3300
+ /**
3301
+ * The panel's value picker: a trigger in the row, the shell's `Menu` for the
3302
+ * list. Everything the list needs — outside pointerdown, Escape, the arrow
3303
+ * walk, the focus return to the trigger, the translucent material, the
3304
+ * viewport-clamped portal — belongs to the primitive, so this owns `open` and
3305
+ * which label the trigger shows, and nothing else.
3306
+ */
2884
3307
  function SchemeMenu(props) {
2885
3308
  const { value, options, onSelect, disabled } = props;
2886
3309
  const [open, setOpen] = react.useState(false);
2887
- const rootRef = react.useRef(null);
2888
- const listRef = react.useRef(null);
2889
- react.useEffect(() => {
2890
- if (!open) return;
2891
- function onDown(e) {
2892
- if (!(e.target instanceof Node)) return;
2893
- if (rootRef.current?.contains(e.target)) return;
2894
- if (listRef.current?.contains(e.target)) return;
2895
- setOpen(false);
2896
- }
2897
- function onKey(e) {
2898
- if (e.key === "Escape") setOpen(false);
2899
- }
2900
- document.addEventListener("pointerdown", onDown);
2901
- document.addEventListener("keydown", onKey);
2902
- return () => {
2903
- document.removeEventListener("pointerdown", onDown);
2904
- document.removeEventListener("keydown", onKey);
2905
- };
2906
- }, [open]);
2907
3310
  const selected = options.find((o) => o.value === value);
2908
- return react.createElement("span", {
2909
- ref: rootRef,
2910
- style: {
2911
- position: "relative",
2912
- display: "inline-flex"
2913
- }
2914
- }, react.createElement("button", {
2915
- type: "button",
2916
- className: "ct-select",
2917
- disabled,
2918
- "aria-haspopup": "menu",
2919
- "aria-expanded": open && !disabled,
2920
- onClick: () => setOpen(!open)
2921
- }, react.createElement("span", { className: "ct-select-label" }, selected?.label ?? ""), react.createElement("span", { className: "ct-select-chevron" }, react.createElement(IconChevron, null))), open && !disabled ? react.createElement("div", {
2922
- ref: listRef,
2923
- className: "ct-menu-list",
2924
- style: {
2925
- position: "absolute",
2926
- top: "calc(100% + 4px)",
2927
- right: 0,
2928
- zIndex: 100
3311
+ const expanded = open && !disabled;
3312
+ return react.createElement(_deepseek_ai_dsh_client_ui_primitives.Menu, {
3313
+ open: expanded,
3314
+ align: "end",
3315
+ side: "bottom",
3316
+ portal: true,
3317
+ items: options.map((o) => ({
3318
+ id: o.value,
3319
+ label: o.label
3320
+ })),
3321
+ selectedId: value,
3322
+ onSelect: (v) => {
3323
+ setOpen(false);
3324
+ onSelect(v);
2929
3325
  },
2930
- role: "menu",
2931
- onClick: (e) => e.stopPropagation()
2932
- }, ...options.map((o) => {
2933
- const sel = o.value === value;
2934
- return react.createElement("button", {
2935
- key: o.value,
3326
+ onClose: () => setOpen(false),
3327
+ anchor: react.createElement("button", {
2936
3328
  type: "button",
2937
- role: "menuitem",
2938
- className: "ct-menu-item",
2939
- onClick: () => {
2940
- setOpen(false);
2941
- onSelect(o.value);
2942
- }
2943
- }, react.createElement("span", { className: "ct-menu-item-label" }, o.label), sel ? react.createElement(IconCheck, { className: "ct-menu-check" }) : null);
2944
- })) : null);
2945
- }
2946
- /** Accessible on/off switch used to enable the custom theme. */
2947
- function Switch(props) {
2948
- const { checked, label, onChange } = props;
2949
- return react.createElement("button", {
2950
- type: "button",
2951
- role: "switch",
2952
- "aria-checked": checked,
2953
- "aria-label": label,
2954
- className: checked ? "ct-switch ct-switch-on" : "ct-switch",
2955
- onClick: () => onChange(!checked)
2956
- }, react.createElement("span", { className: "ct-switch-knob" }));
3329
+ className: "ct-select",
3330
+ disabled,
3331
+ "aria-haspopup": "menu",
3332
+ "aria-expanded": expanded,
3333
+ onClick: () => setOpen(!open)
3334
+ }, react.createElement("span", { className: "ct-select-label" }, selected?.label ?? ""), react.createElement("span", { className: "ct-select-chevron" }, react.createElement(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { size: ICON_SIZE })))
3335
+ });
2957
3336
  }
2958
3337
  /**
2959
3338
  * Confirmation dialog for destructive actions, mirroring DSH's own Modal
2960
- * (design-platform mask token + blur, r24 card on layer-2, prominent shadow).
2961
- * Rendered inline rather than through a portal so it needs no react-dom import.
3339
+ * (design-platform mask token + blur, `radius-panel` card on layer-2,
3340
+ * prominent shadow) and the footer its `RiskConfirmation` lays out: an outline
3341
+ * cancel beside the confirming action.
3342
+ * Still rendered inline rather than through the shell's `Modal`: its Escape has
3343
+ * to take part in the panel's own leave-the-draft questions, and a shell-owned
3344
+ * modal layer would answer the key before this dialog could.
2962
3345
  */
2963
3346
  function ConfirmDialog(props) {
2964
- const { title, description, confirmLabel, cancelLabel, onConfirm, onCancel } = props;
3347
+ const { title, description, confirmLabel, cancelLabel, danger, onConfirm, onCancel } = props;
2965
3348
  react.useEffect(() => {
2966
3349
  const onKey = (e) => {
2967
3350
  if (e.key === "Escape") onCancel();
@@ -2978,13 +3361,13 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
2978
3361
  role: "dialog",
2979
3362
  "aria-modal": true,
2980
3363
  "aria-label": title
2981
- }, react.createElement("div", { className: "ct-modal-title" }, title), react.createElement("div", { className: "ct-modal-desc" }, description), react.createElement("div", { className: "ct-modal-footer" }, react.createElement("button", {
2982
- type: "button",
2983
- className: "ct-btn",
3364
+ }, react.createElement("div", { className: "ct-modal-title" }, title), react.createElement("div", { className: "ct-modal-desc" }, description), react.createElement("div", { className: "ct-modal-footer" }, react.createElement(_deepseek_ai_dsh_client_ui_primitives.Button, {
3365
+ variant: "outline",
3366
+ className: "ct-action-cancel",
2984
3367
  onClick: onCancel
2985
- }, cancelLabel), react.createElement("button", {
2986
- type: "button",
2987
- className: "ct-btn ct-btn-danger",
3368
+ }, cancelLabel), react.createElement(_deepseek_ai_dsh_client_ui_primitives.Button, {
3369
+ variant: danger ? "outline" : "primary",
3370
+ className: danger ? "ct-action-confirm ct-danger" : "ct-action-confirm",
2988
3371
  onClick: onConfirm
2989
3372
  }, confirmLabel))));
2990
3373
  }
@@ -2993,148 +3376,6 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
2993
3376
  return error instanceof ThemeApiUnavailableError ? "custom.toast.unavailable" : "custom.toast.failed";
2994
3377
  }
2995
3378
  /**
2996
- * Transient confirmation banner: a leading result badge plus the copy, top
2997
- * center, sliding in, holding, fading out, then reporting done so the owner can
2998
- * unmount it. Metrics, tokens, badge and timing follow DSH's own toast — the
2999
- * badge is the success circle its confirmations wear — but the component is
3000
- * local: the plugin must keep answering a save on a host that does not share
3001
- * the primitives module.
3002
- *
3003
- * TOAST_HOLD_MS and TOAST_FADE_MS have to agree with the `ct-toast` animation
3004
- * in the injected stylesheet, which owns the visual timing.
3005
- * @param props.text - resolved, already-localized copy.
3006
- * @param props.onDone - called once the fade completes; unmount the toast here.
3007
- */
3008
- function Toast(props) {
3009
- const { text, onDone } = props;
3010
- react.useEffect(() => {
3011
- const timer = setTimeout(onDone, 4e3);
3012
- return () => clearTimeout(timer);
3013
- }, [onDone]);
3014
- return react.createElement("div", {
3015
- className: "ct-toast",
3016
- role: "status"
3017
- }, react.createElement(ToastBadge), react.createElement("span", { className: "ct-toast-text" }, text));
3018
- }
3019
- /** The leading badge every confirmation wears: a success ring around the check. */
3020
- function ToastBadge() {
3021
- return react.createElement("span", {
3022
- className: "ct-toast-icon",
3023
- "aria-hidden": true
3024
- }, react.createElement(IconCheck, { size: 12 }));
3025
- }
3026
- /**
3027
- * Plus glyph for the add button, path data taken verbatim from DSH's own
3028
- * `IconPlusOutline16` so the two controls read as the same affordance.
3029
- */
3030
- function IconPlus(props) {
3031
- const { size = 14 } = props;
3032
- return react.createElement("svg", {
3033
- width: size,
3034
- height: size,
3035
- viewBox: "0 0 16 16",
3036
- fill: "none",
3037
- xmlns: "http://www.w3.org/2000/svg",
3038
- "aria-hidden": true,
3039
- focusable: false
3040
- }, react.createElement("path", {
3041
- d: "M8.64453 1.5V7.34961H14.5V8.65039H8.64453V14.5H7.34473V8.65039H1.5V7.34961H7.34473V1.5H8.64453Z",
3042
- fill: "currentColor"
3043
- }));
3044
- }
3045
- /**
3046
- * Lucide `edit` (the pencil in a square), path data verbatim. Row actions are
3047
- * icon-only, so the glyph has to read as the label the accessible name still
3048
- * carries.
3049
- */
3050
- function IconEdit(props) {
3051
- const { size = 14 } = props;
3052
- return react.createElement("svg", {
3053
- width: size,
3054
- height: size,
3055
- viewBox: "0 0 24 24",
3056
- fill: "none",
3057
- stroke: "currentColor",
3058
- strokeWidth: 2,
3059
- strokeLinecap: "round",
3060
- strokeLinejoin: "round",
3061
- xmlns: "http://www.w3.org/2000/svg",
3062
- "aria-hidden": true,
3063
- focusable: false
3064
- }, react.createElement("path", { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" }), react.createElement("path", { d: "M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" }));
3065
- }
3066
- /** Lucide `trash`, path data verbatim; the row's danger action. */
3067
- function IconTrash(props) {
3068
- const { size = 14 } = props;
3069
- return react.createElement("svg", {
3070
- width: size,
3071
- height: size,
3072
- viewBox: "0 0 24 24",
3073
- fill: "none",
3074
- stroke: "currentColor",
3075
- strokeWidth: 2,
3076
- strokeLinecap: "round",
3077
- strokeLinejoin: "round",
3078
- xmlns: "http://www.w3.org/2000/svg",
3079
- "aria-hidden": true,
3080
- focusable: false
3081
- }, react.createElement("path", { d: "M3 6h18" }), react.createElement("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }), react.createElement("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" }), react.createElement("line", {
3082
- x1: 10,
3083
- y1: 11,
3084
- x2: 10,
3085
- y2: 17
3086
- }), react.createElement("line", {
3087
- x1: 14,
3088
- y1: 11,
3089
- x2: 14,
3090
- y2: 17
3091
- }));
3092
- }
3093
- /** Lucide `share`, path data verbatim; sends one theme out as an archive. */
3094
- function IconShare(props) {
3095
- const { size = 14 } = props;
3096
- return react.createElement("svg", {
3097
- width: size,
3098
- height: size,
3099
- viewBox: "0 0 24 24",
3100
- fill: "none",
3101
- stroke: "currentColor",
3102
- strokeWidth: 2,
3103
- strokeLinecap: "round",
3104
- strokeLinejoin: "round",
3105
- xmlns: "http://www.w3.org/2000/svg",
3106
- "aria-hidden": true,
3107
- focusable: false
3108
- }, react.createElement("path", { d: "M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8" }), react.createElement("polyline", { points: "16 6 12 2 8 6" }), react.createElement("line", {
3109
- x1: 12,
3110
- y1: 2,
3111
- x2: 12,
3112
- y2: 15
3113
- }));
3114
- }
3115
- /** Lucide `download`, path data verbatim; takes one archive in. */
3116
- function IconDownload(props) {
3117
- const { size = 14 } = props;
3118
- return react.createElement("svg", {
3119
- width: size,
3120
- height: size,
3121
- viewBox: "0 0 24 24",
3122
- fill: "none",
3123
- stroke: "currentColor",
3124
- strokeWidth: 2,
3125
- strokeLinecap: "round",
3126
- strokeLinejoin: "round",
3127
- xmlns: "http://www.w3.org/2000/svg",
3128
- "aria-hidden": true,
3129
- focusable: false
3130
- }, react.createElement("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), react.createElement("polyline", { points: "7 10 12 15 17 10" }), react.createElement("line", {
3131
- x1: 12,
3132
- y1: 15,
3133
- x2: 12,
3134
- y2: 3
3135
- }));
3136
- }
3137
- /**
3138
3379
  * One collapsed saved-theme card: the name activates the theme, and the trailing
3139
3380
  * controls export it, open the editor or delete it. The card as a whole is a
3140
3381
  * click target too, but its controls own their clicks.
@@ -3142,22 +3383,29 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3142
3383
  function ThemeCard(props) {
3143
3384
  const { entry, active, disabled, t, onActivate, onExport, onEdit, onDelete } = props;
3144
3385
  /**
3145
- * One square icon action; `danger` is the tinted delete variant. The glyph is
3146
- * decorative, so the label travels as the accessible name instead of as text,
3147
- * and as `data-tip` for the hover tooltip. `leave` marks the button on the
3148
- * markup the outside-click guard watches (see the guard's own comment).
3386
+ * One square icon action. The glyph is decorative, so the label travels as
3387
+ * the accessible name and as the shell's own `Tooltip` above the button.
3388
+ * `danger` paints the error face; `leave` marks the button on the markup the
3389
+ * outside-click guard watches (see that guard) — it is not a visual state.
3149
3390
  */
3150
- const action = (label, icon, onClick, variant) => react.createElement("button", {
3151
- type: "button",
3152
- className: variant === "danger" ? "ct-list-btn ct-list-btn-danger ct-tip" : "ct-list-btn ct-tip",
3153
- "aria-label": label,
3154
- "data-tip": label,
3155
- ...variant === "leave" ? {
3156
- "data-ct-leave": "true",
3157
- "data-ct-entry": entry.id
3158
- } : {},
3159
- onClick
3160
- }, icon);
3391
+ const action = (label, icon, onClick, marks) => {
3392
+ const button = react.createElement("button", {
3393
+ type: "button",
3394
+ className: marks?.danger ? "ct-list-btn ct-list-btn-danger" : "ct-list-btn",
3395
+ "aria-label": label,
3396
+ ...marks?.leave ? {
3397
+ "data-ct-leave": "true",
3398
+ "data-ct-entry": entry.id
3399
+ } : {},
3400
+ onClick
3401
+ }, icon);
3402
+ return react.createElement(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
3403
+ label,
3404
+ side: "top",
3405
+ gap: 6,
3406
+ children: button
3407
+ });
3408
+ };
3161
3409
  return react.createElement("div", {
3162
3410
  className: "ct-list-row",
3163
3411
  "data-ct-leave": "true",
@@ -3174,7 +3422,7 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3174
3422
  }, entry.name)), react.createElement("div", {
3175
3423
  className: "ct-list-actions",
3176
3424
  onClick: (e) => e.stopPropagation()
3177
- }, active ? react.createElement("span", { className: "ct-list-badge" }, t("custom.inUse")) : null, action(t("custom.edit"), react.createElement(IconEdit, { size: 14 }), onEdit, "leave"), action(t("custom.export"), react.createElement(IconShare, { size: 14 }), onExport), action(t("custom.delete"), react.createElement(IconTrash, { size: 14 }), onDelete, "danger")));
3425
+ }, active ? react.createElement("span", { className: "ct-list-badge" }, t("custom.inUse")) : null, action(t("custom.edit"), react.createElement(_deepseek_ai_dsh_client_ui_primitives.IconEditOutlineRegular, { size: ICON_SIZE }), onEdit, { leave: true }), action(t("custom.export"), react.createElement(_deepseek_ai_dsh_client_ui_primitives.IconShareOutlineRegular, { size: ICON_SIZE }), onExport), action(t("custom.delete"), react.createElement(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineRegular, { size: ICON_SIZE }), onDelete, { danger: true })));
3178
3426
  }
3179
3427
  /**
3180
3428
  * Which appearance the colour dots edit. `system` resolves through the same
@@ -3190,7 +3438,7 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3190
3438
  }
3191
3439
  }
3192
3440
  function ThemePanel(props) {
3193
- const { theme, getSelection, setSelection, getCustom, setCustom, setCustomBase, resetCustom, saved, getHostToast, t, onRequestClose } = props;
3441
+ const { theme, getSelection, setSelection, getCustom, setCustom, setCustomBase, resetCustom, saved, t, onRequestClose } = props;
3194
3442
  let initScheme = "system";
3195
3443
  try {
3196
3444
  const snap = theme?.getTheme();
@@ -3240,6 +3488,72 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3240
3488
  text
3241
3489
  });
3242
3490
  }
3491
+ const [pickerDotKey, setPickerDotKey] = react.useState(null);
3492
+ const [pickerPos, setPickerPos] = react.useState(null);
3493
+ const pickerOpen = pickerDotKey !== null;
3494
+ const pickerOpenRef = react.useRef(false);
3495
+ pickerOpenRef.current = pickerOpen;
3496
+ /** The swatch the popover is anchored to; re-read on every reposition. */
3497
+ const pickerAnchorRef = react.useRef(null);
3498
+ /** The popover node itself; outside-pointerdown detection needs its bounds. */
3499
+ const pickerPopRef = react.useRef(null);
3500
+ /** Viewport coordinates that put the popover beside its anchor swatch. */
3501
+ function placePicker(anchor) {
3502
+ const WIDTH = 224;
3503
+ const HEIGHT = 240;
3504
+ const GAP = 8;
3505
+ const MARGIN = 8;
3506
+ const rect = anchor.getBoundingClientRect();
3507
+ const viewW = window.innerWidth;
3508
+ const viewH = window.innerHeight;
3509
+ return {
3510
+ left: Math.min(Math.max(MARGIN, rect.right - WIDTH), Math.max(MARGIN, viewW - WIDTH - MARGIN)),
3511
+ top: rect.bottom + GAP + HEIGHT <= viewH - MARGIN ? rect.bottom + GAP : Math.max(MARGIN, rect.top - GAP - HEIGHT)
3512
+ };
3513
+ }
3514
+ /** Toggle one seed's popover; `anchor` is the swatch that was clicked. */
3515
+ function togglePicker(key, anchor) {
3516
+ if (pickerDotKey === key) {
3517
+ closePicker();
3518
+ return;
3519
+ }
3520
+ pickerAnchorRef.current = anchor;
3521
+ setPickerDotKey(key);
3522
+ setPickerPos(placePicker(anchor));
3523
+ }
3524
+ function closePicker() {
3525
+ setPickerDotKey(null);
3526
+ setPickerPos(null);
3527
+ }
3528
+ react.useEffect(() => {
3529
+ if (!pickerOpen) return;
3530
+ function onPointerDown(e) {
3531
+ const target = e.target instanceof Element ? e.target : null;
3532
+ if (!target) return;
3533
+ if (pickerPopRef.current?.contains(target)) return;
3534
+ if (pickerAnchorRef.current?.contains(target)) return;
3535
+ closePicker();
3536
+ }
3537
+ document.addEventListener("pointerdown", onPointerDown, true);
3538
+ return () => document.removeEventListener("pointerdown", onPointerDown, true);
3539
+ }, [pickerOpen]);
3540
+ react.useEffect(() => {
3541
+ if (!pickerOpen) return;
3542
+ let raf = 0;
3543
+ const update = () => {
3544
+ const anchor = pickerAnchorRef.current;
3545
+ if (!anchor) return;
3546
+ cancelAnimationFrame(raf);
3547
+ raf = requestAnimationFrame(() => setPickerPos(placePicker(anchor)));
3548
+ };
3549
+ window.addEventListener("scroll", update, true);
3550
+ window.addEventListener("resize", update);
3551
+ return () => {
3552
+ window.removeEventListener("scroll", update, true);
3553
+ window.removeEventListener("resize", update);
3554
+ cancelAnimationFrame(raf);
3555
+ };
3556
+ }, [pickerOpen]);
3243
3557
  /** Re-read both the list and the active pointer after any list mutation. */
3244
3558
  function syncSaved() {
3245
3559
  setList(saved.list());
@@ -3361,6 +3675,12 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3361
3675
  }
3362
3676
  function onKeyDown(e) {
3363
3677
  if (e.key !== "Escape") return;
3678
+ if (pickerOpenRef.current) {
3679
+ e.preventDefault();
3680
+ e.stopPropagation();
3681
+ closePicker();
3682
+ return;
3683
+ }
3364
3684
  if (confirmCloseRef.current || pendingLeaveRef.current) {
3365
3685
  e.preventDefault();
3366
3686
  e.stopPropagation();
@@ -3378,6 +3698,7 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3378
3698
  const target = e.target instanceof Element ? e.target : null;
3379
3699
  if (!target) return;
3380
3700
  if (target.closest("[data-ct-editor]")) return;
3701
+ if (target.closest("[role=\"menu\"]")) return;
3381
3702
  const panel = settingsPanel();
3382
3703
  if (!!panel && !panel.contains(target) || isCloseButton(target)) {
3383
3704
  if (!onRequestClose) return;
@@ -3414,6 +3735,7 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3414
3735
  }, [onRequestClose]);
3415
3736
  /** Open a fresh, unsaved theme seeded from the currently selected preset. */
3416
3737
  function startAdd() {
3738
+ closePicker();
3417
3739
  const origin = beginEditing(null, nextThemeName(t("custom.defaultName"), list.map((e) => e.name)), "", getCustom().theme);
3418
3740
  setCustomBase(shownPreset);
3419
3741
  const draft = resetCustom();
@@ -3422,6 +3744,7 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3422
3744
  }
3423
3745
  /** Open an existing card for editing; it also becomes the previewed theme. */
3424
3746
  function startEdit(entry) {
3747
+ closePicker();
3425
3748
  const next = beginEditing(entry.id, entry.name, entry.name, entry.theme);
3426
3749
  setEditing(next);
3427
3750
  onLoadSaved(entry.id);
@@ -3429,6 +3752,7 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3429
3752
  /** Discard the open editor and put the previously applied theme back. */
3430
3753
  function cancelEdit() {
3431
3754
  if (!editing) return;
3755
+ closePicker();
3432
3756
  revertEditing(editing);
3433
3757
  setEditing(null);
3434
3758
  syncSaved();
@@ -3491,6 +3815,7 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3491
3815
  /** Commit the open editor: create a new entry, or update the one being edited. */
3492
3816
  async function saveEdit() {
3493
3817
  if (!editing) return;
3818
+ closePicker();
3494
3819
  const name = editing.name.trim() || t("custom.defaultName");
3495
3820
  const id = editing.id;
3496
3821
  savingRef.current = true;
@@ -3547,6 +3872,7 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3547
3872
  setCustomState(getCustom().theme);
3548
3873
  return;
3549
3874
  }
3875
+ closePicker();
3550
3876
  if (editing) revertEditing(editing);
3551
3877
  setEditing(null);
3552
3878
  setSelectionState(shownPreset);
@@ -3593,7 +3919,7 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3593
3919
  react.createElement("div", {
3594
3920
  className: "ct-row ct-row-flush",
3595
3921
  key: "custom-toggle"
3596
- }, react.createElement("div", { className: "ct-row-main" }, react.createElement("div", { className: "ct-row-title" }, t("custom.title")), react.createElement("div", { className: "ct-row-desc" }, t("custom.toggle.desc"))), react.createElement(Switch, {
3922
+ }, react.createElement("div", { className: "ct-row-main" }, react.createElement("div", { className: "ct-row-title" }, t("custom.title")), react.createElement("div", { className: "ct-row-desc" }, t("custom.toggle.desc"))), react.createElement(_deepseek_ai_dsh_client_ui_primitives.Switch, {
3597
3923
  checked: customOn,
3598
3924
  label: t("custom.title"),
3599
3925
  onChange: toggleCustom
@@ -3604,18 +3930,21 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3604
3930
  const dotRow = (key, label, dots) => react.createElement("div", {
3605
3931
  className: "ct-seed-row",
3606
3932
  key
3607
- }, react.createElement("div", { className: "ct-seed-label" }, label), react.createElement("div", { className: "ct-seed-dots" }, ...dots.map((d) => react.createElement("label", {
3933
+ }, react.createElement("div", { className: "ct-seed-label" }, label), react.createElement("div", { className: "ct-seed-dots" }, ...dots.map((d) => react.createElement(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
3608
3934
  key: d.key,
3609
- className: "ct-seed-dot ct-tip",
3610
- style: { background: d.value },
3611
- "data-tip": d.name
3612
- }, react.createElement("input", {
3613
- className: "ct-seed-input",
3614
- type: "color",
3615
- value: d.value,
3616
- "aria-label": `${d.name} — ${d.hint}`,
3617
- onChange: (e) => d.onChange(e.target.value.toUpperCase())
3618
- })))));
3935
+ label: d.name,
3936
+ side: "top",
3937
+ gap: 6,
3938
+ children: react.createElement("button", {
3939
+ type: "button",
3940
+ className: "ct-seed-dot",
3941
+ style: { background: d.value },
3942
+ "aria-haspopup": "dialog",
3943
+ "aria-expanded": pickerDotKey === d.key,
3944
+ "aria-label": `${d.name} — ${d.hint}`,
3945
+ onClick: (e) => togglePicker(d.key, e.currentTarget)
3946
+ })
3947
+ }))));
3619
3948
  const pair = (key, title, desc) => ({
3620
3949
  key,
3621
3950
  name: t(title),
@@ -3672,21 +4001,24 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3672
4001
  })
3673
4002
  }));
3674
4003
  /** The light/dark segmented control above the dots. */
3675
- const modeButton = (id, label) => react.createElement("button", {
3676
- key: id,
3677
- type: "button",
3678
- className: seedMode === id ? "ct-mode-btn ct-mode-btn-on" : "ct-mode-btn",
3679
- "aria-pressed": seedMode === id,
3680
- onClick: () => {
3681
- setSeedMode(id);
3682
- previewAppearance(id);
3683
- }
3684
- }, label);
3685
- const modeToggle = react.createElement("div", {
3686
- className: "ct-mode",
3687
- role: "group",
3688
- "aria-label": t("custom.mode.label")
3689
- }, modeButton("light", t("custom.seed.light")), modeButton("dark", t("custom.seed.dark")));
4004
+ const modeToggle = react.createElement(_deepseek_ai_dsh_client_ui_primitives.SegmentedControl, {
4005
+ id: SEED_MODE_CONTROL_ID,
4006
+ value: seedMode,
4007
+ options: [{
4008
+ value: "light",
4009
+ label: t("custom.seed.light")
4010
+ }, {
4011
+ value: "dark",
4012
+ label: t("custom.seed.dark")
4013
+ }],
4014
+ onChange: (next) => {
4015
+ const mode = next;
4016
+ setSeedMode(mode);
4017
+ previewAppearance(mode);
4018
+ },
4019
+ label: t("custom.mode.label"),
4020
+ className: "ct-mode"
4021
+ });
3690
4022
  const editorName = react.createElement("input", {
3691
4023
  className: "ct-editor-name",
3692
4024
  type: "text",
@@ -3703,20 +4035,40 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3703
4035
  else if (e.key === "Escape") cancelEdit();
3704
4036
  }
3705
4037
  });
3706
- const editorActions = react.createElement("div", { className: "ct-editor-actions" }, react.createElement("button", {
3707
- type: "button",
3708
- className: "ct-btn",
4038
+ const editorActions = react.createElement("div", { className: "ct-editor-actions" }, react.createElement(_deepseek_ai_dsh_client_ui_primitives.Button, {
4039
+ variant: "outline",
3709
4040
  onClick: cancelEdit
3710
- }, t("custom.cancel")), react.createElement("button", {
3711
- type: "button",
3712
- className: "ct-btn ct-btn-primary",
4041
+ }, t("custom.cancel")), react.createElement(_deepseek_ai_dsh_client_ui_primitives.Button, {
4042
+ variant: "primary",
3713
4043
  onClick: () => void saveEdit()
3714
4044
  }, t("custom.save")));
4045
+ const pickerDot = pickerDotKey ? [...seedDots, ...shikiDots].find((d) => d.key === pickerDotKey) ?? null : null;
4046
+ const pickerPop = pickerDot && pickerPos ? react.createElement("div", {
4047
+ key: "color-picker",
4048
+ className: "ct-color-pop",
4049
+ ref: pickerPopRef,
4050
+ style: {
4051
+ left: pickerPos.left,
4052
+ top: pickerPos.top
4053
+ }
4054
+ }, react.createElement(Z, {
4055
+ color: pickerDot.value,
4056
+ onChange: (v) => pickerDot.onChange(v.toUpperCase())
4057
+ }), react.createElement(Oe, {
4058
+ className: "ct-hex-input",
4059
+ color: pickerDot.value,
4060
+ "aria-label": pickerDot.name,
4061
+ onChange: (v) => pickerDot.onChange(v.toUpperCase())
4062
+ })) : null;
3715
4063
  const editorCard = (key) => react.createElement("div", {
3716
4064
  className: "ct-editor",
3717
4065
  key,
3718
4066
  "data-ct-editor": "true"
3719
- }, react.createElement("div", { className: "ct-editor-head" }, editorName, modeToggle), dotRow("seeds", t("custom.group.seeds"), seedDots), dotRow("shiki", t("custom.group.shiki"), shikiDots), editorActions);
4067
+ }, react.createElement("div", { className: "ct-editor-head" }, editorName, modeToggle), react.createElement("div", {
4068
+ role: "tabpanel",
4069
+ id: `${SEED_MODE_CONTROL_ID}-${seedMode}-panel`,
4070
+ "aria-labelledby": `${SEED_MODE_CONTROL_ID}-${seedMode}`
4071
+ }, dotRow("seeds", t("custom.group.seeds"), seedDots), dotRow("shiki", t("custom.group.shiki"), shikiDots)), editorActions, pickerPop);
3720
4072
  const cards = list.map((entry) => editing && editing.id === entry.id ? editorCard(entry.id) : react.createElement(ThemeCard, {
3721
4073
  key: entry.id,
3722
4074
  entry,
@@ -3741,13 +4093,13 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3741
4093
  className: "ct-add-btn",
3742
4094
  disabled: importing,
3743
4095
  onClick: startImport
3744
- }, react.createElement(IconDownload, null), t("custom.import")), react.createElement("button", {
4096
+ }, react.createElement(_deepseek_ai_dsh_client_ui_primitives.IconDownloadOutlineRegular, { size: ICON_SIZE }), t("custom.import")), react.createElement("button", {
3745
4097
  key: "add",
3746
4098
  type: "button",
3747
4099
  className: "ct-add-btn",
3748
4100
  disabled: editing !== null,
3749
4101
  onClick: startAdd
3750
- }, react.createElement(IconPlus, null), t("custom.add")), react.createElement("input", {
4102
+ }, react.createElement(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineRegular, { size: ICON_SIZE }), t("custom.add")), react.createElement("input", {
3751
4103
  key: "import-input",
3752
4104
  ref: importInputRef,
3753
4105
  type: "file",
@@ -3762,6 +4114,7 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3762
4114
  description: t("custom.delete.desc").replace("{0}", pendingDelete.name),
3763
4115
  confirmLabel: t("custom.delete"),
3764
4116
  cancelLabel: t("custom.cancel"),
4117
+ danger: true,
3765
4118
  onConfirm: onConfirmDelete,
3766
4119
  onCancel: () => setPendingDelete(null)
3767
4120
  }));
@@ -3794,20 +4147,12 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3794
4147
  },
3795
4148
  onCancel: () => setPendingLeave(null)
3796
4149
  }));
3797
- if (toast) {
3798
- const onDone = () => setToast((cur) => cur?.seq === toast.seq ? null : cur);
3799
- const HostToast = getHostToast();
3800
- children.push(HostToast ? react.createElement(HostToast, {
3801
- key: `toast-${String(toast.seq)}`,
3802
- text: toast.text,
3803
- icon: react.createElement(ToastBadge),
3804
- onDone
3805
- }) : react.createElement(Toast, {
3806
- key: `toast-${String(toast.seq)}`,
3807
- text: toast.text,
3808
- onDone
3809
- }));
3810
- }
4150
+ if (toast) children.push(react.createElement(_deepseek_ai_dsh_client_ui_primitives.Toast, {
4151
+ key: `toast-${String(toast.seq)}`,
4152
+ text: toast.text,
4153
+ tone: "success",
4154
+ onDone: () => setToast((cur) => cur?.seq === toast.seq ? null : cur)
4155
+ }));
3811
4156
  return react.createElement("div", { style: {
3812
4157
  display: "flex",
3813
4158
  flexDirection: "column",
@@ -3978,19 +4323,6 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
3978
4323
  ".ct-select-label{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left;}",
3979
4324
  ".ct-select-chevron{flex:none;color:var(--dsw-alias-label-tertiary);display:inline-flex;transition:transform 120ms ease;}",
3980
4325
  ".ct-select[aria-expanded=\"true\"] .ct-select-chevron{transform:rotate(180deg);}",
3981
- ".ct-menu-list{box-sizing:border-box;padding:4px;display:flex;flex-direction:column;gap:0;border:1px solid var(--dsw-alias-border-inverted);border-radius:12px;background:var(--dsw-specific-menu);box-shadow:var(--dsw-shadow-lv3);min-width:218px;max-width:360px;max-height:min(320px,50vh);overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;scrollbar-gutter:stable;}",
3982
- ".ct-menu-list:not(:hover){scrollbar-color:transparent transparent;}",
3983
- ".ct-menu-list::-webkit-scrollbar{width:8px;height:8px;}",
3984
- ".ct-menu-list::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px;border:2px solid var(--dsw-specific-menu);background-clip:content-box;transition:background 150ms ease, border-color 150ms ease;}",
3985
- ".ct-menu-list::-webkit-scrollbar-thumb:hover{background:var(--dsw-alias-label-tertiary);border:2px solid var(--dsw-specific-menu);background-clip:content-box;}",
3986
- ".ct-menu-list::-webkit-scrollbar-thumb:active{background:var(--dsw-alias-label-secondary, var(--dsw-alias-label-tertiary));border:2px solid var(--dsw-specific-menu);background-clip:content-box;}",
3987
- ".ct-menu-list:not(:hover)::-webkit-scrollbar-thumb{background:transparent;border-color:transparent;}",
3988
- ".ct-menu-list::-webkit-scrollbar-track{background:transparent;margin:4px 0;}",
3989
- ".ct-menu-list::-webkit-scrollbar-corner{background:transparent;}",
3990
- ".ct-menu-item{display:flex;align-items:center;gap:8px;width:100%;min-height:40px;padding:8px 10px;border:none;border-radius:10px;background:transparent;cursor:pointer;font-size:14px;line-height:22px;color:var(--dsw-alias-label-primary);text-align:left;font-family:inherit;}",
3991
- ".ct-menu-item:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);}",
3992
- ".ct-menu-check{flex:none;color:var(--dsw-alias-label-primary);display:inline-flex;margin-left:auto;}",
3993
- ".ct-menu-item-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
3994
4326
  ".ct-row{border-bottom:1px solid var(--dsw-alias-border-l2);padding:16px 2px;display:flex;align-items:center;gap:16px;}",
3995
4327
  ".ct-row:last-child{border-bottom:none;}",
3996
4328
  ".ct-row-flush{border-bottom:none;}",
@@ -4000,13 +4332,12 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
4000
4332
  ".ct-seed-row{display:flex;align-items:center;gap:16px;padding:12px 0;}",
4001
4333
  ".ct-seed-label{flex:0 0 auto;min-width:96px;padding-left:3px;font-size:14px;line-height:22px;color:var(--dsw-alias-label-primary);}",
4002
4334
  ".ct-seed-dots{flex:1 1 auto;display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:10px;}",
4003
- ".ct-seed-dot{position:relative;box-sizing:border-box;display:inline-block;flex:none;width:26px;height:26px;border:1px solid var(--dsw-alias-border-l2);border-radius:50%;cursor:pointer;}",
4004
- ".ct-seed-input{position:absolute;inset:0;box-sizing:border-box;width:100%;height:100%;padding:0;border:none;background:transparent;opacity:0;cursor:pointer;}",
4005
- ".ct-seed-dot:focus-within{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3);}",
4006
- ".ct-tip::after{content:attr(data-tip);position:absolute;bottom:calc(100% + 6px);left:50%;transform:translateX(-50%);z-index:100;box-sizing:border-box;width:max-content;max-width:220px;padding:3px 7px;border-radius:8px;background:var(--dsw-alias-tooltip-bg);color:var(--dsw-static-neutral-bluish-00);font-size:13px;font-weight:400;line-height:20px;white-space:pre-line;overflow-wrap:break-word;text-align:left;pointer-events:none;opacity:0;visibility:hidden;transition:opacity 120ms ease;}",
4007
- ".ct-seed-dot:hover::after,.ct-seed-dot:focus-within::after{opacity:1;visibility:visible;}",
4008
- ".ct-list-btn:hover::after,.ct-list-btn:focus-visible::after{opacity:1;visibility:visible;}",
4009
- "@media (prefers-reduced-motion: reduce){.ct-tip::after{transition:none;}}",
4335
+ ".ct-seed-dot{position:relative;box-sizing:border-box;display:inline-block;flex:none;width:26px;height:26px;padding:0;border:1px solid var(--dsw-alias-border-l2);border-radius:50%;cursor:pointer;font:inherit;}",
4336
+ ".ct-seed-dot:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3);}",
4337
+ ".ct-color-pop{position:fixed;z-index:1200;box-sizing:border-box;width:224px;padding:12px;border:1px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-bg-layer-2);box-shadow:var(--dsw-shadow-lv3);display:flex;flex-direction:column;gap:10px;}",
4338
+ ".ct-color-pop .react-colorful{width:198px;height:170px;}",
4339
+ ".ct-color-pop .ct-hex-input{box-sizing:border-box;width:100%;height:34px;padding:0 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:20px;text-align:center;outline:none;}",
4340
+ ".ct-color-pop .ct-hex-input:focus{border-color:var(--dsw-alias-border-l3);}",
4010
4341
  ".ct-list{margin-top:4px;display:flex;flex-direction:column;gap:8px;}",
4011
4342
  ".ct-list-row{display:flex;align-items:center;gap:10px;padding:12px 14px;border:.5px solid var(--dsw-alias-border-l4);border-radius:16px;background:transparent;cursor:pointer;transition:border-color .16s ease,background .16s ease;}",
4012
4343
  ".ct-list-row:hover{background:var(--dsw-alias-interactive-bg-hover);}",
@@ -4016,7 +4347,7 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
4016
4347
  ".ct-list-actions{display:inline-flex;align-items:center;gap:4px;flex:none;margin-left:auto;}",
4017
4348
  ".ct-list-badge{display:inline-flex;align-items:center;height:28px;padding:0 10px;border-radius:14px;background:var(--dsw-alias-bg-module-platform,var(--dsw-alias-bg-layer-2));color:var(--dsw-alias-label-secondary,var(--dsw-alias-label-tertiary));font-size:12px;line-height:18px;white-space:nowrap;}",
4018
4349
  ".ct-list-badge + .ct-list-btn{margin-left:8px;}",
4019
- ".ct-list-btn{position:relative;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;height:28px;width:28px;padding:0;border:none;border-radius:14px;background:transparent;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;line-height:0;}",
4350
+ ".ct-list-btn{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;height:28px;width:28px;padding:0;border:none;border-radius:14px;background:transparent;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;line-height:0;}",
4020
4351
  ".ct-list-btn:hover{background:var(--dsw-alias-interactive-bg-hover);}",
4021
4352
  ".ct-list-btn:active{background:var(--dsw-alias-interactive-bg-active);}",
4022
4353
  ".ct-list-btn:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3);}",
@@ -4025,19 +4356,15 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
4025
4356
  ".ct-list-btn-danger{color:var(--dsw-alias-state-error-primary);}",
4026
4357
  ".ct-list-btn-danger:hover{background:var(--dsw-alias-interactive-bg-hover-danger);}",
4027
4358
  ".ct-list-btn-danger:active{background:var(--dsw-alias-interactive-bg-hover-danger);}",
4028
- ".ct-editor{padding:16px;border:.5px solid var(--dsw-alias-border-l4);border-radius:16px;background:transparent;display:flex;flex-direction:column;gap:0;}",
4359
+ ".ct-editor{padding:16px;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-lg);background:transparent;display:flex;flex-direction:column;gap:0;}",
4029
4360
  ".ct-editor-head{display:flex;align-items:center;gap:10px;padding-bottom:12px;}",
4030
4361
  ".ct-editor-name{flex:1 1 auto;min-width:0;box-sizing:border-box;height:36px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:14px;line-height:22px;}",
4031
4362
  ".ct-editor-name::placeholder{color:var(--dsw-alias-label-tertiary);}",
4032
4363
  ".ct-editor-name:hover{border-color:var(--dsw-alias-border-l3);}",
4033
4364
  ".ct-editor-name:focus{outline:none;border-color:var(--dsw-alias-border-l3);background:var(--dsw-alias-bg-base);}",
4034
- ".ct-mode{box-sizing:border-box;display:inline-flex;flex:none;height:36px;padding:2px;border-radius:10px;background:var(--dsw-alias-bg-module-platform,var(--dsw-alias-bg-layer-2));}",
4035
- ".ct-mode-btn{box-sizing:border-box;height:32px;padding:0 10px;border:none;border-radius:8px;background:transparent;color:var(--dsw-alias-label-tertiary);cursor:pointer;font:inherit;font-size:12px;line-height:18px;}",
4036
- ".ct-mode-btn:hover{color:var(--dsw-alias-label-primary);}",
4037
- ".ct-mode-btn-on{background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);}",
4038
- ".ct-mode-btn:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3);}",
4365
+ ".ct-mode{flex:none;}",
4039
4366
  ".ct-editor-actions{display:flex;justify-content:flex-end;gap:12px;padding-top:12px;}",
4040
- ".ct-add-btn{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:6px;width:100%;height:44px;margin-top:8px;padding:0 14px;border:1px dashed var(--dsw-alias-border-l3);border-radius:16px;background:transparent;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:14px;line-height:22px;}",
4367
+ ".ct-add-btn{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:6px;width:100%;height:44px;margin-top:8px;padding:0 14px;border:1px dashed var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-lg);background:transparent;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:14px;line-height:22px;}",
4041
4368
  ".ct-add-btn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);}",
4042
4369
  ".ct-add-btn:disabled{opacity:.4;cursor:default;}",
4043
4370
  ".ct-add-btn:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3);}",
@@ -4045,28 +4372,13 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
4045
4372
  ".ct-add-row .ct-add-btn{flex:1 1 0;width:auto;margin-top:0;min-width:0;}",
4046
4373
  ".ct-modal-root{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center;padding:24px;}",
4047
4374
  ".ct-modal-mask{position:absolute;inset:0;background:var(--dsw-alias-bg-mask-1,rgba(0,0,0,.24));backdrop-filter:var(--dsw-mask-blur,blur(2px));}",
4048
- ".ct-modal-card{position:relative;z-index:1;display:flex;flex-direction:column;gap:12px;width:min(380px,100%);padding:24px;border-radius:24px;background:var(--dsw-alias-bg-layer-2);box-shadow:var(--dsw-elevation-prominent);}",
4375
+ ".ct-modal-card{position:relative;z-index:1;display:flex;flex-direction:column;gap:12px;width:min(380px,100%);padding:24px;border-radius:var(--dsw-radius-panel);background:var(--dsw-alias-bg-layer-2);box-shadow:var(--dsw-elevation-prominent);}",
4049
4376
  ".ct-modal-title{font-size:16px;line-height:24px;font-weight:600;color:var(--dsw-alias-label-primary);}",
4050
4377
  ".ct-modal-desc{font-size:13px;line-height:20px;color:var(--dsw-alias-label-tertiary);}",
4051
4378
  ".ct-modal-footer{display:flex;justify-content:flex-end;gap:12px;margin-top:12px;}",
4052
- ".ct-switch{position:relative;flex:none;width:40px;height:24px;padding:0;border:none;border-radius:12px;background:var(--dsw-alias-border-l2);cursor:pointer;transition:background 150ms ease;}",
4053
- ".ct-switch-on{background:var(--dsw-static-deepseek-500,rgb(65,118,230));}",
4054
- ".ct-switch-knob{position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);transition:transform 150ms ease;}",
4055
- ".ct-switch-on .ct-switch-knob{transform:translateX(16px);}",
4056
- ".ct-switch:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3);}",
4057
- ".ct-btn{box-sizing:border-box;display:inline-flex;align-items:center;height:34px;padding:0 16px;border:1px solid var(--dsw-alias-border-l2);border-radius:17px;background:transparent;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:13px;line-height:20px;}",
4058
- ".ct-btn:hover{background:var(--dsw-alias-interactive-bg-hover);}",
4059
- ".ct-btn:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3);}",
4060
- ".ct-btn-primary{background:var(--dsw-static-deepseek-500,rgb(65,118,230));border-color:transparent;color:#fff;}",
4061
- ".ct-btn-primary:hover{background:var(--dsw-static-deepseek-450,var(--dsw-static-deepseek-500,rgb(86,134,254)));}",
4062
- ".ct-btn-danger{background:var(--dsw-static-red-500,rgb(239,68,68));border-color:transparent;color:#fff;}",
4063
- ".ct-btn-danger:hover{background:var(--dsw-static-red-600,var(--dsw-static-red-500,rgb(236,19,19)));}",
4064
- ".ct-toast{position:fixed;top:40px;left:50%;z-index:1100;pointer-events:none;display:flex;align-items:center;gap:10px;width:max-content;max-width:min(640px,calc(100vw - 48px));padding:12px 16px;border-radius:14px;background:var(--dsw-alias-button-contrast-fill);color:var(--dsw-alias-label-primary-inverted);font-size:14px;line-height:22px;box-shadow:var(--dsw-shadow-lv3);transform:translateX(-50%);animation:ct-toast-in 160ms ease-out,ct-toast-fade 1s ease 3s forwards;}",
4065
- ".ct-toast-icon{display:grid;place-items:center;flex:none;width:18px;height:18px;border:1.5px solid var(--dsw-alias-state-success-primary);border-radius:50%;corner-shape:round;color:var(--dsw-alias-state-success-primary);}",
4066
- ".ct-toast-text{min-width:0;}",
4067
- "@keyframes ct-toast-in{from{opacity:0;transform:translate(-50%,-6px);}to{opacity:1;transform:translate(-50%,0);}}",
4068
- "@keyframes ct-toast-fade{to{opacity:0;}}",
4069
- "@media (prefers-reduced-motion: reduce){.ct-toast{animation:ct-toast-fade 1s ease 3s forwards;}}"
4379
+ ".ct-action-cancel{min-width:72px}",
4380
+ ".ct-action-confirm{min-width:136px}",
4381
+ "button.ct-danger{color:var(--dsw-alias-state-error-primary);border-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 30%, transparent);--dsw-alias-interactive-bg-hover:color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);}"
4070
4382
  ].join("\n");
4071
4383
  function isValidSelection(v) {
4072
4384
  return !!v && (v === CUSTOM_SELECTION || NOOP_PRESET_IDS.has(v) || v in PRESETS);
@@ -4189,8 +4501,8 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
4189
4501
  /**
4190
4502
  * Coalesce a burst of palette applications into one.
4191
4503
  *
4192
- * A native colour input fires `change` on every pointer move while its slider
4193
- * is dragged. Each application rebuilds both ramps, rewrites every token on
4504
+ * A colour picker fires continuously while its slider is dragged. Each
4505
+ * application rebuilds both ramps, rewrites every token on
4194
4506
  * `body` and forces a style flush in the shell's presenter, so applying once
4195
4507
  * per event is what makes the colour editor stutter. The first change lands
4196
4508
  * immediately and the rest are throttled to one per interval, newest request
@@ -4345,13 +4657,6 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
4345
4657
  if (env && isPresetId(env.base)) lastPreset = env.base;
4346
4658
  }
4347
4659
  apply(initialSelection);
4348
- let sharedToast = null;
4349
- const modules = ctx.get("modules");
4350
- try {
4351
- modules?.import?.("@deepseek-ai/dsh-client-ui-primitives").then((mod) => {
4352
- if (typeof mod?.Toast === "function") sharedToast = mod.Toast;
4353
- }).catch(() => {});
4354
- } catch {}
4355
4660
  ctx.effect(() => () => {
4356
4661
  disposed = true;
4357
4662
  cancelApply();
@@ -4379,7 +4684,6 @@ html[data-ds-dark-theme], body[data-ds-dark-theme] {
4379
4684
  setCustomBase,
4380
4685
  resetCustom,
4381
4686
  saved,
4382
- getHostToast: () => sharedToast,
4383
4687
  onRequestClose: typeof props?.close === "function" ? props.close : null
4384
4688
  }));
4385
4689
  });