Skip to content

Commit 8139d2f

Browse files
gohaberegclaude
andcommitted
docs(openspec): close the CMD+B task and fix the adapter scenario for headless Core
Two loose ends this branch owned: `architecture` still asserted "Default adapter is DOMAdapters" — that Core's constructor calls `this.use(DOMAdapters)`. True at merge-base and still true on main, but this branch made Core headless and dropped that call, so the scenario was false here and contradicted core/spec.md's "No adapter registered fails loudly". The bundle change wrote deltas for `core` and `editorjs-bundle` and missed that the same fact was asserted in `architecture` too. Replaced with "No adapter is bound by default", and tightened the parent requirement to say Core never binds an adapter itself. Task 4.6 was blocked on nothing dispatching `KeydownUIEvent`. That producer landed with #184 (Blocks.ts:125), now merged in. Re-verified in the playground through the bundle: CMD+B bolds and toggles off, CMD+I italicizes, toolbar active states track the model. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 3b61926 commit 8139d2f

2 files changed

Lines changed: 7 additions & 7 deletions

File tree

  • openspec
    • changes/archive/2026-07-22-add-editorjs-bundle-package
    • specs/architecture

openspec/changes/archive/2026-07-22-add-editorjs-bundle-package/tasks.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
- [x] 4.3 Run the full workspace build + typecheck + lint
3333
- [x] 4.4 Run the playground and verify end-to-end: editor renders (3 paragraphs), typing updates the model, inline toolbar renders. (Pre-existing, unrelated `collaboration-manager` "Unknown event type DataNodeAddedEvent" console noise remains — out of scope.)
3434
- [x] 4.5 Add a bundle test asserting a `config.tools` entry named `paragraph` overrides (does not duplicate) the default, and that `isReady` rejects on init failure
35-
- [ ] 4.6 (Blocked) Re-verify keyboard shortcuts end-to-end in the playground (CMD+B through the bundle). Verified in-browser that this does **not** work yet and cannot on this branch: `ShortcutsPlugin` listens for `ui:key-down` (`KeydownUIEvent`), but nothing dispatches that event `packages/ui/src/Blocks/Blocks.ts` only handles CMD+Z/CMD+SHIFT+Z locally and returns early for every other key. Registering the plugin is necessary but not sufficient; the producer side lands with the `BlocksUI` keydown dispatch in the plugin-public-api change (PR #184). Bold itself works: the inline toolbar's B button applies `<b>` to the selection, so this is specifically the shortcut path.
35+
- [x] 4.6 Re-verify keyboard shortcuts end-to-end in the playground (CMD+B through the bundle). Was blocked on the missing producer: `ShortcutsPlugin` listens for `ui:key-down` (`KeydownUIEvent`), but nothing dispatched it `packages/ui/src/Blocks/Blocks.ts` handled CMD+Z/CMD+SHIFT+Z locally and returned early for every other key. That dispatch landed with the plugin-public-api change (PR #184, now merged into this branch) at `Blocks.ts:125`. Re-verified in-browser through the bundle: CMD+B bolds the selection and the toolbar's B goes active, CMD+B again unformats it, and CMD+I italicizes — so both the Format and Unformat branches work, and the handler table is populated from the namespaced `static options.plugins.shortcuts.shortcut` that Bold and Italic declare.
3636

3737
## 5. Finalize
3838

openspec/specs/architecture/spec.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Purpose
44

5-
Cross-cutting structural invariants that span multiple packages and aren't owned by any single capability spec: the dependency direction between packages, the event-channel naming convention used across the `EventBus`, the single-adapter contract `core` enforces, and which undo/redo implementation takes precedence when collaboration is enabled. These constrain how packages may depend on and communicate with each other; package-specific behavior lives in the respective capability specs ([[model-types]], [[sdk]], [[model]], [[dom-adapters]], [[collaboration-manager]], [[core]], [[ui]], [[ot-server]], [[tools]]).
5+
Cross-cutting structural invariants that span multiple packages and aren't owned by any single capability spec: the dependency direction between packages, the event-channel naming convention used across the `EventBus`, the single-adapter contract `core` enforces, and which undo/redo implementation takes precedence when collaboration is enabled. These constrain how packages may depend on and communicate with each other; package-specific behavior lives in the respective capability specs ([[model-types]], [[sdk]], [[model]], [[dom-adapters]], [[collaboration-manager]], [[core]], [[ui]], [[ot-server]], [[tools]], [[editorjs-bundle]]).
66

77
## Requirements
88

@@ -42,19 +42,19 @@ Every event dispatched on an `EventBus` SHALL be namespaced by its origin as a `
4242
Implemented in `packages/sdk/src/entities/EventBus/events/core/CoreEventBase.ts`, `.../ui/UIEventBase.ts`, `.../core/CoreEventType.ts`, `.../adapter/AdapterEventType.ts`.
4343

4444
### Requirement: Exactly one adapter plugin is bound
45-
`Core` SHALL require exactly one `PluginType.Adapter` plugin bound in its plugin container at initialization time. Registering a second adapter via `use()` SHALL replace the previously bound one rather than error or bind both.
45+
`Core` SHALL require exactly one `PluginType.Adapter` plugin bound in its plugin container at initialization time, and SHALL NOT bind one itself — every adapter reaches the container through a `use()` call. Registering a second adapter via `use()` SHALL replace the previously bound one rather than error or bind both.
4646

4747
#### Scenario: Registering a second adapter replaces the first
4848
- **GIVEN** an adapter plugin has already been registered via `core.use(SomeAdapter)`
4949
- **WHEN** `core.use(AnotherAdapter)` is called with another `PluginType.Adapter` plugin
5050
- **THEN** the container rebinds `PluginType.Adapter` to the new adapter, so only the most recently registered adapter is active when `#initializeAdapter()` runs
5151

52-
#### Scenario: Default adapter is DOMAdapters
52+
#### Scenario: No adapter is bound by default
5353
- **GIVEN** a `Core` instance is constructed without an explicit adapter registration
54-
- **WHEN** the constructor runs
55-
- **THEN** it calls `this.use(DOMAdapters)`, so `@editorjs/dom-adapters` is bound as the default adapter
54+
- **WHEN** `initialize()` is called
55+
- **THEN** it throws rather than falling back to a built-in adapter, because `Core` is headless: binding `@editorjs/dom-adapters` is the caller's job, which [[editorjs-bundle]] does on the caller's behalf
5656

57-
Implemented in `packages/core/src/index.ts` (`use()`, `#initializeAdapter()`), `packages/core/src/tokens.ts` (`TOKENS.Adapter`).
57+
Implemented in `packages/core/src/index.ts` (`use()`, `#validatePreconditions()`, `#initializeAdapter()`), `packages/core/src/tokens.ts` (`TOKENS.Adapter`), `packages/editorjs/src/index.ts` (`this.#core.use(DOMAdapters)`).
5858

5959
### Requirement: Collaboration's undo/redo preempts core's local undo/redo
6060
When `@editorjs/collaboration-manager` is registered, it SHALL intercept `core:undo`/`core:redo` events and call `preventDefault()` on them before `core`'s own `UndoRedoManager` acts, substituting its own OT-aware undo/redo (which accounts for remote operations) for `core`'s local-only undo/redo. This is an intentional override, not a duplicated/competing implementation.

0 commit comments

Comments
 (0)