@input/pen-core 0.1.1 → 0.1.2

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 CHANGED
@@ -141,6 +141,8 @@ __export(index_exports, {
141
141
  interpolateMessage: () => interpolateMessage,
142
142
  isBlockSelected: () => isBlockSelected,
143
143
  isCollapsed: () => isCollapsed,
144
+ isContainerBlock: () => isContainerBlock,
145
+ isContainerBlockType: () => isContainerBlockType,
144
146
  isContinuousTextFlowCapability: () => isContinuousTextFlowCapability,
145
147
  isMultiBlock: () => isMultiBlock,
146
148
  isPseudoLocaleText: () => isPseudoLocaleText,
@@ -200,6 +202,7 @@ __export(index_exports, {
200
202
  shouldAllowFlowInsertionInSlashMenu: () => shouldAllowFlowInsertionInSlashMenu,
201
203
  shouldExposeBlockInTooling: () => shouldExposeBlockInTooling,
202
204
  shouldForceBlockScopedSelectAll: () => shouldForceBlockScopedSelectAll,
205
+ shouldRenderContainerChildren: () => shouldRenderContainerChildren,
203
206
  shouldShowBlockInDefaultMenus: () => shouldShowBlockInDefaultMenus,
204
207
  singleController: () => singleController,
205
208
  slashMenuGroupOf: () => slashMenuGroupOf,
@@ -2185,7 +2188,7 @@ function schemaDeclaresBlockCapability(schema, capability) {
2185
2188
  }
2186
2189
 
2187
2190
  // src/editor/editor.ts
2188
- var import_pen_types10 = require("@input/pen-types");
2191
+ var import_pen_types11 = require("@input/pen-types");
2189
2192
  var import_pen_yjs8 = require("@input/pen-yjs");
2190
2193
 
2191
2194
  // src/editor/events.ts
@@ -2930,6 +2933,7 @@ function opBlockId(_pipeline, op) {
2930
2933
  var import_pen_yjs = require("@input/pen-yjs");
2931
2934
 
2932
2935
  // src/schema/contentType.ts
2936
+ var import_pen_types2 = require("@input/pen-types");
2933
2937
  function resolveRuntimeContentType(schema) {
2934
2938
  if (!schema) {
2935
2939
  return "none";
@@ -2939,6 +2943,10 @@ function resolveRuntimeContentType(schema) {
2939
2943
  }
2940
2944
  return schema.content;
2941
2945
  }
2946
+ function isContainerBlock(schema) {
2947
+ if (!schema) return false;
2948
+ return (0, import_pen_types2.isNestedContent)(schema.content) || schema.isContainer === true;
2949
+ }
2942
2950
 
2943
2951
  // src/editor/rejectedOwnKeys.ts
2944
2952
  var REJECTED_OWN_PROP_KEYS = /* @__PURE__ */ new Set([
@@ -3813,6 +3821,15 @@ function executeOps(pipeline, ops, origin, structural) {
3813
3821
  const blockId = opBlockId(pipeline, op);
3814
3822
  if (!validateOp(pipeline, op)) continue;
3815
3823
  if (op.type === "insert-block") {
3824
+ if (blockExists(pipeline, op.blockId) || pendingBlockIds.has(op.blockId)) {
3825
+ emitPipelineDiagnostic(pipeline, {
3826
+ code: "PEN_APPLY_010",
3827
+ level: "warn",
3828
+ source: "apply",
3829
+ message: `apply: skipping insert-block for already-present block "${op.blockId}"`
3830
+ });
3831
+ continue;
3832
+ }
3816
3833
  pendingBlockIds.add(op.blockId);
3817
3834
  pendingBlockTypes.set(op.blockId, op.blockType);
3818
3835
  }
@@ -6278,9 +6295,11 @@ var SelectionAuthorityImpl = class {
6278
6295
  };
6279
6296
 
6280
6297
  // src/editor/documentState.ts
6298
+ var EMPTY_CHILD_IDS = Object.freeze([]);
6281
6299
  var DocumentStateImpl = class {
6282
6300
  _positionIndex;
6283
6301
  _parentIndex;
6302
+ _childIndex;
6284
6303
  _blockOrder;
6285
6304
  _generation = 0;
6286
6305
  _documentProfile;
@@ -6294,6 +6313,7 @@ var DocumentStateImpl = class {
6294
6313
  this._documentProfile = documentProfile;
6295
6314
  this._positionIndex = /* @__PURE__ */ new Map();
6296
6315
  this._parentIndex = /* @__PURE__ */ new Map();
6316
+ this._childIndex = /* @__PURE__ */ new Map();
6297
6317
  this._blockOrder = [];
6298
6318
  this.rebuild();
6299
6319
  }
@@ -6332,6 +6352,9 @@ var DocumentStateImpl = class {
6332
6352
  parentOf(blockId) {
6333
6353
  return this._parentIndex.get(blockId) ?? null;
6334
6354
  }
6355
+ childrenOf(blockId) {
6356
+ return this._childIndex.get(blockId) ?? EMPTY_CHILD_IDS;
6357
+ }
6335
6358
  *allBlocks() {
6336
6359
  const seen = /* @__PURE__ */ new Set();
6337
6360
  for (const id of this._blockOrder) {
@@ -6351,21 +6374,44 @@ var DocumentStateImpl = class {
6351
6374
  this._blockOrder = [];
6352
6375
  this._positionIndex = /* @__PURE__ */ new Map();
6353
6376
  this._parentIndex = /* @__PURE__ */ new Map();
6377
+ this._childIndex = /* @__PURE__ */ new Map();
6354
6378
  for (let i = 0; i < order.length; i++) {
6355
6379
  const id = order.get(i);
6356
6380
  this._blockOrder.push(id);
6357
6381
  this._positionIndex.set(id, i);
6358
6382
  }
6383
+ const nestedChildIds = /* @__PURE__ */ new Set();
6384
+ const parentIdChildIds = [];
6359
6385
  for (const [blockId, blockMap] of this._doc.blocks.entries()) {
6360
6386
  const props = blockMap.get("props");
6361
6387
  if (props?.get?.("parentId")) {
6362
6388
  this._parentIndex.set(blockId, props.get("parentId"));
6389
+ parentIdChildIds.push(blockId);
6363
6390
  }
6364
6391
  const children = blockMap.get("children");
6365
- if (children) {
6392
+ if (children && children.length > 0) {
6393
+ const childIds = [];
6366
6394
  for (let i = 0; i < children.length; i++) {
6367
- this._parentIndex.set(children.get(i), blockId);
6395
+ const childId = children.get(i);
6396
+ this._parentIndex.set(childId, blockId);
6397
+ nestedChildIds.add(childId);
6398
+ childIds.push(childId);
6368
6399
  }
6400
+ this._childIndex.set(blockId, childIds);
6401
+ }
6402
+ }
6403
+ parentIdChildIds.sort(
6404
+ (a, b) => (this._positionIndex.get(a) ?? -1) - (this._positionIndex.get(b) ?? -1)
6405
+ );
6406
+ for (const childId of parentIdChildIds) {
6407
+ if (nestedChildIds.has(childId)) continue;
6408
+ const parentId = this._parentIndex.get(childId);
6409
+ if (parentId === void 0) continue;
6410
+ const siblings = this._childIndex.get(parentId);
6411
+ if (siblings === void 0) {
6412
+ this._childIndex.set(parentId, [childId]);
6413
+ } else {
6414
+ siblings.push(childId);
6369
6415
  }
6370
6416
  }
6371
6417
  this._generation++;
@@ -6373,6 +6419,7 @@ var DocumentStateImpl = class {
6373
6419
  clear() {
6374
6420
  this._positionIndex.clear();
6375
6421
  this._parentIndex.clear();
6422
+ this._childIndex.clear();
6376
6423
  this._blockOrder = [];
6377
6424
  this._generation++;
6378
6425
  }
@@ -7596,7 +7643,7 @@ function sameIdList(left, right) {
7596
7643
  }
7597
7644
 
7598
7645
  // src/facets/i18nFacets.ts
7599
- var import_pen_types2 = require("@input/pen-types");
7646
+ var import_pen_types3 = require("@input/pen-types");
7600
7647
  function resolveEnvironmentLocale() {
7601
7648
  if (typeof navigator === "object" && navigator !== null) {
7602
7649
  const language = navigator.language;
@@ -7614,7 +7661,7 @@ var messagesFacet = defineFacet({
7614
7661
  name: "pen.messages",
7615
7662
  combine: (inputs) => {
7616
7663
  const catalog = {
7617
- ...import_pen_types2.DEFAULT_MESSAGE_CATALOG
7664
+ ...import_pen_types3.DEFAULT_MESSAGE_CATALOG
7618
7665
  };
7619
7666
  for (let index = inputs.length - 1; index >= 0; index -= 1) {
7620
7667
  Object.assign(catalog, inputs[index]);
@@ -7636,11 +7683,18 @@ var BACKSPACE_EXIT_TYPES = /* @__PURE__ */ new Set([
7636
7683
  ...CONTAINER_EXIT_TYPES,
7637
7684
  ...HEADING_TYPES
7638
7685
  ]);
7639
- var PARENT_ID_CONTAINER_TYPES = /* @__PURE__ */ new Set([
7640
- "toggle",
7641
- "callout",
7642
- "blockquote"
7643
- ]);
7686
+ function isContainerBlockType(editor, blockType) {
7687
+ if (!blockType) {
7688
+ return false;
7689
+ }
7690
+ return isContainerBlock(editor.schema.resolve(blockType));
7691
+ }
7692
+ function shouldRenderContainerChildren(editor, block) {
7693
+ if (!block || !isContainerBlockType(editor, block.type)) {
7694
+ return false;
7695
+ }
7696
+ return block.props?.open !== false;
7697
+ }
7644
7698
  function emitCommandDiagnostic(editor, event) {
7645
7699
  editor.internals?.emit("diagnostic", event);
7646
7700
  }
@@ -7692,18 +7746,13 @@ function isInsideParentIdContainer(editor, blockId) {
7692
7746
  return false;
7693
7747
  }
7694
7748
  const parent = editor.getBlock(parentId);
7695
- return !!parent && PARENT_ID_CONTAINER_TYPES.has(parent.type);
7749
+ return !!parent && isContainerBlockType(editor, parent.type);
7696
7750
  }
7697
7751
  function getRootBlockIds(editor) {
7698
7752
  return editor.documentState.blockOrder.filter(
7699
7753
  (blockId) => editor.documentState.parentOf(blockId) == null
7700
7754
  );
7701
7755
  }
7702
- function getParentIdChildBlockIds(editor, parentBlockId) {
7703
- return editor.documentState.blockOrder.filter(
7704
- (blockId) => editor.documentState.parentOf(blockId) === parentBlockId
7705
- );
7706
- }
7707
7756
  function getVisibleBlockIds(editor) {
7708
7757
  const visibleBlockIds = [];
7709
7758
  for (const rootBlockId of getRootBlockIds(editor)) {
@@ -7825,23 +7874,13 @@ function convertBlockOps(editor, options) {
7825
7874
  }
7826
7875
  function collectVisibleBlockIds(editor, blockId, visibleBlockIds) {
7827
7876
  visibleBlockIds.push(blockId);
7828
- if (!shouldShowParentIdChildren(editor, blockId)) {
7877
+ if (!shouldRenderContainerChildren(editor, editor.getBlock(blockId))) {
7829
7878
  return;
7830
7879
  }
7831
- for (const childBlockId of getParentIdChildBlockIds(editor, blockId)) {
7880
+ for (const childBlockId of editor.documentState.childrenOf(blockId)) {
7832
7881
  collectVisibleBlockIds(editor, childBlockId, visibleBlockIds);
7833
7882
  }
7834
7883
  }
7835
- function shouldShowParentIdChildren(editor, blockId) {
7836
- const block = editor.getBlock(blockId);
7837
- if (!block || !PARENT_ID_CONTAINER_TYPES.has(block.type)) {
7838
- return false;
7839
- }
7840
- if (block.type !== "toggle") {
7841
- return true;
7842
- }
7843
- return Boolean(block.props?.open);
7844
- }
7845
7884
 
7846
7885
  // src/commands/commandSelection.ts
7847
7886
  function textSelectionResult(anchor, focus = anchor, extras) {
@@ -8017,12 +8056,12 @@ function parentContainerKind(editor, parentId) {
8017
8056
  if (!parent) {
8018
8057
  return null;
8019
8058
  }
8020
- if (PARENT_ID_CONTAINER_TYPES.has(parent.type)) {
8021
- return "layout-cell";
8022
- }
8023
8059
  if (parent.type === "table") {
8024
8060
  return "table";
8025
8061
  }
8062
+ if (isContainerBlockType(editor, parent.type)) {
8063
+ return "layout-cell";
8064
+ }
8026
8065
  return null;
8027
8066
  }
8028
8067
 
@@ -9235,7 +9274,7 @@ function isUndoManager(value) {
9235
9274
  }
9236
9275
 
9237
9276
  // src/commands/structure.ts
9238
- var import_pen_types3 = require("@input/pen-types");
9277
+ var import_pen_types4 = require("@input/pen-types");
9239
9278
  var moveBlockUp = defineCommand("pen.moveBlockUp");
9240
9279
  var moveBlockDown = defineCommand("pen.moveBlockDown");
9241
9280
  var duplicateBlock = defineCommand("pen.duplicateBlock");
@@ -9286,7 +9325,7 @@ function handleDuplicateBlock(editor, param) {
9286
9325
  if (!block) {
9287
9326
  return false;
9288
9327
  }
9289
- const newBlockId = (0, import_pen_types3.generateId)();
9328
+ const newBlockId = (0, import_pen_types4.generateId)();
9290
9329
  const ops = [
9291
9330
  {
9292
9331
  type: "insert-block",
@@ -9319,7 +9358,7 @@ function handleDeleteBlock(editor, param) {
9319
9358
  (blockId) => !blockIds.includes(blockId)
9320
9359
  );
9321
9360
  if (remaining.length === 0) {
9322
- const replacementId = (0, import_pen_types3.generateId)();
9361
+ const replacementId = (0, import_pen_types4.generateId)();
9323
9362
  editor.apply(
9324
9363
  [
9325
9364
  {
@@ -9893,7 +9932,7 @@ function deleteSelectedBlocks(editor, blockIds) {
9893
9932
  }
9894
9933
 
9895
9934
  // src/commands/textEnter.ts
9896
- var import_pen_types4 = require("@input/pen-types");
9935
+ var import_pen_types5 = require("@input/pen-types");
9897
9936
 
9898
9937
  // src/commands/textInsert.ts
9899
9938
  function handleInsertText(editor, param) {
@@ -10080,7 +10119,7 @@ function handleSplitBlock(editor) {
10080
10119
  if (!block) {
10081
10120
  return false;
10082
10121
  }
10083
- const newBlockId = (0, import_pen_types4.generateId)();
10122
+ const newBlockId = (0, import_pen_types5.generateId)();
10084
10123
  const recipe = buildSplitBlockRecipe({
10085
10124
  block,
10086
10125
  offset: focus.offset,
@@ -10511,12 +10550,12 @@ function getCommandRegistry(editor) {
10511
10550
  }
10512
10551
 
10513
10552
  // src/facets/a11yFacets.ts
10514
- var import_pen_types5 = require("@input/pen-types");
10553
+ var import_pen_types6 = require("@input/pen-types");
10515
10554
  function isUsableA11yLabel(value) {
10516
10555
  if (typeof value === "string") {
10517
10556
  return value.trim().length > 0;
10518
10557
  }
10519
- if (value == null || !(0, import_pen_types5.isA11yLabelledBy)(value)) {
10558
+ if (value == null || !(0, import_pen_types6.isA11yLabelledBy)(value)) {
10520
10559
  return false;
10521
10560
  }
10522
10561
  return value.labelledBy.trim().length > 0;
@@ -10854,7 +10893,7 @@ function sortExtensions(extensions) {
10854
10893
  }
10855
10894
 
10856
10895
  // src/editor/editorApiHelpers.ts
10857
- var import_pen_types6 = require("@input/pen-types");
10896
+ var import_pen_types7 = require("@input/pen-types");
10858
10897
  var import_pen_yjs4 = require("@input/pen-yjs");
10859
10898
 
10860
10899
  // src/changes/blockIndex.ts
@@ -10964,19 +11003,19 @@ function toStringMap(value) {
10964
11003
 
10965
11004
  // src/editor/editorApiHelpers.ts
10966
11005
  var FACET_BY_SLOT_KEY = {
10967
- [import_pen_types6.FIELD_EDITOR_SLOT_KEY]: fieldEditorHostFacet,
10968
- [import_pen_types6.INPUT_RULES_ENGINE_SLOT_KEY]: inputRulesEngineFacet,
10969
- [import_pen_types6.UNDO_HISTORY_RESTORE_SLOT_KEY]: undoRestoreControllerFacet,
10970
- [import_pen_types6.UNDO_HISTORY_METADATA_CONTROLLER_SLOT_KEY]: undoMetadataControllerFacet,
10971
- [import_pen_types6.INLINE_COMPLETION_SLOT]: aiInlineCompletionFacet,
10972
- [import_pen_types6.AI_CONTROLLER_SLOT]: aiControllerFacet,
10973
- [import_pen_types6.AI_INLINE_HISTORY_SLOT]: aiInlineHistoryFacet,
10974
- [import_pen_types6.AI_REVIEW_CONTROLLER_SLOT]: aiReviewControllerFacet,
10975
- [import_pen_types6.AI_AUTOCOMPLETE_CONTROLLER_SLOT]: aiAutocompleteControllerFacet,
10976
- [import_pen_types6.AI_SUGGESTIONS_CONTROLLER_SLOT]: aiSuggestionsControllerFacet,
10977
- [import_pen_types6.SEARCH_CONTROLLER_SLOT]: searchControllerFacet,
10978
- [import_pen_types6.MULTIPLAYER_CONTROLLER_SLOT]: multiplayerControllerFacet,
10979
- [import_pen_types6.SNAPSHOTS_CONTROLLER_SLOT]: snapshotsControllerFacet,
11006
+ [import_pen_types7.FIELD_EDITOR_SLOT_KEY]: fieldEditorHostFacet,
11007
+ [import_pen_types7.INPUT_RULES_ENGINE_SLOT_KEY]: inputRulesEngineFacet,
11008
+ [import_pen_types7.UNDO_HISTORY_RESTORE_SLOT_KEY]: undoRestoreControllerFacet,
11009
+ [import_pen_types7.UNDO_HISTORY_METADATA_CONTROLLER_SLOT_KEY]: undoMetadataControllerFacet,
11010
+ [import_pen_types7.INLINE_COMPLETION_SLOT]: aiInlineCompletionFacet,
11011
+ [import_pen_types7.AI_CONTROLLER_SLOT]: aiControllerFacet,
11012
+ [import_pen_types7.AI_INLINE_HISTORY_SLOT]: aiInlineHistoryFacet,
11013
+ [import_pen_types7.AI_REVIEW_CONTROLLER_SLOT]: aiReviewControllerFacet,
11014
+ [import_pen_types7.AI_AUTOCOMPLETE_CONTROLLER_SLOT]: aiAutocompleteControllerFacet,
11015
+ [import_pen_types7.AI_SUGGESTIONS_CONTROLLER_SLOT]: aiSuggestionsControllerFacet,
11016
+ [import_pen_types7.SEARCH_CONTROLLER_SLOT]: searchControllerFacet,
11017
+ [import_pen_types7.MULTIPLAYER_CONTROLLER_SLOT]: multiplayerControllerFacet,
11018
+ [import_pen_types7.SNAPSHOTS_CONTROLLER_SLOT]: snapshotsControllerFacet,
10980
11019
  "paste:importers": clipboardFacet,
10981
11020
  "paste:assetProvider": assetProviderFacet,
10982
11021
  "undo:manager": undoManagerFacet,
@@ -10985,7 +11024,7 @@ var FACET_BY_SLOT_KEY = {
10985
11024
  "pen.messages": messagesFacet,
10986
11025
  "pen.a11yLabel": a11yLabelFacet,
10987
11026
  "delta-stream:target": streamingTargetFacet,
10988
- [import_pen_types6.ANNOUNCER_SLOT_KEY]: announcerFacet
11027
+ [import_pen_types7.ANNOUNCER_SLOT_KEY]: announcerFacet
10989
11028
  };
10990
11029
  function writeAssignedSlot(self, key, value) {
10991
11030
  self._slots.set(key, value);
@@ -11057,10 +11096,10 @@ function recordMutationGroupMetadata(editor, origin, groupId) {
11057
11096
  return;
11058
11097
  }
11059
11098
  const controller = self._slots.get(
11060
- import_pen_types6.UNDO_HISTORY_METADATA_CONTROLLER_SLOT_KEY
11099
+ import_pen_types7.UNDO_HISTORY_METADATA_CONTROLLER_SLOT_KEY
11061
11100
  );
11062
11101
  controller?.setCurrentEntryMetadata(
11063
- import_pen_types6.MUTATION_GROUP_METADATA_KEY,
11102
+ import_pen_types7.MUTATION_GROUP_METADATA_KEY,
11064
11103
  {
11065
11104
  before: null,
11066
11105
  after: createMutationGroupMetadata(origin, groupId)
@@ -11505,7 +11544,7 @@ function openEditorTextStream(editor, target, options, host) {
11505
11544
  }
11506
11545
 
11507
11546
  // src/editor/editorLifecycle.ts
11508
- var import_pen_types8 = require("@input/pen-types");
11547
+ var import_pen_types9 = require("@input/pen-types");
11509
11548
 
11510
11549
  // src/changes/install.ts
11511
11550
  var import_pen_yjs5 = require("@input/pen-yjs");
@@ -11982,11 +12021,11 @@ function flushDeferredCRDTEvent(host) {
11982
12021
  var import_pen_yjs7 = require("@input/pen-yjs");
11983
12022
 
11984
12023
  // src/migrations/runMigrations.ts
11985
- var import_pen_types7 = require("@input/pen-types");
12024
+ var import_pen_types8 = require("@input/pen-types");
11986
12025
  var MIGRATION_ORIGIN = "migration";
11987
12026
  function readLedger(editor) {
11988
12027
  const value = editor.internals.doc.metadata.get(
11989
- import_pen_types7.MIGRATION_LEDGER_METADATA_KEY
12028
+ import_pen_types8.MIGRATION_LEDGER_METADATA_KEY
11990
12029
  );
11991
12030
  if (!Array.isArray(value)) {
11992
12031
  return [];
@@ -11995,7 +12034,7 @@ function readLedger(editor) {
11995
12034
  }
11996
12035
  function writeLedger(editor, ids) {
11997
12036
  const metadata = editor.internals.doc.metadata;
11998
- metadata.set(import_pen_types7.MIGRATION_LEDGER_METADATA_KEY, [...ids]);
12037
+ metadata.set(import_pen_types8.MIGRATION_LEDGER_METADATA_KEY, [...ids]);
11999
12038
  }
12000
12039
  function bindMigrationApply(editor) {
12001
12040
  const previousApply = editor.apply.bind(editor);
@@ -12356,7 +12395,7 @@ function ensureInitialParagraph(editor) {
12356
12395
  [
12357
12396
  {
12358
12397
  type: "insert-block",
12359
- blockId: (0, import_pen_types8.generateId)(),
12398
+ blockId: (0, import_pen_types9.generateId)(),
12360
12399
  blockType: "paragraph",
12361
12400
  props: {},
12362
12401
  position: "last"
@@ -12484,7 +12523,7 @@ function stampSummaryCommitId(summary, commitId) {
12484
12523
  }
12485
12524
 
12486
12525
  // src/editor/editorSelectionMutations.ts
12487
- var import_pen_types9 = require("@input/pen-types");
12526
+ var import_pen_types10 = require("@input/pen-types");
12488
12527
  function replaceEditorSelection(editor, content) {
12489
12528
  const self = editor;
12490
12529
  const sel = self._selection.getSelection();
@@ -12543,7 +12582,7 @@ function replaceEditorSelection(editor, content) {
12543
12582
  )
12544
12583
  };
12545
12584
  if (typeof content === "string") {
12546
- const newId = (0, import_pen_types9.generateId)();
12585
+ const newId = (0, import_pen_types10.generateId)();
12547
12586
  ops.push({
12548
12587
  type: "insert-block",
12549
12588
  blockId: newId,
@@ -12563,7 +12602,7 @@ function replaceEditorSelection(editor, content) {
12563
12602
  } else if (Array.isArray(content)) {
12564
12603
  let prevPosition = insertPosition;
12565
12604
  for (const block of content) {
12566
- const newId = (0, import_pen_types9.generateId)();
12605
+ const newId = (0, import_pen_types10.generateId)();
12567
12606
  ops.push({
12568
12607
  type: "insert-block",
12569
12608
  blockId: newId,
@@ -12919,7 +12958,7 @@ var EditorImpl = class {
12919
12958
  _unsubSummary = null;
12920
12959
  _blockRevisions = /* @__PURE__ */ new Map();
12921
12960
  _decorations;
12922
- _viewId = (0, import_pen_types10.generateId)();
12961
+ _viewId = (0, import_pen_types11.generateId)();
12923
12962
  _extensionLifecycle = Promise.resolve();
12924
12963
  _facetRegistry;
12925
12964
  _slotDeprecationWarned = /* @__PURE__ */ new Set();
@@ -13390,7 +13429,7 @@ function createHeadlessEditor(options = {}) {
13390
13429
  }
13391
13430
 
13392
13431
  // src/editor/inlineCompletion.ts
13393
- var import_pen_types11 = require("@input/pen-types");
13432
+ var import_pen_types12 = require("@input/pen-types");
13394
13433
  var inlineCompletionLeases = /* @__PURE__ */ new WeakMap();
13395
13434
  var InlineCompletionControllerImpl = class {
13396
13435
  constructor(_editor) {
@@ -13455,7 +13494,7 @@ var InlineCompletionControllerImpl = class {
13455
13494
  this._emit();
13456
13495
  return true;
13457
13496
  }
13458
- const blockId = (0, import_pen_types11.generateId)();
13497
+ const blockId = (0, import_pen_types12.generateId)();
13459
13498
  this._editor.apply(
13460
13499
  [
13461
13500
  {
@@ -13495,7 +13534,7 @@ var InlineCompletionControllerImpl = class {
13495
13534
  type: "block",
13496
13535
  blockId: suggestion2.blockId,
13497
13536
  attributes: {
13498
- [import_pen_types11.INLINE_COMPLETION_VISIBLE_BLOCK_ATTRIBUTE]: true
13537
+ [import_pen_types12.INLINE_COMPLETION_VISIBLE_BLOCK_ATTRIBUTE]: true
13499
13538
  }
13500
13539
  };
13501
13540
  if (suggestion2.type !== "inline") {
@@ -13566,7 +13605,7 @@ function ensureInlineCompletionController(editor) {
13566
13605
  };
13567
13606
  }
13568
13607
  const controller = new InlineCompletionControllerImpl(editor);
13569
- editor.internals.assignSlot(import_pen_types11.INLINE_COMPLETION_SLOT, controller);
13608
+ editor.internals.assignSlot(import_pen_types12.INLINE_COMPLETION_SLOT, controller);
13570
13609
  inlineCompletionLeases.set(editor, {
13571
13610
  controller,
13572
13611
  refCount: 1
@@ -13594,7 +13633,7 @@ function createInlineCompletionRelease(editor, controller) {
13594
13633
  }
13595
13634
  inlineCompletionLeases.delete(editor);
13596
13635
  if (getInlineCompletionController(editor) === controller) {
13597
- editor.internals.assignSlot(import_pen_types11.INLINE_COMPLETION_SLOT, null);
13636
+ editor.internals.assignSlot(import_pen_types12.INLINE_COMPLETION_SLOT, null);
13598
13637
  }
13599
13638
  controller.destroy();
13600
13639
  };
@@ -13727,13 +13766,13 @@ function renderSelectionTargetBlockText(editor, target, options) {
13727
13766
  }
13728
13767
 
13729
13768
  // src/importerUtils.ts
13730
- var import_pen_types12 = require("@input/pen-types");
13769
+ var import_pen_types13 = require("@input/pen-types");
13731
13770
  function blocksToOps(blocks, options) {
13732
13771
  const ops = [];
13733
13772
  let position = options?.position ?? "last";
13734
13773
  for (const block of blocks) {
13735
13774
  if (block.type.startsWith("__table")) continue;
13736
- const blockId = (0, import_pen_types12.generateId)();
13775
+ const blockId = (0, import_pen_types13.generateId)();
13737
13776
  ops.push({
13738
13777
  type: "insert-block",
13739
13778
  blockId,
@@ -13973,7 +14012,7 @@ var urlPolicyFacet = defineFacet({
13973
14012
  });
13974
14013
 
13975
14014
  // src/facets/aiEgressFacet.ts
13976
- var import_pen_types13 = require("@input/pen-types");
14015
+ var import_pen_types14 = require("@input/pen-types");
13977
14016
  var aiEgressFacet = defineFacet({
13978
14017
  name: "pen.aiEgress",
13979
14018
  combine: (inputs) => {
@@ -14032,7 +14071,7 @@ function emitInventory(editor, context) {
14032
14071
  return;
14033
14072
  }
14034
14073
  editor.internals.emit("diagnostic", {
14035
- code: import_pen_types13.AI_EGRESS_INVENTORY_CODE,
14074
+ code: import_pen_types14.AI_EGRESS_INVENTORY_CODE,
14036
14075
  level: "info",
14037
14076
  source: "ai",
14038
14077
  message: "AI request excerpt inventory",
@@ -14045,7 +14084,7 @@ function emitInventory(editor, context) {
14045
14084
  }
14046
14085
  function emitRefused(editor, context) {
14047
14086
  editor.internals.emit("diagnostic", {
14048
- code: import_pen_types13.AI_REQUEST_REFUSED_CODE,
14087
+ code: import_pen_types14.AI_REQUEST_REFUSED_CODE,
14049
14088
  level: "info",
14050
14089
  source: "ai",
14051
14090
  message: "AI request refused by pen.aiEgress",
@@ -14566,7 +14605,7 @@ var defaultKeymapBindings = {
14566
14605
  };
14567
14606
 
14568
14607
  // src/i18n/messages.ts
14569
- var import_pen_types14 = require("@input/pen-types");
14608
+ var import_pen_types15 = require("@input/pen-types");
14570
14609
  function interpolateMessage(template, params) {
14571
14610
  if (!params) {
14572
14611
  return template;
@@ -14583,21 +14622,21 @@ function interpolateMessage(template, params) {
14583
14622
  );
14584
14623
  }
14585
14624
  function resolveMessage(catalog, key, ...args) {
14586
- const raw = catalog[key] ?? import_pen_types14.DEFAULT_MESSAGE_CATALOG[key];
14625
+ const raw = catalog[key] ?? import_pen_types15.DEFAULT_MESSAGE_CATALOG[key];
14587
14626
  if (raw == null) {
14588
14627
  return "";
14589
14628
  }
14590
- if ((0, import_pen_types14.isPluralMessage)(raw)) {
14629
+ if ((0, import_pen_types15.isPluralMessage)(raw)) {
14591
14630
  return interpolateMessage(raw.other, args[0]);
14592
14631
  }
14593
14632
  return interpolateMessage(raw, args[0]);
14594
14633
  }
14595
14634
 
14596
14635
  // src/editor/toolExecution.ts
14597
- var import_pen_types15 = require("@input/pen-types");
14636
+ var import_pen_types16 = require("@input/pen-types");
14598
14637
  async function collectToolExecutionOutput(result, onPart) {
14599
14638
  const resolved = await result;
14600
- if (!(0, import_pen_types15.isAsyncIterable)(resolved)) {
14639
+ if (!(0, import_pen_types16.isAsyncIterable)(resolved)) {
14601
14640
  return resolved;
14602
14641
  }
14603
14642
  const parts = [];
@@ -14609,7 +14648,7 @@ async function collectToolExecutionOutput(result, onPart) {
14609
14648
  }
14610
14649
 
14611
14650
  // src/i18n/resolveEditorMessage.ts
14612
- var import_pen_types16 = require("@input/pen-types");
14651
+ var import_pen_types17 = require("@input/pen-types");
14613
14652
 
14614
14653
  // src/i18n/formatters.ts
14615
14654
  function formatterKey(locale, options) {
@@ -14668,7 +14707,7 @@ function resolveEditorMessage(editor, key, ...args) {
14668
14707
  return interpolateMessage(selectTemplate(value, locale, params), params);
14669
14708
  }
14670
14709
  function selectTemplate(value, locale, params) {
14671
- if (!(0, import_pen_types16.isPluralMessage)(value)) {
14710
+ if (!(0, import_pen_types17.isPluralMessage)(value)) {
14672
14711
  return value;
14673
14712
  }
14674
14713
  const count = params?.count;
@@ -14696,7 +14735,7 @@ function emitMissingOnce(editor, key) {
14696
14735
  }
14697
14736
 
14698
14737
  // src/a11y/resolveEditorA11yLabel.ts
14699
- var import_pen_types17 = require("@input/pen-types");
14738
+ var import_pen_types18 = require("@input/pen-types");
14700
14739
  var A11Y_MISSING_LABEL_CODE = "a11y-missing-label";
14701
14740
  var missingLabelWarned = /* @__PURE__ */ new WeakSet();
14702
14741
  function resolveEditorA11yLabel(editor) {
@@ -14704,7 +14743,7 @@ function resolveEditorA11yLabel(editor) {
14704
14743
  if (typeof value === "string") {
14705
14744
  return { "aria-label": value };
14706
14745
  }
14707
- if (value != null && (0, import_pen_types17.isA11yLabelledBy)(value)) {
14746
+ if (value != null && (0, import_pen_types18.isA11yLabelledBy)(value)) {
14708
14747
  return { "aria-labelledby": value.labelledBy };
14709
14748
  }
14710
14749
  warnMissingA11yLabel(editor);
@@ -14730,7 +14769,7 @@ function warnMissingA11yLabel(editor) {
14730
14769
  }
14731
14770
 
14732
14771
  // src/a11y/announceEditorA11y.ts
14733
- var import_pen_types18 = require("@input/pen-types");
14772
+ var import_pen_types19 = require("@input/pen-types");
14734
14773
  function announceEditorA11y(editor, key, ...args) {
14735
14774
  const announcer = editor.facet(announcerFacet) ?? null;
14736
14775
  if (!announcer) {
@@ -14749,7 +14788,7 @@ function announceEditorA11y(editor, key, ...args) {
14749
14788
  }
14750
14789
  function resolveA11yBlockTypeLabel(editor, type) {
14751
14790
  const key = `pen.schema.${type}.title`;
14752
- if ((0, import_pen_types18.isMessageKey)(key)) {
14791
+ if ((0, import_pen_types19.isMessageKey)(key)) {
14753
14792
  const label = resolveEditorMessage(editor, key);
14754
14793
  if (label.length > 0) {
14755
14794
  return label;
@@ -14802,7 +14841,7 @@ function warnMissingSchemaA11y(editor, type) {
14802
14841
  }
14803
14842
 
14804
14843
  // src/i18n/pseudoLocale.ts
14805
- var import_pen_types19 = require("@input/pen-types");
14844
+ var import_pen_types20 = require("@input/pen-types");
14806
14845
  var PSEUDO_LOCALE_OPEN = "[[";
14807
14846
  var PSEUDO_LOCALE_CLOSE = " \xB7\xB7\xB7]]";
14808
14847
  function toPseudoLocaleText(text) {
@@ -14812,7 +14851,7 @@ function toPseudoLocaleText(text) {
14812
14851
  return `${PSEUDO_LOCALE_OPEN}${text}${PSEUDO_LOCALE_CLOSE}`;
14813
14852
  }
14814
14853
  function toPseudoLocaleValue(value) {
14815
- if (!(0, import_pen_types19.isPluralMessage)(value)) {
14854
+ if (!(0, import_pen_types20.isPluralMessage)(value)) {
14816
14855
  return toPseudoLocaleText(value);
14817
14856
  }
14818
14857
  const next = {
@@ -14825,7 +14864,7 @@ function toPseudoLocaleValue(value) {
14825
14864
  }
14826
14865
  return next;
14827
14866
  }
14828
- function createPseudoLocaleCatalog(catalog = import_pen_types19.DEFAULT_MESSAGE_CATALOG) {
14867
+ function createPseudoLocaleCatalog(catalog = import_pen_types20.DEFAULT_MESSAGE_CATALOG) {
14829
14868
  const next = {};
14830
14869
  for (const key of Object.keys(catalog)) {
14831
14870
  next[key] = toPseudoLocaleValue(catalog[key]);
@@ -15007,6 +15046,8 @@ function mapOffsetThroughSplices(splices, offset, assoc) {
15007
15046
  interpolateMessage,
15008
15047
  isBlockSelected,
15009
15048
  isCollapsed,
15049
+ isContainerBlock,
15050
+ isContainerBlockType,
15010
15051
  isContinuousTextFlowCapability,
15011
15052
  isMultiBlock,
15012
15053
  isPseudoLocaleText,
@@ -15066,6 +15107,7 @@ function mapOffsetThroughSplices(splices, offset, assoc) {
15066
15107
  shouldAllowFlowInsertionInSlashMenu,
15067
15108
  shouldExposeBlockInTooling,
15068
15109
  shouldForceBlockScopedSelectAll,
15110
+ shouldRenderContainerChildren,
15069
15111
  shouldShowBlockInDefaultMenus,
15070
15112
  singleController,
15071
15113
  slashMenuGroupOf,
package/dist/index.d.cts CHANGED
@@ -504,6 +504,19 @@ interface NormalPositionSnapshot {
504
504
  */
505
505
  declare function snapToNormalPosition(doc: NormalPositionSnapshot, point: Point, direction: NormalPositionDirection): NextNormalPositionResult;
506
506
 
507
+ /**
508
+ * Whether a block type holds child blocks, resolved from its schema rather than
509
+ * from a hardcoded type list — host-defined containers count too.
510
+ */
511
+ declare function isContainerBlockType(editor: Editor, blockType: string | null | undefined): boolean;
512
+ /**
513
+ * Whether a container's children participate in rendering and navigation.
514
+ *
515
+ * Collapsing is expressed by the block's own `open` prop, so any container that
516
+ * declares one is collapsible. `toggle` defaults `open` to `false` and so stays
517
+ * collapsed until opened; containers without the prop always show children.
518
+ */
519
+ declare function shouldRenderContainerChildren(editor: Editor, block: BlockHandle | null | undefined): boolean;
507
520
  /**
508
521
  * Ops that change one block's type in place, keeping its id and its text.
509
522
  *
@@ -910,6 +923,15 @@ declare const outdent: _input_pen_types.Command<void>;
910
923
  declare const toggleMark: _input_pen_types.Command<ToggleMarkParam>;
911
924
  declare const convertBlock: _input_pen_types.Command<ConvertBlockParam>;
912
925
 
926
+ /**
927
+ * Whether a block type holds child blocks, by either route: a nested-content
928
+ * schema, or the `parentId` convention that `isContainer` marks.
929
+ *
930
+ * This is the single authority for the question. Callers must not test block
931
+ * type names — a hardcoded set silently excludes every host-defined container.
932
+ */
933
+ declare function isContainerBlock(schema: BlockSchema | null | undefined): boolean;
934
+
913
935
  interface StructureBlockParam {
914
936
  readonly blockId?: string;
915
937
  }
@@ -1021,4 +1043,4 @@ declare function affectedBlockIdsFromSummary(summary: Pick<ChangeSummary, "block
1021
1043
  */
1022
1044
  declare function mapOffsetThroughSplices(splices: readonly TextSplice[], offset: number, assoc: Assoc): number;
1023
1045
 
1024
- export { A11Y_MISSING_LABEL_CODE, APPLY_STORM_CODE, APPLY_STORM_QUEUE_LIMIT, type BeforeApplyHook, type BlockDirection, type BlockDirectionResolver, type BlockDirectionSetting, type CaretMotionParam, type CellCaretFocus, type CellCaretWrite, type ClipboardHandler, type CommandDispatchContext, type CommandHandlerTable, type CommandRegistry, type ContentMove, type ConvertBlockParam, type CreateCommandRegistryOptions, type CreateFacetRegistryOptions, type CreateHeadlessEditorOptions, type DecorationSource, type DefaultKeymapBinding, type DefaultKeymapContext, type DefinedBlockSchema, type DeleteGranularity, type DeleteParam, type DocumentMigration, DocumentRangeImpl, type EditorA11yLabelAttrs, EventEmitter, ExtensionManagerImpl, type FacetRegistry, type FacetSettleInput, HOOK_PRIORITIES, type InsertTextParam, type Keymap, type KeymapPlatform, type MigrationReport, type NormalPositionSnapshot, PIPELINE_PHASES, PSEUDO_LOCALE_CLOSE, PSEUDO_LOCALE_OPEN, type PendingBlock, type PendingBlockImportPolicyViolation, type PendingBlockProfilePolicyViolation, type ProfilePolicyViolation, type SchemaA11yAttrs, type SchemaA11yKind, SchemaEngineImpl, type SchemaRegistryConfig, SchemaRegistryImpl, type SelectBlockParam, SelectionAuthorityImpl as SelectionAuthority, type StructureBlockParam, type ToggleMarkParam, type UrlContext, type UrlPolicy, type VerticalCaretDirection, type VerticalCaretMeasure, type VerticalCaretMeasureResult, type VerticalCaretPoint, type WordRange, a11yLabelFacet, affectedBlockIdsFromSummary, aiAutocompleteControllerFacet, aiControllerFacet, aiEgressExtension, aiEgressFacet, aiInlineCompletionFacet, aiInlineHistoryFacet, aiReviewControllerFacet, aiSuggestionsControllerFacet, announceEditorA11y, announcerFacet, applyDirectedBinding, applyMergeBlocks, applySplitBlock, ariaReadOnlyFacet, assetProviderFacet, beforeApplyFacet, blockDirectionFacet, blockLogicalText, blocksToOps, buildMergeBlocksRecipe, buildNormalPositionSnapshot, buildSplitBlockRecipe, buildTableChildren, builtinCommandHandlers, caretBlockEnd, caretBlockStart, caretDocEnd, caretDocStart, caretDown, caretLeft, caretLineEnd, caretLineStart, caretRight, caretUp, caretWordLeft, caretWordRight, clipboardFacet, collectEditorKeyBindings, collectToolExecutionOutput, commandHandler, commandsFacet, convertBlock, convertBlockOps, createAppHandle, createBlockHandle, createCommandRegistry, createDecorationSet, createDocumentSession, createEditor, createEmptySchema, createFacetRegistry, createHeadlessEditor, createImportResult, createMutationGroupMetadata, createPseudoLocaleCatalog, createTextSelection, decorationsFacet, deepEqual, defaultDirectionFacet, defaultKeymapBindings, defineBlock, defineCommand, defineExtension, defineFacet, delegatesToGridEditing, deleteAdjacentInlineAtom, deleteBackward, deleteBlock, deleteForward, deriveContentMoves, duplicateBlock, emptyDecorationSet, ensureInlineCompletionController, fieldEditorHostFacet, filterAIRequest, filterOpsForDocumentProfile, filterPendingBlocksForDocumentProfile, foldAndNormalize, getApplyOptionsGroupId, getBlockSelectionRoleFromSchema, getBlockSelectionRoleFromType, getCellCaretFocus, getCommandRegistry, getEditorSelectionRecord, getFlowCapabilityFromSchema, getFlowCapabilityFromType, getInlineCompletionController, getNumberedListItemValue, getOpOriginGroupId, getOpOriginType, getSelectionBlockRange, getVerticalCaretGoalX, getVerticalCaretMeasure, hasFieldEditorSurface, hasIndexedCellSelectionMetadata, historyRedo, historyUndo, hookPriorityToPrecedence, indent, inputRulesEngineFacet, inputRulesFacet, insertLineBreak, insertText, interpolateMessage, isBlockSelected, isCollapsed, isContinuousTextFlowCapability, isMultiBlock, isPseudoLocaleText, keyBindingPriorityToPrecedence, keymapFacet, localeFacet, mapOffsetThroughSplices, mergeDecorationSets, mergeSchemas, messagesFacet, moveBlockDown, moveBlockUp, multiplayerControllerFacet, nextGraphemeBoundary, nextWordBoundary, normalizePendingBlocksForImport, orderSlashMenuItemsByGroup, outdent, previousGraphemeBoundary, previousWordBoundary, priorityToPrecedence, prop, renderSelectionTargetBlockText, renderSelectionTargetText, repairAnchor, reportPendingBlockImportViolations, reportPendingBlockProfileViolations, resolveA11yBlockTypeLabel, resolveA11ySpec, resolveBlockDirection, resolveBlockFlowCapability, resolveCellSelectionCoord, resolveCellSelectionMatrix, resolveDefaultKeymap, resolveDirectedBinding, resolveDirectedCommand, resolveEditorA11yLabel, resolveEditorMessage, resolveEditorSchema, resolveFieldEditorBehavior, resolveFieldEditorInputMode, resolveFocusBlockDirection, resolveMessage, resolveSchema, resolveSchemaA11y, resolveSelectionTargetBlockIds, runMigrations, searchControllerFacet, selectAdjacentInlineAtom, selectAll, selectBlock, selectionToRange, setCellCaretFocus, setVerticalCaretGoalX, setVerticalCaretMeasure, shouldAllowDirectBlockPaste, shouldAllowFlowInsertionInSlashMenu, shouldExposeBlockInTooling, shouldForceBlockScopedSelectAll, shouldShowBlockInDefaultMenus, singleController, slashMenuGroupOf, snapToNormalPosition, snapshotsControllerFacet, sortDeltaAttributes, spliceDeleteOp, spliceInsertOp, splitBlock, streamThroughEgress, streamingTargetFacet, suggestion, supportsInlineInputRules, supportsInlineMarks, tableCellDown, tableCellNext, tableCellPrev, tableEscapeGrid, toPseudoLocaleText, toggleMark, toolRuntimeFacet, undoManagerFacet, undoMetadataControllerFacet, undoRestoreControllerFacet, urlPolicy, urlPolicyFacet, usesInlineTextSelection, wordRangeAt };
1046
+ export { A11Y_MISSING_LABEL_CODE, APPLY_STORM_CODE, APPLY_STORM_QUEUE_LIMIT, type BeforeApplyHook, type BlockDirection, type BlockDirectionResolver, type BlockDirectionSetting, type CaretMotionParam, type CellCaretFocus, type CellCaretWrite, type ClipboardHandler, type CommandDispatchContext, type CommandHandlerTable, type CommandRegistry, type ContentMove, type ConvertBlockParam, type CreateCommandRegistryOptions, type CreateFacetRegistryOptions, type CreateHeadlessEditorOptions, type DecorationSource, type DefaultKeymapBinding, type DefaultKeymapContext, type DefinedBlockSchema, type DeleteGranularity, type DeleteParam, type DocumentMigration, DocumentRangeImpl, type EditorA11yLabelAttrs, EventEmitter, ExtensionManagerImpl, type FacetRegistry, type FacetSettleInput, HOOK_PRIORITIES, type InsertTextParam, type Keymap, type KeymapPlatform, type MigrationReport, type NormalPositionSnapshot, PIPELINE_PHASES, PSEUDO_LOCALE_CLOSE, PSEUDO_LOCALE_OPEN, type PendingBlock, type PendingBlockImportPolicyViolation, type PendingBlockProfilePolicyViolation, type ProfilePolicyViolation, type SchemaA11yAttrs, type SchemaA11yKind, SchemaEngineImpl, type SchemaRegistryConfig, SchemaRegistryImpl, type SelectBlockParam, SelectionAuthorityImpl as SelectionAuthority, type StructureBlockParam, type ToggleMarkParam, type UrlContext, type UrlPolicy, type VerticalCaretDirection, type VerticalCaretMeasure, type VerticalCaretMeasureResult, type VerticalCaretPoint, type WordRange, a11yLabelFacet, affectedBlockIdsFromSummary, aiAutocompleteControllerFacet, aiControllerFacet, aiEgressExtension, aiEgressFacet, aiInlineCompletionFacet, aiInlineHistoryFacet, aiReviewControllerFacet, aiSuggestionsControllerFacet, announceEditorA11y, announcerFacet, applyDirectedBinding, applyMergeBlocks, applySplitBlock, ariaReadOnlyFacet, assetProviderFacet, beforeApplyFacet, blockDirectionFacet, blockLogicalText, blocksToOps, buildMergeBlocksRecipe, buildNormalPositionSnapshot, buildSplitBlockRecipe, buildTableChildren, builtinCommandHandlers, caretBlockEnd, caretBlockStart, caretDocEnd, caretDocStart, caretDown, caretLeft, caretLineEnd, caretLineStart, caretRight, caretUp, caretWordLeft, caretWordRight, clipboardFacet, collectEditorKeyBindings, collectToolExecutionOutput, commandHandler, commandsFacet, convertBlock, convertBlockOps, createAppHandle, createBlockHandle, createCommandRegistry, createDecorationSet, createDocumentSession, createEditor, createEmptySchema, createFacetRegistry, createHeadlessEditor, createImportResult, createMutationGroupMetadata, createPseudoLocaleCatalog, createTextSelection, decorationsFacet, deepEqual, defaultDirectionFacet, defaultKeymapBindings, defineBlock, defineCommand, defineExtension, defineFacet, delegatesToGridEditing, deleteAdjacentInlineAtom, deleteBackward, deleteBlock, deleteForward, deriveContentMoves, duplicateBlock, emptyDecorationSet, ensureInlineCompletionController, fieldEditorHostFacet, filterAIRequest, filterOpsForDocumentProfile, filterPendingBlocksForDocumentProfile, foldAndNormalize, getApplyOptionsGroupId, getBlockSelectionRoleFromSchema, getBlockSelectionRoleFromType, getCellCaretFocus, getCommandRegistry, getEditorSelectionRecord, getFlowCapabilityFromSchema, getFlowCapabilityFromType, getInlineCompletionController, getNumberedListItemValue, getOpOriginGroupId, getOpOriginType, getSelectionBlockRange, getVerticalCaretGoalX, getVerticalCaretMeasure, hasFieldEditorSurface, hasIndexedCellSelectionMetadata, historyRedo, historyUndo, hookPriorityToPrecedence, indent, inputRulesEngineFacet, inputRulesFacet, insertLineBreak, insertText, interpolateMessage, isBlockSelected, isCollapsed, isContainerBlock, isContainerBlockType, isContinuousTextFlowCapability, isMultiBlock, isPseudoLocaleText, keyBindingPriorityToPrecedence, keymapFacet, localeFacet, mapOffsetThroughSplices, mergeDecorationSets, mergeSchemas, messagesFacet, moveBlockDown, moveBlockUp, multiplayerControllerFacet, nextGraphemeBoundary, nextWordBoundary, normalizePendingBlocksForImport, orderSlashMenuItemsByGroup, outdent, previousGraphemeBoundary, previousWordBoundary, priorityToPrecedence, prop, renderSelectionTargetBlockText, renderSelectionTargetText, repairAnchor, reportPendingBlockImportViolations, reportPendingBlockProfileViolations, resolveA11yBlockTypeLabel, resolveA11ySpec, resolveBlockDirection, resolveBlockFlowCapability, resolveCellSelectionCoord, resolveCellSelectionMatrix, resolveDefaultKeymap, resolveDirectedBinding, resolveDirectedCommand, resolveEditorA11yLabel, resolveEditorMessage, resolveEditorSchema, resolveFieldEditorBehavior, resolveFieldEditorInputMode, resolveFocusBlockDirection, resolveMessage, resolveSchema, resolveSchemaA11y, resolveSelectionTargetBlockIds, runMigrations, searchControllerFacet, selectAdjacentInlineAtom, selectAll, selectBlock, selectionToRange, setCellCaretFocus, setVerticalCaretGoalX, setVerticalCaretMeasure, shouldAllowDirectBlockPaste, shouldAllowFlowInsertionInSlashMenu, shouldExposeBlockInTooling, shouldForceBlockScopedSelectAll, shouldRenderContainerChildren, shouldShowBlockInDefaultMenus, singleController, slashMenuGroupOf, snapToNormalPosition, snapshotsControllerFacet, sortDeltaAttributes, spliceDeleteOp, spliceInsertOp, splitBlock, streamThroughEgress, streamingTargetFacet, suggestion, supportsInlineInputRules, supportsInlineMarks, tableCellDown, tableCellNext, tableCellPrev, tableEscapeGrid, toPseudoLocaleText, toggleMark, toolRuntimeFacet, undoManagerFacet, undoMetadataControllerFacet, undoRestoreControllerFacet, urlPolicy, urlPolicyFacet, usesInlineTextSelection, wordRangeAt };
package/dist/index.d.ts CHANGED
@@ -504,6 +504,19 @@ interface NormalPositionSnapshot {
504
504
  */
505
505
  declare function snapToNormalPosition(doc: NormalPositionSnapshot, point: Point, direction: NormalPositionDirection): NextNormalPositionResult;
506
506
 
507
+ /**
508
+ * Whether a block type holds child blocks, resolved from its schema rather than
509
+ * from a hardcoded type list — host-defined containers count too.
510
+ */
511
+ declare function isContainerBlockType(editor: Editor, blockType: string | null | undefined): boolean;
512
+ /**
513
+ * Whether a container's children participate in rendering and navigation.
514
+ *
515
+ * Collapsing is expressed by the block's own `open` prop, so any container that
516
+ * declares one is collapsible. `toggle` defaults `open` to `false` and so stays
517
+ * collapsed until opened; containers without the prop always show children.
518
+ */
519
+ declare function shouldRenderContainerChildren(editor: Editor, block: BlockHandle | null | undefined): boolean;
507
520
  /**
508
521
  * Ops that change one block's type in place, keeping its id and its text.
509
522
  *
@@ -910,6 +923,15 @@ declare const outdent: _input_pen_types.Command<void>;
910
923
  declare const toggleMark: _input_pen_types.Command<ToggleMarkParam>;
911
924
  declare const convertBlock: _input_pen_types.Command<ConvertBlockParam>;
912
925
 
926
+ /**
927
+ * Whether a block type holds child blocks, by either route: a nested-content
928
+ * schema, or the `parentId` convention that `isContainer` marks.
929
+ *
930
+ * This is the single authority for the question. Callers must not test block
931
+ * type names — a hardcoded set silently excludes every host-defined container.
932
+ */
933
+ declare function isContainerBlock(schema: BlockSchema | null | undefined): boolean;
934
+
913
935
  interface StructureBlockParam {
914
936
  readonly blockId?: string;
915
937
  }
@@ -1021,4 +1043,4 @@ declare function affectedBlockIdsFromSummary(summary: Pick<ChangeSummary, "block
1021
1043
  */
1022
1044
  declare function mapOffsetThroughSplices(splices: readonly TextSplice[], offset: number, assoc: Assoc): number;
1023
1045
 
1024
- export { A11Y_MISSING_LABEL_CODE, APPLY_STORM_CODE, APPLY_STORM_QUEUE_LIMIT, type BeforeApplyHook, type BlockDirection, type BlockDirectionResolver, type BlockDirectionSetting, type CaretMotionParam, type CellCaretFocus, type CellCaretWrite, type ClipboardHandler, type CommandDispatchContext, type CommandHandlerTable, type CommandRegistry, type ContentMove, type ConvertBlockParam, type CreateCommandRegistryOptions, type CreateFacetRegistryOptions, type CreateHeadlessEditorOptions, type DecorationSource, type DefaultKeymapBinding, type DefaultKeymapContext, type DefinedBlockSchema, type DeleteGranularity, type DeleteParam, type DocumentMigration, DocumentRangeImpl, type EditorA11yLabelAttrs, EventEmitter, ExtensionManagerImpl, type FacetRegistry, type FacetSettleInput, HOOK_PRIORITIES, type InsertTextParam, type Keymap, type KeymapPlatform, type MigrationReport, type NormalPositionSnapshot, PIPELINE_PHASES, PSEUDO_LOCALE_CLOSE, PSEUDO_LOCALE_OPEN, type PendingBlock, type PendingBlockImportPolicyViolation, type PendingBlockProfilePolicyViolation, type ProfilePolicyViolation, type SchemaA11yAttrs, type SchemaA11yKind, SchemaEngineImpl, type SchemaRegistryConfig, SchemaRegistryImpl, type SelectBlockParam, SelectionAuthorityImpl as SelectionAuthority, type StructureBlockParam, type ToggleMarkParam, type UrlContext, type UrlPolicy, type VerticalCaretDirection, type VerticalCaretMeasure, type VerticalCaretMeasureResult, type VerticalCaretPoint, type WordRange, a11yLabelFacet, affectedBlockIdsFromSummary, aiAutocompleteControllerFacet, aiControllerFacet, aiEgressExtension, aiEgressFacet, aiInlineCompletionFacet, aiInlineHistoryFacet, aiReviewControllerFacet, aiSuggestionsControllerFacet, announceEditorA11y, announcerFacet, applyDirectedBinding, applyMergeBlocks, applySplitBlock, ariaReadOnlyFacet, assetProviderFacet, beforeApplyFacet, blockDirectionFacet, blockLogicalText, blocksToOps, buildMergeBlocksRecipe, buildNormalPositionSnapshot, buildSplitBlockRecipe, buildTableChildren, builtinCommandHandlers, caretBlockEnd, caretBlockStart, caretDocEnd, caretDocStart, caretDown, caretLeft, caretLineEnd, caretLineStart, caretRight, caretUp, caretWordLeft, caretWordRight, clipboardFacet, collectEditorKeyBindings, collectToolExecutionOutput, commandHandler, commandsFacet, convertBlock, convertBlockOps, createAppHandle, createBlockHandle, createCommandRegistry, createDecorationSet, createDocumentSession, createEditor, createEmptySchema, createFacetRegistry, createHeadlessEditor, createImportResult, createMutationGroupMetadata, createPseudoLocaleCatalog, createTextSelection, decorationsFacet, deepEqual, defaultDirectionFacet, defaultKeymapBindings, defineBlock, defineCommand, defineExtension, defineFacet, delegatesToGridEditing, deleteAdjacentInlineAtom, deleteBackward, deleteBlock, deleteForward, deriveContentMoves, duplicateBlock, emptyDecorationSet, ensureInlineCompletionController, fieldEditorHostFacet, filterAIRequest, filterOpsForDocumentProfile, filterPendingBlocksForDocumentProfile, foldAndNormalize, getApplyOptionsGroupId, getBlockSelectionRoleFromSchema, getBlockSelectionRoleFromType, getCellCaretFocus, getCommandRegistry, getEditorSelectionRecord, getFlowCapabilityFromSchema, getFlowCapabilityFromType, getInlineCompletionController, getNumberedListItemValue, getOpOriginGroupId, getOpOriginType, getSelectionBlockRange, getVerticalCaretGoalX, getVerticalCaretMeasure, hasFieldEditorSurface, hasIndexedCellSelectionMetadata, historyRedo, historyUndo, hookPriorityToPrecedence, indent, inputRulesEngineFacet, inputRulesFacet, insertLineBreak, insertText, interpolateMessage, isBlockSelected, isCollapsed, isContinuousTextFlowCapability, isMultiBlock, isPseudoLocaleText, keyBindingPriorityToPrecedence, keymapFacet, localeFacet, mapOffsetThroughSplices, mergeDecorationSets, mergeSchemas, messagesFacet, moveBlockDown, moveBlockUp, multiplayerControllerFacet, nextGraphemeBoundary, nextWordBoundary, normalizePendingBlocksForImport, orderSlashMenuItemsByGroup, outdent, previousGraphemeBoundary, previousWordBoundary, priorityToPrecedence, prop, renderSelectionTargetBlockText, renderSelectionTargetText, repairAnchor, reportPendingBlockImportViolations, reportPendingBlockProfileViolations, resolveA11yBlockTypeLabel, resolveA11ySpec, resolveBlockDirection, resolveBlockFlowCapability, resolveCellSelectionCoord, resolveCellSelectionMatrix, resolveDefaultKeymap, resolveDirectedBinding, resolveDirectedCommand, resolveEditorA11yLabel, resolveEditorMessage, resolveEditorSchema, resolveFieldEditorBehavior, resolveFieldEditorInputMode, resolveFocusBlockDirection, resolveMessage, resolveSchema, resolveSchemaA11y, resolveSelectionTargetBlockIds, runMigrations, searchControllerFacet, selectAdjacentInlineAtom, selectAll, selectBlock, selectionToRange, setCellCaretFocus, setVerticalCaretGoalX, setVerticalCaretMeasure, shouldAllowDirectBlockPaste, shouldAllowFlowInsertionInSlashMenu, shouldExposeBlockInTooling, shouldForceBlockScopedSelectAll, shouldShowBlockInDefaultMenus, singleController, slashMenuGroupOf, snapToNormalPosition, snapshotsControllerFacet, sortDeltaAttributes, spliceDeleteOp, spliceInsertOp, splitBlock, streamThroughEgress, streamingTargetFacet, suggestion, supportsInlineInputRules, supportsInlineMarks, tableCellDown, tableCellNext, tableCellPrev, tableEscapeGrid, toPseudoLocaleText, toggleMark, toolRuntimeFacet, undoManagerFacet, undoMetadataControllerFacet, undoRestoreControllerFacet, urlPolicy, urlPolicyFacet, usesInlineTextSelection, wordRangeAt };
1046
+ export { A11Y_MISSING_LABEL_CODE, APPLY_STORM_CODE, APPLY_STORM_QUEUE_LIMIT, type BeforeApplyHook, type BlockDirection, type BlockDirectionResolver, type BlockDirectionSetting, type CaretMotionParam, type CellCaretFocus, type CellCaretWrite, type ClipboardHandler, type CommandDispatchContext, type CommandHandlerTable, type CommandRegistry, type ContentMove, type ConvertBlockParam, type CreateCommandRegistryOptions, type CreateFacetRegistryOptions, type CreateHeadlessEditorOptions, type DecorationSource, type DefaultKeymapBinding, type DefaultKeymapContext, type DefinedBlockSchema, type DeleteGranularity, type DeleteParam, type DocumentMigration, DocumentRangeImpl, type EditorA11yLabelAttrs, EventEmitter, ExtensionManagerImpl, type FacetRegistry, type FacetSettleInput, HOOK_PRIORITIES, type InsertTextParam, type Keymap, type KeymapPlatform, type MigrationReport, type NormalPositionSnapshot, PIPELINE_PHASES, PSEUDO_LOCALE_CLOSE, PSEUDO_LOCALE_OPEN, type PendingBlock, type PendingBlockImportPolicyViolation, type PendingBlockProfilePolicyViolation, type ProfilePolicyViolation, type SchemaA11yAttrs, type SchemaA11yKind, SchemaEngineImpl, type SchemaRegistryConfig, SchemaRegistryImpl, type SelectBlockParam, SelectionAuthorityImpl as SelectionAuthority, type StructureBlockParam, type ToggleMarkParam, type UrlContext, type UrlPolicy, type VerticalCaretDirection, type VerticalCaretMeasure, type VerticalCaretMeasureResult, type VerticalCaretPoint, type WordRange, a11yLabelFacet, affectedBlockIdsFromSummary, aiAutocompleteControllerFacet, aiControllerFacet, aiEgressExtension, aiEgressFacet, aiInlineCompletionFacet, aiInlineHistoryFacet, aiReviewControllerFacet, aiSuggestionsControllerFacet, announceEditorA11y, announcerFacet, applyDirectedBinding, applyMergeBlocks, applySplitBlock, ariaReadOnlyFacet, assetProviderFacet, beforeApplyFacet, blockDirectionFacet, blockLogicalText, blocksToOps, buildMergeBlocksRecipe, buildNormalPositionSnapshot, buildSplitBlockRecipe, buildTableChildren, builtinCommandHandlers, caretBlockEnd, caretBlockStart, caretDocEnd, caretDocStart, caretDown, caretLeft, caretLineEnd, caretLineStart, caretRight, caretUp, caretWordLeft, caretWordRight, clipboardFacet, collectEditorKeyBindings, collectToolExecutionOutput, commandHandler, commandsFacet, convertBlock, convertBlockOps, createAppHandle, createBlockHandle, createCommandRegistry, createDecorationSet, createDocumentSession, createEditor, createEmptySchema, createFacetRegistry, createHeadlessEditor, createImportResult, createMutationGroupMetadata, createPseudoLocaleCatalog, createTextSelection, decorationsFacet, deepEqual, defaultDirectionFacet, defaultKeymapBindings, defineBlock, defineCommand, defineExtension, defineFacet, delegatesToGridEditing, deleteAdjacentInlineAtom, deleteBackward, deleteBlock, deleteForward, deriveContentMoves, duplicateBlock, emptyDecorationSet, ensureInlineCompletionController, fieldEditorHostFacet, filterAIRequest, filterOpsForDocumentProfile, filterPendingBlocksForDocumentProfile, foldAndNormalize, getApplyOptionsGroupId, getBlockSelectionRoleFromSchema, getBlockSelectionRoleFromType, getCellCaretFocus, getCommandRegistry, getEditorSelectionRecord, getFlowCapabilityFromSchema, getFlowCapabilityFromType, getInlineCompletionController, getNumberedListItemValue, getOpOriginGroupId, getOpOriginType, getSelectionBlockRange, getVerticalCaretGoalX, getVerticalCaretMeasure, hasFieldEditorSurface, hasIndexedCellSelectionMetadata, historyRedo, historyUndo, hookPriorityToPrecedence, indent, inputRulesEngineFacet, inputRulesFacet, insertLineBreak, insertText, interpolateMessage, isBlockSelected, isCollapsed, isContainerBlock, isContainerBlockType, isContinuousTextFlowCapability, isMultiBlock, isPseudoLocaleText, keyBindingPriorityToPrecedence, keymapFacet, localeFacet, mapOffsetThroughSplices, mergeDecorationSets, mergeSchemas, messagesFacet, moveBlockDown, moveBlockUp, multiplayerControllerFacet, nextGraphemeBoundary, nextWordBoundary, normalizePendingBlocksForImport, orderSlashMenuItemsByGroup, outdent, previousGraphemeBoundary, previousWordBoundary, priorityToPrecedence, prop, renderSelectionTargetBlockText, renderSelectionTargetText, repairAnchor, reportPendingBlockImportViolations, reportPendingBlockProfileViolations, resolveA11yBlockTypeLabel, resolveA11ySpec, resolveBlockDirection, resolveBlockFlowCapability, resolveCellSelectionCoord, resolveCellSelectionMatrix, resolveDefaultKeymap, resolveDirectedBinding, resolveDirectedCommand, resolveEditorA11yLabel, resolveEditorMessage, resolveEditorSchema, resolveFieldEditorBehavior, resolveFieldEditorInputMode, resolveFocusBlockDirection, resolveMessage, resolveSchema, resolveSchemaA11y, resolveSelectionTargetBlockIds, runMigrations, searchControllerFacet, selectAdjacentInlineAtom, selectAll, selectBlock, selectionToRange, setCellCaretFocus, setVerticalCaretGoalX, setVerticalCaretMeasure, shouldAllowDirectBlockPaste, shouldAllowFlowInsertionInSlashMenu, shouldExposeBlockInTooling, shouldForceBlockScopedSelectAll, shouldRenderContainerChildren, shouldShowBlockInDefaultMenus, singleController, slashMenuGroupOf, snapToNormalPosition, snapshotsControllerFacet, sortDeltaAttributes, spliceDeleteOp, spliceInsertOp, splitBlock, streamThroughEgress, streamingTargetFacet, suggestion, supportsInlineInputRules, supportsInlineMarks, tableCellDown, tableCellNext, tableCellPrev, tableEscapeGrid, toPseudoLocaleText, toggleMark, toolRuntimeFacet, undoManagerFacet, undoMetadataControllerFacet, undoRestoreControllerFacet, urlPolicy, urlPolicyFacet, usesInlineTextSelection, wordRangeAt };
package/dist/index.mjs CHANGED
@@ -2699,6 +2699,9 @@ function opBlockId(_pipeline, op) {
2699
2699
  import { STRUCTURAL_ORIGIN_META_KEY } from "@input/pen-yjs";
2700
2700
 
2701
2701
  // src/schema/contentType.ts
2702
+ import {
2703
+ isNestedContent
2704
+ } from "@input/pen-types";
2702
2705
  function resolveRuntimeContentType(schema) {
2703
2706
  if (!schema) {
2704
2707
  return "none";
@@ -2708,6 +2711,10 @@ function resolveRuntimeContentType(schema) {
2708
2711
  }
2709
2712
  return schema.content;
2710
2713
  }
2714
+ function isContainerBlock(schema) {
2715
+ if (!schema) return false;
2716
+ return isNestedContent(schema.content) || schema.isContainer === true;
2717
+ }
2711
2718
 
2712
2719
  // src/editor/rejectedOwnKeys.ts
2713
2720
  var REJECTED_OWN_PROP_KEYS = /* @__PURE__ */ new Set([
@@ -3582,6 +3589,15 @@ function executeOps(pipeline, ops, origin, structural) {
3582
3589
  const blockId = opBlockId(pipeline, op);
3583
3590
  if (!validateOp(pipeline, op)) continue;
3584
3591
  if (op.type === "insert-block") {
3592
+ if (blockExists(pipeline, op.blockId) || pendingBlockIds.has(op.blockId)) {
3593
+ emitPipelineDiagnostic(pipeline, {
3594
+ code: "PEN_APPLY_010",
3595
+ level: "warn",
3596
+ source: "apply",
3597
+ message: `apply: skipping insert-block for already-present block "${op.blockId}"`
3598
+ });
3599
+ continue;
3600
+ }
3585
3601
  pendingBlockIds.add(op.blockId);
3586
3602
  pendingBlockTypes.set(op.blockId, op.blockType);
3587
3603
  }
@@ -6047,9 +6063,11 @@ var SelectionAuthorityImpl = class {
6047
6063
  };
6048
6064
 
6049
6065
  // src/editor/documentState.ts
6066
+ var EMPTY_CHILD_IDS = Object.freeze([]);
6050
6067
  var DocumentStateImpl = class {
6051
6068
  _positionIndex;
6052
6069
  _parentIndex;
6070
+ _childIndex;
6053
6071
  _blockOrder;
6054
6072
  _generation = 0;
6055
6073
  _documentProfile;
@@ -6063,6 +6081,7 @@ var DocumentStateImpl = class {
6063
6081
  this._documentProfile = documentProfile;
6064
6082
  this._positionIndex = /* @__PURE__ */ new Map();
6065
6083
  this._parentIndex = /* @__PURE__ */ new Map();
6084
+ this._childIndex = /* @__PURE__ */ new Map();
6066
6085
  this._blockOrder = [];
6067
6086
  this.rebuild();
6068
6087
  }
@@ -6101,6 +6120,9 @@ var DocumentStateImpl = class {
6101
6120
  parentOf(blockId) {
6102
6121
  return this._parentIndex.get(blockId) ?? null;
6103
6122
  }
6123
+ childrenOf(blockId) {
6124
+ return this._childIndex.get(blockId) ?? EMPTY_CHILD_IDS;
6125
+ }
6104
6126
  *allBlocks() {
6105
6127
  const seen = /* @__PURE__ */ new Set();
6106
6128
  for (const id of this._blockOrder) {
@@ -6120,21 +6142,44 @@ var DocumentStateImpl = class {
6120
6142
  this._blockOrder = [];
6121
6143
  this._positionIndex = /* @__PURE__ */ new Map();
6122
6144
  this._parentIndex = /* @__PURE__ */ new Map();
6145
+ this._childIndex = /* @__PURE__ */ new Map();
6123
6146
  for (let i = 0; i < order.length; i++) {
6124
6147
  const id = order.get(i);
6125
6148
  this._blockOrder.push(id);
6126
6149
  this._positionIndex.set(id, i);
6127
6150
  }
6151
+ const nestedChildIds = /* @__PURE__ */ new Set();
6152
+ const parentIdChildIds = [];
6128
6153
  for (const [blockId, blockMap] of this._doc.blocks.entries()) {
6129
6154
  const props = blockMap.get("props");
6130
6155
  if (props?.get?.("parentId")) {
6131
6156
  this._parentIndex.set(blockId, props.get("parentId"));
6157
+ parentIdChildIds.push(blockId);
6132
6158
  }
6133
6159
  const children = blockMap.get("children");
6134
- if (children) {
6160
+ if (children && children.length > 0) {
6161
+ const childIds = [];
6135
6162
  for (let i = 0; i < children.length; i++) {
6136
- this._parentIndex.set(children.get(i), blockId);
6163
+ const childId = children.get(i);
6164
+ this._parentIndex.set(childId, blockId);
6165
+ nestedChildIds.add(childId);
6166
+ childIds.push(childId);
6137
6167
  }
6168
+ this._childIndex.set(blockId, childIds);
6169
+ }
6170
+ }
6171
+ parentIdChildIds.sort(
6172
+ (a, b) => (this._positionIndex.get(a) ?? -1) - (this._positionIndex.get(b) ?? -1)
6173
+ );
6174
+ for (const childId of parentIdChildIds) {
6175
+ if (nestedChildIds.has(childId)) continue;
6176
+ const parentId = this._parentIndex.get(childId);
6177
+ if (parentId === void 0) continue;
6178
+ const siblings = this._childIndex.get(parentId);
6179
+ if (siblings === void 0) {
6180
+ this._childIndex.set(parentId, [childId]);
6181
+ } else {
6182
+ siblings.push(childId);
6138
6183
  }
6139
6184
  }
6140
6185
  this._generation++;
@@ -6142,6 +6187,7 @@ var DocumentStateImpl = class {
6142
6187
  clear() {
6143
6188
  this._positionIndex.clear();
6144
6189
  this._parentIndex.clear();
6190
+ this._childIndex.clear();
6145
6191
  this._blockOrder = [];
6146
6192
  this._generation++;
6147
6193
  }
@@ -7418,11 +7464,18 @@ var BACKSPACE_EXIT_TYPES = /* @__PURE__ */ new Set([
7418
7464
  ...CONTAINER_EXIT_TYPES,
7419
7465
  ...HEADING_TYPES
7420
7466
  ]);
7421
- var PARENT_ID_CONTAINER_TYPES = /* @__PURE__ */ new Set([
7422
- "toggle",
7423
- "callout",
7424
- "blockquote"
7425
- ]);
7467
+ function isContainerBlockType(editor, blockType) {
7468
+ if (!blockType) {
7469
+ return false;
7470
+ }
7471
+ return isContainerBlock(editor.schema.resolve(blockType));
7472
+ }
7473
+ function shouldRenderContainerChildren(editor, block) {
7474
+ if (!block || !isContainerBlockType(editor, block.type)) {
7475
+ return false;
7476
+ }
7477
+ return block.props?.open !== false;
7478
+ }
7426
7479
  function emitCommandDiagnostic(editor, event) {
7427
7480
  editor.internals?.emit("diagnostic", event);
7428
7481
  }
@@ -7474,18 +7527,13 @@ function isInsideParentIdContainer(editor, blockId) {
7474
7527
  return false;
7475
7528
  }
7476
7529
  const parent = editor.getBlock(parentId);
7477
- return !!parent && PARENT_ID_CONTAINER_TYPES.has(parent.type);
7530
+ return !!parent && isContainerBlockType(editor, parent.type);
7478
7531
  }
7479
7532
  function getRootBlockIds(editor) {
7480
7533
  return editor.documentState.blockOrder.filter(
7481
7534
  (blockId) => editor.documentState.parentOf(blockId) == null
7482
7535
  );
7483
7536
  }
7484
- function getParentIdChildBlockIds(editor, parentBlockId) {
7485
- return editor.documentState.blockOrder.filter(
7486
- (blockId) => editor.documentState.parentOf(blockId) === parentBlockId
7487
- );
7488
- }
7489
7537
  function getVisibleBlockIds(editor) {
7490
7538
  const visibleBlockIds = [];
7491
7539
  for (const rootBlockId of getRootBlockIds(editor)) {
@@ -7607,23 +7655,13 @@ function convertBlockOps(editor, options) {
7607
7655
  }
7608
7656
  function collectVisibleBlockIds(editor, blockId, visibleBlockIds) {
7609
7657
  visibleBlockIds.push(blockId);
7610
- if (!shouldShowParentIdChildren(editor, blockId)) {
7658
+ if (!shouldRenderContainerChildren(editor, editor.getBlock(blockId))) {
7611
7659
  return;
7612
7660
  }
7613
- for (const childBlockId of getParentIdChildBlockIds(editor, blockId)) {
7661
+ for (const childBlockId of editor.documentState.childrenOf(blockId)) {
7614
7662
  collectVisibleBlockIds(editor, childBlockId, visibleBlockIds);
7615
7663
  }
7616
7664
  }
7617
- function shouldShowParentIdChildren(editor, blockId) {
7618
- const block = editor.getBlock(blockId);
7619
- if (!block || !PARENT_ID_CONTAINER_TYPES.has(block.type)) {
7620
- return false;
7621
- }
7622
- if (block.type !== "toggle") {
7623
- return true;
7624
- }
7625
- return Boolean(block.props?.open);
7626
- }
7627
7665
 
7628
7666
  // src/commands/commandSelection.ts
7629
7667
  function textSelectionResult(anchor, focus = anchor, extras) {
@@ -7799,12 +7837,12 @@ function parentContainerKind(editor, parentId) {
7799
7837
  if (!parent) {
7800
7838
  return null;
7801
7839
  }
7802
- if (PARENT_ID_CONTAINER_TYPES.has(parent.type)) {
7803
- return "layout-cell";
7804
- }
7805
7840
  if (parent.type === "table") {
7806
7841
  return "table";
7807
7842
  }
7843
+ if (isContainerBlockType(editor, parent.type)) {
7844
+ return "layout-cell";
7845
+ }
7808
7846
  return null;
7809
7847
  }
7810
7848
 
@@ -14830,6 +14868,8 @@ export {
14830
14868
  interpolateMessage,
14831
14869
  isBlockSelected,
14832
14870
  isCollapsed,
14871
+ isContainerBlock,
14872
+ isContainerBlockType,
14833
14873
  isContinuousTextFlowCapability,
14834
14874
  isMultiBlock,
14835
14875
  isPseudoLocaleText,
@@ -14889,6 +14929,7 @@ export {
14889
14929
  shouldAllowFlowInsertionInSlashMenu,
14890
14930
  shouldExposeBlockInTooling,
14891
14931
  shouldForceBlockScopedSelectAll,
14932
+ shouldRenderContainerChildren,
14892
14933
  shouldShowBlockInDefaultMenus,
14893
14934
  singleController,
14894
14935
  slashMenuGroupOf,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@input/pen-core",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Headless, extension-first editor engine for human-AI co-authoring",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/input-systems/pen#readme",
@@ -43,8 +43,8 @@
43
43
  },
44
44
  "sideEffects": false,
45
45
  "dependencies": {
46
- "@input/pen-yjs": "^0.1.1",
47
- "@input/pen-types": "^0.1.1"
46
+ "@input/pen-yjs": "^0.1.2",
47
+ "@input/pen-types": "^0.1.2"
48
48
  },
49
49
  "devDependencies": {
50
50
  "tsup": "^8.4.0",