@constela/ui 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +160 -0
- package/components/alert/alert.constela.json +22 -0
- package/components/alert/alert.styles.json +14 -0
- package/components/alert/alert.test.ts +173 -0
- package/components/avatar/avatar.constela.json +32 -0
- package/components/avatar/avatar.styles.json +15 -0
- package/components/avatar/avatar.test.ts +197 -0
- package/components/badge/badge.constela.json +19 -0
- package/components/badge/badge.styles.json +16 -0
- package/components/badge/badge.test.ts +135 -0
- package/components/breadcrumb/breadcrumb.constela.json +17 -0
- package/components/breadcrumb/breadcrumb.styles.json +5 -0
- package/components/breadcrumb/breadcrumb.test.ts +149 -0
- package/components/button/README.md +164 -0
- package/components/button/button.constela.json +27 -0
- package/components/button/button.styles.json +25 -0
- package/components/button/button.test.ts +233 -0
- package/components/card/card.constela.json +21 -0
- package/components/card/card.styles.json +14 -0
- package/components/card/card.test.ts +154 -0
- package/components/checkbox/checkbox.constela.json +33 -0
- package/components/checkbox/checkbox.styles.json +15 -0
- package/components/checkbox/checkbox.test.ts +275 -0
- package/components/container/container.constela.json +21 -0
- package/components/container/container.styles.json +18 -0
- package/components/container/container.test.ts +164 -0
- package/components/dialog/dialog.constela.json +19 -0
- package/components/dialog/dialog.styles.json +5 -0
- package/components/dialog/dialog.test.ts +139 -0
- package/components/grid/grid.constela.json +23 -0
- package/components/grid/grid.styles.json +25 -0
- package/components/grid/grid.test.ts +193 -0
- package/components/input/input.constela.json +34 -0
- package/components/input/input.styles.json +19 -0
- package/components/input/input.test.ts +301 -0
- package/components/pagination/pagination.constela.json +22 -0
- package/components/pagination/pagination.styles.json +15 -0
- package/components/pagination/pagination.test.ts +170 -0
- package/components/popover/popover.constela.json +20 -0
- package/components/popover/popover.styles.json +16 -0
- package/components/popover/popover.test.ts +165 -0
- package/components/radio/radio.constela.json +31 -0
- package/components/radio/radio.styles.json +15 -0
- package/components/radio/radio.test.ts +253 -0
- package/components/select/select.constela.json +32 -0
- package/components/select/select.styles.json +15 -0
- package/components/select/select.test.ts +257 -0
- package/components/skeleton/skeleton.constela.json +24 -0
- package/components/skeleton/skeleton.styles.json +5 -0
- package/components/skeleton/skeleton.test.ts +164 -0
- package/components/stack/stack.constela.json +27 -0
- package/components/stack/stack.styles.json +33 -0
- package/components/stack/stack.test.ts +261 -0
- package/components/switch/switch.constela.json +29 -0
- package/components/switch/switch.styles.json +15 -0
- package/components/switch/switch.test.ts +224 -0
- package/components/tabs/tabs.constela.json +21 -0
- package/components/tabs/tabs.styles.json +14 -0
- package/components/tabs/tabs.test.ts +163 -0
- package/components/textarea/textarea.constela.json +34 -0
- package/components/textarea/textarea.styles.json +15 -0
- package/components/textarea/textarea.test.ts +290 -0
- package/components/toast/toast.constela.json +23 -0
- package/components/toast/toast.styles.json +17 -0
- package/components/toast/toast.test.ts +183 -0
- package/components/tooltip/tooltip.constela.json +21 -0
- package/components/tooltip/tooltip.styles.json +16 -0
- package/components/tooltip/tooltip.test.ts +164 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +83 -0
- package/package.json +39 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"params": {
|
|
3
|
+
"value": { "type": "string", "required": false },
|
|
4
|
+
"disabled": { "type": "boolean", "required": false },
|
|
5
|
+
"required": { "type": "boolean", "required": false },
|
|
6
|
+
"placeholder": { "type": "string", "required": false },
|
|
7
|
+
"name": { "type": "string", "required": false },
|
|
8
|
+
"id": { "type": "string", "required": false },
|
|
9
|
+
"ariaLabel": { "type": "string", "required": false },
|
|
10
|
+
"size": { "type": "string", "required": false }
|
|
11
|
+
},
|
|
12
|
+
"view": {
|
|
13
|
+
"kind": "element",
|
|
14
|
+
"tag": "select",
|
|
15
|
+
"props": {
|
|
16
|
+
"className": {
|
|
17
|
+
"expr": "style",
|
|
18
|
+
"preset": "selectStyles",
|
|
19
|
+
"props": {
|
|
20
|
+
"size": { "expr": "param", "name": "size" }
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"value": { "expr": "param", "name": "value" },
|
|
24
|
+
"disabled": { "expr": "param", "name": "disabled" },
|
|
25
|
+
"required": { "expr": "param", "name": "required" },
|
|
26
|
+
"name": { "expr": "param", "name": "name" },
|
|
27
|
+
"id": { "expr": "param", "name": "id" },
|
|
28
|
+
"aria-label": { "expr": "param", "name": "ariaLabel" }
|
|
29
|
+
},
|
|
30
|
+
"children": [{ "kind": "slot" }]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"selectStyles": {
|
|
3
|
+
"base": "flex w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
4
|
+
"variants": {
|
|
5
|
+
"size": {
|
|
6
|
+
"default": "h-10",
|
|
7
|
+
"sm": "h-9 text-xs",
|
|
8
|
+
"lg": "h-11 text-base"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"defaultVariants": {
|
|
12
|
+
"size": "default"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test suite for Select component
|
|
3
|
+
*
|
|
4
|
+
* @constela/ui Select component tests following TDD methodology.
|
|
5
|
+
* These tests verify the Select component structure, params, styles, and accessibility.
|
|
6
|
+
*
|
|
7
|
+
* Coverage:
|
|
8
|
+
* - Component structure validation
|
|
9
|
+
* - Params definition validation
|
|
10
|
+
* - Style preset validation
|
|
11
|
+
* - Accessibility attributes
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { describe, it, expect, beforeAll } from 'vitest';
|
|
15
|
+
import {
|
|
16
|
+
loadComponentForTesting,
|
|
17
|
+
assertValidComponent,
|
|
18
|
+
assertValidStylePreset,
|
|
19
|
+
hasParams,
|
|
20
|
+
isOptionalParam,
|
|
21
|
+
hasParamType,
|
|
22
|
+
getRootTag,
|
|
23
|
+
hasVariants,
|
|
24
|
+
hasVariantOptions,
|
|
25
|
+
hasDefaultVariants,
|
|
26
|
+
hasSlot,
|
|
27
|
+
findPropInView,
|
|
28
|
+
type ComponentTestContext,
|
|
29
|
+
} from '../../tests/helpers/test-utils.js';
|
|
30
|
+
|
|
31
|
+
describe('Select Component', () => {
|
|
32
|
+
let ctx: ComponentTestContext;
|
|
33
|
+
|
|
34
|
+
beforeAll(() => {
|
|
35
|
+
ctx = loadComponentForTesting('select');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// ==================== Component Structure Tests ====================
|
|
39
|
+
|
|
40
|
+
describe('Component Structure', () => {
|
|
41
|
+
it('should have valid component structure', () => {
|
|
42
|
+
assertValidComponent(ctx.component);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should have select as root element', () => {
|
|
46
|
+
const rootTag = getRootTag(ctx.component);
|
|
47
|
+
expect(rootTag).toBe('select');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should contain a slot for option children', () => {
|
|
51
|
+
expect(hasSlot(ctx.component.view)).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should have className using StyleExpr', () => {
|
|
55
|
+
const className = findPropInView(ctx.component.view, 'className');
|
|
56
|
+
expect(className).not.toBeNull();
|
|
57
|
+
// StyleExpr should have expr: 'style' and preset reference
|
|
58
|
+
expect(className).toMatchObject({
|
|
59
|
+
expr: 'style',
|
|
60
|
+
preset: 'selectStyles',
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// ==================== Params Validation Tests ====================
|
|
66
|
+
|
|
67
|
+
describe('Params Validation', () => {
|
|
68
|
+
const expectedParams = ['value', 'disabled', 'required', 'placeholder', 'name', 'id', 'ariaLabel'];
|
|
69
|
+
|
|
70
|
+
it('should have all expected params', () => {
|
|
71
|
+
expect(hasParams(ctx.component, expectedParams)).toBe(true);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('param: value', () => {
|
|
75
|
+
it('should be optional', () => {
|
|
76
|
+
expect(isOptionalParam(ctx.component, 'value')).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should have type string', () => {
|
|
80
|
+
expect(hasParamType(ctx.component, 'value', 'string')).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('param: disabled', () => {
|
|
85
|
+
it('should be optional', () => {
|
|
86
|
+
expect(isOptionalParam(ctx.component, 'disabled')).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should have type boolean', () => {
|
|
90
|
+
expect(hasParamType(ctx.component, 'disabled', 'boolean')).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('param: required', () => {
|
|
95
|
+
it('should be optional', () => {
|
|
96
|
+
expect(isOptionalParam(ctx.component, 'required')).toBe(true);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should have type boolean', () => {
|
|
100
|
+
expect(hasParamType(ctx.component, 'required', 'boolean')).toBe(true);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe('param: placeholder', () => {
|
|
105
|
+
it('should be optional', () => {
|
|
106
|
+
expect(isOptionalParam(ctx.component, 'placeholder')).toBe(true);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should have type string', () => {
|
|
110
|
+
expect(hasParamType(ctx.component, 'placeholder', 'string')).toBe(true);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe('param: name', () => {
|
|
115
|
+
it('should be optional', () => {
|
|
116
|
+
expect(isOptionalParam(ctx.component, 'name')).toBe(true);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should have type string', () => {
|
|
120
|
+
expect(hasParamType(ctx.component, 'name', 'string')).toBe(true);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe('param: id', () => {
|
|
125
|
+
it('should be optional', () => {
|
|
126
|
+
expect(isOptionalParam(ctx.component, 'id')).toBe(true);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should have type string', () => {
|
|
130
|
+
expect(hasParamType(ctx.component, 'id', 'string')).toBe(true);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe('param: ariaLabel', () => {
|
|
135
|
+
it('should be optional', () => {
|
|
136
|
+
expect(isOptionalParam(ctx.component, 'ariaLabel')).toBe(true);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should have type string', () => {
|
|
140
|
+
expect(hasParamType(ctx.component, 'ariaLabel', 'string')).toBe(true);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// ==================== Style Preset Tests ====================
|
|
146
|
+
|
|
147
|
+
describe('Style Preset', () => {
|
|
148
|
+
it('should have valid style preset structure', () => {
|
|
149
|
+
const selectStyles = ctx.styles['selectStyles'];
|
|
150
|
+
expect(selectStyles).toBeDefined();
|
|
151
|
+
assertValidStylePreset(selectStyles);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should have base classes', () => {
|
|
155
|
+
const selectStyles = ctx.styles['selectStyles'];
|
|
156
|
+
expect(selectStyles.base).toBeDefined();
|
|
157
|
+
expect(typeof selectStyles.base).toBe('string');
|
|
158
|
+
expect(selectStyles.base.length).toBeGreaterThan(0);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe('size variants', () => {
|
|
162
|
+
const sizeOptions = ['default', 'sm', 'lg'];
|
|
163
|
+
|
|
164
|
+
it('should have size variants', () => {
|
|
165
|
+
const selectStyles = ctx.styles['selectStyles'];
|
|
166
|
+
expect(hasVariants(selectStyles, ['size'])).toBe(true);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it.each(sizeOptions)('should have %s size option', (option) => {
|
|
170
|
+
const selectStyles = ctx.styles['selectStyles'];
|
|
171
|
+
expect(hasVariantOptions(selectStyles, 'size', [option])).toBe(true);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe('default variants', () => {
|
|
176
|
+
it('should have default size set to default', () => {
|
|
177
|
+
const selectStyles = ctx.styles['selectStyles'];
|
|
178
|
+
expect(hasDefaultVariants(selectStyles, { size: 'default' })).toBe(true);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// ==================== Accessibility Tests ====================
|
|
184
|
+
|
|
185
|
+
describe('Accessibility', () => {
|
|
186
|
+
it('should support aria-label attribute', () => {
|
|
187
|
+
const ariaLabel = findPropInView(ctx.component.view, 'aria-label');
|
|
188
|
+
expect(ariaLabel).not.toBeNull();
|
|
189
|
+
// Should reference the ariaLabel param
|
|
190
|
+
expect(ariaLabel).toMatchObject({
|
|
191
|
+
expr: 'param',
|
|
192
|
+
name: 'ariaLabel',
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('should support disabled attribute', () => {
|
|
197
|
+
const disabled = findPropInView(ctx.component.view, 'disabled');
|
|
198
|
+
expect(disabled).not.toBeNull();
|
|
199
|
+
// Should reference the disabled param
|
|
200
|
+
expect(disabled).toMatchObject({
|
|
201
|
+
expr: 'param',
|
|
202
|
+
name: 'disabled',
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('should support required attribute', () => {
|
|
207
|
+
const required = findPropInView(ctx.component.view, 'required');
|
|
208
|
+
expect(required).not.toBeNull();
|
|
209
|
+
// Should reference the required param
|
|
210
|
+
expect(required).toMatchObject({
|
|
211
|
+
expr: 'param',
|
|
212
|
+
name: 'required',
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// ==================== View Props Tests ====================
|
|
218
|
+
|
|
219
|
+
describe('View Props', () => {
|
|
220
|
+
it('should pass value to select element', () => {
|
|
221
|
+
const value = findPropInView(ctx.component.view, 'value');
|
|
222
|
+
expect(value).not.toBeNull();
|
|
223
|
+
expect(value).toMatchObject({
|
|
224
|
+
expr: 'param',
|
|
225
|
+
name: 'value',
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('should pass name to select element', () => {
|
|
230
|
+
const name = findPropInView(ctx.component.view, 'name');
|
|
231
|
+
expect(name).not.toBeNull();
|
|
232
|
+
expect(name).toMatchObject({
|
|
233
|
+
expr: 'param',
|
|
234
|
+
name: 'name',
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('should pass id to select element', () => {
|
|
239
|
+
const id = findPropInView(ctx.component.view, 'id');
|
|
240
|
+
expect(id).not.toBeNull();
|
|
241
|
+
expect(id).toMatchObject({
|
|
242
|
+
expr: 'param',
|
|
243
|
+
name: 'id',
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('should pass size to StyleExpr', () => {
|
|
248
|
+
const className = findPropInView(ctx.component.view, 'className');
|
|
249
|
+
expect(className).toMatchObject({
|
|
250
|
+
expr: 'style',
|
|
251
|
+
props: expect.objectContaining({
|
|
252
|
+
size: expect.objectContaining({ expr: 'param', name: 'size' }),
|
|
253
|
+
}),
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"params": {
|
|
3
|
+
"width": { "type": "string", "required": false },
|
|
4
|
+
"height": { "type": "string", "required": false },
|
|
5
|
+
"className": { "type": "string", "required": false }
|
|
6
|
+
},
|
|
7
|
+
"view": {
|
|
8
|
+
"kind": "element",
|
|
9
|
+
"tag": "div",
|
|
10
|
+
"props": {
|
|
11
|
+
"className": {
|
|
12
|
+
"expr": "style",
|
|
13
|
+
"preset": "skeletonStyles",
|
|
14
|
+
"props": {
|
|
15
|
+
"className": { "expr": "param", "name": "className" }
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"style": {
|
|
19
|
+
"width": { "expr": "param", "name": "width" },
|
|
20
|
+
"height": { "expr": "param", "name": "height" }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test suite for Skeleton component
|
|
3
|
+
*
|
|
4
|
+
* @constela/ui Skeleton component tests following TDD methodology.
|
|
5
|
+
* These tests verify the Skeleton component structure, params, and styles.
|
|
6
|
+
*
|
|
7
|
+
* Coverage:
|
|
8
|
+
* - Component structure validation
|
|
9
|
+
* - Params definition validation
|
|
10
|
+
* - Style preset validation
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { describe, it, expect, beforeAll } from 'vitest';
|
|
14
|
+
import {
|
|
15
|
+
loadComponentForTesting,
|
|
16
|
+
assertValidComponent,
|
|
17
|
+
assertValidStylePreset,
|
|
18
|
+
hasParams,
|
|
19
|
+
isOptionalParam,
|
|
20
|
+
hasParamType,
|
|
21
|
+
getRootTag,
|
|
22
|
+
hasSlot,
|
|
23
|
+
findPropInView,
|
|
24
|
+
type ComponentTestContext,
|
|
25
|
+
} from '../../tests/helpers/test-utils.js';
|
|
26
|
+
|
|
27
|
+
describe('Skeleton Component', () => {
|
|
28
|
+
let ctx: ComponentTestContext;
|
|
29
|
+
|
|
30
|
+
beforeAll(() => {
|
|
31
|
+
ctx = loadComponentForTesting('skeleton');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// ==================== Component Structure Tests ====================
|
|
35
|
+
|
|
36
|
+
describe('Component Structure', () => {
|
|
37
|
+
it('should have valid component structure', () => {
|
|
38
|
+
assertValidComponent(ctx.component);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should have div as root element', () => {
|
|
42
|
+
const rootTag = getRootTag(ctx.component);
|
|
43
|
+
expect(rootTag).toBe('div');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should NOT contain a slot (skeleton is self-contained)', () => {
|
|
47
|
+
expect(hasSlot(ctx.component.view)).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should have className using StyleExpr with preset "skeletonStyles"', () => {
|
|
51
|
+
const className = findPropInView(ctx.component.view, 'className');
|
|
52
|
+
expect(className).not.toBeNull();
|
|
53
|
+
// StyleExpr should have expr: 'style' and preset reference
|
|
54
|
+
expect(className).toMatchObject({
|
|
55
|
+
expr: 'style',
|
|
56
|
+
preset: 'skeletonStyles',
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// ==================== Params Validation Tests ====================
|
|
62
|
+
|
|
63
|
+
describe('Params Validation', () => {
|
|
64
|
+
const expectedParams = ['width', 'height', 'className'];
|
|
65
|
+
|
|
66
|
+
it('should have all expected params', () => {
|
|
67
|
+
expect(hasParams(ctx.component, expectedParams)).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('param: width', () => {
|
|
71
|
+
it('should be optional', () => {
|
|
72
|
+
expect(isOptionalParam(ctx.component, 'width')).toBe(true);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should have type string', () => {
|
|
76
|
+
expect(hasParamType(ctx.component, 'width', 'string')).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('param: height', () => {
|
|
81
|
+
it('should be optional', () => {
|
|
82
|
+
expect(isOptionalParam(ctx.component, 'height')).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should have type string', () => {
|
|
86
|
+
expect(hasParamType(ctx.component, 'height', 'string')).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe('param: className', () => {
|
|
91
|
+
it('should be optional', () => {
|
|
92
|
+
expect(isOptionalParam(ctx.component, 'className')).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should have type string', () => {
|
|
96
|
+
expect(hasParamType(ctx.component, 'className', 'string')).toBe(true);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// ==================== Style Preset Tests ====================
|
|
102
|
+
|
|
103
|
+
describe('Style Preset', () => {
|
|
104
|
+
it('should have valid style preset structure', () => {
|
|
105
|
+
const skeletonStyles = ctx.styles['skeletonStyles'];
|
|
106
|
+
expect(skeletonStyles).toBeDefined();
|
|
107
|
+
assertValidStylePreset(skeletonStyles);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should have base classes with common skeleton styles', () => {
|
|
111
|
+
const skeletonStyles = ctx.styles['skeletonStyles'];
|
|
112
|
+
expect(skeletonStyles.base).toBeDefined();
|
|
113
|
+
expect(typeof skeletonStyles.base).toBe('string');
|
|
114
|
+
expect(skeletonStyles.base.length).toBeGreaterThan(0);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should include animate-pulse in base classes', () => {
|
|
118
|
+
const skeletonStyles = ctx.styles['skeletonStyles'];
|
|
119
|
+
expect(skeletonStyles.base).toContain('animate-pulse');
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should include bg-muted in base classes', () => {
|
|
123
|
+
const skeletonStyles = ctx.styles['skeletonStyles'];
|
|
124
|
+
expect(skeletonStyles.base).toContain('bg-muted');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should include rounded in base classes', () => {
|
|
128
|
+
const skeletonStyles = ctx.styles['skeletonStyles'];
|
|
129
|
+
expect(skeletonStyles.base).toContain('rounded');
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// ==================== View Props Tests ====================
|
|
134
|
+
|
|
135
|
+
describe('View Props', () => {
|
|
136
|
+
it('should pass width to style attribute', () => {
|
|
137
|
+
const style = findPropInView(ctx.component.view, 'style');
|
|
138
|
+
expect(style).not.toBeNull();
|
|
139
|
+
// Style object should contain width
|
|
140
|
+
expect(style).toMatchObject({
|
|
141
|
+
width: expect.objectContaining({ expr: 'param', name: 'width' }),
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should pass height to style attribute', () => {
|
|
146
|
+
const style = findPropInView(ctx.component.view, 'style');
|
|
147
|
+
expect(style).not.toBeNull();
|
|
148
|
+
// Style object should contain height
|
|
149
|
+
expect(style).toMatchObject({
|
|
150
|
+
height: expect.objectContaining({ expr: 'param', name: 'height' }),
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should pass className to StyleExpr props', () => {
|
|
155
|
+
const className = findPropInView(ctx.component.view, 'className');
|
|
156
|
+
expect(className).toMatchObject({
|
|
157
|
+
expr: 'style',
|
|
158
|
+
props: expect.objectContaining({
|
|
159
|
+
className: expect.objectContaining({ expr: 'param', name: 'className' }),
|
|
160
|
+
}),
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"params": {
|
|
3
|
+
"direction": { "type": "string", "required": false },
|
|
4
|
+
"gap": { "type": "string", "required": false },
|
|
5
|
+
"align": { "type": "string", "required": false },
|
|
6
|
+
"justify": { "type": "string", "required": false },
|
|
7
|
+
"className": { "type": "string", "required": false }
|
|
8
|
+
},
|
|
9
|
+
"view": {
|
|
10
|
+
"kind": "element",
|
|
11
|
+
"tag": "div",
|
|
12
|
+
"props": {
|
|
13
|
+
"className": {
|
|
14
|
+
"expr": "style",
|
|
15
|
+
"preset": "stackStyles",
|
|
16
|
+
"props": {
|
|
17
|
+
"direction": { "expr": "param", "name": "direction" },
|
|
18
|
+
"gap": { "expr": "param", "name": "gap" },
|
|
19
|
+
"align": { "expr": "param", "name": "align" },
|
|
20
|
+
"justify": { "expr": "param", "name": "justify" },
|
|
21
|
+
"className": { "expr": "param", "name": "className" }
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"children": [{ "kind": "slot" }]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"stackStyles": {
|
|
3
|
+
"base": "flex",
|
|
4
|
+
"variants": {
|
|
5
|
+
"direction": {
|
|
6
|
+
"row": "flex-row",
|
|
7
|
+
"column": "flex-col"
|
|
8
|
+
},
|
|
9
|
+
"gap": {
|
|
10
|
+
"none": "gap-0",
|
|
11
|
+
"sm": "gap-2",
|
|
12
|
+
"md": "gap-4",
|
|
13
|
+
"lg": "gap-8"
|
|
14
|
+
},
|
|
15
|
+
"align": {
|
|
16
|
+
"start": "items-start",
|
|
17
|
+
"center": "items-center",
|
|
18
|
+
"end": "items-end",
|
|
19
|
+
"stretch": "items-stretch"
|
|
20
|
+
},
|
|
21
|
+
"justify": {
|
|
22
|
+
"start": "justify-start",
|
|
23
|
+
"center": "justify-center",
|
|
24
|
+
"end": "justify-end",
|
|
25
|
+
"between": "justify-between"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"defaultVariants": {
|
|
29
|
+
"direction": "column",
|
|
30
|
+
"gap": "md"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|