1d105b1f55
Publish to NPM / Check version changes and publish (push) Successful in 9m58s
Two gaps an author hits within the first minute of using atom blocks: - there was no way to add a paragraph after a non-text block. Enter on a selected atom now starts a paragraph below it (exitAtom, chained before splitBlock), and a click on the root's padding below a trailing atom does the same — ends-in-text just places the caret at the end - the slash menu ignored its own overflow: keyboard navigation walked the highlight out of view (now scrollIntoView nearest), and a background wheel scroll tore the menu off its caret anchor (now prevented outside the menu; scrolling the list itself stays native) - BlockMeta gains `description`; the menu shows a detail pane beside the list with the highlighted item's description, replaceable wholesale via the new #preview slot. Headless stays headless: the pane is unstyled text and appears only when there is a description or a slot. Preset blocks are all described Both floating menus (slash, bubble) are re-layered to the combobox convention: PopperRoot provides the positioning context OUTSIDE a bare Portal, which resolves its target from the ConfigProvider's teleportTarget — the previous hardcoded to="body" was overriding the app's configured target. A Combobox itself is the wrong base here on purpose: its keyboard lives on ComboboxInput, while a suggestion menu must leave focus in the contenteditable — the editor is the input. writekit 0.0.3. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
19 lines
729 B
TypeScript
19 lines
729 B
TypeScript
import { defineBlock } from '../registry';
|
||
|
||
const LEVELS = [1, 2, 3, 4, 5, 6] as const;
|
||
|
||
export const heading = defineBlock({
|
||
type: 'heading',
|
||
spec: {
|
||
content: { kind: 'text' },
|
||
group: 'block',
|
||
attrs: {
|
||
level: { default: 1, validate: value => typeof value === 'number' && value >= 1 && value <= 6 },
|
||
},
|
||
toDOM: node => [`h${node.attrs['level'] ?? 1}`, 0],
|
||
parseDOM: LEVELS.map(level => ({ tag: `h${level}`, attrs: { level } })),
|
||
},
|
||
inputRules: LEVELS.map(level => ({ match: new RegExp(`^#{${level}}\\s$`), attrs: { level } })),
|
||
meta: { title: 'Heading', icon: 'heading', keywords: ['heading', 'title', 'h1', 'h2', 'h3'], group: 'basic', description: 'A section title, levels 1–6.' },
|
||
});
|