experimental web port of the Union style engine + adapters
styling theming css solidjs react union kde
1

Configure Feed

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

fix solid-demo with outline heuristics

whey.party (Jun 18, 2026, 1:02 AM +0700) 19a08355 fb527f38

+79 -31
+2 -1
packages/solid-plugin/src/ApplicationHeader.tsx
··· 21 21 style:min-height="46px" 22 22 style:padding-left="6px" 23 23 style:padding-right="6px" 24 - style:justify-content="center" 24 + // unsure why justify-content center is even here? 25 + //style:justify-content="center" 25 26 > 26 27 {props.title ? <Heading level={1}>{props.title}</Heading> : props.children} 27 28 </StyledRect>
+75 -29
packages/solid-plugin/src/StyledRect.tsx
··· 92 92 /* Shadow via box-shadow */ 93 93 if (props.boxShadow) s['box-shadow'] = props.boxShadow; 94 94 if (!props.boxShadow && (props.shadowColor || props.shadowSize !== undefined || props.shadowBlur !== undefined || 95 - props.shadowOffsetHorizontal !== undefined || props.shadowOffsetVertical !== undefined)) { 95 + props.shadowOffsetHorizontal !== undefined || props.shadowOffsetVertical !== undefined)) { 96 96 const parts: string[] = []; 97 97 if (props.shadowOffsetHorizontal !== undefined) parts.push(toPx(props.shadowOffsetHorizontal)!); 98 98 if (props.shadowOffsetVertical !== undefined) parts.push(toPx(props.shadowOffsetVertical)!); ··· 102 102 s['box-shadow'] = parts.join(' '); 103 103 } 104 104 105 - /* Outline — flattened to native CSS `outline`. 106 - * 107 - * TODO: Per-side outline (+ expanded corner radius per adjacent widths) 108 - * requires the pseudo-element approach from styledrect-css-mapping-design(1).md §4.6: 109 - * 110 - * outline pseudo-element { 111 - * content: ""; 112 - * position: absolute; 113 - * pointer-events: none; 114 - * inset: -Npx; 115 - * border: Npx solid color; 116 - * border-radius: calc(R + min(Nadj))px; 117 - * } 118 - * 119 - * Union expresses outline as per-side widths/colors/styles, but CSS 120 - * `outline` is inherently uniform. For temporary simplicity, we flatten 121 - * all sides into a single uniform outline by picking the first side 122 - * with a defined width. Per-side differences are dropped at this layer. 123 - */ 124 - const outlineW = props.outlineLeftSize ?? props.outlineRightSize ?? props.outlineTopSize ?? props.outlineBottomSize; 125 - if (outlineW !== undefined) { 126 - const outlineC = props.outlineLeftColor ?? props.outlineRightColor ?? props.outlineTopColor ?? props.outlineBottomColor; 127 - const outlineS = props.outlineLeftStyle ?? props.outlineRightStyle ?? props.outlineTopStyle ?? props.outlineBottomStyle; 128 - s.outline = [toPx(outlineW), outlineS ?? 'solid', outlineC].filter(Boolean).join(' '); 129 - s['outline-offset'] = '0px'; 130 - } else if (props.outline) { 131 - s.outline = props.outline; 105 + /* 106 + * Outline — flattened to native CSS `outline`. 107 + * 108 + * CSS `outline` is uniform; Union expresses it per-side. We flatten heuristically: 109 + * Width: largest nonzero across all sides + shorthand; falls back to zero then undefined. 110 + * Color: shorthand color > winning-width side color > first truthy side (L→T→R→B). 111 + * Style: always "solid" if any width or color is set (only supported Union outline style). 112 + * 113 + * HACK: packOutlineSide emits unitless numbers ("2 solid red"), so we parse the shorthand 114 + * string back into components to re-add "px" via toPx(). 115 + * 116 + * TODO: Per-side outlines + per-corner radius adjustment requires the pseudo-element approach 117 + * which will also eliminate the HACK above. 118 + * 119 + * div::after { content:""; position:absolute; pointer-events:none; 120 + * inset:-Npx; border:Npx solid color; border-radius:calc(R + min(Nadj))px; } 121 + */ 122 + 123 + // --- parse shorthand string --- 124 + let shorthandW: number | undefined; 125 + let shorthandC: string | undefined; 126 + if (props.outline) { 127 + for (const p of props.outline.split(/\s+/)) { 128 + if (shorthandW === undefined) { 129 + const n = parseFloat(p); 130 + if (!isNaN(n)) { shorthandW = n; continue; } 131 + } 132 + // skip style token — we always force solid 133 + if (p === 'solid' || p === 'none') continue; 134 + if (shorthandC === undefined) shorthandC = p; 135 + } 136 + } 137 + 138 + // --- pick winning width and which side it came from --- 139 + const sides = ['Left', 'Right', 'Top', 'Bottom'] as const; 140 + type Side = typeof sides[number]; 141 + 142 + let winW: number | undefined; 143 + let winSide: Side | undefined; 144 + 145 + for (const side of sides) { 146 + const v = props[`outline${side}Size` as keyof typeof props] as number | undefined; 147 + if (v == null) continue; 148 + if (winW === undefined || v > winW) { winW = v; winSide = side; } 149 + } 150 + 151 + // shorthand competes: prefer it if it ties or wins (gives shorthand priority on equal) 152 + if (shorthandW !== undefined && (winW === undefined || shorthandW >= winW)) { 153 + winW = shorthandW; 154 + winSide = undefined; // came from shorthand, not a side 155 + } 156 + 157 + // --- pick color --- 158 + let outlineC: string | undefined = 159 + shorthandC // 1. shorthand 160 + ?? (winSide ? props[`outline${winSide}Color` as keyof typeof props] as string | undefined : undefined) // 2. winning side 161 + ?? sides.map(s => props[`outline${s}Color` as keyof typeof props] as string | undefined) 162 + .find(Boolean); // 3. first truthy L→T→R→B 163 + 164 + // --- emit --- 165 + if (winW !== undefined || outlineC) { 166 + s.outline = [toPx(winW), 'solid', outlineC].filter(Boolean).join(' '); 132 167 s['outline-offset'] = '0px'; 133 - s['outline-style'] = 'solid'; 134 168 } 135 169 136 170 return s; 171 + } 172 + 173 + function pickSize(...values: (number | undefined)[]) { 174 + let zero = undefined; 175 + 176 + for (const v of values) { 177 + if (v == null) continue; 178 + if (v > 0) return v; 179 + if (v === 0) zero = 0; 180 + } 181 + 182 + return zero; 137 183 } 138 184 139 185 /* ── Positioner child style utility ─────────────────────────── */
+2 -1
packages/solid-plugin/src/TextArea.tsx
··· 89 89 style:font-family="inherit" 90 90 style:font-size="inherit" 91 91 style:width="100%" 92 - style:outline="none" 92 + // unsure who set this :eyes: 93 + //style:outline="none" 93 94 style:resize="vertical" 94 95 value={props.value ?? ''} 95 96 disabled={props.disabled}