npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@hanfy/engine

v2.10.34

Published

<p align="center"> 一个支持协同编辑的富文本编辑器,可以自由的使用React、Vue 等前端常用库扩展定义插件。 </p>

Downloads

8

Readme

aomao-preview

特性

  • 🎁 开箱即用,提供几十种丰富的插件来满足大部分需求
  • 🚀 高扩展性,除了 mark inline block 类型基础插件外,我们还提供 card 组件结合 React Vue 等前端库渲染插件 UI
  • 🎨 丰富的多媒体支持,不仅支持图片和音视频,更支持插入嵌入式多媒体内容
  • 📝 支持 Markdown 语法
  • 🌍 支持国际化
  • 💻 引擎纯 JavaScript 编写,不依赖任何前端库,插件可以使用 React Vue 等前端库渲染。复杂架构轻松应对
  • 👥 内置协同编辑方案,轻量配置即可使用
  • 📱 兼容大部分最新移动端浏览器

插件

| | 版本 | 大小 | 描述 | | :---------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------- | | @hanfy/toolbar | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 工具栏, 适用于 React | | @hanfy/toolbar-vue | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 工具栏, 适用于 Vue3 | | am-editor-toolbar-vue2 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 工具栏, 适用于 Vue2 | | @hanfy/plugin-alignment | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 对齐方式 | | @hanfy/plugin-embed | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 嵌入网址 | | @hanfy/plugin-backcolor | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 背景色 | | @hanfy/plugin-bold | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 加粗 | | @hanfy/plugin-code | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 行内代码 | | @hanfy/plugin-codeblock | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 代码块, 适用于 React | | @hanfy/plugin-codeblock-vue | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 代码块, 适用于 Vue3 | | am-editor-codeblock-vue2 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 代码块, 适用于 Vue2 | | @hanfy/plugin-fontcolor | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 前景色 | | @hanfy/plugin-fontfamily | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 字体 | | @hanfy/plugin-fontsize | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 字体大小 | | @hanfy/plugin-heading | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 标题 | | @hanfy/plugin-hr | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 分割线 | | @hanfy/plugin-indent | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 缩进 | | @hanfy/plugin-italic | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 斜体 | | @hanfy/plugin-link | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 链接, 适用于 React | | @hanfy/plugin-link-vue | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 链接, 适用于 Vue3 | | am-editor-link-vue2 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 链接, 适用于 Vue2 | | @hanfy/plugin-line-height | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 行高 | | @hanfy/plugin-mark | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 标记 | | @hanfy/plugin-mention | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 提及 | | @hanfy/plugin-orderedlist | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 有序列表 | | @hanfy/plugin-paintformat | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 格式刷 | | @hanfy/plugin-quote | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 引用块 | | @hanfy/plugin-redo | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 重做 | | @hanfy/plugin-removeformat | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 移除样式 | | @hanfy/plugin-selectall | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 全选 | | @hanfy/plugin-status | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 状态 | | @hanfy/plugin-strikethrough | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 删除线 | | @hanfy/plugin-sub | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 下标 | | @hanfy/plugin-sup | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 上标 | | @hanfy/plugin-tasklist | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 任务列表 | | @hanfy/plugin-underline | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 下划线 | | @hanfy/plugin-undo | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 撤销 | | @hanfy/plugin-unorderedlist | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 无序列表 | | @hanfy/plugin-image | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 图片 | | @hanfy/plugin-table | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 表格 | | @hanfy/plugin-file | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 文件 | | @hanfy/plugin-mark-range | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 标记光标, 例如: 批注. | | @hanfy/plugin-math | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 数学公式 | | @hanfy/plugin-video | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 | 视频 |

快速上手

安装

编辑器由 引擎工具栏插件 组成。引擎 为我们提供了核心的编辑能力。

使用 npm 或者 yarn 安装引擎包

$ npm install @hanfy/engine
# or
$ yarn add @hanfy/engine

使用

我们按照惯例先输出一个Hello world!

import React, { useEffect, useRef, useState } from 'react';
import Engine, { EngineInterface } from '@hanfy/engine';

const EngineDemo = () => {
	//编辑器容器
	const ref = useRef<HTMLDivElement | null>(null);
	//引擎实例
	const [engine, setEngine] = useState<EngineInterface>();
	//编辑器内容
	const [content, setContent] = useState<string>('<p>Hello world!</p>');

	useEffect(() => {
		if (!ref.current) return;
		//实例化引擎
		const engine = new Engine(ref.current);
		//设置编辑器值
		engine.setValue(content);
		//监听编辑器值改变事件
		engine.on('change', () => {
			const value = engine.getValue();
			setContent(value);
			console.log(`value:${value}`);
		});
		//设置引擎实例
		setEngine(engine);
	}, []);

	return <div ref={ref} />;
};
export default EngineDemo;

插件

引入 @hanfy/plugin-bold 加粗插件

import Bold from '@hanfy/plugin-bold';

Bold 插件加入引擎

//实例化引擎
const engine = new Engine(ref.current, {
	plugins: [Bold],
});

