Skip to content

Commit

Permalink
fix: renderCustomElements is not bullet-proof (#280)
Browse files Browse the repository at this point in the history
* fix: renderCustomElements is not bullet-proof

* add test case

* test: add unit test. wip

* test: complete unit test case

* improve: simplify function

* refactor: add new unit tests group

* fix hydration errors
  • Loading branch information
fago authored Dec 26, 2024
1 parent b8430e6 commit ee5572b
Show file tree
Hide file tree
Showing 5 changed files with 421 additions and 8 deletions.
211 changes: 211 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@
"@nuxt/schema": "^3.14.1592",
"@nuxt/test-utils": "^3.15.1",
"@nuxtjs/i18n": "^8.5.6",
"@vue/test-utils": "^2.4.6",
"eslint": "^9.17.0",
"happy-dom": "^15.11.7",
"nuxt": "^3.14.1592",
"typescript": "^5.7.2",
"vitest": "^1.6.0"
Expand Down
45 changes: 37 additions & 8 deletions src/runtime/composables/useDrupalCe/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,21 +255,50 @@ export const useDrupalCe = () => {
}

/**
* Render elements from page data returned from fetchPage
* @param customElements
* Renders Vue components from JSON-serialized custom element data.
*
* @param customElements - Custom element data that can be:
* - null/undefined (returns null, skipping render)
* - string (auto-creates component rendering string as HTML if it contains markup)
* - single custom element object with {element: string, ...props}
* - array of custom element objects
* @returns Vue component definition, null for skipped render, or HTML-capable component for strings.
* Result can be used directly with Vue's dynamic component: <component :is="result">
*/
const renderCustomElements = (customElements: Record<string, any> | Array<object>) => {
if (Object.keys(customElements).length === 0) {
return
const renderCustomElements = (
customElements: null | undefined | string | Record<string, any> | Array<object>
) => {
// Handle null/undefined case
if (customElements == null) {
return null
}

// Handle string case by creating a component that can render HTML
if (typeof customElements === 'string') {
return defineComponent({
setup() {
return () => h('div', {
innerHTML: customElements
})
}
})
}

// Handle empty object case
if (typeof customElements === 'object' && Object.keys(customElements).length === 0) {
return null
}

// Handle array of custom elements
if (Array.isArray(customElements)) {
return customElements.map((customElement) => {
const resolvedElement = resolveCustomElement(customElement.element)
return resolvedElement ? h(resolvedElement, customElement) : null
return renderCustomElements(customElement)
})
}

// Handle single custom element object
const resolvedElement = resolveCustomElement(customElements.element)
return resolvedElement ? h((resolvedElement), customElements) : null
return resolvedElement ? h(resolvedElement, customElements) : null
}

/**
Expand Down
Loading

0 comments on commit ee5572b

Please sign in to comment.