@textbus/adapter-vue 4.0.0-alpha.6 → 4.0.0-alpha.61

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,23 +1,94 @@
1
- import { getCurrentInstance, onMounted, onUpdated, onUnmounted, ref, h } from 'vue';
2
- import { Subject } from '@tanbo/stream';
3
- import { makeError, VElement, VTextNode, replaceEmpty } from '@textbus/core';
1
+ import { makeError, VElement, VTextNode } from '@textbus/core';
2
+ import { ref, h, getCurrentInstance, onMounted, onUpdated, onUnmounted } 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 = {};
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
+ });
43
+ }
44
+ else {
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);
55
+ }
56
+ return h(comp, {
57
+ component,
58
+ rootRef,
59
+ key: component.id
60
+ });
61
+ }
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) => {
66
+ a[b[0]] = b[1];
67
+ return a;
68
+ }, {})));
69
+ if (vNode.classes.size) {
70
+ props.class = Array.from(vNode.classes).join(' ');
71
+ }
72
+ if (vNode.styles) {
73
+ props.style = Array.from(vNode.styles).reduce((a, b) => {
74
+ a[b[0]] = b[1];
75
+ return a;
76
+ }, {});
77
+ }
78
+ return h(vNode.tagName, props, ...children);
79
+ }
80
+ }, mount);
81
+ // private compositionRef = ref<HTMLElement>()
15
82
  this.componentRefs = new WeakMap();
83
+ this.components = {};
84
+ // watchEffect(() => {
85
+ // this.compositionNode = this.compositionRef.value || null
86
+ // })
16
87
  Object.keys(components).forEach(key => {
17
88
  const vueComponent = components[key];
18
89
  const setup = vueComponent.setup;
19
90
  const self = this;
20
- vueComponent.setup = function (props) {
91
+ vueComponent.setup = function (props, context, ...args) {
21
92
  const component = props.component;
22
93
  const vueInstance = getCurrentInstance();
23
94
  const sub = component.changeMarker.onChange.subscribe(() => {
@@ -34,91 +105,46 @@ class Adapter extends DomAdapter {
34
105
  }
35
106
  });
36
107
  onUpdated(() => {
108
+ var _a;
109
+ const context = self.componentRendingStack[self.componentRendingStack.length - 1];
110
+ if (context === component) {
111
+ self.componentRendingStack.pop();
112
+ }
113
+ component.changeMarker.rendered();
37
114
  self.onViewUpdated.next();
115
+ if (!(((_a = self.componentRefs.get(component)) === null || _a === void 0 ? void 0 : _a.value) instanceof HTMLElement)) {
116
+ // eslint-disable-next-line max-len
117
+ throw adapterError(`Component \`${component.name}\` is not bound to rootRef, you must bind rootRef to the root element node of the component view.`);
118
+ }
38
119
  });
39
120
  onUnmounted(() => {
40
121
  sub.unsubscribe();
41
122
  });
42
- return setup(props);
123
+ const result = setup(props, context, ...args);
124
+ if (typeof result === 'function') {
125
+ return function (...args) {
126
+ component.__slots__.forEach(i => self.renderedSlotCache.delete(i));
127
+ component.__slots__.length = 0;
128
+ self.componentRendingStack.push(component);
129
+ return result.apply(this, args);
130
+ };
131
+ }
132
+ return result;
43
133
  };
134
+ if (vueComponent.render) {
135
+ const oldRender = vueComponent.render;
136
+ vueComponent.render = function (context, ...args) {
137
+ context.component.__slots__.length = 0;
138
+ self.componentRendingStack.push(context.component);
139
+ return oldRender.apply(this, [context, ...args]);
140
+ };
141
+ }
44
142
  this.components[key] = vueComponent;
45
143
  });
46
144
  }