卡片

卡片是编辑器中的一个独立区域,其 UI 和逻辑在卡片内部可以使用 ReactVue 或其他前端库自定义渲染内容,最后再挂载到编辑器上。

我们引入了 @hanfy/plugin-codeblock 代码块插件,该插件的语言下拉框使用 React 渲染,因此有所区别。Vue3 则使用 @hanfy/plugin-codeblock-vue

import CodeBlock, { CodeBlockComponent } from '@hanfy/plugin-codeblock';

CodeBlock 插件和 CodeBlockComponent 卡片组件加入引擎

//实例化引擎
const engine = new Engine(ref.current, {
	plugins: [CodeBlock],
	cards: [CodeBlockComponent],
});

CodeBlock 插件默认支持 markdown,在编辑器一行开头位置输入代码块语法```javascript 空格后即可触发。

节点约束

为了更方便的管理节点,降低复杂性。编辑器抽象化了节点属性和功能,制定了 mark inline block card 4 种类型节点,他们由不同的属性、样式或 html 结构组成,并统一使用 schema 对它们进行约束。

一个简单的 schema 看起来像是这样:

{
  name: 'p', // 节点名称
  type: 'block' // 节点类型
}

除此之外,还可以描述属性、样式等,比如:

{
  name: 'span', // 节点名称
  type: 'mark', // 节点类型
  attributes: {
    // 节点有一个 style 属性
    style: {
      // 必须包含一个color的样式
      color: {
        required: true, // 必须包含
        value: '@color' // 值是一个符合css规范的颜色值,@color 是编辑器内部定义的颜色效验,此处也可以使用方法、正则表达式去判断是否符合需要的规则
      }
    },
    // 可选的包含一个 test 属性,他的值可以是任意的,但不是必须的
    test: '*'
  }
}

下面这几种节点都符合上面的规则:

<span style="color:#fff"></span>
<span style="color:#fff" test="test123" test1="test1"></span>
<span style="color:#fff;background-color:#000;"></span>
<span style="color:#fff;background-color:#000;" test="test123"></span>

但是除了在 color 和 test 已经在 schema 中定义外,其它的属性(background-color、test1)在处理时都会被编辑器过滤掉。

可编辑器区域内的节点通过 schema 规则,制定了 mark inline block card 4 种组合节点,他们由不同的属性、样式或 html 结构组成,并对它们的嵌套进行了一定的约束。

工具栏

引入 @hanfy/toolbar 工具栏,工具栏由于交互复杂,基本上都是使用 React + Antd UI 组件渲染,Vue3 使用 @hanfy/toolbar-vue

工具栏除了 UI 交互外,大部分工作只是对不同的按钮事件触发后调用了引擎执行对应的插件命令,在需求比较复杂或需要重新定制 UI 的情况下,Fork 后修改起来也比较容易。

import Toolbar, { ToolbarPlugin, ToolbarComponent } from '@hanfy/toolbar';

ToolbarPlugin 插件和 ToolbarComponent 卡片组件加入引擎,它可以让我们在编辑器中可以使用快捷键 / 唤醒出卡片工具栏

//实例化引擎
const engine = new Engine(ref.current, {
	plugins: [ToolbarPlugin],
	cards: [ToolbarComponent],
});

渲染工具栏,工具栏已配置好所有插件,这里我们只需要传入插件名称即可

return (
    ...
    {
        engine && (
            <Toolbar
                engine={engine}
                items={[
                    ['collapse'],
                    [
                        'bold',
                    ],
                ]}
            />
        )
    }
    ...
)

更复杂的工具栏配置请查看文档 https://editor.aomao.com/zh-CN/config/toolbar

协同编辑

该开源库通过监听编辑区域(contenteditable 根节点)内的 html 结构的变化,使用 MutationObserver 反推数据结构,并通过 WebSocketYjs 连接交互,实现多用户协同编辑的功能。

交互模式

每位编辑者作为 客户端 通过 @hanfy/plugin-yjs-websocket 插件中的 Websocket服务端 进行通信交互。

  • @hanfy/yjs 实现编辑器与 Yjs 数据的转换
  • @hanfy/plugin-yjs-websocket 提供编辑器与 YjsWebSocket 客户端功能
  • @hanfy/plugin-yjs-websocket/server 提供 YjsWebSocket 服务端,使用 Node.js 编写,并支持使用 MongoDBLevelDB 存储数据。

项目图标

Iconfont

开发

React

在使用该开源库之前,需要先在项目根目录中安装依赖。

yarn install

lerna bootstrap

依赖安装好后,只需要在根目录执行以下命令即可启动项目:

yarn start

该开源库的开发目录结构如下:

  • packages 存放引擎和工具栏相关代码
  • plugins 存放所有的插件
  • api 提供一些插件所需要的 API 访问,默认使用 https://editor.aomao.com 作为 API 服务
  • yjs-server 存放协同服务端代码,可通过 yarn dev 启动服务。

Vue

am-editor vue example

贡献