a small incremental UI library for the web
javascript web ui
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix scoping and style todo

garrison 140ae000 bbcf2575

+67 -18
+61 -5
demos/todo/todo.tsx
··· 2 2 import { useState, useEffect, useStyle, useFiber } from '../../js/hooks.ts'; 3 3 4 4 function App(props) { 5 + useStyle(` 6 + main { 7 + margin: 96px auto; 8 + max-width: 400px; 9 + 10 + font-family: system-ui; 11 + -webkit-font-smoothing: antialiased; 12 + } 13 + `); 5 14 return ( 6 - <div> 15 + <main> 7 16 <List /> 8 - </div> 17 + </main> 9 18 ); 10 19 } 11 20 ··· 18 27 display: flex; 19 28 flex-direction: column; 20 29 } 30 + 31 + .items { 32 + margin-top: 8px; 33 + display: flex; 34 + flex-direction: column; 35 + border: 1px solid black; 36 + border-radius: 4px; 37 + } 21 38 `); 22 39 23 40 return ( 24 41 <div class="container"> 25 42 <ItemInput addItem={text => setItems(items => [...items, text])} /> 26 - <div id="items">{items.map(text => <Item text={text} />)}</div> 43 + <div class="items">{items.map(text => <Item text={text} />)}</div> 27 44 </div> 28 45 ); 29 46 } ··· 32 49 const [text, setText] = useState(''); 33 50 34 51 function submit() { 52 + if (text === '') return; 35 53 addItem(text); 36 54 setText(''); 37 55 } 38 56 57 + useStyle(` 58 + div { 59 + display: flex; 60 + gap: 8px; 61 + } 62 + input { 63 + flex: 1; 64 + } 65 + 66 + button, input { 67 + padding: 4px 8px; 68 + border: 1px solid black; 69 + border-radius: 4px; 70 + } 71 + button:focus-visible, input:focus-visible { 72 + outline: 1px solid blue; 73 + } 74 + 75 + button { 76 + background-color: transparent; 77 + } 78 + button:active { 79 + opacity: 40%; 80 + } 81 + `); 82 + 39 83 return ( 40 84 <div> 41 85 <input ··· 54 98 function Item(props) { 55 99 const [checked, setChecked] = useState(false); 56 100 101 + useStyle(` 102 + label { 103 + padding: 8px; 104 + display: flex; 105 + align-items: center; 106 + gap: 8px; 107 + } 108 + label:not(:last-child) { 109 + border-bottom: 1px solid black; 110 + } 111 + `); 112 + 57 113 return ( 58 - <div> 114 + <label> 59 115 <input 60 116 type="checkbox" 61 117 checked={checked} ··· 68 124 ? <s>{props.text}</s> 69 125 : <span>{props.text}</span> 70 126 } 71 - </div> 127 + </label> 72 128 ); 73 129 } 74 130
+6 -6
js/hooks.ts
··· 88 88 89 89 if (existingText !== text) { 90 90 scope = insertScopedStyles(text); 91 - setCurrentScope(scope); 92 - 93 91 fiber.hooks[pointer + 1] = text; 94 92 fiber.hooks[pointer + 2] = scope; 95 93 } 96 94 95 + setCurrentScope(scope); 97 96 return scope; 98 97 } 99 98 100 - const KNOWN_STYLES = new Set(); 99 + const KNOWN_STYLES = new Map(); 101 100 function insertScopedStyles(text) { 102 - if (KNOWN_STYLES.has(text)) return; 103 - KNOWN_STYLES.add(text); 101 + let scope = KNOWN_STYLES.get(text); 102 + if (scope !== undefined) return scope; 104 103 105 104 const hash = hashString(text); 106 105 // TODO: abs prevents a negative number (s--123) but is not ideal 107 - const scope = 's-' + Math.abs(hash).toString(36); 106 + scope = 's-' + Math.abs(hash).toString(36); 107 + KNOWN_STYLES.set(text, scope); 108 108 109 109 const ast = parseCSS(text); 110 110 scopeCSS(ast, scope);
-7
priv/static/todo.html
··· 2 2 <html> 3 3 <head> 4 4 <script defer src="/assets/js/todo.js"></script> 5 - <style> 6 - body { 7 - padding: 32px; 8 - margin: 0 auto; 9 - width: 800px; 10 - } 11 - </style> 12 5 </head> 13 6 <body> 14 7 <div id="root" />