Unified interface for defining components for Vue and React using a single code base.
Inkline is written and maintained by @alexgrozav.
Homepage
·
Documentation
·
Storybook
·
Playground
·
Issue Tracker
- First, install dependencies using
npm install
. - From the root directory, run
npm run test
in the command line.
- Set an alias in your build system to resolve
@inkline/paper
to either@inkline/paper/vue
or@inkline/paper/react
.
@inkline/paper
=>@inkline/paper/vue
@inkline/paper
=>@inkline/paper/react
-
Import the common component definition interface from
@inkline/paper
and decide whether you're creating a library forvue
orreact
at build time. -
Configure
tsconfig.json
to use the customh
andFragment
JSX Factory functions.
{
"compilerOptions": {
"jsx": "preserve",
"jsxFactory": "h",
"jsxFragmentFactory": "Fragment"
}
}
h(type: string, props: Record<string, any>, children: (VNode | string)[]): VNode
The hoist function h()
is used to create elements.
import { h } from '@inkline/paper';
const type = 'button';
const props = { id: 'button' };
const children = ['Hello world'];
const node = h(type, props, children);
It also serves as a JSX Factory.
import { h } from '@inkline/paper';
const node = <div id="myid">Hello world!</div>
defineComponent<Props, State>(definition: ComponentDefinition<Props, State>)
The defineComponent()
function is used to set up framework-specific internals and get type annotations.
import { defineComponent, h } from '@inkline/paper';
const Component = defineComponent({
render () {
return h('div');
}
});
import { defineComponent, h } from '@inkline/paper';
const Component = defineComponent({
render () {
return <div />;
}
});
Vue.js
<component />
React.js
<Component />
defineComponent({ render(state: Props & State, ctx: RenderContext): VNode })
The render()
function is mandatory and is used to return the component markup using hoisting.
import { defineComponent, h } from '@inkline/paper';
const Component = defineComponent({
render () {
return h('button', {}, 'Hello world');
}
});
import { defineComponent, h } from '@inkline/paper';
const Component = defineComponent({
render () {
return <button>Hello world</button>;
}
});
Vue.js
<component />
React.js
<Component />
defineComponent({ setup(props: Props, ctx: SetupContext) })
The setup()
function is used to prepare functions.
import { defineComponent, h } from '@inkline/paper';
const Component = defineComponent<{}, { text: string }>({
setup () {
return {
text: "Hello world"
};
},
render (state) {
return h('button', {}, [
state.text
]);
}
});
import { defineComponent, h } from '@inkline/paper';
const Component = defineComponent<{}, { text: string }>({
setup () {
return {
text: "Hello world"
};
},
render (state) {
return <button>{state.text}</button>;
}
});
Vue.js
<component />
React.js
<Component />
ref<Type>(defaultValue: Type)
The ref
variable works similar to the Vue.js ref
. To access or set the value of a reference variable, access or manipulate its value
field directly.
import { defineComponent, ref, h, Ref } from '@inkline/paper';
const Component = defineComponent<{}, { text: Ref<string>, onClick: () => void }>({
setup () {
const text = ref('Hello world');
const onClick = () => {
text.value = 'Bye world';
}
return {
text,
onClick
};
},
render (state) {
return h('button', { onClick: state.onClick }, [
state.text.value
]);
}
});
Vue.js
<component />
React.js
<Component />
computed<Type>(() => Type)
import { defineComponent, ref, h, Ref } from '@inkline/paper';
const Component = defineComponent<{ value: number; }, { double: Ref<number> }>({
setup (props) {
const double = computed(() => props.value * 2);
return {
double
};
},
render (state) {
return h('button', {}, [
state.double.value
]);
}
});
Vue.js
<component />
React.js
<Component />
provide<Type>(identifier: string, value: Type)
inject<Type>(identifier: string, defaultValue?: Type): Type
import { defineComponent, ref, h, Ref } from '@inkline/paper';
const identifier = Symbol('identifier');
const Provider = defineComponent<{}, {}>({
setup (props, ctx) {
ctx.provide(identifier, 'value');
return {};
},
render (state, ctx) {
return h('div', {}, [
ctx.slot()
]);
}
});
const Consumer = defineComponent<{}, { value?: string; }>({
setup (props, ctx) {
const value = inject(identifier, 'defaultValue');
return { value };
},
render (state, ctx) {
return h('div', {}, [
`${state.value}`
]);
}
});
Vue.js
<provider>
<consumer />
</provider>
React.js
<Provider>
<Consumer />
</Provider>
defineComponent({ props: ComponentProps<Props> })
Define the props using the props
field, using the same format used in Vue.js.
The setup()
function receives the defined prop values with default as fallback.
import { defineComponent, h } from '@inkline/paper';
const Component = defineComponent<{ text: string }, {}>({
props: {
text: {
type: String,
default: () => 'Hello world'
}
},
render (state) {
return h('button', {}, [
state.text
]);
}
});
Vue.js
<component text="Button" />
React.js
<Component text={"Button"} />
defineComponent({ slots: string[] })` and `renderContext.slot(slotName)
The slots
array allows you to define multiple slot names for the component. Out of the box, the default
slot is pre-defined.
The slot()
function is available in the render function execution context.
import { defineComponent, h } from '@inkline/paper';
const Component = defineComponent({
slots: ['header', 'footer'],
render (state, ctx) {
return h('div', { class: 'card' }, [
ctx.slot('header'),
ctx.slot(), // Default slot
ctx.slot('footer'),
]);
}
});
Vue.js
<component>
<template #header>Header</template>
Body
<template #footer>Header</template>
</component>
React.js
<Component>
<Component.Header>Header</Component.Header>
Body
<Component.Footer>Header</Component.Footer>
</Component>
defineComponent({ emits: string[] })` and `setupContext.emit(eventName, ...args)
The emits
array allows you to define event emitters.
- for Vue.js, this uses the native
emit()
function - for React.js, this creates an
on[EventName]
callback
import { defineComponent, h } from '@inkline/paper';
const Component = defineComponent<{}, { emitChange: () => void }>({
emits: ['change'],
setup (props, ctx) {
const emitChange = () => {
ctx.emit('change');
}
return { emitChange };
},
render (state, ctx) {
return h('button', { onClick: state.emitChange }, [ctx.slot()]);
}
});
Vue.js
<component @change="doSomething" />
React.js
<Component onChange={() => doSomething()} />
Alex Grozav
- https://grozav.com
- https://twitter.com/alexgrozav
- https://facebook.com/alexgrozav
- https://github.com/alexgrozav
If you use Inkline in your daily work and feel that it has made your life easier, please consider sponsoring me on Github Sponsors. 💖
Homepage and documentation copyright 2017-2022 Inkline Authors. Docs released under ISC License.