@rathkit/rte-vue 0.0.0 → 0.1.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,11 +1,38 @@
1
1
  # @rathkit/rte-vue
2
2
 
3
- This version is an empty placeholder. It holds no code.
3
+ > **Alpha** (0.1.0-alpha.0). Not for production: the APIs will change between releases. Published to the `next` tag only.
4
4
 
5
- @rathkit/rte-vue is in alpha. Install the alpha with the `next` tag:
5
+ The editor for Vue: a component and composables over the headless layer. A ref changes only when the value it holds does.
6
+
7
+ ## Install
6
8
 
7
9
  ```sh
8
- npm install @rathkit/rte-vue@next
10
+ npm install @rathkit/rte-vue@next @rathkit/rte-core@next @rathkit/rte-headless@next
11
+ ```
12
+
13
+ This package has no dependencies of its own. It works with `@rathkit/rte-core`, `@rathkit/rte-headless`, `vue` (peer dependencies, all optional so that npm installs nothing you did not ask for), so install the ones you use alongside it; `vue` comes from your own project.
14
+
15
+ ## Example
16
+
17
+ ```vue
18
+ <script setup>
19
+ import { shallowRef } from "vue";
20
+ import { RteEditor, useCommand } from "@rathkit/rte-vue";
21
+
22
+ const editor = shallowRef();
23
+ const bold = useCommand(editor, "format.bold");
24
+ </script>
25
+
26
+ <template>
27
+ <button :aria-pressed="bold.active" @click="editor?.commands.run('format.bold')">Bold</button>
28
+ <RteEditor label="Body" default-value="<p>Hello</p>" @ready="(e) => (editor = e)" @change="(html) => console.log(html)" />
29
+ </template>
9
30
  ```
10
31
 
