Open babalugats76 opened 1 month ago
Hey there @babalugats76 thanks a lot for reaching out! I'm pretty happy to see more people using the package.
Yes, we are currently working to integrate it into our ecosystem so you can use it from the Storyblok Vue and Nuxt SDK.
About the custom component resolver, I have a snippet that would simplify your life big time, and its how currently we are implementing it on our Vue SDK
import { StoryblokComponent } from '@storyblok/vue`
const componentResolver: StoryblokRichTextNodeResolver<VNode> = (
node: StoryblokRichTextNode<VNode>
): VNode => {
return h(
StoryblokComponent,
{
blok: node?.attrs?.body[0],
id: node.attrs?.id,
},
node.children
);
};
Instead of doing the component map manually, take advantage of the StoryblokComponent.vue
that comes in the @storyblok/vue
package. Make sure you have your components inside of the storyblok
directory tho. But should work just fine.
@alvarosabu Thank you so much for the helpful and detailed response. Much appreciated. I will take what you have provided and see if I can incorporate, dropping something similar into resolvers
, etc. The idea of resolving via StoryblokComponent
is a much better idea. I will give that a shot and report back.
The reason why the code is so complicated is that I found that, when using the rich editor, body[0]
is not always guaranteed. In my testing, the body could have multiple entries if the user inserted consecutive, adjacent components. Have you tried that? That was my principle concern if that makes sense.
The reason why the code is so complicated is that I found that, when using the rich editor, body[0] is not always guaranteed. In my testing, the body could have multiple entries if the user inserted consecutive, adjacent components. Have you tried that? That was my principle concern if that makes sense.
Mmm, thats quite important feedback, do you have an example so I can reproduce where body
has more than 1 entry?
@alvarosabu Absolutemente.
Add two consecutive components in the rich text editor using your preferred technique:
This will result in story JSON similar to this:
{
"story": {
"name": "Test",
"created_at": "2024-10-08T20:24:32.599Z",
"published_at": "2024-10-11T19:38:28.669Z",
"id": 12947931,
"uuid": "cbb00947-c9cd-4ef2-9f2d-0a3fdfe0e0cb",
"content": {
"_uid": "99560d3d-ad9d-4b76-8e9e-4ff96c96f1bb",
"body": [
{
"_uid": "1304e7f1-0cb5-4ca3-8b39-5f019a035f24",
"text": {
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"text": "Before components",
"type": "text"
}
]
},
{
"type": "blok",
"attrs": {
"id": "dabd9c69-02a7-46d4-8654-6fd381470dd1",
"body": [
{
"_uid": "i-da6aeb2b-e0fe-4764-a507-413e7484cf00",
"class": "",
"float": "",
"image": {
"id": 922456,
"alt": "A close up of a bunch of crayons",
"name": "",
"focus": "",
"title": "Crayons",
"source": "",
"filename": "https://a-us.storyblok.com/f/1021359/5616x3744/8a8956ad0e/crayons.jpg",
"copyright": "Photo by Alexander Grey on Unsplash",
"fieldtype": "asset",
"meta_data": {
"alt": "A close up of a bunch of crayons",
"title": "Crayons",
"source": "",
"copyright": "Photo by Alexander Grey on Unsplash"
},
"is_external_url": false
},
"width": "",
"height": "",
"rounded": "",
"component": "image",
"grayscale": false,
"responsive": true,
"_editable": "\u003C!--#storyblok#{\"name\": \"image\", \"space\": \"1021359\", \"uid\": \"i-da6aeb2b-e0fe-4764-a507-413e7484cf00\", \"id\": \"12947931\"}--\u003E"
},
{
"_uid": "i-dfcfac59-58a9-4ec3-9c02-9dce44f53800",
"class": "",
"float": "",
"image": {
"id": 922456,
"alt": "A close up of a bunch of crayons",
"name": "",
"focus": "",
"title": "Crayons",
"source": "",
"filename": "https://a-us.storyblok.com/f/1021359/5616x3744/8a8956ad0e/crayons.jpg",
"copyright": "Photo by Alexander Grey on Unsplash",
"fieldtype": "asset",
"meta_data": {
"alt": "A close up of a bunch of crayons",
"title": "Crayons",
"source": "",
"copyright": "Photo by Alexander Grey on Unsplash"
},
"is_external_url": false
},
"width": "",
"height": "",
"rounded": "",
"component": "image",
"grayscale": false,
"responsive": true,
"_editable": "\u003C!--#storyblok#{\"name\": \"image\", \"space\": \"1021359\", \"uid\": \"i-dfcfac59-58a9-4ec3-9c02-9dce44f53800\", \"id\": \"12947931\"}--\u003E"
}
]
}
},
{
"type": "paragraph",
"content": [
{
"text": "After components",
"type": "text"
}
]
}
]
},
"variant": "lavender",
"component": "rich-text",
"scaleText": true,
"_editable": "\u003C!--#storyblok#{\"name\": \"rich-text\", \"space\": \"1021359\", \"uid\": \"1304e7f1-0cb5-4ca3-8b39-5f019a035f24\", \"id\": \"12947931\"}--\u003E"
}
],
"component": "page",
"metaTitle": "This is the headline",
"metaDescription": "This is the byline",
"_editable": "\u003C!--#storyblok#{\"name\": \"page\", \"space\": \"1021359\", \"uid\": \"99560d3d-ad9d-4b76-8e9e-4ff96c96f1bb\", \"id\": \"12947931\"}--\u003E"
},
"slug": "test",
"full_slug": "test",
"sort_by_date": null,
"position": -140,
"tag_list": [],
"is_startpage": false,
"parent_id": null,
"meta_data": null,
"group_id": "1f75f5da-3105-452e-8cb5-73406e1b20c1",
"first_published_at": "2024-10-08T23:49:37.001Z",
"release_id": null,
"lang": "default",
"path": null,
"alternates": [],
"default_full_slug": null,
"translated_slugs": null
},
"cv": 1729449138,
"rels": [],
"links": []
}
The reason why the code is so complicated is that I found that, when using the rich editor, body[0] is not always guaranteed. In my testing, the body could have multiple entries if the user inserted consecutive, adjacent components. Have you tried that? That was my principle concern if that makes sense.
Mmm, thats quite important feedback, do you have an example so I can reproduce where
body
has more than 1 entry?
You have an example in playground https://github.com/storyblok/richtext/blob/main/playground/vue/src/components/HomeView.vue#L353
@konstantin-karlovich-unbiased-co-uk Thank you for the feedback! However, I have already taken a look at that. To me, this is not an example of my use case nor does it show how to handle a true custom component.
Keep in mind that in Vue button
will render without fail, regardless of resolution, because it is a native HTML element, so the playground example doesn't illuminate anything because it does not feature an element that would fail to render if not resolved, etc.
Best I can tell, something outside the HTML spec needs to be shown in an example. Both one-off and consecutive, adjacent use of true custom components (non-HTML spec), including how to use a resolver, etc.
I submitted this issue after having read and absorbed all the provided docs beforehand, including the HomeView.vue
example you referenced. That approach did not appear to work for true custom components.
Any help you can provide would be much appreciated, but please keep in mind that I provided a detailed example above that I would like addressed. If need be, I can create a reproduction. Just let me know.
@konstantin-karlovich-unbiased-co-uk Thank you for the feedback! However, I have already taken a look at that. To me, this is not an example of my use case nor does it show how to handle a true custom component.
Keep in mind that in Vue
button
will render without fail, regardless of resolution, because it is a native HTML element, so the playground example doesn't illuminate anything because it does not feature an element that would fail to render if not resolved, etc.Best I can tell, something outside the HTML spec needs to be shown in an example. Both one-off and consecutive, adjacent use of true custom components (non-HTML spec), including how to use a resolver, etc.
I submitted this issue after having read and absorbed all the provided docs beforehand, including the
HomeView.vue
example you referenced. That approach did not appear to work for true custom components.Any help you can provide would be much appreciated, but please keep in mind that I provided a detailed example above that I would like addressed. If need be, I can create a reproduction. Just let me know.
@babalugats76 Sorry, but, my comment was for @alvarosabu when he asked for an example when body
has more than 1 entry
Summary
I am using Nuxt 3/Vue and need help migrating from renderRichText to storyblok/richtext, especially when it comes to the resolution and rendering of custom components contained within richtext fields.
I realize that this project is relatively new and probably still under heavy development, but, I have reviewed the playgrounds and available materials closely and my use case does not appear to be adequately addressed. IMHO, the Vue playground is missing key design patterns that would seemingly be part of any Vue implementation of the module.
Previous Solution
My previous solution utilized
renderRichText
and theVue3RuntimeTemplate
modules (for dynamic resolution).Work-In-Progress
I started by creating a composable to handle the application-wide rendering. I am specifically trying to address handling of
[BlockTypes.COMPONENT]
in the resolver and mapping of thecomponent
prop to the nested components, i.e.,Image
,Accordion
, andYouTube
:rich.ts
Then, I created a wrapper component that can be used to render the VNode returned from
RichTextRenderer.vue
In turn, I use this component downstream; for example, in a custom
Rich
Storyblok component:Rich.vue
Questions
What is the right way to resolve custom components?
Here is what I am doing which seems onerous and WAY more complicated (Array seems clunky, etc.) than before:
Is there a better way to do dynamic resolution?
I tried a lot of things, but ultimately had to ditch the use of
Vue3RuntimeTemplate
and instead had to hard code the dependencies:Any help/guidance would be greatly appreciated.