mirror of
https://github.com/tenrok/BBob.git
synced 2026-06-17 19:21:20 +03:00
feat: react, vue3 and vanilla examples (#242)
* feat: react, vue3 and vanilla examples * fix: vue3 example * Create rare-worms-tease.md * fix: vue3 types * fix: vue3 ts checks * fix: vue3 render types * fix: vue3 component types
This commit is contained in:
@@ -53,12 +53,12 @@ const renderContent = (content: TagNodeTree, openTag: string, closeTag: string)
|
||||
return null
|
||||
}
|
||||
|
||||
export class TagNode implements TagNodeObject {
|
||||
public readonly tag: string
|
||||
export class TagNode<TagValue extends any = any> implements TagNodeObject {
|
||||
public readonly tag: string | TagValue
|
||||
public attrs: Record<string, unknown>
|
||||
public content: TagNodeTree
|
||||
|
||||
constructor(tag: string, attrs: Record<string, unknown>, content: TagNodeTree) {
|
||||
constructor(tag: string | TagValue, attrs: Record<string, unknown>, content: TagNodeTree) {
|
||||
this.tag = tag;
|
||||
this.attrs = attrs;
|
||||
this.content = content
|
||||
@@ -81,7 +81,7 @@ export class TagNode implements TagNodeObject {
|
||||
}
|
||||
|
||||
toTagStart({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}) {
|
||||
const tagAttrs = getTagAttrs(this.tag, this.attrs);
|
||||
const tagAttrs = getTagAttrs(String(this.tag), this.attrs);
|
||||
|
||||
return `${openTag}${tagAttrs}${closeTag}`;
|
||||
}
|
||||
@@ -91,7 +91,7 @@ export class TagNode implements TagNodeObject {
|
||||
}
|
||||
|
||||
toTagNode() {
|
||||
return new TagNode(this.tag.toLowerCase(), this.attrs, this.content);
|
||||
return new TagNode(String(this.tag).toLowerCase(), this.attrs, this.content);
|
||||
}
|
||||
|
||||
toString({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}): string {
|
||||
|
||||
@@ -11,6 +11,14 @@
|
||||
"@bbob/preset-html5": "*",
|
||||
"@bbob/types": "*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "> 15.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"react": "18.x",
|
||||
"react-dom": "18.x",
|
||||
"@types/react": "18.x"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
"jsnext:main": "es/index.js",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import presetHTML5 from '@bbob/preset-html5';
|
||||
|
||||
import type { PresetTagsDefinition } from '@bbob/types';
|
||||
|
||||
const tagAttr = (style: Record<string, string>) => ({
|
||||
@@ -7,7 +8,7 @@ const tagAttr = (style: Record<string, string>) => ({
|
||||
},
|
||||
});
|
||||
|
||||
const presetReact = presetHTML5.extend((tags: PresetTagsDefinition<'b' | 'i' | 'u' | 's'>) => ({
|
||||
const presetReact = presetHTML5.extend<PresetTagsDefinition>((tags) => ({
|
||||
...tags,
|
||||
|
||||
b: (...args) => ({
|
||||
|
||||
@@ -5,14 +5,19 @@ import { render } from './render';
|
||||
|
||||
const content = (children: ReactNode, plugins?: BBobPlugins, options?: BBobCoreOptions) =>
|
||||
React.Children.map(children,
|
||||
(child) =>
|
||||
(typeof child === 'string' ? render(child, plugins, options) : child)
|
||||
(child) => {
|
||||
if (typeof child === 'string') {
|
||||
return render(child, plugins, options)
|
||||
}
|
||||
|
||||
return child
|
||||
}
|
||||
);
|
||||
|
||||
export type BBobReactComponentProps = {
|
||||
children: ReactNode
|
||||
container: string
|
||||
componentProps: Record<string, unknown>
|
||||
container?: string
|
||||
componentProps?: Record<string, unknown>
|
||||
plugins?: BBobPlugins
|
||||
options?: BBobCoreOptions
|
||||
}
|
||||
@@ -23,7 +28,7 @@ const Component = ({
|
||||
children,
|
||||
plugins = [],
|
||||
options = {},
|
||||
}: BBobReactComponentProps) => React.createElement(
|
||||
}: BBobReactComponentProps): React.JSX.Element => React.createElement(
|
||||
container,
|
||||
componentProps,
|
||||
content(children, plugins, options),
|
||||
|
||||
@@ -24,7 +24,9 @@ const toAST = (
|
||||
) =>
|
||||
core(plugins).process(source, {
|
||||
...options,
|
||||
render: (input) => htmlrender(input, { stripTags: true }),
|
||||
render: (input) => {
|
||||
return htmlrender(input, { stripTags: true })
|
||||
},
|
||||
}).tree;
|
||||
|
||||
const isContentEmpty = (content: TagNodeTree) => {
|
||||
@@ -65,7 +67,7 @@ function renderToReactNodes(nodes?: BBobCoreTagNodeTree | TagNodeTree) {
|
||||
const prevArr = arr; // stupid eslint
|
||||
const prevNode = lastIdx >= 0 ? prevArr[lastIdx] : null;
|
||||
|
||||
if (prevArr[lastIdx] && prevNode !== null && !isEOL(String(prevNode))) {
|
||||
if (prevArr[lastIdx] && isStringNode(prevArr[lastIdx]) && prevNode !== null && !isEOL(String(prevNode))) {
|
||||
prevArr[lastIdx] += String(node);
|
||||
|
||||
return prevArr;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
export type StringNode = string | number
|
||||
|
||||
export interface TagNodeObject<TagValue extends any = any> {
|
||||
readonly tag: TagValue
|
||||
attrs?: Record<string, unknown>
|
||||
content?: TagNodeTree<TagValue>
|
||||
}
|
||||
|
||||
export type NodeContent<TagValue extends any = any> = TagNodeObject<TagValue> | StringNode | null
|
||||
|
||||
export type PartialNodeContent<TagValue extends any = any> = Partial<TagNodeObject<TagValue>> | StringNode | null
|
||||
|
||||
export type TagNodeTree<TagValue extends any = any> = NodeContent<TagValue> | NodeContent<TagValue>[] | null
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ParseOptions } from "./parser";
|
||||
import { NodeContent, PartialNodeContent, TagNodeObject, TagNodeTree } from "./types";
|
||||
import { NodeContent, PartialNodeContent, TagNodeObject, TagNodeTree } from "./common";
|
||||
|
||||
export interface BBobCoreOptions<
|
||||
Data = unknown | null,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export * from './types'
|
||||
export * from './common'
|
||||
export * from './parser'
|
||||
export * from './core'
|
||||
export * from './preset'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TagNodeTree } from "./types";
|
||||
import { TagNodeTree } from "./common";
|
||||
|
||||
export interface ParseError {
|
||||
tagName: string;
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
|
||||
import { BBobCoreTagNodeTree, BBobPluginFunction, BBobPluginOptions } from "./core";
|
||||
import { TagNodeObject } from "./types";
|
||||
import { TagNodeObject } from "./common";
|
||||
|
||||
export type PartialRecord<K extends keyof any, T> = Partial<Record<K, T>>
|
||||
|
||||
export type PresetTagsDefinition<Key extends string = string> = Record<Key, PresetTagFunction>
|
||||
export type PresetTagsDefinition<
|
||||
Key extends string = string,
|
||||
TagValue extends any = any
|
||||
> = Record<Key, PresetTagFunction<TagNodeObject<TagValue>>>
|
||||
|
||||
export type PresetOptions = Record<string, unknown>
|
||||
|
||||
@@ -15,7 +18,7 @@ export type ProcessorFunction<Tags extends PresetTagsDefinition = PresetTagsDefi
|
||||
options: Options
|
||||
) => BBobCoreTagNodeTree
|
||||
|
||||
// export type ProcessorReturnType = ReturnType<ProcessorFunction>;
|
||||
export type ProcessorReturnType = ReturnType<ProcessorFunction>;
|
||||
|
||||
export interface PresetTagFunction<Node extends TagNodeObject = TagNodeObject, Options extends PresetOptions = PresetOptions> {
|
||||
(
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
export type StringNode = string | number
|
||||
|
||||
export interface TagNodeObject {
|
||||
readonly tag: string
|
||||
attrs?: Record<string, unknown>
|
||||
content?: TagNodeTree
|
||||
}
|
||||
|
||||
export type NodeContent = TagNodeObject | StringNode | null
|
||||
|
||||
export type PartialNodeContent = Partial<TagNodeObject> | StringNode | null
|
||||
|
||||
export type TagNodeTree = NodeContent | NodeContent[] | null
|
||||
@@ -4,6 +4,7 @@
|
||||
"description": "A BBCode to Vue2 Renderer part of @bbob",
|
||||
"keywords": [
|
||||
"vue",
|
||||
"vue2",
|
||||
"bbcode",
|
||||
"parser",
|
||||
"bbob"
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import type{ VueConstructor } from 'vue';
|
||||
import type { VueConstructor } from 'vue';
|
||||
import Component from './Component';
|
||||
|
||||
function install(vue: VueConstructor) {
|
||||
vue.component("bbob-bbcode", Component);
|
||||
vue.component("BBobBBCode", Component);
|
||||
vue.component("BBCode", Component);
|
||||
}
|
||||
|
||||
export { render } from './render';
|
||||
export { Component };
|
||||
|
||||
function install(vue: VueConstructor) {
|
||||
vue.component('bbob-bbcode', Component);
|
||||
}
|
||||
|
||||
export default install;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"description": "A BBCode to Vue3 Renderer part of @bbob",
|
||||
"keywords": [
|
||||
"vue",
|
||||
"vue3",
|
||||
"bbcode",
|
||||
"parser",
|
||||
"bbob"
|
||||
@@ -20,12 +21,12 @@
|
||||
"devDependencies": {
|
||||
"@bbob/preset-vue": "*",
|
||||
"@testing-library/vue": "7.0.0",
|
||||
"@vue/compiler-sfc": "3.4.21",
|
||||
"@vue/runtime-dom": "3.4.21",
|
||||
"@vue/runtime-core": "3.4.21",
|
||||
"@vue/compiler-dom": "3.4.21",
|
||||
"@vue/compiler-sfc": "*",
|
||||
"@vue/runtime-dom": "*",
|
||||
"@vue/runtime-core": "*",
|
||||
"@vue/compiler-dom": "*",
|
||||
"@vue/test-utils": "2.4.5",
|
||||
"vue": "3.4.21"
|
||||
"vue": "*"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
||||
@@ -3,7 +3,7 @@ import { render } from "./render";
|
||||
|
||||
import type { BBobPlugins, BBobCoreOptions } from "@bbob/types";
|
||||
|
||||
type VueComponentProps = {
|
||||
export type VueComponentProps = {
|
||||
container: string;
|
||||
componentProps: Record<string, unknown>;
|
||||
plugins?: BBobPlugins;
|
||||
@@ -26,18 +26,21 @@ const Component = defineComponent({
|
||||
|
||||
render(props: VueComponentProps) {
|
||||
if (this.$slots.default) {
|
||||
const source = this.$slots
|
||||
.default()
|
||||
.reduce((acc: VNode, vnode: VNode) => {
|
||||
if (typeof acc === "string") {
|
||||
const content = this.$slots.default()
|
||||
const source = content.reduce((acc: string, vnode: VNode) => {
|
||||
if (vnode && typeof vnode.children === "string") {
|
||||
return acc + vnode.children;
|
||||
}
|
||||
|
||||
return acc
|
||||
}, "");
|
||||
|
||||
return h(
|
||||
props.container,
|
||||
render(h, source, props.plugins, props.options)
|
||||
);
|
||||
if (source) {
|
||||
return h(
|
||||
props.container,
|
||||
render(h, String(source), props.plugins, props.options)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import type { App } from "vue";
|
||||
import type { Plugin } from "@vue/runtime-core";
|
||||
import Component from "./Component";
|
||||
|
||||
const plugin = {
|
||||
install(app) {
|
||||
app.component("bbob-bbcode", Component);
|
||||
app.component("BBobBBCode", Component);
|
||||
app.component("BBCode", Component);
|
||||
}
|
||||
} as Plugin<any[]>;
|
||||
|
||||
export { render } from "./render";
|
||||
export { Component };
|
||||
|
||||
function install(Vue: App) {
|
||||
Vue.component("bbob-bbcode", Component);
|
||||
}
|
||||
|
||||
export default install;
|
||||
export default plugin;
|
||||
|
||||
@@ -7,8 +7,6 @@ import { render } from '@testing-library/vue';
|
||||
|
||||
import Component from '../src/Component';
|
||||
|
||||
console.log('Vue.v', Vue.version, Vue.createApp);
|
||||
|
||||
const renderBBCode = (input, options) => {
|
||||
const { html } = render(Component, {
|
||||
props: {
|
||||
|
||||
Reference in New Issue
Block a user