From 718dc3b73d1f7c85cfdb38ad1d35f589bcddfdcb Mon Sep 17 00:00:00 2001 From: Chris Wanstrath <2+defunkt@users.noreply.github.com> Date: Mon, 29 Dec 2025 15:11:18 -0800 Subject: [PATCH] selectors --- README.md | 49 ++++++++++++++++++++++++++++++++++++++++++++ examples/profile.tsx | 2 +- examples/spa/app.tsx | 16 +++++++-------- src/index.tsx | 9 ++++---- 4 files changed, 62 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 7137ac2..9ff85a1 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,55 @@ console.log() console.log() ``` +### selectors + +Use `selectors` to write custom CSS selectors. Reference the current +element with `&` and other parts with `@PartName`: + +```tsx +const Checkbox = define("Checkbox", { + parts: { + Input: { + base: "input[type=checkbox]", + display: "none", + }, + Label: { + base: "label", + padding: 10, + cursor: "pointer", + color: "gray", + + selectors: { + // style Label when Input is checked + "@Input:checked + &": { + color: "green", + fontWeight: "bold", + }, + // style Label when Input is disabled + "@Input:disabled + &": { + opacity: 0.5, + cursor: "not-allowed", + }, + }, + }, + }, + + render({ props, parts: { Root, Input, Label } }) { + return ( + + + + ) + }, +}) + +// Usage + +``` + ## themes built-in support for CSS variables with full type safety: diff --git a/examples/profile.tsx b/examples/profile.tsx index 68e728c..9078a08 100644 --- a/examples/profile.tsx +++ b/examples/profile.tsx @@ -9,8 +9,8 @@ const UserProfile = define('UserProfile', { maxWidth: 600, margin: "0 auto", background: theme('colors-bgElevated'), - border: `1px solid ${theme('colors-border')}`, borderRadius: theme('radius-md'), + border: theme('colors-accent'), parts: { Header: { diff --git a/examples/spa/app.tsx b/examples/spa/app.tsx index 465c12a..a92d035 100644 --- a/examples/spa/app.tsx +++ b/examples/spa/app.tsx @@ -35,16 +35,9 @@ const ThemePicker = define('SpaThemePicker', { }, render({ parts: { Root, Select } }) { - const handleChange = (e: Event) => { - const target = e.target as HTMLSelectElement - const themeName = target.value - document.body.setAttribute('data-theme', themeName) - localStorage.setItem('theme', themeName) - } - return ( - @@ -53,6 +46,13 @@ const ThemePicker = define('SpaThemePicker', { } }) +function themeChanged(e: Event) { + const target = e.target as HTMLSelectElement + const themeName = target.value + document.body.setAttribute('data-theme', themeName) + localStorage.setItem('theme', themeName) +} + export const Main = define('SpaMain', { base: 'div', diff --git a/src/index.tsx b/src/index.tsx index 45cf5ee..db2c583 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -51,13 +51,12 @@ export function createThemedVar>(_themes: T) { } // Simplified API: register multiple themes and get typed themeVar in one call -export function createThemes< - T extends Record> ->(themes: T) { - const registeredThemes: Record> = {} +type Theme = Record +export function createThemes>(themes: T) { + const registeredThemes = {} as T for (const [name, values] of Object.entries(themes)) { - registeredThemes[name] = createTheme(name, values) + (registeredThemes as any)[name] = createTheme(name, values) } return createThemedVar(registeredThemes)