Two build targets — core and full

dist/ribbit/ribbit-core.js    — editor without extra features
dist/ribbit/ribbit.js         — editor with all features

Added a theme feature flag for vim keybindings
This commit is contained in:
gsb 2026-04-29 07:48:06 +00:00
parent 3368e719fd
commit 2e28598243
5 changed files with 48 additions and 22 deletions

View File

@ -7,10 +7,12 @@
"dist/ribbit/"
],
"scripts": {
"build": "mkdir -p dist/ribbit && npm run build:check && npm run build:js && npm run build:min && npm run build:css",
"build": "mkdir -p dist/ribbit && npm run build:check && npm run build:js && npm run build:min && npm run build:core && npm run build:core-min && npm run build:css",
"build:check": "tsc --noEmit",
"build:js": "esbuild src/ts/ribbit-editor.ts --bundle --format=iife --global-name=ribbit --sourcemap --outfile=dist/ribbit/ribbit.js",
"build:min": "esbuild src/ts/ribbit-editor.ts --bundle --format=iife --global-name=ribbit --minify --outfile=dist/ribbit/ribbit.min.js",
"build:core": "esbuild src/ts/ribbit-core.ts --bundle --format=iife --global-name=ribbit --sourcemap --outfile=dist/ribbit/ribbit-core.js",
"build:core-min": "esbuild src/ts/ribbit-core.ts --bundle --format=iife --global-name=ribbit --minify --outfile=dist/ribbit/ribbit-core.min.js",
"build:css": "cp src/static/ribbit-core.css dist/ribbit/ && cp -r src/static/themes dist/ribbit/",
"test": "npm run build && jest --verbose",
"test:coverage": "npm run build && jest --coverage"

21
src/ts/ribbit-core.ts Normal file
View File

@ -0,0 +1,21 @@
/*
* ribbit-core.ts lightweight entry point without optional features (vim).
*
* Same API as ribbit-editor.ts but excludes VimHandler.
*/
import { HopDown } from './hopdown';
import { defaultTags, defaultBlockTags, defaultInlineTags, inlineTag } from './tags';
import { defaultTheme } from './default-theme';
import { Ribbit, camelCase, decodeHtmlEntities, encodeHtmlEntities } from './ribbit';
import { type MacroDef } from './macros';
export { RibbitEditor as Editor } from './ribbit-editor';
export { Ribbit as Viewer };
export { HopDown };
export { inlineTag };
export { defaultTags, defaultBlockTags, defaultInlineTags };
export { defaultTheme };
export { camelCase, decodeHtmlEntities, encodeHtmlEntities };
export { ToolbarManager } from './toolbar';
export type { MacroDef };

View File

@ -23,7 +23,7 @@ import { type MacroDef } from './macros';
* editor.view(); // switch to read-only view
*/
export class RibbitEditor extends Ribbit {
private vim!: VimHandler;
private vim?: VimHandler;
run(): void {
this.states = {
@ -32,6 +32,7 @@ export class RibbitEditor extends Ribbit {
WYSIWYG: 'wysiwyg'
};
if (this.theme.features?.vim) {
this.vim = new VimHandler((mode) => {
if (mode === 'normal') {
this.toolbar.disable();
@ -43,6 +44,7 @@ export class RibbitEditor extends Ribbit {
this.element.classList.remove('vim-normal');
}
});
}
this.#bindEvents();
this.element.classList.add('loaded');
@ -218,7 +220,7 @@ export class RibbitEditor extends Ribbit {
wysiwyg(): void {
if (this.getState() === this.states.WYSIWYG) return;
this.vim.detach();
this.vim?.detach();
this.element.contentEditable = 'true';
this.element.innerHTML = this.getHTML();
Array.from(this.element.querySelectorAll('.macro')).forEach(el => {
@ -238,7 +240,7 @@ export class RibbitEditor extends Ribbit {
if (this.state === this.states.EDIT) return;
this.element.contentEditable = 'true';
this.element.innerHTML = encodeHtmlEntities(this.getMarkdown());
this.vim.attach(this.element);
this.vim?.attach(this.element);
this.setState(this.states.EDIT);
}

View File

@ -68,6 +68,7 @@ export interface InlineTagDef {
export interface RibbitThemeFeatures {
sourceMode?: boolean;
vim?: boolean;
}
/**

View File

@ -6,14 +6,14 @@ describe('VimHandler', () => {
beforeEach(() => resetDOM('hello world'));
it('starts in insert mode', () => {
const editor = new r.Editor({});
const editor = new r.Editor({ currentTheme: 'vim', themes: [{ name: 'vim', features: { sourceMode: true, vim: true }, tags: r.defaultTags }] });
editor.run();
editor.edit();
expect(editor.element.classList.contains('vim-insert')).toBe(true);
});
it('Esc enters normal mode', () => {
const editor = new r.Editor({});
const editor = new r.Editor({ currentTheme: 'vim', themes: [{ name: 'vim', features: { sourceMode: true, vim: true }, tags: r.defaultTags }] });
editor.run();
editor.edit();
editor.element.dispatchEvent(new r.window.KeyboardEvent('keydown', { key: 'Escape' }));
@ -22,7 +22,7 @@ describe('VimHandler', () => {
});
it('i returns to insert mode', () => {
const editor = new r.Editor({});
const editor = new r.Editor({ currentTheme: 'vim', themes: [{ name: 'vim', features: { sourceMode: true, vim: true }, tags: r.defaultTags }] });
editor.run();
editor.edit();
// Enter normal mode
@ -34,7 +34,7 @@ describe('VimHandler', () => {
});
it('disables toolbar in normal mode', () => {
const editor = new r.Editor({ autoToolbar: false });
const editor = new r.Editor({ autoToolbar: false, currentTheme: 'vim', themes: [{ name: 'vim', features: { sourceMode: true, vim: true }, tags: r.defaultTags }] });
editor.run();
editor.toolbar.render();
editor.edit();
@ -45,7 +45,7 @@ describe('VimHandler', () => {
});
it('re-enables toolbar in insert mode', () => {
const editor = new r.Editor({ autoToolbar: false });
const editor = new r.Editor({ autoToolbar: false, currentTheme: 'vim', themes: [{ name: 'vim', features: { sourceMode: true, vim: true }, tags: r.defaultTags }] });
editor.run();
editor.toolbar.render();
editor.edit();
@ -56,7 +56,7 @@ describe('VimHandler', () => {
});
it('detaches when leaving edit mode', () => {
const editor = new r.Editor({});
const editor = new r.Editor({ currentTheme: 'vim', themes: [{ name: 'vim', features: { sourceMode: true, vim: true }, tags: r.defaultTags }] });
editor.run();
editor.edit();
editor.element.dispatchEvent(new r.window.KeyboardEvent('keydown', { key: 'Escape' }));
@ -68,7 +68,7 @@ describe('VimHandler', () => {
});
it('only activates in edit mode', () => {
const editor = new r.Editor({});
const editor = new r.Editor({ currentTheme: 'vim', themes: [{ name: 'vim', features: { sourceMode: true, vim: true }, tags: r.defaultTags }] });
editor.run();
editor.wysiwyg();
// Esc in wysiwyg should not add vim classes