@panda-lingo/goldendict 0.1.4 → 0.1.7

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/README.md CHANGED
@@ -17,6 +17,23 @@ view.client = new DictionaryClient({ baseUrl: "/api/v1" });
17
17
  await view.lookup("example");
18
18
  ```
19
19
 
20
+ `baseUrl` is the complete public API mount, including a reverse-proxy prefix
21
+ when one exists. GoldenDict-rooted article resources are rebased through that
22
+ mount, so a host can expose the service at a route such as `/api/v1/mdict`
23
+ without rewriting lookup payloads:
24
+
25
+ ```ts
26
+ view.client = new DictionaryClient({ baseUrl: "/api/v1/mdict" });
27
+ ```
28
+
29
+ Search-first hosts can request bounded prefix suggestions through the same
30
+ client and API base before committing an article lookup:
31
+
32
+ ```ts
33
+ const result = await view.client.suggestions("exam", { limit: 20 });
34
+ console.log(result.suggestions);
35
+ ```
36
+
20
37
  Importing the package registers `<goldendict-view>` automatically. Call
21
38
  `defineGoldendictView("my-dictionary-view")` when a custom tag name is useful.
22
39
 
@@ -64,8 +81,8 @@ it when a particular dictionary requires different behavior. Set
64
81
 
65
82
  The public API includes:
66
83
 
67
- - `DictionaryClient` for dictionary listing and lookup, plus the backend's
68
- explicitly opt-in server-path load operation.
84
+ - `DictionaryClient` for dictionary listing, prefix suggestions, and lookup,
85
+ plus the backend's explicitly opt-in server-path load operation.
69
86
  - `GoldenDictView` and `defineGoldendictView` for framework-independent use.
70
87
  - `GoldenDictTheme`, light/dark token presets, and `themeToCss` for branding.
71
88
  - `GOLDENDICT_EVENTS` for lookup, active article, collapse, media, external-link,
@@ -1,4 +1,4 @@
1
- import type { DictionaryClientOptions, DictionarySummary, LoadDictionaryRequest, LoadDictionaryResponse, LookupOptions, LookupResponse } from "../types";
1
+ import type { DictionaryClientOptions, DictionarySummary, LoadDictionaryRequest, LoadDictionaryResponse, LookupOptions, LookupResponse, SuggestionsOptions, SuggestionsResponse } from "../types";
2
2
  export declare class DictionaryApiError extends Error {
3
3
  readonly status: number;
4
4
  readonly body: unknown;
@@ -13,6 +13,7 @@ export declare class DictionaryClient {
13
13
  listDictionaries(signal?: AbortSignal): Promise<DictionarySummary[]>;
14
14
  loadDictionary(input: LoadDictionaryRequest, signal?: AbortSignal): Promise<LoadDictionaryResponse>;
15
15
  lookup(word: string, options?: LookupOptions): Promise<LookupResponse>;
16
+ suggestions(prefix: string, options?: SuggestionsOptions): Promise<SuggestionsResponse>;
16
17
  private request;
17
18
  }
18
19
  //# sourceMappingURL=dictionary-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dictionary-client.d.ts","sourceRoot":"","sources":["../../src/client/dictionary-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,aAAa,EACb,cAAc,EACf,MAAM,UAAU,CAAC;AAElB,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO;CAM5D;AAiDD,qBAAa,gBAAgB;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0B;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAC3D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;gBAErC,OAAO,GAAE,uBAA4B;IAW3C,gBAAgB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAQpE,cAAc,CAClB,KAAK,EAAE,qBAAqB,EAC5B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,sBAAsB,CAAC;IA6B5B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,cAAc,CAAC;YAsBlE,OAAO;CAoCtB"}
1
+ {"version":3,"file":"dictionary-client.d.ts","sourceRoot":"","sources":["../../src/client/dictionary-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,UAAU,CAAC;AAElB,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO;CAM5D;AAiDD,qBAAa,gBAAgB;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0B;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAC3D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;gBAErC,OAAO,GAAE,uBAA4B;IAW3C,gBAAgB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAQpE,cAAc,CAClB,KAAK,EAAE,qBAAqB,EAC5B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,sBAAsB,CAAC;IA6B5B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,cAAc,CAAC;IAsB1E,WAAW,CACf,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,mBAAmB,CAAC;YA2BjB,OAAO;CAoCtB"}
package/dist/index.js CHANGED
@@ -84,6 +84,28 @@ class v {
84
84
  lookupTimeMs: r.lookupTimeMs ?? 0
85
85
  };
86
86
  }
87
+ async suggestions(e, o = {}) {
88
+ const t = e.trim();
89
+ if (!t)
90
+ throw new TypeError("Suggestion prefix must not be empty");
91
+ const n = o.limit ?? 20;
92
+ if (!Number.isInteger(n) || n < 1 || n > 100)
93
+ throw new RangeError("Suggestion limit must be an integer between 1 and 100");
94
+ const a = new URLSearchParams({
95
+ prefix: t,
96
+ limit: String(n)
97
+ });
98
+ o.dictionaryIds?.length && a.set("dictionary_ids", o.dictionaryIds.join(","));
99
+ const r = await this.request(
100
+ `/suggestions?${a.toString()}`,
101
+ { signal: o.signal }
102
+ );
103
+ return {
104
+ prefix: r.prefix ?? t,
105
+ suggestions: r.suggestions ?? [],
106
+ lookupTimeMs: r.lookupTimeMs ?? 0
107
+ };
108
+ }
87
109
  async request(e, o = {}) {
88
110
  const t = await this.fetchImpl(`${this.baseUrl}${e}`, {
89
111
  ...o,
@@ -108,7 +130,7 @@ class v {
108
130
  return n;
109
131
  }
110
132
  }
111
- const U = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
133
+ const R = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
112
134
  <!-- Created with Inkscape (http://www.inkscape.org/) -->
113
135
 
114
136
  <svg
@@ -154,7 +176,7 @@ const U = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
154
176
  sodipodi:nodetypes="cccc" />
155
177
  </g>
156
178
  </svg>
157
- `, R = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfmAxMKDTHgIis/AAAAwUlEQVQoz33RsUtCcRTF8U+vJ8/RCAKHdEoc+isachBcMhranQQXt/YIGmxrLAgRac/JFsP+jVqaHVvkuTy0V/08dzzfC/eew2+1FWxRz1KCG42/ZuxeKpWgaeYub++ZStcAsRcddgwdgCPVDC1qOHat7F2dz2xvMwluXeDBWQgomeDSIAp8s1DEh8PIdqUhoOQbFV8h4MojTsxjb9mbNZW13bIwtu9U72dQr7mgeNIPR10z9CwKlzXStfv/eef5uldwrDr7rieveQAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMi0wMy0xOVQxMDoxMzo0OSswMDowMH0jItoAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjItMDMtMTlUMTA6MTM6NDkrMDA6MDAMfppmAAAAAElFTkSuQmCC", F = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
179
+ `, U = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfmAxMKDTHgIis/AAAAwUlEQVQoz33RsUtCcRTF8U+vJ8/RCAKHdEoc+isachBcMhranQQXt/YIGmxrLAgRac/JFsP+jVqaHVvkuTy0V/08dzzfC/eew2+1FWxRz1KCG42/ZuxeKpWgaeYub++ZStcAsRcddgwdgCPVDC1qOHat7F2dz2xvMwluXeDBWQgomeDSIAp8s1DEh8PIdqUhoOQbFV8h4MojTsxjb9mbNZW13bIwtu9U72dQr7mgeNIPR10z9CwKlzXStfv/eef5uldwrDr7rieveQAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMi0wMy0xOVQxMDoxMzo0OSswMDowMH0jItoAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjItMDMtMTlUMTA6MTM6NDkrMDA6MDAMfppmAAAAAElFTkSuQmCC", F = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
158
180
  <!-- Created with Inkscape (http://www.inkscape.org/) -->
159
181
 
160
182
  <svg
@@ -243,7 +265,7 @@ const U = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
243
265
  sodipodi:nodetypes="cccccccc" />
244
266
  </g>
245
267
  </svg>
246
- `, G = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
268
+ `, N = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
247
269
  <svg
248
270
  width="24.000002"
249
271
  height="24"
@@ -311,7 +333,7 @@ const U = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
311
333
  x="1.1215118e-09"
312
334
  y="4.9718442"
313
335
  ry="0.64957041" /></svg>
314
- `, N = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAATrAAAE6wHYKlsNAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAcRJREFUOI2lkztvE0EQgL8Z7/rB2T5fCixhQQc00FAjJCRkiTYV/JH0adIgfgJVGn4CKRBUSIjCHYiOBimK7KA4ORw/dofC3Ck2dhpGGu1r5pvZmV0xM/5HXDEZDAbf2u12BkiM0UIImBlmRoyxHBeLBaPRaNzv9++tAJIkyVS1673HzBCRUtfFzEo/d/VAVRERzvf2uDw6AqB6eMhlt1va9Hq9FWgJiDEiIqgqcTwmnp4CUPeearu9EmRjDYp7qiqVNEV3dgCYx8hlniMimBlZlm0GFN0QERoHB7j9/bIGVUDiHCrVfzLQqwDvPSLCZDIhz3MuLi6YTye4eY58fkOnUbkeUERMkoRWq0WaptRqDaYfXvPr3StmP75cX4PZbIb3HoDx6TmttImveZoPn9N+0KfWvbsdYGY45xARvn76zvu3H8m6GS/2dpnefLRsb4Bb2wAhBJxbLoc/hwCcDc9QqVCvuzLy+uPa2IUnu4+p36hz5/5tGkmdxWKBc45Op0MIYXsNClAzTXj28imquqKFzUbA8fHxbzMbi0glhKBmpsuEREQkqmpU1Sgi8eTkJC/8ZNN3FhEHNIHG360pkJvZdN32D0SOwDehr1HXAAAAAElFTkSuQmCC", V = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
336
+ `, G = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAATrAAAE6wHYKlsNAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAcRJREFUOI2lkztvE0EQgL8Z7/rB2T5fCixhQQc00FAjJCRkiTYV/JH0adIgfgJVGn4CKRBUSIjCHYiOBimK7KA4ORw/dofC3Ck2dhpGGu1r5pvZmV0xM/5HXDEZDAbf2u12BkiM0UIImBlmRoyxHBeLBaPRaNzv9++tAJIkyVS1673HzBCRUtfFzEo/d/VAVRERzvf2uDw6AqB6eMhlt1va9Hq9FWgJiDEiIqgqcTwmnp4CUPeearu9EmRjDYp7qiqVNEV3dgCYx8hlniMimBlZlm0GFN0QERoHB7j9/bIGVUDiHCrVfzLQqwDvPSLCZDIhz3MuLi6YTye4eY58fkOnUbkeUERMkoRWq0WaptRqDaYfXvPr3StmP75cX4PZbIb3HoDx6TmttImveZoPn9N+0KfWvbsdYGY45xARvn76zvu3H8m6GS/2dpnefLRsb4Bb2wAhBJxbLoc/hwCcDc9QqVCvuzLy+uPa2IUnu4+p36hz5/5tGkmdxWKBc45Op0MIYXsNClAzTXj28imquqKFzUbA8fHxbzMbi0glhKBmpsuEREQkqmpU1Sgi8eTkJC/8ZNN3FhEHNIHG360pkJvZdN32D0SOwDehr1HXAAAAAElFTkSuQmCC", V = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
315
337
  <!-- Created with Inkscape (http://www.inkscape.org/) -->
316
338
 
317
339
  <svg
@@ -725,12 +747,12 @@ function s(i) {
725
747
  return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(i)}`;
