{"id":51429493,"url":"https://github.com/bnomei/emdash-blocks","last_synced_at":"2026-07-05T03:02:10.700Z","repository":{"id":365483851,"uuid":"1267752849","full_name":"bnomei/emdash-blocks","owner":"bnomei","description":"JSON block-list field widget for EmDash entries, with normalized block props and visibility state.","archived":false,"fork":false,"pushed_at":"2026-06-29T15:08:22.000Z","size":534,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-29T16:32:25.578Z","etag":null,"topics":["astro","block","block-editor","cms","custom","dynamic","emdash","emdash-plugin","field-widget","javascript","json","react","sort"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bnomei.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"bnomei","buy_me_a_coffee":"bnomei"}},"created_at":"2026-06-12T20:40:14.000Z","updated_at":"2026-06-29T15:08:39.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/bnomei/emdash-blocks","commit_stats":null,"previous_names":["bnomei/emdash-blocks"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/bnomei/emdash-blocks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bnomei%2Femdash-blocks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bnomei%2Femdash-blocks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bnomei%2Femdash-blocks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bnomei%2Femdash-blocks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bnomei","download_url":"https://codeload.github.com/bnomei/emdash-blocks/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bnomei%2Femdash-blocks/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35141966,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-05T02:00:06.290Z","response_time":100,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["astro","block","block-editor","cms","custom","dynamic","emdash","emdash-plugin","field-widget","javascript","json","react","sort"],"created_at":"2026-07-05T03:02:08.002Z","updated_at":"2026-07-05T03:02:10.694Z","avatar_url":"https://github.com/bnomei.png","language":"TypeScript","funding_links":["https://github.com/sponsors/bnomei","https://buymeacoffee.com/bnomei"],"categories":[],"sub_categories":[],"readme":"# @bnomei/emdash-blocks\n\n[![npm version](https://img.shields.io/npm/v/@bnomei/emdash-blocks.svg)](https://www.npmjs.com/package/@bnomei/emdash-blocks)\n[![npm downloads](https://img.shields.io/npm/dm/@bnomei/emdash-blocks.svg)](https://www.npmjs.com/package/@bnomei/emdash-blocks)\n[![license](https://img.shields.io/npm/l/@bnomei/emdash-blocks.svg)](https://www.npmjs.com/package/@bnomei/emdash-blocks)\n[![types](https://img.shields.io/badge/types-included-blue.svg)](./package.json)\n[![source](https://img.shields.io/badge/source-GitHub-181717.svg?logo=github)](https://github.com/bnomei/emdash-blocks)\n\nStructured block-list editor for EmDash JSON fields.\n\n`@bnomei/emdash-blocks` is a native EmDash plugin for ordered\ncontent blocks stored as plain JSON. It registers the `block-builder:blocks`\nadmin widget, lets schemas define project-specific block types and typed prop\ncontrols, and exports runtime helpers for Astro renderers. Use it when an\nEmDash site needs controlled page sections, marketing modules, email blocks, or\nimported block data without moving that content into Portable Text.\n\n## What It Provides\n\n- Native EmDash plugin factory: `blockBuilderPlugin()`.\n- JSON field widget: `block-builder:blocks`.\n- Stored value shape for ordered blocks with `id`, `type`, `hidden`, and\n  `props`.\n- Admin UI built with [Kumo UI](https://kumo-ui.com/) with full light and dark\n  mode support.\n- Frontend helpers: `visibleBlocks()`, `blockProps()`, and\n  `isBlockBuilderBlock()`.\n\n## Install\n\n```sh\nnpm install @bnomei/emdash-blocks\n```\n\nRegister the plugin in `astro.config.mjs`:\n\n```js\nimport emdash from \"emdash/astro\";\nimport { blockBuilderPlugin } from \"@bnomei/emdash-blocks\";\n\nexport default {\n  integrations: [\n    emdash({\n      plugins: [blockBuilderPlugin()],\n    }),\n  ],\n};\n```\n\n## Field Widget\n\nUse the widget on an EmDash `json` field:\n\nBlock configuration belongs to the field's `options` object. The Astro plugin\nconfiguration registers the widget; it does not provide per-field block schemas.\n\nUse `options.blockTypes` when you only need a compact type catalog for the block\ntype dropdown. Built-in block types still use their built-in prop fields. Use\n`options.blockDefinitions` when the editor should render project-specific typed\nprop controls and defaults for each block type.\n\n```json\n{\n  \"slug\": \"blocks\",\n  \"label\": \"Blocks\",\n  \"type\": \"json\",\n  \"widget\": \"block-builder:blocks\",\n  \"options\": {\n    \"blockTypes\": [\n      { \"type\": \"heading\", \"label\": \"Heading\" },\n      { \"type\": \"text\", \"label\": \"Text\" },\n      { \"type\": \"image\", \"label\": \"Image\" }\n    ]\n  }\n}\n```\n\nUse `blockDefinitions` when the editor should render project-specific typed prop\ncontrols instead of only selecting block types. TypeScript schemas can import\n`BlockBuilderOptions` from the public package entry to type field options:\n\n```ts\nimport type { BlockBuilderOptions } from \"@bnomei/emdash-blocks\";\n\nconst blockOptions: BlockBuilderOptions = {\n  blockDefinitions: [\n    {\n      type: \"heading\",\n      label: \"Heading\",\n      props: [\n        { key: \"text\", label: \"Text\", type: \"text\" },\n        {\n          key: \"level\",\n          label: \"Level\",\n          type: \"select\",\n          defaultValue: \"h2\",\n          options: [\"h1\", \"h2\", \"h3\", \"h4\"],\n        },\n      ],\n    },\n  ],\n};\n\nconst blocksField = {\n  slug: \"blocks\",\n  label: \"Blocks\",\n  type: \"json\",\n  widget: \"block-builder:blocks\",\n  options: blockOptions,\n};\n```\n\nThe same options can be used directly in JSON schemas:\n\n```json\n{\n  \"slug\": \"blocks\",\n  \"label\": \"Blocks\",\n  \"type\": \"json\",\n  \"widget\": \"block-builder:blocks\",\n  \"options\": {\n    \"blockDefinitions\": [\n      {\n        \"type\": \"heading\",\n        \"label\": \"Heading\",\n        \"props\": [\n          { \"key\": \"text\", \"label\": \"Text\", \"type\": \"text\" },\n          {\n            \"key\": \"level\",\n            \"label\": \"Level\",\n            \"type\": \"select\",\n            \"defaultValue\": \"h2\",\n            \"options\": [\"h1\", \"h2\", \"h3\", \"h4\"]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\nSupported prop field types include all 16 EmDash field types: `string`, `text`,\n`url`, `number`, `integer`, `boolean`, `datetime`, `select`, `multiSelect`,\n`portableText`, `image`, `file`, `reference`, `json`, `slug`, and `repeater`.\n\nThe block builder also supports generic block-editor field types: `writer`,\n`markdown`, `textarea`, `color`, `media`, and `media-list`. Text-like fields\nrender as text inputs or textareas, numeric fields normalize numeric values,\n`boolean` renders as a switch, `select` and `multiSelect` render choice controls,\nand `portableText`/`writer` render the built-in rich text editor with paragraph,\nheading, quote, bold, italic, list, and link controls. `media` and `media-list`\nrender media-library selectors backed by EmDash media values. `json` and\n`repeater` use focused JSON editors, with `repeater` stored as a JSON array until\na dedicated repeater UI is available. `image`, `file`, `reference`, and `slug`\nrender ID/text inputs that match EmDash's stored values for those field types.\n\nProject-specific block types should be supplied through field options, or from a\nsite-local helper/plugin that writes those options. Keep the publishable block\nbuilder package focused on generic block editing.\n\nThe package defaults include only generic starter blocks. Site-specific blocks\nbelong in `options.blockDefinitions` on each field schema.\n\n## Stored Value\n\n```ts\ntype BlockBuilderValue = Array\u003c{\n  id: string;\n  type: string;\n  hidden?: boolean;\n  props: Record\u003cstring, unknown\u003e;\n}\u003e;\n```\n\n## Frontend Rendering\n\nThe package exports helpers for frontend renderers:\n\n```ts\nimport { blockProps, isBlockBuilderBlock, visibleBlocks } from \"@bnomei/emdash-blocks\";\n\nconst blocks = visibleBlocks(entry.blocks);\n```\n\nRenderers should use `block.type` to pick a component and `block.props` for that\ncomponent's data:\n\n```astro\n{\n  blocks.map((block) =\u003e (\n    \u003c\u003e\n      {block.type === \"heading\" \u0026\u0026 \u003cHeadingBlock props={blockProps(block)} /\u003e}\n      {block.type === \"text\" \u0026\u0026 \u003cTextBlock props={blockProps(block)} /\u003e}\n    \u003c/\u003e\n  ))\n}\n```\n\n`visibleBlocks()` accepts native Block Builder values and filters hidden blocks.\nMigration from other systems should happen before values are saved into EmDash.\n\n## Package Surface\n\n- ESM entry: `@bnomei/emdash-blocks`.\n- Admin entry: `@bnomei/emdash-blocks/admin`.\n- Type declarations are included from `dist/`.\n- Peer dependencies: `emdash` `\u003e=0.17.0`, `react` `^18.0.0 || ^19.0.0`,\n  `react-dom` `^18.0.0 || ^19.0.0`, `@cloudflare/kumo` `^2.5.0`, and `@phosphor-icons/react`\n  `^2.1.10`.\n\n## Status\n\nThis package ships as a native EmDash plugin because the editor is a trusted React admin field widget. Package exports point at `vp pack`-built `dist/` JavaScript and declarations.\n\n## Related Packages\n\n- `@bnomei/emdash-fields` provides smaller JSON-backed field widgets.\n- `@bnomei/emdash-bento` provides row and column layout editing and\n  reuses Block Builder for nested blocks.\n\n## License\n\nMIT.\n\n## Screenshot\n\n![Block Builder screenshot](./screenshot.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbnomei%2Femdash-blocks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbnomei%2Femdash-blocks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbnomei%2Femdash-blocks/lists"}