blockprint 0.2.0 → 0.2.1
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 +22 -0
- package/dist/Renderer.d.ts +1 -1
- package/dist/Renderer.js +84 -25
- package/dist/config.d.ts +3 -3
- package/dist/createRegistry.d.ts +2 -2
- package/dist/env.d.ts +5 -0
- package/dist/env.js +7 -0
- package/dist/fallback.d.ts +1 -1
- package/dist/fallback.js +2 -1
- package/dist/index.d.ts +6 -6
- package/dist/parseConfig.d.ts +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +3 -2
- package/dist/chunk-4JB5QQUK.js +0 -37
- package/dist/chunk-4JB5QQUK.js.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
**Live demo: [blockprint.terzidest.com](https://blockprint.terzidest.com)** — three completely different pages (commerce, SaaS, editorial) from one renderer and one registry, plus a deliberately broken config showing graceful fallback. · [GitHub](https://github.com/terzidest/blockprint)
|
|
6
6
|
|
|
7
|
+
In production at [ethereal_nature](https://github.com/terzidest/ethereal_nature): storefront pages from DB-stored configs, an admin page editor, and server-side validation via `blockprint/config`.
|
|
8
|
+
|
|
7
9
|
## The problem
|
|
8
10
|
|
|
9
11
|
Content teams compose pages from a fixed set of block types; your app receives JSON like `[{ "type": "hero", "props": { … } }, …]`. Consuming that in React usually collapses into a `switch` on `block.type` — every block imported into every page, props typed `any`, unknown types crashing the page.
|
|
@@ -58,6 +60,26 @@ The default fallback renders a warning box in development and `null` in producti
|
|
|
58
60
|
|
|
59
61
|
The optional `wrapBlock={(node, entry, index) => …}` prop wraps every rendered entry — blocks and fallbacks alike — with access to the config entry and its index. This is the hook point for visual-editing overlays, analytics boundaries, or per-block chrome.
|
|
60
62
|
|
|
63
|
+
A common recipe — shared section chrome, deep-link anchors, and analytics attributes in one place instead of repeated in every block:
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
<Renderer
|
|
67
|
+
config={config}
|
|
68
|
+
registry={registry}
|
|
69
|
+
wrapBlock={(node, entry) => (
|
|
70
|
+
<section
|
|
71
|
+
id={entry.id != null ? String(entry.id) : undefined} // anchor: /page#hero-1
|
|
72
|
+
data-block={entry.type} // analytics / e2e hooks
|
|
73
|
+
className="mx-auto max-w-5xl px-6 py-10"
|
|
74
|
+
>
|
|
75
|
+
{node}
|
|
76
|
+
</section>
|
|
77
|
+
)}
|
|
78
|
+
/>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Rendering and schema validation are memoised per `(config, registry)` identity — keep the config referentially stable across renders (state, loader data, `useMemo`) to benefit. Duplicate `id`s warn in development and render under collision-safe keys.
|
|
82
|
+
|
|
61
83
|
### `parseConfig(input)`
|
|
62
84
|
|
|
63
85
|
The boundary validator, exported for consumers who want to fail at fetch time rather than render time. Throws `ConfigError` with the entry index and reason.
|
package/dist/Renderer.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ComponentType, ReactNode } from "react";
|
|
2
|
-
import type { BlockConfig, BlocksShape, FallbackProps, Registry } from "./types.
|
|
2
|
+
import type { BlockConfig, BlocksShape, FallbackProps, Registry } from "./types.js";
|
|
3
3
|
export interface RendererProps<T extends BlocksShape> {
|
|
4
4
|
/** Untrusted input; the outer shape is validated internally. */
|
|
5
5
|
config: unknown;
|
package/dist/Renderer.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { Fragment } from "react";
|
|
2
|
+
import { Fragment, useMemo } from "react";
|
|
3
3
|
import { parseConfig } from "./parseConfig.js";
|
|
4
4
|
import { DefaultFallback } from "./fallback.js";
|
|
5
|
+
import { isDev } from "./env.js";
|
|
6
|
+
// StrictMode double-invokes render (and therefore the memo) in development;
|
|
7
|
+
// remember what we've already warned about so each duplicate id logs once.
|
|
8
|
+
const warnedDuplicateIds = new Set();
|
|
5
9
|
// `memo`/`forwardRef` components are exotic objects, not functions, so the
|
|
6
10
|
// bare-vs-definition split must discriminate on the `component` key.
|
|
7
11
|
function resolveDef(def) {
|
|
@@ -10,37 +14,92 @@ function resolveDef(def) {
|
|
|
10
14
|
}
|
|
11
15
|
return { component: def };
|
|
12
16
|
}
|
|
13
|
-
|
|
14
|
-
const Fallback = fallback ?? DefaultFallback;
|
|
17
|
+
function prepare(config, registry) {
|
|
15
18
|
const entries = parseConfig(config);
|
|
19
|
+
const seenKeys = new Set();
|
|
16
20
|
return entries.map((entry, index) => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
let key = entry.id ?? `${entry.type}-${index}`;
|
|
22
|
+
if (seenKeys.has(key)) {
|
|
23
|
+
if (isDev() && !warnedDuplicateIds.has(key)) {
|
|
24
|
+
warnedDuplicateIds.add(key);
|
|
25
|
+
console.warn(`blockprint: duplicate block id "${key}" at config[${index}]; ids should be unique per config`);
|
|
26
|
+
}
|
|
27
|
+
key = `${key}__dup${index}`;
|
|
28
|
+
}
|
|
29
|
+
seenKeys.add(key);
|
|
30
|
+
if (!Object.hasOwn(registry.blocks, entry.type)) {
|
|
31
|
+
return {
|
|
32
|
+
key,
|
|
33
|
+
entry,
|
|
34
|
+
kind: "fallback",
|
|
35
|
+
fallbackProps: {
|
|
36
|
+
reason: "unknown-type",
|
|
37
|
+
type: entry.type,
|
|
38
|
+
props: entry.props,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const { component, schema } = resolveDef(registry.blocks[entry.type]);
|
|
43
|
+
if (!schema) {
|
|
44
|
+
return {
|
|
45
|
+
key,
|
|
46
|
+
entry,
|
|
47
|
+
kind: "block",
|
|
48
|
+
component,
|
|
49
|
+
props: entry.props,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
30
52
|
const result = schema["~standard"].validate(entry.props);
|
|
31
53
|
// React render is synchronous; async schemas are a config mistake and
|
|
32
54
|
// are contained like any other invalid block.
|
|
33
55
|
if (result instanceof Promise) {
|
|
34
|
-
return
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
56
|
+
return {
|
|
57
|
+
key,
|
|
58
|
+
entry,
|
|
59
|
+
kind: "fallback",
|
|
60
|
+
fallbackProps: {
|
|
61
|
+
reason: "invalid-props",
|
|
62
|
+
type: entry.type,
|
|
63
|
+
props: entry.props,
|
|
64
|
+
issues: [
|
|
65
|
+
{
|
|
66
|
+
message: "schema validated asynchronously; blockprint only supports synchronous schemas",
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
};
|
|
39
71
|
}
|
|
40
72
|
if (result.issues) {
|
|
41
|
-
return
|
|
73
|
+
return {
|
|
74
|
+
key,
|
|
75
|
+
entry,
|
|
76
|
+
kind: "fallback",
|
|
77
|
+
fallbackProps: {
|
|
78
|
+
reason: "invalid-props",
|
|
79
|
+
type: entry.type,
|
|
80
|
+
props: entry.props,
|
|
81
|
+
issues: result.issues,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
42
84
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
85
|
+
return {
|
|
86
|
+
key,
|
|
87
|
+
entry,
|
|
88
|
+
kind: "block",
|
|
89
|
+
component,
|
|
90
|
+
props: result.value,
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
export function Renderer({ config, registry, fallback, wrapBlock, }) {
|
|
95
|
+
const Fallback = fallback ?? DefaultFallback;
|
|
96
|
+
// Parsing and schema validation run once per (config, registry) identity,
|
|
97
|
+
// not on every render; a consumer recreating the config array each render
|
|
98
|
+
// opts out of the caching, not the correctness.
|
|
99
|
+
const prepared = useMemo(() => prepare(config, registry), [config, registry]);
|
|
100
|
+
return prepared.map((item, index) => {
|
|
101
|
+
const node = item.kind === "block" ? (_jsx(item.component, { ...item.props })) : (_jsx(Fallback, { ...item.fallbackProps }));
|
|
102
|
+
// The key lives on a Fragment so it survives whatever wrapBlock returns.
|
|
103
|
+
return (_jsx(Fragment, { children: wrapBlock ? wrapBlock(node, item.entry, index) : node }, item.key));
|
|
104
|
+
});
|
|
46
105
|
}
|
package/dist/config.d.ts
CHANGED
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* this module (and its imports) free of React — servers validating stored
|
|
5
5
|
* configs want exactly this and nothing more.
|
|
6
6
|
*/
|
|
7
|
-
export { parseConfig, ConfigError } from "./parseConfig.
|
|
8
|
-
export type { BlockConfig } from "./types.
|
|
9
|
-
export type { StandardSchemaV1 } from "./standard-schema.
|
|
7
|
+
export { parseConfig, ConfigError } from "./parseConfig.js";
|
|
8
|
+
export type { BlockConfig } from "./types.js";
|
|
9
|
+
export type { StandardSchemaV1 } from "./standard-schema.js";
|
package/dist/createRegistry.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ComponentType } from "react";
|
|
2
|
-
import type { StandardSchemaV1 } from "./standard-schema.
|
|
3
|
-
import type { BlocksShape, Registry } from "./types.
|
|
2
|
+
import type { StandardSchemaV1 } from "./standard-schema.js";
|
|
3
|
+
import type { BlocksShape, Registry } from "./types.js";
|
|
4
4
|
/**
|
|
5
5
|
* Maps every compatible entry to `unknown` (an identity when intersected) and
|
|
6
6
|
* every entry whose schema output is not assignable to its component's props
|
package/dist/env.d.ts
ADDED
package/dist/env.js
ADDED
package/dist/fallback.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { FallbackProps } from "./types.
|
|
1
|
+
import type { FallbackProps } from "./types.js";
|
|
2
2
|
export declare function DefaultFallback(props: FallbackProps): import("react").JSX.Element | null;
|
package/dist/fallback.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { createRegistry } from "./createRegistry.
|
|
2
|
-
export { Renderer } from "./Renderer.
|
|
3
|
-
export type { RendererProps } from "./Renderer.
|
|
4
|
-
export { parseConfig, ConfigError } from "./parseConfig.
|
|
5
|
-
export type { BlockConfig, BlockDef, BlocksShape, ConfigFor, FallbackProps, InputFor, PropsFor, Registry, } from "./types.
|
|
6
|
-
export type { StandardSchemaV1 } from "./standard-schema.
|
|
1
|
+
export { createRegistry } from "./createRegistry.js";
|
|
2
|
+
export { Renderer } from "./Renderer.js";
|
|
3
|
+
export type { RendererProps } from "./Renderer.js";
|
|
4
|
+
export { parseConfig, ConfigError } from "./parseConfig.js";
|
|
5
|
+
export type { BlockConfig, BlockDef, BlocksShape, ConfigFor, FallbackProps, InputFor, PropsFor, Registry, } from "./types.js";
|
|
6
|
+
export type { StandardSchemaV1 } from "./standard-schema.js";
|
package/dist/parseConfig.d.ts
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ComponentType } from "react";
|
|
2
|
-
import type { StandardSchemaV1 } from "./standard-schema.
|
|
2
|
+
import type { StandardSchemaV1 } from "./standard-schema.js";
|
|
3
3
|
export type AnyComponent = ComponentType<any>;
|
|
4
4
|
export type BlockDef = AnyComponent | {
|
|
5
5
|
component: AnyComponent;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blockprint",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Typed, config-driven block renderer for React. Render arbitrary UI trees from untrusted JSON with compile-time registry safety and runtime schema validation.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://blockprint.terzidest.com",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/react": "^19.2.18",
|
|
45
45
|
"@types/react-dom": "^19.2.4",
|
|
46
|
+
"jsdom": "^30.1.3",
|
|
46
47
|
"react": "^19.2.8",
|
|
47
48
|
"react-dom": "^19.2.8",
|
|
48
49
|
"typescript": "^7.0.2",
|
|
@@ -55,7 +56,7 @@
|
|
|
55
56
|
}
|
|
56
57
|
},
|
|
57
58
|
"scripts": {
|
|
58
|
-
"build": "tsc -p tsconfig.build.json",
|
|
59
|
+
"build": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json && node scripts/fix-dts.mjs",
|
|
59
60
|
"typecheck": "tsc",
|
|
60
61
|
"test": "vitest run"
|
|
61
62
|
}
|
package/dist/chunk-4JB5QQUK.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
// src/parseConfig.ts
|
|
2
|
-
var ConfigError = class extends Error {
|
|
3
|
-
constructor(message) {
|
|
4
|
-
super(message);
|
|
5
|
-
this.name = "ConfigError";
|
|
6
|
-
}
|
|
7
|
-
};
|
|
8
|
-
function parseConfig(input) {
|
|
9
|
-
if (!Array.isArray(input)) {
|
|
10
|
-
throw new ConfigError(
|
|
11
|
-
`config must be an array, received ${input === null ? "null" : typeof input}`
|
|
12
|
-
);
|
|
13
|
-
}
|
|
14
|
-
return input.map((entry, index) => {
|
|
15
|
-
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
16
|
-
throw new ConfigError(`config[${index}] must be an object`);
|
|
17
|
-
}
|
|
18
|
-
const { type, props, id } = entry;
|
|
19
|
-
if (typeof type !== "string" || type.length === 0) {
|
|
20
|
-
throw new ConfigError(
|
|
21
|
-
`config[${index}].type must be a non-empty string`
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
if (id !== void 0 && typeof id !== "string" && typeof id !== "number") {
|
|
25
|
-
throw new ConfigError(
|
|
26
|
-
`config[${index}].id must be a string or number when present`
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
return id === void 0 ? { type, props } : { type, props, id };
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export {
|
|
34
|
-
ConfigError,
|
|
35
|
-
parseConfig
|
|
36
|
-
};
|
|
37
|
-
//# sourceMappingURL=chunk-4JB5QQUK.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/parseConfig.ts"],"sourcesContent":["import type { BlockConfig } from \"./types\";\n\nexport class ConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigError\";\n }\n}\n\n/**\n * The single boundary where untrusted input becomes a typed config. Validates\n * the outer shape only; per-block props are validated against their registered\n * schema at render time.\n */\nexport function parseConfig(input: unknown): BlockConfig[] {\n if (!Array.isArray(input)) {\n throw new ConfigError(\n `config must be an array, received ${input === null ? \"null\" : typeof input}`,\n );\n }\n\n return input.map((entry, index) => {\n if (typeof entry !== \"object\" || entry === null || Array.isArray(entry)) {\n throw new ConfigError(`config[${index}] must be an object`);\n }\n const { type, props, id } = entry as Record<string, unknown>;\n if (typeof type !== \"string\" || type.length === 0) {\n throw new ConfigError(\n `config[${index}].type must be a non-empty string`,\n );\n }\n if (id !== undefined && typeof id !== \"string\" && typeof id !== \"number\") {\n throw new ConfigError(\n `config[${index}].id must be a string or number when present`,\n );\n }\n return id === undefined ? { type, props } : { type, props, id };\n });\n}\n"],"mappings":";AAEO,IAAM,cAAN,cAA0B,MAAM;AAAA,EACrC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAOO,SAAS,YAAY,OAA+B;AACzD,MAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,UAAM,IAAI;AAAA,MACR,qCAAqC,UAAU,OAAO,SAAS,OAAO,KAAK;AAAA,IAC7E;AAAA,EACF;AAEA,SAAO,MAAM,IAAI,CAAC,OAAO,UAAU;AACjC,QAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GAAG;AACvE,YAAM,IAAI,YAAY,UAAU,KAAK,qBAAqB;AAAA,IAC5D;AACA,UAAM,EAAE,MAAM,OAAO,GAAG,IAAI;AAC5B,QAAI,OAAO,SAAS,YAAY,KAAK,WAAW,GAAG;AACjD,YAAM,IAAI;AAAA,QACR,UAAU,KAAK;AAAA,MACjB;AAAA,IACF;AACA,QAAI,OAAO,UAAa,OAAO,OAAO,YAAY,OAAO,OAAO,UAAU;AACxE,YAAM,IAAI;AAAA,QACR,UAAU,KAAK;AAAA,MACjB;AAAA,IACF;AACA,WAAO,OAAO,SAAY,EAAE,MAAM,MAAM,IAAI,EAAE,MAAM,OAAO,GAAG;AAAA,EAChE,CAAC;AACH;","names":[]}
|
package/dist/config.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/createRegistry.ts","../src/Renderer.tsx","../src/fallback.tsx"],"sourcesContent":["import type { ComponentType } from \"react\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport type { BlocksShape, Registry } from \"./types\";\n\n/**\n * Maps every compatible entry to `unknown` (an identity when intersected) and\n * every entry whose schema output is not assignable to its component's props\n * to an impossible shape — so the type error lands on the offending key with\n * a message naming it.\n */\nexport type ValidateBlocks<T extends BlocksShape> = {\n [K in keyof T]: T[K] extends {\n component: ComponentType<infer P>;\n schema: StandardSchemaV1<unknown, infer S>;\n }\n ? [S] extends [P]\n ? unknown\n : {\n schema: `schema output is not assignable to props of '${K & string}'`;\n }\n : unknown;\n};\n\nexport function createRegistry<T extends BlocksShape>(\n blocks: T & ValidateBlocks<T>,\n): Registry<T> {\n return { blocks: blocks as T };\n}\n","import { Fragment } from \"react\";\nimport type { ComponentType, ReactNode } from \"react\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport type {\n AnyComponent,\n BlockConfig,\n BlocksShape,\n FallbackProps,\n Registry,\n} from \"./types\";\nimport { parseConfig } from \"./parseConfig\";\nimport { DefaultFallback } from \"./fallback\";\n\nexport interface RendererProps<T extends BlocksShape> {\n /** Untrusted input; the outer shape is validated internally. */\n config: unknown;\n registry: Registry<T>;\n fallback?: ComponentType<FallbackProps>;\n /**\n * Wraps every rendered entry — blocks and fallbacks alike — with access to\n * the config entry and its index. The hook point for visual-editing\n * overlays, analytics boundaries, or per-block chrome.\n */\n wrapBlock?: (node: ReactNode, entry: BlockConfig, index: number) => ReactNode;\n}\n\ninterface ResolvedDef {\n component: AnyComponent;\n schema?: StandardSchemaV1<unknown, any>;\n}\n\n// `memo`/`forwardRef` components are exotic objects, not functions, so the\n// bare-vs-definition split must discriminate on the `component` key.\nfunction resolveDef(def: BlocksShape[string]): ResolvedDef {\n if (typeof def === \"object\" && def !== null && \"component\" in def) {\n return def;\n }\n return { component: def };\n}\n\nexport function Renderer<T extends BlocksShape>({\n config,\n registry,\n fallback,\n wrapBlock,\n}: RendererProps<T>): ReactNode {\n const Fallback = fallback ?? DefaultFallback;\n const entries = parseConfig(config);\n\n return entries.map((entry, index) => {\n const key = entry.id ?? `${entry.type}-${index}`;\n const node = renderEntry(entry, registry, Fallback);\n // The key lives on a Fragment so it survives whatever wrapBlock returns.\n return (\n <Fragment key={key}>\n {wrapBlock ? wrapBlock(node, entry, index) : node}\n </Fragment>\n );\n });\n}\n\nfunction renderEntry(\n entry: BlockConfig,\n registry: Registry<BlocksShape>,\n Fallback: ComponentType<FallbackProps>,\n): ReactNode {\n if (!Object.hasOwn(registry.blocks, entry.type)) {\n return (\n <Fallback reason=\"unknown-type\" type={entry.type} props={entry.props} />\n );\n }\n\n const { component: Component, schema } = resolveDef(\n registry.blocks[entry.type] as BlocksShape[string],\n );\n\n let props = entry.props;\n if (schema) {\n const result = schema[\"~standard\"].validate(entry.props);\n // React render is synchronous; async schemas are a config mistake and\n // are contained like any other invalid block.\n if (result instanceof Promise) {\n return (\n <Fallback\n reason=\"invalid-props\"\n type={entry.type}\n props={entry.props}\n issues={[\n {\n message:\n \"schema validated asynchronously; blockprint only supports synchronous schemas\",\n },\n ]}\n />\n );\n }\n if (result.issues) {\n return (\n <Fallback\n reason=\"invalid-props\"\n type={entry.type}\n props={entry.props}\n issues={result.issues}\n />\n );\n }\n props = result.value;\n }\n\n return <Component {...(props as object | undefined)} />;\n}\n","import type { FallbackProps } from \"./types\";\n\n// Ambient declaration instead of @types/node: bundlers replace\n// process.env.NODE_ENV statically, and the library has no other Node surface.\ndeclare const process: { env: { NODE_ENV?: string } };\n\nexport function DefaultFallback(props: FallbackProps) {\n if (process.env.NODE_ENV === \"production\") {\n return null;\n }\n\n const detail =\n props.reason === \"invalid-props\"\n ? props.issues.map((issue) => issue.message).join(\"; \")\n : \"no component registered for this type\";\n\n return (\n <div\n role=\"note\"\n style={{\n border: \"1px dashed #c00\",\n borderRadius: 4,\n padding: \"8px 12px\",\n fontFamily: \"monospace\",\n fontSize: 13,\n color: \"#c00\",\n }}\n >\n blockprint: block "{props.type}" not rendered ({props.reason}):{\" \"}\n {detail}\n </div>\n );\n}\n"],"mappings":";;;;;;AAuBO,SAAS,eACd,QACa;AACb,SAAO,EAAE,OAAoB;AAC/B;;;AC3BA,SAAS,gBAAgB;;;ACiBrB;AAXG,SAAS,gBAAgB,OAAsB;AACpD,MAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,WAAO;AAAA,EACT;AAEA,QAAM,SACJ,MAAM,WAAW,kBACb,MAAM,OAAO,IAAI,CAAC,UAAU,MAAM,OAAO,EAAE,KAAK,IAAI,IACpD;AAEN,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,OAAO;AAAA,MACT;AAAA,MACD;AAAA;AAAA,QAC0B,MAAM;AAAA,QAAK;AAAA,QAAsB,MAAM;AAAA,QAAO;AAAA,QAAG;AAAA,QACzE;AAAA;AAAA;AAAA,EACH;AAEJ;;;ADsBM;AArBN,SAAS,WAAW,KAAuC;AACzD,MAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,eAAe,KAAK;AACjE,WAAO;AAAA,EACT;AACA,SAAO,EAAE,WAAW,IAAI;AAC1B;AAEO,SAAS,SAAgC;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAgC;AAC9B,QAAM,WAAW,YAAY;AAC7B,QAAM,UAAU,YAAY,MAAM;AAElC,SAAO,QAAQ,IAAI,CAAC,OAAO,UAAU;AACnC,UAAM,MAAM,MAAM,MAAM,GAAG,MAAM,IAAI,IAAI,KAAK;AAC9C,UAAM,OAAO,YAAY,OAAO,UAAU,QAAQ;AAElD,WACE,oBAAC,YACE,sBAAY,UAAU,MAAM,OAAO,KAAK,IAAI,QADhC,GAEf;AAAA,EAEJ,CAAC;AACH;AAEA,SAAS,YACP,OACA,UACA,UACW;AACX,MAAI,CAAC,OAAO,OAAO,SAAS,QAAQ,MAAM,IAAI,GAAG;AAC/C,WACE,oBAAC,YAAS,QAAO,gBAAe,MAAM,MAAM,MAAM,OAAO,MAAM,OAAO;AAAA,EAE1E;AAEA,QAAM,EAAE,WAAW,WAAW,OAAO,IAAI;AAAA,IACvC,SAAS,OAAO,MAAM,IAAI;AAAA,EAC5B;AAEA,MAAI,QAAQ,MAAM;AAClB,MAAI,QAAQ;AACV,UAAM,SAAS,OAAO,WAAW,EAAE,SAAS,MAAM,KAAK;AAGvD,QAAI,kBAAkB,SAAS;AAC7B,aACE;AAAA,QAAC;AAAA;AAAA,UACC,QAAO;AAAA,UACP,MAAM,MAAM;AAAA,UACZ,OAAO,MAAM;AAAA,UACb,QAAQ;AAAA,YACN;AAAA,cACE,SACE;AAAA,YACJ;AAAA,UACF;AAAA;AAAA,MACF;AAAA,IAEJ;AACA,QAAI,OAAO,QAAQ;AACjB,aACE;AAAA,QAAC;AAAA;AAAA,UACC,QAAO;AAAA,UACP,MAAM,MAAM;AAAA,UACZ,OAAO,MAAM;AAAA,UACb,QAAQ,OAAO;AAAA;AAAA,MACjB;AAAA,IAEJ;AACA,YAAQ,OAAO;AAAA,EACjB;AAEA,SAAO,oBAAC,aAAW,GAAI,OAA8B;AACvD;","names":[]}
|