@agent-native/core 0.39.1 → 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/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/skills.d.ts +6 -6
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +936 -1167
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +2 -5
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/NewWorkspaceAppFlow.js +1 -1
- package/dist/client/NewWorkspaceAppFlow.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/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +11 -19
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/use-chat-models.d.ts.map +1 -1
- package/dist/client/use-chat-models.js +2 -5
- package/dist/client/use-chat-models.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/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +2 -1
- package/dist/deploy/build.js.map +1 -1
- package/dist/deploy/route-discovery.d.ts +29 -0
- package/dist/deploy/route-discovery.d.ts.map +1 -1
- package/dist/deploy/route-discovery.js +158 -11
- package/dist/deploy/route-discovery.js.map +1 -1
- package/dist/server/auth.d.ts +2 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +9 -0
- package/dist/server/auth.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/dist/templates/default/.agents/skills/actions/SKILL.md +96 -11
- package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +126 -26
- package/dist/templates/default/.agents/skills/capture-learnings/SKILL.md +56 -30
- package/dist/templates/default/.agents/skills/create-skill/SKILL.md +28 -0
- package/dist/templates/default/.agents/skills/delegate-to-agent/SKILL.md +75 -5
- package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +17 -0
- package/dist/templates/default/.agents/skills/real-time-collab/SKILL.md +99 -124
- package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +43 -10
- package/dist/templates/default/.agents/skills/security/SKILL.md +162 -144
- package/dist/templates/default/.agents/skills/self-modifying-code/SKILL.md +5 -3
- package/dist/templates/default/.agents/skills/shadcn-ui/SKILL.md +15 -0
- package/dist/templates/default/.agents/skills/storing-data/SKILL.md +116 -83
- package/dist/templates/default/DEVELOPING.md +10 -13
- package/dist/templates/workspace-core/.agents/skills/client-methods/references/legacy-client-fetch-audit-2026-06-03.md +9 -0
- package/dist/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +27 -0
- package/docs/content/template-plan.md +5 -3
- package/docs/content/visual-plans.md +5 -2
- package/package.json +16 -1
- package/src/templates/default/.agents/skills/actions/SKILL.md +96 -11
- package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +126 -26
- package/src/templates/default/.agents/skills/capture-learnings/SKILL.md +56 -30
- package/src/templates/default/.agents/skills/create-skill/SKILL.md +28 -0
- package/src/templates/default/.agents/skills/delegate-to-agent/SKILL.md +75 -5
- package/src/templates/default/.agents/skills/frontend-design/SKILL.md +17 -0
- package/src/templates/default/.agents/skills/real-time-collab/SKILL.md +99 -124
- package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +43 -10
- package/src/templates/default/.agents/skills/security/SKILL.md +162 -144
- package/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +5 -3
- package/src/templates/default/.agents/skills/shadcn-ui/SKILL.md +15 -0
- package/src/templates/default/.agents/skills/storing-data/SKILL.md +116 -83
- package/src/templates/default/DEVELOPING.md +10 -13
- package/src/templates/workspace-core/.agents/skills/client-methods/references/legacy-client-fetch-audit-2026-06-03.md +9 -0
- package/src/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +27 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/table.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,qBAAqB,EACrB,QAAQ,EACR,mBAAmB,EACnB,SAAS,EACT,SAAS,EACT,KAAK,GACN,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAkB,MAAM,mBAAmB,CAAC;AAE1E;;;;;;;;;GASG;AAEH;;;;;;;GAOG;AACH,SAAS,cAAc,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAA6B;IACzE,OAAO,CACL,mBAAS,SAAS,EAAC,4BAA4B,mBAAgB,OAAO,aACnE,KAAK,IAAI,cAAK,SAAS,EAAC,kBAAkB,YAAE,KAAK,GAAO,EACzD,iBAAO,SAAS,EAAC,gDAAgD,aAC/D,0BACE,aAAI,SAAS,EAAC,mDAAmD,YAC9D,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAC5B,aAAiB,SAAS,EAAC,yBAAyB,YACjD,MAAM,IADA,MAAM,CAEV,CACN,CAAC,GACC,GACC,EACR,0BACG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,CAC7B,aAAgB,SAAS,EAAC,2BAA2B,YAClD,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,CAC5B,aAAoB,SAAS,EAAC,2BAA2B,YACtD,IAAI,IADE,SAAS,CAEb,CACN,CAAC,IALK,KAAK,CAMT,CACN,CAAC,GACI,IACF,IACA,CACX,CAAC;AACJ,CAAC;AAED,MAAM,cAAc,GAClB,kQAAkQ,CAAC;AAErQ,MAAM,eAAe,GACnB,oNAAoN,CAAC;AAEvN,MAAM,cAAc,GAClB,yOAAyO,CAAC;AAE5O;;;;;;;GAOG;AACH,SAAS,cAAc,CAAC,EACtB,IAAI,EACJ,QAAQ,EACR,QAAQ,GACkB;IAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;IAC7B,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAEnC,MAAM,MAAM,GAAG,CAAC,IAAe,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAEnD,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,KAAa,EAAE,EAAE;QACjD,MAAM,CAAC;YACL,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACzD,IAAI;SACL,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,OAAO,GAAG,CAAC,QAAgB,EAAE,SAAiB,EAAE,KAAa,EAAE,EAAE;QACrE,MAAM,CAAC;YACL,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CACxB,CAAC,KAAK,QAAQ;gBACZ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBACxD,CAAC,CAAC,GAAG,CACR;SACF,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,GAAG,EAAE;QACrB,MAAM,CAAC;YACL,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,UAAU,WAAW,GAAG,CAAC,EAAE,CAAC;YAClD,4DAA4D;YAC5D,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,CAAC;SACtC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,CAAC,KAAa,EAAE,EAAE;QACrC,MAAM,CAAC;YACL,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC;YAC9C,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC;SAC3D,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,GAAG,EAAE;QAClB,MAAM,CAAC;YACL,OAAO;YACP,4CAA4C;YAC5C,IAAI,EAAE;gBACJ,GAAG,IAAI;gBACP,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;aAC3D;SACF,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,EAAE;QAClC,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC,CAAC;IAChE,CAAC,CAAC;IAEF,OAAO,CACL,eAAK,SAAS,EAAC,2CAA2C,aACxD,cAAK,SAAS,EAAC,iBAAiB,YAC9B,iBAAO,SAAS,EAAC,gDAAgD,aAC/D,0BACE,yBACG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAC9B,aAAgB,SAAS,EAAC,eAAe,YACvC,eAAK,SAAS,EAAC,yBAAyB,aACtC,gBACE,IAAI,EAAC,MAAM,+CAEC,UAAU,KAAK,GAAG,CAAC,SAAS,EACxC,SAAS,EAAE,cAAc,EACzB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,QAAQ,EACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,GACzD,EACF,iBACE,IAAI,EAAC,QAAQ,+CAED,iBAAiB,KAAK,GAAG,CAAC,EAAE,EACxC,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,CAAC,QAAQ,EACnB,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,YAElC,KAAC,KAAK,IAAC,IAAI,EAAE,EAAE,GAAI,GACZ,IACL,IArBC,KAAK,CAsBT,CACN,CAAC,EACF,aAAI,SAAS,EAAC,eAAe,YAC3B,iBACE,IAAI,EAAC,QAAQ,+CAEF,YAAY,EACvB,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,CAAC,QAAQ,EACnB,OAAO,EAAE,SAAS,YAElB,KAAC,qBAAqB,IAAC,IAAI,EAAE,EAAE,GAAI,GAC5B,GACN,IACF,GACC,EACR,0BACG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,CAAC,CAC3B,yBACG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,CACzD,aAAoB,SAAS,EAAC,eAAe,YAC3C,gBACE,IAAI,EAAC,MAAM,+CAEC,OAAO,QAAQ,GAAG,CAAC,YAAY,SAAS,GAAG,CAAC,EAAE,EAC1D,SAAS,EAAE,cAAc,EACzB,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,EAC3B,QAAQ,EAAE,CAAC,QAAQ,EACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAClB,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,GAElD,IAXK,SAAS,CAYb,CACN,CAAC,EACF,aAAI,SAAS,EAAC,eAAe,YAC3B,iBACE,IAAI,EAAC,QAAQ,+CAED,cAAc,QAAQ,GAAG,CAAC,EAAE,EACxC,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,CAAC,QAAQ,EACnB,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,YAElC,KAAC,SAAS,IAAC,IAAI,EAAE,EAAE,GAAI,GAChB,GACN,KA3BE,QAAQ,CA4BZ,CACN,CAAC,GACI,IACF,GACJ,EACN,eAAK,SAAS,EAAC,sBAAsB,aACnC,kBACE,IAAI,EAAC,QAAQ,iCAEb,SAAS,EAAE,cAAc,EACzB,QAAQ,EAAE,CAAC,QAAQ,EACnB,OAAO,EAAE,MAAM,aAEf,KAAC,mBAAmB,IAAC,IAAI,EAAE,EAAE,GAAI,eAE1B,EACT,kBACE,IAAI,EAAC,QAAQ,iCAEb,SAAS,EAAE,cAAc,EACzB,QAAQ,EAAE,CAAC,QAAQ,EACnB,OAAO,EAAE,SAAS,aAElB,KAAC,QAAQ,IAAC,IAAI,EAAE,EAAE,GAAI,kBAEf,IACL,IACF,CACP,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,WAAW,CAAY;IAC/C,IAAI,EAAE,OAAO;IACb,MAAM,EAAE,WAAW;IACnB,GAAG,EAAE,QAAQ;IACb,IAAI,EAAE,cAAc;IACpB,IAAI,EAAE,cAAc;IACpB,SAAS,EAAE,CAAC,OAAO,CAAC;IACpB,mEAAmE;IACnE,gBAAgB,EAAE,IAAI;IACtB,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAC7B,KAAC,SAAS,IAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,GAAI,CAChD;IACD,WAAW,EACT,qGAAqG;IACvG,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACZ,OAAO,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC;QACjC,IAAI,EAAE;YACJ,CAAC,EAAE,EAAE,EAAE,CAAC;YACR,CAAC,EAAE,EAAE,EAAE,CAAC;SACT;KACF,CAAC;CACH,CAAC,CAAC","sourcesContent":["import {\n IconColumnInsertRight,\n IconPlus,\n IconRowInsertBottom,\n IconTable,\n IconTrash,\n IconX,\n} from \"@tabler/icons-react\";\nimport { defineBlock } from \"../types.js\";\nimport type { BlockEditProps, BlockReadProps } from \"../types.js\";\nimport { tableMdx, tableSchema, type TableData } from \"./table.config.js\";\n\n/**\n * Standard `table` block — a simple grid of header columns and string rows.\n * STANDARD library block: lives in core (`@agent-native/core/blocks`) so any\n * app can register it. The plan app's registries (server + client) import\n * {@link tableBlock} (browser) and the React-free {@link tableMdx}/\n * {@link tableSchema} config (server) so its render + MDX round-trip move out\n * of the plan `PlanBlockView` switch / `serializeBlock` into the registry,\n * while the legacy branch stays as a backward-compatible fallback for\n * unregistered renderers.\n */\n\n/**\n * Read-only renderer. Mirrors the legacy plan `PlanBlockView` table branch\n * markup byte-for-byte (same `plan-block overflow-x-auto` section + title +\n * `plan-line`/`plan-muted` table) so converting the block to the registry does\n * not change the rendered output. The `plan-*` class names are styled by the\n * consuming app's CSS — core only emits the markup, exactly like the existing\n * `CalloutBlock` read renderer.\n */\nfunction TableBlockRead({ data, blockId, title }: BlockReadProps<TableData>) {\n return (\n <section className=\"plan-block overflow-x-auto\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n <table className=\"w-full min-w-[640px] border-collapse text-left\">\n <thead>\n <tr className=\"border-b border-plan-line text-sm text-plan-muted\">\n {data.columns.map((column) => (\n <th key={column} className=\"py-3 pr-4 font-semibold\">\n {column}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.rows.map((row, index) => (\n <tr key={index} className=\"border-b border-plan-line\">\n {row.map((cell, cellIndex) => (\n <td key={cellIndex} className=\"py-4 pr-4 text-plan-muted\">\n {cell}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </section>\n );\n}\n\nconst editInputClass =\n \"h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\";\n\nconst iconButtonClass =\n \"inline-flex size-7 items-center justify-center rounded-md border border-input text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground disabled:cursor-not-allowed disabled:opacity-50\";\n\nconst addButtonClass =\n \"inline-flex items-center gap-1.5 rounded-md border border-input bg-transparent px-3 py-1.5 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground disabled:cursor-not-allowed disabled:opacity-50\";\n\n/**\n * Editable grid. The schema's `columns: string[]` / `rows: string[][]` are\n * positional/structured, which the schema auto-editor intentionally cannot\n * render, so this block supplies its own `Edit`: an editable header row plus a\n * body grid, with add/remove controls for both columns and rows. Every change\n * commits a full new `{ columns, rows }` value (re-validated upstream by the\n * registry), keeping rows rectangular with the column count.\n */\nfunction TableBlockEdit({\n data,\n onChange,\n editable,\n}: BlockEditProps<TableData>) {\n const columns = data.columns ?? [];\n const rows = data.rows ?? [];\n const columnCount = columns.length;\n\n const commit = (next: TableData) => onChange(next);\n\n const setColumn = (index: number, value: string) => {\n commit({\n columns: columns.map((c, i) => (i === index ? value : c)),\n rows,\n });\n };\n\n const setCell = (rowIndex: number, cellIndex: number, value: string) => {\n commit({\n columns,\n rows: rows.map((row, i) =>\n i === rowIndex\n ? row.map((cell, j) => (j === cellIndex ? value : cell))\n : row,\n ),\n });\n };\n\n const addColumn = () => {\n commit({\n columns: [...columns, `Column ${columnCount + 1}`],\n // Keep rows rectangular: append an empty cell to every row.\n rows: rows.map((row) => [...row, \"\"]),\n });\n };\n\n const removeColumn = (index: number) => {\n commit({\n columns: columns.filter((_, i) => i !== index),\n rows: rows.map((row) => row.filter((_, i) => i !== index)),\n });\n };\n\n const addRow = () => {\n commit({\n columns,\n // New row matches the current column count.\n rows: [\n ...rows,\n Array.from({ length: Math.max(columnCount, 1) }, () => \"\"),\n ],\n });\n };\n\n const removeRow = (index: number) => {\n commit({ columns, rows: rows.filter((_, i) => i !== index) });\n };\n\n return (\n <div className=\"an-table-block-editor flex flex-col gap-3\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full min-w-[480px] border-collapse text-left\">\n <thead>\n <tr>\n {columns.map((column, index) => (\n <th key={index} className=\"p-1 align-top\">\n <div className=\"flex items-center gap-1\">\n <input\n type=\"text\"\n data-plan-interactive\n aria-label={`Column ${index + 1} header`}\n className={editInputClass}\n value={column}\n disabled={!editable}\n onChange={(event) => setColumn(index, event.target.value)}\n />\n <button\n type=\"button\"\n data-plan-interactive\n aria-label={`Remove column ${index + 1}`}\n className={iconButtonClass}\n disabled={!editable}\n onClick={() => removeColumn(index)}\n >\n <IconX size={14} />\n </button>\n </div>\n </th>\n ))}\n <th className=\"p-1 align-top\">\n <button\n type=\"button\"\n data-plan-interactive\n aria-label=\"Add column\"\n className={iconButtonClass}\n disabled={!editable}\n onClick={addColumn}\n >\n <IconColumnInsertRight size={16} />\n </button>\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row, rowIndex) => (\n <tr key={rowIndex}>\n {Array.from({ length: columnCount }).map((_, cellIndex) => (\n <td key={cellIndex} className=\"p-1 align-top\">\n <input\n type=\"text\"\n data-plan-interactive\n aria-label={`Row ${rowIndex + 1}, column ${cellIndex + 1}`}\n className={editInputClass}\n value={row[cellIndex] ?? \"\"}\n disabled={!editable}\n onChange={(event) =>\n setCell(rowIndex, cellIndex, event.target.value)\n }\n />\n </td>\n ))}\n <td className=\"p-1 align-top\">\n <button\n type=\"button\"\n data-plan-interactive\n aria-label={`Remove row ${rowIndex + 1}`}\n className={iconButtonClass}\n disabled={!editable}\n onClick={() => removeRow(rowIndex)}\n >\n <IconTrash size={14} />\n </button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n data-plan-interactive\n className={addButtonClass}\n disabled={!editable}\n onClick={addRow}\n >\n <IconRowInsertBottom size={16} />\n Add row\n </button>\n <button\n type=\"button\"\n data-plan-interactive\n className={addButtonClass}\n disabled={!editable}\n onClick={addColumn}\n >\n <IconPlus size={16} />\n Add column\n </button>\n </div>\n </div>\n );\n}\n\n/**\n * The full standard `table` `BlockSpec`. Pairs the React-free\n * {@link tableSchema}/{@link tableMdx} config (also used by the server registry)\n * with the React `Read`/`Edit`. `empty()` seeds a 2×2 grid for slash insertion.\n */\nexport const tableBlock = defineBlock<TableData>({\n type: \"table\",\n schema: tableSchema,\n mdx: tableMdx,\n Read: TableBlockRead,\n Edit: TableBlockEdit,\n placement: [\"block\"],\n // A simple grid maps to an NFM table, so it round-trips to Notion.\n notionCompatible: true,\n label: \"Table\",\n icon: ({ size, className }) => (\n <IconTable size={size} className={className} />\n ),\n description:\n \"A simple grid with header columns and string rows for comparisons, parameters, or structured lists.\",\n empty: () => ({\n columns: [\"Column 1\", \"Column 2\"],\n rows: [\n [\"\", \"\"],\n [\"\", \"\"],\n ],\n }),\n});\n"]}
|
|
1
|
+
{"version":3,"file":"table.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/table.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useLayoutEffect,\n useRef,\n type ClipboardEvent,\n type FormEvent,\n type KeyboardEvent,\n} from \"react\";\nimport {\n IconColumnInsertRight,\n IconPlus,\n IconRowInsertBottom,\n IconTable,\n IconTrash,\n IconX,\n} from \"@tabler/icons-react\";\nimport { defineBlock } from \"../types.js\";\nimport type {\n BlockEditProps,\n BlockReadProps,\n BlockRenderContext,\n} from \"../types.js\";\nimport {\n tableMdx,\n tableSchema,\n type TableData,\n type TableDensity,\n} from \"./table.config.js\";\n\n/**\n * Standard `table` block — a simple grid of header columns and string rows.\n * STANDARD library block: lives in core (`@agent-native/core/blocks`) so any\n * app can register it. The plan app's registries (server + client) import\n * {@link tableBlock} (browser) and the React-free {@link tableMdx}/\n * {@link tableSchema} config (server) so its render + MDX round-trip move out\n * of the plan `PlanBlockView` switch / `serializeBlock` into the registry,\n * while the legacy branch stays as a backward-compatible fallback for\n * unregistered renderers.\n */\n\n/**\n * Read-only renderer. Mirrors the legacy plan `PlanBlockView` table branch\n * markup byte-for-byte (same `plan-block overflow-x-auto` section + title +\n * `plan-line`/`plan-muted` table) so converting the block to the registry does\n * not change the rendered output. The `plan-*` class names are styled by the\n * consuming app's CSS — core only emits the markup, exactly like the existing\n * `CalloutBlock` read renderer.\n */\nconst densityClasses: Record<TableDensity, { header: string; cell: string }> = {\n compact: {\n header: \"py-1.5\",\n cell: \"py-2\",\n },\n normal: {\n header: \"py-3\",\n cell: \"py-4\",\n },\n relaxed: {\n header: \"py-5\",\n cell: \"py-6\",\n },\n};\n\nfunction resolveDensity(data: TableData): TableDensity {\n return data.density ?? \"normal\";\n}\n\nfunction TableBlockRead({\n data,\n blockId,\n title,\n ctx,\n}: BlockReadProps<TableData>) {\n const density = resolveDensity(data);\n const spacing = densityClasses[density];\n\n return (\n <section className=\"plan-block overflow-x-auto\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n <table className=\"w-full min-w-[640px] border-collapse text-left\">\n <thead>\n <tr className=\"border-b border-plan-line text-sm text-plan-muted\">\n {data.columns.map((column) => (\n <th\n key={column}\n className={`${spacing.header} pr-4 font-semibold`}\n >\n {renderTableMarkdown(ctx, column, tableHeaderMarkdownClass)}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.rows.map((row, index) => (\n <tr key={index} className=\"border-b border-plan-line\">\n {row.map((cell, cellIndex) => (\n <td\n key={cellIndex}\n className={`${spacing.cell} pr-4 text-plan-muted`}\n >\n {renderTableMarkdown(ctx, cell, tableCellMarkdownClass)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </section>\n );\n}\n\nconst tableCellMarkdownClass =\n \"an-table-cell-markdown mt-0 max-w-none text-plan-muted\";\n\nconst tableHeaderMarkdownClass = `${tableCellMarkdownClass} an-table-cell-markdown--header font-semibold`;\n\nconst plainTextFieldBaseClass =\n \"min-h-6 w-full whitespace-pre-wrap break-words rounded-sm border border-transparent bg-transparent px-0 leading-6 text-plan-muted outline-none focus:border-transparent focus:bg-transparent focus:px-0 focus:outline-none focus:ring-0 focus-visible:border-transparent focus-visible:bg-transparent focus-visible:px-0 focus-visible:outline-none focus-visible:ring-0 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50\";\n\nconst iconButtonBaseClass =\n \"inline-flex size-7 items-center justify-center rounded-md border border-input bg-background/80 text-muted-foreground opacity-0 shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:opacity-100 disabled:cursor-not-allowed disabled:opacity-50\";\n\nconst tableHoverIconButtonClass = `${iconButtonBaseClass} group-hover/table:opacity-100`;\n\nconst columnHoverIconButtonClass = `${iconButtonBaseClass} group-hover/column:opacity-100`;\n\nconst rowHoverIconButtonClass = `${iconButtonBaseClass} group-hover/row:opacity-100`;\n\nconst addButtonClass =\n \"inline-flex items-center gap-1.5 rounded-md border border-input bg-transparent px-3 py-1.5 text-sm text-muted-foreground opacity-0 transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:opacity-100 group-hover/table:opacity-100 disabled:cursor-not-allowed disabled:opacity-50\";\n\nfunction renderTableMarkdown(\n ctx: BlockRenderContext,\n value: string,\n className: string,\n) {\n return ctx.renderMarkdown?.(value, { className }) ?? value;\n}\n\nfunction TableMarkdownField({\n ctx,\n value,\n onChange,\n editable,\n ariaLabel,\n className,\n}: {\n ctx: BlockRenderContext;\n value: string;\n onChange: (value: string) => void;\n editable: boolean;\n ariaLabel: string;\n className: string;\n}) {\n const editor = ctx.renderMarkdownEditor?.({\n value,\n onChange,\n editable,\n className,\n ariaLabel,\n });\n\n if (editor) return editor;\n\n return (\n <PlainTextTableField\n value={value}\n onChange={onChange}\n editable={editable}\n ariaLabel={ariaLabel}\n className={`${plainTextFieldBaseClass} ${className}`}\n />\n );\n}\n\nfunction PlainTextTableField({\n value,\n onChange,\n editable,\n ariaLabel,\n className,\n}: {\n value: string;\n onChange: (value: string) => void;\n editable: boolean;\n ariaLabel: string;\n className: string;\n}) {\n const ref = useRef<HTMLDivElement | null>(null);\n\n useLayoutEffect(() => {\n const node = ref.current;\n if (!node || document.activeElement === node) return;\n if (node.textContent !== value) node.textContent = value;\n }, [value]);\n\n const handleInput = (event: FormEvent<HTMLDivElement>) => {\n onChange(event.currentTarget.textContent ?? \"\");\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key !== \"Enter\") return;\n event.preventDefault();\n event.currentTarget.blur();\n };\n\n const handlePaste = (event: ClipboardEvent<HTMLDivElement>) => {\n const text = event.clipboardData.getData(\"text/plain\");\n if (!text) return;\n event.preventDefault();\n const selection = window.getSelection();\n if (!selection || selection.rangeCount === 0) return;\n const range = selection.getRangeAt(0);\n range.deleteContents();\n range.insertNode(document.createTextNode(text));\n range.collapse(false);\n selection.removeAllRanges();\n selection.addRange(range);\n onChange(event.currentTarget.textContent ?? \"\");\n };\n\n return (\n <div\n ref={ref}\n data-plan-interactive\n data-disabled={!editable ? \"true\" : undefined}\n role=\"textbox\"\n aria-label={ariaLabel}\n contentEditable={editable}\n suppressContentEditableWarning\n className={className}\n onInput={handleInput}\n onKeyDown={handleKeyDown}\n onPaste={handlePaste}\n />\n );\n}\n\n/**\n * Editable grid. The schema's `columns: string[]` / `rows: string[][]` are\n * positional/structured, which the schema auto-editor intentionally cannot\n * render, so this block supplies its own `Edit`: an editable header row plus a\n * body grid, with add/remove controls for both columns and rows. Every change\n * commits a full new `{ columns, rows }` value (re-validated upstream by the\n * registry), keeping rows rectangular with the column count.\n */\nfunction TableBlockEdit({\n data,\n onChange,\n editable,\n ctx,\n}: BlockEditProps<TableData>) {\n const columns = data.columns ?? [];\n const rows = data.rows ?? [];\n const columnCount = columns.length;\n const density = resolveDensity(data);\n const spacing = densityClasses[density];\n\n const commit = (next: TableData) => onChange({ ...data, ...next });\n\n const setColumn = (index: number, value: string) => {\n commit({\n columns: columns.map((c, i) => (i === index ? value : c)),\n rows,\n });\n };\n\n const setCell = (rowIndex: number, cellIndex: number, value: string) => {\n commit({\n columns,\n rows: rows.map((row, i) =>\n i === rowIndex\n ? row.map((cell, j) => (j === cellIndex ? value : cell))\n : row,\n ),\n });\n };\n\n const addColumn = () => {\n commit({\n columns: [...columns, `Column ${columnCount + 1}`],\n // Keep rows rectangular: append an empty cell to every row.\n rows: rows.map((row) => [...row, \"\"]),\n });\n };\n\n const removeColumn = (index: number) => {\n if (columns.length <= 1) return;\n commit({\n columns: columns.filter((_, i) => i !== index),\n rows: rows.map((row) => row.filter((_, i) => i !== index)),\n });\n };\n\n const addRow = () => {\n commit({\n columns,\n // New row matches the current column count.\n rows: [\n ...rows,\n Array.from({ length: Math.max(columnCount, 1) }, () => \"\"),\n ],\n });\n };\n\n const removeRow = (index: number) => {\n commit({ columns, rows: rows.filter((_, i) => i !== index) });\n };\n\n return (\n <div className=\"an-table-block-editor group/table flex flex-col gap-2\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full min-w-[480px] border-collapse text-left\">\n <thead>\n <tr className=\"border-b border-plan-line\">\n {columns.map((column, index) => (\n <th\n key={index}\n className={`group/column ${spacing.header} pr-4 align-top`}\n >\n <div className=\"flex items-center gap-2\">\n <TableMarkdownField\n ctx={ctx}\n value={column}\n onChange={(value) => setColumn(index, value)}\n editable={editable}\n ariaLabel={`Column ${index + 1} header`}\n className={tableHeaderMarkdownClass}\n />\n <button\n type=\"button\"\n data-plan-interactive\n aria-label={`Remove column ${index + 1}`}\n className={columnHoverIconButtonClass}\n disabled={!editable || columns.length <= 1}\n onClick={() => removeColumn(index)}\n >\n <IconX size={14} />\n </button>\n </div>\n </th>\n ))}\n <th className=\"py-1 align-top\">\n <button\n type=\"button\"\n data-plan-interactive\n aria-label=\"Add column in grid\"\n className={tableHoverIconButtonClass}\n disabled={!editable}\n onClick={addColumn}\n >\n <IconColumnInsertRight size={16} />\n </button>\n </th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row, rowIndex) => (\n <tr\n key={rowIndex}\n className=\"group/row border-b border-plan-line\"\n >\n {Array.from({ length: columnCount }).map((_, cellIndex) => (\n <td\n key={cellIndex}\n className={`${spacing.cell} pr-4 align-top`}\n >\n <TableMarkdownField\n ctx={ctx}\n value={row[cellIndex] ?? \"\"}\n onChange={(value) => setCell(rowIndex, cellIndex, value)}\n editable={editable}\n ariaLabel={`Row ${rowIndex + 1}, column ${cellIndex + 1}`}\n className={tableCellMarkdownClass}\n />\n </td>\n ))}\n <td className=\"py-2 align-top\">\n <button\n type=\"button\"\n data-plan-interactive\n aria-label={`Remove row ${rowIndex + 1}`}\n className={rowHoverIconButtonClass}\n disabled={!editable}\n onClick={() => removeRow(rowIndex)}\n >\n <IconTrash size={14} />\n </button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n data-plan-interactive\n className={addButtonClass}\n disabled={!editable}\n onClick={addRow}\n >\n <IconRowInsertBottom size={16} />\n Add row\n </button>\n <button\n type=\"button\"\n data-plan-interactive\n className={addButtonClass}\n disabled={!editable}\n onClick={addColumn}\n >\n <IconPlus size={16} />\n Add column\n </button>\n </div>\n </div>\n );\n}\n\n/**\n * The full standard `table` `BlockSpec`. Pairs the React-free\n * {@link tableSchema}/{@link tableMdx} config (also used by the server registry)\n * with the React `Read`/`Edit`. `empty()` seeds a 2×2 grid for slash insertion.\n */\nexport const tableBlock = defineBlock<TableData>({\n type: \"table\",\n schema: tableSchema,\n mdx: tableMdx,\n Read: TableBlockRead,\n Edit: TableBlockEdit,\n placement: [\"block\"],\n editSurface: \"inline\",\n // A simple grid maps to an NFM table, so it round-trips to Notion.\n notionCompatible: true,\n label: \"Table\",\n icon: ({ size, className }) => (\n <IconTable size={size} className={className} />\n ),\n description:\n \"A simple grid with header columns and string rows for comparisons, parameters, or structured lists.\",\n empty: () => ({\n columns: [\"Column 1\", \"Column 2\"],\n rows: [\n [\"\", \"\"],\n [\"\", \"\"],\n ],\n }),\n});\n"]}
|
|
@@ -8,11 +8,12 @@ import type { NestedBlock } from "../types.js";
|
|
|
8
8
|
* (`tabs.tsx`). Keeping this React-free means importing it into a server module
|
|
9
9
|
* never pulls React into the Nitro/SSR bundle.
|
|
10
10
|
*
|
|
11
|
-
* `tabs` is a STANDARD library block: a
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* `tabs` is a STANDARD library block: a pill-tab container where each tab holds
|
|
12
|
+
* a list of child blocks. The rail is horizontal by default, and can opt into a
|
|
13
|
+
* vertical side rail for dense file/review surfaces. The children are rendered
|
|
14
|
+
* RECURSIVELY through the app's own block dispatcher (`ctx.renderBlock`), so
|
|
15
|
+
* registered children render via their spec and unconverted children still fall
|
|
16
|
+
* through the app's legacy switch — the coexistence seam.
|
|
16
17
|
*
|
|
17
18
|
* Its schema MUST stay data-compatible with the legacy plan `tabs` branch of
|
|
18
19
|
* `planBlockSchema` (`tabs[]` of `{ id, label, blocks: Block[] }`), and the MDX
|
|
@@ -33,8 +34,14 @@ export interface TabsTab {
|
|
|
33
34
|
*/
|
|
34
35
|
blocks: NestedBlock[];
|
|
35
36
|
}
|
|
37
|
+
export type TabsOrientation = "horizontal" | "vertical";
|
|
36
38
|
export interface TabsData {
|
|
37
39
|
tabs: TabsTab[];
|
|
40
|
+
/**
|
|
41
|
+
* Visual rail layout. Omitted means the historical horizontal pill rail, so
|
|
42
|
+
* old stored plans keep byte-identical MDX output.
|
|
43
|
+
*/
|
|
44
|
+
orientation?: TabsOrientation;
|
|
38
45
|
}
|
|
39
46
|
/**
|
|
40
47
|
* Child blocks are validated by the app's own recursive `planBlockSchema` when
|
|
@@ -48,9 +55,10 @@ export declare const tabsSchema: z.ZodType<TabsData>;
|
|
|
48
55
|
* self-closing — exactly the legacy `<TabsBlock id … tabs={[…]} />` form. The
|
|
49
56
|
* entire `tabs` array (labels + nested child blocks) is one JSON prop; child
|
|
50
57
|
* blocks are NOT serialized as nested MDX, which preserves the current byte
|
|
51
|
-
* output. `toAttrs` returns
|
|
52
|
-
* (defaulting to `[]` for backward-compat with
|
|
53
|
-
*
|
|
58
|
+
* output. `toAttrs` returns `tabs` plus non-default `orientation`; `fromAttrs`
|
|
59
|
+
* reads the `tabs` array (defaulting to `[]` for backward-compat with
|
|
60
|
+
* malformed/empty stored blocks, mirroring the legacy
|
|
61
|
+
* `arrayAttr(node, "tabs") ?? []`) and accepts the optional orientation prop.
|
|
54
62
|
*/
|
|
55
63
|
export declare const tabsMdx: BlockMdxConfig<TabsData>;
|
|
56
64
|
//# sourceMappingURL=tabs.config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs.config.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/tabs.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C
|
|
1
|
+
{"version":3,"file":"tabs.config.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/tabs.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,yDAAyD;AACzD,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,UAAU,CAAC;AAExD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAKD;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAYN,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;AAErC;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO,EAAE,cAAc,CAAC,QAAQ,CAW5C,CAAC"}
|
|
@@ -16,21 +16,27 @@ export const tabsSchema = z.object({
|
|
|
16
16
|
}))
|
|
17
17
|
.min(1)
|
|
18
18
|
.max(12),
|
|
19
|
+
orientation: z.enum(["horizontal", "vertical"]).optional(),
|
|
19
20
|
});
|
|
20
21
|
/**
|
|
21
22
|
* MDX config: `tabs` is a single JSON-encoded attribute and the block is
|
|
22
23
|
* self-closing — exactly the legacy `<TabsBlock id … tabs={[…]} />` form. The
|
|
23
24
|
* entire `tabs` array (labels + nested child blocks) is one JSON prop; child
|
|
24
25
|
* blocks are NOT serialized as nested MDX, which preserves the current byte
|
|
25
|
-
* output. `toAttrs` returns
|
|
26
|
-
* (defaulting to `[]` for backward-compat with
|
|
27
|
-
*
|
|
26
|
+
* output. `toAttrs` returns `tabs` plus non-default `orientation`; `fromAttrs`
|
|
27
|
+
* reads the `tabs` array (defaulting to `[]` for backward-compat with
|
|
28
|
+
* malformed/empty stored blocks, mirroring the legacy
|
|
29
|
+
* `arrayAttr(node, "tabs") ?? []`) and accepts the optional orientation prop.
|
|
28
30
|
*/
|
|
29
31
|
export const tabsMdx = {
|
|
30
32
|
tag: "TabsBlock",
|
|
31
|
-
toAttrs: (data) => ({
|
|
33
|
+
toAttrs: (data) => ({
|
|
34
|
+
tabs: data.tabs,
|
|
35
|
+
orientation: data.orientation === "vertical" ? data.orientation : undefined,
|
|
36
|
+
}),
|
|
32
37
|
fromAttrs: (attrs) => ({
|
|
33
38
|
tabs: (attrs.array("tabs") ?? []),
|
|
39
|
+
orientation: attrs.string("orientation") === "vertical" ? "vertical" : undefined,
|
|
34
40
|
}),
|
|
35
41
|
};
|
|
36
42
|
//# sourceMappingURL=tabs.config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs.config.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/tabs.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"tabs.config.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/tabs.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAkDxB,yEAAyE;AACzE,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,IAAI,EAAE,CAAC;SACJ,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;QACP,EAAE,EAAE,WAAW;QACf,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;QACxC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;KACjC,CAAC,CACH;SACA,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,EAAE,CAAC;IACV,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE;CAC3D,CAAmC,CAAC;AAErC;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,OAAO,GAA6B;IAC/C,GAAG,EAAE,WAAW;IAChB,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAClB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;KAC5E,CAAC;IACF,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACrB,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAU,MAAM,CAAC,IAAI,EAAE,CAAc;QACvD,WAAW,EACT,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;KACtE,CAAC;CACH,CAAC","sourcesContent":["import { z } from \"zod\";\nimport type { BlockMdxConfig } from \"../types.js\";\nimport type { NestedBlock } from \"../types.js\";\n\n/**\n * Pure (React-free) part of the standard `tabs` block: its data schema and MDX\n * round-trip config. Shared by the server MDX adapter (a plan/content app\n * registers it via `@agent-native/core/blocks/server`) and the full client spec\n * (`tabs.tsx`). Keeping this React-free means importing it into a server module\n * never pulls React into the Nitro/SSR bundle.\n *\n * `tabs` is a STANDARD library block: a pill-tab container where each tab holds\n * a list of child blocks. The rail is horizontal by default, and can opt into a\n * vertical side rail for dense file/review surfaces. The children are rendered\n * RECURSIVELY through the app's own block dispatcher (`ctx.renderBlock`), so\n * registered children render via their spec and unconverted children still fall\n * through the app's legacy switch — the coexistence seam.\n *\n * Its schema MUST stay data-compatible with the legacy plan `tabs` branch of\n * `planBlockSchema` (`tabs[]` of `{ id, label, blocks: Block[] }`), and the MDX\n * `tag` + attribute shape MUST match the legacy\n * `<TabsBlock … tabs={[…]} />` encoding — the WHOLE `tabs` array (including\n * nested child blocks) encoded as one JSON prop, NOT nested MDX\n * (`plan-mdx.ts` `serializeBlock` L349 / `parseBlock` L705) — so stored `.mdx`\n * round-trips byte-compatibly.\n */\n\n/** One tab: a label and the child blocks it contains. */\nexport interface TabsTab {\n id: string;\n label: string;\n /**\n * Child blocks. Typed loosely as {@link NestedBlock} because the app owns the\n * authoritative recursive block union (`planBlockSchema`); the tabs spec only\n * validates the tab envelope (`id`/`label`) and passes children through.\n */\n blocks: NestedBlock[];\n}\n\nexport type TabsOrientation = \"horizontal\" | \"vertical\";\n\nexport interface TabsData {\n tabs: TabsTab[];\n /**\n * Visual rail layout. Omitted means the historical horizontal pill rail, so\n * old stored plans keep byte-identical MDX output.\n */\n orientation?: TabsOrientation;\n}\n\n/** Matches the plan `idSchema` (`z.string().trim().min(1).max(120)`). */\nconst tabIdSchema = z.string().trim().min(1).max(120);\n\n/**\n * Child blocks are validated by the app's own recursive `planBlockSchema` when\n * the plan persists; here they pass through untyped (`z.any()`) so core never\n * needs to import an app-specific block union. The tab envelope (`id`/`label`)\n * mirrors the plan tabs schema bounds (`plan-content.ts` L1051) exactly.\n */\nexport const tabsSchema = z.object({\n tabs: z\n .array(\n z.object({\n id: tabIdSchema,\n label: z.string().trim().min(1).max(120),\n blocks: z.array(z.any()).max(40),\n }),\n )\n .min(1)\n .max(12),\n orientation: z.enum([\"horizontal\", \"vertical\"]).optional(),\n}) as unknown as z.ZodType<TabsData>;\n\n/**\n * MDX config: `tabs` is a single JSON-encoded attribute and the block is\n * self-closing — exactly the legacy `<TabsBlock id … tabs={[…]} />` form. The\n * entire `tabs` array (labels + nested child blocks) is one JSON prop; child\n * blocks are NOT serialized as nested MDX, which preserves the current byte\n * output. `toAttrs` returns `tabs` plus non-default `orientation`; `fromAttrs`\n * reads the `tabs` array (defaulting to `[]` for backward-compat with\n * malformed/empty stored blocks, mirroring the legacy\n * `arrayAttr(node, \"tabs\") ?? []`) and accepts the optional orientation prop.\n */\nexport const tabsMdx: BlockMdxConfig<TabsData> = {\n tag: \"TabsBlock\",\n toAttrs: (data) => ({\n tabs: data.tabs,\n orientation: data.orientation === \"vertical\" ? data.orientation : undefined,\n }),\n fromAttrs: (attrs) => ({\n tabs: (attrs.array<TabsTab>(\"tabs\") ?? []) as TabsTab[],\n orientation:\n attrs.string(\"orientation\") === \"vertical\" ? \"vertical\" : undefined,\n }),\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/tabs.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/tabs.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAEV,cAAc,EACd,cAAc,EAEf,MAAM,aAAa,CAAC;AACrB,OAAO,EAGL,KAAK,QAAQ,EAGd,MAAM,kBAAkB,CAAC;AAuG1B,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,OAAO,EACP,KAAK,EACL,GAAG,GACJ,EAAE,cAAc,CAAC,QAAQ,CAAC,2CAqC1B;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,KAAK,EACL,GAAG,GACJ,EAAE,cAAc,CAAC,QAAQ,CAAC,2CA6L1B;AAuLD;;;;;GAKG;AACH,eAAO,MAAM,SAAS,2CA0BpB,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from "react";
|
|
3
|
-
import { IconLayoutNavbar, IconPlus,
|
|
3
|
+
import { IconLayoutNavbar, IconPencil, IconPlus, IconTrash, } from "@tabler/icons-react";
|
|
4
4
|
import { cn } from "../../utils.js";
|
|
5
|
+
import { Popover, PopoverContent, PopoverTrigger, } from "../../components/ui/popover.js";
|
|
5
6
|
import { defineBlock } from "../types.js";
|
|
6
7
|
import { tabsSchema, tabsMdx, } from "./tabs.config.js";
|
|
7
8
|
/**
|
|
@@ -13,9 +14,8 @@ import { tabsSchema, tabsMdx, } from "./tabs.config.js";
|
|
|
13
14
|
* `plan-block` section, the `inline-flex` pill tab rail with `role="tablist"`/
|
|
14
15
|
* `role="tab"`, the same active-tab `useState`, and the `compactVisuals`
|
|
15
16
|
* heuristic on the block title) so converting the block to the registry does not
|
|
16
|
-
* change rendered output. The
|
|
17
|
-
*
|
|
18
|
-
* exactly as before.
|
|
17
|
+
* change rendered output. The block chrome uses semantic shadcn tokens so the
|
|
18
|
+
* same renderer stays quiet in both the plan and content apps.
|
|
19
19
|
*
|
|
20
20
|
* Child rendering flows through `ctx.renderBlock` — the app's own block
|
|
21
21
|
* dispatcher — so registered children render via their spec and unconverted
|
|
@@ -30,13 +30,31 @@ function newTabId() {
|
|
|
30
30
|
function isCompact(title) {
|
|
31
31
|
return /interaction|component|note/i.test(title ?? "");
|
|
32
32
|
}
|
|
33
|
+
const tabSettingsInputClass = "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50";
|
|
34
|
+
function tabOrientation(data) {
|
|
35
|
+
return data.orientation === "vertical" ? "vertical" : "horizontal";
|
|
36
|
+
}
|
|
37
|
+
function tabsWith(data, tabs) {
|
|
38
|
+
return { ...data, tabs };
|
|
39
|
+
}
|
|
40
|
+
function tabButtonClass(selected, orientation) {
|
|
41
|
+
return cn("rounded-lg border border-transparent text-sm font-semibold transition-colors", orientation === "vertical"
|
|
42
|
+
? "min-w-0 max-w-72 shrink-0 px-3 py-2 text-left md:w-full md:max-w-none"
|
|
43
|
+
: "shrink-0 whitespace-nowrap px-4 py-2", selected
|
|
44
|
+
? "bg-primary/5 text-foreground dark:bg-primary/10"
|
|
45
|
+
: "text-muted-foreground hover:bg-muted/40 hover:text-foreground");
|
|
46
|
+
}
|
|
47
|
+
function tabLabelClass(orientation) {
|
|
48
|
+
return orientation === "vertical" ? "block min-w-0 truncate" : undefined;
|
|
49
|
+
}
|
|
33
50
|
/** Shared pill-tab rail. */
|
|
34
|
-
function TabRail({ tabs, activeId, onSelect, }) {
|
|
35
|
-
|
|
51
|
+
function TabRail({ tabs, activeId, onSelect, orientation, }) {
|
|
52
|
+
const vertical = orientation === "vertical";
|
|
53
|
+
return (_jsx("div", { className: cn(vertical
|
|
54
|
+
? "mb-5 flex w-full min-w-0 max-w-full flex-nowrap gap-1 overflow-x-auto md:mb-0 md:max-h-[62vh] md:flex-col md:overflow-x-hidden md:overflow-y-auto md:pr-2"
|
|
55
|
+
: "mb-8 flex w-full min-w-0 max-w-full flex-nowrap gap-1 overflow-x-auto"), role: "tablist", "aria-orientation": orientation, "data-plan-interactive": true, children: tabs.map((tab) => {
|
|
36
56
|
const selected = tab.id === activeId;
|
|
37
|
-
return (_jsx("button", { type: "button", role: "tab", "aria-selected": selected, onClick: () => onSelect(tab.id), className:
|
|
38
|
-
? "bg-plan-block text-plan-text shadow-sm"
|
|
39
|
-
: "text-plan-muted hover:bg-plan-block/60 hover:text-plan-text"), children: tab.label }, tab.id));
|
|
57
|
+
return (_jsx("button", { type: "button", role: "tab", "aria-selected": selected, onClick: () => onSelect(tab.id), className: tabButtonClass(selected, orientation), children: _jsx("span", { className: tabLabelClass(orientation), children: tab.label }) }, tab.id));
|
|
40
58
|
}) }));
|
|
41
59
|
}
|
|
42
60
|
/** Read renderer: pill tabs, child blocks rendered read-only via the app. */
|
|
@@ -44,11 +62,14 @@ export function TabsBlockReader({ data, blockId, title, ctx, }) {
|
|
|
44
62
|
const [activeId, setActiveId] = useState(data.tabs[0]?.id ?? "");
|
|
45
63
|
const active = data.tabs.find((tab) => tab.id === activeId) ?? data.tabs[0];
|
|
46
64
|
const compact = isCompact(title);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
65
|
+
const orientation = tabOrientation(data);
|
|
66
|
+
const vertical = orientation === "vertical";
|
|
67
|
+
return (_jsxs("section", { className: "plan-block", "data-block-id": blockId, children: [title && _jsx("div", { className: "plan-block-label", children: title }), _jsxs("div", { className: cn(vertical &&
|
|
68
|
+
"grid min-w-0 gap-5 md:grid-cols-[minmax(10rem,14rem)_minmax(0,1fr)] md:items-start"), children: [_jsx(TabRail, { tabs: data.tabs, activeId: active?.id, onSelect: setActiveId, orientation: orientation }), active && (_jsx("div", { className: cn(vertical && "min-w-0"), children: active.blocks.map((child) => (_jsx("div", { children: ctx.renderBlock?.({
|
|
69
|
+
block: child,
|
|
70
|
+
editing: false,
|
|
71
|
+
compactVisuals: compact,
|
|
72
|
+
}) }, child.id))) }))] })] }));
|
|
52
73
|
}
|
|
53
74
|
/**
|
|
54
75
|
* Editor: pill tabs plus tab management (add/remove/rename), with child blocks
|
|
@@ -61,7 +82,13 @@ export function TabsBlockEditor({ data, onChange, editable, blockId, title, ctx,
|
|
|
61
82
|
const [activeId, setActiveId] = useState(data.tabs[0]?.id ?? "");
|
|
62
83
|
const active = data.tabs.find((tab) => tab.id === activeId) ?? data.tabs[0];
|
|
63
84
|
const compact = isCompact(title);
|
|
64
|
-
const
|
|
85
|
+
const orientation = tabOrientation(data);
|
|
86
|
+
const vertical = orientation === "vertical";
|
|
87
|
+
const commit = (tabs) => onChange(tabsWith(data, tabs));
|
|
88
|
+
const setOrientation = (next) => onChange({
|
|
89
|
+
...data,
|
|
90
|
+
orientation: next === "vertical" ? "vertical" : undefined,
|
|
91
|
+
});
|
|
65
92
|
const renameTab = (id, label) => commit(data.tabs.map((tab) => (tab.id === id ? { ...tab, label } : tab)));
|
|
66
93
|
const removeTab = (id) => {
|
|
67
94
|
const next = data.tabs.filter((tab) => tab.id !== id);
|
|
@@ -92,15 +119,105 @@ export function TabsBlockEditor({ data, onChange, editable, blockId, title, ctx,
|
|
|
92
119
|
// section, so wrapping again here would double-nest. The read renderer
|
|
93
120
|
// (`TabsBlockReader`) owns its own section because read mode renders the spec
|
|
94
121
|
// directly.
|
|
95
|
-
return (
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
122
|
+
return (_jsx("div", { className: "min-w-0", "data-tabs-edit-block": blockId, children: _jsxs("div", { className: cn(vertical &&
|
|
123
|
+
"grid min-w-0 gap-5 md:grid-cols-[minmax(10rem,14rem)_minmax(0,1fr)] md:items-start"), children: [_jsxs("div", { className: cn("flex min-w-0 items-start gap-2", vertical ? "mb-5 md:mb-0" : "mb-8 w-full"), children: [_jsx("div", { className: cn("flex min-w-0 flex-1 gap-1", vertical
|
|
124
|
+
? "flex-nowrap overflow-x-auto md:max-h-[62vh] md:flex-col md:overflow-x-hidden md:overflow-y-auto md:pr-2"
|
|
125
|
+
: "w-full flex-nowrap items-center overflow-x-auto"), role: "tablist", "aria-orientation": orientation, "data-plan-interactive": true, children: data.tabs.map((tab) => {
|
|
126
|
+
const selected = tab.id === active?.id;
|
|
127
|
+
const tabLabel = (_jsx("span", { className: tabLabelClass(orientation), children: tab.label }));
|
|
128
|
+
if (!vertical) {
|
|
129
|
+
return (_jsx("button", { type: "button", role: "tab", "aria-selected": selected, onClick: () => setActiveId(tab.id), className: tabButtonClass(selected, orientation), children: tabLabel }, tab.id));
|
|
130
|
+
}
|
|
131
|
+
const tabButton = (_jsx("button", { type: "button", role: "tab", "aria-selected": selected, onClick: () => setActiveId(tab.id), className: cn(tabButtonClass(selected, orientation), vertical && editable && selected && "pr-9"), children: tabLabel }));
|
|
132
|
+
return (_jsxs("div", { className: "group/tab relative flex min-w-0 max-w-72 shrink-0 md:w-full md:max-w-none", children: [tabButton, editable && selected && (_jsx(TabsSettingsPopover, { active: active, orientation: orientation, tabs: data.tabs, triggerClassName: "pointer-events-none absolute right-1.5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover/tab:pointer-events-auto group-hover/tab:opacity-100 group-focus-within/tab:pointer-events-auto group-focus-within/tab:opacity-100 data-[state=open]:pointer-events-auto data-[state=open]:opacity-100", onRename: renameTab, onOrientationChange: setOrientation, onAdd: addTab, onRemove: removeTab }))] }, tab.id));
|
|
133
|
+
}) }), editable && !vertical && (_jsx(TabsSettingsPopover, { active: active, orientation: orientation, tabs: data.tabs, onRename: renameTab, onOrientationChange: setOrientation, onAdd: addTab, onRemove: removeTab }))] }), active && (_jsx("div", { className: cn(vertical && "min-w-0"), children: ctx.renderBlocksEditor
|
|
134
|
+
? ctx.renderBlocksEditor({
|
|
135
|
+
blocks: active.blocks,
|
|
136
|
+
onChange: (nextBlocks) => onChange({
|
|
137
|
+
...data,
|
|
138
|
+
tabs: data.tabs.map((tab) => tab.id === active.id
|
|
139
|
+
? { ...tab, blocks: nextBlocks }
|
|
140
|
+
: tab),
|
|
141
|
+
}, {
|
|
142
|
+
containerRegion: {
|
|
143
|
+
regionId: active.id,
|
|
144
|
+
blocks: nextBlocks,
|
|
145
|
+
},
|
|
146
|
+
}),
|
|
147
|
+
editable,
|
|
148
|
+
containerBlockId: blockId,
|
|
149
|
+
regionId: active.id,
|
|
150
|
+
regionLabel: active.label,
|
|
151
|
+
compactVisuals: compact,
|
|
152
|
+
})
|
|
153
|
+
: active.blocks.map((child) => (_jsx("div", { children: ctx.renderBlock?.({
|
|
99
154
|
block: child,
|
|
100
155
|
editing: true,
|
|
101
156
|
compactVisuals: compact,
|
|
102
157
|
onChange: (next) => updateChild(active.id, next),
|
|
103
|
-
}) }, child.id))) })] })
|
|
158
|
+
}) }, child.id))) }))] }) }));
|
|
159
|
+
}
|
|
160
|
+
function TabsSettingsPopover({ active, orientation, tabs, onRename, onOrientationChange, onAdd, onRemove, triggerClassName, }) {
|
|
161
|
+
return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { type: "button", "data-plan-interactive": true, "aria-label": "Edit tabs", className: cn("flex size-8 shrink-0 items-center justify-center rounded-md text-plan-muted transition-colors hover:text-plan-text focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", triggerClassName), children: _jsx(IconPencil, { className: "size-4" }) }) }), _jsxs(PopoverContent, { align: "end", side: "bottom", className: "w-80 p-0", "data-plan-interactive": true, children: [_jsxs("div", { className: "border-b border-border px-3 py-2", children: [_jsx("div", { className: "text-sm font-semibold text-foreground", children: "Tab settings" }), _jsx("div", { className: "text-xs text-muted-foreground", children: "Rename the active tab, change layout, or manage the tab set." })] }), _jsxs("div", { className: "grid gap-3 p-3", children: [_jsxs("label", { className: "grid gap-1.5", children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Active tab label" }), _jsx("input", { type: "text", "data-plan-interactive": true, className: tabSettingsInputClass, value: active?.label ?? "", disabled: !active, onChange: (event) => {
|
|
162
|
+
if (!active)
|
|
163
|
+
return;
|
|
164
|
+
onRename(active.id, event.target.value);
|
|
165
|
+
} })] }), _jsxs("label", { className: "grid gap-1.5", children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Layout" }), _jsx("div", { className: "grid grid-cols-2 gap-1 rounded-md border border-border bg-muted/30 p-1", role: "radiogroup", "aria-label": "Tabs layout", children: [
|
|
166
|
+
["horizontal", "Top"],
|
|
167
|
+
["vertical", "Side"],
|
|
168
|
+
].map(([value, label]) => {
|
|
169
|
+
const selected = orientation === value;
|
|
170
|
+
return (_jsx("button", { type: "button", role: "radio", "aria-checked": selected, "data-plan-interactive": true, onClick: () => onOrientationChange(value), className: cn("h-8 rounded px-2 text-xs font-medium transition-colors", selected
|
|
171
|
+
? "bg-background text-foreground"
|
|
172
|
+
: "text-muted-foreground hover:bg-background/70 hover:text-foreground"), children: label }, value));
|
|
173
|
+
}) })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("button", { type: "button", "data-plan-interactive": true, disabled: tabs.length >= 12, onClick: onAdd, className: "inline-flex h-8 items-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50", children: [_jsx(IconPlus, { className: "size-3.5" }), "Add tab"] }), _jsxs("button", { type: "button", "data-plan-interactive": true, disabled: !active || tabs.length <= 1, onClick: () => {
|
|
174
|
+
if (!active)
|
|
175
|
+
return;
|
|
176
|
+
onRemove(active.id);
|
|
177
|
+
}, className: "inline-flex h-8 items-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium text-destructive transition-colors hover:bg-destructive/10 disabled:cursor-not-allowed disabled:opacity-50", children: [_jsx(IconTrash, { className: "size-3.5" }), "Remove current"] })] })] })] })] }));
|
|
178
|
+
}
|
|
179
|
+
function tabRegions(data) {
|
|
180
|
+
return data.tabs.map((tab) => ({
|
|
181
|
+
id: tab.id,
|
|
182
|
+
label: tab.label,
|
|
183
|
+
blocks: tab.blocks,
|
|
184
|
+
}));
|
|
185
|
+
}
|
|
186
|
+
function addTabRegion(data, afterRegionId) {
|
|
187
|
+
if (data.tabs.length >= 12)
|
|
188
|
+
return data;
|
|
189
|
+
const nextTab = {
|
|
190
|
+
id: newTabId(),
|
|
191
|
+
label: `Tab ${data.tabs.length + 1}`,
|
|
192
|
+
blocks: [],
|
|
193
|
+
};
|
|
194
|
+
if (!afterRegionId)
|
|
195
|
+
return tabsWith(data, [...data.tabs, nextTab]);
|
|
196
|
+
const afterIndex = data.tabs.findIndex((tab) => tab.id === afterRegionId);
|
|
197
|
+
if (afterIndex < 0)
|
|
198
|
+
return tabsWith(data, [...data.tabs, nextTab]);
|
|
199
|
+
return tabsWith(data, [
|
|
200
|
+
...data.tabs.slice(0, afterIndex + 1),
|
|
201
|
+
nextTab,
|
|
202
|
+
...data.tabs.slice(afterIndex + 1),
|
|
203
|
+
]);
|
|
204
|
+
}
|
|
205
|
+
function removeTabRegion(data, regionId) {
|
|
206
|
+
if (data.tabs.length <= 1)
|
|
207
|
+
return data;
|
|
208
|
+
return tabsWith(data, data.tabs.filter((tab) => tab.id !== regionId));
|
|
209
|
+
}
|
|
210
|
+
function reorderTabRegion(data, fromRegionId, toRegionId) {
|
|
211
|
+
const fromIndex = data.tabs.findIndex((tab) => tab.id === fromRegionId);
|
|
212
|
+
const toIndex = data.tabs.findIndex((tab) => tab.id === toRegionId);
|
|
213
|
+
if (fromIndex < 0 || toIndex < 0 || fromIndex === toIndex)
|
|
214
|
+
return data;
|
|
215
|
+
const next = [...data.tabs];
|
|
216
|
+
const [moved] = next.splice(fromIndex, 1);
|
|
217
|
+
if (!moved)
|
|
218
|
+
return data;
|
|
219
|
+
next.splice(toIndex, 0, moved);
|
|
220
|
+
return tabsWith(data, next);
|
|
104
221
|
}
|
|
105
222
|
/**
|
|
106
223
|
* The standard tabs block spec (with React `Read`/`Edit`). Apps register this in
|
|
@@ -115,9 +232,17 @@ export const tabsBlock = defineBlock({
|
|
|
115
232
|
Read: TabsBlockReader,
|
|
116
233
|
Edit: TabsBlockEditor,
|
|
117
234
|
placement: ["block", "inline"],
|
|
235
|
+
editSurface: "container",
|
|
236
|
+
container: {
|
|
237
|
+
regions: tabRegions,
|
|
238
|
+
updateRegion: (data, regionId, blocks) => tabsWith(data, data.tabs.map((tab) => tab.id === regionId ? { ...tab, blocks } : tab)),
|
|
239
|
+
addRegion: addTabRegion,
|
|
240
|
+
removeRegion: removeTabRegion,
|
|
241
|
+
reorderRegion: reorderTabRegion,
|
|
242
|
+
},
|
|
118
243
|
label: "Tabs",
|
|
119
244
|
icon: IconLayoutNavbar,
|
|
120
|
-
description: "A
|
|
245
|
+
description: "A top or side tab container; each tab holds its own list of blocks.",
|
|
121
246
|
empty: () => ({ tabs: [{ id: newTabId(), label: "Tab 1", blocks: [] }] }),
|
|
122
247
|
});
|
|
123
248
|
//# sourceMappingURL=tabs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/tabs.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState } from \"react\";\nimport { IconLayoutNavbar, IconPlus, IconX } from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport { defineBlock } from \"../types.js\";\nimport type { BlockReadProps, BlockEditProps, NestedBlock } from \"../types.js\";\nimport {\n tabsSchema,\n tabsMdx,\n type TabsData,\n type TabsTab,\n} from \"./tabs.config.js\";\n\n/**\n * Standard `tabs` block: a horizontal pill-tab container whose tabs each hold a\n * list of child blocks. Lives in core so any app (plan today, content later) can\n * register it.\n *\n * `Read`/`Edit` mirror the legacy plan `TabsBlock` markup byte-for-byte (same\n * `plan-block` section, the `inline-flex` pill tab rail with `role=\"tablist\"`/\n * `role=\"tab\"`, the same active-tab `useState`, and the `compactVisuals`\n * heuristic on the block title) so converting the block to the registry does not\n * change rendered output. The plan CSS classes (`plan-block`, `bg-plan-block`,\n * `text-plan-*`) resolve against the plan app's stylesheet at render time,\n * exactly as before.\n *\n * Child rendering flows through `ctx.renderBlock` — the app's own block\n * dispatcher — so registered children render via their spec and unconverted\n * children fall through the app's legacy switch. This is the coexistence seam:\n * the core tabs block never has to know app-specific child block types.\n */\n\n/** Mint a reasonably-unique tab id without pulling a dep into core. */\nfunction newTabId(): string {\n return `tab-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/** Compact embedded visuals for dense tab panes, matching legacy behavior. */\nfunction isCompact(title: string | undefined): boolean {\n return /interaction|component|note/i.test(title ?? \"\");\n}\n\n/** Shared pill-tab rail. */\nfunction TabRail({\n tabs,\n activeId,\n onSelect,\n}: {\n tabs: TabsTab[];\n activeId: string | undefined;\n onSelect: (id: string) => void;\n}) {\n return (\n <div\n className=\"mb-8 inline-flex max-w-full gap-1 overflow-x-auto\"\n role=\"tablist\"\n data-plan-interactive\n >\n {tabs.map((tab) => {\n const selected = tab.id === activeId;\n return (\n <button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n onClick={() => onSelect(tab.id)}\n className={cn(\n \"rounded-lg px-4 py-2 text-sm font-semibold transition-colors\",\n selected\n ? \"bg-plan-block text-plan-text shadow-sm\"\n : \"text-plan-muted hover:bg-plan-block/60 hover:text-plan-text\",\n )}\n >\n {tab.label}\n </button>\n );\n })}\n </div>\n );\n}\n\n/** Read renderer: pill tabs, child blocks rendered read-only via the app. */\nexport function TabsBlockReader({\n data,\n blockId,\n title,\n ctx,\n}: BlockReadProps<TabsData>) {\n const [activeId, setActiveId] = useState(data.tabs[0]?.id ?? \"\");\n const active = data.tabs.find((tab) => tab.id === activeId) ?? data.tabs[0];\n const compact = isCompact(title);\n return (\n <section className=\"plan-block\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n <TabRail tabs={data.tabs} activeId={active?.id} onSelect={setActiveId} />\n {active && (\n <div>\n {active.blocks.map((child) => (\n <div key={child.id}>\n {ctx.renderBlock?.({\n block: child,\n editing: false,\n compactVisuals: compact,\n })}\n </div>\n ))}\n </div>\n )}\n </section>\n );\n}\n\n/**\n * Editor: pill tabs plus tab management (add/remove/rename), with child blocks\n * rendered editable in place through the app dispatcher. A child change updates\n * that child within its tab and commits the whole tabs block — mirroring the\n * legacy `TabsBlock` onChange bubbling so the plan's recursive `updateBlocks`/\n * `findBlock` (`PlanContentRenderer`) keeps working unchanged.\n */\nexport function TabsBlockEditor({\n data,\n onChange,\n editable,\n blockId,\n title,\n ctx,\n}: BlockEditProps<TabsData>) {\n const [activeId, setActiveId] = useState(data.tabs[0]?.id ?? \"\");\n const active = data.tabs.find((tab) => tab.id === activeId) ?? data.tabs[0];\n const compact = isCompact(title);\n\n const commit = (tabs: TabsTab[]) => onChange({ tabs });\n\n const renameTab = (id: string, label: string) =>\n commit(data.tabs.map((tab) => (tab.id === id ? { ...tab, label } : tab)));\n\n const removeTab = (id: string) => {\n const next = data.tabs.filter((tab) => tab.id !== id);\n if (next.length === 0) return; // tabs must keep at least one (schema min 1)\n commit(next);\n if (activeId === id) setActiveId(next[0]?.id ?? \"\");\n };\n\n const addTab = () => {\n if (data.tabs.length >= 12) return; // schema max\n const id = newTabId();\n commit([\n ...data.tabs,\n { id, label: `Tab ${data.tabs.length + 1}`, blocks: [] },\n ]);\n setActiveId(id);\n };\n\n const updateChild = (tabId: string, child: NestedBlock) =>\n commit(\n data.tabs.map((tab) =>\n tab.id === tabId\n ? {\n ...tab,\n blocks: tab.blocks.map((existing) =>\n existing.id === child.id ? child : existing,\n ),\n }\n : tab,\n ),\n );\n\n // Renders BARE (no `plan-block` section / title): in edit mode the app's\n // block dispatcher already wraps registered editors in a titled `plan-block`\n // section, so wrapping again here would double-nest. The read renderer\n // (`TabsBlockReader`) owns its own section because read mode renders the spec\n // directly.\n return (\n <div data-tabs-edit-block={blockId}>\n <div\n className=\"mb-8 flex max-w-full flex-wrap items-center gap-1 overflow-x-auto\"\n role=\"tablist\"\n data-plan-interactive\n >\n {data.tabs.map((tab) => {\n const selected = tab.id === active?.id;\n return (\n <div\n key={tab.id}\n className={cn(\n \"group flex items-center gap-1 rounded-lg pr-1 transition-colors\",\n selected ? \"bg-plan-block shadow-sm\" : \"hover:bg-plan-block/60\",\n )}\n >\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n onClick={() => setActiveId(tab.id)}\n className={cn(\n \"rounded-lg px-4 py-2 text-sm font-semibold transition-colors\",\n selected ? \"text-plan-text\" : \"text-plan-muted\",\n )}\n >\n {tab.label}\n </button>\n {editable && data.tabs.length > 1 && (\n <button\n type=\"button\"\n data-plan-interactive\n aria-label={`Remove ${tab.label}`}\n className={cn(\n \"flex size-6 shrink-0 items-center justify-center rounded text-plan-muted transition-opacity\",\n \"opacity-0 group-hover:opacity-100 group-focus-within:opacity-100\",\n \"hover:bg-muted hover:text-foreground\",\n )}\n onClick={() => removeTab(tab.id)}\n >\n <IconX className=\"size-3.5 shrink-0\" />\n </button>\n )}\n </div>\n );\n })}\n {editable && data.tabs.length < 12 && (\n <button\n type=\"button\"\n data-plan-interactive\n aria-label=\"Add tab\"\n className=\"flex items-center gap-1.5 rounded-md px-2 py-2 text-sm text-plan-muted hover:bg-plan-block/60 hover:text-plan-text\"\n onClick={addTab}\n >\n <IconPlus className=\"size-4\" />\n Add tab\n </button>\n )}\n </div>\n {active && (\n <div className=\"grid gap-3\">\n {editable && (\n <input\n type=\"text\"\n data-plan-interactive\n className=\"flex h-9 w-full max-w-xs rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n placeholder=\"Tab label\"\n value={active.label}\n onChange={(event) => renameTab(active.id, event.target.value)}\n />\n )}\n <div>\n {active.blocks.map((child) => (\n <div key={child.id}>\n {ctx.renderBlock?.({\n block: child,\n editing: true,\n compactVisuals: compact,\n onChange: (next) => updateChild(active.id, next),\n })}\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n );\n}\n\n/**\n * The standard tabs block spec (with React `Read`/`Edit`). Apps register this in\n * their browser registry. The schema + MDX config come from `./tabs.config.ts`,\n * the exact same object server / agent code registers, so rendering and source\n * round-trip never drift.\n */\nexport const tabsBlock = defineBlock<TabsData>({\n type: \"tabs\",\n schema: tabsSchema,\n mdx: tabsMdx,\n Read: TabsBlockReader,\n Edit: TabsBlockEditor,\n placement: [\"block\", \"inline\"],\n label: \"Tabs\",\n icon: IconLayoutNavbar,\n description:\n \"A horizontal pill-tab container; each tab holds its own list of blocks.\",\n empty: () => ({ tabs: [{ id: newTabId(), label: \"Tab 1\", blocks: [] }] }),\n});\n"]}
|
|
1
|
+
{"version":3,"file":"tabs.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/tabs.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState } from \"react\";\nimport {\n IconLayoutNavbar,\n IconPencil,\n IconPlus,\n IconTrash,\n} from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"../../components/ui/popover.js\";\nimport { defineBlock } from \"../types.js\";\nimport type {\n BlockContainerRegion,\n BlockReadProps,\n BlockEditProps,\n NestedBlock,\n} from \"../types.js\";\nimport {\n tabsSchema,\n tabsMdx,\n type TabsData,\n type TabsOrientation,\n type TabsTab,\n} from \"./tabs.config.js\";\n\n/**\n * Standard `tabs` block: a horizontal pill-tab container whose tabs each hold a\n * list of child blocks. Lives in core so any app (plan today, content later) can\n * register it.\n *\n * `Read`/`Edit` mirror the legacy plan `TabsBlock` markup byte-for-byte (same\n * `plan-block` section, the `inline-flex` pill tab rail with `role=\"tablist\"`/\n * `role=\"tab\"`, the same active-tab `useState`, and the `compactVisuals`\n * heuristic on the block title) so converting the block to the registry does not\n * change rendered output. The block chrome uses semantic shadcn tokens so the\n * same renderer stays quiet in both the plan and content apps.\n *\n * Child rendering flows through `ctx.renderBlock` — the app's own block\n * dispatcher — so registered children render via their spec and unconverted\n * children fall through the app's legacy switch. This is the coexistence seam:\n * the core tabs block never has to know app-specific child block types.\n */\n\n/** Mint a reasonably-unique tab id without pulling a dep into core. */\nfunction newTabId(): string {\n return `tab-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/** Compact embedded visuals for dense tab panes, matching legacy behavior. */\nfunction isCompact(title: string | undefined): boolean {\n return /interaction|component|note/i.test(title ?? \"\");\n}\n\nconst tabSettingsInputClass =\n \"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\";\n\nfunction tabOrientation(data: Pick<TabsData, \"orientation\">): TabsOrientation {\n return data.orientation === \"vertical\" ? \"vertical\" : \"horizontal\";\n}\n\nfunction tabsWith(data: TabsData, tabs: TabsTab[]): TabsData {\n return { ...data, tabs };\n}\n\nfunction tabButtonClass(\n selected: boolean,\n orientation: TabsOrientation,\n): string {\n return cn(\n \"rounded-lg border border-transparent text-sm font-semibold transition-colors\",\n orientation === \"vertical\"\n ? \"min-w-0 max-w-72 shrink-0 px-3 py-2 text-left md:w-full md:max-w-none\"\n : \"shrink-0 whitespace-nowrap px-4 py-2\",\n selected\n ? \"bg-primary/5 text-foreground dark:bg-primary/10\"\n : \"text-muted-foreground hover:bg-muted/40 hover:text-foreground\",\n );\n}\n\nfunction tabLabelClass(orientation: TabsOrientation): string | undefined {\n return orientation === \"vertical\" ? \"block min-w-0 truncate\" : undefined;\n}\n\n/** Shared pill-tab rail. */\nfunction TabRail({\n tabs,\n activeId,\n onSelect,\n orientation,\n}: {\n tabs: TabsTab[];\n activeId: string | undefined;\n onSelect: (id: string) => void;\n orientation: TabsOrientation;\n}) {\n const vertical = orientation === \"vertical\";\n return (\n <div\n className={cn(\n vertical\n ? \"mb-5 flex w-full min-w-0 max-w-full flex-nowrap gap-1 overflow-x-auto md:mb-0 md:max-h-[62vh] md:flex-col md:overflow-x-hidden md:overflow-y-auto md:pr-2\"\n : \"mb-8 flex w-full min-w-0 max-w-full flex-nowrap gap-1 overflow-x-auto\",\n )}\n role=\"tablist\"\n aria-orientation={orientation}\n data-plan-interactive\n >\n {tabs.map((tab) => {\n const selected = tab.id === activeId;\n return (\n <button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n onClick={() => onSelect(tab.id)}\n className={tabButtonClass(selected, orientation)}\n >\n <span className={tabLabelClass(orientation)}>{tab.label}</span>\n </button>\n );\n })}\n </div>\n );\n}\n\n/** Read renderer: pill tabs, child blocks rendered read-only via the app. */\nexport function TabsBlockReader({\n data,\n blockId,\n title,\n ctx,\n}: BlockReadProps<TabsData>) {\n const [activeId, setActiveId] = useState(data.tabs[0]?.id ?? \"\");\n const active = data.tabs.find((tab) => tab.id === activeId) ?? data.tabs[0];\n const compact = isCompact(title);\n const orientation = tabOrientation(data);\n const vertical = orientation === \"vertical\";\n return (\n <section className=\"plan-block\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n <div\n className={cn(\n vertical &&\n \"grid min-w-0 gap-5 md:grid-cols-[minmax(10rem,14rem)_minmax(0,1fr)] md:items-start\",\n )}\n >\n <TabRail\n tabs={data.tabs}\n activeId={active?.id}\n onSelect={setActiveId}\n orientation={orientation}\n />\n {active && (\n <div className={cn(vertical && \"min-w-0\")}>\n {active.blocks.map((child) => (\n <div key={child.id}>\n {ctx.renderBlock?.({\n block: child,\n editing: false,\n compactVisuals: compact,\n })}\n </div>\n ))}\n </div>\n )}\n </div>\n </section>\n );\n}\n\n/**\n * Editor: pill tabs plus tab management (add/remove/rename), with child blocks\n * rendered editable in place through the app dispatcher. A child change updates\n * that child within its tab and commits the whole tabs block — mirroring the\n * legacy `TabsBlock` onChange bubbling so the plan's recursive `updateBlocks`/\n * `findBlock` (`PlanContentRenderer`) keeps working unchanged.\n */\nexport function TabsBlockEditor({\n data,\n onChange,\n editable,\n blockId,\n title,\n ctx,\n}: BlockEditProps<TabsData>) {\n const [activeId, setActiveId] = useState(data.tabs[0]?.id ?? \"\");\n const active = data.tabs.find((tab) => tab.id === activeId) ?? data.tabs[0];\n const compact = isCompact(title);\n const orientation = tabOrientation(data);\n const vertical = orientation === \"vertical\";\n\n const commit = (tabs: TabsTab[]) => onChange(tabsWith(data, tabs));\n\n const setOrientation = (next: TabsOrientation) =>\n onChange({\n ...data,\n orientation: next === \"vertical\" ? \"vertical\" : undefined,\n });\n\n const renameTab = (id: string, label: string) =>\n commit(data.tabs.map((tab) => (tab.id === id ? { ...tab, label } : tab)));\n\n const removeTab = (id: string) => {\n const next = data.tabs.filter((tab) => tab.id !== id);\n if (next.length === 0) return; // tabs must keep at least one (schema min 1)\n commit(next);\n if (activeId === id) setActiveId(next[0]?.id ?? \"\");\n };\n\n const addTab = () => {\n if (data.tabs.length >= 12) return; // schema max\n const id = newTabId();\n commit([\n ...data.tabs,\n { id, label: `Tab ${data.tabs.length + 1}`, blocks: [] },\n ]);\n setActiveId(id);\n };\n\n const updateChild = (tabId: string, child: NestedBlock) =>\n commit(\n data.tabs.map((tab) =>\n tab.id === tabId\n ? {\n ...tab,\n blocks: tab.blocks.map((existing) =>\n existing.id === child.id ? child : existing,\n ),\n }\n : tab,\n ),\n );\n\n // Renders BARE (no `plan-block` section / title): in edit mode the app's\n // block dispatcher already wraps registered editors in a titled `plan-block`\n // section, so wrapping again here would double-nest. The read renderer\n // (`TabsBlockReader`) owns its own section because read mode renders the spec\n // directly.\n return (\n <div className=\"min-w-0\" data-tabs-edit-block={blockId}>\n <div\n className={cn(\n vertical &&\n \"grid min-w-0 gap-5 md:grid-cols-[minmax(10rem,14rem)_minmax(0,1fr)] md:items-start\",\n )}\n >\n <div\n className={cn(\n \"flex min-w-0 items-start gap-2\",\n vertical ? \"mb-5 md:mb-0\" : \"mb-8 w-full\",\n )}\n >\n <div\n className={cn(\n \"flex min-w-0 flex-1 gap-1\",\n vertical\n ? \"flex-nowrap overflow-x-auto md:max-h-[62vh] md:flex-col md:overflow-x-hidden md:overflow-y-auto md:pr-2\"\n : \"w-full flex-nowrap items-center overflow-x-auto\",\n )}\n role=\"tablist\"\n aria-orientation={orientation}\n data-plan-interactive\n >\n {data.tabs.map((tab) => {\n const selected = tab.id === active?.id;\n const tabLabel = (\n <span className={tabLabelClass(orientation)}>{tab.label}</span>\n );\n if (!vertical) {\n return (\n <button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n onClick={() => setActiveId(tab.id)}\n className={tabButtonClass(selected, orientation)}\n >\n {tabLabel}\n </button>\n );\n }\n const tabButton = (\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n onClick={() => setActiveId(tab.id)}\n className={cn(\n tabButtonClass(selected, orientation),\n vertical && editable && selected && \"pr-9\",\n )}\n >\n {tabLabel}\n </button>\n );\n return (\n <div\n key={tab.id}\n className=\"group/tab relative flex min-w-0 max-w-72 shrink-0 md:w-full md:max-w-none\"\n >\n {tabButton}\n {editable && selected && (\n <TabsSettingsPopover\n active={active}\n orientation={orientation}\n tabs={data.tabs}\n triggerClassName=\"pointer-events-none absolute right-1.5 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover/tab:pointer-events-auto group-hover/tab:opacity-100 group-focus-within/tab:pointer-events-auto group-focus-within/tab:opacity-100 data-[state=open]:pointer-events-auto data-[state=open]:opacity-100\"\n onRename={renameTab}\n onOrientationChange={setOrientation}\n onAdd={addTab}\n onRemove={removeTab}\n />\n )}\n </div>\n );\n })}\n </div>\n {editable && !vertical && (\n <TabsSettingsPopover\n active={active}\n orientation={orientation}\n tabs={data.tabs}\n onRename={renameTab}\n onOrientationChange={setOrientation}\n onAdd={addTab}\n onRemove={removeTab}\n />\n )}\n </div>\n {active && (\n <div className={cn(vertical && \"min-w-0\")}>\n {ctx.renderBlocksEditor\n ? ctx.renderBlocksEditor({\n blocks: active.blocks,\n onChange: (nextBlocks) =>\n onChange(\n {\n ...data,\n tabs: data.tabs.map((tab) =>\n tab.id === active.id\n ? { ...tab, blocks: nextBlocks }\n : tab,\n ),\n },\n {\n containerRegion: {\n regionId: active.id,\n blocks: nextBlocks,\n },\n },\n ),\n editable,\n containerBlockId: blockId,\n regionId: active.id,\n regionLabel: active.label,\n compactVisuals: compact,\n })\n : active.blocks.map((child) => (\n <div key={child.id}>\n {ctx.renderBlock?.({\n block: child,\n editing: true,\n compactVisuals: compact,\n onChange: (next) => updateChild(active.id, next),\n })}\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction TabsSettingsPopover({\n active,\n orientation,\n tabs,\n onRename,\n onOrientationChange,\n onAdd,\n onRemove,\n triggerClassName,\n}: {\n active: TabsTab | undefined;\n orientation: TabsOrientation;\n tabs: TabsTab[];\n onRename: (id: string, label: string) => void;\n onOrientationChange: (orientation: TabsOrientation) => void;\n onAdd: () => void;\n onRemove: (id: string) => void;\n triggerClassName?: string;\n}) {\n return (\n <Popover>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n data-plan-interactive\n aria-label=\"Edit tabs\"\n className={cn(\n \"flex size-8 shrink-0 items-center justify-center rounded-md text-plan-muted transition-colors hover:text-plan-text focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\",\n triggerClassName,\n )}\n >\n <IconPencil className=\"size-4\" />\n </button>\n </PopoverTrigger>\n <PopoverContent\n align=\"end\"\n side=\"bottom\"\n className=\"w-80 p-0\"\n data-plan-interactive\n >\n <div className=\"border-b border-border px-3 py-2\">\n <div className=\"text-sm font-semibold text-foreground\">\n Tab settings\n </div>\n <div className=\"text-xs text-muted-foreground\">\n Rename the active tab, change layout, or manage the tab set.\n </div>\n </div>\n <div className=\"grid gap-3 p-3\">\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Active tab label\n </span>\n <input\n type=\"text\"\n data-plan-interactive\n className={tabSettingsInputClass}\n value={active?.label ?? \"\"}\n disabled={!active}\n onChange={(event) => {\n if (!active) return;\n onRename(active.id, event.target.value);\n }}\n />\n </label>\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Layout\n </span>\n <div\n className=\"grid grid-cols-2 gap-1 rounded-md border border-border bg-muted/30 p-1\"\n role=\"radiogroup\"\n aria-label=\"Tabs layout\"\n >\n {(\n [\n [\"horizontal\", \"Top\"],\n [\"vertical\", \"Side\"],\n ] satisfies Array<[TabsOrientation, string]>\n ).map(([value, label]) => {\n const selected = orientation === value;\n return (\n <button\n key={value}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n data-plan-interactive\n onClick={() => onOrientationChange(value)}\n className={cn(\n \"h-8 rounded px-2 text-xs font-medium transition-colors\",\n selected\n ? \"bg-background text-foreground\"\n : \"text-muted-foreground hover:bg-background/70 hover:text-foreground\",\n )}\n >\n {label}\n </button>\n );\n })}\n </div>\n </label>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n data-plan-interactive\n disabled={tabs.length >= 12}\n onClick={onAdd}\n className=\"inline-flex h-8 items-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <IconPlus className=\"size-3.5\" />\n Add tab\n </button>\n <button\n type=\"button\"\n data-plan-interactive\n disabled={!active || tabs.length <= 1}\n onClick={() => {\n if (!active) return;\n onRemove(active.id);\n }}\n className=\"inline-flex h-8 items-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium text-destructive transition-colors hover:bg-destructive/10 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <IconTrash className=\"size-3.5\" />\n Remove current\n </button>\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n\nfunction tabRegions(data: TabsData): BlockContainerRegion[] {\n return data.tabs.map((tab) => ({\n id: tab.id,\n label: tab.label,\n blocks: tab.blocks,\n }));\n}\n\nfunction addTabRegion(data: TabsData, afterRegionId?: string): TabsData {\n if (data.tabs.length >= 12) return data;\n const nextTab: TabsTab = {\n id: newTabId(),\n label: `Tab ${data.tabs.length + 1}`,\n blocks: [],\n };\n if (!afterRegionId) return tabsWith(data, [...data.tabs, nextTab]);\n const afterIndex = data.tabs.findIndex((tab) => tab.id === afterRegionId);\n if (afterIndex < 0) return tabsWith(data, [...data.tabs, nextTab]);\n return tabsWith(data, [\n ...data.tabs.slice(0, afterIndex + 1),\n nextTab,\n ...data.tabs.slice(afterIndex + 1),\n ]);\n}\n\nfunction removeTabRegion(data: TabsData, regionId: string): TabsData {\n if (data.tabs.length <= 1) return data;\n return tabsWith(\n data,\n data.tabs.filter((tab) => tab.id !== regionId),\n );\n}\n\nfunction reorderTabRegion(\n data: TabsData,\n fromRegionId: string,\n toRegionId: string,\n): TabsData {\n const fromIndex = data.tabs.findIndex((tab) => tab.id === fromRegionId);\n const toIndex = data.tabs.findIndex((tab) => tab.id === toRegionId);\n if (fromIndex < 0 || toIndex < 0 || fromIndex === toIndex) return data;\n const next = [...data.tabs];\n const [moved] = next.splice(fromIndex, 1);\n if (!moved) return data;\n next.splice(toIndex, 0, moved);\n return tabsWith(data, next);\n}\n\n/**\n * The standard tabs block spec (with React `Read`/`Edit`). Apps register this in\n * their browser registry. The schema + MDX config come from `./tabs.config.ts`,\n * the exact same object server / agent code registers, so rendering and source\n * round-trip never drift.\n */\nexport const tabsBlock = defineBlock<TabsData>({\n type: \"tabs\",\n schema: tabsSchema,\n mdx: tabsMdx,\n Read: TabsBlockReader,\n Edit: TabsBlockEditor,\n placement: [\"block\", \"inline\"],\n editSurface: \"container\",\n container: {\n regions: tabRegions,\n updateRegion: (data, regionId, blocks) =>\n tabsWith(\n data,\n data.tabs.map((tab) =>\n tab.id === regionId ? { ...tab, blocks } : tab,\n ),\n ),\n addRegion: addTabRegion,\n removeRegion: removeTabRegion,\n reorderRegion: reorderTabRegion,\n },\n label: \"Tabs\",\n icon: IconLayoutNavbar,\n description:\n \"A top or side tab container; each tab holds its own list of blocks.\",\n empty: () => ({ tabs: [{ id: newTabId(), label: \"Tab 1\", blocks: [] }] }),\n});\n"]}
|
|
@@ -19,7 +19,8 @@ export { checklistSchema, checklistMdx, type ChecklistData, type ChecklistItem,
|
|
|
19
19
|
export { tableSchema, tableMdx, type TableData, } from "./library/table.config.js";
|
|
20
20
|
export { codeTabsSchema, codeTabsMdx, type CodeTabsData, type CodeTabsTab, } from "./library/code-tabs.config.js";
|
|
21
21
|
export { htmlSchema, htmlMdx, type HtmlBlockData, } from "./library/html.config.js";
|
|
22
|
-
export { tabsSchema, tabsMdx, type TabsData, type TabsTab, } from "./library/tabs.config.js";
|
|
22
|
+
export { tabsSchema, tabsMdx, type TabsData, type TabsOrientation, type TabsTab, } from "./library/tabs.config.js";
|
|
23
|
+
export { columnsSchema, columnsMdx, type ColumnsData, type ColumnsColumn, } from "./library/columns.config.js";
|
|
23
24
|
export { mermaidSchema, mermaidMdx, type MermaidData, } from "./library/mermaid.config.js";
|
|
24
25
|
export { apiEndpointSchema, apiEndpointMdx, API_ENDPOINT_METHODS, API_PARAM_LOCATIONS, type ApiEndpointData, type ApiEndpointMethod, type ApiEndpointParam, type ApiEndpointRequest, type ApiEndpointResponse, type ApiParamLocation, } from "./library/api-endpoint.config.js";
|
|
25
26
|
export { dataModelSchema, dataModelMdx, DATA_MODEL_RELATION_KINDS, type DataModelData, type DataModelEntity, type DataModelField, type DataModelRelation, type DataModelRelationKind, } from "./library/data-model.config.js";
|