Integration
You can easily integrate this library with React.js and Vue.js libraries.
React integration
Nodality ships a React component: import Nodality from "nodality/react"
(Nodality 1.3.25 and later, React 18 and later). It hosts a Nodality render
inside your React tree, in either of the library's two forms.
To start a new app with it already set up, including build-time prerendering:
npx create-nodality-react@latest my-app
To add it to an existing React app, install nodality and import the component:
npm install nodality
Component code you own: view
Pass a function that returns a Nodality component, and the values it depends on
in deps. The view is rebuilt when deps change, with the same meaning as
useEffect's dependency array, and not on every parent render.
import { useState } from "react";
import { Text, Wrapper } from "nodality";
import Nodality from "nodality/react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<>
<Nodality
view={() =>
new Wrapper().set({ background: "#FFF7ED", pad: [{ a: "1rem" }] }).add([
new Text(`Count ${count}`).set({ size: "S5", color: "#9A3412" }),
])
}
deps={[count]}
/>
<button onClick={() => setCount(count + 1)}>Increment</button>
</>
);
}
A rebuild replaces the view's elements, so a field inside it loses focus when its
deps change. Leave values that change on every keystroke out of deps.
A specification: elements and nodes
Pass the (E, N) pair as data:
import Nodality from "nodality/react";
const elements = [
{ type: "wrap", id: "hero", children: [
{ type: "h1", id: "title", text: "Declared as data" },
]},
];
const nodes = [
{ op: "blast", target: ["title"], color: "#1D6FE0", width: "2px" },
];
export default function Hero() {
return <Nodality elements={elements} nodes={nodes} />;
}
The difference that matters
Only a specification survives the build. Because it is data, the component writes
it into the page next to its host (<script type="application/json" data-nodality-for="…">), and a prerenderer can render it to HTML at build time,
so crawlers see real markup. create-nodality-react does this in its
npm run build. A view is a function, so it renders in the browser only.
Props
| Prop | Description |
|---|---|
view | A function returning a Nodality component, e.g. () => new Wrapper()…. |
deps | When to rebuild view; same meaning as useEffect's dependency array. |
elements | The specification's elements (E). |
nodes | The specification's nodes (N). |
defs | Definitions, passed to Des.defs(). |
className, style | Applied to the host div. |
Next.js
nodality/react is marked "use client", so it works in the Next.js App Router.
A server component can render it with elements and nodes, because those are
plain data. view is a function, and functions cannot be passed from a server
component, so use view inside a client component.
Vue.js integration
You can also integrate this library with Vue.js. Here is the complete example. To quickly scaffold a Vue app you can use:
npx create-nodality-vue@latest my-app
<template>
<HelloWorld :text="textInstance" v-model:msg="welcomeMessage"/>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
import {Text} from "nodality";
export default {
name: 'App',
components: {
HelloWorld
},
watch: {
// Watch for changes to welcomeMessage and recreate the instance
welcomeMessage() {
console.log(this.welcomeMessage) // THIS WORKS
this.textInstance = new Text(this.welcomeMessage).set({ size: "S1", color: "#1abc9c" });
},
},
data() {
return {
welcomeMessage: "Welcome to Your Vue.js App", // Define a reactive property
textInstance: null
}
},
created() {
// Initialize the Text instance when the component is created
this.textInstance = new Text(this.welcomeMessage).set({ size: "S1", color: "#1abc9c" });
},
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
// 13:21:24 <slot> 26/04/2024
HelloWorld.vue
<script setup>
import { useTemplateRef, onMounted, defineProps, defineEmits, watch } from 'vue'
//import {Text} from "../lib/TextCopy.js";
// Define props to accept the msg value
const props = defineProps({
msg: String,
text: Object
})
const emit = defineEmits(['update:msg'])
// the first argument must match the ref value in the template
const input = useTemplateRef('my-input')
let mycomp = useTemplateRef('my-comp')
onMounted(() => {
input.value.focus()
let ela = props.text.render();//document.createElement("h1");
mycomp.value.appendChild(ela);
})
watch(() => props.msg, () => { // 12:21:57 Wow!!!
mycomp.value.innerHTML = ""; // Clear existing content
const element = props.text.render(); // Call the render method
mycomp.value.appendChild(element);
})
function updateMessage(event) {
emit('update:msg', event.target.value)
}
</script>
<template>
<input ref="my-input" :value="msg" @input="updateMessage" />
<div ref="my-comp"/>
</template>