@textbus/adapter-vue 4.0.0-alpha.39 → 4.0.0-alpha.42

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,179 +1,90 @@
1
- import { ref, watchEffect, getCurrentInstance, onMounted, onUpdated, onUnmounted, h } from 'vue';
2
- import { Subject } from '@tanbo/stream';
3
- import { makeError, VElement, VTextNode, replaceEmpty, invokeListener } from '@textbus/core';
1
+ import { makeError, VElement, VTextNode } from '@textbus/core';
2
+ import { ref, h } from 'vue';
4
3
  import { DomAdapter } from '@textbus/platform-browser';
5
4
 
6
5
  const adapterError = makeError('VueAdapter');
7
- /**
8
- * Textbus 桥接 Vue 渲染能力适配器,用于在 Vue 项目中渲染 Textbus 数据
9
- */
10
- class Adapter extends DomAdapter {
6
+ class VueAdapter extends DomAdapter {
11
7
  constructor(components, mount) {
12
- super(mount);
13
- this.onViewUpdated = new Subject();
14
- this.components = {};
15
- this.componentRefs = new WeakMap();
16
- this.componentRendingStack = [];
17
- this.compositionRef = ref();
18
- watchEffect(() => {
19
- this.compositionNode = this.compositionRef.value || null;
20
- });
21
- Object.keys(components).forEach(key => {
22
- const vueComponent = components[key];
23
- const setup = vueComponent.setup;
24
- const self = this;
25
- vueComponent.setup = function (props) {
26
- const component = props.component;
27
- const vueInstance = getCurrentInstance();
28
- const sub = component.changeMarker.onChange.subscribe(() => {
29
- if (component.changeMarker.dirty) {
30
- vueInstance.proxy.$forceUpdate();
31
- }
32
- });
33
- onMounted(() => {
34
- if (props.rootRef.value) {
35
- self.componentRootElementCaches.set(component, props.rootRef.value);
36
- }
37
- else {
38
- self.componentRootElementCaches.remove(component);
39
- }
40
- });
41
- onUpdated(() => {
42
- var _a;
43
- const context = self.componentRendingStack[self.componentRendingStack.length - 1];
44
- if (context === component) {
45
- self.componentRendingStack.pop();
46
- }
47
- component.changeMarker.rendered();
48
- self.onViewUpdated.next();
49
- if (!(((_a = self.componentRefs.get(component)) === null || _a === void 0 ? void 0 : _a.value) instanceof HTMLElement)) {
50
- // eslint-disable-next-line max-len
51
- throw adapterError(`Component \`${component.name}\` is not bound to rootRef, you must bind rootRef to the root element node of the component view.`);
52
- }
53
- });
54
- onUnmounted(() => {
55
- sub.unsubscribe();
56
- });
57
- const result = setup(props);
58
- if (typeof result === 'function') {
59
- return function () {
60
- component.__slots__.forEach(i => self.renderedSlotCache.delete(i));
61
- component.__slots__.length = 0;
62
- self.componentRendingStack.push(component);
63
- return result();
64
- };
65
- }
66
- return result;
67
- };
68
- if (vueComponent.render) {
69
- const oldRender = vueComponent.render;
70
- vueComponent.render = function (context) {
71
- context.component.__slots__.length = 0;
72
- self.componentRendingStack.push(context.component);
73
- oldRender.apply(this, context);
74
- };
75
- }
76
- this.components[key] = vueComponent;
77
- });
78
- }
79
- componentRender(component) {
80
- const comp = this.components[component.name] || this.components['*'];
81
- if (comp) {
82
- let rootRef = this.componentRefs.get(component);
83
- if (!rootRef) {
84
- rootRef = ref();
85
- this.componentRefs.set(component, rootRef);
86
- }
87
- return h(comp, {
88
- component,
89
- rootRef,
90
- key: component.id
91
- });
92
- }
93
- throw adapterError(`cannot found view component \`${component.name}\`!`);
94
- }
95
- slotRender(slot, slotHostRender, renderEnv) {
96
- var _a;
97
- const context = this.componentRendingStack[this.componentRendingStack.length - 1];
98
- if (context) {
99
- context.__slots__.push(slot);
100
- }
101
- else if (!this.renderedSlotCache.has(slot)) {
102
- throw adapterError(`Unrendered slots must be rendered together with the corresponding "${((_a = slot.parent) === null || _a === void 0 ? void 0 : _a.name) || 'unknown'}" component`);
103
- }
104
- this.renderedSlotCache.set(slot, true);
105
- const vElement = slot.toTree(slotHostRender, renderEnv);
106
- this.slotRootVElementCaches.set(slot, vElement);
107
- const vNodeToJSX = (vNode) => {
108
- const children = [];
109
- if (this.composition && this.composition.slot === slot) {
110
- this.insertCompositionByIndex(slot, vNode, this.composition, () => {
111
- return new VElement('span', {
112
- style: {
113
- textDecoration: 'underline'
114
- },
115
- ref: this.compositionRef
116
- }, [
117
- new VTextNode(this.composition.text)
118
- ]);
119
- });
120
- }
121
- for (let i = 0; i < vNode.children.length; i++) {
122
- const child = vNode.children[i];
123
- if (child instanceof VElement) {
124
- children.push(vNodeToJSX(child));
125
- }
126
- else if (child instanceof VTextNode) {
127
- children.push(replaceEmpty(child.textContent));
8
+ super({
9
+ createCompositionNode: (compositionState, updateNativeCompositionNode) => {
10
+ return new VElement('span', {
11
+ style: {
12
+ textDecoration: 'underline'
13
+ },
14
+ ref: updateNativeCompositionNode
15
+ }, [
16
+ new VTextNode(compositionState.text)
17
+ ]);
18
+ },
19
+ getParentNode(node) {
20
+ return node.parentNode;
21
+ },
22
+ getChildNodes(parentElement) {
23
+ return Array.from(parentElement.childNodes);
24
+ },
25
+ isNativeElementNode(node) {
26
+ return node instanceof HTMLElement;
27
+ },
28
+ getChildByIndex(parentElement, index) {
29
+ return parentElement.childNodes[index];
30
+ },
31
+ getAndUpdateSlotRootNativeElement(vElement, update) {
32
+ const currentRef = vElement.attrs.get('ref');
33
+ if (currentRef) {
34
+ vElement.attrs.set('ref', (v) => {
35
+ update(v);
36
+ if (typeof currentRef === 'function') {
37
+ currentRef(v);
38
+ }
39
+ else if (!currentRef.value) {
40
+ currentRef.value = v;
41
+ }
42
+ });
128
43
  }
129
44
  else {
130
- children.push(this.componentRender(child));
131
- if (!this.firstRending) {
132
- invokeListener(child, 'onParentSlotUpdated');
45
+ vElement.attrs.set('ref', update);
46
+ }
47
+ },
48
+ componentRender: (component) => {
49
+ const comp = this.components[component.name] || this.components['*'];
50
+ if (comp) {
51
+ let rootRef = this.componentRefs.get(component);
52
+ if (!rootRef) {
53
+ rootRef = ref();
54
+ this.componentRefs.set(component, rootRef);
133
55
  }
56
+ return h(comp, {
57
+ component,
58
+ rootRef,
59
+ key: component.id
60
+ });
134
61
  }
135
- }
136
- const props = Object.assign({}, (Array.from(vNode.attrs).reduce((a, b) => {
137
- a[b[0]] = b[1];
138
- return a;
139
- }, {})));
140
- if (vNode.classes.size) {
141
- props.class = Array.from(vNode.classes).join(' ');
142
- }
143
- if (vNode.styles) {
144
- props.style = Array.from(vNode.styles).reduce((a, b) => {
62
+ throw adapterError(`cannot found view component \`${component.name}\`!`);
63
+ },
64
+ vElementToViewElement(vNode, children) {
65
+ const props = Object.assign({}, (Array.from(vNode.attrs).reduce((a, b) => {
145
66
  a[b[0]] = b[1];
146
67
  return a;
147
- }, {});
148
- }
149
- return h(vNode.tagName, props, ...children);
150
- };
151
- const refFn = (nativeNode) => {
152
- if (!nativeNode) {
153
- this.slotRootNativeElementCaches.remove(slot);
154
- }
155
- else {
156
- this.slotRootNativeElementCaches.set(slot, nativeNode);
157
- }
158
- };
159
- const currentRef = vElement.attrs.get('ref');
160
- if (currentRef) {
161
- vElement.attrs.set('ref', (v) => {
162
- refFn(v);
163
- if (typeof currentRef === 'function') {
164
- currentRef(v);
68
+ }, {})));
69
+ if (vNode.classes.size) {
70
+ props.class = Array.from(vNode.classes).join(' ');
165
71
  }
166
- else if (!currentRef.value) {
167
- currentRef.value = v;
72
+ if (vNode.styles) {
73
+ props.style = Array.from(vNode.styles).reduce((a, b) => {
74
+ a[b[0]] = b[1];
75
+ return a;
76
+ }, {});
168
77
  }
169
- });
170
- }
171
- else {
172
- vElement.attrs.set('ref', refFn);
173
- }
174
- slot.__changeMarker__.rendered();
175
- return vNodeToJSX(vElement);
78
+ return h(vNode.tagName, props, ...children);
79
+ }
80
+ }, mount);
81
+ // private compositionRef = ref<HTMLElement>()
82
+ this.componentRefs = new WeakMap();
83
+ this.components = {};
84
+ }
85
+ copy() {
86
+ document.execCommand('copy');
176
87
  }
177
88
  }
178
89
 
179
- export { Adapter };
90
+ export { VueAdapter };
package/bundles/index.js CHANGED
@@ -1,181 +1,92 @@
1
1
  'use strict';
2
2
 
3
- var vue = require('vue');
4
- var stream = require('@tanbo/stream');
5
3
  var core = require('@textbus/core');
4
+ var vue = require('vue');
6
5
  var platformBrowser = require('@textbus/platform-browser');
7
6
 
8
7
  const adapterError = core.makeError('VueAdapter');
9
- /**
10
- * Textbus 桥接 Vue 渲染能力适配器,用于在 Vue 项目中渲染 Textbus 数据
11
- */
12
- class Adapter extends platformBrowser.DomAdapter {
8
+ class VueAdapter extends platformBrowser.DomAdapter {
13
9
  constructor(components, mount) {
14
- super(mount);
15
- this.onViewUpdated = new stream.Subject();
16
- this.components = {};
17
- this.componentRefs = new WeakMap();
18
- this.componentRendingStack = [];
19
- this.compositionRef = vue.ref();
20
- vue.watchEffect(() => {
21
- this.compositionNode = this.compositionRef.value || null;
22
- });
23
- Object.keys(components).forEach(key => {
24
- const vueComponent = components[key];
25
- const setup = vueComponent.setup;
26
- const self = this;
27
- vueComponent.setup = function (props) {
28
- const component = props.component;
29
- const vueInstance = vue.getCurrentInstance();
30
- const sub = component.changeMarker.onChange.subscribe(() => {
31
- if (component.changeMarker.dirty) {
32
- vueInstance.proxy.$forceUpdate();
33
- }
34
- });
35
- vue.onMounted(() => {
36
- if (props.rootRef.value) {
37
- self.componentRootElementCaches.set(component, props.rootRef.value);
38
- }
39
- else {
40
- self.componentRootElementCaches.remove(component);
41
- }
42
- });
43
- vue.onUpdated(() => {
44
- var _a;
45
- const context = self.componentRendingStack[self.componentRendingStack.length - 1];
46
- if (context === component) {
47
- self.componentRendingStack.pop();
48
- }
49
- component.changeMarker.rendered();
50
- self.onViewUpdated.next();
51
- if (!(((_a = self.componentRefs.get(component)) === null || _a === void 0 ? void 0 : _a.value) instanceof HTMLElement)) {
52
- // eslint-disable-next-line max-len
53
- throw adapterError(`Component \`${component.name}\` is not bound to rootRef, you must bind rootRef to the root element node of the component view.`);
54
- }
55
- });
56
- vue.onUnmounted(() => {
57
- sub.unsubscribe();
58
- });
59
- const result = setup(props);
60
- if (typeof result === 'function') {
61
- return function () {
62
- component.__slots__.forEach(i => self.renderedSlotCache.delete(i));
63
- component.__slots__.length = 0;
64
- self.componentRendingStack.push(component);
65
- return result();
66
- };
67
- }
68
- return result;
69
- };
70
- if (vueComponent.render) {
71
- const oldRender = vueComponent.render;
72
- vueComponent.render = function (context) {
73
- context.component.__slots__.length = 0;
74
- self.componentRendingStack.push(context.component);
75
- oldRender.apply(this, context);
76
- };
77
- }
78
- this.components[key] = vueComponent;
79
- });
80
- }
81
- componentRender(component) {
82
- const comp = this.components[component.name] || this.components['*'];
83
- if (comp) {
84
- let rootRef = this.componentRefs.get(component);
85
- if (!rootRef) {
86
- rootRef = vue.ref();
87
- this.componentRefs.set(component, rootRef);
88
- }
89
- return vue.h(comp, {
90
- component,
91
- rootRef,
92
- key: component.id
93
- });
94
- }
95
- throw adapterError(`cannot found view component \`${component.name}\`!`);
96
- }
97
- slotRender(slot, slotHostRender, renderEnv) {
98
- var _a;
99
- const context = this.componentRendingStack[this.componentRendingStack.length - 1];
100
- if (context) {
101
- context.__slots__.push(slot);
102
- }
103
- else if (!this.renderedSlotCache.has(slot)) {
104
- throw adapterError(`Unrendered slots must be rendered together with the corresponding "${((_a = slot.parent) === null || _a === void 0 ? void 0 : _a.name) || 'unknown'}" component`);
105
- }
106
- this.renderedSlotCache.set(slot, true);
107
- const vElement = slot.toTree(slotHostRender, renderEnv);
108
- this.slotRootVElementCaches.set(slot, vElement);
109
- const vNodeToJSX = (vNode) => {
110
- const children = [];
111
- if (this.composition && this.composition.slot === slot) {
112
- this.insertCompositionByIndex(slot, vNode, this.composition, () => {
113
- return new core.VElement('span', {
114
- style: {
115
- textDecoration: 'underline'
116
- },
117
- ref: this.compositionRef
118
- }, [
119
- new core.VTextNode(this.composition.text)
120
- ]);
121
- });
122
- }
123
- for (let i = 0; i < vNode.children.length; i++) {
124
- const child = vNode.children[i];
125
- if (child instanceof core.VElement) {
126
- children.push(vNodeToJSX(child));
127
- }
128
- else if (child instanceof core.VTextNode) {
129
- children.push(core.replaceEmpty(child.textContent));
10
+ super({
11
+ createCompositionNode: (compositionState, updateNativeCompositionNode) => {
12
+ return new core.VElement('span', {
13
+ style: {
14
+ textDecoration: 'underline'
15
+ },
16
+ ref: updateNativeCompositionNode
17
+ }, [
18
+ new core.VTextNode(compositionState.text)
19
+ ]);
20
+ },
21
+ getParentNode(node) {
22
+ return node.parentNode;
23
+ },
24
+ getChildNodes(parentElement) {
25
+ return Array.from(parentElement.childNodes);
26
+ },
27
+ isNativeElementNode(node) {
28
+ return node instanceof HTMLElement;
29
+ },
30
+ getChildByIndex(parentElement, index) {
31
+ return parentElement.childNodes[index];
32
+ },
33
+ getAndUpdateSlotRootNativeElement(vElement, update) {
34
+ const currentRef = vElement.attrs.get('ref');
35
+ if (currentRef) {
36
+ vElement.attrs.set('ref', (v) => {
37
+ update(v);
38
+ if (typeof currentRef === 'function') {
39
+ currentRef(v);
40
+ }
41
+ else if (!currentRef.value) {
42
+ currentRef.value = v;
43
+ }
44
+ });
130
45
  }
131
46
  else {
132
- children.push(this.componentRender(child));
133
- if (!this.firstRending) {
134
- core.invokeListener(child, 'onParentSlotUpdated');
47
+ vElement.attrs.set('ref', update);
48
+ }
49
+ },
50
+ componentRender: (component) => {
51
+ const comp = this.components[component.name] || this.components['*'];
52
+ if (comp) {
53
+ let rootRef = this.componentRefs.get(component);
54
+ if (!rootRef) {
55
+ rootRef = vue.ref();
56
+ this.componentRefs.set(component, rootRef);
135
57
  }
58
+ return vue.h(comp, {
59
+ component,
60
+ rootRef,
61
+ key: component.id
62
+ });
136
63
  }
137
- }
138
- const props = Object.assign({}, (Array.from(vNode.attrs).reduce((a, b) => {
139
- a[b[0]] = b[1];
140
- return a;
141
- }, {})));
142
- if (vNode.classes.size) {
143
- props.class = Array.from(vNode.classes).join(' ');
144
- }
145
- if (vNode.styles) {
146
- props.style = Array.from(vNode.styles).reduce((a, b) => {
64
+ throw adapterError(`cannot found view component \`${component.name}\`!`);
65
+ },
66
+ vElementToViewElement(vNode, children) {
67
+ const props = Object.assign({}, (Array.from(vNode.attrs).reduce((a, b) => {
147
68
  a[b[0]] = b[1];
148
69
  return a;
149
- }, {});
150
- }
151
- return vue.h(vNode.tagName, props, ...children);
152
- };
153
- const refFn = (nativeNode) => {
154
- if (!nativeNode) {
155
- this.slotRootNativeElementCaches.remove(slot);
156
- }
157
- else {
158
- this.slotRootNativeElementCaches.set(slot, nativeNode);
159
- }
160
- };
161
- const currentRef = vElement.attrs.get('ref');
162
- if (currentRef) {
163
- vElement.attrs.set('ref', (v) => {
164
- refFn(v);
165
- if (typeof currentRef === 'function') {
166
- currentRef(v);
70
+ }, {})));
71
+ if (vNode.classes.size) {
72
+ props.class = Array.from(vNode.classes).join(' ');
167
73
  }
168
- else if (!currentRef.value) {
169
- currentRef.value = v;
74
+ if (vNode.styles) {
75
+ props.style = Array.from(vNode.styles).reduce((a, b) => {
76
+ a[b[0]] = b[1];
77
+ return a;
78
+ }, {});
170
79
  }
171
- });
172
- }
173
- else {
174
- vElement.attrs.set('ref', refFn);
175
- }
176
- slot.__changeMarker__.rendered();
177
- return vNodeToJSX(vElement);
80
+ return vue.h(vNode.tagName, props, ...children);
81
+ }
82
+ }, mount);
83
+ // private compositionRef = ref<HTMLElement>()
84
+ this.componentRefs = new WeakMap();
85
+ this.components = {};
86
+ }
87
+ copy() {
88
+ document.execCommand('copy');
178
89
  }
179
90
  }
180
91
 
181
- exports.Adapter = Adapter;
92
+ exports.VueAdapter = VueAdapter;
@@ -1 +1 @@
1
- export * from './adapter';
1
+ export * from './vue-adapter';
@@ -0,0 +1,16 @@
1
+ import { Component, ViewMount } from '@textbus/core';
2
+ import { DefineComponent, Ref, VNode } from 'vue';
3
+ import { DomAdapter } from '@textbus/platform-browser';
4
+ export interface ViewComponentProps<T extends Component> {
5
+ component: T;
6
+ rootRef: Ref<HTMLElement | undefined>;
7
+ }
8
+ export interface VueAdapterComponents {
9
+ [key: string]: DefineComponent<ViewComponentProps<any>>;
10
+ }
11
+ export declare class VueAdapter extends DomAdapter<VNode, VNode> {
12
+ private componentRefs;
13
+ private components;
14
+ constructor(components: VueAdapterComponents, mount: ViewMount<VNode, HTMLElement>);
15
+ copy(): void;
16
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@textbus/adapter-vue",
3
- "version": "4.0.0-alpha.39",
3
+ "version": "4.0.0-alpha.42",
4
4
  "description": "Textbus is a rich text editor and framework that is highly customizable and extensible to achieve rich wysiwyg effects.",
5
5
  "main": "./bundles/index.js",
6
6
  "module": "./bundles/index.esm.js",
@@ -26,8 +26,8 @@
26
26
  ],
27
27
  "dependencies": {
28
28
  "@tanbo/stream": "^1.2.3",
29
- "@textbus/core": "^4.0.0-alpha.39",
30
- "@textbus/platform-browser": "^4.0.0-alpha.39",
29
+ "@textbus/core": "^4.0.0-alpha.42",
30
+ "@textbus/platform-browser": "^4.0.0-alpha.42",
31
31
  "vue": "^3.3.4"
32
32
  },
33
33
  "devDependencies": {
@@ -48,5 +48,5 @@
48
48
  "bugs": {
49
49
  "url": "https://github.com/textbus/textbus.git/issues"
50
50
  },
51
- "gitHead": "6c5f853e09df7cdc7464af4946b487574ae6dcda"
51
+ "gitHead": "690f066925bac5379883f54f470684c74645d12e"
52
52
  }
@@ -1,24 +0,0 @@
1
- import { DefineComponent, Ref, VNode } from 'vue';
2
- import { Subject } from '@tanbo/stream';
3
- import { Component, Slot, VElement, VTextNode } from '@textbus/core';
4
- import { DomAdapter } from '@textbus/platform-browser';
5
- export interface ViewComponentProps<T extends Component> {
6
- component: T;
7
- rootRef: Ref<HTMLElement | undefined>;
8
- }
9
- export interface VueAdapterComponents {
10
- [key: string]: DefineComponent<ViewComponentProps<any>>;
11
- }
12
- /**
13
- * Textbus 桥接 Vue 渲染能力适配器,用于在 Vue 项目中渲染 Textbus 数据
14
- */
15
- export declare class Adapter extends DomAdapter<VNode, VNode> {
16
- onViewUpdated: Subject<void>;
17
- private components;
18
- private componentRefs;
19
- private componentRendingStack;
20
- private compositionRef;
21
- constructor(components: VueAdapterComponents, mount: (host: HTMLElement, root: VNode) => (void | (() => void)));
22
- componentRender(component: Component): VNode;
23
- slotRender(slot: Slot, slotHostRender: (children: Array<VElement | VTextNode | Component>) => VElement, renderEnv?: any): VNode;
24
- }