Skip to content

Commit 3f8c4b7

Browse files
authored
refactor: padding and margin styles (#774)
1 parent 43e31a6 commit 3f8c4b7

File tree

10 files changed

+867
-239
lines changed

10 files changed

+867
-239
lines changed

.changeset/afraid-eels-drive.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@cube-dev/ui-kit": patch
3+
---
4+
5+
Improve style state application for padding and margin styles making it predictable.

src/tasty/styles/margin.test.ts

Lines changed: 345 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,345 @@
1+
import { marginStyle } from './margin';
2+
3+
describe('marginStyle', () => {
4+
describe('basic functionality', () => {
5+
it('returns empty object when no margin properties are provided', () => {
6+
expect(marginStyle({})).toEqual({});
7+
});
8+
9+
it('handles boolean true value', () => {
10+
const result = marginStyle({ margin: true });
11+
expect(result).toEqual({
12+
'margin-top': 'var(--gap)',
13+
'margin-right': 'var(--gap)',
14+
'margin-bottom': 'var(--gap)',
15+
'margin-left': 'var(--gap)',
16+
});
17+
});
18+
19+
it('handles number value', () => {
20+
const result = marginStyle({ margin: 16 });
21+
expect(result).toEqual({
22+
'margin-top': '16px',
23+
'margin-right': '16px',
24+
'margin-bottom': '16px',
25+
'margin-left': '16px',
26+
});
27+
});
28+
29+
it('handles single string value', () => {
30+
const result = marginStyle({ margin: '2x' });
31+
expect(result).toEqual({
32+
'margin-top': 'calc(2 * var(--gap))',
33+
'margin-right': 'calc(2 * var(--gap))',
34+
'margin-bottom': 'calc(2 * var(--gap))',
35+
'margin-left': 'calc(2 * var(--gap))',
36+
});
37+
});
38+
39+
it('handles two-value string (vertical horizontal)', () => {
40+
const result = marginStyle({ margin: '2x 3x' });
41+
expect(result).toEqual({
42+
'margin-top': 'calc(2 * var(--gap))',
43+
'margin-right': 'calc(3 * var(--gap))',
44+
'margin-bottom': 'calc(2 * var(--gap))',
45+
'margin-left': 'calc(3 * var(--gap))',
46+
});
47+
});
48+
49+
it('handles four-value string (top right bottom left)', () => {
50+
const result = marginStyle({ margin: '1x 2x 3x 4x' });
51+
expect(result).toEqual({
52+
'margin-top': 'var(--gap)',
53+
'margin-right': 'calc(2 * var(--gap))',
54+
'margin-bottom': 'calc(3 * var(--gap))',
55+
'margin-left': 'calc(4 * var(--gap))',
56+
});
57+
});
58+
});
59+
60+
describe('directional margin', () => {
61+
it('handles directional margin - top only', () => {
62+
const result = marginStyle({ margin: '2x top' });
63+
expect(result).toEqual({
64+
'margin-top': 'calc(2 * var(--gap))',
65+
});
66+
});
67+
68+
it('handles directional margin - left and right', () => {
69+
const result = marginStyle({ margin: '3x left right' });
70+
expect(result).toEqual({
71+
'margin-left': 'calc(3 * var(--gap))',
72+
'margin-right': 'calc(3 * var(--gap))',
73+
});
74+
});
75+
76+
it('handles directional margin - bottom only', () => {
77+
const result = marginStyle({ margin: '1x bottom' });
78+
expect(result).toEqual({
79+
'margin-bottom': 'var(--gap)',
80+
});
81+
});
82+
});
83+
84+
describe('marginBlock and marginInline', () => {
85+
it('handles marginBlock (top and bottom)', () => {
86+
const result = marginStyle({ marginBlock: '2x' });
87+
expect(result).toEqual({
88+
'margin-top': 'calc(2 * var(--gap))',
89+
'margin-bottom': 'calc(2 * var(--gap))',
90+
});
91+
});
92+
93+
it('handles marginBlock with two values', () => {
94+
const result = marginStyle({ marginBlock: '1x 3x' });
95+
expect(result).toEqual({
96+
'margin-top': 'var(--gap)',
97+
'margin-bottom': 'calc(3 * var(--gap))',
98+
});
99+
});
100+
101+
it('handles marginInline (left and right)', () => {
102+
const result = marginStyle({ marginInline: '4x' });
103+
expect(result).toEqual({
104+
'margin-left': 'calc(4 * var(--gap))',
105+
'margin-right': 'calc(4 * var(--gap))',
106+
});
107+
});
108+
109+
it('handles marginInline with two values', () => {
110+
const result = marginStyle({ marginInline: '2x 5x' });
111+
expect(result).toEqual({
112+
'margin-left': 'calc(2 * var(--gap))',
113+
'margin-right': 'calc(5 * var(--gap))',
114+
});
115+
});
116+
117+
it('handles boolean and number values for logical properties', () => {
118+
const result = marginStyle({
119+
marginBlock: true,
120+
marginInline: 8,
121+
});
122+
expect(result).toEqual({
123+
'margin-top': 'var(--gap)',
124+
'margin-bottom': 'var(--gap)',
125+
'margin-left': '8px',
126+
'margin-right': '8px',
127+
});
128+
});
129+
});
130+
131+
describe('individual direction properties', () => {
132+
it('handles individual direction properties', () => {
133+
const result = marginStyle({
134+
marginTop: '1x',
135+
marginRight: '2x',
136+
marginBottom: '3x',
137+
marginLeft: '4x',
138+
});
139+
expect(result).toEqual({
140+
'margin-top': 'var(--gap)',
141+
'margin-right': 'calc(2 * var(--gap))',
142+
'margin-bottom': 'calc(3 * var(--gap))',
143+
'margin-left': 'calc(4 * var(--gap))',
144+
});
145+
});
146+
147+
it('handles boolean and number values for individual directions', () => {
148+
const result = marginStyle({
149+
marginTop: true,
150+
marginRight: 12,
151+
marginBottom: '2x',
152+
marginLeft: false,
153+
});
154+
expect(result).toEqual({
155+
'margin-top': 'var(--gap)',
156+
'margin-right': '12px',
157+
'margin-bottom': 'calc(2 * var(--gap))',
158+
});
159+
});
160+
});
161+
162+
describe('priority system', () => {
163+
it('margin (low) < marginBlock/marginInline (medium)', () => {
164+
const result = marginStyle({
165+
margin: '1x',
166+
marginBlock: '2x',
167+
marginInline: '3x',
168+
});
169+
expect(result).toEqual({
170+
'margin-top': 'calc(2 * var(--gap))', // overridden by marginBlock
171+
'margin-right': 'calc(3 * var(--gap))', // overridden by marginInline
172+
'margin-bottom': 'calc(2 * var(--gap))', // overridden by marginBlock
173+
'margin-left': 'calc(3 * var(--gap))', // overridden by marginInline
174+
});
175+
});
176+
177+
it('marginBlock/marginInline (medium) < individual directions (high)', () => {
178+
const result = marginStyle({
179+
marginBlock: '2x',
180+
marginInline: '3x',
181+
marginTop: '4x',
182+
marginRight: '5x',
183+
});
184+
expect(result).toEqual({
185+
'margin-top': 'calc(4 * var(--gap))', // overridden by marginTop
186+
'margin-right': 'calc(5 * var(--gap))', // overridden by marginRight
187+
'margin-bottom': 'calc(2 * var(--gap))', // from marginBlock
188+
'margin-left': 'calc(3 * var(--gap))', // from marginInline
189+
});
190+
});
191+
192+
it('complete priority chain: margin < marginBlock/Inline < individual', () => {
193+
const result = marginStyle({
194+
margin: '1x',
195+
marginBlock: '2x',
196+
marginInline: '3x',
197+
marginTop: '4x',
198+
marginRight: '5x',
199+
});
200+
expect(result).toEqual({
201+
'margin-top': 'calc(4 * var(--gap))', // highest: individual direction
202+
'margin-right': 'calc(5 * var(--gap))', // highest: individual direction
203+
'margin-bottom': 'calc(2 * var(--gap))', // medium: marginBlock
204+
'margin-left': 'calc(3 * var(--gap))', // medium: marginInline
205+
});
206+
});
207+
208+
it('example: margin="1x" marginRight="2x"', () => {
209+
const result = marginStyle({
210+
margin: '1x',
211+
marginRight: '2x',
212+
});
213+
expect(result).toEqual({
214+
'margin-top': 'var(--gap)',
215+
'margin-right': 'calc(2 * var(--gap))', // overridden by marginRight
216+
'margin-bottom': 'var(--gap)',
217+
'margin-left': 'var(--gap)',
218+
});
219+
});
220+
221+
it('example: margin="1x" marginBlock="2x"', () => {
222+
const result = marginStyle({
223+
margin: '1x',
224+
marginBlock: '2x',
225+
});
226+
expect(result).toEqual({
227+
'margin-top': 'calc(2 * var(--gap))', // overridden by marginBlock
228+
'margin-right': 'var(--gap)',
229+
'margin-bottom': 'calc(2 * var(--gap))', // overridden by marginBlock
230+
'margin-left': 'var(--gap)',
231+
});
232+
});
233+
});
234+
235+
describe('edge cases', () => {
236+
it('handles null and undefined values', () => {
237+
const result = marginStyle({
238+
margin: undefined,
239+
marginBlock: undefined,
240+
marginTop: undefined,
241+
});
242+
expect(result).toEqual({});
243+
});
244+
245+
it('handles empty string values', () => {
246+
const result = marginStyle({
247+
margin: '',
248+
marginBlock: '',
249+
marginTop: '2x',
250+
});
251+
expect(result).toEqual({
252+
'margin-top': 'calc(2 * var(--gap))',
253+
});
254+
});
255+
256+
it('handles zero values', () => {
257+
const result = marginStyle({
258+
margin: 0,
259+
marginTop: '1x',
260+
});
261+
expect(result).toEqual({
262+
'margin-top': 'var(--gap)', // overridden by marginTop
263+
'margin-right': '0px',
264+
'margin-bottom': '0px',
265+
'margin-left': '0px',
266+
});
267+
});
268+
269+
it('handles mixed types', () => {
270+
const result = marginStyle({
271+
margin: true,
272+
marginBlock: 16,
273+
marginLeft: '3x',
274+
});
275+
expect(result).toEqual({
276+
'margin-top': '16px', // overridden by marginBlock
277+
'margin-right': 'var(--gap)', // from margin
278+
'margin-bottom': '16px', // overridden by marginBlock
279+
'margin-left': 'calc(3 * var(--gap))', // overridden by marginLeft
280+
});
281+
});
282+
283+
it('handles negative values', () => {
284+
const result = marginStyle({
285+
margin: '-1x',
286+
marginTop: -8,
287+
});
288+
expect(result).toEqual({
289+
'margin-top': '-8px', // overridden by marginTop
290+
'margin-right': 'calc(-1 * var(--gap))',
291+
'margin-bottom': 'calc(-1 * var(--gap))',
292+
'margin-left': 'calc(-1 * var(--gap))',
293+
});
294+
});
295+
});
296+
297+
describe('directional margin with priority', () => {
298+
it('respects individual directions over directional margin', () => {
299+
const result = marginStyle({
300+
margin: '2x top bottom',
301+
marginTop: '5x',
302+
});
303+
expect(result).toEqual({
304+
'margin-top': 'calc(5 * var(--gap))', // overridden by marginTop
305+
'margin-bottom': 'calc(2 * var(--gap))', // from directional margin
306+
});
307+
});
308+
309+
it('combines directional margin with logical properties', () => {
310+
const result = marginStyle({
311+
margin: '1x top',
312+
marginInline: '3x',
313+
});
314+
expect(result).toEqual({
315+
'margin-top': 'var(--gap)', // from directional margin
316+
'margin-left': 'calc(3 * var(--gap))', // from marginInline
317+
'margin-right': 'calc(3 * var(--gap))', // from marginInline
318+
});
319+
});
320+
});
321+
322+
describe('auto values', () => {
323+
it('handles auto values for centering', () => {
324+
const result = marginStyle({
325+
marginInline: 'auto',
326+
});
327+
expect(result).toEqual({
328+
'margin-left': 'auto',
329+
'margin-right': 'auto',
330+
});
331+
});
332+
333+
it('handles mixed auto and specific values', () => {
334+
const result = marginStyle({
335+
margin: '1x auto',
336+
});
337+
expect(result).toEqual({
338+
'margin-top': 'var(--gap)',
339+
'margin-right': 'auto',
340+
'margin-bottom': 'var(--gap)',
341+
'margin-left': 'auto',
342+
});
343+
});
344+
});
345+
});

0 commit comments

Comments
 (0)