47
- componentRender(component) {
48
- const comp = this.components[component.name] || this.components['*'];
49
- if (comp) {
50
- component.changeMarker.rendered();
51
- let rootRef = this.componentRefs.get(component);
52
- if (!rootRef) {
53
- rootRef = ref();
54
- this.componentRefs.set(component, rootRef);
55
- }
56
- return h(comp, {
57
- component,
58
- rootRef,
59
- key: component.id
60
- });
61
- }
62
- throw adapterError(`cannot found view component \`${component.name}\`!`);
63
- }
64
- slotRender(slot, slotHostRender, renderEnv) {
65
- const vElement = slot.toTree(slotHostRender, renderEnv);
66
- this.slotRootVElementCaches.set(slot, vElement);
67
- const vNodeToJSX = (vNode) => {
68
- const children = [];
69
- for (let i = 0; i < vNode.children.length; i++) {
70
- const child = vNode.children[i];
71
- if (child instanceof VElement) {
72
- children.push(vNodeToJSX(child));
73
- }
74
- else if (child instanceof VTextNode) {
75
- children.push(replaceEmpty(child.textContent));
76
- }
77
- else {
78
- children.push(this.componentRender(child));
79
- }
80
- }
81
- const props = Object.assign({}, (Array.from(vNode.attrs).reduce((a, b) => {
82
- a[b[0]] = b[1];
83
- return a;
84
- }, {})));
85
- if (vNode.classes.size) {
86
- props.class = Array.from(vNode.classes).join(' ');
87
- }
88
- if (vNode.styles) {
89
- props.style = Array.from(vNode.styles).reduce((a, b) => {
90
- a[b[0]] = b[1];
91
- return a;
92
- }, {});
93
- }
94
- return h(vNode.tagName, props, ...children);
95
- };
96
- const refFn = (nativeNode) => {
97
- if (!nativeNode) {
98
- this.slotRootNativeElementCaches.remove(nativeNode);
99
- }
100
- else {
101
- this.slotRootNativeElementCaches.set(slot, nativeNode);
102
- }
103
- };
104
- const currentRef = vElement.attrs.get('ref');
105
- if (currentRef) {
106
- vElement.attrs.set('ref', (v) => {
107
- refFn(v);
108
- if (typeof currentRef === 'function') {
109
- currentRef(v);
110
- }
111
- else if (!currentRef.value) {
112
- currentRef.value = v;
113
- }
114
- });
115
- }
116
- else {
117
- vElement.attrs.set('ref', refFn);
118
- }
119
- slot.changeMarker.rendered();
120
- return vNodeToJSX(vElement);
145
+ copy() {
146
+ document.execCommand('copy');
121
147
  }
122
148
  }
123
149
 
124
- export { Adapter };
150
+ export { VueAdapter };
package/bundles/index.js CHANGED
@@ -1,25 +1,96 @@
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 = {};
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
+ });
45
+ }
46
+ else {
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);
57
+ }
58
+ return vue.h(comp, {
59
+ component,
60
+ rootRef,
61
+ key: component.id
62
+ });
63
+ }
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) => {
68
+ a[b[0]] = b[1];
69
+ return a;
70
+ }, {})));
71
+ if (vNode.classes.size) {
72
+ props.class = Array.from(vNode.classes).join(' ');
73
+ }
74
+ if (vNode.styles) {
75
+ props.style = Array.from(vNode.styles).reduce((a, b) => {
76
+ a[b[0]] = b[1];
77
+ return a;
78
+ }, {});
79
+ }
80
+ return vue.h(vNode.tagName, props, ...children);
81
+ }
82
+ }, mount);
83
+ // private compositionRef = ref<HTMLElement>()
17
84
  this.componentRefs = new WeakMap();
85
+ this.components = {};
86
+ // watchEffect(() => {
87
+ // this.compositionNode = this.compositionRef.value || null
88
+ // })
18
89
  Object.keys(components).forEach(key => {
19
90
  const vueComponent = components[key];
20
91
  const setup = vueComponent.setup;
21
92
  const self = this;
22
- vueComponent.setup = function (props) {
93
+ vueComponent.setup = function (props, context, ...args) {
23
94
  const component = props.component;
24
95
  const vueInstance = vue.getCurrentInstance();
25
96
  const sub = component.changeMarker.onChange.subscribe(() => {
@@ -36,91 +107,46 @@ class Adapter extends platformBrowser.DomAdapter {
36
107
  }
37
108
  });
38
109
  vue.onUpdated(() => {
110
+ var _a;
111
+ const context = self.componentRendingStack[self.componentRendingStack.length - 1];
112
+ if (context === component) {
113
+ self.componentRendingStack.pop();
114
+ }
115
+ component.changeMarker.rendered();
39
116
  self.onViewUpdated.next();
117
+ if (!(((_a = self.componentRefs.get(component)) === null || _a === void 0 ? void 0 : _a.value) instanceof HTMLElement)) {
118
+ // eslint-disable-next-line max-len
119
+ throw adapterError(`Component \`${component.name}\` is not bound to rootRef, you must bind rootRef to the root element node of the component view.`);
120
+ }
40
121
  });
41
122
  vue.onUnmounted(() => {
42
123
  sub.unsubscribe();
43
124
  });
44
- return setup(props);
125
+ const result = setup(props, context, ...args);
126
+ if (typeof result === 'function') {
127
+ return function (...args) {
128
+ component.__slots__.forEach(i => self.renderedSlotCache.delete(i));
129
+ component.__slots__.length = 0;
130
+ self.componentRendingStack.push(component);
131
+ return result.apply(this, args);
132
+ };
133
+ }
134
+ return result;
45
135
  };
136
+ if (vueComponent.render) {
137
+ const oldRender = vueComponent.render;
138
+ vueComponent.render = function (context, ...args) {
139
+ context.component.__slots__.length = 0;
140
+ self.componentRendingStack.push(context.component);
141
+ return oldRender.apply(this, [context, ...args]);
142
+ };
143
+ }
46
144
  this.components[key] = vueComponent;
47
145
  });
48
146
  }
