@agent-native/core 0.39.2 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/action.js +12 -0
- package/dist/action.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +5 -1
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/skills.d.ts +4 -3
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +756 -694
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/blocks/AiEditableField.d.ts +8 -0
- package/dist/client/blocks/AiEditableField.d.ts.map +1 -0
- package/dist/client/blocks/AiEditableField.js +10 -0
- package/dist/client/blocks/AiEditableField.js.map +1 -0
- package/dist/client/blocks/BlockView.d.ts +3 -3
- package/dist/client/blocks/BlockView.d.ts.map +1 -1
- package/dist/client/blocks/BlockView.js +15 -3
- package/dist/client/blocks/BlockView.js.map +1 -1
- package/dist/client/blocks/SchemaBlockEditor.js +2 -2
- package/dist/client/blocks/SchemaBlockEditor.js.map +1 -1
- package/dist/client/blocks/index.d.ts +5 -2
- package/dist/client/blocks/index.d.ts.map +1 -1
- package/dist/client/blocks/index.js +6 -3
- package/dist/client/blocks/index.js.map +1 -1
- package/dist/client/blocks/library/ApiEndpointBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/ApiEndpointBlock.js +20 -6
- package/dist/client/blocks/library/ApiEndpointBlock.js.map +1 -1
- package/dist/client/blocks/library/DiffBlock.d.ts +29 -0
- package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/DiffBlock.js +190 -30
- package/dist/client/blocks/library/DiffBlock.js.map +1 -1
- package/dist/client/blocks/library/FileTreeBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/FileTreeBlock.js +46 -7
- package/dist/client/blocks/library/FileTreeBlock.js.map +1 -1
- package/dist/client/blocks/library/HighlightedCode.d.ts +10 -0
- package/dist/client/blocks/library/HighlightedCode.d.ts.map +1 -0
- package/dist/client/blocks/library/HighlightedCode.js +92 -0
- package/dist/client/blocks/library/HighlightedCode.js.map +1 -0
- package/dist/client/blocks/library/JsonExplorerBlock.d.ts +9 -4
- package/dist/client/blocks/library/JsonExplorerBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/JsonExplorerBlock.js +66 -30
- package/dist/client/blocks/library/JsonExplorerBlock.js.map +1 -1
- package/dist/client/blocks/library/MermaidBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/MermaidBlock.js +73 -44
- package/dist/client/blocks/library/MermaidBlock.js.map +1 -1
- package/dist/client/blocks/library/OpenApiSpecBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/OpenApiSpecBlock.js +3 -2
- package/dist/client/blocks/library/OpenApiSpecBlock.js.map +1 -1
- package/dist/client/blocks/library/checklist.d.ts.map +1 -1
- package/dist/client/blocks/library/checklist.js +1 -0
- package/dist/client/blocks/library/checklist.js.map +1 -1
- package/dist/client/blocks/library/code-tabs.d.ts.map +1 -1
- package/dist/client/blocks/library/code-tabs.js +183 -102
- package/dist/client/blocks/library/code-tabs.js.map +1 -1
- package/dist/client/blocks/library/columns.config.d.ts +60 -0
- package/dist/client/blocks/library/columns.config.d.ts.map +1 -0
- package/dist/client/blocks/library/columns.config.js +37 -0
- package/dist/client/blocks/library/columns.config.js.map +1 -0
- package/dist/client/blocks/library/columns.d.ts +25 -0
- package/dist/client/blocks/library/columns.d.ts.map +1 -0
- package/dist/client/blocks/library/columns.js +199 -0
- package/dist/client/blocks/library/columns.js.map +1 -0
- package/dist/client/blocks/library/dev-doc-ui.d.ts +2 -1
- package/dist/client/blocks/library/dev-doc-ui.d.ts.map +1 -1
- package/dist/client/blocks/library/dev-doc-ui.js +2 -1
- package/dist/client/blocks/library/dev-doc-ui.js.map +1 -1
- package/dist/client/blocks/library/html.d.ts +1 -1
- package/dist/client/blocks/library/html.d.ts.map +1 -1
- package/dist/client/blocks/library/html.js +34 -4
- package/dist/client/blocks/library/html.js.map +1 -1
- package/dist/client/blocks/library/json-explorer.config.d.ts +3 -1
- package/dist/client/blocks/library/json-explorer.config.d.ts.map +1 -1
- package/dist/client/blocks/library/json-explorer.config.js +30 -1
- package/dist/client/blocks/library/json-explorer.config.js.map +1 -1
- package/dist/client/blocks/library/server-specs.d.ts.map +1 -1
- package/dist/client/blocks/library/server-specs.js +13 -3
- package/dist/client/blocks/library/server-specs.js.map +1 -1
- package/dist/client/blocks/library/specs.d.ts +4 -4
- package/dist/client/blocks/library/specs.d.ts.map +1 -1
- package/dist/client/blocks/library/specs.js +21 -16
- package/dist/client/blocks/library/specs.js.map +1 -1
- package/dist/client/blocks/library/table.config.d.ts +3 -0
- package/dist/client/blocks/library/table.config.d.ts.map +1 -1
- package/dist/client/blocks/library/table.config.js +13 -1
- package/dist/client/blocks/library/table.config.js.map +1 -1
- package/dist/client/blocks/library/table.d.ts.map +1 -1
- package/dist/client/blocks/library/table.js +90 -9
- package/dist/client/blocks/library/table.js.map +1 -1
- package/dist/client/blocks/library/tabs.config.d.ts +16 -8
- package/dist/client/blocks/library/tabs.config.d.ts.map +1 -1
- package/dist/client/blocks/library/tabs.config.js +10 -4
- package/dist/client/blocks/library/tabs.config.js.map +1 -1
- package/dist/client/blocks/library/tabs.d.ts.map +1 -1
- package/dist/client/blocks/library/tabs.js +146 -21
- package/dist/client/blocks/library/tabs.js.map +1 -1
- package/dist/client/blocks/server.d.ts +2 -1
- package/dist/client/blocks/server.d.ts.map +1 -1
- package/dist/client/blocks/server.js +1 -0
- package/dist/client/blocks/server.js.map +1 -1
- package/dist/client/blocks/types.d.ts +99 -9
- package/dist/client/blocks/types.d.ts.map +1 -1
- package/dist/client/blocks/types.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/rich-markdown-editor/BubbleToolbar.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/BubbleToolbar.js +13 -3
- package/dist/client/rich-markdown-editor/BubbleToolbar.js.map +1 -1
- package/dist/client/rich-markdown-editor/DragHandle.d.ts +49 -4
- package/dist/client/rich-markdown-editor/DragHandle.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/DragHandle.js +656 -88
- package/dist/client/rich-markdown-editor/DragHandle.js.map +1 -1
- package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts +10 -1
- package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/RegistryBlockNode.js +180 -15
- package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts +2 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.js +3 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.js.map +1 -1
- package/dist/client/rich-markdown-editor/SlashCommandMenu.d.ts +5 -0
- package/dist/client/rich-markdown-editor/SlashCommandMenu.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/SlashCommandMenu.js +33 -5
- package/dist/client/rich-markdown-editor/SlashCommandMenu.js.map +1 -1
- package/dist/client/rich-markdown-editor/index.d.ts +3 -3
- package/dist/client/rich-markdown-editor/index.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/index.js +2 -2
- package/dist/client/rich-markdown-editor/index.js.map +1 -1
- package/dist/client/rich-markdown-editor/registrySlashCommands.d.ts +14 -0
- package/dist/client/rich-markdown-editor/registrySlashCommands.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/registrySlashCommands.js +38 -0
- package/dist/client/rich-markdown-editor/registrySlashCommands.js.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts +1 -0
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +4 -0
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +17 -1
- package/dist/db/client.js.map +1 -1
- package/dist/sharing/access.d.ts +4 -2
- package/dist/sharing/access.d.ts.map +1 -1
- package/dist/sharing/access.js +8 -3
- package/dist/sharing/access.js.map +1 -1
- package/dist/sharing/actions/set-resource-visibility.d.ts.map +1 -1
- package/dist/sharing/actions/set-resource-visibility.js +2 -3
- package/dist/sharing/actions/set-resource-visibility.js.map +1 -1
- package/dist/sharing/registry.d.ts +13 -0
- package/dist/sharing/registry.d.ts.map +1 -1
- package/dist/sharing/registry.js.map +1 -1
- package/dist/styles/rich-markdown-editor.css +15 -0
- package/package.json +16 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RegistryBlockNode.js","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/RegistryBlockNode.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAkB,MAAM,OAAO,CAAC;AAClE,OAAO,EACL,IAAI,EACJ,eAAe,EACf,qBAAqB,EACrB,eAAe,GAEhB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAoB,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAoEzE,MAAM,wBAAwB,GAC5B,aAAa,CAAqC,IAAI,CAAC,CAAC;AAE1D,MAAM,UAAU,yBAAyB,CAEvC,EACA,KAAK,EACL,QAAQ,GAIT;IACC,OAAO,CACL,KAAC,wBAAwB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAC5C,QAAQ,GACyB,CACrC,CAAC;AACJ,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,oBAAoB;IAGlC,OAAO,UAAU,CACf,wBAAwB,CACgB,CAAC;AAC7C,CAAC;AAED,gFAAgF;AAChF,gFAAgF;AAChF,gFAAgF;AAEhF;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAoB;IACxD,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IAEvD,MAAM,aAAa,GAAG,wBAAwB,EAAE,CAAC;IACjD,MAAM,OAAO,GAAG,oBAAoB,EAAE,CAAC;IAEvC,MAAM,KAAK,GAAG,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,KAAK,CAAC;IAC5C,MAAM,OAAO,GAAG,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC;IAC3C,2EAA2E;IAC3E,4EAA4E;IAC5E,2CAA2C;IAC3C,MAAM,sBAAsB,GAC1B,CAAC,OAAO,EAAE,UAAU,IAAI,KAAK,CAAC;QAC9B,CAAC,OAAO,EAAE,wBAAwB,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,CAAC;IAE5D,+EAA+E;IAC/E,kEAAkE;IAClE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CACL,KAAC,eAAe,IAAC,SAAS,EAAC,iBAAiB,mBAAgB,OAAO,YACjE,cACE,eAAe,EAAE,KAAK,iCAEtB,SAAS,EAAC,oHAAoH,YAE7H,SAAS,CAAC,CAAC,CAAC,WAAW,SAAS,SAAS,CAAC,CAAC,CAAC,gBAAgB,GACzD,GACU,CACnB,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,aAAa,EAAE,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAEpD,uCAAuC;IACvC,2EAA2E;IAC3E,yEAAyE;IACzE,gCAAgC;IAChC,+EAA+E;IAC/E,2EAA2E;IAC3E,+EAA+E;IAC/E,yEAAyE;IACzE,sDAAsD;IACtD,+CAA+C;IAC/C,IAAI,IAAe,CAAC;IACpB,IAAI,aAAa,IAAI,IAAI,EAAE,CAAC;QAC1B,IAAI,GAAG,CACL,KAAC,SAAS,IACR,IAAI,EAAE,IAAI,EACV,KAAK,EAAE;gBACL,EAAE,EAAE,KAAK,CAAC,EAAE;gBACZ,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,IAAI,EAAG,KAA2B,CAAC,IAAI;aACxC,EACD,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,EAAE,iBAAiB,CAAC,OAAO,EAAE,QAAQ,CAAC,EACrE,GAAG,EAAE,aAAa,CAAC,GAAG,GACtB,CACH,CAAC;IACJ,CAAC;SAAM,IAAI,OAAO,EAAE,iBAAiB,EAAE,CAAC;QACtC,IAAI,GAAG,OAAO,CAAC,iBAAiB,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IACvD,CAAC;SAAM,CAAC;QACN,IAAI,GAAG,CACL,cAAK,SAAS,EAAC,mGAAmG,YAC/G,KAAK,CAAC,KAAK,IAAI,SAAS,IAAI,mBAAmB,GAC5C,CACP,CAAC;IACJ,CAAC;IAED,OAAO,CACL,KAAC,eAAe,IACd,SAAS,EAAC,iBAAiB,mBACZ,OAAO,8BACI,sBAAsB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,YAEjE,eAAK,eAAe,EAAE,KAAK,4CACxB,sBAAsB,IAAI,CACzB,eACE,SAAS,EAAC,yBAAyB,EACnC,KAAK,EAAC,oEAAoE,qCAGrE,CACR,EACA,IAAI,IACD,GACU,CACnB,CAAC;AACJ,CAAC;AA6BD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAAuC;IAEvC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,GAAG,OAAO,EAAE,GAAG,OAAO,CAAC;IAC/D,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC,GAAG,QAAQ,WAAW,CAAC,CAAC;IAExD;;;;OAIG;IACH,SAAS,cAAc,CAAC,KAAkB;QAMxC,MAAM,KAAK,GAKN,EAAE,CAAC;QACR,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;YAClC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAChC,KAAK,CAAC,IAAI,CAAC;oBACT,GAAG;oBACH,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC;oBAC7C,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;oBACzC,aAAa,EACX,OAAO,IAAI,CAAC,KAAK,CAAC,aAAa,KAAK,QAAQ;wBAC1C,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa;wBAC1B,CAAC,CAAC,SAAS;iBAChB,CAAC,CAAC;YACL,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;QACH,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;OAKG;IACH,SAAS,sBAAsB,CAAC,KAAkB;QAChD,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAEtC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,IAAI,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC;QAClB,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,UAAU,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC7D,IAAI,UAAU,EAAE,CAAC;gBACf,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,IAAI,OAAO,CAAC,CAAC;gBACnD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACzC,IAAI,IAAI,EAAE,CAAC;oBACT,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,EAAE,SAAS,EAAE;wBAC1C,GAAG,IAAI,CAAC,KAAK;wBACb,OAAO,EAAE,OAAO;wBAChB,aAAa,EAAE,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,OAAO,IAAI,IAAI;qBAC5D,CAAC,CAAC;oBACH,OAAO,GAAG,IAAI,CAAC;gBACjB,CAAC;gBACD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACpB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACtD,CAAC;IAED,OAAO,IAAI,CAAC,MAAM,CAAC;QACjB,IAAI,EAAE,QAAQ;QACd,KAAK;QACL,IAAI,EAAE,IAAI;QACV,SAAS,EAAE,IAAI;QACf,UAAU,EAAE,IAAI;QAChB,SAAS,EAAE,IAAI;QAEf,aAAa;YACX,OAAO;gBACL,SAAS,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;gBAC1B,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;gBACxB,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;gBACxB,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;gBAC1B,aAAa,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;gBAChC,8DAA8D;gBAC9D,uEAAuE;gBACvE,mBAAmB;gBACnB,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE;aAC1C,CAAC;QACJ,CAAC;QAED,SAAS;YACP,OAAO;gBACL;oBACE,GAAG,EAAE,OAAO,OAAO,GAAG;oBACtB,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE;wBACpB,MAAM,IAAI,GAAG,OAAsB,CAAC;wBACpC,OAAO;4BACL,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,IAAI,EAAE;4BACrD,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,IAAI,EAAE;4BACjD,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,IAAI;4BAC9C,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,IAAI,IAAI;4BAClD,aAAa,EAAE,IAAI,CAAC,YAAY,CAAC,sBAAsB,CAAC,IAAI,IAAI;yBACjE,CAAC;oBACJ,CAAC;iBACF;aACF,CAAC;QACJ,CAAC;QAED,UAAU,CAAC,EAAE,cAAc,EAAE;YAC3B,OAAO;gBACL,KAAK;gBACL,eAAe,CAAC,cAAc,EAAE;oBAC9B,CAAC,OAAO,CAAC,EAAE,EAAE;oBACb,iBAAiB,EAAE,cAAc,CAAC,SAAS,IAAI,EAAE;oBACjD,eAAe,EAAE,cAAc,CAAC,OAAO,IAAI,EAAE;oBAC7C,YAAY,EAAE,cAAc,CAAC,KAAK,IAAI,SAAS;oBAC/C,cAAc,EAAE,cAAc,CAAC,OAAO,IAAI,SAAS;oBACnD,sBAAsB,EAAE,cAAc,CAAC,aAAa,IAAI,SAAS;iBAClE,CAAC;aACH,CAAC;QACJ,CAAC;QAED,WAAW;YACT,OAAO,qBAAqB,CAAC,qBAAqB,CAAC,CAAC;QACtD,CAAC;QAED,qBAAqB;YACnB,OAAO;gBACL,IAAI,MAAM,CAAC;oBACT,GAAG,EAAE,SAAS;oBACd,iBAAiB,CAAC,YAAY,EAAE,SAAS,EAAE,QAAQ;wBACjD,iEAAiE;wBACjE,IACE,YAAY,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAChC,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAC/B;4BACD,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,EAC3D,CAAC;4BACD,OAAO,IAAI,CAAC;wBACd,CAAC;wBACD,OAAO,sBAAsB,CAAC,QAAQ,CAAC,CAAC;oBAC1C,CAAC;iBACF,CAAC;aACH,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { createContext, useContext, type ReactNode } from \"react\";\nimport {\n Node,\n NodeViewWrapper,\n ReactNodeViewRenderer,\n mergeAttributes,\n type NodeViewProps,\n} from \"@tiptap/react\";\nimport { Plugin, PluginKey, type EditorState } from \"@tiptap/pm/state\";\nimport { BlockView, useOptionalBlockRegistry } from \"../blocks/index.js\";\n\n/* -------------------------------------------------------------------------- */\n/* The generic registry-block side-map + Tiptap NodeView, lifted into core. */\n/* */\n/* This is the app-agnostic NodeView that renders registered block specs */\n/* inside a `SharedRichEditor` document. Hosts mount the node produced by */\n/* {@link createRegistryBlockNode} as an extra extension and wrap the editor */\n/* in a {@link RegistryBlockDataProvider}, sourcing the typed block `data` */\n/* from their own authoritative store (for example, PlanContent.blocks). The */\n/* node itself carries only lightweight identity attrs (type/id/title/summary) */\n/* plus an optional `__raw` verbatim-MDX attr for byte-stable source */\n/* round-trips; the heavy typed `data` is threaded through the side-map */\n/* context, keeping the doc small and the block data the single source of */\n/* truth. */\n/* -------------------------------------------------------------------------- */\n\n/* -------------------------------------------------------------------------- */\n/* C. Block-data side-map context */\n/* -------------------------------------------------------------------------- */\n\n/** The minimal block shape the NodeView renders through `<BlockView>`. */\nexport interface RegistryBlockSideMapBlock {\n id: string;\n title?: string;\n summary?: string;\n data: unknown;\n}\n\n/**\n * The side-map an editor host supplies so the registry NodeView can resolve a\n * block's full typed `data` (and commit edits) by its stable id, without ever\n * storing that data in the ProseMirror doc.\n */\nexport interface RegistryBlockDataValue<\n TBlock extends RegistryBlockSideMapBlock = RegistryBlockSideMapBlock,\n> {\n /** Resolve a block's full record (incl. `data`) by its stable id. */\n getBlock: (blockId: string) => TBlock | undefined;\n /** Commit a new `data` value for a block (edit-mode only). */\n onBlockDataChange: (blockId: string, nextData: unknown) => void;\n /** Whether the document (and thus its blocks) is editable. */\n editable: boolean;\n /**\n * When true, blocks whose type has no Notion (NFM) analog are badged so the\n * author knows they won't sync. The host decides which types are incompatible\n * via {@link isNotionIncompatibleType}; this flag just toggles the badge on.\n */\n notionSync?: boolean;\n /**\n * Decide whether a block type is Notion-incompatible (no NFM analog). Only\n * consulted when {@link notionSync} is true. Injected by the host so the\n * single registry-level allowlist (plan's `isNotionCompatibleBlockType`, or\n * content's registry-derived gate) drives the badge — core stays policy-free.\n */\n isNotionIncompatibleType?: (blockType: string) => boolean;\n /**\n * Render a block whose type is NOT in the registry through the host's own\n * dispatcher (plan: `PlanBlockView` for decision / legacy visual-questions /\n * image; omitted in hosts with no legacy types), so every block type renders\n * in the document instead of a bare fallback.\n */\n renderLegacyBlock?: (\n block: TBlock,\n options: { editing: boolean },\n ) => ReactNode;\n}\n\nconst RegistryBlockDataContext =\n createContext<RegistryBlockDataValue<any> | null>(null);\n\nexport function RegistryBlockDataProvider<\n TBlock extends RegistryBlockSideMapBlock = RegistryBlockSideMapBlock,\n>({\n value,\n children,\n}: {\n value: RegistryBlockDataValue<TBlock>;\n children: ReactNode;\n}) {\n return (\n <RegistryBlockDataContext.Provider value={value}>\n {children}\n </RegistryBlockDataContext.Provider>\n );\n}\n\n/** Read the registry block side-map. Returns `null` outside a provider. */\nexport function useRegistryBlockData<\n TBlock extends RegistryBlockSideMapBlock = RegistryBlockSideMapBlock,\n>(): RegistryBlockDataValue<TBlock> | null {\n return useContext(\n RegistryBlockDataContext,\n ) as RegistryBlockDataValue<TBlock> | null;\n}\n\n/* -------------------------------------------------------------------------- */\n/* B. RegistryBlockNodeView (React) */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Renders one registry-block atom. The block is non-editable as far as\n * ProseMirror is concerned (`contentEditable={false}`); all interaction happens\n * inside the registry-driven `<BlockView>`. Read vs edit is toggled by\n * `props.selected` (the node is \"selected\" in the editor) AND the document being\n * editable. `data-plan-interactive` keeps existing host click-guards from\n * treating clicks inside the block as document clicks.\n */\nexport function RegistryBlockNodeView(props: NodeViewProps) {\n const blockType = String(props.node.attrs.blockType ?? \"\");\n const blockId = String(props.node.attrs.blockId ?? \"\");\n\n const registryValue = useOptionalBlockRegistry();\n const sideMap = useRegistryBlockData();\n\n const block = sideMap?.getBlock(blockId);\n const editable = sideMap?.editable ?? false;\n const editing = editable && props.selected;\n // In Notion-sync mode, flag blocks that have no Notion (NFM) analog so the\n // author sees what won't push. Prose blocks aren't registry-block nodes, so\n // this only ever covers structured blocks.\n const incompatibleWithNotion =\n (sideMap?.notionSync ?? false) &&\n (sideMap?.isNotionIncompatibleType?.(blockType) ?? false);\n\n // The block data isn't in the side-map yet (e.g. a freshly inserted node whose\n // store entry hasn't been seeded). Render a graceful placeholder.\n if (!block) {\n return (\n <NodeViewWrapper className=\"plan-block-node\" data-block-id={blockId}>\n <div\n contentEditable={false}\n data-plan-interactive\n className=\"plan-block-node__placeholder rounded-md border border-dashed border-border px-3 py-2 text-sm text-muted-foreground\"\n >\n {blockType ? `Loading ${blockType} block…` : \"Loading block…\"}\n </div>\n </NodeViewWrapper>\n );\n }\n\n const spec = registryValue?.registry.get(blockType);\n\n // Choose how to render the block body:\n // 1. Registered spec → the registry `BlockView` (Read, or the spec Edit /\n // auto-form when selected). This is the common path (callout, table,\n // code-tabs, wireframe, …).\n // 2. No spec, but the side-map provides `renderLegacyBlock` → delegate to the\n // host's dispatcher (decision, legacy visual-questions, image, and any\n // other type rendered by a bespoke component rather than the registry), so\n // EVERY block type renders in the document exactly as it does in the\n // per-block reader — never a bare title fallback.\n // 3. Neither → a small non-crashing fallback.\n let body: ReactNode;\n if (registryValue && spec) {\n body = (\n <BlockView\n spec={spec}\n block={{\n id: block.id,\n title: block.title,\n summary: block.summary,\n data: (block as { data: unknown }).data,\n }}\n editing={editing}\n editable={editable}\n onChange={(nextData) => sideMap?.onBlockDataChange(blockId, nextData)}\n ctx={registryValue.ctx}\n />\n );\n } else if (sideMap?.renderLegacyBlock) {\n body = sideMap.renderLegacyBlock(block, { editing });\n } else {\n body = (\n <div className=\"plan-block-node__fallback rounded-md border border-border px-3 py-2 text-sm text-muted-foreground\">\n {block.title || blockType || \"Unsupported block\"}\n </div>\n );\n }\n\n return (\n <NodeViewWrapper\n className=\"plan-block-node\"\n data-block-id={blockId}\n data-notion-incompatible={incompatibleWithNotion ? \"\" : undefined}\n >\n <div contentEditable={false} data-plan-interactive>\n {incompatibleWithNotion && (\n <span\n className=\"plan-block-notion-badge\"\n title=\"This block type has no Notion equivalent and won't sync to Notion.\"\n >\n Won't sync to Notion\n </span>\n )}\n {body}\n </div>\n </NodeViewWrapper>\n );\n}\n\n/* -------------------------------------------------------------------------- */\n/* A. registry-block Tiptap node factory */\n/* -------------------------------------------------------------------------- */\n\n/** Options for {@link createRegistryBlockNode}. */\nexport interface CreateRegistryBlockNodeOptions {\n /**\n * The Tiptap node name (e.g. `\"planBlock\"`). Hosts that serialize the doc by\n * node name (plan's `plan-doc.ts` keys off `\"planBlock\"`) must pass the exact\n * name their serializer expects.\n */\n nodeName: string;\n /**\n * The HTML data-attribute that marks a serialized registry block on copy/paste\n * round-trip (e.g. `\"data-plan-block\"`).\n */\n dataTag: string;\n /**\n * Mint a fresh, unique block id for a given block type. Used by the dedupe\n * plugin to re-mint duplicate / missing ids (paste/duplicate). Plan passes\n * `createPlanBlockId`.\n */\n mintId: (blockType: string) => string;\n /** Node group (default `\"block\"`). */\n group?: string;\n}\n\n/**\n * Build the generic registry-block Tiptap atom node. Returns a Tiptap `Node`\n * that:\n * - carries identity attrs `blockType` / `blockId` / `title` / `summary`, a\n * `sourceBlockId` (set when a duplicate is re-minted, so the host can copy the\n * original block's data), and an optional `__raw` verbatim-MDX attr for\n * byte-stable source round-trips;\n * - is an atom + isolating + draggable block that renders through\n * {@link RegistryBlockNodeView} (via `ReactNodeViewRenderer`);\n * - installs a dedupe `appendTransaction` plugin that re-mints any duplicate or\n * empty `blockId` (the classic paste/duplicate case), preserving the original\n * block's id + side-map data and tagging its own transaction so it never\n * loops.\n */\nexport function createRegistryBlockNode(\n options: CreateRegistryBlockNodeOptions,\n) {\n const { nodeName, dataTag, mintId, group = \"block\" } = options;\n const dedupeKey = new PluginKey(`${nodeName}DedupeIds`);\n\n /**\n * Collect every `blockId` currently present on this node type in a doc, with\n * the position of each node, so duplicate ids (from paste/duplicate) can be\n * detected and re-minted.\n */\n function collectEntries(state: EditorState): Array<{\n pos: number;\n blockType: string;\n blockId: string;\n sourceBlockId?: string;\n }> {\n const found: Array<{\n pos: number;\n blockType: string;\n blockId: string;\n sourceBlockId?: string;\n }> = [];\n state.doc.descendants((node, pos) => {\n if (node.type.name === nodeName) {\n found.push({\n pos,\n blockType: String(node.attrs.blockType ?? \"\"),\n blockId: String(node.attrs.blockId ?? \"\"),\n sourceBlockId:\n typeof node.attrs.sourceBlockId === \"string\"\n ? node.attrs.sourceBlockId\n : undefined,\n });\n }\n return true;\n });\n return found;\n }\n\n /**\n * Build a transaction that re-mints any duplicate / missing ids in `state`, or\n * `null` when nothing needs changing. Only the *later* duplicate (and any node\n * with an empty id) is re-minted, so the original keeps its id and side-map\n * data.\n */\n function buildDedupeTransaction(state: EditorState) {\n const entries = collectEntries(state);\n if (entries.length === 0) return null;\n\n const seen = new Set<string>();\n let tr = state.tr;\n let changed = false;\n\n for (const entry of entries) {\n const needsNewId = !entry.blockId || seen.has(entry.blockId);\n if (needsNewId) {\n const freshId = mintId(entry.blockType || \"block\");\n const node = state.doc.nodeAt(entry.pos);\n if (node) {\n tr = tr.setNodeMarkup(entry.pos, undefined, {\n ...node.attrs,\n blockId: freshId,\n sourceBlockId: entry.sourceBlockId || entry.blockId || null,\n });\n changed = true;\n }\n seen.add(freshId);\n } else {\n seen.add(entry.blockId);\n }\n }\n\n return changed ? tr.setMeta(dedupeKey, true) : null;\n }\n\n return Node.create({\n name: nodeName,\n group,\n atom: true,\n draggable: true,\n selectable: true,\n isolating: true,\n\n addAttributes() {\n return {\n blockType: { default: \"\" },\n blockId: { default: \"\" },\n title: { default: null },\n summary: { default: null },\n sourceBlockId: { default: null },\n // Optional verbatim source for hosts that need byte-identical\n // source-format round-trips without React (server pull, hashing). Plan\n // never sets this.\n __raw: { default: null, rendered: false },\n };\n },\n\n parseHTML() {\n return [\n {\n tag: `div[${dataTag}]`,\n getAttrs: (element) => {\n const node = element as HTMLElement;\n return {\n blockType: node.getAttribute(\"data-block-type\") || \"\",\n blockId: node.getAttribute(\"data-block-id\") || \"\",\n title: node.getAttribute(\"data-title\") || null,\n summary: node.getAttribute(\"data-summary\") || null,\n sourceBlockId: node.getAttribute(\"data-source-block-id\") || null,\n };\n },\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\n \"div\",\n mergeAttributes(HTMLAttributes, {\n [dataTag]: \"\",\n \"data-block-type\": HTMLAttributes.blockType ?? \"\",\n \"data-block-id\": HTMLAttributes.blockId ?? \"\",\n \"data-title\": HTMLAttributes.title ?? undefined,\n \"data-summary\": HTMLAttributes.summary ?? undefined,\n \"data-source-block-id\": HTMLAttributes.sourceBlockId ?? undefined,\n }),\n ];\n },\n\n addNodeView() {\n return ReactNodeViewRenderer(RegistryBlockNodeView);\n },\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: dedupeKey,\n appendTransaction(transactions, _oldState, newState) {\n // Ignore our own re-mint, and skip when nothing changed the doc.\n if (\n transactions.some((transaction) =>\n transaction.getMeta(dedupeKey),\n ) ||\n !transactions.some((transaction) => transaction.docChanged)\n ) {\n return null;\n }\n return buildDedupeTransaction(newState);\n },\n }),\n ];\n },\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"RegistryBlockNode.js","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/RegistryBlockNode.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n createContext,\n useEffect,\n useContext,\n useMemo,\n useState,\n type ReactNode,\n type MouseEvent as ReactMouseEvent,\n} from \"react\";\nimport { IconPencil } from \"@tabler/icons-react\";\nimport {\n Node,\n NodeViewWrapper,\n ReactNodeViewRenderer,\n mergeAttributes,\n type NodeViewProps,\n} from \"@tiptap/react\";\nimport {\n NodeSelection,\n Plugin,\n PluginKey,\n type EditorState,\n} from \"@tiptap/pm/state\";\nimport {\n blockEditSurface,\n useOptionalBlockRegistry,\n type BlockDataChangeMeta,\n type BlockRenderContext,\n} from \"../blocks/index.js\";\nimport { SchemaBlockEditor } from \"../blocks/SchemaBlockEditor.js\";\n\n/* -------------------------------------------------------------------------- */\n/* The generic registry-block side-map + Tiptap NodeView, lifted into core. */\n/* */\n/* This is the app-agnostic NodeView that renders registered block specs */\n/* inside a `SharedRichEditor` document. Hosts mount the node produced by */\n/* {@link createRegistryBlockNode} as an extra extension and wrap the editor */\n/* in a {@link RegistryBlockDataProvider}, sourcing the typed block `data` */\n/* from their own authoritative store (for example, PlanContent.blocks). The */\n/* node itself carries only lightweight identity attrs (type/id/title/summary) */\n/* plus an optional `__raw` verbatim-MDX attr for byte-stable source */\n/* round-trips; the heavy typed `data` is threaded through the side-map */\n/* context, keeping the doc small and the block data the single source of */\n/* truth. */\n/* -------------------------------------------------------------------------- */\n\n/* -------------------------------------------------------------------------- */\n/* C. Block-data side-map context */\n/* -------------------------------------------------------------------------- */\n\n/** The minimal block shape the NodeView renders through `<BlockView>`. */\nexport interface RegistryBlockSideMapBlock {\n id: string;\n title?: string;\n summary?: string;\n data: unknown;\n}\n\n/**\n * The side-map an editor host supplies so the registry NodeView can resolve a\n * block's full typed `data` (and commit edits) by its stable id, without ever\n * storing that data in the ProseMirror doc.\n */\nexport interface RegistryBlockDataValue<\n TBlock extends RegistryBlockSideMapBlock = RegistryBlockSideMapBlock,\n> {\n /** Resolve a block's full record (incl. `data`) by its stable id. */\n getBlock: (blockId: string) => TBlock | undefined;\n /** Commit a new `data` value for a block (edit-mode only). */\n onBlockDataChange: (\n blockId: string,\n nextData: unknown,\n meta?: BlockDataChangeMeta,\n ) => void;\n /** Whether the document (and thus its blocks) is editable. */\n editable: boolean;\n /**\n * When true, blocks whose type has no Notion (NFM) analog are badged so the\n * author knows they won't sync. The host decides which types are incompatible\n * via {@link isNotionIncompatibleType}; this flag just toggles the badge on.\n */\n notionSync?: boolean;\n /**\n * Decide whether a block type is Notion-incompatible (no NFM analog). Only\n * consulted when {@link notionSync} is true. Injected by the host so the\n * single registry-level allowlist (plan's `isNotionCompatibleBlockType`, or\n * content's registry-derived gate) drives the badge — core stays policy-free.\n */\n isNotionIncompatibleType?: (blockType: string) => boolean;\n /**\n * Render a block whose type is NOT in the registry through the host's own\n * dispatcher (plan: `PlanBlockView` for decision / legacy visual-questions /\n * image; omitted in hosts with no legacy types), so every block type renders\n * in the document instead of a bare fallback.\n */\n renderLegacyBlock?: (\n block: TBlock,\n options: { editing: boolean },\n ) => ReactNode;\n}\n\nconst RegistryBlockDataContext =\n createContext<RegistryBlockDataValue<any> | null>(null);\n\nexport function RegistryBlockDataProvider<\n TBlock extends RegistryBlockSideMapBlock = RegistryBlockSideMapBlock,\n>({\n value,\n children,\n}: {\n value: RegistryBlockDataValue<TBlock>;\n children: ReactNode;\n}) {\n return (\n <RegistryBlockDataContext.Provider value={value}>\n {children}\n </RegistryBlockDataContext.Provider>\n );\n}\n\n/** Read the registry block side-map. Returns `null` outside a provider. */\nexport function useRegistryBlockData<\n TBlock extends RegistryBlockSideMapBlock = RegistryBlockSideMapBlock,\n>(): RegistryBlockDataValue<TBlock> | null {\n return useContext(\n RegistryBlockDataContext,\n ) as RegistryBlockDataValue<TBlock> | null;\n}\n\nfunction clickedInteractiveChild(target: HTMLElement) {\n if (target.closest(\"button,input,textarea,select,a,[role='textbox']\")) {\n return true;\n }\n\n const blockNode = target.closest(\".plan-block-node\");\n const editable = target.closest(\"[contenteditable='true']\");\n return !!blockNode && !!editable && blockNode.contains(editable);\n}\n\n/* -------------------------------------------------------------------------- */\n/* B. RegistryBlockNodeView (React) */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Renders one registry-block atom. The block is non-editable as far as\n * ProseMirror is concerned (`contentEditable={false}`); all interaction happens\n * inside the registry-driven `<BlockView>`. Read vs edit is toggled by\n * `props.selected` (the node is \"selected\" in the editor) AND the document being\n * editable. `data-plan-interactive` keeps existing host click-guards from\n * treating clicks inside the block as document clicks.\n */\nexport function RegistryBlockNodeView(props: NodeViewProps) {\n const blockType = String(props.node.attrs.blockType ?? \"\");\n const blockId = String(props.node.attrs.blockId ?? \"\");\n const [panelOpen, setPanelOpen] = useState(false);\n const [shellHovered, setShellHovered] = useState(false);\n\n const registryValue = useOptionalBlockRegistry();\n const sideMap = useRegistryBlockData();\n\n const block = sideMap?.getBlock(blockId);\n const editable = sideMap?.editable ?? false;\n // In Notion-sync mode, flag blocks that have no Notion (NFM) analog so the\n // author sees what won't push. Prose blocks aren't registry-block nodes, so\n // this only ever covers structured blocks.\n const incompatibleWithNotion =\n (sideMap?.notionSync ?? false) &&\n (sideMap?.isNotionIncompatibleType?.(blockType) ?? false);\n\n // The block data isn't in the side-map yet (e.g. a freshly inserted node whose\n // store entry hasn't been seeded). Render a graceful placeholder.\n if (!block) {\n return (\n <NodeViewWrapper className=\"plan-block-node\" data-block-id={blockId}>\n <div\n contentEditable={false}\n data-plan-interactive\n className=\"plan-block-node__placeholder rounded-md border border-dashed border-border px-3 py-2 text-sm text-muted-foreground\"\n >\n {blockType ? `Loading ${blockType} block…` : \"Loading block…\"}\n </div>\n </NodeViewWrapper>\n );\n }\n\n const spec = registryValue?.registry.get(blockType);\n const selectNode = (event: ReactMouseEvent<HTMLElement>) => {\n if (!editable) return;\n const target = event.target;\n if (target instanceof HTMLElement && clickedInteractiveChild(target))\n return;\n const pos = typeof props.getPos === \"function\" ? props.getPos() : null;\n if (typeof pos !== \"number\") return;\n try {\n event.preventDefault();\n event.stopPropagation();\n const { view } = props.editor;\n view.dispatch(\n view.state.tr.setSelection(NodeSelection.create(view.state.doc, pos)),\n );\n view.focus();\n } catch {\n // Ignore stale positions during React/ProseMirror reconciliation.\n }\n };\n const updateShellHover = (event: ReactMouseEvent<HTMLElement>) => {\n const target = event.target;\n setShellHovered(\n target instanceof HTMLElement &&\n target.closest(\".plan-block-node__shell\") === event.currentTarget,\n );\n };\n\n // Choose how to render the block body:\n // 1. Registered spec → read view by default; direct-manipulation specs\n // (`editSurface: \"inline\" | \"container\"`) render their editor in place,\n // while artifact/config specs (`\"panel\"`) keep the read view plus a\n // corner edit button.\n // 2. No spec, but the side-map provides `renderLegacyBlock` → delegate to the\n // host's dispatcher (decision, legacy visual-questions, image, and any\n // other type rendered by a bespoke component rather than the registry), so\n // EVERY block type renders in the document exactly as it does in the\n // per-block reader — never a bare title fallback.\n // 3. Neither → a small non-crashing fallback.\n let body: ReactNode;\n let editSurface: ReactNode = null;\n if (registryValue && spec) {\n const blockData = (block as { data: unknown }).data;\n const Read = spec.Read;\n const readNode = (\n <Read\n data={blockData}\n blockId={block.id}\n title={block.title}\n summary={block.summary}\n ctx={registryValue.ctx}\n />\n );\n body = readNode;\n const canEditBlock =\n editable &&\n spec.placement.includes(\"block\") &&\n !!sideMap?.onBlockDataChange;\n if (canEditBlock) {\n const Edit = spec.Edit;\n const editorNode = Edit ? (\n <Edit\n data={blockData}\n onChange={(nextData, meta) =>\n sideMap?.onBlockDataChange(blockId, nextData, meta)\n }\n editable\n blockId={block.id}\n title={block.title}\n summary={block.summary}\n ctx={registryValue.ctx}\n />\n ) : (\n <SchemaBlockEditor\n data={blockData}\n onChange={(nextData) => sideMap?.onBlockDataChange(blockId, nextData)}\n schema={spec.schema}\n editable\n blockId={block.id}\n ctx={registryValue.ctx}\n />\n );\n const surface = blockEditSurface(spec);\n if (surface === \"panel\" && registryValue.ctx.renderEditSurface) {\n editSurface = registryValue.ctx.renderEditSurface({\n title: spec.label,\n open: panelOpen,\n onOpenChange: setPanelOpen,\n blockId: block.id,\n blockType,\n blockTitle: block.title,\n blockSummary: block.summary,\n blockData,\n trigger: (\n <button\n type=\"button\"\n data-plan-interactive\n aria-label={`Edit ${spec.label}`}\n onClick={() => setPanelOpen(true)}\n className=\"an-block-edit-trigger flex size-7 items-center justify-center rounded-md border border-border bg-background/85 text-muted-foreground opacity-0 shadow-sm backdrop-blur transition-opacity hover:bg-muted hover:text-foreground focus-visible:opacity-100 data-[visible=true]:opacity-100\"\n data-visible={panelOpen || shellHovered}\n >\n <IconPencil className=\"size-4\" />\n </button>\n ),\n children: editorNode,\n });\n } else if (surface === \"panel\") {\n editSurface = props.selected ? (\n <div className=\"mt-3\">{editorNode}</div>\n ) : null;\n } else {\n body = editorNode;\n }\n }\n } else if (sideMap?.renderLegacyBlock) {\n body = sideMap.renderLegacyBlock(block, { editing: false });\n if (editable && sideMap.onBlockDataChange) {\n editSurface = (\n <LegacyJsonEditSurface\n block={block}\n open={panelOpen}\n onOpenChange={setPanelOpen}\n renderEditSurface={registryValue?.ctx.renderEditSurface}\n onChange={(nextBlock) =>\n sideMap.onBlockDataChange(blockId, nextBlock)\n }\n selected={shellHovered}\n />\n );\n }\n } else {\n body = (\n <div className=\"plan-block-node__fallback rounded-md border border-border px-3 py-2 text-sm text-muted-foreground\">\n {block.title || blockType || \"Unsupported block\"}\n </div>\n );\n }\n\n return (\n <NodeViewWrapper\n className=\"plan-block-node\"\n data-block-id={blockId}\n data-plan-block-selected={props.selected ? \"\" : undefined}\n data-notion-incompatible={incompatibleWithNotion ? \"\" : undefined}\n onMouseDownCapture={selectNode}\n >\n <div\n contentEditable={false}\n data-plan-interactive\n className=\"plan-block-node__shell relative\"\n onMouseEnter={updateShellHover}\n onMouseMove={updateShellHover}\n onMouseLeave={() => setShellHovered(false)}\n >\n {incompatibleWithNotion && (\n <span\n className=\"plan-block-notion-badge\"\n title=\"This block type has no Notion equivalent and won't sync to Notion.\"\n >\n Won't sync to Notion\n </span>\n )}\n {body}\n {editSurface && (\n <div className=\"plan-block-node__edit absolute right-2 top-2 z-20\">\n {editSurface}\n </div>\n )}\n </div>\n </NodeViewWrapper>\n );\n}\n\nexport function LegacyJsonEditSurface({\n block,\n open,\n onOpenChange,\n renderEditSurface,\n onChange,\n selected,\n}: {\n block: RegistryBlockSideMapBlock;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n renderEditSurface?: BlockRenderContext[\"renderEditSurface\"];\n onChange: (nextData: unknown) => void;\n selected: boolean;\n}) {\n const serializedBlockData = useMemo(\n () => JSON.stringify(block.data, null, 2),\n [block.data],\n );\n const [draft, setDraft] = useState(serializedBlockData);\n const [parseError, setParseError] = useState<string | null>(null);\n\n useEffect(() => {\n setDraft(serializedBlockData);\n setParseError(null);\n }, [block.id, serializedBlockData]);\n\n const saveDraft = () => {\n try {\n const nextData = JSON.parse(draft) as unknown;\n setParseError(null);\n onChange(nextData);\n onOpenChange(false);\n } catch (error) {\n setParseError(\n error instanceof Error ? error.message : \"Invalid JSON data.\",\n );\n }\n };\n\n const trigger = (\n <button\n type=\"button\"\n data-plan-interactive\n aria-label={`Edit ${block.title ?? \"block\"}`}\n onClick={() => onOpenChange(true)}\n className=\"an-block-edit-trigger flex size-7 items-center justify-center rounded-md border border-border bg-background/85 text-muted-foreground opacity-0 shadow-sm backdrop-blur transition-opacity hover:bg-muted hover:text-foreground focus-visible:opacity-100 data-[visible=true]:opacity-100\"\n data-visible={selected || open}\n >\n <IconPencil className=\"size-4\" />\n </button>\n );\n const editor = (\n <div className=\"grid gap-3\">\n <textarea\n data-plan-interactive\n className=\"min-h-64 w-full rounded-md border border-input bg-background px-3 py-2 font-mono text-xs leading-5 text-foreground shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n value={draft}\n aria-invalid={parseError ? true : undefined}\n onChange={(event) => {\n setDraft(event.target.value);\n if (parseError) setParseError(null);\n }}\n />\n {parseError ? (\n <p className=\"text-xs text-destructive\" role=\"alert\">\n Invalid JSON: {parseError}\n </p>\n ) : null}\n <button\n type=\"button\"\n data-plan-interactive\n className=\"inline-flex h-8 items-center justify-center rounded-md bg-primary px-3 text-xs font-medium text-primary-foreground\"\n onClick={saveDraft}\n >\n Save\n </button>\n </div>\n );\n if (!renderEditSurface) return open ? editor : trigger;\n return renderEditSurface({\n title: block.title ?? \"Block\",\n open,\n onOpenChange,\n blockId: block.id,\n blockType:\n typeof (block as { type?: unknown }).type === \"string\"\n ? ((block as unknown as { type: string }).type ?? \"\")\n : \"legacy\",\n blockTitle: block.title,\n blockSummary: block.summary,\n blockData: block.data,\n trigger,\n children: editor,\n });\n}\n\n/* -------------------------------------------------------------------------- */\n/* A. registry-block Tiptap node factory */\n/* -------------------------------------------------------------------------- */\n\n/** Options for {@link createRegistryBlockNode}. */\nexport interface CreateRegistryBlockNodeOptions {\n /**\n * The Tiptap node name (e.g. `\"planBlock\"`). Hosts that serialize the doc by\n * node name (plan's `plan-doc.ts` keys off `\"planBlock\"`) must pass the exact\n * name their serializer expects.\n */\n nodeName: string;\n /**\n * The HTML data-attribute that marks a serialized registry block on copy/paste\n * round-trip (e.g. `\"data-plan-block\"`).\n */\n dataTag: string;\n /**\n * Mint a fresh, unique block id for a given block type. Used by the dedupe\n * plugin to re-mint duplicate / missing ids (paste/duplicate). Plan passes\n * `createPlanBlockId`.\n */\n mintId: (blockType: string) => string;\n /** Node group (default `\"block\"`). */\n group?: string;\n}\n\n/**\n * Build the generic registry-block Tiptap atom node. Returns a Tiptap `Node`\n * that:\n * - carries identity attrs `blockType` / `blockId` / `title` / `summary`, a\n * `sourceBlockId` (set when a duplicate is re-minted, so the host can copy the\n * original block's data), and an optional `__raw` verbatim-MDX attr for\n * byte-stable source round-trips;\n * - is an atom + isolating + draggable block that renders through\n * {@link RegistryBlockNodeView} (via `ReactNodeViewRenderer`);\n * - installs a dedupe `appendTransaction` plugin that re-mints any duplicate or\n * empty `blockId` (the classic paste/duplicate case), preserving the original\n * block's id + side-map data and tagging its own transaction so it never\n * loops.\n */\nexport function createRegistryBlockNode(\n options: CreateRegistryBlockNodeOptions,\n) {\n const { nodeName, dataTag, mintId, group = \"block\" } = options;\n const dedupeKey = new PluginKey(`${nodeName}DedupeIds`);\n const keyboardGuardKey = new PluginKey(`${nodeName}KeyboardGuard`);\n\n /**\n * Collect every `blockId` currently present on this node type in a doc, with\n * the position of each node, so duplicate ids (from paste/duplicate) can be\n * detected and re-minted.\n */\n function collectEntries(state: EditorState): Array<{\n pos: number;\n blockType: string;\n blockId: string;\n sourceBlockId?: string;\n }> {\n const found: Array<{\n pos: number;\n blockType: string;\n blockId: string;\n sourceBlockId?: string;\n }> = [];\n state.doc.descendants((node, pos) => {\n if (node.type.name === nodeName) {\n found.push({\n pos,\n blockType: String(node.attrs.blockType ?? \"\"),\n blockId: String(node.attrs.blockId ?? \"\"),\n sourceBlockId:\n typeof node.attrs.sourceBlockId === \"string\"\n ? node.attrs.sourceBlockId\n : undefined,\n });\n }\n return true;\n });\n return found;\n }\n\n /**\n * Build a transaction that re-mints any duplicate / missing ids in `state`, or\n * `null` when nothing needs changing. Only the *later* duplicate (and any node\n * with an empty id) is re-minted, so the original keeps its id and side-map\n * data.\n */\n function buildDedupeTransaction(state: EditorState) {\n const entries = collectEntries(state);\n if (entries.length === 0) return null;\n\n const seen = new Set<string>();\n let tr = state.tr;\n let changed = false;\n\n for (const entry of entries) {\n const needsNewId = !entry.blockId || seen.has(entry.blockId);\n if (needsNewId) {\n const freshId = mintId(entry.blockType || \"block\");\n const node = state.doc.nodeAt(entry.pos);\n if (node) {\n tr = tr.setNodeMarkup(entry.pos, undefined, {\n ...node.attrs,\n blockId: freshId,\n sourceBlockId: entry.sourceBlockId || entry.blockId || null,\n });\n changed = true;\n }\n seen.add(freshId);\n } else {\n seen.add(entry.blockId);\n }\n }\n\n return changed ? tr.setMeta(dedupeKey, true) : null;\n }\n\n const selectedRegistryBlock = (state: EditorState) =>\n state.selection instanceof NodeSelection &&\n state.selection.node.type.name === nodeName;\n\n const isMutatingKey = (event: KeyboardEvent) => {\n if (event.altKey || event.ctrlKey || event.metaKey) return false;\n if (event.key === \"Enter\") return true;\n return event.key.length === 1;\n };\n\n return Node.create({\n name: nodeName,\n group,\n atom: true,\n draggable: true,\n selectable: true,\n isolating: true,\n\n addAttributes() {\n return {\n blockType: { default: \"\" },\n blockId: { default: \"\" },\n title: { default: null },\n summary: { default: null },\n sourceBlockId: { default: null },\n // Optional verbatim source for hosts that need byte-identical\n // source-format round-trips without React (server pull, hashing). Plan\n // never sets this.\n __raw: { default: null, rendered: false },\n };\n },\n\n parseHTML() {\n return [\n {\n tag: `div[${dataTag}]`,\n getAttrs: (element) => {\n const node = element as HTMLElement;\n return {\n blockType: node.getAttribute(\"data-block-type\") || \"\",\n blockId: node.getAttribute(\"data-block-id\") || \"\",\n title: node.getAttribute(\"data-title\") || null,\n summary: node.getAttribute(\"data-summary\") || null,\n sourceBlockId: node.getAttribute(\"data-source-block-id\") || null,\n };\n },\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\n \"div\",\n mergeAttributes(HTMLAttributes, {\n [dataTag]: \"\",\n \"data-block-type\": HTMLAttributes.blockType ?? \"\",\n \"data-block-id\": HTMLAttributes.blockId ?? \"\",\n \"data-title\": HTMLAttributes.title ?? undefined,\n \"data-summary\": HTMLAttributes.summary ?? undefined,\n \"data-source-block-id\": HTMLAttributes.sourceBlockId ?? undefined,\n }),\n ];\n },\n\n addNodeView() {\n return ReactNodeViewRenderer(RegistryBlockNodeView);\n },\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: dedupeKey,\n appendTransaction(transactions, _oldState, newState) {\n // Ignore our own re-mint, and skip when nothing changed the doc.\n if (\n transactions.some((transaction) =>\n transaction.getMeta(dedupeKey),\n ) ||\n !transactions.some((transaction) => transaction.docChanged)\n ) {\n return null;\n }\n return buildDedupeTransaction(newState);\n },\n }),\n new Plugin({\n key: keyboardGuardKey,\n props: {\n handleClickOn(view, _pos, node, nodePos, event, direct) {\n if (node.type.name !== nodeName || !direct) return false;\n if (\n event.target instanceof HTMLElement &&\n clickedInteractiveChild(event.target)\n ) {\n return false;\n }\n event.preventDefault();\n view.dispatch(\n view.state.tr.setSelection(\n NodeSelection.create(view.state.doc, nodePos),\n ),\n );\n view.focus();\n return true;\n },\n handleKeyDown(view, event) {\n if (!selectedRegistryBlock(view.state) || !isMutatingKey(event))\n return false;\n event.preventDefault();\n return true;\n },\n handleTextInput(view) {\n return selectedRegistryBlock(view.state);\n },\n handlePaste(view, event) {\n if (!selectedRegistryBlock(view.state)) return false;\n event.preventDefault();\n return true;\n },\n handleDOMEvents: {\n beforeinput(view, event) {\n if (!selectedRegistryBlock(view.state)) return false;\n const inputEvent = event as InputEvent;\n if (\n !inputEvent.inputType ||\n (!inputEvent.inputType.startsWith(\"insert\") &&\n inputEvent.inputType !== \"formatSetBlockTextDirection\")\n ) {\n return false;\n }\n event.preventDefault();\n return true;\n },\n },\n },\n }),\n ];\n },\n });\n}\n"]}
|
|
@@ -29,6 +29,7 @@ export interface SharedRichEditorProps {
|
|
|
29
29
|
placeholder?: string;
|
|
30
30
|
className?: string;
|
|
31
31
|
editorClassName?: string;
|
|
32
|
+
ariaLabel?: string;
|
|
32
33
|
interactive?: boolean;
|
|
33
34
|
/**
|
|
34
35
|
* Yjs document for real-time multi-user editing. When provided, prose is
|
|
@@ -81,5 +82,5 @@ export interface SharedRichEditorProps {
|
|
|
81
82
|
* With a `ydoc` it binds the framework collaboration stack; markdown stays the
|
|
82
83
|
* canonical saved representation while the Y.Doc is transient live state.
|
|
83
84
|
*/
|
|
84
|
-
export declare function SharedRichEditor({ value, onChange, onBlur, contentUpdatedAt, editable, dialect, preset, features, onImageUpload, extraExtensions, placeholder, className, editorClassName, interactive, ydoc, awareness, user, slashItems, buildBubbleItems, getMarkdown, setContent, normalizeValue, shouldSeed, initialAppliedUpdatedAt, wrapperClassName, }: SharedRichEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
85
|
+
export declare function SharedRichEditor({ value, onChange, onBlur, contentUpdatedAt, editable, dialect, preset, features, onImageUpload, extraExtensions, placeholder, className, editorClassName, ariaLabel, interactive, ydoc, awareness, user, slashItems, buildBubbleItems, getMarkdown, setContent, normalizeValue, shouldSeed, initialAppliedUpdatedAt, wrapperClassName, }: SharedRichEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
85
86
|
//# sourceMappingURL=SharedRichEditor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SharedRichEditor.d.ts","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/SharedRichEditor.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"SharedRichEditor.d.ts","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/SharedRichEditor.tsx"],"names":[],"mappings":"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"}
|
|
@@ -17,7 +17,7 @@ import { BubbleToolbar } from "./BubbleToolbar.js";
|
|
|
17
17
|
* With a `ydoc` it binds the framework collaboration stack; markdown stays the
|
|
18
18
|
* canonical saved representation while the Y.Doc is transient live state.
|
|
19
19
|
*/
|
|
20
|
-
export function SharedRichEditor({ value, onChange, onBlur, contentUpdatedAt, editable = true, dialect = "gfm", preset = "plan", features, onImageUpload = null, extraExtensions, placeholder = "Type '/' for commands...", className, editorClassName, interactive = editable, ydoc = null, awareness = null, user = null, slashItems, buildBubbleItems, getMarkdown, setContent, normalizeValue, shouldSeed, initialAppliedUpdatedAt, wrapperClassName, }) {
|
|
20
|
+
export function SharedRichEditor({ value, onChange, onBlur, contentUpdatedAt, editable = true, dialect = "gfm", preset = "plan", features, onImageUpload = null, extraExtensions, placeholder = "Type '/' for commands...", className, editorClassName, ariaLabel, interactive = editable, ydoc = null, awareness = null, user = null, slashItems, buildBubbleItems, getMarkdown, setContent, normalizeValue, shouldSeed, initialAppliedUpdatedAt, wrapperClassName, }) {
|
|
21
21
|
const readMarkdown = getMarkdown ?? getEditorMarkdown;
|
|
22
22
|
const onChangeRef = useRef(onChange);
|
|
23
23
|
const onBlurRef = useRef(onBlur);
|
|
@@ -73,6 +73,8 @@ export function SharedRichEditor({ value, onChange, onBlur, contentUpdatedAt, ed
|
|
|
73
73
|
editorProps: {
|
|
74
74
|
attributes: {
|
|
75
75
|
class: cn("an-rich-md-prose", editorClassName),
|
|
76
|
+
role: ariaLabel ? "textbox" : undefined,
|
|
77
|
+
"aria-label": ariaLabel,
|
|
76
78
|
},
|
|
77
79
|
},
|
|
78
80
|
onUpdate: ({ editor, transaction }) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SharedRichEditor.js","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/SharedRichEditor.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useMemo, useRef } from \"react\";\nimport { EditorContent, useEditor } from \"@tiptap/react\";\nimport type { Extension, Node, Mark } from \"@tiptap/core\";\nimport type { Doc as YDoc } from \"yjs\";\nimport type { Awareness } from \"y-protocols/awareness\";\nimport { cn } from \"../utils.js\";\nimport {\n createSharedEditorExtensions,\n type RichMarkdownDialect,\n type RichMarkdownEditorPreset,\n type RichMarkdownCollabUser,\n type SharedEditorFeatures,\n} from \"./extensions.js\";\nimport type { ImageUploadFn } from \"./ImageExtension.js\";\nimport {\n useCollabReconcile,\n getEditorMarkdown,\n type UseCollabReconcileResult,\n} from \"./useCollabReconcile.js\";\nimport { SlashCommandMenu, type SlashCommandItem } from \"./SlashCommandMenu.js\";\nimport { BubbleToolbar, type BubbleToolbarItem } from \"./BubbleToolbar.js\";\n\nexport interface SharedRichEditorProps {\n value: string;\n onChange: (markdown: string) => void;\n onBlur?: () => void;\n contentUpdatedAt?: string | null;\n editable?: boolean;\n dialect?: RichMarkdownDialect;\n preset?: RichMarkdownEditorPreset;\n /** Toggle individual base extensions (tables/tasks/link/codeBlock/image). */\n features?: SharedEditorFeatures;\n /**\n * Injectable image uploader for the shared image block. Used only when\n * `features.image` is on. Pass `uploadEditorImage` (the framework\n * `upload-image` action) for a real uploading image block.\n */\n onImageUpload?: ImageUploadFn | null;\n /**\n * App-specific extensions (Notion nodes, media, drag handles, comment\n * anchors, …) appended after the shared base schema.\n */\n extraExtensions?: Array<Extension | Node | Mark>;\n placeholder?: string;\n className?: string;\n editorClassName?: string;\n interactive?: boolean;\n /**\n * Yjs document for real-time multi-user editing. When provided, prose is\n * authored against the shared Y.Doc and mirrored back to `value` as markdown\n * (still the source of truth). When omitted, the editor is a plain controlled\n * `value`/`onChange` editor — the existing, non-collaborative behavior.\n */\n ydoc?: YDoc | null;\n /** Shared awareness instance for live cursors/presence. */\n awareness?: Awareness | null;\n /** Current user info for the collaborative cursor label. */\n user?: RichMarkdownCollabUser | null;\n /** Override the slash-menu block command list. */\n slashItems?: SlashCommandItem[];\n /** Override the bubble-toolbar item builder. */\n buildBubbleItems?: (\n editor: import(\"@tiptap/react\").Editor,\n toggleLink: () => void,\n ) => BubbleToolbarItem[];\n /**\n * Override how the editor's content is read into the canonical `value`.\n * Defaults to the tiptap-markdown storage reader. Apps with a custom on-disk\n * format (Content's NFM, the plan's `blocks[]` JSON) pass their serializer so\n * seed/reconcile/onChange all speak the same value space.\n */\n getMarkdown?: (editor: import(\"@tiptap/react\").Editor) => string;\n /** Override how the canonical `value` is applied into the editor (seed + reconcile). */\n setContent?: (\n editor: import(\"@tiptap/react\").Editor,\n value: string,\n options: { emitUpdate?: boolean; addToHistory?: boolean },\n ) => void;\n /** Canonicalize `value` for the echo / already-in-sync equality checks. */\n normalizeValue?: (value: string) => string;\n /** Override the empty-doc seed predicate (see {@link useCollabReconcile}). */\n shouldSeed?: (info: {\n value: string;\n currentMarkdown: string;\n fragmentLength: number;\n }) => boolean;\n /** Initial \"applied\" watermark (see {@link useCollabReconcile}). */\n initialAppliedUpdatedAt?: string | null;\n /** Extra class on the editor wrapper (e.g. a drag-handle `wrapperSelector` hook). */\n wrapperClassName?: string;\n}\n\n/**\n * The single shared rich markdown editor surface. Combines\n * {@link createSharedEditorExtensions} (schema + dialect-keyed markdown +\n * optional collab + app extras), {@link useCollabReconcile} (seed / reconcile /\n * lead-client logic), and the shared {@link SlashCommandMenu} +\n * {@link BubbleToolbar}.\n *\n * With no `ydoc` it is a controlled `value`/`onChange` single-user editor.\n * With a `ydoc` it binds the framework collaboration stack; markdown stays the\n * canonical saved representation while the Y.Doc is transient live state.\n */\nexport function SharedRichEditor({\n value,\n onChange,\n onBlur,\n contentUpdatedAt,\n editable = true,\n dialect = \"gfm\",\n preset = \"plan\",\n features,\n onImageUpload = null,\n extraExtensions,\n placeholder = \"Type '/' for commands...\",\n className,\n editorClassName,\n interactive = editable,\n ydoc = null,\n awareness = null,\n user = null,\n slashItems,\n buildBubbleItems,\n getMarkdown,\n setContent,\n normalizeValue,\n shouldSeed,\n initialAppliedUpdatedAt,\n wrapperClassName,\n}: SharedRichEditorProps) {\n const readMarkdown = getMarkdown ?? getEditorMarkdown;\n const onChangeRef = useRef(onChange);\n const onBlurRef = useRef(onBlur);\n onChangeRef.current = onChange;\n onBlurRef.current = onBlur;\n\n const extensions = useMemo(\n () =>\n createSharedEditorExtensions({\n dialect,\n preset,\n placeholder,\n features,\n extraExtensions,\n onImageUpload,\n collab: ydoc ? { ydoc, awareness, user } : null,\n }),\n // `preset` is retained in the dependency list so future preset-specific\n // schema branches re-create the editor; it is currently schema-neutral. The\n // collab inputs are identity-stable per block (one Y.Doc per docId), so they\n // only change on a genuine doc switch — exactly when the editor must\n // re-create to rebind Collaboration.\n [\n dialect,\n placeholder,\n preset,\n features,\n extraExtensions,\n onImageUpload,\n ydoc,\n awareness,\n user?.name,\n user?.email,\n user?.color,\n ],\n );\n\n const collab = !!ydoc;\n\n // The collab hook needs the editor, but useEditor's `onUpdate` needs the\n // hook's guards. Break the cycle with a ref: `onUpdate` reads the guards\n // through `guardsRef`, which is populated right after the hook runs below.\n // `onUpdate` only ever fires after the editor exists, by which point the ref\n // holds the real guards.\n const guardsRef = useRef<UseCollabReconcileResult | null>(null);\n\n const editor = useEditor({\n extensions,\n // With Collaboration active the prose is owned by the shared Y.XmlFragment.\n // Seeding `content` here too would make the editor initialize from BOTH the\n // prop and the Y.Doc, firing a spurious initial update that could autosave a\n // stale value over newer SQL. The lead-client seed effect populates an empty\n // doc instead. Non-collab editors keep initializing from `value`.\n // With Collaboration the Y.Doc owns the prose (seeded by the lead client).\n // With a custom `setContent` the reconcile seeds the editor too (the raw\n // `value` is not directly settable content — e.g. the plan's blocks JSON),\n // so only the plain markdown path seeds from `value` here.\n content: collab || setContent ? undefined : value,\n editable,\n editorProps: {\n attributes: {\n class: cn(\"an-rich-md-prose\", editorClassName),\n },\n },\n onUpdate: ({ editor, transaction }) => {\n const guards = guardsRef.current;\n if (!guards || guards.shouldIgnoreUpdate(transaction)) return;\n try {\n const markdown = readMarkdown(editor);\n if (!guards.registerEmitted(markdown)) return;\n queueMicrotask(() => onChangeRef.current(markdown));\n } catch (error) {\n console.error(\"Markdown serialization error:\", error);\n }\n },\n onBlur: () => {\n onBlurRef.current?.();\n },\n });\n\n const collabState = useCollabReconcile({\n editor,\n ydoc,\n awareness,\n value,\n contentUpdatedAt,\n editable,\n getMarkdown: readMarkdown,\n setContent,\n normalizeValue,\n shouldSeed,\n initialAppliedUpdatedAt,\n });\n guardsRef.current = collabState;\n\n useEffect(() => {\n if (!editor || editor.isDestroyed) return;\n editor.setEditable(editable);\n }, [editable, editor]);\n\n useEffect(() => () => editor?.destroy(), [editor]);\n\n const handleWrapperClick = (event: React.MouseEvent<HTMLDivElement>) => {\n if (!editable || !editor || editor.isDestroyed) return;\n const target = event.target as HTMLElement;\n if (\n target.classList.contains(\"an-rich-md-wrapper\") ||\n target.classList.contains(\"an-rich-md-clickable\")\n ) {\n editor.chain().focus(\"end\").run();\n }\n };\n\n if (!editor) {\n return (\n <div\n className={cn(\"an-rich-md-wrapper an-rich-md-loading\", className)}\n data-plan-interactive={interactive ? true : undefined}\n />\n );\n }\n\n return (\n <div\n className={cn(\n \"an-rich-md-wrapper an-rich-md-clickable\",\n !editable && \"an-rich-md-wrapper--readonly\",\n wrapperClassName,\n className,\n )}\n onClick={handleWrapperClick}\n data-plan-interactive={interactive ? true : undefined}\n >\n {editable ? (\n <BubbleToolbar editor={editor} buildItems={buildBubbleItems} />\n ) : null}\n {editable ? (\n <SlashCommandMenu editor={editor} items={slashItems} />\n ) : null}\n <EditorContent editor={editor} />\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"SharedRichEditor.js","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/SharedRichEditor.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useMemo, useRef } from \"react\";\nimport { EditorContent, useEditor } from \"@tiptap/react\";\nimport type { Extension, Node, Mark } from \"@tiptap/core\";\nimport type { Doc as YDoc } from \"yjs\";\nimport type { Awareness } from \"y-protocols/awareness\";\nimport { cn } from \"../utils.js\";\nimport {\n createSharedEditorExtensions,\n type RichMarkdownDialect,\n type RichMarkdownEditorPreset,\n type RichMarkdownCollabUser,\n type SharedEditorFeatures,\n} from \"./extensions.js\";\nimport type { ImageUploadFn } from \"./ImageExtension.js\";\nimport {\n useCollabReconcile,\n getEditorMarkdown,\n type UseCollabReconcileResult,\n} from \"./useCollabReconcile.js\";\nimport { SlashCommandMenu, type SlashCommandItem } from \"./SlashCommandMenu.js\";\nimport { BubbleToolbar, type BubbleToolbarItem } from \"./BubbleToolbar.js\";\n\nexport interface SharedRichEditorProps {\n value: string;\n onChange: (markdown: string) => void;\n onBlur?: () => void;\n contentUpdatedAt?: string | null;\n editable?: boolean;\n dialect?: RichMarkdownDialect;\n preset?: RichMarkdownEditorPreset;\n /** Toggle individual base extensions (tables/tasks/link/codeBlock/image). */\n features?: SharedEditorFeatures;\n /**\n * Injectable image uploader for the shared image block. Used only when\n * `features.image` is on. Pass `uploadEditorImage` (the framework\n * `upload-image` action) for a real uploading image block.\n */\n onImageUpload?: ImageUploadFn | null;\n /**\n * App-specific extensions (Notion nodes, media, drag handles, comment\n * anchors, …) appended after the shared base schema.\n */\n extraExtensions?: Array<Extension | Node | Mark>;\n placeholder?: string;\n className?: string;\n editorClassName?: string;\n ariaLabel?: string;\n interactive?: boolean;\n /**\n * Yjs document for real-time multi-user editing. When provided, prose is\n * authored against the shared Y.Doc and mirrored back to `value` as markdown\n * (still the source of truth). When omitted, the editor is a plain controlled\n * `value`/`onChange` editor — the existing, non-collaborative behavior.\n */\n ydoc?: YDoc | null;\n /** Shared awareness instance for live cursors/presence. */\n awareness?: Awareness | null;\n /** Current user info for the collaborative cursor label. */\n user?: RichMarkdownCollabUser | null;\n /** Override the slash-menu block command list. */\n slashItems?: SlashCommandItem[];\n /** Override the bubble-toolbar item builder. */\n buildBubbleItems?: (\n editor: import(\"@tiptap/react\").Editor,\n toggleLink: () => void,\n ) => BubbleToolbarItem[];\n /**\n * Override how the editor's content is read into the canonical `value`.\n * Defaults to the tiptap-markdown storage reader. Apps with a custom on-disk\n * format (Content's NFM, the plan's `blocks[]` JSON) pass their serializer so\n * seed/reconcile/onChange all speak the same value space.\n */\n getMarkdown?: (editor: import(\"@tiptap/react\").Editor) => string;\n /** Override how the canonical `value` is applied into the editor (seed + reconcile). */\n setContent?: (\n editor: import(\"@tiptap/react\").Editor,\n value: string,\n options: { emitUpdate?: boolean; addToHistory?: boolean },\n ) => void;\n /** Canonicalize `value` for the echo / already-in-sync equality checks. */\n normalizeValue?: (value: string) => string;\n /** Override the empty-doc seed predicate (see {@link useCollabReconcile}). */\n shouldSeed?: (info: {\n value: string;\n currentMarkdown: string;\n fragmentLength: number;\n }) => boolean;\n /** Initial \"applied\" watermark (see {@link useCollabReconcile}). */\n initialAppliedUpdatedAt?: string | null;\n /** Extra class on the editor wrapper (e.g. a drag-handle `wrapperSelector` hook). */\n wrapperClassName?: string;\n}\n\n/**\n * The single shared rich markdown editor surface. Combines\n * {@link createSharedEditorExtensions} (schema + dialect-keyed markdown +\n * optional collab + app extras), {@link useCollabReconcile} (seed / reconcile /\n * lead-client logic), and the shared {@link SlashCommandMenu} +\n * {@link BubbleToolbar}.\n *\n * With no `ydoc` it is a controlled `value`/`onChange` single-user editor.\n * With a `ydoc` it binds the framework collaboration stack; markdown stays the\n * canonical saved representation while the Y.Doc is transient live state.\n */\nexport function SharedRichEditor({\n value,\n onChange,\n onBlur,\n contentUpdatedAt,\n editable = true,\n dialect = \"gfm\",\n preset = \"plan\",\n features,\n onImageUpload = null,\n extraExtensions,\n placeholder = \"Type '/' for commands...\",\n className,\n editorClassName,\n ariaLabel,\n interactive = editable,\n ydoc = null,\n awareness = null,\n user = null,\n slashItems,\n buildBubbleItems,\n getMarkdown,\n setContent,\n normalizeValue,\n shouldSeed,\n initialAppliedUpdatedAt,\n wrapperClassName,\n}: SharedRichEditorProps) {\n const readMarkdown = getMarkdown ?? getEditorMarkdown;\n const onChangeRef = useRef(onChange);\n const onBlurRef = useRef(onBlur);\n onChangeRef.current = onChange;\n onBlurRef.current = onBlur;\n\n const extensions = useMemo(\n () =>\n createSharedEditorExtensions({\n dialect,\n preset,\n placeholder,\n features,\n extraExtensions,\n onImageUpload,\n collab: ydoc ? { ydoc, awareness, user } : null,\n }),\n // `preset` is retained in the dependency list so future preset-specific\n // schema branches re-create the editor; it is currently schema-neutral. The\n // collab inputs are identity-stable per block (one Y.Doc per docId), so they\n // only change on a genuine doc switch — exactly when the editor must\n // re-create to rebind Collaboration.\n [\n dialect,\n placeholder,\n preset,\n features,\n extraExtensions,\n onImageUpload,\n ydoc,\n awareness,\n user?.name,\n user?.email,\n user?.color,\n ],\n );\n\n const collab = !!ydoc;\n\n // The collab hook needs the editor, but useEditor's `onUpdate` needs the\n // hook's guards. Break the cycle with a ref: `onUpdate` reads the guards\n // through `guardsRef`, which is populated right after the hook runs below.\n // `onUpdate` only ever fires after the editor exists, by which point the ref\n // holds the real guards.\n const guardsRef = useRef<UseCollabReconcileResult | null>(null);\n\n const editor = useEditor({\n extensions,\n // With Collaboration active the prose is owned by the shared Y.XmlFragment.\n // Seeding `content` here too would make the editor initialize from BOTH the\n // prop and the Y.Doc, firing a spurious initial update that could autosave a\n // stale value over newer SQL. The lead-client seed effect populates an empty\n // doc instead. Non-collab editors keep initializing from `value`.\n // With Collaboration the Y.Doc owns the prose (seeded by the lead client).\n // With a custom `setContent` the reconcile seeds the editor too (the raw\n // `value` is not directly settable content — e.g. the plan's blocks JSON),\n // so only the plain markdown path seeds from `value` here.\n content: collab || setContent ? undefined : value,\n editable,\n editorProps: {\n attributes: {\n class: cn(\"an-rich-md-prose\", editorClassName),\n role: ariaLabel ? \"textbox\" : undefined,\n \"aria-label\": ariaLabel,\n },\n },\n onUpdate: ({ editor, transaction }) => {\n const guards = guardsRef.current;\n if (!guards || guards.shouldIgnoreUpdate(transaction)) return;\n try {\n const markdown = readMarkdown(editor);\n if (!guards.registerEmitted(markdown)) return;\n queueMicrotask(() => onChangeRef.current(markdown));\n } catch (error) {\n console.error(\"Markdown serialization error:\", error);\n }\n },\n onBlur: () => {\n onBlurRef.current?.();\n },\n });\n\n const collabState = useCollabReconcile({\n editor,\n ydoc,\n awareness,\n value,\n contentUpdatedAt,\n editable,\n getMarkdown: readMarkdown,\n setContent,\n normalizeValue,\n shouldSeed,\n initialAppliedUpdatedAt,\n });\n guardsRef.current = collabState;\n\n useEffect(() => {\n if (!editor || editor.isDestroyed) return;\n editor.setEditable(editable);\n }, [editable, editor]);\n\n useEffect(() => () => editor?.destroy(), [editor]);\n\n const handleWrapperClick = (event: React.MouseEvent<HTMLDivElement>) => {\n if (!editable || !editor || editor.isDestroyed) return;\n const target = event.target as HTMLElement;\n if (\n target.classList.contains(\"an-rich-md-wrapper\") ||\n target.classList.contains(\"an-rich-md-clickable\")\n ) {\n editor.chain().focus(\"end\").run();\n }\n };\n\n if (!editor) {\n return (\n <div\n className={cn(\"an-rich-md-wrapper an-rich-md-loading\", className)}\n data-plan-interactive={interactive ? true : undefined}\n />\n );\n }\n\n return (\n <div\n className={cn(\n \"an-rich-md-wrapper an-rich-md-clickable\",\n !editable && \"an-rich-md-wrapper--readonly\",\n wrapperClassName,\n className,\n )}\n onClick={handleWrapperClick}\n data-plan-interactive={interactive ? true : undefined}\n >\n {editable ? (\n <BubbleToolbar editor={editor} buildItems={buildBubbleItems} />\n ) : null}\n {editable ? (\n <SlashCommandMenu editor={editor} items={slashItems} />\n ) : null}\n <EditorContent editor={editor} />\n </div>\n );\n}\n"]}
|
|
@@ -4,6 +4,11 @@ import { type ImageUploadFn } from "./ImageExtension.js";
|
|
|
4
4
|
export interface SlashCommandItem {
|
|
5
5
|
title: string;
|
|
6
6
|
description: string;
|
|
7
|
+
/**
|
|
8
|
+
* Optional hidden search text. Use this for raw block types and aliases that
|
|
9
|
+
* should match slash queries without making the visible description verbose.
|
|
10
|
+
*/
|
|
11
|
+
searchText?: string;
|
|
7
12
|
/** Short text glyph shown in the menu (T, H1, tbl, …). */
|
|
8
13
|
icon: string;
|
|
9
14
|
action: (editor: Editor) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SlashCommandMenu.d.ts","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/SlashCommandMenu.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE7E,2EAA2E;AAC3E,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED;;;GAGG;AACH,eAAO,MAAM,sBAAsB,EAAE,gBAAgB,EA2EpD,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,aAAa,GACpB,gBAAgB,CAOlB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC5B;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,KAA8B,GAC/B,EAAE,qBAAqB,
|
|
1
|
+
{"version":3,"file":"SlashCommandMenu.d.ts","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/SlashCommandMenu.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE7E,2EAA2E;AAC3E,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED;;;GAGG;AACH,eAAO,MAAM,sBAAsB,EAAE,gBAAgB,EA2EpD,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,aAAa,GACpB,gBAAgB,CAOlB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC5B;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,KAA8B,GAC/B,EAAE,qBAAqB,2CAwKvB"}
|
|
@@ -104,9 +104,15 @@ export function SlashCommandMenu({ editor, items = DEFAULT_SLASH_COMMANDS, }) {
|
|
|
104
104
|
const [query, setQuery] = useState("");
|
|
105
105
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
106
106
|
const [position, setPosition] = useState(null);
|
|
107
|
+
const menuRef = useRef(null);
|
|
108
|
+
const selectedItemRef = useRef(null);
|
|
107
109
|
const slashPosRef = useRef(null);
|
|
108
|
-
const filteredCommands = useMemo(() =>
|
|
109
|
-
|
|
110
|
+
const filteredCommands = useMemo(() => {
|
|
111
|
+
const normalizedQuery = query.toLowerCase();
|
|
112
|
+
return items.filter((cmd) => cmd.title.toLowerCase().includes(normalizedQuery) ||
|
|
113
|
+
cmd.description.toLowerCase().includes(normalizedQuery) ||
|
|
114
|
+
cmd.searchText?.toLowerCase().includes(normalizedQuery));
|
|
115
|
+
}, [items, query]);
|
|
110
116
|
const close = useCallback(() => {
|
|
111
117
|
setIsOpen(false);
|
|
112
118
|
setQuery("");
|
|
@@ -130,10 +136,14 @@ export function SlashCommandMenu({ editor, items = DEFAULT_SLASH_COMMANDS, }) {
|
|
|
130
136
|
return;
|
|
131
137
|
if (event.key === "ArrowDown") {
|
|
132
138
|
event.preventDefault();
|
|
139
|
+
if (filteredCommands.length === 0)
|
|
140
|
+
return;
|
|
133
141
|
setSelectedIndex((index) => (index + 1) % filteredCommands.length);
|
|
134
142
|
}
|
|
135
143
|
else if (event.key === "ArrowUp") {
|
|
136
144
|
event.preventDefault();
|
|
145
|
+
if (filteredCommands.length === 0)
|
|
146
|
+
return;
|
|
137
147
|
setSelectedIndex((index) => (index - 1 + filteredCommands.length) % filteredCommands.length);
|
|
138
148
|
}
|
|
139
149
|
else if (event.key === "Enter") {
|
|
@@ -149,12 +159,30 @@ export function SlashCommandMenu({ editor, items = DEFAULT_SLASH_COMMANDS, }) {
|
|
|
149
159
|
document.addEventListener("keydown", handleKeyDown, true);
|
|
150
160
|
return () => document.removeEventListener("keydown", handleKeyDown, true);
|
|
151
161
|
}, [close, executeCommand, filteredCommands, isOpen, selectedIndex]);
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
if (!isOpen)
|
|
164
|
+
return;
|
|
165
|
+
const menu = menuRef.current;
|
|
166
|
+
const item = selectedItemRef.current;
|
|
167
|
+
if (!menu || !item)
|
|
168
|
+
return;
|
|
169
|
+
const itemTop = item.offsetTop;
|
|
170
|
+
const itemBottom = itemTop + item.offsetHeight;
|
|
171
|
+
const visibleTop = menu.scrollTop;
|
|
172
|
+
const visibleBottom = visibleTop + menu.clientHeight;
|
|
173
|
+
if (itemTop < visibleTop) {
|
|
174
|
+
menu.scrollTop = itemTop;
|
|
175
|
+
}
|
|
176
|
+
else if (itemBottom > visibleBottom) {
|
|
177
|
+
menu.scrollTop = itemBottom - menu.clientHeight;
|
|
178
|
+
}
|
|
179
|
+
}, [filteredCommands.length, isOpen, selectedIndex]);
|
|
152
180
|
useEffect(() => {
|
|
153
181
|
const handleTransaction = () => {
|
|
154
182
|
const { state } = editor;
|
|
155
183
|
const { from } = state.selection;
|
|
156
184
|
const textBefore = state.doc.textBetween(Math.max(0, from - 32), from, "\n");
|
|
157
|
-
const slashMatch = textBefore.match(/\/([a-zA-Z0-9]*)$/);
|
|
185
|
+
const slashMatch = textBefore.match(/\/([a-zA-Z0-9 ]*)$/);
|
|
158
186
|
if (!slashMatch) {
|
|
159
187
|
if (isOpen)
|
|
160
188
|
close();
|
|
@@ -182,12 +210,12 @@ export function SlashCommandMenu({ editor, items = DEFAULT_SLASH_COMMANDS, }) {
|
|
|
182
210
|
}, [close, editor, isOpen]);
|
|
183
211
|
if (!isOpen || !position || filteredCommands.length === 0)
|
|
184
212
|
return null;
|
|
185
|
-
return (_jsxs("div", { className: "an-rich-md-slash-menu", style: {
|
|
213
|
+
return (_jsxs("div", { ref: menuRef, className: "an-rich-md-slash-menu", style: {
|
|
186
214
|
position: "fixed",
|
|
187
215
|
...(position.flipUp
|
|
188
216
|
? { bottom: window.innerHeight - position.top + 4 }
|
|
189
217
|
: { top: position.top }),
|
|
190
218
|
left: position.left,
|
|
191
|
-
}, "data-plan-interactive": true, children: [_jsx("div", { className: "an-rich-md-slash-heading", children: "Blocks" }), filteredCommands.map((command, index) => (_jsxs("button", { type: "button", className: cn("an-rich-md-slash-item", index === selectedIndex && "an-rich-md-slash-item--active"), onMouseEnter: () => setSelectedIndex(index), onMouseDown: (event) => event.preventDefault(), onClick: () => executeCommand(command), children: [_jsx("span", { className: "an-rich-md-slash-icon", children: command.icon }), _jsxs("span", { children: [_jsx("span", { className: "an-rich-md-slash-title", children: command.title }), _jsx("span", { className: "an-rich-md-slash-description", children: command.description })] })] }, command.title)))] }));
|
|
219
|
+
}, "data-plan-interactive": true, children: [_jsx("div", { className: "an-rich-md-slash-heading", children: "Blocks" }), filteredCommands.map((command, index) => (_jsxs("button", { ref: index === selectedIndex ? selectedItemRef : undefined, type: "button", className: cn("an-rich-md-slash-item", index === selectedIndex && "an-rich-md-slash-item--active"), onMouseEnter: () => setSelectedIndex(index), onMouseDown: (event) => event.preventDefault(), onClick: () => executeCommand(command), children: [_jsx("span", { className: "an-rich-md-slash-icon", children: command.icon }), _jsxs("span", { className: "an-rich-md-slash-copy", children: [_jsx("span", { className: "an-rich-md-slash-title", children: command.title }), _jsx("span", { className: "an-rich-md-slash-description", children: command.description })] })] }, command.title)))] }));
|
|
192
220
|
}
|
|
193
221
|
//# sourceMappingURL=SlashCommandMenu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SlashCommandMenu.js","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/SlashCommandMenu.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n} from \"react\";\nimport type { Editor } from \"@tiptap/react\";\nimport { cn } from \"../utils.js\";\nimport { pickAndInsertImage, type ImageUploadFn } from \"./ImageExtension.js\";\n\n/** A single slash-menu block command. Apps can extend the default list. */\nexport interface SlashCommandItem {\n title: string;\n description: string;\n /** Short text glyph shown in the menu (T, H1, tbl, …). */\n icon: string;\n action: (editor: Editor) => void;\n}\n\n/**\n * The default block commands — Plan's current set. Apps pass their own `items`\n * (typically `[...DEFAULT_SLASH_COMMANDS, ...extra]`) to extend it.\n */\nexport const DEFAULT_SLASH_COMMANDS: SlashCommandItem[] = [\n {\n title: \"Text\",\n description: \"Plain text block\",\n icon: \"T\",\n action: (editor) => editor.chain().focus().setParagraph().run(),\n },\n {\n title: \"Heading 1\",\n description: \"Large heading\",\n icon: \"H1\",\n action: (editor) =>\n editor.chain().focus().toggleHeading({ level: 1 }).run(),\n },\n {\n title: \"Heading 2\",\n description: \"Section heading\",\n icon: \"H2\",\n action: (editor) =>\n editor.chain().focus().toggleHeading({ level: 2 }).run(),\n },\n {\n title: \"Heading 3\",\n description: \"Subheading\",\n icon: \"H3\",\n action: (editor) =>\n editor.chain().focus().toggleHeading({ level: 3 }).run(),\n },\n {\n title: \"Bulleted list\",\n description: \"Unordered list\",\n icon: \"-\",\n action: (editor) => editor.chain().focus().toggleBulletList().run(),\n },\n {\n title: \"Numbered list\",\n description: \"Ordered list\",\n icon: \"1.\",\n action: (editor) => editor.chain().focus().toggleOrderedList().run(),\n },\n {\n title: \"To-do list\",\n description: \"Checklist items\",\n icon: \"[]\",\n action: (editor) => editor.chain().focus().toggleTaskList().run(),\n },\n {\n title: \"Quote\",\n description: \"Block quote\",\n icon: '\"',\n action: (editor) => editor.chain().focus().toggleBlockquote().run(),\n },\n {\n title: \"Code block\",\n description: \"Code snippet\",\n icon: \"<>\",\n action: (editor) => editor.chain().focus().toggleCodeBlock().run(),\n },\n {\n title: \"Divider\",\n description: \"Horizontal rule\",\n icon: \"-\",\n action: (editor) => editor.chain().focus().setHorizontalRule().run(),\n },\n {\n title: \"Table\",\n description: \"Three by three table\",\n icon: \"tbl\",\n action: (editor) =>\n editor\n .chain()\n .focus()\n .insertTable({ rows: 3, cols: 3, withHeaderRow: true })\n .run(),\n },\n];\n\n/**\n * Build the `/image` slash command for the shared image block. Requires the\n * editor to mount the shared image extension (`features.image`) and an\n * {@link ImageUploadFn}; the command opens a native file picker and uploads +\n * inserts the chosen image(s). Add it to the list an app passes to\n * {@link SlashCommandMenu} (e.g. `[...DEFAULT_SLASH_COMMANDS, createImageSlashCommand(upload)]`).\n */\nexport function createImageSlashCommand(\n upload: ImageUploadFn,\n): SlashCommandItem {\n return {\n title: \"Image\",\n description: \"Upload an image\",\n icon: \"img\",\n action: (editor) => pickAndInsertImage(editor.view, upload),\n };\n}\n\nexport interface SlashCommandMenuProps {\n editor: Editor;\n /** Block command list. Defaults to {@link DEFAULT_SLASH_COMMANDS}. */\n items?: SlashCommandItem[];\n}\n\n/**\n * The shared \"/\" block-insert menu. Detects a `/query` at the caret, filters the\n * provided command list, and renders a fixed-position picker with keyboard\n * navigation. Extracted from the inline plan menu so apps share one\n * implementation and only swap the command list.\n */\nexport function SlashCommandMenu({\n editor,\n items = DEFAULT_SLASH_COMMANDS,\n}: SlashCommandMenuProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [selectedIndex, setSelectedIndex] = useState(0);\n const [position, setPosition] = useState<{\n top: number;\n left: number;\n flipUp: boolean;\n } | null>(null);\n const slashPosRef = useRef<number | null>(null);\n\n const filteredCommands = useMemo(\n () =>\n items.filter(\n (cmd) =>\n cmd.title.toLowerCase().includes(query.toLowerCase()) ||\n cmd.description.toLowerCase().includes(query.toLowerCase()),\n ),\n [items, query],\n );\n\n const close = useCallback(() => {\n setIsOpen(false);\n setQuery(\"\");\n slashPosRef.current = null;\n }, []);\n\n const executeCommand = useCallback(\n (command: SlashCommandItem) => {\n if (slashPosRef.current !== null) {\n const { from } = editor.state.selection;\n editor\n .chain()\n .focus()\n .deleteRange({ from: slashPosRef.current, to: from })\n .run();\n }\n command.action(editor);\n close();\n },\n [close, editor],\n );\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (!isOpen) return;\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setSelectedIndex((index) => (index + 1) % filteredCommands.length);\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setSelectedIndex(\n (index) =>\n (index - 1 + filteredCommands.length) % filteredCommands.length,\n );\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n const command = filteredCommands[selectedIndex];\n if (command) executeCommand(command);\n } else if (event.key === \"Escape\") {\n close();\n }\n };\n document.addEventListener(\"keydown\", handleKeyDown, true);\n return () => document.removeEventListener(\"keydown\", handleKeyDown, true);\n }, [close, executeCommand, filteredCommands, isOpen, selectedIndex]);\n\n useEffect(() => {\n const handleTransaction = () => {\n const { state } = editor;\n const { from } = state.selection;\n const textBefore = state.doc.textBetween(\n Math.max(0, from - 32),\n from,\n \"\\n\",\n );\n const slashMatch = textBefore.match(/\\/([a-zA-Z0-9]*)$/);\n if (!slashMatch) {\n if (isOpen) close();\n return;\n }\n\n const slashStart = from - slashMatch[0].length;\n slashPosRef.current = slashStart;\n setQuery(slashMatch[1]);\n setSelectedIndex(0);\n const coords = editor.view.coordsAtPos(from);\n const menuHeight = 320;\n const spaceBelow = window.innerHeight - coords.bottom;\n const flipUp = spaceBelow < menuHeight && coords.top > menuHeight;\n setPosition({\n top: flipUp ? coords.top : coords.bottom + 4,\n left: Math.min(coords.left, window.innerWidth - 250),\n flipUp,\n });\n setIsOpen(true);\n };\n\n editor.on(\"transaction\", handleTransaction);\n return () => {\n editor.off(\"transaction\", handleTransaction);\n };\n }, [close, editor, isOpen]);\n\n if (!isOpen || !position || filteredCommands.length === 0) return null;\n\n return (\n <div\n className=\"an-rich-md-slash-menu\"\n style={\n {\n position: \"fixed\",\n ...(position.flipUp\n ? { bottom: window.innerHeight - position.top + 4 }\n : { top: position.top }),\n left: position.left,\n } as CSSProperties\n }\n data-plan-interactive\n >\n <div className=\"an-rich-md-slash-heading\">Blocks</div>\n {filteredCommands.map((command, index) => (\n <button\n key={command.title}\n type=\"button\"\n className={cn(\n \"an-rich-md-slash-item\",\n index === selectedIndex && \"an-rich-md-slash-item--active\",\n )}\n onMouseEnter={() => setSelectedIndex(index)}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => executeCommand(command)}\n >\n <span className=\"an-rich-md-slash-icon\">{command.icon}</span>\n <span>\n <span className=\"an-rich-md-slash-title\">{command.title}</span>\n <span className=\"an-rich-md-slash-description\">\n {command.description}\n </span>\n </span>\n </button>\n ))}\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"SlashCommandMenu.js","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/SlashCommandMenu.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n} from \"react\";\nimport type { Editor } from \"@tiptap/react\";\nimport { cn } from \"../utils.js\";\nimport { pickAndInsertImage, type ImageUploadFn } from \"./ImageExtension.js\";\n\n/** A single slash-menu block command. Apps can extend the default list. */\nexport interface SlashCommandItem {\n title: string;\n description: string;\n /**\n * Optional hidden search text. Use this for raw block types and aliases that\n * should match slash queries without making the visible description verbose.\n */\n searchText?: string;\n /** Short text glyph shown in the menu (T, H1, tbl, …). */\n icon: string;\n action: (editor: Editor) => void;\n}\n\n/**\n * The default block commands — Plan's current set. Apps pass their own `items`\n * (typically `[...DEFAULT_SLASH_COMMANDS, ...extra]`) to extend it.\n */\nexport const DEFAULT_SLASH_COMMANDS: SlashCommandItem[] = [\n {\n title: \"Text\",\n description: \"Plain text block\",\n icon: \"T\",\n action: (editor) => editor.chain().focus().setParagraph().run(),\n },\n {\n title: \"Heading 1\",\n description: \"Large heading\",\n icon: \"H1\",\n action: (editor) =>\n editor.chain().focus().toggleHeading({ level: 1 }).run(),\n },\n {\n title: \"Heading 2\",\n description: \"Section heading\",\n icon: \"H2\",\n action: (editor) =>\n editor.chain().focus().toggleHeading({ level: 2 }).run(),\n },\n {\n title: \"Heading 3\",\n description: \"Subheading\",\n icon: \"H3\",\n action: (editor) =>\n editor.chain().focus().toggleHeading({ level: 3 }).run(),\n },\n {\n title: \"Bulleted list\",\n description: \"Unordered list\",\n icon: \"-\",\n action: (editor) => editor.chain().focus().toggleBulletList().run(),\n },\n {\n title: \"Numbered list\",\n description: \"Ordered list\",\n icon: \"1.\",\n action: (editor) => editor.chain().focus().toggleOrderedList().run(),\n },\n {\n title: \"To-do list\",\n description: \"Checklist items\",\n icon: \"[]\",\n action: (editor) => editor.chain().focus().toggleTaskList().run(),\n },\n {\n title: \"Quote\",\n description: \"Block quote\",\n icon: '\"',\n action: (editor) => editor.chain().focus().toggleBlockquote().run(),\n },\n {\n title: \"Code block\",\n description: \"Code snippet\",\n icon: \"<>\",\n action: (editor) => editor.chain().focus().toggleCodeBlock().run(),\n },\n {\n title: \"Divider\",\n description: \"Horizontal rule\",\n icon: \"-\",\n action: (editor) => editor.chain().focus().setHorizontalRule().run(),\n },\n {\n title: \"Table\",\n description: \"Three by three table\",\n icon: \"tbl\",\n action: (editor) =>\n editor\n .chain()\n .focus()\n .insertTable({ rows: 3, cols: 3, withHeaderRow: true })\n .run(),\n },\n];\n\n/**\n * Build the `/image` slash command for the shared image block. Requires the\n * editor to mount the shared image extension (`features.image`) and an\n * {@link ImageUploadFn}; the command opens a native file picker and uploads +\n * inserts the chosen image(s). Add it to the list an app passes to\n * {@link SlashCommandMenu} (e.g. `[...DEFAULT_SLASH_COMMANDS, createImageSlashCommand(upload)]`).\n */\nexport function createImageSlashCommand(\n upload: ImageUploadFn,\n): SlashCommandItem {\n return {\n title: \"Image\",\n description: \"Upload an image\",\n icon: \"img\",\n action: (editor) => pickAndInsertImage(editor.view, upload),\n };\n}\n\nexport interface SlashCommandMenuProps {\n editor: Editor;\n /** Block command list. Defaults to {@link DEFAULT_SLASH_COMMANDS}. */\n items?: SlashCommandItem[];\n}\n\n/**\n * The shared \"/\" block-insert menu. Detects a `/query` at the caret, filters the\n * provided command list, and renders a fixed-position picker with keyboard\n * navigation. Extracted from the inline plan menu so apps share one\n * implementation and only swap the command list.\n */\nexport function SlashCommandMenu({\n editor,\n items = DEFAULT_SLASH_COMMANDS,\n}: SlashCommandMenuProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [selectedIndex, setSelectedIndex] = useState(0);\n const [position, setPosition] = useState<{\n top: number;\n left: number;\n flipUp: boolean;\n } | null>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const selectedItemRef = useRef<HTMLButtonElement>(null);\n const slashPosRef = useRef<number | null>(null);\n\n const filteredCommands = useMemo(() => {\n const normalizedQuery = query.toLowerCase();\n return items.filter(\n (cmd) =>\n cmd.title.toLowerCase().includes(normalizedQuery) ||\n cmd.description.toLowerCase().includes(normalizedQuery) ||\n cmd.searchText?.toLowerCase().includes(normalizedQuery),\n );\n }, [items, query]);\n\n const close = useCallback(() => {\n setIsOpen(false);\n setQuery(\"\");\n slashPosRef.current = null;\n }, []);\n\n const executeCommand = useCallback(\n (command: SlashCommandItem) => {\n if (slashPosRef.current !== null) {\n const { from } = editor.state.selection;\n editor\n .chain()\n .focus()\n .deleteRange({ from: slashPosRef.current, to: from })\n .run();\n }\n command.action(editor);\n close();\n },\n [close, editor],\n );\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (!isOpen) return;\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n if (filteredCommands.length === 0) return;\n setSelectedIndex((index) => (index + 1) % filteredCommands.length);\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n if (filteredCommands.length === 0) return;\n setSelectedIndex(\n (index) =>\n (index - 1 + filteredCommands.length) % filteredCommands.length,\n );\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n const command = filteredCommands[selectedIndex];\n if (command) executeCommand(command);\n } else if (event.key === \"Escape\") {\n close();\n }\n };\n document.addEventListener(\"keydown\", handleKeyDown, true);\n return () => document.removeEventListener(\"keydown\", handleKeyDown, true);\n }, [close, executeCommand, filteredCommands, isOpen, selectedIndex]);\n\n useEffect(() => {\n if (!isOpen) return;\n const menu = menuRef.current;\n const item = selectedItemRef.current;\n if (!menu || !item) return;\n\n const itemTop = item.offsetTop;\n const itemBottom = itemTop + item.offsetHeight;\n const visibleTop = menu.scrollTop;\n const visibleBottom = visibleTop + menu.clientHeight;\n\n if (itemTop < visibleTop) {\n menu.scrollTop = itemTop;\n } else if (itemBottom > visibleBottom) {\n menu.scrollTop = itemBottom - menu.clientHeight;\n }\n }, [filteredCommands.length, isOpen, selectedIndex]);\n\n useEffect(() => {\n const handleTransaction = () => {\n const { state } = editor;\n const { from } = state.selection;\n const textBefore = state.doc.textBetween(\n Math.max(0, from - 32),\n from,\n \"\\n\",\n );\n const slashMatch = textBefore.match(/\\/([a-zA-Z0-9 ]*)$/);\n if (!slashMatch) {\n if (isOpen) close();\n return;\n }\n\n const slashStart = from - slashMatch[0].length;\n slashPosRef.current = slashStart;\n setQuery(slashMatch[1]);\n setSelectedIndex(0);\n const coords = editor.view.coordsAtPos(from);\n const menuHeight = 320;\n const spaceBelow = window.innerHeight - coords.bottom;\n const flipUp = spaceBelow < menuHeight && coords.top > menuHeight;\n setPosition({\n top: flipUp ? coords.top : coords.bottom + 4,\n left: Math.min(coords.left, window.innerWidth - 250),\n flipUp,\n });\n setIsOpen(true);\n };\n\n editor.on(\"transaction\", handleTransaction);\n return () => {\n editor.off(\"transaction\", handleTransaction);\n };\n }, [close, editor, isOpen]);\n\n if (!isOpen || !position || filteredCommands.length === 0) return null;\n\n return (\n <div\n ref={menuRef}\n className=\"an-rich-md-slash-menu\"\n style={\n {\n position: \"fixed\",\n ...(position.flipUp\n ? { bottom: window.innerHeight - position.top + 4 }\n : { top: position.top }),\n left: position.left,\n } as CSSProperties\n }\n data-plan-interactive\n >\n <div className=\"an-rich-md-slash-heading\">Blocks</div>\n {filteredCommands.map((command, index) => (\n <button\n key={command.title}\n ref={index === selectedIndex ? selectedItemRef : undefined}\n type=\"button\"\n className={cn(\n \"an-rich-md-slash-item\",\n index === selectedIndex && \"an-rich-md-slash-item--active\",\n )}\n onMouseEnter={() => setSelectedIndex(index)}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => executeCommand(command)}\n >\n <span className=\"an-rich-md-slash-icon\">{command.icon}</span>\n <span className=\"an-rich-md-slash-copy\">\n <span className=\"an-rich-md-slash-title\">{command.title}</span>\n <span className=\"an-rich-md-slash-description\">\n {command.description}\n </span>\n </span>\n </button>\n ))}\n </div>\n );\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { createSharedEditorExtensions, MARKDOWN_DIALECT_CONFIG, type RichMarkdownDialect, type RichMarkdownEditorPreset, type RichMarkdownCollabUser, type SharedEditorCollab, type SharedEditorFeatures, type CreateSharedEditorExtensionsOptions, } from "./extensions.js";
|
|
2
|
-
export { useCollabReconcile, getEditorMarkdown, type UseCollabReconcileOptions, type UseCollabReconcileResult, } from "./useCollabReconcile.js";
|
|
2
|
+
export { useCollabReconcile, getEditorMarkdown, RICH_MARKDOWN_PROGRAMMATIC_TRANSACTION, type UseCollabReconcileOptions, type UseCollabReconcileResult, } from "./useCollabReconcile.js";
|
|
3
3
|
export { SlashCommandMenu, DEFAULT_SLASH_COMMANDS, createImageSlashCommand, type SlashCommandItem, type SlashCommandMenuProps, } from "./SlashCommandMenu.js";
|
|
4
4
|
export { SharedImage, createImageExtension, pickAndInsertImage, type ImageUploadFn, type SharedImageOptions, } from "./ImageExtension.js";
|
|
5
5
|
export { uploadEditorImage } from "./uploadEditorImage.js";
|
|
@@ -8,7 +8,7 @@ export { SharedRichEditor, type SharedRichEditorProps, } from "./SharedRichEdito
|
|
|
8
8
|
export { RichMarkdownEditor, createRichMarkdownExtensions, type RichMarkdownEditorProps, type CreateRichMarkdownExtensionsOptions, } from "./RichMarkdownEditor.js";
|
|
9
9
|
export { RunId, RUN_ID_NODE_TYPES } from "./RunId.js";
|
|
10
10
|
export { gfmToProseJSON, proseJSONToGfm } from "./gfmDoc.js";
|
|
11
|
-
export { DragHandle, DEFAULT_DRAG_HANDLE_WRAPPER_SELECTOR, type DragHandleOptions, } from "./DragHandle.js";
|
|
11
|
+
export { DragHandle, DEFAULT_DRAG_HANDLE_WRAPPER_SELECTOR, type DragHandleDropContext, type DragHandleDropPlacement, type DragHandleOptions, } from "./DragHandle.js";
|
|
12
12
|
export { createRegistryBlockNode, RegistryBlockNodeView, RegistryBlockDataProvider, useRegistryBlockData, type CreateRegistryBlockNodeOptions, type RegistryBlockDataValue, type RegistryBlockSideMapBlock, } from "./RegistryBlockNode.js";
|
|
13
|
-
export { buildRegistryBlockSlashItems, type BuildRegistryBlockSlashItemsOptions, } from "./registrySlashCommands.js";
|
|
13
|
+
export { buildRegistryBlockSlashItems, getRegistryBlockSlashDescription, getRegistryBlockSlashSearchText, type BuildRegistryBlockSlashItemsOptions, } from "./registrySlashCommands.js";
|
|
14
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,mCAAmC,GACzC,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,GAC9B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EACL,aAAa,EACb,uBAAuB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,gBAAgB,EAChB,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,kBAAkB,EAClB,4BAA4B,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,mCAAmC,GACzC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EACL,UAAU,EACV,oCAAoC,EACpC,KAAK,iBAAiB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,EACpB,KAAK,8BAA8B,EACnC,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,GAC/B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,4BAA4B,EAC5B,KAAK,mCAAmC,GACzC,MAAM,4BAA4B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,mCAAmC,GACzC,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,sCAAsC,EACtC,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,GAC9B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EACL,aAAa,EACb,uBAAuB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,gBAAgB,EAChB,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,kBAAkB,EAClB,4BAA4B,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,mCAAmC,GACzC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EACL,UAAU,EACV,oCAAoC,EACpC,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,iBAAiB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,EACpB,KAAK,8BAA8B,EACnC,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,GAC/B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,4BAA4B,EAC5B,gCAAgC,EAChC,+BAA+B,EAC/B,KAAK,mCAAmC,GACzC,MAAM,4BAA4B,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { createSharedEditorExtensions, MARKDOWN_DIALECT_CONFIG, } from "./extensions.js";
|
|
2
|
-
export { useCollabReconcile, getEditorMarkdown, } from "./useCollabReconcile.js";
|
|
2
|
+
export { useCollabReconcile, getEditorMarkdown, RICH_MARKDOWN_PROGRAMMATIC_TRANSACTION, } from "./useCollabReconcile.js";
|
|
3
3
|
export { SlashCommandMenu, DEFAULT_SLASH_COMMANDS, createImageSlashCommand, } from "./SlashCommandMenu.js";
|
|
4
4
|
export { SharedImage, createImageExtension, pickAndInsertImage, } from "./ImageExtension.js";
|
|
5
5
|
export { uploadEditorImage } from "./uploadEditorImage.js";
|
|
@@ -10,5 +10,5 @@ export { RunId, RUN_ID_NODE_TYPES } from "./RunId.js";
|
|
|
10
10
|
export { gfmToProseJSON, proseJSONToGfm } from "./gfmDoc.js";
|
|
11
11
|
export { DragHandle, DEFAULT_DRAG_HANDLE_WRAPPER_SELECTOR, } from "./DragHandle.js";
|
|
12
12
|
export { createRegistryBlockNode, RegistryBlockNodeView, RegistryBlockDataProvider, useRegistryBlockData, } from "./RegistryBlockNode.js";
|
|
13
|
-
export { buildRegistryBlockSlashItems, } from "./registrySlashCommands.js";
|
|
13
|
+
export { buildRegistryBlockSlashItems, getRegistryBlockSlashDescription, getRegistryBlockSlashSearchText, } from "./registrySlashCommands.js";
|
|
14
14
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,GAOxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,GAOxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,sCAAsC,GAGvC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,GAGxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,kBAAkB,GAGnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EACL,aAAa,EACb,uBAAuB,GAGxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,gBAAgB,GAEjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,kBAAkB,EAClB,4BAA4B,GAG7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EACL,UAAU,EACV,oCAAoC,GAIrC,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,GAIrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,4BAA4B,EAC5B,gCAAgC,EAChC,+BAA+B,GAEhC,MAAM,4BAA4B,CAAC","sourcesContent":["export {\n createSharedEditorExtensions,\n MARKDOWN_DIALECT_CONFIG,\n type RichMarkdownDialect,\n type RichMarkdownEditorPreset,\n type RichMarkdownCollabUser,\n type SharedEditorCollab,\n type SharedEditorFeatures,\n type CreateSharedEditorExtensionsOptions,\n} from \"./extensions.js\";\nexport {\n useCollabReconcile,\n getEditorMarkdown,\n RICH_MARKDOWN_PROGRAMMATIC_TRANSACTION,\n type UseCollabReconcileOptions,\n type UseCollabReconcileResult,\n} from \"./useCollabReconcile.js\";\nexport {\n SlashCommandMenu,\n DEFAULT_SLASH_COMMANDS,\n createImageSlashCommand,\n type SlashCommandItem,\n type SlashCommandMenuProps,\n} from \"./SlashCommandMenu.js\";\nexport {\n SharedImage,\n createImageExtension,\n pickAndInsertImage,\n type ImageUploadFn,\n type SharedImageOptions,\n} from \"./ImageExtension.js\";\nexport { uploadEditorImage } from \"./uploadEditorImage.js\";\nexport {\n BubbleToolbar,\n buildDefaultBubbleItems,\n type BubbleToolbarItem,\n type BubbleToolbarProps,\n} from \"./BubbleToolbar.js\";\nexport {\n SharedRichEditor,\n type SharedRichEditorProps,\n} from \"./SharedRichEditor.js\";\nexport {\n RichMarkdownEditor,\n createRichMarkdownExtensions,\n type RichMarkdownEditorProps,\n type CreateRichMarkdownExtensionsOptions,\n} from \"./RichMarkdownEditor.js\";\nexport { RunId, RUN_ID_NODE_TYPES } from \"./RunId.js\";\nexport { gfmToProseJSON, proseJSONToGfm } from \"./gfmDoc.js\";\nexport {\n DragHandle,\n DEFAULT_DRAG_HANDLE_WRAPPER_SELECTOR,\n type DragHandleDropContext,\n type DragHandleDropPlacement,\n type DragHandleOptions,\n} from \"./DragHandle.js\";\nexport {\n createRegistryBlockNode,\n RegistryBlockNodeView,\n RegistryBlockDataProvider,\n useRegistryBlockData,\n type CreateRegistryBlockNodeOptions,\n type RegistryBlockDataValue,\n type RegistryBlockSideMapBlock,\n} from \"./RegistryBlockNode.js\";\nexport {\n buildRegistryBlockSlashItems,\n getRegistryBlockSlashDescription,\n getRegistryBlockSlashSearchText,\n type BuildRegistryBlockSlashItemsOptions,\n} from \"./registrySlashCommands.js\";\n"]}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { BlockRegistry, BlockSpec } from "../blocks/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Compact, user-facing slash-menu copy for structured registry blocks. The full
|
|
4
|
+
* registry description remains available through search text, but the visible
|
|
5
|
+
* row should scan like a command palette, not a block reference page.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getRegistryBlockSlashDescription(spec: Pick<BlockSpec, "type" | "description">): string;
|
|
8
|
+
/** Searchable text for registry block slash items, including raw type keywords. */
|
|
9
|
+
export declare function getRegistryBlockSlashSearchText(spec: Pick<BlockSpec, "type" | "label" | "description">): string;
|
|
2
10
|
/**
|
|
3
11
|
* Shared builder for the registry-derived block slash commands both the plan and
|
|
4
12
|
* content editors offer. Both apps take every `BlockSpec` whose `placement`
|
|
@@ -31,6 +39,12 @@ export interface BuildRegistryBlockSlashItemsOptions<TItem, TEditor> {
|
|
|
31
39
|
isNotionCompatible?: (spec: BlockSpec) => boolean;
|
|
32
40
|
/** Build one app-shaped slash item from a surviving block spec. */
|
|
33
41
|
toItem: (spec: BlockSpec, insert: (editor: TEditor) => void) => TItem;
|
|
42
|
+
/**
|
|
43
|
+
* Optional app-level capability gate. Use this for blocks whose schema is
|
|
44
|
+
* registered for parse/render compatibility but whose authoring experience is
|
|
45
|
+
* not available in this editor yet.
|
|
46
|
+
*/
|
|
47
|
+
includeSpec?: (spec: BlockSpec) => boolean;
|
|
34
48
|
/**
|
|
35
49
|
* Insert this spec's block atom into the editor. Plan inserts a `planBlock`
|
|
36
50
|
* node; content inserts a `registryBlock` node seeded with inline `__raw`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registrySlashCommands.d.ts","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/registrySlashCommands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"registrySlashCommands.d.ts","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/registrySlashCommands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAwBnE;;;;GAIG;AACH,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAAC,GAC5C,MAAM,CAKR;AAED,mFAAmF;AACnF,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,aAAa,CAAC,GACtD,MAAM,CAKR;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,mCAAmC,CAAC,KAAK,EAAE,OAAO;IACjE;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC;IAClD,mEAAmE;IACnE,MAAM,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,KAAK,KAAK,CAAC;IACtE;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC;IAC3C;;;OAGG;IACH,WAAW,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;CACzD;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,EACzD,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE,mCAAmC,CAAC,KAAK,EAAE,OAAO,CAAC,GAC3D,KAAK,EAAE,CAUT"}
|