@persona/layout-editor-remote-module 0.10.0 → 0.11.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/README.md +21 -0
- package/dist/bridge-frame.d.mts +2 -1
- package/dist/bridge-frame.mjs +1 -1
- package/dist/bridge-host.d.mts +2 -1
- package/dist/bridge-host.mjs +1 -1
- package/dist/config-form.d.mts +23 -0
- package/dist/config-form.mjs +79 -0
- package/dist/{protocol-Dqnl8JTs.d.mts → protocol-ClWDYwW2.d.mts} +2 -9
- package/dist/types-CBSiNsDJ.d.mts +17 -0
- package/package.json +8 -1
- /package/dist/{protocol-Br3C6FM7.mjs → protocol-BfjTaW1S.mjs} +0 -0
package/README.md
CHANGED
|
@@ -180,3 +180,24 @@ const { modules } = parseRemoteModuleManifest(await response.json());
|
|
|
180
180
|
It throws `RemoteModuleManifestParseError` (with `.issues` and a prettified `.message`) on a
|
|
181
181
|
malformed document; `safeParseRemoteModuleManifest` returns `{ success, data | error }` instead of
|
|
182
182
|
throwing.
|
|
183
|
+
|
|
184
|
+
### Rendering a config panel
|
|
185
|
+
|
|
186
|
+
A host stores a placed module's config under a `config` property, so its RJSF form edits
|
|
187
|
+
`{ config }`. The `./config-form` entry adapts a manifest to that shape, with no React or RJSF
|
|
188
|
+
dependency:
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
import {
|
|
192
|
+
nestRemoteConfigSchema,
|
|
193
|
+
nestRemoteUiConfigSchema,
|
|
194
|
+
remoteConfigDefaults,
|
|
195
|
+
} from '@persona/layout-editor-remote-module/config-form';
|
|
196
|
+
|
|
197
|
+
const schema = nestRemoteConfigSchema(module.configSchema); // `$ref`s rewritten to match
|
|
198
|
+
const uiSchema = nestRemoteUiConfigSchema(module.uiConfigSchema);
|
|
199
|
+
const initialConfig = remoteConfigDefaults(module.configSchema); // top-level `default`s
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Render the form with `schema`, `uiSchema` and `formData: { config }`, and read the edited config
|
|
203
|
+
back from `formData.config`.
|
package/dist/bridge-frame.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as Json } from "./types-CBSiNsDJ.mjs";
|
|
2
|
+
import { t as RemoteModuleContext } from "./protocol-ClWDYwW2.mjs";
|
|
2
3
|
import { ReactNode } from "react";
|
|
3
4
|
|
|
4
5
|
//#region src/bridge/origin.d.ts
|
package/dist/bridge-frame.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as resolveAllowedHostOrigins, n as SOURCE, o as candidateParentOrigin, r as parseHostToModuleMessage, s as personaDashboardHostOrigins, t as PROTOCOL_VERSION } from "./protocol-
|
|
1
|
+
import { c as resolveAllowedHostOrigins, n as SOURCE, o as candidateParentOrigin, r as parseHostToModuleMessage, s as personaDashboardHostOrigins, t as PROTOCOL_VERSION } from "./protocol-BfjTaW1S.mjs";
|
|
2
2
|
import { Component, useEffect, useRef, useState } from "react";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
|
package/dist/bridge-host.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as Json } from "./types-CBSiNsDJ.mjs";
|
|
2
|
+
import { t as RemoteModuleContext } from "./protocol-ClWDYwW2.mjs";
|
|
2
3
|
import { CSSProperties, ReactNode, Ref } from "react";
|
|
3
4
|
|
|
4
5
|
//#region src/bridge/host/buildModuleSrc.d.ts
|
package/dist/bridge-host.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as assertNotSelfOrigin, i as parseModuleToHostMessage, n as SOURCE, t as PROTOCOL_VERSION } from "./protocol-
|
|
1
|
+
import { a as assertNotSelfOrigin, i as parseModuleToHostMessage, n as SOURCE, t as PROTOCOL_VERSION } from "./protocol-BfjTaW1S.mjs";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { n as JsonSchemaObject, t as Json } from "./types-CBSiNsDJ.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/config-form.d.ts
|
|
4
|
+
|
|
5
|
+
/** JSON pointer, in the nested schema, of the module's own config schema. */
|
|
6
|
+
declare const REMOTE_CONFIG_POINTER_PREFIX = "#/properties/config";
|
|
7
|
+
/**
|
|
8
|
+
* Nest a manifest `configSchema` under a top-level `config` property, rewriting `$ref`s so they
|
|
9
|
+
* still resolve. Drops `$schema` and `$id`; keeps `$defs` / `definitions` at the root.
|
|
10
|
+
*/
|
|
11
|
+
declare function nestRemoteConfigSchema(configSchema: JsonSchemaObject): JsonSchemaObject;
|
|
12
|
+
/**
|
|
13
|
+
* Nest a manifest `uiConfigSchema` to match {@link nestRemoteConfigSchema}, hiding the wrapper
|
|
14
|
+
* object's title so the module's fields render as if top level.
|
|
15
|
+
*/
|
|
16
|
+
declare function nestRemoteUiConfigSchema(uiConfigSchema: JsonSchemaObject | undefined): JsonSchemaObject;
|
|
17
|
+
/**
|
|
18
|
+
* A config holding each top-level `configSchema` property's `default`. Properties without one are
|
|
19
|
+
* left unset; defaults are cloned so the result can be mutated freely.
|
|
20
|
+
*/
|
|
21
|
+
declare function remoteConfigDefaults(configSchema: JsonSchemaObject | undefined): Record<string, Json>;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { REMOTE_CONFIG_POINTER_PREFIX, nestRemoteConfigSchema, nestRemoteUiConfigSchema, remoteConfigDefaults };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
//#region src/config-form.ts
|
|
2
|
+
/** JSON pointer, in the nested schema, of the module's own config schema. */
|
|
3
|
+
const REMOTE_CONFIG_POINTER_PREFIX = "#/properties/config";
|
|
4
|
+
/** Keywords whose values are instance data, never schemas, so a `$ref` key inside them is data. */
|
|
5
|
+
const LITERAL_KEYWORDS = new Set([
|
|
6
|
+
"const",
|
|
7
|
+
"default",
|
|
8
|
+
"enum",
|
|
9
|
+
"examples"
|
|
10
|
+
]);
|
|
11
|
+
/** Keywords whose values map arbitrary names to schemas, so a name like `default` is a schema. */
|
|
12
|
+
const SCHEMA_MAP_KEYWORDS = new Set([
|
|
13
|
+
"$defs",
|
|
14
|
+
"definitions",
|
|
15
|
+
"dependentSchemas",
|
|
16
|
+
"patternProperties",
|
|
17
|
+
"properties"
|
|
18
|
+
]);
|
|
19
|
+
function rewriteSchemaMap(value, schemaId) {
|
|
20
|
+
if (value == null || typeof value !== "object" || Array.isArray(value)) return value;
|
|
21
|
+
return Object.fromEntries(Object.entries(value).map(([name, schema]) => [name, rewriteReferences(schema, schemaId)]));
|
|
22
|
+
}
|
|
23
|
+
function rewriteReferences(value, schemaId) {
|
|
24
|
+
if (Array.isArray(value)) return value.map((item) => rewriteReferences(item, schemaId));
|
|
25
|
+
if (value == null || typeof value !== "object") return value;
|
|
26
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => {
|
|
27
|
+
if (key === "$ref" && typeof child === "string") return [key, rewriteReference(child, schemaId)];
|
|
28
|
+
if (LITERAL_KEYWORDS.has(key)) return [key, child];
|
|
29
|
+
if (SCHEMA_MAP_KEYWORDS.has(key)) return [key, rewriteSchemaMap(child, schemaId)];
|
|
30
|
+
return [key, rewriteReferences(child, schemaId)];
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
function rewriteReference(reference, schemaId) {
|
|
34
|
+
if (schemaId != null) {
|
|
35
|
+
if (reference === schemaId) return REMOTE_CONFIG_POINTER_PREFIX;
|
|
36
|
+
if (reference.startsWith(`${schemaId}#`)) return rewriteReference(reference.slice(schemaId.length));
|
|
37
|
+
}
|
|
38
|
+
if (reference === "#") return REMOTE_CONFIG_POINTER_PREFIX;
|
|
39
|
+
if (reference.startsWith("#/$defs/") || reference.startsWith("#/definitions/")) return reference;
|
|
40
|
+
if (reference.startsWith("#/")) return `${REMOTE_CONFIG_POINTER_PREFIX}${reference.slice(1)}`;
|
|
41
|
+
return reference;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Nest a manifest `configSchema` under a top-level `config` property, rewriting `$ref`s so they
|
|
45
|
+
* still resolve. Drops `$schema` and `$id`; keeps `$defs` / `definitions` at the root.
|
|
46
|
+
*/
|
|
47
|
+
function nestRemoteConfigSchema(configSchema) {
|
|
48
|
+
const { $defs, definitions, $id, ...rest } = configSchema;
|
|
49
|
+
const body = Object.fromEntries(Object.entries(rest).filter(([key]) => key !== "$schema"));
|
|
50
|
+
const schemaId = typeof $id === "string" ? $id : void 0;
|
|
51
|
+
return {
|
|
52
|
+
type: "object",
|
|
53
|
+
properties: { config: rewriteReferences(body, schemaId) },
|
|
54
|
+
...$defs != null && { $defs: rewriteSchemaMap($defs, schemaId) },
|
|
55
|
+
...definitions != null && { definitions: rewriteSchemaMap(definitions, schemaId) }
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Nest a manifest `uiConfigSchema` to match {@link nestRemoteConfigSchema}, hiding the wrapper
|
|
60
|
+
* object's title so the module's fields render as if top level.
|
|
61
|
+
*/
|
|
62
|
+
function nestRemoteUiConfigSchema(uiConfigSchema) {
|
|
63
|
+
return { config: {
|
|
64
|
+
...uiConfigSchema,
|
|
65
|
+
"ui:title": ""
|
|
66
|
+
} };
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A config holding each top-level `configSchema` property's `default`. Properties without one are
|
|
70
|
+
* left unset; defaults are cloned so the result can be mutated freely.
|
|
71
|
+
*/
|
|
72
|
+
function remoteConfigDefaults(configSchema) {
|
|
73
|
+
const properties = configSchema?.properties;
|
|
74
|
+
if (properties == null || typeof properties !== "object" || Array.isArray(properties)) return {};
|
|
75
|
+
return Object.fromEntries(Object.entries(properties).filter(([, propertySchema]) => typeof propertySchema === "object" && propertySchema != null && !Array.isArray(propertySchema) && "default" in propertySchema).map(([key, propertySchema]) => [key, structuredClone(propertySchema.default)]));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
//#endregion
|
|
79
|
+
export { REMOTE_CONFIG_POINTER_PREFIX, nestRemoteConfigSchema, nestRemoteUiConfigSchema, remoteConfigDefaults };
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
//#region src/types.d.ts
|
|
4
|
-
|
|
5
|
-
type Json = boolean | JsonObject | JsonValue[] | null | number | string;
|
|
6
|
-
type JsonObject = {
|
|
7
|
-
[key: string]: Json;
|
|
8
|
-
};
|
|
9
|
-
type JsonValue = Json;
|
|
10
|
-
//#endregion
|
|
11
3
|
//#region src/bridge/protocol.d.ts
|
|
4
|
+
|
|
12
5
|
/**
|
|
13
6
|
* Runtime facts about where the module is rendered, owned by the host and not
|
|
14
7
|
* derivable by the module itself. Distinct from `data`, which is the module's
|
|
@@ -24,4 +17,4 @@ declare const remoteModuleContextSchema: z.ZodObject<{
|
|
|
24
17
|
}, z.core.$strip>;
|
|
25
18
|
type RemoteModuleContext = z.infer<typeof remoteModuleContextSchema>;
|
|
26
19
|
//#endregion
|
|
27
|
-
export {
|
|
20
|
+
export { RemoteModuleContext as t };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
|
|
5
|
+
type Json = boolean | JsonObject | JsonValue[] | null | number | string;
|
|
6
|
+
/**
|
|
7
|
+
* Loose JSON Schema object. Deliberately not a full JSON Schema type system —
|
|
8
|
+
* this package only needs to carry what `z.toJSONSchema()` emits for consumers
|
|
9
|
+
* to validate or render.
|
|
10
|
+
*/
|
|
11
|
+
type JsonSchemaObject = Record<string, unknown>;
|
|
12
|
+
type JsonObject = {
|
|
13
|
+
[key: string]: Json;
|
|
14
|
+
};
|
|
15
|
+
type JsonValue = Json;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { JsonSchemaObject as n, Json as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@persona/layout-editor-remote-module",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Shared manifest format, Vite plugin, and host/iframe bridge for remotely-defined dashboard layout modules in Persona dashboard apps.",
|
|
5
5
|
"license": "SEE LICENSE",
|
|
6
6
|
"type": "module",
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
],
|
|
16
16
|
"bridge-frame": [
|
|
17
17
|
"dist/bridge-frame.d.mts"
|
|
18
|
+
],
|
|
19
|
+
"config-form": [
|
|
20
|
+
"dist/config-form.d.mts"
|
|
18
21
|
]
|
|
19
22
|
}
|
|
20
23
|
},
|
|
@@ -111,6 +114,10 @@
|
|
|
111
114
|
"types": "./dist/bridge-host.d.mts",
|
|
112
115
|
"import": "./dist/bridge-host.mjs"
|
|
113
116
|
},
|
|
117
|
+
"./config-form": {
|
|
118
|
+
"types": "./dist/config-form.d.mts",
|
|
119
|
+
"import": "./dist/config-form.mjs"
|
|
120
|
+
},
|
|
114
121
|
"./bridge-frame": {
|
|
115
122
|
"types": "./dist/bridge-frame.d.mts",
|
|
116
123
|
"import": "./dist/bridge-frame.mjs"
|
|
File without changes
|