11
- About the project: https://rathkit.com
32
+ ## More
33
+
34
+ Documentation: <https://rathkit.com>. Source and issues: <https://github.com/rathkit/rte>. What is checked: [SUPPORT.md](https://github.com/rathkit/rte/blob/main/docs/SUPPORT.md). Changes: [CHANGELOG.md](https://github.com/rathkit/rte/blob/main/CHANGELOG.md). How a release is verified: [VERIFY.md](https://github.com/rathkit/rte/blob/main/docs/VERIFY.md).
35
+
36
+ ## License
37
+
38
+ [Apache-2.0](LICENSE)
@@ -0,0 +1,9 @@
1
+ import { type MaybeRef, type Ref } from "vue";
2
+ import { type ExternalStore, type HeadlessEditor } from "@rathkit/rte-headless";
3
+ import type { CommandState, EditorSnapshot } from "@rathkit/rte-core";
4
+ /** Follows a store with a ref. The editor may be given as a ref that fills in later; the ref follows whichever editor is current. */
5
+ export declare function useStore<T, E extends HeadlessEditor | undefined>(editor: MaybeRef<E>, make: (editor: HeadlessEditor) => ExternalStore<T>, empty: T): Readonly<Ref<T>>;
6
+ /** One command's state: whether it can run, whether it is on, its value. Off and disabled until the editor exists. */
7
+ export declare function useCommand(editor: MaybeRef<HeadlessEditor | undefined>, name: string): Readonly<Ref<CommandState>>;
8
+ /** One value worked out from the editor state. The ref changes, and anything reading it re-runs, only when that value changes. */
9
+ export declare function useSelector<T>(editor: MaybeRef<HeadlessEditor | undefined>, selector: (snapshot: EditorSnapshot) => T, equals?: (a: T, b: T) => boolean): Readonly<Ref<T | undefined>>;
@@ -0,0 +1,25 @@
1
+ import { onScopeDispose, shallowRef, unref, watch } from "vue";
2
+ import { commandStore, selectStore } from "@rathkit/rte-headless";
3
+ const idle = Object.freeze({ enabled: false, active: false, value: undefined });
4
+ export function useStore(editor, make, empty) {
5
+ const state = shallowRef(empty);
6
+ let unsubscribe = () => undefined;
7
+ const stop = watch(() => unref(editor), (current) => {
8
+ unsubscribe();
9
+ if (!current) {
10
+ state.value = empty;
11
+ return;
12
+ }
13
+ const store = make(current);
14
+ state.value = store.getSnapshot();
15
+ unsubscribe = store.subscribe(() => { state.value = store.getSnapshot(); });
16
+ }, { immediate: true });
17
+ onScopeDispose(() => { stop(); unsubscribe(); });
18
+ return state;
19
+ }
20
+ export function useCommand(editor, name) {
21
+ return useStore(editor, (e) => commandStore(e, name), idle);
22
+ }
23
+ export function useSelector(editor, selector, equals) {
24
+ return useStore(editor, (e) => selectStore(e, selector, equals), undefined);
25
+ }
@@ -0,0 +1,3 @@
1
+ import { type StandardOptions } from "@rathkit/rte-core/standard";
2
+ export type RteOptions = Omit<StandardOptions, "element" | "html" | "readOnly">;
3
+ export declare const RteEditor: unknown;
package/dist/editor.js ADDED
@@ -0,0 +1,35 @@
1
+ import { defineComponent, h, onBeforeUnmount, onMounted, shallowRef, watch } from "vue";
2
+ import { createEditor } from "@rathkit/rte-core/standard";
3
+ export const RteEditor = defineComponent({
4
+ name: "RteEditor",
5
+ props: {
6
+ defaultValue: { type: String, default: "" },
7
+ readOnly: { type: Boolean, default: false },
8
+ label: { type: String, required: true },
9
+ options: { type: Object, default: () => ({}) },
10
+ },
11
+ emits: ["change", "ready"],
12
+ setup(props, { emit, expose }) {
13
+ const element = shallowRef(null);
14
+ const editor = shallowRef(undefined);
15
+ let stop = () => undefined;
16
+ onMounted(() => {
17
+ const made = createEditor({ ...props.options, element: element.value, html: props.defaultValue, readOnly: props.readOnly });
18
+ let last = made.getHtml();
19
+ const off = made.subscribe(() => {
20
+ const html = made.getHtml();
21
+ if (html === last)
22
+ return;
23
+ last = html;
24
+ emit("change", html);
25
+ });
26
+ stop = () => { off(); made.destroy(); };
27
+ editor.value = made;
28
+ emit("ready", made);
29
+ });
30
+ onBeforeUnmount(() => { stop(); editor.value = undefined; });
31
+ watch(() => props.readOnly, (readOnly) => editor.value?.setReadOnly(readOnly));
32
+ expose({ editor });
33
+ return () => h("div", { ref: element, "aria-label": props.label, "data-rk-surface": "" });
34
+ },
35
+ });
@@ -0,0 +1,2 @@
1
+ export { useCommand, useSelector, useStore } from "./composables.ts";
2
+ export { RteEditor, type RteOptions } from "./editor.ts";
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { useCommand, useSelector, useStore } from "./composables.js";
2
+ export { RteEditor } from "./editor.js";
package/package.json CHANGED
@@ -1,7 +1,17 @@
1
1
  {
2
2
  "name": "@rathkit/rte-vue",
3
- "version": "0.0.0",
4
- "description": "Placeholder. @rathkit/rte-vue is in alpha: install it with the next tag.",
3
+ "version": "0.1.0-alpha.3",
4
+ "description": "The editor for Vue: a component and composables over the headless layer, with no editor or accessibility logic of its own.",
5
+ "keywords": [
6
+ "rich-text",
7
+ "editor",
8
+ "wysiwyg",
9
+ "contenteditable",
10
+ "zero-dependencies",
11
+ "typescript",
12
+ "vue",
13
+ "composables"
14
+ ],
5
15
  "license": "Apache-2.0",
6
16
  "homepage": "https://rathkit.com",
7
17
  "repository": {
@@ -12,7 +22,59 @@
12
22
  "bugs": {
13
23
  "url": "https://github.com/rathkit/rte/issues"
14
24
  },
25
+ "type": "module",
26
+ "sideEffects": false,
27
+ "engines": {
28
+ "node": ">=22.14.0"
29
+ },
15
30
  "publishConfig": {
16
- "access": "public"
31
+ "access": "public",
32
+ "provenance": true,
33
+ "tag": "next"
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "NOTICE",
38
+ "!dist/**/*.map"
39
+ ],
40
+ "exports": {
41
+ ".": {
42
+ "types": "./dist/index.d.ts",
43
+ "default": "./dist/index.js"
44
+ }
45
+ },
46
+ "peerDependencies": {
47
+ "@rathkit/rte-core": ">=0.1.0-alpha.3 <0.2.0",
48
+ "@rathkit/rte-headless": ">=0.1.0-alpha.3 <0.2.0",
49
+ "vue": ">=3.4"
50
+ },
51
+ "peerDependenciesMeta": {
52
+ "@rathkit/rte-core": {
53
+ "optional": true
54
+ },
55
+ "@rathkit/rte-headless": {
56
+ "optional": true
57
+ },
58
+ "vue": {
59
+ "optional": true
60
+ }
61
+ },
62
+ "devDependencies": {
63
+ "@rathkit/rte-core": "workspace:*",
64
+ "@rathkit/rte-headless": "workspace:*"
65
+ },
66
+ "scripts": {
67
+ "build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json && tsc -p tsconfig.build.js.json",
68
+ "typecheck": "tsc -p tsconfig.json",
69
+ "test": "node --import ./test/register.mjs --test \"src/**/*.test.ts\""
70
+ },
71
+ "rathkit": {
72
+ "budgets": [
73
+ {
74
+ "name": "vue",
75
+ "entry": "dist/index.js",
76
+ "gzipKB": 2
77
+ }
78
+ ]
17
79
  }
18
80
  }