SVG handling

This commit is contained in:
Miel Truyen 2019-11-22 16:15:53 +01:00
parent 029fe16b6d
commit 698656c8f6
10 changed files with 147 additions and 14 deletions

View File

@ -63,6 +63,10 @@ export function render(vnode, opts = {}) {
let renderer = meta.renderer; let renderer = meta.renderer;
if(!renderer) throw new Error("No renderer for vnode", item.vnode); if(!renderer) throw new Error("No renderer for vnode", item.vnode);
// SVG handling..
if(!item.inSvg && item.vnode?.type === 'svg') item.inSvg = true;
else if(item.inSvg && item.vnode?.type === 'foreignObject') item.inSvg = false;
// Create the element if no matching existing element was set // Create the element if no matching existing element was set
let newlyCreated = false; let newlyCreated = false;
if (!item.host) { if (!item.host) {

View File

@ -13,6 +13,10 @@ const VNODEPROP_IGNORE = {
['ref']: true ['ref']: true
}; };
let namespace = {
svg: "http://www.w3.org/2000/svg"
}
/** /**
* Takes care of rendering a typical VNode (like div, span or any custom-element) * Takes care of rendering a typical VNode (like div, span or any custom-element)
* *
@ -28,7 +32,11 @@ export const NodeTreeRenderer = {
let vnode = item.vnode; let vnode = item.vnode;
if(typeof(vnode.type) === 'string'){ if(typeof(vnode.type) === 'string'){
// String-type -> DOM // String-type -> DOM
return item.document.createElement(vnode.type); if(item.inSvg){
return item.document.createElementNS(namespace.svg, vnode.type);
}else{
return item.document.createElement(vnode.type);
}
}else if(vnode.type?.tagName){ }else if(vnode.type?.tagName){
// Object-type -> CUSTOM-ELEMENT // Object-type -> CUSTOM-ELEMENT
return item.document.createElement(vnode.type.tagName); return item.document.createElement(vnode.type.tagName);
@ -90,7 +98,8 @@ export const NodeTreeRenderer = {
} }
// TODO might want to support objects for defining events, so we can specifiy passive or not, and other event options // TODO might want to support objects for defining events, so we can specifiy passive or not, and other event options
}else{ }else{
if(!VNODEPROP_EXCLUDE_DIRECT[key]){ if(!VNODEPROP_EXCLUDE_DIRECT[key] && !item.inSvg){
// TODO there are many properties we do not want to be setting directly.. (transform attr on svg's is a good example...)
// Unless otherwise excluded, set the prop directly on the Element as well (because this is what we'd typically want to do passing complex objects into custom-elements) // Unless otherwise excluded, set the prop directly on the Element as well (because this is what we'd typically want to do passing complex objects into custom-elements)
host[key] = newVal; host[key] = newVal;
} }

View File

@ -34,6 +34,30 @@ export default [
}) })
] ]
}, },
// SVG test
{
input: 'test/svg/index.jsx',
output: {
file: 'public/svg/index.js',
format: 'iife', // immediately-invoked function expression — suitable for <script> tags
sourcemap: true
},
plugins: [
sass(),
babel(), // babel
resolve({
extensions: [ '.mjs', '.js', '.jsx', '.json' ],
}), // node_modules
commonjs(), // CJS-modules
production && terser(), // minify, but only in production
copy({
targets: [
{ src: 'test/svg/index.html', dest: 'public/svg' }
],
copyOnce: true
})
]
},
// Todos MVC // Todos MVC
{ {
input: 'test/todos-mvc/index.jsx', input: 'test/todos-mvc/index.jsx',

View File

@ -10,21 +10,9 @@ document.body.appendChild(render(<div class="center-me" iCanDoUpperCaseAttrs={ "
//document.body.appendChild(render(<example-page />)); //document.body.appendChild(render(<example-page />));
document.body.appendChild(render(<ExamplePage />)); document.body.appendChild(render(<ExamplePage />));
/**
* Findings:
* - JSX does not allow dot-notation in attributes: language error
* - Current code lower-cases attributes that result: this a limitation of setAttribute
* - React uses on<EventName> to capture events and the IDE auto-suggests using this (can we generalize this approach for customEvents?)
*/
/** /**
* Continuation suggestionss: * Continuation suggestionss:
* - ref={...} does not work yet
* - style-attribute untested * - style-attribute untested
* - Want a way to toggle classes: <Host class={{'bq-checkbox': true, 'checked': this.isChecked}}> could do * - Want a way to toggle classes: <Host class={{'bq-checkbox': true, 'checked': this.isChecked}}> could do
* - Need to support update an existing DOM-tree to a VNode-tree
* - Need to support the key-attribute for lists (linking with previous to have an idea how to update DOM-tree efficiently, are we going atomico/react/prect style diffing with a Virtual-DOM?)
* - <Host> and <ShadowDom> special handlers
* - Supporting fragments <>...</>? * - Supporting fragments <>...</>?
* - Try working towards a simple ToDo-MVC application
*/ */

View File

@ -15,6 +15,9 @@
<li> <li>
<a href="./basic/">Basic testing</a> <a href="./basic/">Basic testing</a>
</li> </li>
<li>
<a href="./svg/">SVG Rendering</a>
</li>
<li> <li>
<a href="./todos-mvc/">Todos MVC</a> <a href="./todos-mvc/">Todos MVC</a>
</li> </li>

10
test/svg/index.html Normal file
View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Cerxes - CustomElements - SVG</title>
</head>
<body>
<script type="text/javascript" src="./index.js"></script>
</body>
</html>

11
test/svg/index.jsx Normal file
View File

@ -0,0 +1,11 @@
import {render} from "../../packages/csx";
import style from "./index.scss";
import {SvgLoader} from "./svg-loader";
document.body.appendChild(render(<style>{style}</style>));
document.body.appendChild(render(
<div class="center-me">
<h3>SVG Loader</h3>
<SvgLoader />
</div>
));

19
test/svg/index.scss Normal file
View File

@ -0,0 +1,19 @@
html{
width: 100%;
height: 100%;
}
body{
display: flex;
flex-direction: column;
overflow: auto;
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
.center-me{
align-self: center;
}

55
test/svg/svg-loader.jsx Normal file
View File

@ -0,0 +1,55 @@
import {CustomElement, defineElement, Host, ShadowDOM, State} from "../../packages/csx";
import loaderComponentShadowStyle from './svg-loader.shadow.scss';
// TODO configurability, like inverted and not with props...
@defineElement('svg-loader')
export class SvgLoader extends CustomElement{
// Constructor
constructor(){
super();
}
// Private properties
// Properties
// Handlers
// CustomElement
render(){
return (
<Host>
<ShadowDOM>
<style>
{ loaderComponentShadowStyle }
</style>
<div class="loader-content">
<div class="spinner">
<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg" stroke="#000">
<g fill="none" fill-rule="evenodd">
<g transform="translate(1 1)" stroke-width="2">
<circle stroke-opacity=".5" cx="18" cy="18" r="18"/>
<path d="M36 18c0-9.94-8.06-18-18-18">
<animateTransform
attributeName="transform"
type="rotate"
from="0 18 18"
to="360 18 18"
dur="1s"
repeatCount="indefinite"/>
</path>
</g>
</g>
</svg>
</div>
<slot>
</slot>
</div>
</ShadowDOM>
</Host>
)
}
}

View File

@ -0,0 +1,10 @@
:host{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.spinner{
padding: .5rem;
}
}