@createcms/core 0.1.1 → 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/dist/index.cjs +105 -0
- package/dist/index.d.cts +81 -3
- package/dist/index.d.ts +81 -3
- package/dist/index.js +105 -0
- package/dist/next/index.d.cts +62 -1
- package/dist/next/index.d.ts +62 -1
- package/dist/plugins/ab-test/index.cjs +4 -0
- package/dist/plugins/ab-test/index.d.cts +62 -1
- package/dist/plugins/ab-test/index.d.ts +62 -1
- package/dist/plugins/ab-test/index.js +4 -0
- package/dist/plugins/consent/index.d.cts +62 -1
- package/dist/plugins/consent/index.d.ts +62 -1
- package/dist/plugins/i18n/index.cjs +4 -0
- package/dist/plugins/i18n/index.d.cts +62 -1
- package/dist/plugins/i18n/index.d.ts +62 -1
- package/dist/plugins/i18n/index.js +4 -0
- package/dist/plugins/multi-tenant/index.d.cts +62 -1
- package/dist/plugins/multi-tenant/index.d.ts +62 -1
- package/dist/react/blocks.cjs +2 -1
- package/dist/react/blocks.d.cts +79 -9
- package/dist/react/blocks.d.ts +79 -9
- package/dist/react/blocks.js +2 -1
- package/dist/react/index.cjs +4 -0
- package/dist/react/index.d.cts +66 -1
- package/dist/react/index.d.ts +66 -1
- package/dist/react/index.js +4 -0
- package/dist/react/tracking.d.cts +62 -1
- package/dist/react/tracking.d.ts +62 -1
- package/package.json +1 -1
|
@@ -227,18 +227,70 @@ type BlockDefinition<TProps extends Record<string, BlockProperty> = Record<strin
|
|
|
227
227
|
label: string;
|
|
228
228
|
description?: string;
|
|
229
229
|
previewImageUrl?: string;
|
|
230
|
+
/**
|
|
231
|
+
* Editor hint: the block-picker category this block is shown under (e.g.
|
|
232
|
+
* `'Forms'`, `'Layout'`). Purely presentational — the editor groups blocks by
|
|
233
|
+
* this label; the package never acts on it. Free-form by design; for
|
|
234
|
+
* consistent, autocompleted group names across blocks, reference a shared
|
|
235
|
+
* `as const` object (e.g. `group: BLOCK_GROUPS.forms`).
|
|
236
|
+
*/
|
|
237
|
+
group?: string;
|
|
230
238
|
/** Events this (functional) block can emit — see {@link EventDeclaration}. */
|
|
231
239
|
events?: TEvents;
|
|
232
240
|
} & ({
|
|
233
241
|
allowChildren?: false;
|
|
234
242
|
} | {
|
|
235
243
|
allowChildren: true;
|
|
236
|
-
allowedChildBlocks?: string[];
|
|
237
244
|
});
|
|
238
245
|
type AnyBlockDefinition = BlockDefinition<Record<string, BlockProperty>, Record<string, EventDeclaration>>;
|
|
239
246
|
type RootDefinition<TProps extends Record<string, BlockProperty> = Record<string, BlockProperty>> = {
|
|
240
247
|
properties: TProps;
|
|
241
248
|
};
|
|
249
|
+
/**
|
|
250
|
+
* One PARENT's placement rule inside a collection's {@link CollectionStructure}
|
|
251
|
+
* — declares which child block types that parent (or the literal `'root'`) may
|
|
252
|
+
* contain. There are three mutually-exclusive modes, enforced by the type:
|
|
253
|
+
*
|
|
254
|
+
* - **open** — `{}` or `{ accepts: '*' }`: holds any block. (Same as having no
|
|
255
|
+
* entry at all; `'*'` is just an explicit, readable form.)
|
|
256
|
+
* - **whitelist** — `{ accepts: ['a', 'b'] }`: holds ONLY `a`/`b`. Fail-closed —
|
|
257
|
+
* a block added to the collection later is rejected until listed. `excludes`
|
|
258
|
+
* is forbidden here (a concrete `accepts` already says exactly what's allowed).
|
|
259
|
+
* - **blacklist** — `{ excludes: ['z'] }` (or `{ accepts: '*', excludes: ['z'] }`):
|
|
260
|
+
* holds anything EXCEPT `z`. Fail-open — a block added later is accepted.
|
|
261
|
+
*
|
|
262
|
+
* Whether a parent accepts children AT ALL is the separate, coarser
|
|
263
|
+
* `allowChildren` gate on the block (the root always accepts children); these
|
|
264
|
+
* rules only refine WHICH children an accepting parent may hold.
|
|
265
|
+
*/
|
|
266
|
+
type BlockStructureEntry<TBlockName extends string> = {
|
|
267
|
+
/** `'*'` = open base (optional, for readability). */
|
|
268
|
+
accepts?: '*';
|
|
269
|
+
/** Holds anything except these. */
|
|
270
|
+
excludes?: readonly TBlockName[];
|
|
271
|
+
} | {
|
|
272
|
+
/** Holds ONLY these block types. */
|
|
273
|
+
accepts: readonly TBlockName[];
|
|
274
|
+
/**
|
|
275
|
+
* Forbidden alongside a concrete `accepts` list — the list already names
|
|
276
|
+
* exactly what is allowed, so `excludes` would be ignored.
|
|
277
|
+
*/
|
|
278
|
+
excludes?: "Remove 'excludes': a concrete 'accepts' list already defines exactly which blocks are allowed. Use accepts: '*' with excludes for an all-except list.";
|
|
279
|
+
};
|
|
280
|
+
/**
|
|
281
|
+
* Placement rules for a collection, keyed by PARENT block name (or the literal
|
|
282
|
+
* `'root'` for the top level). Open by default: a parent with no entry holds any
|
|
283
|
+
* block. The keys and the `accepts` / `excludes` block names autocomplete against
|
|
284
|
+
* the collection's block names and are checked at compile time by
|
|
285
|
+
* {@link defineCollection} (the field type alone enforces this — no extra step).
|
|
286
|
+
*
|
|
287
|
+
* This is the single source of truth that the visual editor (drop-zone gating)
|
|
288
|
+
* and the server guard (createBlock / moveBlock / duplicateBlock) both read,
|
|
289
|
+
* alongside each block's `allowChildren` flag, so they can never diverge.
|
|
290
|
+
*/
|
|
291
|
+
type CollectionStructure<TBlocks extends Record<string, AnyBlockDefinition>> = {
|
|
292
|
+
[K in keyof TBlocks | 'root']?: BlockStructureEntry<keyof TBlocks & string>;
|
|
293
|
+
};
|
|
242
294
|
type SlugConfig = {
|
|
243
295
|
enabled: false;
|
|
244
296
|
} | {
|
|
@@ -262,6 +314,15 @@ type CollectionDefinition<TProps extends Record<string, BlockProperty> = Record<
|
|
|
262
314
|
* regardless of this flag). Any collection can still be a reference target.
|
|
263
315
|
*/
|
|
264
316
|
reusableBlock?: boolean;
|
|
317
|
+
/**
|
|
318
|
+
* Placement rules keyed by PARENT block name (or `'root'`) — which children
|
|
319
|
+
* each container may hold, via `accepts` (whitelist) / `excludes` (blacklist)
|
|
320
|
+
* (see {@link CollectionStructure}). Read by the editor and the server guard
|
|
321
|
+
* together with each block's `allowChildren` flag. Open by default; block
|
|
322
|
+
* names are checked at compile time by the field type itself, so a typo is a
|
|
323
|
+
* compile error at the `defineCollection` call site.
|
|
324
|
+
*/
|
|
325
|
+
structure?: CollectionStructure<TBlocks>;
|
|
265
326
|
};
|
|
266
327
|
type AnyCollectionDefinition = CollectionDefinition<Record<string, BlockProperty>, Record<string, AnyBlockDefinition>>;
|
|
267
328
|
type CollectionWithName = Omit<AnyCollectionDefinition, 'blocks'> & {
|
|
@@ -925,6 +925,10 @@ const CMS_ERRORS = {
|
|
|
925
925
|
status: 404,
|
|
926
926
|
message: 'Parent block not found'
|
|
927
927
|
},
|
|
928
|
+
BLOCK_NOT_ALLOWED_IN_PARENT: {
|
|
929
|
+
status: 400,
|
|
930
|
+
message: 'This block type is not allowed inside the target parent'
|
|
931
|
+
},
|
|
928
932
|
ROOT_NOT_FOUND: {
|
|
929
933
|
status: 404,
|
|
930
934
|
message: 'Root block not found in snapshot'
|
|
@@ -225,18 +225,70 @@ type BlockDefinition<TProps extends Record<string, BlockProperty> = Record<strin
|
|
|
225
225
|
label: string;
|
|
226
226
|
description?: string;
|
|
227
227
|
previewImageUrl?: string;
|
|
228
|
+
/**
|
|
229
|
+
* Editor hint: the block-picker category this block is shown under (e.g.
|
|
230
|
+
* `'Forms'`, `'Layout'`). Purely presentational — the editor groups blocks by
|
|
231
|
+
* this label; the package never acts on it. Free-form by design; for
|
|
232
|
+
* consistent, autocompleted group names across blocks, reference a shared
|
|
233
|
+
* `as const` object (e.g. `group: BLOCK_GROUPS.forms`).
|
|
234
|
+
*/
|
|
235
|
+
group?: string;
|
|
228
236
|
/** Events this (functional) block can emit — see {@link EventDeclaration}. */
|
|
229
237
|
events?: TEvents;
|
|
230
238
|
} & ({
|
|
231
239
|
allowChildren?: false;
|
|
232
240
|
} | {
|
|
233
241
|
allowChildren: true;
|
|
234
|
-
allowedChildBlocks?: string[];
|
|
235
242
|
});
|
|
236
243
|
type AnyBlockDefinition = BlockDefinition<Record<string, BlockProperty>, Record<string, EventDeclaration>>;
|
|
237
244
|
type RootDefinition<TProps extends Record<string, BlockProperty> = Record<string, BlockProperty>> = {
|
|
238
245
|
properties: TProps;
|
|
239
246
|
};
|
|
247
|
+
/**
|
|
248
|
+
* One PARENT's placement rule inside a collection's {@link CollectionStructure}
|
|
249
|
+
* — declares which child block types that parent (or the literal `'root'`) may
|
|
250
|
+
* contain. There are three mutually-exclusive modes, enforced by the type:
|
|
251
|
+
*
|
|
252
|
+
* - **open** — `{}` or `{ accepts: '*' }`: holds any block. (Same as having no
|
|
253
|
+
* entry at all; `'*'` is just an explicit, readable form.)
|
|
254
|
+
* - **whitelist** — `{ accepts: ['a', 'b'] }`: holds ONLY `a`/`b`. Fail-closed —
|
|
255
|
+
* a block added to the collection later is rejected until listed. `excludes`
|
|
256
|
+
* is forbidden here (a concrete `accepts` already says exactly what's allowed).
|
|
257
|
+
* - **blacklist** — `{ excludes: ['z'] }` (or `{ accepts: '*', excludes: ['z'] }`):
|
|
258
|
+
* holds anything EXCEPT `z`. Fail-open — a block added later is accepted.
|
|
259
|
+
*
|
|
260
|
+
* Whether a parent accepts children AT ALL is the separate, coarser
|
|
261
|
+
* `allowChildren` gate on the block (the root always accepts children); these
|
|
262
|
+
* rules only refine WHICH children an accepting parent may hold.
|
|
263
|
+
*/
|
|
264
|
+
type BlockStructureEntry<TBlockName extends string> = {
|
|
265
|
+
/** `'*'` = open base (optional, for readability). */
|
|
266
|
+
accepts?: '*';
|
|
267
|
+
/** Holds anything except these. */
|
|
268
|
+
excludes?: readonly TBlockName[];
|
|
269
|
+
} | {
|
|
270
|
+
/** Holds ONLY these block types. */
|
|
271
|
+
accepts: readonly TBlockName[];
|
|
272
|
+
/**
|
|
273
|
+
* Forbidden alongside a concrete `accepts` list — the list already names
|
|
274
|
+
* exactly what is allowed, so `excludes` would be ignored.
|
|
275
|
+
*/
|
|
276
|
+
excludes?: "Remove 'excludes': a concrete 'accepts' list already defines exactly which blocks are allowed. Use accepts: '*' with excludes for an all-except list.";
|
|
277
|
+
};
|
|
278
|
+
/**
|
|
279
|
+
* Placement rules for a collection, keyed by PARENT block name (or the literal
|
|
280
|
+
* `'root'` for the top level). Open by default: a parent with no entry holds any
|
|
281
|
+
* block. The keys and the `accepts` / `excludes` block names autocomplete against
|
|
282
|
+
* the collection's block names and are checked at compile time by
|
|
283
|
+
* {@link defineCollection} (the field type alone enforces this — no extra step).
|
|
284
|
+
*
|
|
285
|
+
* This is the single source of truth that the visual editor (drop-zone gating)
|
|
286
|
+
* and the server guard (createBlock / moveBlock / duplicateBlock) both read,
|
|
287
|
+
* alongside each block's `allowChildren` flag, so they can never diverge.
|
|
288
|
+
*/
|
|
289
|
+
type CollectionStructure<TBlocks extends Record<string, AnyBlockDefinition>> = {
|
|
290
|
+
[K in keyof TBlocks | 'root']?: BlockStructureEntry<keyof TBlocks & string>;
|
|
291
|
+
};
|
|
240
292
|
type SlugConfig = {
|
|
241
293
|
enabled: false;
|
|
242
294
|
} | {
|
|
@@ -260,6 +312,15 @@ type CollectionDefinition<TProps extends Record<string, BlockProperty> = Record<
|
|
|
260
312
|
* regardless of this flag). Any collection can still be a reference target.
|
|
261
313
|
*/
|
|
262
314
|
reusableBlock?: boolean;
|
|
315
|
+
/**
|
|
316
|
+
* Placement rules keyed by PARENT block name (or `'root'`) — which children
|
|
317
|
+
* each container may hold, via `accepts` (whitelist) / `excludes` (blacklist)
|
|
318
|
+
* (see {@link CollectionStructure}). Read by the editor and the server guard
|
|
319
|
+
* together with each block's `allowChildren` flag. Open by default; block
|
|
320
|
+
* names are checked at compile time by the field type itself, so a typo is a
|
|
321
|
+
* compile error at the `defineCollection` call site.
|
|
322
|
+
*/
|
|
323
|
+
structure?: CollectionStructure<TBlocks>;
|
|
263
324
|
};
|
|
264
325
|
type AnyCollectionDefinition = CollectionDefinition<Record<string, BlockProperty>, Record<string, AnyBlockDefinition>>;
|
|
265
326
|
type CollectionWithName = Omit<AnyCollectionDefinition, 'blocks'> & {
|
|
@@ -225,18 +225,70 @@ type BlockDefinition<TProps extends Record<string, BlockProperty> = Record<strin
|
|
|
225
225
|
label: string;
|
|
226
226
|
description?: string;
|
|
227
227
|
previewImageUrl?: string;
|
|
228
|
+
/**
|
|
229
|
+
* Editor hint: the block-picker category this block is shown under (e.g.
|
|
230
|
+
* `'Forms'`, `'Layout'`). Purely presentational — the editor groups blocks by
|
|
231
|
+
* this label; the package never acts on it. Free-form by design; for
|
|
232
|
+
* consistent, autocompleted group names across blocks, reference a shared
|
|
233
|
+
* `as const` object (e.g. `group: BLOCK_GROUPS.forms`).
|
|
234
|
+
*/
|
|
235
|
+
group?: string;
|
|
228
236
|
/** Events this (functional) block can emit — see {@link EventDeclaration}. */
|
|
229
237
|
events?: TEvents;
|
|
230
238
|
} & ({
|
|
231
239
|
allowChildren?: false;
|
|
232
240
|
} | {
|
|
233
241
|
allowChildren: true;
|
|
234
|
-
allowedChildBlocks?: string[];
|
|
235
242
|
});
|
|
236
243
|
type AnyBlockDefinition = BlockDefinition<Record<string, BlockProperty>, Record<string, EventDeclaration>>;
|
|
237
244
|
type RootDefinition<TProps extends Record<string, BlockProperty> = Record<string, BlockProperty>> = {
|
|
238
245
|
properties: TProps;
|
|
239
246
|
};
|
|
247
|
+
/**
|
|
248
|
+
* One PARENT's placement rule inside a collection's {@link CollectionStructure}
|
|
249
|
+
* — declares which child block types that parent (or the literal `'root'`) may
|
|
250
|
+
* contain. There are three mutually-exclusive modes, enforced by the type:
|
|
251
|
+
*
|
|
252
|
+
* - **open** — `{}` or `{ accepts: '*' }`: holds any block. (Same as having no
|
|
253
|
+
* entry at all; `'*'` is just an explicit, readable form.)
|
|
254
|
+
* - **whitelist** — `{ accepts: ['a', 'b'] }`: holds ONLY `a`/`b`. Fail-closed —
|
|
255
|
+
* a block added to the collection later is rejected until listed. `excludes`
|
|
256
|
+
* is forbidden here (a concrete `accepts` already says exactly what's allowed).
|
|
257
|
+
* - **blacklist** — `{ excludes: ['z'] }` (or `{ accepts: '*', excludes: ['z'] }`):
|
|
258
|
+
* holds anything EXCEPT `z`. Fail-open — a block added later is accepted.
|
|
259
|
+
*
|
|
260
|
+
* Whether a parent accepts children AT ALL is the separate, coarser
|
|
261
|
+
* `allowChildren` gate on the block (the root always accepts children); these
|
|
262
|
+
* rules only refine WHICH children an accepting parent may hold.
|
|
263
|
+
*/
|
|
264
|
+
type BlockStructureEntry<TBlockName extends string> = {
|
|
265
|
+
/** `'*'` = open base (optional, for readability). */
|
|
266
|
+
accepts?: '*';
|
|
267
|
+
/** Holds anything except these. */
|
|
268
|
+
excludes?: readonly TBlockName[];
|
|
269
|
+
} | {
|
|
270
|
+
/** Holds ONLY these block types. */
|
|
271
|
+
accepts: readonly TBlockName[];
|
|
272
|
+
/**
|
|
273
|
+
* Forbidden alongside a concrete `accepts` list — the list already names
|
|
274
|
+
* exactly what is allowed, so `excludes` would be ignored.
|
|
275
|
+
*/
|
|
276
|
+
excludes?: "Remove 'excludes': a concrete 'accepts' list already defines exactly which blocks are allowed. Use accepts: '*' with excludes for an all-except list.";
|
|
277
|
+
};
|
|
278
|
+
/**
|
|
279
|
+
* Placement rules for a collection, keyed by PARENT block name (or the literal
|
|
280
|
+
* `'root'` for the top level). Open by default: a parent with no entry holds any
|
|
281
|
+
* block. The keys and the `accepts` / `excludes` block names autocomplete against
|
|
282
|
+
* the collection's block names and are checked at compile time by
|
|
283
|
+
* {@link defineCollection} (the field type alone enforces this — no extra step).
|
|
284
|
+
*
|
|
285
|
+
* This is the single source of truth that the visual editor (drop-zone gating)
|
|
286
|
+
* and the server guard (createBlock / moveBlock / duplicateBlock) both read,
|
|
287
|
+
* alongside each block's `allowChildren` flag, so they can never diverge.
|
|
288
|
+
*/
|
|
289
|
+
type CollectionStructure<TBlocks extends Record<string, AnyBlockDefinition>> = {
|
|
290
|
+
[K in keyof TBlocks | 'root']?: BlockStructureEntry<keyof TBlocks & string>;
|
|
291
|
+
};
|
|
240
292
|
type SlugConfig = {
|
|
241
293
|
enabled: false;
|
|
242
294
|
} | {
|
|
@@ -260,6 +312,15 @@ type CollectionDefinition<TProps extends Record<string, BlockProperty> = Record<
|
|
|
260
312
|
* regardless of this flag). Any collection can still be a reference target.
|
|
261
313
|
*/
|
|
262
314
|
reusableBlock?: boolean;
|
|
315
|
+
/**
|
|
316
|
+
* Placement rules keyed by PARENT block name (or `'root'`) — which children
|
|
317
|
+
* each container may hold, via `accepts` (whitelist) / `excludes` (blacklist)
|
|
318
|
+
* (see {@link CollectionStructure}). Read by the editor and the server guard
|
|
319
|
+
* together with each block's `allowChildren` flag. Open by default; block
|
|
320
|
+
* names are checked at compile time by the field type itself, so a typo is a
|
|
321
|
+
* compile error at the `defineCollection` call site.
|
|
322
|
+
*/
|
|
323
|
+
structure?: CollectionStructure<TBlocks>;
|
|
263
324
|
};
|
|
264
325
|
type AnyCollectionDefinition = CollectionDefinition<Record<string, BlockProperty>, Record<string, AnyBlockDefinition>>;
|
|
265
326
|
type CollectionWithName = Omit<AnyCollectionDefinition, 'blocks'> & {
|
package/dist/react/blocks.cjs
CHANGED
|
@@ -52,7 +52,8 @@ function isResolvedReference(value) {
|
|
|
52
52
|
return {
|
|
53
53
|
__brand: 'BlocksMap',
|
|
54
54
|
_components: components,
|
|
55
|
-
_events: extractBlockEvents(collection.blocks)
|
|
55
|
+
_events: extractBlockEvents(collection.blocks),
|
|
56
|
+
_collection: collection
|
|
56
57
|
};
|
|
57
58
|
}
|
|
58
59
|
// ============================================================================
|
package/dist/react/blocks.d.cts
CHANGED
|
@@ -133,18 +133,70 @@ type BlockDefinition<TProps extends Record<string, BlockProperty> = Record<strin
|
|
|
133
133
|
label: string;
|
|
134
134
|
description?: string;
|
|
135
135
|
previewImageUrl?: string;
|
|
136
|
+
/**
|
|
137
|
+
* Editor hint: the block-picker category this block is shown under (e.g.
|
|
138
|
+
* `'Forms'`, `'Layout'`). Purely presentational — the editor groups blocks by
|
|
139
|
+
* this label; the package never acts on it. Free-form by design; for
|
|
140
|
+
* consistent, autocompleted group names across blocks, reference a shared
|
|
141
|
+
* `as const` object (e.g. `group: BLOCK_GROUPS.forms`).
|
|
142
|
+
*/
|
|
143
|
+
group?: string;
|
|
136
144
|
/** Events this (functional) block can emit — see {@link EventDeclaration}. */
|
|
137
145
|
events?: TEvents;
|
|
138
146
|
} & ({
|
|
139
147
|
allowChildren?: false;
|
|
140
148
|
} | {
|
|
141
149
|
allowChildren: true;
|
|
142
|
-
allowedChildBlocks?: string[];
|
|
143
150
|
});
|
|
144
151
|
type AnyBlockDefinition = BlockDefinition<Record<string, BlockProperty>, Record<string, EventDeclaration>>;
|
|
145
152
|
type RootDefinition<TProps extends Record<string, BlockProperty> = Record<string, BlockProperty>> = {
|
|
146
153
|
properties: TProps;
|
|
147
154
|
};
|
|
155
|
+
/**
|
|
156
|
+
* One PARENT's placement rule inside a collection's {@link CollectionStructure}
|
|
157
|
+
* — declares which child block types that parent (or the literal `'root'`) may
|
|
158
|
+
* contain. There are three mutually-exclusive modes, enforced by the type:
|
|
159
|
+
*
|
|
160
|
+
* - **open** — `{}` or `{ accepts: '*' }`: holds any block. (Same as having no
|
|
161
|
+
* entry at all; `'*'` is just an explicit, readable form.)
|
|
162
|
+
* - **whitelist** — `{ accepts: ['a', 'b'] }`: holds ONLY `a`/`b`. Fail-closed —
|
|
163
|
+
* a block added to the collection later is rejected until listed. `excludes`
|
|
164
|
+
* is forbidden here (a concrete `accepts` already says exactly what's allowed).
|
|
165
|
+
* - **blacklist** — `{ excludes: ['z'] }` (or `{ accepts: '*', excludes: ['z'] }`):
|
|
166
|
+
* holds anything EXCEPT `z`. Fail-open — a block added later is accepted.
|
|
167
|
+
*
|
|
168
|
+
* Whether a parent accepts children AT ALL is the separate, coarser
|
|
169
|
+
* `allowChildren` gate on the block (the root always accepts children); these
|
|
170
|
+
* rules only refine WHICH children an accepting parent may hold.
|
|
171
|
+
*/
|
|
172
|
+
type BlockStructureEntry<TBlockName extends string> = {
|
|
173
|
+
/** `'*'` = open base (optional, for readability). */
|
|
174
|
+
accepts?: '*';
|
|
175
|
+
/** Holds anything except these. */
|
|
176
|
+
excludes?: readonly TBlockName[];
|
|
177
|
+
} | {
|
|
178
|
+
/** Holds ONLY these block types. */
|
|
179
|
+
accepts: readonly TBlockName[];
|
|
180
|
+
/**
|
|
181
|
+
* Forbidden alongside a concrete `accepts` list — the list already names
|
|
182
|
+
* exactly what is allowed, so `excludes` would be ignored.
|
|
183
|
+
*/
|
|
184
|
+
excludes?: "Remove 'excludes': a concrete 'accepts' list already defines exactly which blocks are allowed. Use accepts: '*' with excludes for an all-except list.";
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* Placement rules for a collection, keyed by PARENT block name (or the literal
|
|
188
|
+
* `'root'` for the top level). Open by default: a parent with no entry holds any
|
|
189
|
+
* block. The keys and the `accepts` / `excludes` block names autocomplete against
|
|
190
|
+
* the collection's block names and are checked at compile time by
|
|
191
|
+
* {@link defineCollection} (the field type alone enforces this — no extra step).
|
|
192
|
+
*
|
|
193
|
+
* This is the single source of truth that the visual editor (drop-zone gating)
|
|
194
|
+
* and the server guard (createBlock / moveBlock / duplicateBlock) both read,
|
|
195
|
+
* alongside each block's `allowChildren` flag, so they can never diverge.
|
|
196
|
+
*/
|
|
197
|
+
type CollectionStructure<TBlocks extends Record<string, AnyBlockDefinition>> = {
|
|
198
|
+
[K in keyof TBlocks | 'root']?: BlockStructureEntry<keyof TBlocks & string>;
|
|
199
|
+
};
|
|
148
200
|
type SlugConfig = {
|
|
149
201
|
enabled: false;
|
|
150
202
|
} | {
|
|
@@ -168,6 +220,15 @@ type CollectionDefinition<TProps extends Record<string, BlockProperty> = Record<
|
|
|
168
220
|
* regardless of this flag). Any collection can still be a reference target.
|
|
169
221
|
*/
|
|
170
222
|
reusableBlock?: boolean;
|
|
223
|
+
/**
|
|
224
|
+
* Placement rules keyed by PARENT block name (or `'root'`) — which children
|
|
225
|
+
* each container may hold, via `accepts` (whitelist) / `excludes` (blacklist)
|
|
226
|
+
* (see {@link CollectionStructure}). Read by the editor and the server guard
|
|
227
|
+
* together with each block's `allowChildren` flag. Open by default; block
|
|
228
|
+
* names are checked at compile time by the field type itself, so a typo is a
|
|
229
|
+
* compile error at the `defineCollection` call site.
|
|
230
|
+
*/
|
|
231
|
+
structure?: CollectionStructure<TBlocks>;
|
|
171
232
|
};
|
|
172
233
|
type AnyCollectionDefinition = CollectionDefinition<Record<string, BlockProperty>, Record<string, AnyBlockDefinition>>;
|
|
173
234
|
|
|
@@ -180,24 +241,33 @@ type BlockComponentProps<TProps extends Record<string, BlockProperty> = Record<s
|
|
|
180
241
|
blockId: string;
|
|
181
242
|
node: BlockTreeNode;
|
|
182
243
|
};
|
|
183
|
-
/** Shorthand to derive block component props from a collection definition.
|
|
244
|
+
/** Shorthand to derive block component props from a collection definition.
|
|
245
|
+
* `blocks` is optional on `CollectionDefinition`, so the constraint accepts the
|
|
246
|
+
* optional shape and `NonNullable` resolves it — passing `typeof myCollection`
|
|
247
|
+
* directly works, and `TBlock` autocompletes the collection's block names. */
|
|
184
248
|
type BlockProps<TCollection extends {
|
|
185
|
-
blocks
|
|
186
|
-
}, TBlock extends keyof TCollection['blocks'] & string> = BlockComponentProps<TCollection['blocks'][TBlock]['properties']>;
|
|
249
|
+
blocks?: Record<string, AnyBlockDefinition>;
|
|
250
|
+
}, TBlock extends keyof NonNullable<TCollection['blocks']> & string> = BlockComponentProps<NonNullable<TCollection['blocks']>[TBlock]['properties']>;
|
|
187
251
|
type BlockComponentMap<TBlocks extends Record<string, AnyBlockDefinition>> = {
|
|
188
252
|
[K in keyof TBlocks & string]: (props: BlockComponentProps<TBlocks[K]['properties']>) => ReactNode;
|
|
189
253
|
};
|
|
190
254
|
declare function isResolvedReference(value: unknown): value is ResolvedReference;
|
|
191
255
|
/**
|
|
192
256
|
* Opaque handle returned by `createBlocksMap`. Pass it to `<BlocksRenderer>`.
|
|
193
|
-
* Carries the React component map
|
|
194
|
-
*
|
|
195
|
-
* functional block
|
|
257
|
+
* Carries the React component map, the per-block-type event declarations (the
|
|
258
|
+
* runtime half of the M2a typed-events seam, so the renderer can tell a
|
|
259
|
+
* functional block from a presentational one), AND the collection definition
|
|
260
|
+
* itself. Bundling the collection means an editor can consume a single object
|
|
261
|
+
* for both rendering (`_components`) and schema/placement/grouping
|
|
262
|
+
* (`_collection`) — no separate `collection` handoff. The type parameter is
|
|
263
|
+
* preserved so that consumption stays typed; it defaults to the erased
|
|
264
|
+
* `AnyCollectionDefinition` for plain `BlocksMap` annotations.
|
|
196
265
|
*/
|
|
197
|
-
type BlocksMap = {
|
|
266
|
+
type BlocksMap<TCollection = AnyCollectionDefinition> = {
|
|
198
267
|
readonly __brand: 'BlocksMap';
|
|
199
268
|
readonly _components: Record<string, (props: any) => ReactNode>;
|
|
200
269
|
readonly _events: Record<string, Record<string, EventDeclaration>>;
|
|
270
|
+
readonly _collection: TCollection;
|
|
201
271
|
};
|
|
202
272
|
/**
|
|
203
273
|
* Extracts the per-block-type event declarations from a collection definition —
|
|
@@ -229,7 +299,7 @@ declare function extractBlockEvents(blocks: Record<string, AnyBlockDefinition> |
|
|
|
229
299
|
* });
|
|
230
300
|
* ```
|
|
231
301
|
*/
|
|
232
|
-
declare function createBlocksMap<TProps extends Record<string, BlockProperty>, TBlocks extends Record<string, AnyBlockDefinition>>(collection: CollectionDefinition<TProps, TBlocks>, components: BlockComponentMap<TBlocks>): BlocksMap
|
|
302
|
+
declare function createBlocksMap<TProps extends Record<string, BlockProperty>, TBlocks extends Record<string, AnyBlockDefinition>>(collection: CollectionDefinition<TProps, TBlocks>, components: BlockComponentMap<TBlocks>): BlocksMap<CollectionDefinition<TProps, TBlocks>>;
|
|
233
303
|
/**
|
|
234
304
|
* Renders a `BlockTreeNode` tree using a block component map.
|
|
235
305
|
*
|
package/dist/react/blocks.d.ts
CHANGED
|
@@ -133,18 +133,70 @@ type BlockDefinition<TProps extends Record<string, BlockProperty> = Record<strin
|
|
|
133
133
|
label: string;
|
|
134
134
|
description?: string;
|
|
135
135
|
previewImageUrl?: string;
|
|
136
|
+
/**
|
|
137
|
+
* Editor hint: the block-picker category this block is shown under (e.g.
|
|
138
|
+
* `'Forms'`, `'Layout'`). Purely presentational — the editor groups blocks by
|
|
139
|
+
* this label; the package never acts on it. Free-form by design; for
|
|
140
|
+
* consistent, autocompleted group names across blocks, reference a shared
|
|
141
|
+
* `as const` object (e.g. `group: BLOCK_GROUPS.forms`).
|
|
142
|
+
*/
|
|
143
|
+
group?: string;
|
|
136
144
|
/** Events this (functional) block can emit — see {@link EventDeclaration}. */
|
|
137
145
|
events?: TEvents;
|
|
138
146
|
} & ({
|
|
139
147
|
allowChildren?: false;
|
|
140
148
|
} | {
|
|
141
149
|
allowChildren: true;
|
|
142
|
-
allowedChildBlocks?: string[];
|
|
143
150
|
});
|
|
144
151
|
type AnyBlockDefinition = BlockDefinition<Record<string, BlockProperty>, Record<string, EventDeclaration>>;
|
|
145
152
|
type RootDefinition<TProps extends Record<string, BlockProperty> = Record<string, BlockProperty>> = {
|
|
146
153
|
properties: TProps;
|
|
147
154
|
};
|
|
155
|
+
/**
|
|
156
|
+
* One PARENT's placement rule inside a collection's {@link CollectionStructure}
|
|
157
|
+
* — declares which child block types that parent (or the literal `'root'`) may
|
|
158
|
+
* contain. There are three mutually-exclusive modes, enforced by the type:
|
|
159
|
+
*
|
|
160
|
+
* - **open** — `{}` or `{ accepts: '*' }`: holds any block. (Same as having no
|
|
161
|
+
* entry at all; `'*'` is just an explicit, readable form.)
|
|
162
|
+
* - **whitelist** — `{ accepts: ['a', 'b'] }`: holds ONLY `a`/`b`. Fail-closed —
|
|
163
|
+
* a block added to the collection later is rejected until listed. `excludes`
|
|
164
|
+
* is forbidden here (a concrete `accepts` already says exactly what's allowed).
|
|
165
|
+
* - **blacklist** — `{ excludes: ['z'] }` (or `{ accepts: '*', excludes: ['z'] }`):
|
|
166
|
+
* holds anything EXCEPT `z`. Fail-open — a block added later is accepted.
|
|
167
|
+
*
|
|
168
|
+
* Whether a parent accepts children AT ALL is the separate, coarser
|
|
169
|
+
* `allowChildren` gate on the block (the root always accepts children); these
|
|
170
|
+
* rules only refine WHICH children an accepting parent may hold.
|
|
171
|
+
*/
|
|
172
|
+
type BlockStructureEntry<TBlockName extends string> = {
|
|
173
|
+
/** `'*'` = open base (optional, for readability). */
|
|
174
|
+
accepts?: '*';
|
|
175
|
+
/** Holds anything except these. */
|
|
176
|
+
excludes?: readonly TBlockName[];
|
|
177
|
+
} | {
|
|
178
|
+
/** Holds ONLY these block types. */
|
|
179
|
+
accepts: readonly TBlockName[];
|
|
180
|
+
/**
|
|
181
|
+
* Forbidden alongside a concrete `accepts` list — the list already names
|
|
182
|
+
* exactly what is allowed, so `excludes` would be ignored.
|
|
183
|
+
*/
|
|
184
|
+
excludes?: "Remove 'excludes': a concrete 'accepts' list already defines exactly which blocks are allowed. Use accepts: '*' with excludes for an all-except list.";
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* Placement rules for a collection, keyed by PARENT block name (or the literal
|
|
188
|
+
* `'root'` for the top level). Open by default: a parent with no entry holds any
|
|
189
|
+
* block. The keys and the `accepts` / `excludes` block names autocomplete against
|
|
190
|
+
* the collection's block names and are checked at compile time by
|
|
191
|
+
* {@link defineCollection} (the field type alone enforces this — no extra step).
|
|
192
|
+
*
|
|
193
|
+
* This is the single source of truth that the visual editor (drop-zone gating)
|
|
194
|
+
* and the server guard (createBlock / moveBlock / duplicateBlock) both read,
|
|
195
|
+
* alongside each block's `allowChildren` flag, so they can never diverge.
|
|
196
|
+
*/
|
|
197
|
+
type CollectionStructure<TBlocks extends Record<string, AnyBlockDefinition>> = {
|
|
198
|
+
[K in keyof TBlocks | 'root']?: BlockStructureEntry<keyof TBlocks & string>;
|
|
199
|
+
};
|
|
148
200
|
type SlugConfig = {
|
|
149
201
|
enabled: false;
|
|
150
202
|
} | {
|
|
@@ -168,6 +220,15 @@ type CollectionDefinition<TProps extends Record<string, BlockProperty> = Record<
|
|
|
168
220
|
* regardless of this flag). Any collection can still be a reference target.
|
|
169
221
|
*/
|
|
170
222
|
reusableBlock?: boolean;
|
|
223
|
+
/**
|
|
224
|
+
* Placement rules keyed by PARENT block name (or `'root'`) — which children
|
|
225
|
+
* each container may hold, via `accepts` (whitelist) / `excludes` (blacklist)
|
|
226
|
+
* (see {@link CollectionStructure}). Read by the editor and the server guard
|
|
227
|
+
* together with each block's `allowChildren` flag. Open by default; block
|
|
228
|
+
* names are checked at compile time by the field type itself, so a typo is a
|
|
229
|
+
* compile error at the `defineCollection` call site.
|
|
230
|
+
*/
|
|
231
|
+
structure?: CollectionStructure<TBlocks>;
|
|
171
232
|
};
|
|
172
233
|
type AnyCollectionDefinition = CollectionDefinition<Record<string, BlockProperty>, Record<string, AnyBlockDefinition>>;
|
|
173
234
|
|
|
@@ -180,24 +241,33 @@ type BlockComponentProps<TProps extends Record<string, BlockProperty> = Record<s
|
|
|
180
241
|
blockId: string;
|
|
181
242
|
node: BlockTreeNode;
|
|
182
243
|
};
|
|
183
|
-
/** Shorthand to derive block component props from a collection definition.
|
|
244
|
+
/** Shorthand to derive block component props from a collection definition.
|
|
245
|
+
* `blocks` is optional on `CollectionDefinition`, so the constraint accepts the
|
|
246
|
+
* optional shape and `NonNullable` resolves it — passing `typeof myCollection`
|
|
247
|
+
* directly works, and `TBlock` autocompletes the collection's block names. */
|
|
184
248
|
type BlockProps<TCollection extends {
|
|
185
|
-
blocks
|
|
186
|
-
}, TBlock extends keyof TCollection['blocks'] & string> = BlockComponentProps<TCollection['blocks'][TBlock]['properties']>;
|
|
249
|
+
blocks?: Record<string, AnyBlockDefinition>;
|
|
250
|
+
}, TBlock extends keyof NonNullable<TCollection['blocks']> & string> = BlockComponentProps<NonNullable<TCollection['blocks']>[TBlock]['properties']>;
|
|
187
251
|
type BlockComponentMap<TBlocks extends Record<string, AnyBlockDefinition>> = {
|
|
188
252
|
[K in keyof TBlocks & string]: (props: BlockComponentProps<TBlocks[K]['properties']>) => ReactNode;
|
|
189
253
|
};
|
|
190
254
|
declare function isResolvedReference(value: unknown): value is ResolvedReference;
|
|
191
255
|
/**
|
|
192
256
|
* Opaque handle returned by `createBlocksMap`. Pass it to `<BlocksRenderer>`.
|
|
193
|
-
* Carries the React component map
|
|
194
|
-
*
|
|
195
|
-
* functional block
|
|
257
|
+
* Carries the React component map, the per-block-type event declarations (the
|
|
258
|
+
* runtime half of the M2a typed-events seam, so the renderer can tell a
|
|
259
|
+
* functional block from a presentational one), AND the collection definition
|
|
260
|
+
* itself. Bundling the collection means an editor can consume a single object
|
|
261
|
+
* for both rendering (`_components`) and schema/placement/grouping
|
|
262
|
+
* (`_collection`) — no separate `collection` handoff. The type parameter is
|
|
263
|
+
* preserved so that consumption stays typed; it defaults to the erased
|
|
264
|
+
* `AnyCollectionDefinition` for plain `BlocksMap` annotations.
|
|
196
265
|
*/
|
|
197
|
-
type BlocksMap = {
|
|
266
|
+
type BlocksMap<TCollection = AnyCollectionDefinition> = {
|
|
198
267
|
readonly __brand: 'BlocksMap';
|
|
199
268
|
readonly _components: Record<string, (props: any) => ReactNode>;
|
|
200
269
|
readonly _events: Record<string, Record<string, EventDeclaration>>;
|
|
270
|
+
readonly _collection: TCollection;
|
|
201
271
|
};
|
|
202
272
|
/**
|
|
203
273
|
* Extracts the per-block-type event declarations from a collection definition —
|
|
@@ -229,7 +299,7 @@ declare function extractBlockEvents(blocks: Record<string, AnyBlockDefinition> |
|
|
|
229
299
|
* });
|
|
230
300
|
* ```
|
|
231
301
|
*/
|
|
232
|
-
declare function createBlocksMap<TProps extends Record<string, BlockProperty>, TBlocks extends Record<string, AnyBlockDefinition>>(collection: CollectionDefinition<TProps, TBlocks>, components: BlockComponentMap<TBlocks>): BlocksMap
|
|
302
|
+
declare function createBlocksMap<TProps extends Record<string, BlockProperty>, TBlocks extends Record<string, AnyBlockDefinition>>(collection: CollectionDefinition<TProps, TBlocks>, components: BlockComponentMap<TBlocks>): BlocksMap<CollectionDefinition<TProps, TBlocks>>;
|
|
233
303
|
/**
|
|
234
304
|
* Renders a `BlockTreeNode` tree using a block component map.
|
|
235
305
|
*
|
package/dist/react/blocks.js
CHANGED
|
@@ -50,7 +50,8 @@ function isResolvedReference(value) {
|
|
|
50
50
|
return {
|
|
51
51
|
__brand: 'BlocksMap',
|
|
52
52
|
_components: components,
|
|
53
|
-
_events: extractBlockEvents(collection.blocks)
|
|
53
|
+
_events: extractBlockEvents(collection.blocks),
|
|
54
|
+
_collection: collection
|
|
54
55
|
};
|
|
55
56
|
}
|
|
56
57
|
// ============================================================================
|
package/dist/react/index.cjs
CHANGED
|
@@ -150,6 +150,10 @@ const CMS_ERRORS = {
|
|
|
150
150
|
status: 404,
|
|
151
151
|
message: 'Parent block not found'
|
|
152
152
|
},
|
|
153
|
+
BLOCK_NOT_ALLOWED_IN_PARENT: {
|
|
154
|
+
status: 400,
|
|
155
|
+
message: 'This block type is not allowed inside the target parent'
|
|
156
|
+
},
|
|
153
157
|
ROOT_NOT_FOUND: {
|
|
154
158
|
status: 404,
|
|
155
159
|
message: 'Root block not found in snapshot'
|