Skip to content

Commit fe2b0b8

Browse files
feat(ui): reorganize primitive components into a new components/primitives directory and add new primitives like Grid, Section, Container, and Slot.
1 parent 571984b commit fe2b0b8

20 files changed

Lines changed: 1282 additions & 67 deletions

File tree

bun.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
"@iconify/react": "^6.0.2",
6868
"@tanstack/react-query": "^5.90.2",
6969
"@uidotdev/usehooks": "^2.4.1",
70+
"@vanilla-extract/vite-plugin": "^5.1.4",
7071
"clsx": "^2.1.1",
7172
"dayjs": "^1.11.19",
7273
"dotenv": "^17.2.3",

packages/lifeforge-ui/src/components/layout/Card.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import clsx from 'clsx'
22
import React from 'react'
33

4-
import { Slot } from '../../primitives/Slot'
4+
import { Slot } from '../primitives/Slot'
55

66
export interface CardBaseProps {
77
children: React.ReactNode

packages/lifeforge-ui/src/primitives/box.css.ts renamed to packages/lifeforge-ui/src/components/primitives/Box/box.css.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { recipe } from '@vanilla-extract/recipes'
22
import { createSprinkles, defineProperties } from '@vanilla-extract/sprinkles'
33

4-
import { defaultCondition, responsiveConditions, vars } from '../system'
4+
import { defaultCondition, responsiveConditions, vars } from '../../../system'
5+
// Import to ensure responsive layout CSS is generated
6+
import '../styles/responsive.css'
57

68
export const boxBase = recipe({
79
base: {

packages/lifeforge-ui/src/primitives/Box.tsx renamed to packages/lifeforge-ui/src/components/primitives/Box/index.tsx

Lines changed: 81 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import { clsx } from 'clsx'
22
import {
3+
type CSSProperties,
34
type ComponentPropsWithRef,
45
type ElementType,
56
type ReactNode,
67
type Ref
78
} from 'react'
89

9-
import { type ResponsiveProp, normalizeResponsiveProp } from '../system'
10-
import { Slot } from './Slot'
10+
import { type ResponsiveProp, normalizeResponsiveProp } from '../../../system'
11+
import { Slot } from '../Slot'
12+
import { getResponsiveLayoutStyles } from '../propDefs'
13+
import { type LayoutProps, type MarginProps } from '../types'
1114
import { type BoxSprinkles, boxBase, boxSprinkles } from './box.css'
1215

13-
type SpaceValue = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'
14-
1516
type BgColor =
1617
| 'transparent'
1718
| 'bg-50'
@@ -40,36 +41,18 @@ type RadiusValue = 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'
4041

4142
type DisplayValue = 'block' | 'inline' | 'inline-block' | 'none' | 'contents'
4243

43-
type PositionValue = 'static' | 'relative' | 'absolute' | 'fixed' | 'sticky'
44-
45-
type OverflowValue = 'visible' | 'hidden' | 'scroll' | 'auto'
46-
4744
const DEFAULT_ELEMENT = 'div' as const
4845

49-
interface BoxOwnProps<T extends ElementType = typeof DEFAULT_ELEMENT> {
46+
interface BoxOwnProps<T extends ElementType = typeof DEFAULT_ELEMENT>
47+
extends LayoutProps, MarginProps {
5048
as?: T
5149
asChild?: boolean
5250
ref?: Ref<HTMLElement>
53-
p?: ResponsiveProp<SpaceValue>
54-
px?: ResponsiveProp<SpaceValue>
55-
py?: ResponsiveProp<SpaceValue>
56-
pt?: ResponsiveProp<SpaceValue>
57-
pb?: ResponsiveProp<SpaceValue>
58-
pl?: ResponsiveProp<SpaceValue>
59-
pr?: ResponsiveProp<SpaceValue>
60-
m?: ResponsiveProp<SpaceValue>
61-
mx?: ResponsiveProp<SpaceValue>
62-
my?: ResponsiveProp<SpaceValue>
63-
mt?: ResponsiveProp<SpaceValue>
64-
mb?: ResponsiveProp<SpaceValue>
65-
ml?: ResponsiveProp<SpaceValue>
66-
mr?: ResponsiveProp<SpaceValue>
51+
display?: ResponsiveProp<DisplayValue>
6752
bg?: ResponsiveProp<BgColor>
6853
rounded?: ResponsiveProp<RadiusValue>
69-
display?: ResponsiveProp<DisplayValue>
70-
position?: ResponsiveProp<PositionValue>
71-
overflow?: ResponsiveProp<OverflowValue>
7254
className?: string
55+
style?: CSSProperties
7356
children?: ReactNode
7457
}
7558

@@ -80,33 +63,65 @@ export function Box<T extends ElementType = typeof DEFAULT_ELEMENT>({
8063
as,
8164
asChild = false,
8265
ref,
66+
// Padding
8367
p,
8468
px,
8569
py,
8670
pt,
8771
pb,
8872
pl,
8973
pr,
74+
// Margin
9075
m,
9176
mx,
9277
my,
9378
mt,
9479
mb,
9580
ml,
9681
mr,
97-
bg,
98-
rounded,
82+
// Layout props (CSS string - now responsive!)
83+
width,
84+
minWidth,
85+
maxWidth,
86+
height,
87+
minHeight,
88+
maxHeight,
89+
inset,
90+
top,
91+
right,
92+
bottom,
93+
left,
94+
flexBasis,
95+
flexGrow,
96+
flexShrink,
97+
gridArea,
98+
gridColumn,
99+
gridColumnStart,
100+
gridColumnEnd,
101+
gridRow,
102+
gridRowStart,
103+
gridRowEnd,
104+
// Sprinkle props
99105
display,
100106
position,
101107
overflow,
108+
overflowX,
109+
overflowY,
110+
bg,
111+
rounded,
112+
// Standard props
102113
className,
114+
style,
103115
children,
104116
...rest
105117
}: BoxProps<T>) {
118+
// Build sprinkles className for tokenized props
106119
const sprinklesClassName = boxSprinkles({
107120
display: normalizeResponsiveProp(display) as BoxSprinkles['display'],
108121
position: normalizeResponsiveProp(position) as BoxSprinkles['position'],
109-
overflow: normalizeResponsiveProp(overflow) as BoxSprinkles['overflow'],
122+
overflow: normalizeResponsiveProp(
123+
overflow ?? overflowX ?? overflowY
124+
) as BoxSprinkles['overflow'],
110125
padding: normalizeResponsiveProp(p) as BoxSprinkles['padding'],
111126
paddingTop: normalizeResponsiveProp(pt ?? py) as BoxSprinkles['paddingTop'],
112127
paddingBottom: normalizeResponsiveProp(
@@ -135,12 +150,48 @@ export function Box<T extends ElementType = typeof DEFAULT_ELEMENT>({
135150
) as BoxSprinkles['borderRadius']
136151
})
137152

153+
// Build responsive styles for CSS string props (now with breakpoint support!)
154+
const responsiveStyles = getResponsiveLayoutStyles({
155+
width,
156+
minWidth,
157+
maxWidth,
158+
height,
159+
minHeight,
160+
maxHeight,
161+
inset,
162+
top,
163+
right,
164+
bottom,
165+
left,
166+
flexBasis,
167+
flexGrow,
168+
flexShrink,
169+
gridArea,
170+
gridColumn,
171+
gridColumnStart,
172+
gridColumnEnd,
173+
gridRow,
174+
gridRowStart,
175+
gridRowEnd
176+
})
177+
178+
const mergedStyle =
179+
Object.keys(responsiveStyles.style).length > 0
180+
? { ...responsiveStyles.style, ...style }
181+
: style
182+
138183
const Component = asChild ? Slot : (as ?? DEFAULT_ELEMENT)
139184

140185
return (
141186
<Component
142187
ref={ref as Ref<never>}
143-
className={clsx(boxBase(), sprinklesClassName, className)}
188+
className={clsx(
189+
boxBase(),
190+
sprinklesClassName,
191+
responsiveStyles.className,
192+
className
193+
)}
194+
style={mergedStyle}
144195
{...rest}
145196
>
146197
{children}

0 commit comments

Comments
 (0)