gucci
This commit is contained in:
parent
097dae4f2a
commit
966a0ce4b0
45
README.md
45
README.md
|
|
@ -6,16 +6,15 @@ Example:
|
||||||
import { define } from "forge"
|
import { define } from "forge"
|
||||||
|
|
||||||
export const Button = define("button", {
|
export const Button = define("button", {
|
||||||
layout: {
|
base: "button",
|
||||||
padding: 20,
|
|
||||||
},
|
padding: 20,
|
||||||
look: {
|
background: "blue",
|
||||||
background: "blue",
|
|
||||||
},
|
|
||||||
variants: {
|
variants: {
|
||||||
kind: {
|
kind: {
|
||||||
danger: { look: { background: "red" } },
|
danger: { background: "red" },
|
||||||
warning: { look: { background: "yellow" } },
|
warning: { background: "yellow" },
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
@ -26,35 +25,31 @@ export const Button = define("button", {
|
||||||
<Button kind="warning">Click me?</Button>
|
<Button kind="warning">Click me?</Button>
|
||||||
|
|
||||||
export const Profile = define("div", {
|
export const Profile = define("div", {
|
||||||
layout: {
|
padding: 50,
|
||||||
padding: 50,
|
background: "red",
|
||||||
},
|
|
||||||
look: {
|
|
||||||
background: "red",
|
|
||||||
},
|
|
||||||
|
|
||||||
parts: {
|
parts: {
|
||||||
header: { layout: { display: "flex" } },
|
Header: { display: "flex" },
|
||||||
avatar: { layout: { width: 50 } },
|
Avatar: { base: 'img', width: 50 },
|
||||||
bio: { look: { color: "gray" } },
|
Bio: { color: "gray" },
|
||||||
},
|
},
|
||||||
|
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
small: {
|
small: {
|
||||||
parts: { avatar: { layout: { width: 20 }}}
|
parts: { Avatar: { width: 20 }}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
render({ props, parts: { root, header, avatar, bio } }) {
|
render({ props, parts: { Root, Header, Avatar, Bio } }) {
|
||||||
return (
|
return (
|
||||||
<root>
|
<Root>
|
||||||
<header>
|
<Header>
|
||||||
<avatar src={props.pic} />
|
<Avatar src={props.pic} />
|
||||||
<bio>{props.bio}</bio>
|
<Bio>{props.bio}</Bio>
|
||||||
</header>
|
</Header>
|
||||||
</root>
|
</Root>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -4,109 +4,80 @@ import { Layout, ExampleSection } from './helpers'
|
||||||
const Button = define('Button', {
|
const Button = define('Button', {
|
||||||
base: 'button',
|
base: 'button',
|
||||||
|
|
||||||
layout: {
|
padding: "12px 24px",
|
||||||
padding: "12px 24px",
|
display: "inline-flex",
|
||||||
display: "inline-flex",
|
alignItems: "center",
|
||||||
alignItems: "center",
|
justifyContent: "center",
|
||||||
justifyContent: "center",
|
gap: 8,
|
||||||
gap: 8,
|
background: "#3b82f6",
|
||||||
},
|
color: "white",
|
||||||
|
border: "none",
|
||||||
look: {
|
borderRadius: 8,
|
||||||
background: "#3b82f6",
|
fontSize: 16,
|
||||||
color: "white",
|
fontWeight: 600,
|
||||||
border: "none",
|
cursor: "pointer",
|
||||||
borderRadius: 8,
|
transition: "all 0.2s ease",
|
||||||
fontSize: 16,
|
userSelect: "none",
|
||||||
fontWeight: 600,
|
boxShadow: "0 4px 6px rgba(59, 130, 246, 0.4), 0 2px 4px rgba(0, 0, 0, 0.1)",
|
||||||
cursor: "pointer",
|
transform: "translateY(0)",
|
||||||
transition: "all 0.2s ease",
|
|
||||||
userSelect: "none",
|
|
||||||
boxShadow: "0 4px 6px rgba(59, 130, 246, 0.4), 0 2px 4px rgba(0, 0, 0, 0.1)",
|
|
||||||
transform: "translateY(0)",
|
|
||||||
},
|
|
||||||
|
|
||||||
states: {
|
states: {
|
||||||
":not(:disabled):hover": {
|
":not(:disabled):hover": {
|
||||||
look: {
|
transform: 'translateY(-2px) !important',
|
||||||
transform: 'translateY(-2px) !important',
|
filter: 'brightness(1.05)'
|
||||||
filter: 'brightness(1.05)'
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
":not(:disabled):active": {
|
":not(:disabled):active": {
|
||||||
look: {
|
transform: 'translateY(1px) !important',
|
||||||
transform: 'translateY(1px) !important',
|
boxShadow: '0 2px 3px rgba(0, 0, 0, 0.2) !important'
|
||||||
boxShadow: '0 2px 3px rgba(0, 0, 0, 0.2) !important'
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
variants: {
|
variants: {
|
||||||
intent: {
|
intent: {
|
||||||
primary: {
|
primary: {
|
||||||
look: {
|
background: "#3b82f6",
|
||||||
background: "#3b82f6",
|
color: "white",
|
||||||
color: "white",
|
boxShadow: "0 4px 6px rgba(59, 130, 246, 0.4), 0 2px 4px rgba(0, 0, 0, 0.1)",
|
||||||
boxShadow: "0 4px 6px rgba(59, 130, 246, 0.4), 0 2px 4px rgba(0, 0, 0, 0.1)",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
secondary: {
|
secondary: {
|
||||||
look: {
|
background: "#f3f4f6",
|
||||||
background: "#f3f4f6",
|
color: "#374151",
|
||||||
color: "#374151",
|
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06)",
|
||||||
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06)",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
danger: {
|
danger: {
|
||||||
look: {
|
background: "#ef4444",
|
||||||
background: "#ef4444",
|
color: "white",
|
||||||
color: "white",
|
boxShadow: "0 4px 6px rgba(239, 68, 68, 0.4), 0 2px 4px rgba(0, 0, 0, 0.1)",
|
||||||
boxShadow: "0 4px 6px rgba(239, 68, 68, 0.4), 0 2px 4px rgba(0, 0, 0, 0.1)",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
ghost: {
|
ghost: {
|
||||||
look: {
|
background: "transparent",
|
||||||
background: "transparent",
|
color: "#aaa",
|
||||||
color: "#aaa",
|
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.2), 0 2px 4px rgba(0, 0, 0, 0.1)",
|
||||||
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.2), 0 2px 4px rgba(0, 0, 0, 0.1)",
|
border: "1px solid #eee",
|
||||||
border: "1px solid #eee",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
small: {
|
small: {
|
||||||
layout: {
|
padding: "8px 16px",
|
||||||
padding: "8px 16px",
|
fontSize: 14,
|
||||||
},
|
|
||||||
look: {
|
|
||||||
fontSize: 14,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
large: {
|
large: {
|
||||||
layout: {
|
padding: "16px 32px",
|
||||||
padding: "16px 32px",
|
fontSize: 18,
|
||||||
},
|
|
||||||
look: {
|
|
||||||
fontSize: 18,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
disabled: {
|
disabled: {
|
||||||
look: {
|
opacity: 0.5,
|
||||||
opacity: 0.5,
|
cursor: "not-allowed",
|
||||||
cursor: "not-allowed",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const ButtonRow = define('ButtonRow', {
|
const ButtonRow = define('ButtonRow', {
|
||||||
layout: {
|
display: 'flex',
|
||||||
display: 'flex',
|
gap: 16,
|
||||||
gap: 16,
|
flexWrap: 'wrap',
|
||||||
flexWrap: 'wrap',
|
alignItems: 'center',
|
||||||
alignItems: 'center',
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export const ButtonExamplesPage = () => (
|
export const ButtonExamplesPage = () => (
|
||||||
|
|
|
||||||
|
|
@ -2,48 +2,35 @@ import { define, Styles } from '../src'
|
||||||
|
|
||||||
export const Body = define('Body', {
|
export const Body = define('Body', {
|
||||||
base: 'body',
|
base: 'body',
|
||||||
layout: {
|
|
||||||
margin: 0,
|
|
||||||
padding: '40px 20px',
|
|
||||||
|
|
||||||
},
|
margin: 0,
|
||||||
look: {
|
padding: '40px 20px',
|
||||||
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
|
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
|
||||||
background: '#f3f4f6',
|
background: '#f3f4f6',
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const Container = define('Container', {
|
const Container = define('Container', {
|
||||||
layout: {
|
maxWidth: 1200,
|
||||||
maxWidth: 1200,
|
margin: '0 auto'
|
||||||
margin: '0 auto'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export const Header = define('Header', {
|
export const Header = define('Header', {
|
||||||
base: 'h1',
|
base: 'h1',
|
||||||
layout: {
|
|
||||||
marginBottom: 40,
|
marginBottom: 40,
|
||||||
},
|
color: '#111827'
|
||||||
look: {
|
|
||||||
color: '#111827'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export const ExampleSection = define('ExampleSection', {
|
export const ExampleSection = define('ExampleSection', {
|
||||||
layout: {
|
marginBottom: 40,
|
||||||
marginBottom: 40
|
|
||||||
},
|
|
||||||
parts: {
|
parts: {
|
||||||
Header: {
|
Header: {
|
||||||
base: 'h2',
|
base: 'h2',
|
||||||
layout: {
|
|
||||||
marginBottom: 16
|
marginBottom: 16,
|
||||||
},
|
color: '#374151',
|
||||||
look: {
|
fontSize: 18
|
||||||
color: '#374151',
|
|
||||||
fontSize: 18
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render({ props, parts: { Root, Header } }) {
|
render({ props, parts: { Root, Header } }) {
|
||||||
|
|
|
||||||
|
|
@ -2,37 +2,29 @@ import { define } from '../src'
|
||||||
import { Layout, ExampleSection } from './helpers'
|
import { Layout, ExampleSection } from './helpers'
|
||||||
|
|
||||||
const Tabs = define('Tabs', {
|
const Tabs = define('Tabs', {
|
||||||
layout: {
|
display: 'flex',
|
||||||
display: 'flex',
|
gap: 0,
|
||||||
gap: 0,
|
borderBottom: '2px solid #e5e7eb',
|
||||||
},
|
|
||||||
look: {
|
|
||||||
borderBottom: '2px solid #e5e7eb',
|
|
||||||
},
|
|
||||||
|
|
||||||
parts: {
|
parts: {
|
||||||
Tab: {
|
Tab: {
|
||||||
base: 'button',
|
base: 'button',
|
||||||
layout: {
|
|
||||||
padding: '12px 24px',
|
padding: '12px 24px',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
marginBottom: -2,
|
marginBottom: -2,
|
||||||
},
|
background: 'transparent',
|
||||||
look: {
|
border: 'none',
|
||||||
background: 'transparent',
|
borderBottom: '2px solid transparent',
|
||||||
border: 'none',
|
color: '#6b7280',
|
||||||
borderBottom: '2px solid transparent',
|
fontSize: 14,
|
||||||
color: '#6b7280',
|
fontWeight: 500,
|
||||||
fontSize: 14,
|
cursor: 'pointer',
|
||||||
fontWeight: 500,
|
transition: 'all 0.2s ease',
|
||||||
cursor: 'pointer',
|
|
||||||
transition: 'all 0.2s ease',
|
|
||||||
},
|
|
||||||
states: {
|
states: {
|
||||||
':hover': {
|
':hover': {
|
||||||
look: {
|
color: '#111827',
|
||||||
color: '#111827',
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -42,10 +34,8 @@ const Tabs = define('Tabs', {
|
||||||
active: {
|
active: {
|
||||||
parts: {
|
parts: {
|
||||||
Tab: {
|
Tab: {
|
||||||
look: {
|
color: '#3b82f6',
|
||||||
color: '#3b82f6',
|
borderBottom: '2px solid #3b82f6',
|
||||||
borderBottom: '2px solid #3b82f6',
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -69,34 +59,28 @@ const Tabs = define('Tabs', {
|
||||||
})
|
})
|
||||||
|
|
||||||
const Pills = define('Pills', {
|
const Pills = define('Pills', {
|
||||||
layout: {
|
display: 'flex',
|
||||||
display: 'flex',
|
gap: 8,
|
||||||
gap: 8,
|
flexWrap: 'wrap',
|
||||||
flexWrap: 'wrap',
|
|
||||||
},
|
|
||||||
|
|
||||||
parts: {
|
parts: {
|
||||||
Pill: {
|
Pill: {
|
||||||
base: 'button',
|
base: 'button',
|
||||||
layout: {
|
|
||||||
padding: '8px 16px',
|
padding: '8px 16px',
|
||||||
},
|
background: '#f3f4f6',
|
||||||
look: {
|
border: 'none',
|
||||||
background: '#f3f4f6',
|
borderRadius: 20,
|
||||||
border: 'none',
|
color: '#6b7280',
|
||||||
borderRadius: 20,
|
fontSize: 14,
|
||||||
color: '#6b7280',
|
fontWeight: 500,
|
||||||
fontSize: 14,
|
cursor: 'pointer',
|
||||||
fontWeight: 500,
|
transition: 'all 0.2s ease',
|
||||||
cursor: 'pointer',
|
|
||||||
transition: 'all 0.2s ease',
|
|
||||||
},
|
|
||||||
states: {
|
states: {
|
||||||
':hover': {
|
':hover': {
|
||||||
look: {
|
background: '#e5e7eb',
|
||||||
background: '#e5e7eb',
|
color: '#111827',
|
||||||
color: '#111827',
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -106,16 +90,12 @@ const Pills = define('Pills', {
|
||||||
active: {
|
active: {
|
||||||
parts: {
|
parts: {
|
||||||
Pill: {
|
Pill: {
|
||||||
look: {
|
background: '#3b82f6',
|
||||||
background: '#3b82f6',
|
color: 'white',
|
||||||
color: 'white',
|
|
||||||
},
|
|
||||||
states: {
|
states: {
|
||||||
':hover': {
|
':hover': {
|
||||||
look: {
|
background: '#2563eb',
|
||||||
background: '#2563eb',
|
color: 'white',
|
||||||
color: 'white',
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -141,52 +121,43 @@ const Pills = define('Pills', {
|
||||||
})
|
})
|
||||||
|
|
||||||
const VerticalNav = define('VerticalNav', {
|
const VerticalNav = define('VerticalNav', {
|
||||||
layout: {
|
display: 'flex',
|
||||||
display: 'flex',
|
flexDirection: 'column',
|
||||||
flexDirection: 'column',
|
gap: 4,
|
||||||
gap: 4,
|
width: 240,
|
||||||
width: 240,
|
|
||||||
},
|
|
||||||
|
|
||||||
parts: {
|
parts: {
|
||||||
NavItem: {
|
NavItem: {
|
||||||
base: 'a',
|
base: 'a',
|
||||||
layout: {
|
|
||||||
padding: '12px 16px',
|
padding: '12px 16px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
gap: 12,
|
gap: 12,
|
||||||
},
|
|
||||||
look: {
|
background: 'transparent',
|
||||||
background: 'transparent',
|
borderRadius: 8,
|
||||||
borderRadius: 8,
|
color: '#6b7280',
|
||||||
color: '#6b7280',
|
fontSize: 14,
|
||||||
fontSize: 14,
|
fontWeight: 500,
|
||||||
fontWeight: 500,
|
textDecoration: 'none',
|
||||||
textDecoration: 'none',
|
cursor: 'pointer',
|
||||||
cursor: 'pointer',
|
transition: 'all 0.2s ease',
|
||||||
transition: 'all 0.2s ease',
|
|
||||||
},
|
|
||||||
states: {
|
states: {
|
||||||
':hover': {
|
':hover': {
|
||||||
look: {
|
background: '#f3f4f6',
|
||||||
background: '#f3f4f6',
|
color: '#111827',
|
||||||
color: '#111827',
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Icon: {
|
Icon: {
|
||||||
layout: {
|
width: 20,
|
||||||
width: 20,
|
height: 20,
|
||||||
height: 20,
|
display: 'flex',
|
||||||
display: 'flex',
|
alignItems: 'center',
|
||||||
alignItems: 'center',
|
justifyContent: 'center',
|
||||||
justifyContent: 'center',
|
fontSize: 18,
|
||||||
},
|
|
||||||
look: {
|
|
||||||
fontSize: 18,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -194,16 +165,12 @@ const VerticalNav = define('VerticalNav', {
|
||||||
active: {
|
active: {
|
||||||
parts: {
|
parts: {
|
||||||
NavItem: {
|
NavItem: {
|
||||||
look: {
|
background: '#eff6ff',
|
||||||
background: '#eff6ff',
|
color: '#3b82f6',
|
||||||
color: '#3b82f6',
|
|
||||||
},
|
|
||||||
states: {
|
states: {
|
||||||
':hover': {
|
':hover': {
|
||||||
look: {
|
background: '#dbeafe',
|
||||||
background: '#dbeafe',
|
color: '#2563eb',
|
||||||
color: '#2563eb',
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -230,43 +197,35 @@ const VerticalNav = define('VerticalNav', {
|
||||||
})
|
})
|
||||||
|
|
||||||
const Breadcrumbs = define('Breadcrumbs', {
|
const Breadcrumbs = define('Breadcrumbs', {
|
||||||
layout: {
|
display: 'flex',
|
||||||
display: 'flex',
|
alignItems: 'center',
|
||||||
alignItems: 'center',
|
gap: 8,
|
||||||
gap: 8,
|
flexWrap: 'wrap',
|
||||||
flexWrap: 'wrap',
|
|
||||||
},
|
|
||||||
|
|
||||||
parts: {
|
parts: {
|
||||||
Item: {
|
Item: {
|
||||||
base: 'a',
|
base: 'a',
|
||||||
look: {
|
|
||||||
color: '#6b7280',
|
color: '#6b7280',
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
textDecoration: 'none',
|
textDecoration: 'none',
|
||||||
transition: 'color 0.2s ease',
|
transition: 'color 0.2s ease',
|
||||||
},
|
|
||||||
states: {
|
states: {
|
||||||
':hover': {
|
':hover': {
|
||||||
look: {
|
color: '#3b82f6',
|
||||||
color: '#3b82f6',
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Separator: {
|
Separator: {
|
||||||
look: {
|
color: '#d1d5db',
|
||||||
color: '#d1d5db',
|
fontSize: 14,
|
||||||
fontSize: 14,
|
userSelect: 'none',
|
||||||
userSelect: 'none',
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Current: {
|
Current: {
|
||||||
look: {
|
color: '#111827',
|
||||||
color: '#111827',
|
fontSize: 14,
|
||||||
fontSize: 14,
|
fontWeight: 500,
|
||||||
fontWeight: 500,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,167 +4,129 @@ import { Layout, ExampleSection } from './helpers'
|
||||||
const UserProfile = define('UserProfile', {
|
const UserProfile = define('UserProfile', {
|
||||||
base: 'div',
|
base: 'div',
|
||||||
|
|
||||||
layout: {
|
padding: 24,
|
||||||
padding: 24,
|
maxWidth: 600,
|
||||||
maxWidth: 600,
|
margin: "0 auto",
|
||||||
margin: "0 auto",
|
background: "white",
|
||||||
},
|
borderRadius: 12,
|
||||||
|
boxShadow: "0 2px 8px rgba(0,0,0,0.1)",
|
||||||
look: {
|
|
||||||
background: "white",
|
|
||||||
borderRadius: 12,
|
|
||||||
boxShadow: "0 2px 8px rgba(0,0,0,0.1)",
|
|
||||||
},
|
|
||||||
|
|
||||||
parts: {
|
parts: {
|
||||||
Header: {
|
Header: {
|
||||||
layout: {
|
display: "flex",
|
||||||
display: "flex",
|
alignItems: "center",
|
||||||
alignItems: "center",
|
gap: 16,
|
||||||
gap: 16,
|
marginBottom: 16,
|
||||||
marginBottom: 16,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Avatar: {
|
Avatar: {
|
||||||
base: 'img',
|
base: 'img',
|
||||||
layout: {
|
width: 64,
|
||||||
width: 64,
|
height: 64,
|
||||||
height: 64,
|
borderRadius: "50%",
|
||||||
},
|
objectFit: "cover",
|
||||||
look: {
|
border: "3px solid #e5e7eb",
|
||||||
borderRadius: "50%",
|
|
||||||
objectFit: "cover",
|
|
||||||
border: "3px solid #e5e7eb",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Info: {
|
Info: {
|
||||||
layout: {
|
flex: 1,
|
||||||
flex: 1,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Name: {
|
Name: {
|
||||||
layout: {
|
marginBottom: 4,
|
||||||
marginBottom: 4,
|
fontSize: 20,
|
||||||
},
|
fontWeight: 600,
|
||||||
look: {
|
color: "#111827",
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: 600,
|
|
||||||
color: "#111827",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Handle: {
|
Handle: {
|
||||||
look: {
|
fontSize: 14,
|
||||||
fontSize: 14,
|
color: "#6b7280",
|
||||||
color: "#6b7280",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Bio: {
|
Bio: {
|
||||||
layout: {
|
marginBottom: 16,
|
||||||
marginBottom: 16,
|
width: "100%",
|
||||||
width: "100%",
|
fontSize: 14,
|
||||||
},
|
lineHeight: 1.6,
|
||||||
look: {
|
color: "#374151",
|
||||||
fontSize: 14,
|
wordWrap: "break-word",
|
||||||
lineHeight: 1.6,
|
|
||||||
color: "#374151",
|
|
||||||
wordWrap: "break-word",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Stats: {
|
Stats: {
|
||||||
layout: {
|
display: "flex",
|
||||||
display: "flex",
|
gap: 24,
|
||||||
gap: 24,
|
paddingTop: 16,
|
||||||
paddingTop: 16,
|
borderTop: "1px solid #e5e7eb",
|
||||||
},
|
|
||||||
look: {
|
|
||||||
borderTop: "1px solid #e5e7eb",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Stat: {
|
Stat: {
|
||||||
layout: {
|
display: "flex",
|
||||||
display: "flex",
|
flexDirection: "column",
|
||||||
flexDirection: "column",
|
gap: 4,
|
||||||
gap: 4,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
StatValue: {
|
StatValue: {
|
||||||
look: {
|
fontSize: 18,
|
||||||
fontSize: 18,
|
fontWeight: 600,
|
||||||
fontWeight: 600,
|
color: "#111827",
|
||||||
color: "#111827",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
StatLabel: {
|
StatLabel: {
|
||||||
look: {
|
fontSize: 12,
|
||||||
fontSize: 12,
|
color: "#6b7280",
|
||||||
color: "#6b7280",
|
textTransform: "uppercase",
|
||||||
textTransform: "uppercase",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
compact: {
|
compact: {
|
||||||
layout: { padding: 16, maxWidth: 300 },
|
padding: 16,
|
||||||
|
maxWidth: 300,
|
||||||
parts: {
|
parts: {
|
||||||
Avatar: { layout: { width: 48, height: 48 } },
|
Avatar: { width: 48, height: 48 },
|
||||||
Name: { look: { fontSize: 16 } },
|
Name: { fontSize: 16 },
|
||||||
Bio: { look: { fontSize: 13 } },
|
Bio: { fontSize: 13 },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
skinny: {
|
skinny: {
|
||||||
layout: { padding: 20, maxWidth: 125 },
|
padding: 20,
|
||||||
|
maxWidth: 125,
|
||||||
parts: {
|
parts: {
|
||||||
Header: {
|
Header: {
|
||||||
layout: {
|
flexDirection: "column",
|
||||||
flexDirection: "column",
|
alignItems: "center",
|
||||||
alignItems: "center",
|
gap: 12,
|
||||||
gap: 12,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Avatar: { layout: { width: 80, height: 80 } },
|
Avatar: { width: 80, height: 80 },
|
||||||
Info: { layout: { flex: 0, width: "100%" } },
|
Info: { flex: 0, width: "100%" },
|
||||||
Name: { look: { textAlign: "center", fontSize: 18 } },
|
Name: { textAlign: "center", fontSize: 18 },
|
||||||
Handle: { look: { textAlign: "center" } },
|
Handle: { textAlign: "center" },
|
||||||
Bio: { look: { textAlign: "center", fontSize: 13 } },
|
Bio: { textAlign: "center", fontSize: 13 },
|
||||||
Stats: {
|
Stats: {
|
||||||
layout: {
|
flexDirection: "column",
|
||||||
flexDirection: "column",
|
gap: 16,
|
||||||
gap: 16,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Stat: { layout: { alignItems: "center" } },
|
Stat: { alignItems: "center" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
large: {
|
large: {
|
||||||
layout: { padding: 32, maxWidth: 800 },
|
padding: 32,
|
||||||
|
maxWidth: 800,
|
||||||
parts: {
|
parts: {
|
||||||
Avatar: { layout: { width: 96, height: 96 } },
|
Avatar: { width: 96, height: 96 },
|
||||||
Name: { look: { fontSize: 24 } },
|
Name: { fontSize: 24 },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
verified: {
|
verified: {
|
||||||
parts: {
|
parts: {
|
||||||
Avatar: {
|
Avatar: {
|
||||||
look: {
|
border: "3px solid #3b82f6",
|
||||||
border: "3px solid #3b82f6",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
theme: {
|
theme: {
|
||||||
dark: {
|
dark: {
|
||||||
look: {
|
background: "#1f2937",
|
||||||
background: "#1f2937",
|
|
||||||
},
|
|
||||||
parts: {
|
parts: {
|
||||||
Name: { look: { color: "#f9fafb" } },
|
Name: { color: "#f9fafb" },
|
||||||
Handle: { look: { color: "#9ca3af" } },
|
Handle: { color: "#9ca3af" },
|
||||||
Bio: { look: { color: "#d1d5db" } },
|
Bio: { color: "#d1d5db" },
|
||||||
Stats: { look: { borderTop: "1px solid #374151" } },
|
Stats: { borderTop: "1px solid #374151" },
|
||||||
StatValue: { look: { color: "#f9fafb" } },
|
StatValue: { color: "#f9fafb" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import type { JSX } from 'hono/jsx'
|
import type { JSX } from 'hono/jsx'
|
||||||
import { type TagDef, UnitlessProps } from './types'
|
import { type TagDef, UnitlessProps, NonStyleKeys } from './types'
|
||||||
|
|
||||||
export const styles: Record<string, Record<string, string>> = {}
|
export const styles: Record<string, Record<string, string>> = {}
|
||||||
export const Styles = () => <style dangerouslySetInnerHTML={{ __html: stylesToCSS(styles) }} />
|
export const Styles = () => <style dangerouslySetInnerHTML={{ __html: stylesToCSS(styles) }} />
|
||||||
|
|
@ -45,8 +45,10 @@ function camelToDash(name: string): string {
|
||||||
function makeStyle(def: TagDef) {
|
function makeStyle(def: TagDef) {
|
||||||
const style: Record<string, string> = {}
|
const style: Record<string, string> = {}
|
||||||
|
|
||||||
for (const [name, value] of Object.entries(Object.assign({}, def.layout ?? {}, def.look ?? {})))
|
for (const [name, value] of Object.entries(def)) {
|
||||||
|
if (NonStyleKeys.has(name)) continue
|
||||||
style[camelToDash(name)] = `${typeof value === 'number' && !UnitlessProps.has(name) ? `${value}px` : value}`
|
style[camelToDash(name)] = `${typeof value === 'number' && !UnitlessProps.has(name) ? `${value}px` : value}`
|
||||||
|
}
|
||||||
|
|
||||||
return style
|
return style
|
||||||
}
|
}
|
||||||
|
|
@ -57,28 +59,37 @@ function makeComponent(baseName: string, rootDef: TagDef, rootProps: Record<stri
|
||||||
const base = def.base ?? 'div'
|
const base = def.base ?? 'div'
|
||||||
const Tag = (base) as keyof JSX.IntrinsicElements
|
const Tag = (base) as keyof JSX.IntrinsicElements
|
||||||
|
|
||||||
const classNames = [makeClassName(baseName, partName)]
|
return ({ children, ...props }: { children: any, [key: string]: any }) => {
|
||||||
|
const classNames = [makeClassName(baseName, partName)]
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(rootProps)) {
|
const allProps = { ...rootProps, ...props }
|
||||||
const variantConfig = rootDef.variants?.[key]
|
|
||||||
if (!variantConfig) continue
|
|
||||||
|
|
||||||
const variantName = key
|
for (const [key, value] of Object.entries(allProps)) {
|
||||||
const variantKey = value
|
const variantConfig = rootDef.variants?.[key]
|
||||||
|
if (!variantConfig) continue
|
||||||
|
|
||||||
let variantDef: TagDef | undefined
|
// Remove variant prop from being passed to HTML element
|
||||||
if ('parts' in variantConfig || 'layout' in variantConfig || 'look' in variantConfig) {
|
delete props[key]
|
||||||
if (value === true) variantDef = variantConfig as TagDef
|
|
||||||
} else {
|
const variantName = key
|
||||||
variantDef = (variantConfig as Record<string, TagDef>)[value as string]
|
const variantKey = value
|
||||||
|
|
||||||
|
let variantDef: TagDef | undefined
|
||||||
|
// Distinguish boolean variants from keyed variants:
|
||||||
|
// - Boolean variants: component({ variant: true }) → variantConfig is a TagDef
|
||||||
|
// - Keyed variants: component({ variant: 'key' }) → variantConfig[key] is a TagDef
|
||||||
|
if (value === true) {
|
||||||
|
variantDef = variantConfig as TagDef
|
||||||
|
} else if (typeof value === 'string') {
|
||||||
|
variantDef = (variantConfig as Record<string, TagDef>)[value]
|
||||||
|
}
|
||||||
|
if (!variantDef) continue
|
||||||
|
|
||||||
|
classNames.push(variantKey === true ? variantName : `${variantName}-${variantKey}`)
|
||||||
}
|
}
|
||||||
if (!variantDef) continue
|
|
||||||
|
|
||||||
classNames.push(variantKey === true ? variantName : `${variantName}-${variantKey}`)
|
return <Tag class={classNames.join(' ')} {...props}>{children}</Tag>
|
||||||
}
|
}
|
||||||
|
|
||||||
return ({ children, ...props }: { children: any, [key: string]: any }) =>
|
|
||||||
<Tag class={classNames.join(' ')} {...props}>{children}</Tag>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// adds CSS styles for tag definition
|
// adds CSS styles for tag definition
|
||||||
|
|
@ -98,13 +109,17 @@ function registerStyles(name: string, def: TagDef) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [variantName, variantConfig] of Object.entries(def.variants ?? {})) {
|
for (const [variantName, variantConfig] of Object.entries(def.variants ?? {})) {
|
||||||
// Check if it's a boolean variant (has layout/look/parts directly) or a keyed variant
|
// Detect boolean vs keyed variants by checking if config has structural keys or looks like a TagDef
|
||||||
if ('parts' in variantConfig || 'layout' in variantConfig || 'look' in variantConfig) {
|
const isBooleanVariant = 'parts' in variantConfig || 'styles' in variantConfig || 'states' in variantConfig ||
|
||||||
// Boolean variant - treat variantConfig as TagDef
|
// If first key is camelCase or contains CSS-like properties, treat as boolean variant
|
||||||
|
Object.keys(variantConfig).some(k => k !== k.toLowerCase() || typeof (variantConfig as any)[k] !== 'object')
|
||||||
|
|
||||||
|
if (isBooleanVariant) {
|
||||||
|
// Boolean variant - variantConfig is a TagDef
|
||||||
const variantDef = variantConfig as TagDef
|
const variantDef = variantConfig as TagDef
|
||||||
const baseClassName = makeClassName(name)
|
const baseClassName = makeClassName(name)
|
||||||
const className = `${baseClassName}.${variantName}`
|
const className = `${baseClassName}.${variantName}`
|
||||||
styles[className] ??= makeStyle({ layout: variantDef.layout, look: variantDef.look })
|
styles[className] ??= makeStyle(variantDef)
|
||||||
for (const [state, style] of Object.entries(variantDef.states ?? {}))
|
for (const [state, style] of Object.entries(variantDef.states ?? {}))
|
||||||
styles[`${className}${state}`] = makeStyle(style)
|
styles[`${className}${state}`] = makeStyle(style)
|
||||||
|
|
||||||
|
|
@ -119,7 +134,7 @@ function registerStyles(name: string, def: TagDef) {
|
||||||
// Keyed variant - iterate over the keys
|
// Keyed variant - iterate over the keys
|
||||||
for (const [variantKey, variantDef] of Object.entries(variantConfig as Record<string, TagDef>)) {
|
for (const [variantKey, variantDef] of Object.entries(variantConfig as Record<string, TagDef>)) {
|
||||||
const className = makeClassName(name, undefined, variantName, variantKey)
|
const className = makeClassName(name, undefined, variantName, variantKey)
|
||||||
styles[className] ??= makeStyle({ layout: variantDef.layout, look: variantDef.look })
|
styles[className] ??= makeStyle(variantDef)
|
||||||
for (const [state, style] of Object.entries(variantDef.states ?? {}))
|
for (const [state, style] of Object.entries(variantDef.states ?? {}))
|
||||||
styles[`${className}${state}`] = makeStyle(style)
|
styles[`${className}${state}`] = makeStyle(style)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { renderToString, getStylesCSS, parseCSS } from './test_helpers'
|
||||||
describe('define - basic functionality', () => {
|
describe('define - basic functionality', () => {
|
||||||
test('creates a component function', () => {
|
test('creates a component function', () => {
|
||||||
const Component = define({
|
const Component = define({
|
||||||
layout: { display: 'flex' }
|
display: 'flex'
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(typeof Component).toBe('function')
|
expect(typeof Component).toBe('function')
|
||||||
|
|
@ -13,7 +13,7 @@ describe('define - basic functionality', () => {
|
||||||
|
|
||||||
test('component returns a JSX element', () => {
|
test('component returns a JSX element', () => {
|
||||||
const Component = define({
|
const Component = define({
|
||||||
layout: { display: 'flex' }
|
display: 'flex'
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = Component({})
|
const result = Component({})
|
||||||
|
|
@ -23,7 +23,7 @@ describe('define - basic functionality', () => {
|
||||||
|
|
||||||
test('applies className to rendered element', () => {
|
test('applies className to rendered element', () => {
|
||||||
const Component = define('MyComponent', {
|
const Component = define('MyComponent', {
|
||||||
layout: { display: 'flex' }
|
display: 'flex'
|
||||||
})
|
})
|
||||||
|
|
||||||
const html = renderToString(Component({}))
|
const html = renderToString(Component({}))
|
||||||
|
|
@ -31,8 +31,8 @@ describe('define - basic functionality', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('generates unique anonymous component names', () => {
|
test('generates unique anonymous component names', () => {
|
||||||
const Component1 = define({ layout: { display: 'flex' } })
|
const Component1 = define({ display: 'flex' })
|
||||||
const Component2 = define({ layout: { display: 'block' } })
|
const Component2 = define({ display: 'block' })
|
||||||
|
|
||||||
const html1 = renderToString(Component1({}))
|
const html1 = renderToString(Component1({}))
|
||||||
const html2 = renderToString(Component2({}))
|
const html2 = renderToString(Component2({}))
|
||||||
|
|
@ -45,7 +45,7 @@ describe('define - basic functionality', () => {
|
||||||
|
|
||||||
test('renders default div element', () => {
|
test('renders default div element', () => {
|
||||||
const Component = define('DivTest', {
|
const Component = define('DivTest', {
|
||||||
layout: { display: 'flex' }
|
display: 'flex'
|
||||||
})
|
})
|
||||||
|
|
||||||
const html = renderToString(Component({}))
|
const html = renderToString(Component({}))
|
||||||
|
|
@ -56,7 +56,7 @@ describe('define - basic functionality', () => {
|
||||||
test('respects custom base element', () => {
|
test('respects custom base element', () => {
|
||||||
const Component = define('ButtonTest', {
|
const Component = define('ButtonTest', {
|
||||||
base: 'button',
|
base: 'button',
|
||||||
look: { color: 'blue' }
|
color: 'blue'
|
||||||
})
|
})
|
||||||
|
|
||||||
const html = renderToString(Component({}))
|
const html = renderToString(Component({}))
|
||||||
|
|
@ -83,11 +83,9 @@ describe('define - basic functionality', () => {
|
||||||
describe('CSS generation - camelCase to kebab-case', () => {
|
describe('CSS generation - camelCase to kebab-case', () => {
|
||||||
test('converts camelCase properties to kebab-case', () => {
|
test('converts camelCase properties to kebab-case', () => {
|
||||||
define('CamelTest', {
|
define('CamelTest', {
|
||||||
layout: {
|
flexDirection: 'column',
|
||||||
flexDirection: 'column',
|
alignItems: 'center',
|
||||||
alignItems: 'center',
|
justifyContent: 'space-between'
|
||||||
justifyContent: 'space-between'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const css = getStylesCSS()
|
const css = getStylesCSS()
|
||||||
|
|
@ -98,10 +96,8 @@ describe('CSS generation - camelCase to kebab-case', () => {
|
||||||
|
|
||||||
test('handles consecutive capital letters', () => {
|
test('handles consecutive capital letters', () => {
|
||||||
define('ConsecutiveTest', {
|
define('ConsecutiveTest', {
|
||||||
look: {
|
backgroundColor: 'red',
|
||||||
backgroundColor: 'red',
|
borderRadius: 5
|
||||||
borderRadius: 5
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const css = getStylesCSS()
|
const css = getStylesCSS()
|
||||||
|
|
@ -113,12 +109,10 @@ describe('CSS generation - camelCase to kebab-case', () => {
|
||||||
describe('CSS generation - numeric values and units', () => {
|
describe('CSS generation - numeric values and units', () => {
|
||||||
test('adds px unit to numeric layout values', () => {
|
test('adds px unit to numeric layout values', () => {
|
||||||
define('NumericTest', {
|
define('NumericTest', {
|
||||||
layout: {
|
width: 100,
|
||||||
width: 100,
|
height: 200,
|
||||||
height: 200,
|
padding: 16,
|
||||||
padding: 16,
|
margin: 8
|
||||||
margin: 8
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const styles = parseCSS(getStylesCSS())
|
const styles = parseCSS(getStylesCSS())
|
||||||
|
|
@ -130,12 +124,10 @@ describe('CSS generation - numeric values and units', () => {
|
||||||
|
|
||||||
test('preserves string values without adding px', () => {
|
test('preserves string values without adding px', () => {
|
||||||
define('StringTest', {
|
define('StringTest', {
|
||||||
layout: {
|
width: '100%',
|
||||||
width: '100%',
|
height: 'auto',
|
||||||
height: 'auto',
|
margin: '0 auto',
|
||||||
margin: '0 auto',
|
padding: '1rem'
|
||||||
padding: '1rem'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const styles = parseCSS(getStylesCSS())
|
const styles = parseCSS(getStylesCSS())
|
||||||
|
|
@ -147,18 +139,14 @@ describe('CSS generation - numeric values and units', () => {
|
||||||
|
|
||||||
test('does not add px to unitless properties', () => {
|
test('does not add px to unitless properties', () => {
|
||||||
define('UnitlessTest', {
|
define('UnitlessTest', {
|
||||||
layout: {
|
flex: 1,
|
||||||
flex: 1,
|
flexGrow: 2,
|
||||||
flexGrow: 2,
|
flexShrink: 1,
|
||||||
flexShrink: 1,
|
zIndex: 10,
|
||||||
zIndex: 10,
|
order: 3,
|
||||||
order: 3
|
opacity: 0.5,
|
||||||
},
|
fontWeight: 700,
|
||||||
look: {
|
lineHeight: 1.5
|
||||||
opacity: 0.5,
|
|
||||||
fontWeight: 700,
|
|
||||||
lineHeight: 1.5
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const styles = parseCSS(getStylesCSS())
|
const styles = parseCSS(getStylesCSS())
|
||||||
|
|
@ -174,14 +162,10 @@ describe('CSS generation - numeric values and units', () => {
|
||||||
|
|
||||||
test('handles numeric zero values correctly', () => {
|
test('handles numeric zero values correctly', () => {
|
||||||
define('ZeroTest', {
|
define('ZeroTest', {
|
||||||
layout: {
|
margin: 0,
|
||||||
margin: 0,
|
padding: 0,
|
||||||
padding: 0,
|
zIndex: 0,
|
||||||
zIndex: 0
|
opacity: 0
|
||||||
},
|
|
||||||
look: {
|
|
||||||
opacity: 0
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const styles = parseCSS(getStylesCSS())
|
const styles = parseCSS(getStylesCSS())
|
||||||
|
|
@ -195,12 +179,10 @@ describe('CSS generation - numeric values and units', () => {
|
||||||
describe('CSS generation - layout and look', () => {
|
describe('CSS generation - layout and look', () => {
|
||||||
test('generates CSS for layout properties', () => {
|
test('generates CSS for layout properties', () => {
|
||||||
define('LayoutTest', {
|
define('LayoutTest', {
|
||||||
layout: {
|
display: 'flex',
|
||||||
display: 'flex',
|
flexDirection: 'column',
|
||||||
flexDirection: 'column',
|
gap: 16,
|
||||||
gap: 16,
|
padding: 20
|
||||||
padding: 20
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const css = getStylesCSS()
|
const css = getStylesCSS()
|
||||||
|
|
@ -213,12 +195,10 @@ describe('CSS generation - layout and look', () => {
|
||||||
|
|
||||||
test('generates CSS for look properties', () => {
|
test('generates CSS for look properties', () => {
|
||||||
define('LookTest', {
|
define('LookTest', {
|
||||||
look: {
|
color: 'blue',
|
||||||
color: 'blue',
|
backgroundColor: 'white',
|
||||||
backgroundColor: 'white',
|
fontSize: 16,
|
||||||
fontSize: 16,
|
fontWeight: 600
|
||||||
fontWeight: 600
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const css = getStylesCSS()
|
const css = getStylesCSS()
|
||||||
|
|
@ -231,14 +211,10 @@ describe('CSS generation - layout and look', () => {
|
||||||
|
|
||||||
test('combines layout and look properties', () => {
|
test('combines layout and look properties', () => {
|
||||||
define('CombinedTest', {
|
define('CombinedTest', {
|
||||||
layout: {
|
display: 'flex',
|
||||||
display: 'flex',
|
padding: 16,
|
||||||
padding: 16
|
color: 'blue',
|
||||||
},
|
backgroundColor: 'white'
|
||||||
look: {
|
|
||||||
color: 'blue',
|
|
||||||
backgroundColor: 'white'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const styles = parseCSS(getStylesCSS())
|
const styles = parseCSS(getStylesCSS())
|
||||||
|
|
@ -253,11 +229,11 @@ describe('CSS generation - layout and look', () => {
|
||||||
describe('CSS generation - parts', () => {
|
describe('CSS generation - parts', () => {
|
||||||
test('generates separate CSS for each part', () => {
|
test('generates separate CSS for each part', () => {
|
||||||
define('PartTest', {
|
define('PartTest', {
|
||||||
layout: { display: 'flex' },
|
display: 'flex',
|
||||||
parts: {
|
parts: {
|
||||||
Header: { base: 'header', look: { color: 'red', fontSize: 20 } },
|
Header: { base: 'header', color: 'red', fontSize: 20 },
|
||||||
Body: { base: 'main', layout: { padding: 20 } },
|
Body: { base: 'main', padding: 20 },
|
||||||
Footer: { base: 'footer', look: { fontSize: 12 } }
|
Footer: { base: 'footer', fontSize: 12 }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -271,7 +247,7 @@ describe('CSS generation - parts', () => {
|
||||||
test('part className format is ComponentName_PartName', () => {
|
test('part className format is ComponentName_PartName', () => {
|
||||||
define('ComponentWithParts', {
|
define('ComponentWithParts', {
|
||||||
parts: {
|
parts: {
|
||||||
MyPart: { look: { color: 'green' } }
|
MyPart: { color: 'green' }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -345,10 +321,10 @@ describe('components with parts', () => {
|
||||||
describe('variants - boolean variants', () => {
|
describe('variants - boolean variants', () => {
|
||||||
test('applies boolean variant class when true', () => {
|
test('applies boolean variant class when true', () => {
|
||||||
const Component = define('BoolVariant', {
|
const Component = define('BoolVariant', {
|
||||||
layout: { display: 'flex' },
|
display: 'flex',
|
||||||
variants: {
|
variants: {
|
||||||
primary: {
|
primary: {
|
||||||
look: { color: 'blue' }
|
color: 'blue'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -362,7 +338,7 @@ describe('variants - boolean variants', () => {
|
||||||
const Component = define('BoolVariantFalse', {
|
const Component = define('BoolVariantFalse', {
|
||||||
variants: {
|
variants: {
|
||||||
active: {
|
active: {
|
||||||
look: { backgroundColor: 'green' }
|
backgroundColor: 'green'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -379,10 +355,10 @@ describe('variants - boolean variants', () => {
|
||||||
|
|
||||||
test('generates CSS for component with boolean variant', () => {
|
test('generates CSS for component with boolean variant', () => {
|
||||||
define('BoolVariantCSS', {
|
define('BoolVariantCSS', {
|
||||||
layout: { display: 'block' },
|
display: 'block',
|
||||||
variants: {
|
variants: {
|
||||||
active: {
|
active: {
|
||||||
look: { backgroundColor: 'green' }
|
backgroundColor: 'green'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -398,9 +374,9 @@ describe('variants - string/enum variants', () => {
|
||||||
const Component = define('StringVariant', {
|
const Component = define('StringVariant', {
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
small: { layout: { padding: 8 } },
|
small: { padding: 8 },
|
||||||
medium: { layout: { padding: 16 } },
|
medium: { padding: 16 },
|
||||||
large: { layout: { padding: 24 } }
|
large: { padding: 24 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -416,9 +392,9 @@ describe('variants - string/enum variants', () => {
|
||||||
define('ColorVariant', {
|
define('ColorVariant', {
|
||||||
variants: {
|
variants: {
|
||||||
color: {
|
color: {
|
||||||
red: { look: { color: 'red', backgroundColor: '#ffeeee' } },
|
red: { color: 'red', backgroundColor: '#ffeeee' },
|
||||||
blue: { look: { color: 'blue', backgroundColor: '#eeeeff' } },
|
blue: { color: 'blue', backgroundColor: '#eeeeff' },
|
||||||
green: { look: { color: 'green', backgroundColor: '#eeffee' } }
|
green: { color: 'green', backgroundColor: '#eeffee' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -433,12 +409,12 @@ describe('variants - string/enum variants', () => {
|
||||||
const Component = define('MultiVariant', {
|
const Component = define('MultiVariant', {
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
small: { layout: { padding: 8 } },
|
small: { padding: 8 },
|
||||||
large: { layout: { padding: 24 } }
|
large: { padding: 24 }
|
||||||
},
|
},
|
||||||
color: {
|
color: {
|
||||||
red: { look: { color: 'red' } },
|
red: { color: 'red' },
|
||||||
blue: { look: { color: 'blue' } }
|
blue: { color: 'blue' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -452,7 +428,7 @@ describe('variants - string/enum variants', () => {
|
||||||
const Component = define('UndefinedVariant', {
|
const Component = define('UndefinedVariant', {
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
small: { layout: { padding: 8 } }
|
small: { padding: 8 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -466,7 +442,7 @@ describe('variants - string/enum variants', () => {
|
||||||
const Component = define('NonVariantProps', {
|
const Component = define('NonVariantProps', {
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
small: { layout: { padding: 8 } }
|
small: { padding: 8 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -488,12 +464,12 @@ describe('variants with parts', () => {
|
||||||
theme: {
|
theme: {
|
||||||
dark: {
|
dark: {
|
||||||
parts: {
|
parts: {
|
||||||
Header: { look: { color: 'white', backgroundColor: 'black' } }
|
Header: { color: 'white', backgroundColor: 'black' }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
light: {
|
light: {
|
||||||
parts: {
|
parts: {
|
||||||
Header: { look: { color: 'black', backgroundColor: 'white' } }
|
Header: { color: 'black', backgroundColor: 'white' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -514,7 +490,7 @@ describe('variants with parts', () => {
|
||||||
},
|
},
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
large: { layout: { padding: 20 } }
|
large: { padding: 20 }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render: ({ props, parts }) => {
|
render: ({ props, parts }) => {
|
||||||
|
|
@ -531,7 +507,7 @@ describe('variants with parts', () => {
|
||||||
describe('custom render function', () => {
|
describe('custom render function', () => {
|
||||||
test('uses custom render when provided', () => {
|
test('uses custom render when provided', () => {
|
||||||
const Component = define('CustomRender', {
|
const Component = define('CustomRender', {
|
||||||
layout: { display: 'flex' },
|
display: 'flex',
|
||||||
render: ({ props, parts }) => {
|
render: ({ props, parts }) => {
|
||||||
return <div class="custom-wrapper">{props.children}</div>
|
return <div class="custom-wrapper">{props.children}</div>
|
||||||
}
|
}
|
||||||
|
|
@ -596,7 +572,7 @@ describe('Styles component', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('Styles renders to HTML with CSS', () => {
|
test('Styles renders to HTML with CSS', () => {
|
||||||
define('StylesComp1', { layout: { width: 100 } })
|
define('StylesComp1', { width: 100 })
|
||||||
|
|
||||||
const html = renderToString(define.Styles())
|
const html = renderToString(define.Styles())
|
||||||
expect(html).toContain('<style>')
|
expect(html).toContain('<style>')
|
||||||
|
|
@ -606,8 +582,8 @@ describe('Styles component', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('Styles includes CSS for all registered components', () => {
|
test('Styles includes CSS for all registered components', () => {
|
||||||
define('StylesComp2', { layout: { width: 100 } })
|
define('StylesComp2', { width: 100 })
|
||||||
define('StylesComp3', { layout: { height: 200 } })
|
define('StylesComp3', { height: 200 })
|
||||||
|
|
||||||
const css = getStylesCSS()
|
const css = getStylesCSS()
|
||||||
expect(css).toContain('.StylesComp2')
|
expect(css).toContain('.StylesComp2')
|
||||||
|
|
@ -620,8 +596,8 @@ describe('Styles component', () => {
|
||||||
define('StylesVariant', {
|
define('StylesVariant', {
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
small: { layout: { padding: 8 } },
|
small: { padding: 8 },
|
||||||
large: { layout: { padding: 24 } }
|
large: { padding: 24 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -636,8 +612,8 @@ describe('Styles component', () => {
|
||||||
test('Styles includes part CSS', () => {
|
test('Styles includes part CSS', () => {
|
||||||
define('StylesPart', {
|
define('StylesPart', {
|
||||||
parts: {
|
parts: {
|
||||||
Header: { look: { color: 'red' } },
|
Header: { color: 'red' },
|
||||||
Body: { look: { color: 'blue' } }
|
Body: { color: 'blue' }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -649,6 +625,125 @@ describe('Styles component', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('variants on parts via props', () => {
|
||||||
|
test('applies boolean variant to part when passed as prop', () => {
|
||||||
|
const Component = define('PartVariantBool', {
|
||||||
|
parts: {
|
||||||
|
Tab: { base: 'button', color: 'gray' }
|
||||||
|
},
|
||||||
|
variants: {
|
||||||
|
active: {
|
||||||
|
parts: {
|
||||||
|
Tab: { color: 'blue' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render: ({ props, parts }) => {
|
||||||
|
return (
|
||||||
|
<parts.Root>
|
||||||
|
<parts.Tab active={true}>Active Tab</parts.Tab>
|
||||||
|
<parts.Tab active={false}>Inactive Tab</parts.Tab>
|
||||||
|
</parts.Root>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const html = renderToString(Component({}))
|
||||||
|
// Should have one tab with active class, one without
|
||||||
|
expect(html).toContain('PartVariantBool_Tab active')
|
||||||
|
// Count occurrences - should have 2 tabs total
|
||||||
|
const tabCount = (html.match(/PartVariantBool_Tab/g) || []).length
|
||||||
|
expect(tabCount).toBe(2)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('applies string variant to part when passed as prop', () => {
|
||||||
|
const Component = define('PartVariantString', {
|
||||||
|
parts: {
|
||||||
|
Pill: { base: 'button' }
|
||||||
|
},
|
||||||
|
variants: {
|
||||||
|
size: {
|
||||||
|
small: { parts: { Pill: { padding: 8 } } },
|
||||||
|
large: { parts: { Pill: { padding: 24 } } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render: ({ props, parts }) => {
|
||||||
|
return (
|
||||||
|
<parts.Root>
|
||||||
|
<parts.Pill size="small">Small</parts.Pill>
|
||||||
|
<parts.Pill size="large">Large</parts.Pill>
|
||||||
|
</parts.Root>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const html = renderToString(Component({}))
|
||||||
|
expect(html).toContain('PartVariantString_Pill size-small')
|
||||||
|
expect(html).toContain('PartVariantString_Pill size-large')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('does not pass variant props through to HTML', () => {
|
||||||
|
const Component = define('NoVariantLeakage', {
|
||||||
|
parts: {
|
||||||
|
Item: { base: 'div' }
|
||||||
|
},
|
||||||
|
variants: {
|
||||||
|
active: {
|
||||||
|
parts: { Item: { color: 'blue' } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render: ({ props, parts }) => {
|
||||||
|
return (
|
||||||
|
<parts.Root>
|
||||||
|
<parts.Item active={true}>Item</parts.Item>
|
||||||
|
</parts.Root>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const html = renderToString(Component({}))
|
||||||
|
// Should have the class, but not the attribute
|
||||||
|
expect(html).toContain('class="NoVariantLeakage_Item active"')
|
||||||
|
expect(html).not.toContain('active="true"')
|
||||||
|
expect(html).not.toContain('active="false"')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('combines root and part level variants', () => {
|
||||||
|
const Component = define('CombinedVariants', {
|
||||||
|
parts: {
|
||||||
|
NavItem: { base: 'a' }
|
||||||
|
},
|
||||||
|
variants: {
|
||||||
|
theme: {
|
||||||
|
dark: {
|
||||||
|
backgroundColor: 'black',
|
||||||
|
parts: { NavItem: { color: 'white' } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
active: {
|
||||||
|
parts: { NavItem: { fontWeight: 700 } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render: ({ props, parts }) => {
|
||||||
|
return (
|
||||||
|
<parts.Root>
|
||||||
|
<parts.NavItem active={true}>Active Link</parts.NavItem>
|
||||||
|
<parts.NavItem active={false}>Inactive Link</parts.NavItem>
|
||||||
|
</parts.Root>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const html = renderToString(Component({ theme: 'dark' }))
|
||||||
|
// Root should have theme variant
|
||||||
|
expect(html).toContain('CombinedVariants theme-dark')
|
||||||
|
// Active NavItem should have both theme and active classes
|
||||||
|
expect(html).toContain('CombinedVariants_NavItem theme-dark active')
|
||||||
|
// Inactive NavItem should have only theme class
|
||||||
|
expect(html).toMatch(/CombinedVariants_NavItem theme-dark"[^>]*>Inactive/)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('edge cases', () => {
|
describe('edge cases', () => {
|
||||||
test('handles empty definition', () => {
|
test('handles empty definition', () => {
|
||||||
const Component = define({})
|
const Component = define({})
|
||||||
|
|
@ -673,7 +768,7 @@ describe('edge cases', () => {
|
||||||
const Component = define({
|
const Component = define({
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
small: { layout: { padding: 8 } }
|
small: { padding: 8 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -683,8 +778,8 @@ describe('edge cases', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('does not duplicate styles when registered multiple times', () => {
|
test('does not duplicate styles when registered multiple times', () => {
|
||||||
define('NoDuplicate', { layout: { width: 100 } })
|
define('NoDuplicate', { width: 100 })
|
||||||
define('NoDuplicate', { layout: { width: 200 } })
|
define('NoDuplicate', { width: 200 })
|
||||||
|
|
||||||
const styles = parseCSS(getStylesCSS())
|
const styles = parseCSS(getStylesCSS())
|
||||||
// Should keep first value (??= operator)
|
// Should keep first value (??= operator)
|
||||||
|
|
@ -693,18 +788,18 @@ describe('edge cases', () => {
|
||||||
|
|
||||||
test('handles complex nested structures', () => {
|
test('handles complex nested structures', () => {
|
||||||
define('ComplexNested', {
|
define('ComplexNested', {
|
||||||
layout: { display: 'grid' },
|
display: 'grid',
|
||||||
parts: {
|
parts: {
|
||||||
Container: { layout: { padding: 16 } },
|
Container: { padding: 16 },
|
||||||
Item: { look: { fontSize: 14 } }
|
Item: { fontSize: 14 }
|
||||||
},
|
},
|
||||||
variants: {
|
variants: {
|
||||||
theme: {
|
theme: {
|
||||||
dark: {
|
dark: {
|
||||||
look: { backgroundColor: 'black' },
|
backgroundColor: 'black',
|
||||||
parts: {
|
parts: {
|
||||||
Container: { look: { backgroundColor: '#222' } },
|
Container: { backgroundColor: '#222' },
|
||||||
Item: { look: { color: 'white' } }
|
Item: { color: 'white' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
129
src/types.ts
129
src/types.ts
|
|
@ -1,37 +1,39 @@
|
||||||
export type TagDef = {
|
export type TagDef = {
|
||||||
className?: string
|
className?: string
|
||||||
base?: string
|
base?: string
|
||||||
layout?: Layout
|
|
||||||
look?: Look
|
|
||||||
states?: Record<string, TagDef>,
|
states?: Record<string, TagDef>,
|
||||||
parts?: Record<string, TagDef>
|
parts?: Record<string, TagDef>
|
||||||
variants?: Record<string, TagDef | Record<string, TagDef>>
|
variants?: Record<string, TagDef | Record<string, TagDef>>
|
||||||
render?: (obj: any) => any
|
render?: (obj: any) => any
|
||||||
}
|
|
||||||
|
|
||||||
type Layout = {
|
// layout-related
|
||||||
alignContent?: string
|
alignContent?: 'normal' | 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly' | 'stretch' | 'start' | 'end' | 'baseline' | string
|
||||||
alignItems?: string
|
alignItems?: 'normal' | 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline' | 'start' | 'end' | 'self-start' | 'self-end' | string
|
||||||
alignSelf?: string
|
alignSelf?: 'auto' | 'normal' | 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline' | 'start' | 'end' | 'self-start' | 'self-end' | string
|
||||||
|
aspectRatio?: number | string
|
||||||
bottom?: number | string
|
bottom?: number | string
|
||||||
display?: string
|
boxSizing?: 'content-box' | 'border-box'
|
||||||
|
columnGap?: number | string
|
||||||
|
contain?: 'none' | 'strict' | 'content' | 'size' | 'layout' | 'style' | 'paint' | string
|
||||||
|
display?: 'block' | 'inline' | 'inline-block' | 'flex' | 'inline-flex' | 'grid' | 'inline-grid' | 'flow-root' | 'none' | 'contents' | 'table' | 'table-row' | 'table-cell' | string
|
||||||
flex?: number | string
|
flex?: number | string
|
||||||
flexBasis?: number | string
|
flexBasis?: number | string
|
||||||
flexDirection?: string
|
flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse'
|
||||||
flexGrow?: number
|
flexGrow?: number
|
||||||
flexShrink?: number
|
flexShrink?: number
|
||||||
flexWrap?: string
|
flexWrap?: 'nowrap' | 'wrap' | 'wrap-reverse'
|
||||||
gap?: number | string
|
gap?: number | string
|
||||||
gridAutoFlow?: string
|
gridAutoFlow?: 'row' | 'column' | 'dense' | 'row dense' | 'column dense'
|
||||||
gridColumn?: string
|
gridColumn?: string
|
||||||
gridGap?: number | string
|
gridGap?: number | string
|
||||||
gridRow?: string
|
gridRow?: string
|
||||||
gridTemplateColumns?: string
|
gridTemplateColumns?: string
|
||||||
gridTemplateRows?: string
|
gridTemplateRows?: string
|
||||||
height?: number | string
|
height?: number | string
|
||||||
justifyContent?: string
|
inset?: number | string
|
||||||
justifyItems?: string
|
justifyContent?: 'normal' | 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly' | 'start' | 'end' | 'left' | 'right' | 'stretch' | string
|
||||||
justifySelf?: string
|
justifyItems?: 'normal' | 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline' | 'start' | 'end' | 'self-start' | 'self-end' | 'left' | 'right' | string
|
||||||
|
justifySelf?: 'auto' | 'normal' | 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline' | 'start' | 'end' | 'self-start' | 'self-end' | 'left' | 'right' | string
|
||||||
left?: number | string
|
left?: number | string
|
||||||
margin?: number | string
|
margin?: number | string
|
||||||
marginBottom?: number | string
|
marginBottom?: number | string
|
||||||
|
|
@ -43,70 +45,125 @@ type Layout = {
|
||||||
minHeight?: number | string
|
minHeight?: number | string
|
||||||
minWidth?: number | string
|
minWidth?: number | string
|
||||||
order?: number
|
order?: number
|
||||||
overflow?: string
|
overflow?: 'visible' | 'hidden' | 'scroll' | 'auto' | 'clip'
|
||||||
overflowX?: string
|
overflowX?: 'visible' | 'hidden' | 'scroll' | 'auto' | 'clip'
|
||||||
overflowY?: string
|
overflowY?: 'visible' | 'hidden' | 'scroll' | 'auto' | 'clip'
|
||||||
padding?: number | string
|
padding?: number | string
|
||||||
paddingBottom?: number | string
|
paddingBottom?: number | string
|
||||||
paddingLeft?: number | string
|
paddingLeft?: number | string
|
||||||
paddingRight?: number | string
|
paddingRight?: number | string
|
||||||
paddingTop?: number | string
|
paddingTop?: number | string
|
||||||
position?: string
|
placeContent?: string
|
||||||
|
placeItems?: string
|
||||||
|
placeSelf?: string
|
||||||
|
position?: 'static' | 'relative' | 'absolute' | 'fixed' | 'sticky'
|
||||||
right?: number | string
|
right?: number | string
|
||||||
|
rowGap?: number | string
|
||||||
top?: number | string
|
top?: number | string
|
||||||
|
verticalAlign?: 'baseline' | 'top' | 'middle' | 'bottom' | 'text-top' | 'text-bottom' | 'sub' | 'super' | string
|
||||||
width?: number | string
|
width?: number | string
|
||||||
zIndex?: number
|
zIndex?: number
|
||||||
}
|
|
||||||
|
|
||||||
type Look = {
|
// visual/theme-related
|
||||||
animation?: string
|
animation?: string
|
||||||
|
appearance?: 'none' | 'auto' | 'button' | 'textfield' | 'searchfield' | 'textarea' | 'checkbox' | 'radio' | string
|
||||||
backdropFilter?: string
|
backdropFilter?: string
|
||||||
background?: string
|
background?: string
|
||||||
|
backgroundAttachment?: 'scroll' | 'fixed' | 'local'
|
||||||
|
backgroundClip?: 'border-box' | 'padding-box' | 'content-box' | 'text'
|
||||||
backgroundColor?: string
|
backgroundColor?: string
|
||||||
|
backgroundImage?: string
|
||||||
|
backgroundPosition?: string
|
||||||
|
backgroundRepeat?: 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat' | 'space' | 'round'
|
||||||
|
backgroundSize?: 'auto' | 'cover' | 'contain' | string
|
||||||
border?: string
|
border?: string
|
||||||
borderBottom?: string
|
borderBottom?: string
|
||||||
|
borderBottomColor?: string
|
||||||
|
borderBottomLeftRadius?: number | string
|
||||||
|
borderBottomRightRadius?: number | string
|
||||||
|
borderBottomStyle?: 'none' | 'solid' | 'dashed' | 'dotted' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset' | 'hidden'
|
||||||
|
borderBottomWidth?: number | string
|
||||||
borderColor?: string
|
borderColor?: string
|
||||||
borderLeft?: string
|
borderLeft?: string
|
||||||
|
borderLeftColor?: string
|
||||||
|
borderLeftStyle?: 'none' | 'solid' | 'dashed' | 'dotted' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset' | 'hidden'
|
||||||
|
borderLeftWidth?: number | string
|
||||||
borderRadius?: number | string
|
borderRadius?: number | string
|
||||||
borderRight?: string
|
borderRight?: string
|
||||||
borderStyle?: string
|
borderRightColor?: string
|
||||||
|
borderRightStyle?: 'none' | 'solid' | 'dashed' | 'dotted' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset' | 'hidden'
|
||||||
|
borderRightWidth?: number | string
|
||||||
|
borderStyle?: 'none' | 'solid' | 'dashed' | 'dotted' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset' | 'hidden'
|
||||||
borderTop?: string
|
borderTop?: string
|
||||||
|
borderTopColor?: string
|
||||||
|
borderTopLeftRadius?: number | string
|
||||||
|
borderTopRightRadius?: number | string
|
||||||
|
borderTopStyle?: 'none' | 'solid' | 'dashed' | 'dotted' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset' | 'hidden'
|
||||||
|
borderTopWidth?: number | string
|
||||||
borderWidth?: number | string
|
borderWidth?: number | string
|
||||||
boxShadow?: string
|
boxShadow?: string
|
||||||
|
clipPath?: string
|
||||||
color?: string
|
color?: string
|
||||||
cursor?: string
|
content?: string
|
||||||
|
cursor?: 'auto' | 'default' | 'none' | 'context-menu' | 'help' | 'pointer' | 'progress' | 'wait' | 'cell' | 'crosshair' | 'text' | 'vertical-text' | 'alias' | 'copy' | 'move' | 'no-drop' | 'not-allowed' | 'grab' | 'grabbing' | 'e-resize' | 'n-resize' | 'ne-resize' | 'nw-resize' | 's-resize' | 'se-resize' | 'sw-resize' | 'w-resize' | 'ew-resize' | 'ns-resize' | 'nesw-resize' | 'nwse-resize' | 'col-resize' | 'row-resize' | 'all-scroll' | 'zoom-in' | 'zoom-out' | string
|
||||||
filter?: string
|
filter?: string
|
||||||
fontFamily?: string
|
fontFamily?: string
|
||||||
fontSize?: number | string
|
fontSize?: number | string
|
||||||
fontStyle?: string
|
fontStyle?: 'normal' | 'italic' | 'oblique'
|
||||||
fontWeight?: number | string
|
fontWeight?: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 'normal' | 'bold' | 'bolder' | 'lighter' | number
|
||||||
|
isolation?: 'auto' | 'isolate'
|
||||||
letterSpacing?: number | string
|
letterSpacing?: number | string
|
||||||
lineHeight?: number | string
|
lineHeight?: number | string
|
||||||
mixBlendMode?: string
|
listStyle?: string
|
||||||
objectFit?: string
|
listStyleImage?: string
|
||||||
|
listStylePosition?: 'inside' | 'outside'
|
||||||
|
listStyleType?: 'none' | 'disc' | 'circle' | 'square' | 'decimal' | 'decimal-leading-zero' | 'lower-roman' | 'upper-roman' | 'lower-alpha' | 'upper-alpha' | 'lower-greek' | 'lower-latin' | 'upper-latin' | string
|
||||||
|
mixBlendMode?: 'normal' | 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'color-dodge' | 'color-burn' | 'hard-light' | 'soft-light' | 'difference' | 'exclusion' | 'hue' | 'saturation' | 'color' | 'luminosity'
|
||||||
|
objectFit?: 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'
|
||||||
opacity?: number
|
opacity?: number
|
||||||
outline?: string
|
outline?: string
|
||||||
outlineColor?: string
|
outlineColor?: string
|
||||||
outlineOffset?: number | string
|
outlineOffset?: number | string
|
||||||
outlineStyle?: string
|
outlineStyle?: 'none' | 'solid' | 'dashed' | 'dotted' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset'
|
||||||
outlineWidth?: number | string
|
outlineWidth?: number | string
|
||||||
pointerEvents?: string
|
pointerEvents?: 'auto' | 'none' | 'visiblePainted' | 'visibleFill' | 'visibleStroke' | 'visible' | 'painted' | 'fill' | 'stroke' | 'all'
|
||||||
textAlign?: string
|
resize?: 'none' | 'both' | 'horizontal' | 'vertical' | 'block' | 'inline'
|
||||||
|
scrollBehavior?: 'auto' | 'smooth'
|
||||||
|
textAlign?: 'left' | 'right' | 'center' | 'justify' | 'start' | 'end'
|
||||||
textDecoration?: string
|
textDecoration?: string
|
||||||
textOverflow?: string
|
textDecorationColor?: string
|
||||||
|
textDecorationLine?: 'none' | 'underline' | 'overline' | 'line-through' | 'blink' | string
|
||||||
|
textDecorationStyle?: 'solid' | 'double' | 'dotted' | 'dashed' | 'wavy'
|
||||||
|
textDecorationThickness?: number | string
|
||||||
|
textIndent?: number | string
|
||||||
|
textOverflow?: 'clip' | 'ellipsis' | string
|
||||||
textShadow?: string
|
textShadow?: string
|
||||||
textTransform?: string
|
textTransform?: 'none' | 'capitalize' | 'uppercase' | 'lowercase' | 'full-width' | 'full-size-kana'
|
||||||
transform?: string
|
transform?: string
|
||||||
transition?: string
|
transition?: string
|
||||||
userSelect?: string
|
userSelect?: 'auto' | 'none' | 'text' | 'contain' | 'all'
|
||||||
visibility?: string
|
visibility?: 'visible' | 'hidden' | 'collapse'
|
||||||
whiteSpace?: string
|
whiteSpace?: 'normal' | 'nowrap' | 'pre' | 'pre-wrap' | 'pre-line' | 'break-spaces'
|
||||||
wordWrap?: string
|
willChange?: 'auto' | 'scroll-position' | 'contents' | string
|
||||||
overflowWrap?: string
|
wordBreak?: 'normal' | 'break-all' | 'keep-all' | 'break-word'
|
||||||
|
wordSpacing?: number | string
|
||||||
|
wordWrap?: 'normal' | 'break-word' | 'anywhere'
|
||||||
|
overflowWrap?: 'normal' | 'break-word' | 'anywhere'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const NonStyleKeys = new Set([
|
||||||
|
'className',
|
||||||
|
'base',
|
||||||
|
'states',
|
||||||
|
'parts',
|
||||||
|
'variants',
|
||||||
|
'render',
|
||||||
|
'styles',
|
||||||
|
])
|
||||||
|
|
||||||
export const UnitlessProps = new Set([
|
export const UnitlessProps = new Set([
|
||||||
'animationIterationCount',
|
'animationIterationCount',
|
||||||
|
'aspectRatio',
|
||||||
'columnCount',
|
'columnCount',
|
||||||
'flex',
|
'flex',
|
||||||
'flexGrow',
|
'flexGrow',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user