Created
May 29, 2021 20:22
-
-
Save a10k/ba8a774edf4cfda7020c70cdd633124a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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/[email protected]/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