@stapel/vocabularies-react 0.1.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.
- package/CHANGELOG.md +52 -0
- package/LICENSE +21 -0
- package/MODULE.md +92 -0
- package/README.md +173 -0
- package/dist/api/extensions.d.ts +8 -0
- package/dist/api/extensions.d.ts.map +1 -0
- package/dist/api/extensions.js +8 -0
- package/dist/api/extensions.js.map +1 -0
- package/dist/api/generated/schema.d.ts +234 -0
- package/dist/api/generated/schema.d.ts.map +1 -0
- package/dist/api/generated/schema.js +2 -0
- package/dist/api/generated/schema.js.map +1 -0
- package/dist/api/types.d.ts +23 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +2 -0
- package/dist/api/types.js.map +1 -0
- package/dist/api/vocabulariesApi.d.ts +14 -0
- package/dist/api/vocabulariesApi.d.ts.map +1 -0
- package/dist/api/vocabulariesApi.js +4 -0
- package/dist/api/vocabulariesApi.js.map +1 -0
- package/dist/client.d.ts +49 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +118 -0
- package/dist/client.js.map +1 -0
- package/dist/default/VocabularyTermSelect.d.ts +24 -0
- package/dist/default/VocabularyTermSelect.d.ts.map +1 -0
- package/dist/default/VocabularyTermSelect.js +75 -0
- package/dist/default/VocabularyTermSelect.js.map +1 -0
- package/dist/default/index.d.ts +16 -0
- package/dist/default/index.d.ts.map +1 -0
- package/dist/default/index.js +14 -0
- package/dist/default/index.js.map +1 -0
- package/dist/default/types.d.ts +12 -0
- package/dist/default/types.d.ts.map +1 -0
- package/dist/default/types.js +2 -0
- package/dist/default/types.js.map +1 -0
- package/dist/flows/errors.d.ts +12 -0
- package/dist/flows/errors.d.ts.map +1 -0
- package/dist/flows/errors.js +13 -0
- package/dist/flows/errors.js.map +1 -0
- package/dist/flows/registry.d.ts +22 -0
- package/dist/flows/registry.d.ts.map +1 -0
- package/dist/flows/registry.js +20 -0
- package/dist/flows/registry.js.map +1 -0
- package/dist/headless/VocabulariesProvider.d.ts +19 -0
- package/dist/headless/VocabulariesProvider.d.ts.map +1 -0
- package/dist/headless/VocabulariesProvider.js +15 -0
- package/dist/headless/VocabulariesProvider.js.map +1 -0
- package/dist/i18n/errorsMap.d.ts +10 -0
- package/dist/i18n/errorsMap.d.ts.map +1 -0
- package/dist/i18n/errorsMap.js +20 -0
- package/dist/i18n/errorsMap.js.map +1 -0
- package/dist/i18n/es.d.ts +21 -0
- package/dist/i18n/es.d.ts.map +1 -0
- package/dist/i18n/es.js +38 -0
- package/dist/i18n/es.js.map +1 -0
- package/dist/i18n/generated/errors.es.gen.d.ts +16 -0
- package/dist/i18n/generated/errors.es.gen.d.ts.map +1 -0
- package/dist/i18n/generated/errors.es.gen.js +58 -0
- package/dist/i18n/generated/errors.es.gen.js.map +1 -0
- package/dist/i18n/generated/errors.gen.d.ts +305 -0
- package/dist/i18n/generated/errors.gen.d.ts.map +1 -0
- package/dist/i18n/generated/errors.gen.js +156 -0
- package/dist/i18n/generated/errors.gen.js.map +1 -0
- package/dist/i18n/generated/errors.ru.gen.d.ts +16 -0
- package/dist/i18n/generated/errors.ru.gen.d.ts.map +1 -0
- package/dist/i18n/generated/errors.ru.gen.js +58 -0
- package/dist/i18n/generated/errors.ru.gen.js.map +1 -0
- package/dist/i18n/keys.d.ts +33 -0
- package/dist/i18n/keys.d.ts.map +1 -0
- package/dist/i18n/keys.js +44 -0
- package/dist/i18n/keys.js.map +1 -0
- package/dist/i18n/ru.d.ts +26 -0
- package/dist/i18n/ru.d.ts.map +1 -0
- package/dist/i18n/ru.js +43 -0
- package/dist/i18n/ru.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/model/context.d.ts +11 -0
- package/dist/model/context.d.ts.map +1 -0
- package/dist/model/context.js +16 -0
- package/dist/model/context.js.map +1 -0
- package/dist/model/queryKeys.d.ts +5 -0
- package/dist/model/queryKeys.d.ts.map +1 -0
- package/dist/model/queryKeys.js +28 -0
- package/dist/model/queryKeys.js.map +1 -0
- package/dist/model/runtime.d.ts +17 -0
- package/dist/model/runtime.d.ts.map +1 -0
- package/dist/model/runtime.js +6 -0
- package/dist/model/runtime.js.map +1 -0
- package/dist/model/useTermLabels.d.ts +26 -0
- package/dist/model/useTermLabels.d.ts.map +1 -0
- package/dist/model/useTermLabels.js +58 -0
- package/dist/model/useTermLabels.js.map +1 -0
- package/dist/model/useTermSearch.d.ts +24 -0
- package/dist/model/useTermSearch.d.ts.map +1 -0
- package/dist/model/useTermSearch.js +85 -0
- package/dist/model/useTermSearch.js.map +1 -0
- package/llms.txt +79 -0
- package/manifest.json +466 -0
- package/package.json +108 -0
- package/src/analytics/generated/events.json +7 -0
- package/src/api/extensions.ts +7 -0
- package/src/api/generated/schema.ts +236 -0
- package/src/api/types.ts +27 -0
- package/src/api/vocabulariesApi.ts +17 -0
- package/src/client.ts +176 -0
- package/src/default/VocabularyTermSelect.tsx +147 -0
- package/src/default/index.ts +15 -0
- package/src/default/types.ts +11 -0
- package/src/flows/errors.ts +16 -0
- package/src/flows/registry.ts +32 -0
- package/src/headless/VocabulariesProvider.tsx +20 -0
- package/src/i18n/errorsMap.ts +31 -0
- package/src/i18n/es.ts +49 -0
- package/src/i18n/generated/errors.es.gen.ts +64 -0
- package/src/i18n/generated/errors.gen.ts +187 -0
- package/src/i18n/generated/errors.json +351 -0
- package/src/i18n/generated/errors.ru.gen.ts +64 -0
- package/src/i18n/keys.ts +53 -0
- package/src/i18n/ru.ts +54 -0
- package/src/index.ts +92 -0
- package/src/model/context.tsx +28 -0
- package/src/model/queryKeys.ts +35 -0
- package/src/model/runtime.ts +25 -0
- package/src/model/useTermLabels.ts +72 -0
- package/src/model/useTermSearch.ts +118 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { StapelClient } from "@stapel/core";
|
|
2
|
+
/**
|
|
3
|
+
* The pair's typed operation surface. Today a thin holder over the injected
|
|
4
|
+
* {@link StapelClient}; the named, typed operations (`vocabularies.<op>()`) will
|
|
5
|
+
* be GENERATED from schema.json operationIds by gen-api v2 (task
|
|
6
|
+
* `core-typed-ops`). Until then add hand-authored operations here and put
|
|
7
|
+
* anything that can never be derived from the schema in `api/extensions.ts`,
|
|
8
|
+
* each flagged with WHY the codegen does not cover it.
|
|
9
|
+
*/
|
|
10
|
+
export interface VocabulariesApi {
|
|
11
|
+
readonly client: StapelClient;
|
|
12
|
+
}
|
|
13
|
+
export declare function createVocabulariesApi(client: StapelClient): VocabulariesApi;
|
|
14
|
+
//# sourceMappingURL=vocabulariesApi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vocabulariesApi.d.ts","sourceRoot":"","sources":["../../src/api/vocabulariesApi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;CAC/B;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,eAAe,CAE3E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vocabulariesApi.js","sourceRoot":"","sources":["../../src/api/vocabulariesApi.ts"],"names":[],"mappings":"AAcA,MAAM,UAAU,qBAAqB,CAAC,MAAoB;IACxD,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** One term of a vocabulary level, as `GET …/terms/` returns it.
|
|
2
|
+
*
|
|
3
|
+
* A structural twin of `@stapel/attributes-react`'s `VocabularyTerm` — the same
|
|
4
|
+
* three fields, `has_children` spelled the wire's way. The declaration is not
|
|
5
|
+
* shared because the two packages must not import each other; the assignment
|
|
6
|
+
* is proven by `test/clientShape.test.ts`. */
|
|
7
|
+
export interface VocabularyTerm {
|
|
8
|
+
readonly code: string;
|
|
9
|
+
readonly label: string;
|
|
10
|
+
readonly has_children?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The seam `@stapel/attributes-react` declares and this package implements.
|
|
14
|
+
*
|
|
15
|
+
* ATTRIBUTES-REACT OWNS THIS SHAPE. The copy here exists so a host can name
|
|
16
|
+
* the type without depending on the attributes pair, and
|
|
17
|
+
* `test/clientShape.test.ts` holds a third, hand-transcribed copy of the
|
|
18
|
+
* upstream declaration that the value returned below is assigned to — so a
|
|
19
|
+
* drift in either package is a red build here rather than a runtime hole in a
|
|
20
|
+
* storefront that wired the two together.
|
|
21
|
+
*/
|
|
22
|
+
export interface VocabularyClient {
|
|
23
|
+
/** Terms of one level, narrowed by `query` and — when the caller has a
|
|
24
|
+
* parent term — by that term's code. An empty `query` means "the first page
|
|
25
|
+
* of this level", which is what a dropdown opens on. `signal` is honoured. */
|
|
26
|
+
search(vocabulary: string, level: string, query: string, parent?: string, signal?: AbortSignal): Promise<readonly VocabularyTerm[]>;
|
|
27
|
+
/** `{code: label}` for codes already stored somewhere. Unknown codes are
|
|
28
|
+
* omitted by the server, so a caller falls back to the code itself. */
|
|
29
|
+
resolve(vocabulary: string, level: string, codes: readonly string[]): Promise<Readonly<Record<string, string>>>;
|
|
30
|
+
}
|
|
31
|
+
export interface CreateVocabularyClientOptions {
|
|
32
|
+
/** Where stapel-vocabularies is mounted, e.g. `/vocabularies/api/v1/` or an
|
|
33
|
+
* absolute origin. A missing trailing slash is added. */
|
|
34
|
+
readonly baseUrl: string;
|
|
35
|
+
/** Transport override — a host's authenticated/instrumented `fetch`.
|
|
36
|
+
* Defaults to the global one. */
|
|
37
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
38
|
+
/** Page size for {@link VocabularyClient.search}; the server caps it at 200
|
|
39
|
+
* and defaults to 50. */
|
|
40
|
+
readonly limit?: number;
|
|
41
|
+
}
|
|
42
|
+
/** The page a typeahead opens on. Matches the server's own default, so the
|
|
43
|
+
* parameter is sent for explicitness rather than to change behaviour. */
|
|
44
|
+
export declare const DEFAULT_TERM_LIMIT = 50;
|
|
45
|
+
/** The server refuses more than this many codes per resolve, and silently
|
|
46
|
+
* ignores the tail — so the client splits instead of losing labels. */
|
|
47
|
+
export declare const RESOLVE_BATCH = 200;
|
|
48
|
+
export declare function createVocabularyClient(options: CreateVocabularyClientOptions): VocabularyClient;
|
|
49
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AA4BA;;;;;8CAK8C;AAC9C,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;CACjC;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;kFAE8E;IAC9E,MAAM,CACJ,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAAC;IACtC;2EACuE;IACvE,OAAO,CACL,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,6BAA6B;IAC5C;6DACyD;IACzD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;qCACiC;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACzC;6BACyB;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;yEACyE;AACzE,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC;uEACuE;AACvE,eAAO,MAAM,aAAa,MAAM,CAAC;AAsBjC,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,6BAA6B,GACrC,gBAAgB,CA+DlB"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `createVocabularyClient` — the two reads a ref feature needs, over the
|
|
3
|
+
* stapel-vocabularies wire.
|
|
4
|
+
*
|
|
5
|
+
* ── Why this is a bare `fetch` client and not the pair's StapelClient ───────
|
|
6
|
+
*
|
|
7
|
+
* A `ref_select` reaches its terms through a seam
|
|
8
|
+
* (`VocabularyClient`) that `@stapel/attributes-react` DECLARES and this
|
|
9
|
+
* package SATISFIES — structurally, without either importing the other, so two
|
|
10
|
+
* L2 pairs stay independently releasable. The seam is two async functions and
|
|
11
|
+
* nothing else: no query client, no auth runtime, no provider. Anything this
|
|
12
|
+
* function returned that needed React context could not be handed to
|
|
13
|
+
* `<VocabularyClientProvider value={…}>` at a container's composition root,
|
|
14
|
+
* which is the one call site the seam exists for.
|
|
15
|
+
*
|
|
16
|
+
* Both endpoints are public reads (`ReadOnlyOrStaff`, ETag'd on the
|
|
17
|
+
* vocabulary's revision, no session), so there is no token to carry and
|
|
18
|
+
* nothing for the auth interceptors to do. A host that DOES need headers
|
|
19
|
+
* passes its own `fetch`.
|
|
20
|
+
*
|
|
21
|
+
* The caching the seam deliberately leaves out lives in this package's hooks
|
|
22
|
+
* (`useTermLabels` is a TanStack query; `useTermSearch` supersedes in flight),
|
|
23
|
+
* not in the client — a raw client is what makes the seam testable and what
|
|
24
|
+
* lets a host wrap it.
|
|
25
|
+
*/
|
|
26
|
+
import { toStapelApiError } from "@stapel/core";
|
|
27
|
+
/** The page a typeahead opens on. Matches the server's own default, so the
|
|
28
|
+
* parameter is sent for explicitness rather than to change behaviour. */
|
|
29
|
+
export const DEFAULT_TERM_LIMIT = 50;
|
|
30
|
+
/** The server refuses more than this many codes per resolve, and silently
|
|
31
|
+
* ignores the tail — so the client splits instead of losing labels. */
|
|
32
|
+
export const RESOLVE_BATCH = 200;
|
|
33
|
+
function withSlash(baseUrl) {
|
|
34
|
+
return baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* `{code: label}` out of a body typed as `Record<string, unknown>` (the
|
|
38
|
+
* contract declares `additionalProperties: {}`). Non-string values are
|
|
39
|
+
* dropped rather than stringified: a label that is not a string is a server
|
|
40
|
+
* the caller should fall back from, and `"[object Object]"` in a dropdown is
|
|
41
|
+
* worse than the code.
|
|
42
|
+
*/
|
|
43
|
+
function labelsOf(body) {
|
|
44
|
+
const out = {};
|
|
45
|
+
if (typeof body !== "object" || body === null)
|
|
46
|
+
return out;
|
|
47
|
+
for (const [code, label] of Object.entries(body)) {
|
|
48
|
+
if (typeof label === "string")
|
|
49
|
+
out[code] = label;
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
export function createVocabularyClient(options) {
|
|
54
|
+
const base = withSlash(options.baseUrl);
|
|
55
|
+
const doFetch = options.fetch ?? globalThis.fetch;
|
|
56
|
+
const limit = options.limit ?? DEFAULT_TERM_LIMIT;
|
|
57
|
+
async function read(url, signal) {
|
|
58
|
+
let response;
|
|
59
|
+
try {
|
|
60
|
+
response = await doFetch(url, {
|
|
61
|
+
method: "GET",
|
|
62
|
+
headers: { accept: "application/json" },
|
|
63
|
+
...(signal !== undefined ? { signal } : {}),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
catch (cause) {
|
|
67
|
+
// An abort is the CALLER's decision, not a failure: rethrow it as-is so
|
|
68
|
+
// `signal.aborted` still discriminates it. Folding it into the error
|
|
69
|
+
// dialect would make a superseded keystroke look like a dead backend.
|
|
70
|
+
if (signal?.aborted === true)
|
|
71
|
+
throw cause;
|
|
72
|
+
throw toStapelApiError(cause);
|
|
73
|
+
}
|
|
74
|
+
if (!response.ok) {
|
|
75
|
+
// One dialect at the single rethrow point (core `errors.ts`): the body is
|
|
76
|
+
// the backend's envelope, the status is the response's.
|
|
77
|
+
const body = await response.json().catch(() => undefined);
|
|
78
|
+
throw toStapelApiError(body, response.status);
|
|
79
|
+
}
|
|
80
|
+
return await response.json();
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
async search(vocabulary, level, query, parent, signal) {
|
|
84
|
+
const params = new URLSearchParams();
|
|
85
|
+
params.set("level", level);
|
|
86
|
+
// OMITTED, not empty: `parent=` would ask the server for the children of
|
|
87
|
+
// a term whose code is the empty string, which is a level with nothing in
|
|
88
|
+
// it — the opposite of "the whole level", which is what no parent means.
|
|
89
|
+
if (parent !== undefined && parent.length > 0)
|
|
90
|
+
params.set("parent", parent);
|
|
91
|
+
params.set("q", query);
|
|
92
|
+
params.set("limit", String(limit));
|
|
93
|
+
const url = `${base}vocabularies/${encodeURIComponent(vocabulary)}/terms/?${params.toString()}`;
|
|
94
|
+
const page = (await read(url, signal));
|
|
95
|
+
const results = page?.results ?? [];
|
|
96
|
+
return results.map((term) => ({
|
|
97
|
+
code: term.code,
|
|
98
|
+
label: term.label,
|
|
99
|
+
has_children: term.has_children,
|
|
100
|
+
}));
|
|
101
|
+
},
|
|
102
|
+
async resolve(vocabulary, level, codes) {
|
|
103
|
+
const wanted = codes.filter((code) => code.length > 0);
|
|
104
|
+
if (wanted.length === 0)
|
|
105
|
+
return {};
|
|
106
|
+
const out = {};
|
|
107
|
+
for (let at = 0; at < wanted.length; at += RESOLVE_BATCH) {
|
|
108
|
+
const params = new URLSearchParams();
|
|
109
|
+
params.set("level", level);
|
|
110
|
+
params.set("codes", wanted.slice(at, at + RESOLVE_BATCH).join(","));
|
|
111
|
+
const url = `${base}vocabularies/${encodeURIComponent(vocabulary)}/terms/resolve/?${params.toString()}`;
|
|
112
|
+
Object.assign(out, labelsOf(await read(url)));
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
import type { VocabularyClient } from "../client.js";
|
|
3
|
+
import type { ThemeModeProp } from "./types.js";
|
|
4
|
+
export interface VocabularyTermSelectProps extends ThemeModeProp {
|
|
5
|
+
/** The seam. `null` draws the unavailable notice — see the module header. */
|
|
6
|
+
readonly client: VocabularyClient | null;
|
|
7
|
+
readonly vocabulary: string;
|
|
8
|
+
readonly level: string;
|
|
9
|
+
/** Code of a term at the level above; narrows the list to its children. */
|
|
10
|
+
readonly parent?: string | undefined;
|
|
11
|
+
/** The codes currently chosen. Always a list, even single-select — a term
|
|
12
|
+
* value is a list on the wire. */
|
|
13
|
+
readonly value?: readonly string[] | undefined;
|
|
14
|
+
readonly onChange?: ((codes: readonly string[]) => void) | undefined;
|
|
15
|
+
/** Several terms at once (a facet filter); default is one. */
|
|
16
|
+
readonly multiple?: boolean | undefined;
|
|
17
|
+
/** Upper bound for a multiple select. */
|
|
18
|
+
readonly maxCount?: number | undefined;
|
|
19
|
+
readonly disabled?: boolean | undefined;
|
|
20
|
+
readonly id?: string | undefined;
|
|
21
|
+
readonly status?: "error" | "warning" | undefined;
|
|
22
|
+
}
|
|
23
|
+
export declare function VocabularyTermSelect(props: VocabularyTermSelectProps): ReactElement;
|
|
24
|
+
//# sourceMappingURL=VocabularyTermSelect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VocabularyTermSelect.d.ts","sourceRoot":"","sources":["../../src/default/VocabularyTermSelect.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAI1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAIrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,WAAW,yBAA0B,SAAQ,aAAa;IAC9D,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC;sCACkC;IAClC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACrE,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;CACnD;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,yBAAyB,GAC/B,YAAY,CAuFd"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* `<VocabularyTermSelect/>` — one vocabulary level as a typeahead.
|
|
4
|
+
*
|
|
5
|
+
* The SAME control `@stapel/attributes-react`'s `ref_select` editor draws,
|
|
6
|
+
* shipped on its own so the places a composer is not — a facet filter, an
|
|
7
|
+
* admin form, a bulk-edit row — do not each grow their own. The two are
|
|
8
|
+
* deliberately separate components rather than one imported across the seam:
|
|
9
|
+
* the editor's props are the attributes value-editor contract (a `FeatureDef`,
|
|
10
|
+
* `siblings`, a rule-narrowed config) and this one's are a vocabulary pointer,
|
|
11
|
+
* and collapsing them would make the two L2 pairs depend on each other for a
|
|
12
|
+
* hundred lines of antd.
|
|
13
|
+
*
|
|
14
|
+
* What it owes a person, and where each part lives:
|
|
15
|
+
*
|
|
16
|
+
* - the options ARE the answer to the current query, so `filterOption={false}`
|
|
17
|
+
* — letting antd filter them again would hide rows the server deliberately
|
|
18
|
+
* ranked (a prefix match first, a label matched in another language);
|
|
19
|
+
* - typing is debounced and superseding (`useTermSearch`);
|
|
20
|
+
* - a code the control already HOLDS is resolved to its label
|
|
21
|
+
* (`useTermLabels`) and kept in the option list even when the current page
|
|
22
|
+
* does not contain it — otherwise reopening a saved filter would silently
|
|
23
|
+
* empty the control;
|
|
24
|
+
* - no client is a LOUD state, not an empty dropdown: a control that cannot
|
|
25
|
+
* reach its terms and looks like one that found none is how a person ends
|
|
26
|
+
* up unable to answer a question nobody told them was broken.
|
|
27
|
+
*/
|
|
28
|
+
import { useMemo } from "react";
|
|
29
|
+
import { Alert, Select } from "antd";
|
|
30
|
+
import { useT } from "@stapel/core";
|
|
31
|
+
import { SkinTheme } from "@stapel/tokens-antd/skin";
|
|
32
|
+
import { useTermSearch } from "../model/useTermSearch.js";
|
|
33
|
+
import { useTermLabels, termLabel } from "../model/useTermLabels.js";
|
|
34
|
+
import { VOCABULARIES_I18N_KEYS } from "../i18n/keys.js";
|
|
35
|
+
export function VocabularyTermSelect(props) {
|
|
36
|
+
const t = useT();
|
|
37
|
+
const { client, vocabulary, level, parent } = props;
|
|
38
|
+
const codes = useMemo(() => (props.value ?? []).filter((code) => code.length > 0), [props.value]);
|
|
39
|
+
const { terms, loading, search, open } = useTermSearch(client, {
|
|
40
|
+
vocabulary,
|
|
41
|
+
level,
|
|
42
|
+
parent,
|
|
43
|
+
});
|
|
44
|
+
const labels = useTermLabels(client, { vocabulary, level, codes });
|
|
45
|
+
// A held code the current page does not contain still has to be visible and
|
|
46
|
+
// pickable, so it is prepended rather than looked up in `terms`.
|
|
47
|
+
const options = useMemo(() => [
|
|
48
|
+
...codes
|
|
49
|
+
.filter((code) => !terms.some((term) => term.code === code))
|
|
50
|
+
.map((code) => ({ value: code, label: termLabel(labels, code) })),
|
|
51
|
+
...terms.map((term) => ({ value: term.code, label: term.label })),
|
|
52
|
+
], [codes, terms, labels]);
|
|
53
|
+
if (client === null || vocabulary.length === 0 || level.length === 0) {
|
|
54
|
+
return (_jsx(SkinTheme, { surface: "bare", ...(props.mode !== undefined ? { mode: props.mode } : {}), children: _jsx(Alert, { type: "warning", showIcon: true, "data-testid": "vocabulary-term-select-unavailable", title: t(VOCABULARIES_I18N_KEYS.termSelectUnavailableTitle), description: t(VOCABULARIES_I18N_KEYS.termSelectUnavailable) }) }));
|
|
55
|
+
}
|
|
56
|
+
const multiple = props.multiple === true;
|
|
57
|
+
const onChange = props.onChange;
|
|
58
|
+
return (_jsx(SkinTheme, { surface: "bare", ...(props.mode !== undefined ? { mode: props.mode } : {}), children: _jsx(Select, { ...(props.id !== undefined ? { id: props.id } : {}), "data-testid": "vocabulary-term-select", style: { width: "100%" }, showSearch: true, filterOption: false, options: options, loading: loading, disabled: props.disabled === true, ...(props.status !== undefined ? { status: props.status } : {}), ...(multiple ? { mode: "multiple" } : {}), ...(multiple && props.maxCount !== undefined
|
|
59
|
+
? { maxCount: props.maxCount }
|
|
60
|
+
: {}), placeholder: t(VOCABULARIES_I18N_KEYS.termSelectPlaceholder),
|
|
61
|
+
// `null` while loading, so antd draws its own spinner instead of
|
|
62
|
+
// saying "no matches" about a question that has not been answered yet.
|
|
63
|
+
notFoundContent: loading ? null : t(VOCABULARIES_I18N_KEYS.termSelectNoMatches), value: multiple ? codes : (codes[0] ?? null), onDropdownVisibleChange: (visible) => {
|
|
64
|
+
if (visible)
|
|
65
|
+
open();
|
|
66
|
+
}, onSearch: search, onChange: (next) => {
|
|
67
|
+
const picked = next === null || next === undefined
|
|
68
|
+
? []
|
|
69
|
+
: Array.isArray(next)
|
|
70
|
+
? [...next]
|
|
71
|
+
: [next];
|
|
72
|
+
onChange?.(picked.filter((code) => code.length > 0));
|
|
73
|
+
} }) }));
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=VocabularyTermSelect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VocabularyTermSelect.js","sourceRoot":"","sources":["../../src/default/VocabularyTermSelect.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@stapel/vocabularies-react/default` — the pair's default AntD skin (§54: a pair ships a
|
|
3
|
+
* FEATURE, not only a bag). A separate entry point, so a host that brings its
|
|
4
|
+
* own visuals never pulls `antd` or the token bridge into its bundle;
|
|
5
|
+
* importing this subpath is the opt-in.
|
|
6
|
+
*
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { VocabularyTermSelect } from "@stapel/vocabularies-react/default";
|
|
9
|
+
* // under core's <I18nProvider>; the client is a prop, not a context read:
|
|
10
|
+
* <VocabularyTermSelect client={client} vocabulary="avito-phones" level="Vendor" … />
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export { VocabularyTermSelect } from "./VocabularyTermSelect.js";
|
|
14
|
+
export type { VocabularyTermSelectProps } from "./VocabularyTermSelect.js";
|
|
15
|
+
export type { ThemeModeProp } from "./types.js";
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/default/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,YAAY,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAC3E,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@stapel/vocabularies-react/default` — the pair's default AntD skin (§54: a pair ships a
|
|
3
|
+
* FEATURE, not only a bag). A separate entry point, so a host that brings its
|
|
4
|
+
* own visuals never pulls `antd` or the token bridge into its bundle;
|
|
5
|
+
* importing this subpath is the opt-in.
|
|
6
|
+
*
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { VocabularyTermSelect } from "@stapel/vocabularies-react/default";
|
|
9
|
+
* // under core's <I18nProvider>; the client is a prop, not a context read:
|
|
10
|
+
* <VocabularyTermSelect client={client} vocabulary="avito-phones" level="Vendor" … />
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export { VocabularyTermSelect } from "./VocabularyTermSelect.js";
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/default/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one prop every skin component in this package shares.
|
|
3
|
+
*
|
|
4
|
+
* `mode` is OPTIONAL and has no default here on purpose: the shared
|
|
5
|
+
* `SkinTheme` (`@stapel/tokens-antd/skin`) follows the host's theme when
|
|
6
|
+
* nobody overrides it, and a `mode = "light"` default in a pair is how a dark
|
|
7
|
+
* host ends up with one white rectangle in the middle of its app.
|
|
8
|
+
*/
|
|
9
|
+
export interface ThemeModeProp {
|
|
10
|
+
readonly mode?: "light" | "dark";
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/default/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAClC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/default/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FlowError } from "@stapel/core";
|
|
2
|
+
export type { FlowError } from "@stapel/core";
|
|
3
|
+
export { isErrorCode } from "@stapel/core";
|
|
4
|
+
/**
|
|
5
|
+
* Fold any thrown value into a {@link FlowError} using this pair's own
|
|
6
|
+
* module-scoped fallback key (`vocabularies.error.unknown`, an en string in
|
|
7
|
+
* {@link vocabulariesI18nBundleEn}) so a non-`StapelApiError` fault still renders
|
|
8
|
+
* real copy rather than a raw key. The primitive lives in `@stapel/core`
|
|
9
|
+
* (frontend-core-architecture §4b); this wrapper only pins the fallback.
|
|
10
|
+
*/
|
|
11
|
+
export declare function toFlowError(error: unknown): FlowError;
|
|
12
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/flows/errors.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,CAErD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { toFlowError as coreToFlowError } from "@stapel/core";
|
|
2
|
+
export { isErrorCode } from "@stapel/core";
|
|
3
|
+
/**
|
|
4
|
+
* Fold any thrown value into a {@link FlowError} using this pair's own
|
|
5
|
+
* module-scoped fallback key (`vocabularies.error.unknown`, an en string in
|
|
6
|
+
* {@link vocabulariesI18nBundleEn}) so a non-`StapelApiError` fault still renders
|
|
7
|
+
* real copy rather than a raw key. The primitive lives in `@stapel/core`
|
|
8
|
+
* (frontend-core-architecture §4b); this wrapper only pins the fallback.
|
|
9
|
+
*/
|
|
10
|
+
export function toFlowError(error) {
|
|
11
|
+
return coreToFlowError(error, "vocabularies.error.unknown");
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/flows/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,eAAe,EAAE,MAAM,cAAc,CAAC;AAI9D,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,eAAe,CAAC,KAAK,EAAE,4BAA4B,CAAC,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-flow registry shim (slim wave §21/S3). stapel-vocabularies annotates no
|
|
3
|
+
* `@flow_step` yet — its backend `docs/flows.json` carries no `vocabularies.*`
|
|
4
|
+
* flows, so `gen:flows` skips emission for this pair (no `flows/generated/`
|
|
5
|
+
* scaffolding). This hand-written shim preserves the pair's public
|
|
6
|
+
* flow-registry surface at its zero-flow shape.
|
|
7
|
+
*
|
|
8
|
+
* When the backend annotates flows, `pnpm gen:flows` emits
|
|
9
|
+
* `./generated/flows.gen.ts` again — replace these exports with re-exports
|
|
10
|
+
* from it (the shapes match by construction) and delete this file.
|
|
11
|
+
*/
|
|
12
|
+
export declare const VOCABULARIES_FLOWS: {};
|
|
13
|
+
/** Canonical flow ids present in flows.json (none yet — see above). */
|
|
14
|
+
export type VocabulariesFlowId = keyof typeof VOCABULARIES_FLOWS;
|
|
15
|
+
export type VocabulariesFlowSpec = (typeof VOCABULARIES_FLOWS)[VocabulariesFlowId];
|
|
16
|
+
export interface FlowEndpoint {
|
|
17
|
+
readonly method: string;
|
|
18
|
+
readonly path: string;
|
|
19
|
+
}
|
|
20
|
+
/** All HTTP endpoints a flow touches, in step order (for the contract test / MSW). */
|
|
21
|
+
export declare function flowEndpoints(id: VocabulariesFlowId): readonly FlowEndpoint[];
|
|
22
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/flows/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,IAAc,CAAC;AAE9C,uEAAuE;AACvE,MAAM,MAAM,kBAAkB,GAAG,MAAM,OAAO,kBAAkB,CAAC;AAEjE,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,kBAAkB,CAAC,CAAC;AAEnF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,EAAE,EAAE,kBAAkB,GAAG,SAAS,YAAY,EAAE,CAO7E"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-flow registry shim (slim wave §21/S3). stapel-vocabularies annotates no
|
|
3
|
+
* `@flow_step` yet — its backend `docs/flows.json` carries no `vocabularies.*`
|
|
4
|
+
* flows, so `gen:flows` skips emission for this pair (no `flows/generated/`
|
|
5
|
+
* scaffolding). This hand-written shim preserves the pair's public
|
|
6
|
+
* flow-registry surface at its zero-flow shape.
|
|
7
|
+
*
|
|
8
|
+
* When the backend annotates flows, `pnpm gen:flows` emits
|
|
9
|
+
* `./generated/flows.gen.ts` again — replace these exports with re-exports
|
|
10
|
+
* from it (the shapes match by construction) and delete this file.
|
|
11
|
+
*/
|
|
12
|
+
export const VOCABULARIES_FLOWS = {};
|
|
13
|
+
/** All HTTP endpoints a flow touches, in step order (for the contract test / MSW). */
|
|
14
|
+
export function flowEndpoints(id) {
|
|
15
|
+
// Same widened body as the generated registry's — valid for the zero-flow
|
|
16
|
+
// shape AND correct once flows exist.
|
|
17
|
+
const spec = VOCABULARIES_FLOWS[id];
|
|
18
|
+
return spec ? spec.steps.flatMap((s) => s.endpoints) : [];
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/flows/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAW,CAAC;AAY9C,sFAAsF;AACtF,MAAM,UAAU,aAAa,CAAC,EAAsB;IAClD,0EAA0E;IAC1E,sCAAsC;IACtC,MAAM,IAAI,GAAG,kBAAkB,CAAC,EAAE,CAErB,CAAC;IACd,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode } from "react";
|
|
2
|
+
import type { VocabulariesRuntime } from "../model/runtime.js";
|
|
3
|
+
/**
|
|
4
|
+
* Provides the wired {@link VocabulariesRuntime} to every vocabularies hook and
|
|
5
|
+
* headless component below it. Bring your own visual shell — this component
|
|
6
|
+
* renders nothing of its own. (Core's `createModuleContext` provider, bound
|
|
7
|
+
* to this pair — slim wave §21/S2.)
|
|
8
|
+
*
|
|
9
|
+
* ```tsx
|
|
10
|
+
* const runtime = createVocabulariesRuntime({ baseUrl: "/vocabularies/api/v1/" });
|
|
11
|
+
* // give runtime.client to core's <StapelConfigProvider config={{ client }}>
|
|
12
|
+
* <VocabulariesProvider runtime={runtime}>{app}</VocabulariesProvider>
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare const VocabulariesProvider: (props: {
|
|
16
|
+
runtime: VocabulariesRuntime;
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
}) => ReactElement;
|
|
19
|
+
//# sourceMappingURL=VocabulariesProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VocabulariesProvider.d.ts","sourceRoot":"","sources":["../../src/headless/VocabulariesProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAErD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,EAAE,CAAC,KAAK,EAAE;IACzC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,QAAQ,EAAE,SAAS,CAAC;CACrB,KAAK,YAA6B,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ModuleProvider } from "../model/context.js";
|
|
2
|
+
/**
|
|
3
|
+
* Provides the wired {@link VocabulariesRuntime} to every vocabularies hook and
|
|
4
|
+
* headless component below it. Bring your own visual shell — this component
|
|
5
|
+
* renders nothing of its own. (Core's `createModuleContext` provider, bound
|
|
6
|
+
* to this pair — slim wave §21/S2.)
|
|
7
|
+
*
|
|
8
|
+
* ```tsx
|
|
9
|
+
* const runtime = createVocabulariesRuntime({ baseUrl: "/vocabularies/api/v1/" });
|
|
10
|
+
* // give runtime.client to core's <StapelConfigProvider config={{ client }}>
|
|
11
|
+
* <VocabulariesProvider runtime={runtime}>{app}</VocabulariesProvider>
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export const VocabulariesProvider = ModuleProvider;
|
|
15
|
+
//# sourceMappingURL=VocabulariesProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VocabulariesProvider.js","sourceRoot":"","sources":["../../src/headless/VocabulariesProvider.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAGZ,cAAc,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Remediation } from "./generated/errors.gen.js";
|
|
2
|
+
export { VOCABULARIES_ERRORS, VOCABULARIES_ERROR_CODES, vocabulariesErrorBundleEn, } from "./generated/errors.gen.js";
|
|
3
|
+
export type { VocabulariesErrorCode, VocabulariesErrorSpec, Remediation, } from "./generated/errors.gen.js";
|
|
4
|
+
/**
|
|
5
|
+
* Resolve a backend error code to its remediation hint, or `undefined` for a
|
|
6
|
+
* code this module doesn't know (e.g. a cross-cutting `stapel.http.*` fallback).
|
|
7
|
+
* Zero guessing at runtime — a static lookup over the generated map.
|
|
8
|
+
*/
|
|
9
|
+
export declare function explainVocabulariesError(code: string): Remediation | undefined;
|
|
10
|
+
//# sourceMappingURL=errorsMap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errorsMap.d.ts","sourceRoot":"","sources":["../../src/i18n/errorsMap.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,WAAW,GACZ,MAAM,2BAA2B,CAAC;AAEnC;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAG9E"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pair's error map (frontend-standard §4 checklist #7, frontend-core §2.5):
|
|
3
|
+
* the generated `code → { status, params, remediation, en }` catalog plus a
|
|
4
|
+
* tiny `explain()` lookup. Backs the manifest `errors` block and gives hosts a
|
|
5
|
+
* mechanical UX branch beside `t(code, params)`. The map itself is generated
|
|
6
|
+
* from the backend registry (`pnpm gen:errors`); this file only adds the lookup
|
|
7
|
+
* helper and re-exports the public surface.
|
|
8
|
+
*/
|
|
9
|
+
import { VOCABULARIES_ERRORS } from "./generated/errors.gen.js";
|
|
10
|
+
export { VOCABULARIES_ERRORS, VOCABULARIES_ERROR_CODES, vocabulariesErrorBundleEn, } from "./generated/errors.gen.js";
|
|
11
|
+
/**
|
|
12
|
+
* Resolve a backend error code to its remediation hint, or `undefined` for a
|
|
13
|
+
* code this module doesn't know (e.g. a cross-cutting `stapel.http.*` fallback).
|
|
14
|
+
* Zero guessing at runtime — a static lookup over the generated map.
|
|
15
|
+
*/
|
|
16
|
+
export function explainVocabulariesError(code) {
|
|
17
|
+
return VOCABULARIES_ERRORS[code]
|
|
18
|
+
?.remediation;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=errorsMap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errorsMap.js","sourceRoot":"","sources":["../../src/i18n/errorsMap.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAGhE,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC;AAOnC;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,OAAQ,mBAAoE,CAAC,IAAI,CAAC;QAChF,EAAE,WAAW,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { I18nDictionary, I18nEngine } from "@stapel/core";
|
|
2
|
+
export { vocabulariesErrorBundleEs } from "./generated/errors.es.gen.js";
|
|
3
|
+
/**
|
|
4
|
+
* Spanish bundle for vocabularies-react — shipped as the
|
|
5
|
+
* `@stapel/vocabularies-react/i18n/es` subpath (i18n-shipping.md §2) so the locale is
|
|
6
|
+
* opt-in: a host that never registers it never carries these strings (the main
|
|
7
|
+
* entry does not import this module).
|
|
8
|
+
*
|
|
9
|
+
* TWO SOURCES, ON PURPOSE — see the ru bundle's header: the generated
|
|
10
|
+
* `vocabulariesErrorBundleEs` covers the codes stapel-core owns, and the 3
|
|
11
|
+
* stapel-vocabularies owns are authored below until upstream ships a
|
|
12
|
+
* `translations/errors.es.json`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const vocabulariesI18nBundleEs: I18nDictionary;
|
|
15
|
+
/**
|
|
16
|
+
* Register the Spanish bundle. The en bundle goes UNDER it
|
|
17
|
+
* (merge-priority convention): a key this locale has not translated yet
|
|
18
|
+
* degrades to ENGLISH, never to a raw key.
|
|
19
|
+
*/
|
|
20
|
+
export declare function registerVocabulariesI18nEs(engine: I18nEngine, locale?: string): void;
|
|
21
|
+
//# sourceMappingURL=es.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"es.d.ts","sourceRoot":"","sources":["../../src/i18n/es.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAI/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAEzE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,EAAE,cAkBtC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,UAAU,EAClB,MAAM,SAAO,GACZ,IAAI,CAGN"}
|