49
- componentRender(component) {
50
- const comp = this.components[component.name] || this.components['*'];
51
- if (comp) {
52
- component.changeMarker.rendered();
53
- let rootRef = this.componentRefs.get(component);
54
- if (!rootRef) {
55
- rootRef = vue.ref();
56
- this.componentRefs.set(component, rootRef);
57
- }
58
- return vue.h(comp, {
59
- component,
60
- rootRef,
61
- key: component.id
62
- });
63
- }
64
- throw adapterError(`cannot found view component \`${component.name}\`!`);
65
- }
66
- slotRender(slot, slotHostRender, renderEnv) {
67
- const vElement = slot.toTree(slotHostRender, renderEnv);
68
- this.slotRootVElementCaches.set(slot, vElement);
69
- const vNodeToJSX = (vNode) => {
70
- const children = [];
71
- for (let i = 0; i < vNode.children.length; i++) {
72
- const child = vNode.children[i];
73
- if (child instanceof core.VElement) {
74
- children.push(vNodeToJSX(child));
75
- }
76
- else if (child instanceof core.VTextNode) {
77
- children.push(core.replaceEmpty(child.textContent));
78
- }
79
- else {
80
- children.push(this.componentRender(child));
81
- }
82
- }
83
- const props = Object.assign({}, (Array.from(vNode.attrs).reduce((a, b) => {
84
- a[b[0]] = b[1];
85
- return a;
86
- }, {})));
87
- if (vNode.classes.size) {
88
- props.class = Array.from(vNode.classes).join(' ');
89
- }
90
- if (vNode.styles) {
91
- props.style = Array.from(vNode.styles).reduce((a, b) => {
92
- a[b[0]] = b[1];
93
- return a;
94
- }, {});
95
- }
96
- return vue.h(vNode.tagName, props, ...children);
97
- };
98
- const refFn = (nativeNode) => {
99
- if (!nativeNode) {
100
- this.slotRootNativeElementCaches.remove(nativeNode);
101
- }
102
- else {
103
- this.slotRootNativeElementCaches.set(slot, nativeNode);
104
- }
105
- };
106
- const currentRef = vElement.attrs.get('ref');
107
- if (currentRef) {
108
- vElement.attrs.set('ref', (v) => {
109
- refFn(v);
110
- if (typeof currentRef === 'function') {
111
- currentRef(v);
112
- }
113
- else if (!currentRef.value) {
114
- currentRef.value = v;
115
- }
116
- });
117
- }
118
- else {
119
- vElement.attrs.set('ref', refFn);
120
- }
121
- slot.changeMarker.rendered();
122
- return vNodeToJSX(vElement);
147
+ copy() {
148
+ document.execCommand('copy');
123
149
  }
124
150
  }
125
151
 
126
- exports.Adapter = Adapter;
152
+ 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.6",
3
+ "version": "4.0.0-alpha.61",
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",
@@ -25,10 +25,10 @@
25
25
  "typescript editor"
26
26
  ],
27
27
  "dependencies": {
28
- "@tanbo/stream": "^1.2.0",
29
- "@textbus/core": "^4.0.0-alpha.6",
30
- "@textbus/platform-browser": "^4.0.0-alpha.6",
31
- "vue": "^3.3.4"
28
+ "@tanbo/stream": "^1.2.5",
29
+ "@textbus/core": "^4.0.0-alpha.61",
30
+ "@textbus/platform-browser": "^4.0.0-alpha.61",
31
+ "vue": "^3.4.28"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@rollup/plugin-commonjs": "^23.0.2",
@@ -48,5 +48,5 @@
48
48
  "bugs": {
49
49
  "url": "https://github.com/textbus/textbus.git/issues"
50
50
  },
51
- "gitHead": "47394e77de252fdfd9193e1620177f944976c1a9"
51
+ "gitHead": "892e0bc033aaf52f89be3476c9536c445e316200"
52
52
  }
@@ -1,22 +0,0 @@
1
- import { DefineComponent, Ref, VNode } from 'vue';
2
- import { Subject } from '@tanbo/stream';
3
- import { Component, ComponentInstance, ExtractComponentInstanceType, Slot, VElement, VTextNode } from '@textbus/core';
4
- import { DomAdapter } from '@textbus/platform-browser';
5
- export interface ViewComponentProps<T extends Component = Component> {
6
- component: ExtractComponentInstanceType<T>;
7
- rootRef: Ref<HTMLElement | undefined>;
8
- }
9
- export interface ReactAdapterComponents {
10
- [key: string]: DefineComponent<ViewComponentProps>;
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
- constructor(components: ReactAdapterComponents, mount: (host: HTMLElement, root: VNode) => (void | (() => void)));
20
- componentRender(component: ComponentInstance): VNode;
21
- slotRender(slot: Slot, slotHostRender: (children: Array<VElement | VTextNode | ComponentInstance>) => VElement, renderEnv?: any): VNode;
22
- }