Skip to content

Instantly share code, notes, and snippets.

@a10k
Created May 29, 2021 20:22
Show Gist options
  • Save a10k/ba8a774edf4cfda7020c70cdd633124a to your computer and use it in GitHub Desktop.
Save a10k/ba8a774edf4cfda7020c70cdd633124a to your computer and use it in GitHub Desktop.
// https://observablehq.com/@a10k/preact-setup@921
export default function define(runtime, observer) {
const main = runtime.module();
main.variable(observer()).define(["Render","htm","Comp"], function(Render,htm,Comp)
{
//borrowed from https://observablehq.com/@observablehq/bannertitles
const pageTitle = "Preact Observable Setup";
const title1 = "Preact Observable";
const title2 = "Setup";
//:scope is uid generated on mount of the Comp/Resp containers
const stylestring = `
:scope svg{ background-color: #9B51E0; fill: #fff; }
:scope text {font-size: 36px; font-weight: bold; overflow-wrap: anywhere;}`;
//Renders to the observable cell
return Render(htm`
<h1 style="display: none">${pageTitle}</h1> <!-- extracted title -->
<${Comp} stylestring=${stylestring}>
<svg width="100%" viewBox="0 0 900 200">
<text x="50%" y="${200 / 4}" text-anchor="middle" opacity="0.8">
<tspan x="50%" dy="1.2em">${title1}</tspan>
<tspan x="50%" dy="1.2em">${title2}</tspan>
</text>
</svg>
</>
`);
}
);
main.variable(observer()).define(["md"], function(md){return(
md`### Usage
~~~js
import {htm, Preact, Render, Comp, Resp, Router, route, history, define} from '@a10k/preact-setup'
~~~
`
)});
main.variable(observer()).define(["md"], function(md){return(
md`### Setup`
)});
main.variable(observer("requires")).define("requires", ["require"], function(require){return(
require.alias({
preact: "https://cdnjs.cloudflare.com/ajax/libs/preact/10.5.12/preact.umd.js",
htm: "https://cdnjs.cloudflare.com/ajax/libs/htm/3.0.4/htm.umd.js",
hooks: "https://cdnjs.cloudflare.com/ajax/libs/preact/10.5.12/hooks.umd.js",
preactRouter: `https://npmcdn.com/preact-router@3.2.1/dist/preact-router.js`,
preactCustomElements: `https://cdnjs.cloudflare.com/ajax/libs/preact-custom-element/4.0.0/preact-custom-element.umd.js`
})
)});
main.variable(observer("Preact")).define("Preact", ["requires"], async function(requires)
{
const Preact = await requires("preact");
const preactRouter = requires("preactRouter");
const hooks = await requires("hooks");
Object.assign(Preact, hooks);
Preact.html = (await requires("htm")).bind(Preact.h);
return Preact;
}
);
main.variable(observer("htm")).define("htm", ["Preact"], function(Preact){return(
Preact.html
)});
main.variable(observer("Render")).define("Render", ["html","Preact"], function(html,Preact){return(
node => {
var dom = this || html`<div></div>`;
//var shadow = dom.shadowRoot || dom.attachShadow({ mode: 'open' });
Preact.render(node, dom);
return dom;
}
)});
main.variable(observer("Comp")).define("Comp", ["Preact","DOM"], function(Preact,DOM){return(
props => {
const { stylestring, classstring, onClick, children } = props;
const [stateStyleID, setStateStyleID] = Preact.useState(DOM.uid());
return Preact.html`<div onClick=${onClick} className=${classstring} id=${
stateStyleID.id
}>
<style>${(stylestring || '').replace(
/\:scope/g,
'#' + stateStyleID.id
)}</style>
${children}
</div>`;
}
)});
main.variable(observer("Resp")).define("Resp", ["Preact","DOM"], function(Preact,DOM){return(
props => {
const {
width,
height,
pagewidth,
classstring,
stylestring,
children
} = props;
const [stateStyleID, setStateStyleID] = Preact.useState(DOM.uid());
const scaling = val => (val / width) * pagewidth;
return Preact.html`<div style=${{
boxSizing: 'border-box',
height: scaling(height) + 'px'
}}>
<div id=${stateStyleID.id} className=${classstring} style=${{
width: width + 'px',
height: height + 'px',
transformOrigin: '0 0 0',
boxSizing: 'border-box',
willChange: 'transform',
transform: `scale3d(${scaling(1)},${scaling(1)},1)`,
"-webkit-font-smoothing": "subpixel-antialiased",
"backface-visibility": "hidden"
}}>
<style>${(stylestring || '').replace(
/\:scope/g,
'#' + stateStyleID.id
)}</style>
${children}
</div>
</div>`;
}
)});
main.variable(observer("Router")).define("Router", ["requires"], async function(requires){return(
(await requires("preactRouter")).Router
)});
main.variable(observer("route")).define("route", ["requires"], async function(requires){return(
(await requires("preactRouter")).route
)});
main.variable(observer("history")).define("history", ["require"], function(require){return(
require("history")
)});
main.variable(observer("define")).define("define", ["requires"], function(requires){return(
requires('preactCustomElements')
)});
main.variable(observer()).define(["md"], function(md){return(
md`### Demo
Minimalistic demos to keep the script small.`
)});
main.variable(observer()).define(["Render","htm","Comp"], function(Render,htm,Comp)
{
//defining styles as objects sucks, you cant copy paste from sketch/figma/xd or even the chrome debugger, what about hover and all the other cool css stuff? :scope is your magic bullet!
var style = `
:scope{
background: #e8e8e8;
border-radius: 2px;
padding: 2px;
cursor: pointer;
}
:scope:hover{
color: #3B5FC0;
}
:scope.underline{
text-decoration: underline;
}
:scope.strike{
text-decoration: line-through;
}
`;
return Render(htm`<${Comp}
classstring=${"strike underline"}
stylestring=${style}>
<i>Hello world!</i>
</>`);
}
);
main.variable(observer()).define(["Render","htm","Resp","width"], function(Render,htm,Resp,width){return(
Render(htm`<${Resp}
classstring=${""}
stylestring=${""}
width="100"
height="30"
pagewidth=${width}>
<i>Hello world!</i>
</>`)
)});
main.variable(observer("routes_example")).define("routes_example", ["route","htm","Router","history","Render"], function(route,htm,Router,history,Render)
{
const Button = props => {
const set_route = () => {
route('/' + props.page);
};
return htm`
<span onClick=${set_route} style="cursor:pointer;padding:5px; border:1px solid #f0f0f0;margin:4px;">
Route ${props.page.toUpperCase()}
</span>`;
};
const Nav = () => {
return htm`
<div>
<${Button} page="a"/>
<${Button} page="b"/>
<div style="padding:12px;background:#f0f0f0;margin:4px;text-align:center;">
<${Router} history=${history.createHashHistory()}>
<div path="/a">Route A</div>
<div path="/b">Route B</div>
<div default>None</div>
</>
</div>
</div>`;
};
return Render(htm`<${Nav}/>`);
}
);
main.variable(observer()).define(["md"], function(md){return(
md`### Demo - Custom elements!!`
)});
main.variable(observer("MyCE")).define("MyCE", ["Preact","htm","define"], function(Preact,htm,define)
{
let C = p => {
var r = Preact.useRef();
var str = p.name || "world";
Preact.useEffect(() => {
r.current.getRootNode().host.value = str;
r.current.getRootNode().host.dispatchEvent(new CustomEvent("input"));
}, [p.name]);
return htm`
<style>
*{
color:tomato;
}
</style>
<p ref=${r}>hello, ${str}</p>`;
};
try {
define(C, "hello-component", ["name"], { shadow: true });
} catch (e) {}
return C;
}
);
main.variable(observer()).define(["html"], function(html){return(
html`<hello-component name="Observable!"></hello-component>`
)});
return main;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment