note-type-registry - #68
Merged
Merged
Conversation
Extend NoteTypeProvider in packages/core with optional UI capability fields (supportedModes, sourceProtected, supportsScrollSync, viewComponent, toolbarItems, contextMenuBuilder) so built-in note types and plugins share a single registration pattern. Key changes: - Add NoteViewMode, NoteTypeToolbarItem, and UI fields to NoteTypeProvider in packages/core/src/contracts.ts (fields typed as unknown to keep core React-free) - New NoteViewRegistry in packages/core — runtime map of note-type IDs to full NoteTypeProvider; disposer-based register/unregister - Each built-in note-type package exports registerBuiltinNoteView(registry) mirroring the plugin registration pattern - packages/editor/src/markdown-note-view.ts provides the markdown built-in registration (avoids circular dep: core must not import React components) - packages/editor/src/note-view-descriptor.ts narrows opaque unknown fields to typed React ComponentType/ReactNode/NoteViewContextMenuBuilder - PluginContext and PluginHost gain registerNoteView(); PluginManager wires it through buildContext() alongside registerFileHandler() - use-plugins.ts creates a stable NoteViewRegistry, registers all built-ins at hook init, and exposes it via PluginsApi/AppServices - markdown-editor.tsx replaces hardcoded NOTE_RENDERERS map with registry lookup; applies sourceProtected, supportedModes, supportsScrollSync from the active descriptor - ModeToggle accepts supportedModes and supportsScrollSync props to filter visible mode buttons and conditionally show the scroll-sync toggle - Context-menu builder from descriptor seeds noteViewCtxBuilder on type change All 156 tests pass; typecheck clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tor, extract sync hooks
## Mode consolidation
EditorMode in packages/editor/src/types.ts is now a re-export alias of
NoteViewMode from packages/core — one canonical definition, zero drift.
Inline ['edit','split','rendered'] as EditorMode[] casts replaced with
EDITOR_MODES throughout.
## Built-in registration moved to app.tsx
NoteViewRegistry creation and all registerBuiltinNoteView() calls moved out
of usePlugins into the App component — an explicit app-level concern.
usePlugins now accepts the registry as a parameter and focuses solely on
the plugin lifecycle. The missing-dep lint warning is resolved.
## Sync hooks extracted (packages/editor/src/use-pane-sync.ts)
Three dedicated hooks replace the inline state/ref boilerplate:
useCursorSync(initialPosition) — { request: CursorRequest, send }
useScrollSync(initialRatio) — { request: ScrollRequest, send }
useFocusSync() — { request: FocusRequest, send }
A generic usePaneSync<T> base is also exported for advanced use.
Scroll-sync lock refs (feedback-loop prevention) live as plain useRef at
the call site — not inside the hook — to satisfy react-hooks/immutability.
## MarkdownEditor merged into NoteEditor
MarkdownEditor no longer orchestrates file I/O, registry routing, or
callbacks — NoteEditor owns all of that directly. MarkdownEditor is now a
lightweight, self-contained inline editor component (no web-app imports,
accepts callbacks as a prop) for use in board cards, calendar events, etc.
The six cross-package imports from @notes/web/src/... are gone from it.
## Lint fixes
- note-editor: setState-in-effect replaced with inline derivation for
context-menu builder (descriptor builder computed directly, component
builder overrides via state as before)
- markdown-editor / note-editor: NoteRenderer resolved via DynamicNoteRenderer
wrapper (declared at module level) to satisfy react-hooks/static-components
- plugin-manager.test.ts: unused parameter removed
All 156 tests pass; typecheck clean; lint clean.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eEditorCallbacks
## MarkdownEditor removed
Board cards and calendar event-details now use RenderedEditor directly
(they only ever rendered in 'rendered' mode — MarkdownEditor was pure overhead).
The MarkdownEditor component is deleted; its types migrate to types.ts:
- MarkdownPane, MarkdownViewState, DEFAULT_MARKDOWN_VIEW_STATE
- RendererProps (sync props removed — now come from PaneSyncContext)
markdown-editor.tsx is emptied; removed from editor/index.ts.
## useEditorCallbacks hook (apps/web/src/state/use-editor-callbacks.tsx)
Extracts the EditorCallbacks construction (wikilink navigation, file
imports, embed rendering, tag/note listing) out of NoteEditor into a
dedicated hook. NoteEditor now calls useEditorCallbacks(isStandalone).
## PaneSyncContext (packages/editor/src/pane-sync-context.tsx)
A React context that carries the full pane-sync state so components no
longer need sync props drilled through them:
- PaneSyncProvider — wraps source + rendered panes in NoteEditor
- useSourcePaneSync() — NativeSourceEditor calls this for cursor/scroll/
focus requests, handlers, callbacks, isReadOnly
- useRenderedPaneSync() — RenderedEditor calls this for the same
Both hooks return undefined outside a provider (graceful standalone use).
## Updated consumers
- NativeSourceEditor: drops all sync/callbacks props; calls useSourcePaneSync()
and merges context over prop fallbacks. Props kept optional for backward compat.
- RenderedEditor: drops all sync props from RenderedEditorProps; calls
useRenderedPaneSync() and merges context over props.
- NoteEditor: wraps markdown panes in PaneSyncProvider; passes only
value/onChange/path/isStandalone/callbacks/onRegisterContextMenu to
DynamicNoteRenderer (sync no longer prop-drilled).
All 156 tests pass; typecheck clean; lint clean.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Component
## Naming — one language, everything is a 'note type'
NoteTypeProvider renamed to NoteTypeDescriptor:
- The 'Provider' suffix implied a React context provider; NoteEditor
already called it 'activeDescriptor', which is the right term.
NoteViewRegistry merged into NoteTypeRegistry:
- Both classes stored the same NoteTypeDescriptor objects; two separate
registries was confusing mixing of 'Type' and 'View' namespaces.
- NoteTypeRegistry.register() now returns a () => void disposer so
plugins and built-ins can unregister cleanly (NoteViewDisposer removed).
Registration functions renamed for consistency:
- registerBuiltinNoteView -> registerBuiltinNoteType (all note-* packages)
- registerMarkdownNoteView -> registerMarkdownNoteType (@notes/editor)
- PluginContext.registerNoteView -> registerNoteType
- Variable noteViewRegistry -> noteTypeRegistry everywhere
## NoteTypeViewDescriptor — properly typed viewComponent
Added NoteTypeViewDescriptor in packages/editor/src/note-view-descriptor.ts,
extending NoteTypeDescriptor with React-typed fields:
- viewComponent?: ComponentType<RendererProps> (not unknown)
- toolbarItems?: TypedNoteTypeToolbarItem[]
- contextMenuBuilder?: NoteViewContextMenuBuilder
All registerBuiltinNoteType functions now annotate their descriptor as
NoteTypeViewDescriptor so TypeScript validates the view component type at
registration time, not just at the point of use.
## Uniform RendererProps for all note view components
BoardView, CanvasView, CalendarView, MermaidView, GridView all previously
had bespoke local props interfaces. Each now uses RendererProps directly.
All 156 tests pass; typecheck clean; lint clean.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ove full type to editor
The previous split had NoteTypeDescriptor (core, unknown fields) and
NoteTypeViewDescriptor (editor, typed fields) — two interfaces for the
same concept, and a correspondingly split markdownNoteType / registerMarkdownNoteType.
## New structure
packages/core:
NoteTypeDetector { id, detect } — minimal interface for server-side detection
NoteTypeRegistry<T extends NoteTypeDetector> — generic; default T = NoteTypeDetector
packages/editor:
NoteTypeDescriptor extends NoteTypeDetector — THE complete descriptor; no opaque
fields, all React types are concrete (viewComponent: ComponentType<RendererProps>,
toolbarItems: NoteTypeToolbarItem[], contextMenuBuilder: NoteViewContextMenuBuilder)
NoteTypeToolbarItem — moved here from core (now properly typed with ReactNode)
EditorMode defined directly (no NoteViewMode alias from core)
## Consequences
- NoteTypeViewDescriptor deleted entirely — it IS NoteTypeDescriptor now
- markdownNoteType in core is a bare NoteTypeDetector (id + detect only)
- markdownDescriptor in packages/editor is the complete descriptor, including
viewComponent: RenderedEditor, supportedModes, supportsScrollSync — one place
- registerMarkdownNoteType accepts NoteTypeRegistry<NoteTypeDescriptor>
- All note-* packages import NoteTypeDescriptor from @notes/editor
- NoteTypeRegistry<NoteTypeDescriptor> used client-side; server still uses
the untyped default (NoteTypeRegistry == NoteTypeRegistry<NoteTypeDetector>)
- Accessor helpers (getNoteViewComponent etc.) simplified: no casts needed since
fields are already properly typed in NoteTypeDescriptor
All 156 tests pass; typecheck clean; lint clean.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.