dsh-plugin-term-dictionary 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,557 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Shared inline styles for the panel and the popup.
5
+ *
6
+ * Only `--dsw-alias-*` and `--dsw-radius-*` theme tokens appear as colors, so the
7
+ * plugin follows light and dark themes without a second code path and degrades
8
+ * safely if a token is renamed. Geometry literals (padding, sizes) mirror the
9
+ * host's own management pages.
10
+ */
11
+
12
+ /** Font stack inherited from the host shell, with a CJK-capable fallback. */
13
+ const FONT = "inherit";
14
+
15
+ /** The panel and popup share one bordered-surface recipe. */
16
+ const surface = {
17
+ background: "var(--dsw-alias-bg-layer-1)",
18
+ border: "0.5px solid var(--dsw-alias-border-l3)",
19
+ borderRadius: "var(--dsw-radius-md, 10px)"
20
+ };
21
+
22
+ /** Text input recipe copied from the host's settings controls. */
23
+ const input = {
24
+ width: "100%",
25
+ boxSizing: "border-box",
26
+ font: FONT,
27
+ fontSize: "13px",
28
+ color: "var(--dsw-alias-label-primary)",
29
+ // The platform's own input fill. `--dsw-alias-bg-l1` (what this used to be) does
30
+ // not exist, and a `var()` with no fallback makes the whole declaration invalid at
31
+ // computed-value time — so the fields silently lost their background instead of
32
+ // falling back to anything.
33
+ background: "var(--dsw-specific-input-major, var(--dsw-alias-bg-base))",
34
+ border: "0.5px solid var(--dsw-alias-border-l3)",
35
+ borderRadius: "var(--dsw-radius-sm, 6px)",
36
+ padding: "6px 8px",
37
+ outline: "none"
38
+ };
39
+
40
+ /** The panel's search field, minus its icon gutter. */
41
+ const SEARCH_INPUT_STYLE = {
42
+ ...input,
43
+ paddingLeft: "28px",
44
+ background: "transparent",
45
+ border: "none"
46
+ };
47
+
48
+ /** Style table consumed by the views; kept as one object so tests can assert it. */
49
+ const applyStyles = {
50
+ panel: {
51
+ display: "flex",
52
+ flexDirection: "column",
53
+ height: "100%",
54
+ minHeight: 0,
55
+ boxSizing: "border-box",
56
+ color: "var(--dsw-alias-label-primary)",
57
+ font: FONT,
58
+ background: "var(--dsw-specific-sidebar-fill, transparent)"
59
+ },
60
+ header: {
61
+ display: "flex",
62
+ alignItems: "flex-start",
63
+ gap: "12px",
64
+ padding: "18px 20px 10px"
65
+ },
66
+ headerText: { display: "flex", flexDirection: "column", gap: "2px", minWidth: 0, flex: "1 1 auto" },
67
+ title: { margin: 0, fontSize: "15px", fontWeight: 600, lineHeight: 1.4 },
68
+ subtitle: { margin: 0, fontSize: "12px", color: "var(--dsw-alias-label-tertiary)", lineHeight: 1.4 },
69
+ searchRow: {
70
+ display: "flex",
71
+ alignItems: "center",
72
+ gap: "6px",
73
+ margin: "0 20px 8px",
74
+ padding: "0 8px",
75
+ border: "0.5px solid var(--dsw-alias-border-l3)",
76
+ borderRadius: "var(--dsw-radius-sm, 6px)",
77
+ background: "var(--dsw-specific-input-major, var(--dsw-alias-bg-base))"
78
+ },
79
+ searchIcon: { display: "flex", color: "var(--dsw-alias-label-tertiary)", flex: "none" },
80
+ tabs: { display: "flex", gap: "4px", padding: "0 20px 10px" },
81
+ tab: {
82
+ appearance: "none",
83
+ font: FONT,
84
+ fontSize: "12px",
85
+ color: "var(--dsw-alias-label-secondary)",
86
+ background: "transparent",
87
+ border: "none",
88
+ borderRadius: "var(--dsw-radius-sm, 6px)",
89
+ padding: "3px 8px",
90
+ cursor: "pointer"
91
+ },
92
+ tabActive: {
93
+ color: "var(--dsw-alias-label-primary)",
94
+ background: "var(--dsw-alias-interactive-bg-hover)"
95
+ },
96
+ notice: {
97
+ display: "flex",
98
+ alignItems: "center",
99
+ gap: "8px",
100
+ margin: "0 20px 8px",
101
+ padding: "6px 10px",
102
+ fontSize: "12px",
103
+ color: "var(--dsw-alias-label-secondary)",
104
+ background: "var(--dsw-alias-bg-layer-2, transparent)",
105
+ border: "0.5px solid var(--dsw-alias-border-l3)",
106
+ borderRadius: "var(--dsw-radius-sm, 6px)"
107
+ },
108
+ error: { margin: 0, fontSize: "12px", color: "var(--dsw-alias-state-error-primary)" },
109
+ list: { flex: "1 1 auto", minHeight: 0, overflowY: "auto", padding: "0 20px 16px", display: "flex", flexDirection: "column", gap: "8px" },
110
+ blank: { margin: "8px 0", fontSize: "13px", lineHeight: 1.6, color: "var(--dsw-alias-label-tertiary)" },
111
+ row: {
112
+ ...surface,
113
+ display: "flex",
114
+ flexDirection: "column",
115
+ gap: "4px",
116
+ padding: "10px 12px",
117
+ // The whole block opens the entry, so say so before the click: a reader who has to discover
118
+ // that by trial will click the name — which is what they did.
119
+ cursor: "pointer"
120
+ },
121
+ /** The row a transcript click asked to reveal, before the cue fades. */
122
+ rowRevealed: {
123
+ borderColor: "var(--dsw-alias-brand-primary, #4d6bfe)",
124
+ boxShadow: "0 0 0 1px var(--dsw-alias-brand-primary, #4d6bfe)"
125
+ },
126
+ rowHead: { display: "flex", alignItems: "center", gap: "6px", flexWrap: "wrap" },
127
+ termButton: {
128
+ appearance: "none",
129
+ background: "transparent",
130
+ border: "none",
131
+ padding: 0,
132
+ font: FONT,
133
+ fontSize: "14px",
134
+ fontWeight: 600,
135
+ color: "var(--dsw-alias-label-primary)",
136
+ cursor: "pointer",
137
+ textAlign: "left"
138
+ },
139
+ zh: { fontSize: "13px", color: "var(--dsw-alias-label-secondary)" },
140
+ domain: { fontSize: "11px", color: "var(--dsw-alias-label-tertiary)", whiteSpace: "nowrap" },
141
+ spacer: { flex: "1 1 auto" },
142
+ badge: {
143
+ fontSize: "10px",
144
+ lineHeight: 1.6,
145
+ padding: "0 6px",
146
+ borderRadius: "999px",
147
+ color: "var(--dsw-alias-label-secondary)",
148
+ background: "var(--dsw-alias-bg-base)",
149
+ border: "0.5px solid var(--dsw-alias-border-l2)"
150
+ },
151
+ badgeWarn: {
152
+ fontSize: "10px",
153
+ lineHeight: 1.6,
154
+ padding: "0 6px",
155
+ borderRadius: "999px",
156
+ color: "var(--dsw-alias-state-warn-primary, var(--dsw-alias-label-secondary))",
157
+ border: "0.5px dashed var(--dsw-alias-border-l3)"
158
+ },
159
+ gloss: { margin: 0, fontSize: "13px", lineHeight: 1.65, color: "var(--dsw-alias-label-secondary)" },
160
+ glossMuted: { margin: 0, fontSize: "13px", fontStyle: "italic", color: "var(--dsw-alias-label-tertiary)" },
161
+ usage: {
162
+ margin: 0,
163
+ fontSize: "12px",
164
+ lineHeight: 1.6,
165
+ color: "var(--dsw-alias-label-tertiary)",
166
+ paddingLeft: "8px",
167
+ borderLeft: "2px solid var(--dsw-alias-border-l2)"
168
+ },
169
+ meta: { margin: 0, fontSize: "11px", color: "var(--dsw-alias-label-caption, var(--dsw-alias-label-tertiary))" },
170
+ /**
171
+ * A context line, clamped to three lines.
172
+ *
173
+ * The editor renders its context directly under the title, so an unbounded context
174
+ * does not merely look untidy — it takes the whole panel and pushes the fields and
175
+ * the Save button out of reach. The collector and the selection path now bound what
176
+ * they store, and this clamp means even a legacy or imported entry with a huge
177
+ * context can never do that again.
178
+ */
179
+ context: {
180
+ margin: 0,
181
+ fontSize: "12px",
182
+ lineHeight: 1.6,
183
+ color: "var(--dsw-alias-label-tertiary)",
184
+ display: "-webkit-box",
185
+ WebkitLineClamp: 3,
186
+ WebkitBoxOrient: "vertical",
187
+ overflow: "hidden",
188
+ overflowWrap: "anywhere"
189
+ },
190
+ storageNote: {
191
+ margin: 0,
192
+ padding: "6px 20px",
193
+ fontSize: "11px",
194
+ color: "var(--dsw-alias-label-caption, var(--dsw-alias-label-tertiary))",
195
+ overflowWrap: "anywhere"
196
+ },
197
+ footer: {
198
+ display: "flex",
199
+ alignItems: "center",
200
+ gap: "12px",
201
+ padding: "8px 20px 12px",
202
+ borderTop: "0.5px solid var(--dsw-alias-border-l2)",
203
+ fontSize: "11px",
204
+ color: "var(--dsw-alias-label-tertiary)"
205
+ },
206
+ linkButton: {
207
+ appearance: "none",
208
+ background: "transparent",
209
+ border: "none",
210
+ padding: 0,
211
+ font: FONT,
212
+ fontSize: "11px",
213
+ color: "var(--dsw-alias-brand-primary, var(--dsw-alias-label-secondary))",
214
+ cursor: "pointer"
215
+ },
216
+ iconButton: {
217
+ appearance: "none",
218
+ display: "inline-flex",
219
+ alignItems: "center",
220
+ justifyContent: "center",
221
+ width: "24px",
222
+ height: "24px",
223
+ padding: 0,
224
+ border: "none",
225
+ borderRadius: "var(--dsw-radius-sm, 6px)",
226
+ background: "transparent",
227
+ color: "var(--dsw-alias-label-secondary)",
228
+ cursor: "pointer",
229
+ flex: "none"
230
+ },
231
+ iconButtonActive: {
232
+ color: "var(--dsw-alias-brand-primary, var(--dsw-alias-label-primary))",
233
+ background: "var(--dsw-alias-interactive-bg-hover)"
234
+ },
235
+
236
+ //#region the settings page and batch selection
237
+ /** The settings page: one preference per line, each with its own explanation. */
238
+ settingsPage: { padding: "0 20px 12px", display: "flex", flexDirection: "column", gap: "2px" },
239
+ /**
240
+ * One preference line.
241
+ *
242
+ * Was a wrapping row of chips under the tabs; the page has room to say what each preference
243
+ * DOES, and a row never did.
244
+ */
245
+ settingRow: {
246
+ display: "flex",
247
+ alignItems: "flex-start",
248
+ justifyContent: "space-between",
249
+ gap: "12px",
250
+ padding: "8px 0",
251
+ borderBottom: "0.5px solid var(--dsw-alias-border-l2)"
252
+ },
253
+ /** The text half of a preference line. */
254
+ settingText: { display: "flex", flexDirection: "column", gap: "2px", minWidth: 0 },
255
+ settingLabel: { margin: 0, font: FONT, fontSize: "12px", color: "var(--dsw-alias-label-primary)" },
256
+ settingHint: { margin: 0, font: FONT, fontSize: "11px", lineHeight: 1.5, color: "var(--dsw-alias-label-tertiary)" },
257
+ /**
258
+ * A two-state preference: a track and a knob.
259
+ *
260
+ * The chip this replaces put its state in its own label ("收代码术语" / "不收代码术语"), so the
261
+ * row's NAME changed as you used it. A switch says the same thing without moving any text,
262
+ * which is what lets a settings row keep one name and one explanation.
263
+ */
264
+ toggleTrack: {
265
+ appearance: "none",
266
+ position: "relative",
267
+ flex: "0 0 auto",
268
+ width: "34px",
269
+ height: "18px",
270
+ padding: 0,
271
+ border: "0.5px solid var(--dsw-alias-border-l2)",
272
+ borderRadius: "999px",
273
+ background: "var(--dsw-specific-input-major, var(--dsw-alias-bg-base))",
274
+ cursor: "pointer",
275
+ transition: "background-color 120ms ease, border-color 120ms ease"
276
+ },
277
+ toggleTrackOn: {
278
+ background: "var(--dsw-alias-button-primary-fill, var(--dsw-alias-brand-primary))",
279
+ borderColor: "transparent"
280
+ },
281
+ toggleKnob: {
282
+ position: "absolute",
283
+ top: "50%",
284
+ left: "2px",
285
+ width: "12px",
286
+ height: "12px",
287
+ marginTop: "-6px",
288
+ borderRadius: "999px",
289
+ background: "var(--dsw-alias-label-secondary)",
290
+ transition: "left 120ms ease, background-color 120ms ease"
291
+ },
292
+ toggleKnobOn: { left: "18px", background: "var(--dsw-alias-label-primary-inverted)" },
293
+ /**
294
+ * Three or more values: an option bar.
295
+ *
296
+ * Every value is visible at once and the chosen one is marked, so the control answers "what
297
+ * are my choices" as well as "what is it now". The cycling chip it replaces did neither
298
+ * without clicking: to learn the options you had to click until they came round again, and to
299
+ * reach one you clicked past the others.
300
+ */
301
+ optionBar: {
302
+ display: "inline-flex",
303
+ flex: "0 0 auto",
304
+ gap: "2px",
305
+ padding: "2px",
306
+ border: "0.5px solid var(--dsw-alias-border-l2)",
307
+ borderRadius: "8px"
308
+ },
309
+ optionItem: {
310
+ appearance: "none",
311
+ border: "none",
312
+ background: "transparent",
313
+ font: FONT,
314
+ fontSize: "11px",
315
+ lineHeight: 1.6,
316
+ padding: "2px 8px",
317
+ borderRadius: "6px",
318
+ color: "var(--dsw-alias-label-secondary)",
319
+ cursor: "pointer",
320
+ whiteSpace: "nowrap"
321
+ },
322
+ optionItemActive: {
323
+ background: "var(--dsw-alias-interactive-bg-hover)",
324
+ color: "var(--dsw-alias-label-primary)"
325
+ },
326
+ /**
327
+ * A delay: a slider plus a box for the exact number.
328
+ *
329
+ * One control in two shapes because the job is two jobs — sweeping to find a feel, and typing a
330
+ * value already in mind. The box is deliberately narrow: it holds three digits.
331
+ */
332
+ delayField: { display: "inline-flex", flex: "0 0 auto", alignItems: "center", gap: "6px" },
333
+ delaySlider: { width: "110px", accentColor: "var(--dsw-alias-brand-primary, #4d6bfe)" },
334
+ delayBox: {
335
+ width: "52px",
336
+ font: FONT,
337
+ fontSize: "11px",
338
+ padding: "2px 4px",
339
+ textAlign: "right",
340
+ color: "var(--dsw-alias-label-primary)",
341
+ background: "var(--dsw-specific-input-major, var(--dsw-alias-bg-base))",
342
+ border: "0.5px solid var(--dsw-alias-border-l2)",
343
+ borderRadius: "6px"
344
+ },
345
+ delayUnit: { font: FONT, fontSize: "11px", color: "var(--dsw-alias-label-tertiary)" },
346
+ /** The bar that appears while rows can be picked. */
347
+ selectBar: {
348
+ display: "flex",
349
+ alignItems: "center",
350
+ gap: "8px",
351
+ flexWrap: "wrap",
352
+ margin: "0 20px 8px",
353
+ padding: "6px 10px",
354
+ fontSize: "12px",
355
+ color: "var(--dsw-alias-label-secondary)",
356
+ background: "var(--dsw-alias-bg-layer-2, transparent)",
357
+ border: "0.5px solid var(--dsw-alias-border-l3)",
358
+ borderRadius: "var(--dsw-radius-sm, 6px)"
359
+ },
360
+ /** A row that is being picked rather than read. */
361
+ rowPicking: {
362
+ ...surface,
363
+ display: "flex",
364
+ alignItems: "center",
365
+ gap: "8px",
366
+ padding: "8px 10px",
367
+ cursor: "pointer"
368
+ },
369
+ checkbox: {
370
+ width: "15px",
371
+ height: "15px",
372
+ flex: "none",
373
+ margin: 0,
374
+ // The host styles its own radios and checkboxes with exactly this property.
375
+ accentColor: "var(--dsw-alias-brand-primary)"
376
+ },
377
+ //#endregion
378
+
379
+ //#region the import/export page, and the deleted view
380
+ /** A row of controls on the transfer page: an option bar, or the download/copy pair. */
381
+ transferRow: { display: "flex", alignItems: "center", gap: "8px", flexWrap: "wrap", padding: "2px 0 8px" },
382
+ /** The category checklist. */
383
+ transferList: { display: "flex", flexDirection: "column", gap: "2px", padding: "0 0 8px" },
384
+ /**
385
+ * One selectable category.
386
+ *
387
+ * A `<label>`, so the whole line is the hit target rather than the 15px box: the checkbox is the
388
+ * control, and next to it the count is what decides which categories are worth exporting.
389
+ */
390
+ transferItem: { display: "flex", alignItems: "center", gap: "8px", padding: "3px 0", fontSize: "12px", color: "var(--dsw-alias-label-primary)", cursor: "pointer" },
391
+ transferName: { flex: "1 1 auto", minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
392
+ transferCount: { flex: "none", fontSize: "11px", color: "var(--dsw-alias-label-caption, var(--dsw-alias-label-tertiary))" },
393
+ /** The file picker. Chrome renders it; it only needs to sit with the rest of the page. */
394
+ transferFile: { font: FONT, fontSize: "12px", color: "var(--dsw-alias-label-secondary)", padding: "2px 0 6px" },
395
+ /**
396
+ * The name of an entry the user deleted.
397
+ *
398
+ * Struck through, because the row is the record of a decision rather than a term to read — and
399
+ * the row is the only place the two states are ever side by side.
400
+ */
401
+ deletedTerm: { fontSize: "13px", color: "var(--dsw-alias-label-secondary)", textDecoration: "line-through" },
402
+ /** A term that is only being named, not offered as a control (the flagged rows). */
403
+ termPlain: { fontSize: "13px", fontWeight: 500, color: "var(--dsw-alias-label-primary)" },
404
+ /**
405
+ * The flagged view's own column.
406
+ *
407
+ * Same reason as the deleted view: the panel's list `gap` reaches only its direct children, and
408
+ * this view is a single child holding the hint and every row.
409
+ */
410
+ flaggedList: { display: "flex", flexDirection: "column", gap: "8px" },
411
+ /**
412
+ * The deleted view's own column.
413
+ *
414
+ * The panel's list is a column too, but its `gap` only reaches its DIRECT children — and this view
415
+ * is one child holding the hint and every row, so without a column of its own the cards would sit
416
+ * flush against each other.
417
+ */
418
+ deletedList: { display: "flex", flexDirection: "column", gap: "8px" },
419
+ //#endregion
420
+
421
+ editorBody: { flex: "1 1 auto", minHeight: 0, overflowY: "auto", padding: "0 20px 16px", display: "flex", flexDirection: "column", gap: "12px" },
422
+ field: { display: "flex", flexDirection: "column", gap: "4px" },
423
+ fieldLabel: { fontSize: "12px", color: "var(--dsw-alias-label-secondary)" },
424
+ input,
425
+ searchInput: SEARCH_INPUT_STYLE,
426
+ actions: { display: "flex", gap: "8px", flexWrap: "wrap", paddingTop: "4px" },
427
+ button: {
428
+ appearance: "none",
429
+ font: FONT,
430
+ fontSize: "13px",
431
+ color: "var(--dsw-alias-label-primary)",
432
+ background: "var(--dsw-alias-bg-base)",
433
+ border: "0.5px solid var(--dsw-alias-border-l3)",
434
+ borderRadius: "var(--dsw-radius-sm, 6px)",
435
+ padding: "5px 12px",
436
+ cursor: "pointer"
437
+ },
438
+ primaryButton: {
439
+ appearance: "none",
440
+ font: FONT,
441
+ fontSize: "13px",
442
+ fontWeight: 600,
443
+ // The host's own primary-button pair.
444
+ //
445
+ // This used to be `var(--dsw-alias-brand-primary)` with
446
+ // `var(--dsw-alias-label-inverse, #fff)`. Neither name is real: the design
447
+ // platform has no `--dsw-alias-label-inverse`, so the label fell back to white,
448
+ // and in the DARK theme `--dsw-alias-brand-primary` is
449
+ // `--dsw-static-neutral-bluish-50` — near-white, the same value the theme gives
450
+ // `--dsw-alias-label-primary`. The label and the fill were therefore both white
451
+ // and the Save button rendered as an empty rectangle.
452
+ //
453
+ // The values below are the ones the platform defines for exactly this job:
454
+ // `button-primary-fill` is the brand fill and `label-primary-inverted` is the
455
+ // text that sits on it — white-on-near-black in the light theme, dark-on-
456
+ // near-white in the dark one. Measured from the shipped theme CSS, not assumed.
457
+ color: "var(--dsw-alias-label-primary-inverted)",
458
+ background: "var(--dsw-alias-button-primary-fill)",
459
+ border: "0.5px solid transparent",
460
+ borderRadius: "var(--dsw-radius-sm, 6px)",
461
+ padding: "5px 12px",
462
+ cursor: "pointer"
463
+ },
464
+
465
+ //#region popup
466
+ popup: {
467
+ ...surface,
468
+ position: "fixed",
469
+ zIndex: 2147483000,
470
+ width: "min(360px, calc(100vw - 24px))",
471
+ maxHeight: "min(60vh, 420px)",
472
+ overflowY: "auto",
473
+ boxShadow: "0 8px 28px rgba(0, 0, 0, 0.18)",
474
+ padding: "12px 14px",
475
+ display: "flex",
476
+ flexDirection: "column",
477
+ gap: "6px",
478
+ font: FONT,
479
+ color: "var(--dsw-alias-label-primary)"
480
+ },
481
+ popupHead: { display: "flex", alignItems: "baseline", gap: "8px", flexWrap: "wrap" },
482
+ popupTerm: { margin: 0, fontSize: "15px", fontWeight: 600, lineHeight: 1.3 },
483
+ popupZh: { fontSize: "13px", color: "var(--dsw-alias-label-secondary)" },
484
+ popupGloss: { margin: 0, fontSize: "13px", lineHeight: 1.7, color: "var(--dsw-alias-label-secondary)", whiteSpace: "pre-wrap" },
485
+ popupUsage: {
486
+ margin: 0,
487
+ fontSize: "12px",
488
+ lineHeight: 1.6,
489
+ color: "var(--dsw-alias-label-tertiary)",
490
+ paddingLeft: "8px",
491
+ borderLeft: "2px solid var(--dsw-alias-border-l2)",
492
+ whiteSpace: "pre-wrap"
493
+ },
494
+ popupMeta: { display: "flex", alignItems: "center", gap: "8px", flexWrap: "wrap", fontSize: "11px", color: "var(--dsw-alias-label-caption, var(--dsw-alias-label-tertiary))" },
495
+ popupActions: { display: "flex", alignItems: "center", gap: "8px", flexWrap: "wrap", paddingTop: "2px" },
496
+ popupContext: {
497
+ margin: 0,
498
+ fontSize: "12px",
499
+ lineHeight: 1.6,
500
+ color: "var(--dsw-alias-label-tertiary)",
501
+ overflowWrap: "anywhere"
502
+ },
503
+ //#endregion
504
+
505
+ //#region hover hint
506
+ //
507
+ // REMOVED with the hover gesture (2026-10-09). The pointer layer belongs to
508
+ // dsh-plugin-term-wikilink, which brings its own card styles; keeping this region would
509
+ // keep a second, unreachable definition of "what a hover card looks like" — and the two
510
+ // would drift the moment the inline styles change, which is precisely the confusion the
511
+ // merge is meant to end.
512
+ //#endregion
513
+
514
+
515
+ //#region selection affordance
516
+ selectionButton: {
517
+ ...surface,
518
+ position: "fixed",
519
+ zIndex: 2147483001,
520
+ display: "inline-flex",
521
+ alignItems: "center",
522
+ gap: "6px",
523
+ padding: "5px 10px",
524
+ font: FONT,
525
+ fontSize: "12px",
526
+ color: "var(--dsw-alias-label-primary)",
527
+ boxShadow: "0 4px 14px rgba(0, 0, 0, 0.16)",
528
+ cursor: "pointer"
529
+ },
530
+ toast: {
531
+ ...surface,
532
+ position: "fixed",
533
+ left: "50%",
534
+ bottom: "28px",
535
+ transform: "translateX(-50%)",
536
+ zIndex: 2147483002,
537
+ display: "flex",
538
+ alignItems: "center",
539
+ gap: "12px",
540
+ padding: "8px 14px",
541
+ font: FONT,
542
+ fontSize: "13px",
543
+ color: "var(--dsw-alias-label-primary)",
544
+ boxShadow: "0 6px 20px rgba(0, 0, 0, 0.18)",
545
+ // A NOTICE MUST NOT EAT INPUT.
546
+ //
547
+ // This sits at the bottom centre with the highest z-index in the plugin — which is exactly
548
+ // where the composer is. Without this line it swallowed every click in its rectangle for the
549
+ // six seconds it lived, so deleting an entry, importing, exporting or clearing the dictionary
550
+ // left the input box unusable until the notice timed out. The interactive parts opt back in
551
+ // (see the toast's own buttons), so undo and close still work.
552
+ pointerEvents: "none"
553
+ }
554
+ //#endregion
555
+ };
556
+
557
+ module.exports = { applyStyles, SEARCH_INPUT_STYLE, surface, input, FONT };