726
748
  }
727
749
  const u = {
728
- "arrow.svg": s(U),
729
- "audio.png": R,
750
+ "arrow.svg": s(R),
751
+ "audio.png": U,
730
752
  "collapse_article.svg": s(P),
731
753
  "collapse_article_hovered.svg": s(F),
732
- "collapse_opt.svg": s(G),
733
- "document.png": N,
754
+ "collapse_opt.svg": s(N),
755
+ "document.png": G,
734
756
  "downarrow.svg": s(V),
735
757
  "expand_article.svg": s(H),
736
758
  "expand_article_hovered.svg": s(O),
@@ -8063,7 +8085,7 @@ function he(i, e) {
8063
8085
  }
8064
8086
  function D(i, e) {
8065
8087
  const o = e.replace(/[?#].*$/, "").replace(/\/+$/, "");
8066
- return (i === _ || i.startsWith(`${_}/`)) && /(?:^|\/)api\/v1$/i.test(o) ? `${o}${i.slice(_.length)}` : /^[a-z][a-z\d+.-]*:/i.test(e) ? new URL(i, e).toString() : i;
8088
+ return (i === _ || i.startsWith(`${_}/`)) && o !== "" ? `${o}${i.slice(_.length)}` : /^[a-z][a-z\d+.-]*:/i.test(e) ? new URL(i, e).toString() : i;
8067
8089
  }
8068
8090
  function C(i) {
8069
8091
  const e = i.resourceBaseUrl;
@@ -8117,7 +8139,7 @@ function fe(i) {
8117
8139
  ...a?.length ? { dictionaryIds: a } : {}
8118
8140
  } : { kind: "unsafe" };
8119
8141
  }
8120
- function L(i, e) {
8142
+ function q(i, e) {
8121
8143
  const o = i.trim();
8122
8144
  if (!o || o === "#")
8123
8145
  return { kind: "anchor", anchor: "" };
@@ -8171,7 +8193,7 @@ function be(i, e, o) {
8171
8193
  const a = i.getAttribute("data-gd-lookup")?.trim();
8172
8194
  if (a && a !== "true" && a !== "1")
8173
8195
  return { kind: "lookup", word: a };
8174
- const r = L(e, o);
8196
+ const r = q(e, o);
8175
8197
  if (r.kind === "lookup")
8176
8198
  return r;
8177
8199
  const l = i.getAttribute("data-gd-word")?.trim();
@@ -8253,7 +8275,7 @@ function ye(i, e, o) {
8253
8275
  const d = r.getAttribute("href");
8254
8276
  d !== null && ke(
8255
8277
  r,
8256
- be(r, d, t) ?? L(d, t),
8278
+ be(r, d, t) ?? q(d, t),
8257
8279
  i.dictionaryId
8258
8280
  );
8259
8281
  } else if (r.hasAttribute("href")) {
@@ -8305,7 +8327,7 @@ const ve = {
8305
8327
  radius: "8px",
8306
8328
  spacing: "8px"
8307
8329
  };
8308
- function q(i = "light") {
8330
+ function L(i = "light") {
8309
8331
  return i !== "auto" ? i : globalThis.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
8310
8332
  }
8311
8333
  function c(i, e) {
@@ -8315,7 +8337,7 @@ function k(i) {
8315
8337
  return i.replace(/<\/style/gi, "<\\/style");
8316
8338
  }
8317
8339
  function ze(i = {}) {
8318
- const e = q(i.mode), o = i.tokens ?? {}, t = e === "dark" ? { ..._e, ...o } : o, n = [
8340
+ const e = L(i.mode), o = i.tokens ?? {}, t = e === "dark" ? { ..._e, ...o } : o, n = [
8319
8341
  c("--gd-font-family", t.fontFamily),
8320
8342
  c("--gd-text-color", t.textColor),
8321
8343
  c("--gd-muted-text-color", t.mutedTextColor),
@@ -8594,7 +8616,7 @@ function De(i, e) {
8594
8616
  "base-uri 'none'"
8595
8617
  ].join("; ");
8596
8618
  }
8597
- function Le() {
8619
+ function qe() {
8598
8620
  return `(function(){
8599
8621
  globalThis.__DICT__={name:"GoldenDict",version:"web"};
8600
8622
  const pending=[];
@@ -8623,8 +8645,8 @@ function Le() {
8623
8645
  },true);
8624
8646
  })();`;
8625
8647
  }
8626
- function qe(i, e) {
8627
- const o = e.theme ?? {}, t = q(o.mode), n = e.layoutMode ?? "responsive", a = e.instanceId.replace(/[^a-zA-Z0-9_-]/g, ""), r = i.articles.map(
8648
+ function Le(i, e) {
8649
+ const o = e.theme ?? {}, t = L(o.mode), n = e.layoutMode ?? "responsive", a = e.instanceId.replace(/[^a-zA-Z0-9_-]/g, ""), r = i.articles.map(
8628
8650
  (d) => Te(d, e.apiBaseUrl, e.scriptPolicy)
8629
8651
  ).join(""), l = r ? `${r}<div class="empty-space" aria-hidden="true"></div>` : `<div class="gdnotfound"><p>No translation for <b>${g(i.word)}</b> was found.</p></div>`, m = o.brandName ? `${i.word} — ${o.brandName}` : i.word;
8630
8652
  return `<!doctype html>
@@ -8633,7 +8655,7 @@ function qe(i, e) {
8633
8655
  <meta name="viewport" content="width=device-width,initial-scale=1">
8634
8656
  <meta http-equiv="Content-Security-Policy" content="${g(De(e.scriptPolicy, a))}">
8635
8657
  <title>${g(m)}</title>
8636
- <script nonce="${a}" data-gd-runtime="compatibility">${Le()}<\/script>
8658
+ <script nonce="${a}" data-gd-runtime="compatibility">${qe()}<\/script>
8637
8659
  <style>${k(de)}</style>
8638
8660
  <style>${k(se(o.preset))}</style>
8639
8661
  ${n === "responsive" ? `<style data-gd-style="responsive">${k(ce)}</style>` : ""}
@@ -8832,7 +8854,7 @@ class z extends HTMLElement {
8832
8854
  this.activeBridgeInstanceId = t;
8833
8855
  const n = this.replaceFrame(!1);
8834
8856
  n.title = e.word ? `Dictionary results for ${e.word}` : "Dictionary article";
8835
- const a = qe(e, {
8857
+ const a = Le(e, {
8836
8858
  apiBaseUrl: this.clientValue.baseUrl,
8837
8859
  instanceId: t,
8838
8860
  scriptPolicy: this.scriptPolicy,
@@ -8995,13 +9017,13 @@ class z extends HTMLElement {
8995
9017
  return this.dispatchEvent(n), n;
8996
9018
  }
8997
9019
  }
8998
- function Ue(i = "goldendict-view") {
9020
+ function Re(i = "goldendict-view") {
8999
9021
  if (!globalThis.customElements)
9000
9022
  return z;
9001
9023
  const e = globalThis.customElements.get(i);
9002
9024
  return e || (globalThis.customElements.define(i, z), z);
9003
9025
  }
9004
- Ue();
9026
+ Re();
9005
9027
  export {
9006
9028
  _e as DARK_THEME_TOKENS,
9007
9029
  M as DictionaryApiError,
@@ -9010,11 +9032,11 @@ export {
9010
9032
  me as GOLDENDICT_SCHEME_SUPPORT,
9011
9033
  z as GoldenDictView,
9012
9034
  ve as LIGHT_THEME_TOKENS,
9013
- L as classifyArticleLink,
9014
- Ue as defineGoldendictView,
9035
+ q as classifyArticleLink,
9036
+ Re as defineGoldendictView,
9015
9037
  k as escapeStyleText,
9016
9038
  p as resolveResourceUrl,
9017
- q as resolveThemeMode,
9039
+ L as resolveThemeMode,
9018
9040
  ze as themeToCss
9019
9041
  };
9020
9042
  //# sourceMappingURL=index.js.map