Manually mounting SolidJS component within HTML component via `render`
I'm on an adventure of doing some truly weird shit. I'm parsing YAML and dynamically creating HTML and inserting SolidJS components based on the
(The user is the one who writes the YAML and runs the app, so it doesn't matter if it's insecure and dangerous)
How I'm getting this to work currently:
templatetemplate properties below:group/main:
template: |
<div class="main">
{{ widgets }}
</div>
widgets:
- type: 'clock'
template: |
<div class="clock">
{{ hours }}:{{ minutes }}
</div>group/main:
template: |
<div class="main">
{{ widgets }}
</div>
widgets:
- type: 'clock'
template: |
<div class="clock">
{{ hours }}:{{ minutes }}
</div>(The user is the one who writes the YAML and runs the app, so it doesn't matter if it's insecure and dangerous)
How I'm getting this to work currently:
export function ClockWidget(props) {
const [date, setDate] = createSignal(new Date());
const minutes = createMemo(() => date().getMinutes());
const hours = createMemo(() => date().getHours());
const interval = setInterval(() => setDate(new Date()), 1000);
// Create an `HTMLElement` from `props.template`.
const element = getParsedTemplate();
createEffect(
on(
() => [hours(), minutes()],
// When the hours/minutes change, re-parse the template and mutate
// the original HTMLElement in-place to match the new template. Maybe there's
// some better way to do this?
() => diffAndMutate(element, getParsedTemplate()),
),
);
function getParsedTemplate() {
return parseTemplate(props.template, { // props.template is a string `<div class="clock">{{ hours }} ...`
bindings: {
strings: {
hours: hours(),
minutes: minutes(),
},
},
});
}
return element; // This does not return JSX; it returns a regular `HTMLElement`.
}
export function Group(props) {
// Create an `HTMLElement` from `props.template`.
return parseTemplate(props.template, {
bindings: {
components: {
// Hardcode clock widget to be the only widget for this example.
widgets: () => (
<ClockWidget template={props.widgets[0].template} />
),
},
},
});
}export function ClockWidget(props) {
const [date, setDate] = createSignal(new Date());
const minutes = createMemo(() => date().getMinutes());
const hours = createMemo(() => date().getHours());
const interval = setInterval(() => setDate(new Date()), 1000);
// Create an `HTMLElement` from `props.template`.
const element = getParsedTemplate();
createEffect(
on(
() => [hours(), minutes()],
// When the hours/minutes change, re-parse the template and mutate
// the original HTMLElement in-place to match the new template. Maybe there's
// some better way to do this?
() => diffAndMutate(element, getParsedTemplate()),
),
);
function getParsedTemplate() {
return parseTemplate(props.template, { // props.template is a string `<div class="clock">{{ hours }} ...`
bindings: {
strings: {
hours: hours(),
minutes: minutes(),
},
},
});
}
return element; // This does not return JSX; it returns a regular `HTMLElement`.
}
export function Group(props) {
// Create an `HTMLElement` from `props.template`.
return parseTemplate(props.template, {
bindings: {
components: {
// Hardcode clock widget to be the only widget for this example.
widgets: () => (
<ClockWidget template={props.widgets[0].template} />
),
},
},
});
}