@fpkit/acss 3.2.1 → 3.4.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/libs/chunk-KAR3HDXK.js +8 -0
- package/libs/chunk-KAR3HDXK.js.map +1 -0
- package/libs/chunk-M5JARVJD.cjs +18 -0
- package/libs/chunk-M5JARVJD.cjs.map +1 -0
- package/libs/components/alert/alert.min.min.css +2 -0
- package/libs/components/badge/badge.min.min.css +2 -0
- package/libs/components/box/box.min.min.css +2 -0
- package/libs/components/breadcrumbs/breadcrumb.min.min.css +2 -0
- package/libs/components/buttons/button.min.min.css +2 -0
- package/libs/components/card.cjs +6 -6
- package/libs/components/card.js +1 -1
- package/libs/components/cards/card-style.min.min.css +2 -0
- package/libs/components/cards/card.min.min.css +2 -0
- package/libs/components/cluster/cluster.min.min.css +2 -0
- package/libs/components/details/details.min.min.css +2 -0
- package/libs/components/dialog/dialog.min.min.css +2 -0
- package/libs/components/flexbox/flex.min.min.css +2 -0
- package/libs/components/form/form.min.min.css +2 -0
- package/libs/components/grid/grid.min.min.css +2 -0
- package/libs/components/icons/icon.min.min.css +2 -0
- package/libs/components/images/img.min.min.css +2 -0
- package/libs/components/layout/landmarks.min.min.css +2 -0
- package/libs/components/link/link.min.min.css +2 -0
- package/libs/components/list/list.min.min.css +2 -0
- package/libs/components/nav/nav.min.min.css +2 -0
- package/libs/components/progress/progress.min.min.css +2 -0
- package/libs/components/stack/stack.min.min.css +2 -0
- package/libs/components/styles/index.min.min.css +2 -0
- package/libs/components/tag/tag.min.min.css +2 -0
- package/libs/components/text-to-speech/text-to-speech.min.min.css +2 -0
- package/libs/index.cjs +27 -25
- package/libs/index.cjs.map +1 -1
- package/libs/index.css +1 -1
- package/libs/index.css.map +1 -1
- package/libs/index.d.cts +275 -1
- package/libs/index.d.ts +275 -1
- package/libs/index.js +10 -10
- package/libs/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/cards/card.stories.tsx +1 -1
- package/src/components/cards/card.tsx +46 -41
- package/src/components/col/README.mdx +532 -0
- package/src/components/col/col.stories.tsx +424 -0
- package/src/components/col/col.test.tsx +321 -0
- package/src/components/col/col.tsx +105 -0
- package/src/components/col/col.types.ts +76 -0
- package/src/components/row/README.mdx +324 -0
- package/src/components/row/row.stories.tsx +595 -0
- package/src/components/row/row.test.tsx +358 -0
- package/src/components/row/row.tsx +121 -0
- package/src/components/row/row.types.ts +93 -0
- package/src/index.scss +1 -0
- package/src/index.ts +2 -0
- package/src/sass/README.mdx +597 -0
- package/src/sass/_columns.scss +198 -0
- package/src/sass/columns.stories.tsx +456 -0
- package/src/styles/index.css +340 -0
- package/src/styles/index.css.map +1 -1
- package/src/types/layout-primitives.ts +61 -0
- package/libs/chunk-OU52NIKA.js +0 -8
- package/libs/chunk-OU52NIKA.js.map +0 -1
- package/libs/chunk-WWPLBWCQ.cjs +0 -18
- package/libs/chunk-WWPLBWCQ.cjs.map +0 -1
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import { describe, it, expect } from "vitest";
|
|
4
|
+
import { Row } from "./row";
|
|
5
|
+
|
|
6
|
+
describe("Row Component", () => {
|
|
7
|
+
describe("Rendering", () => {
|
|
8
|
+
it("renders with default props", () => {
|
|
9
|
+
render(<Row>Test content</Row>);
|
|
10
|
+
expect(screen.getByText("Test content")).toBeInTheDocument();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("renders as div by default", () => {
|
|
14
|
+
const { container } = render(<Row>Content</Row>);
|
|
15
|
+
const row = container.firstChild as HTMLElement;
|
|
16
|
+
expect(row.tagName).toBe("DIV");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("renders as specified element type", () => {
|
|
20
|
+
const { container } = render(<Row as="section">Content</Row>);
|
|
21
|
+
const row = container.firstChild as HTMLElement;
|
|
22
|
+
expect(row.tagName).toBe("SECTION");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("renders as ul element", () => {
|
|
26
|
+
const { container } = render(<Row as="ul">Content</Row>);
|
|
27
|
+
const row = container.firstChild as HTMLElement;
|
|
28
|
+
expect(row.tagName).toBe("UL");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("renders children correctly", () => {
|
|
32
|
+
render(
|
|
33
|
+
<Row>
|
|
34
|
+
<div>Child 1</div>
|
|
35
|
+
<div>Child 2</div>
|
|
36
|
+
</Row>
|
|
37
|
+
);
|
|
38
|
+
expect(screen.getByText("Child 1")).toBeInTheDocument();
|
|
39
|
+
expect(screen.getByText("Child 2")).toBeInTheDocument();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe("Base Class", () => {
|
|
44
|
+
it("always includes .col-row base class", () => {
|
|
45
|
+
const { container } = render(<Row>Content</Row>);
|
|
46
|
+
const row = container.firstChild as HTMLElement;
|
|
47
|
+
expect(row).toHaveClass("col-row");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("includes base class with other utilities", () => {
|
|
51
|
+
const { container } = render(
|
|
52
|
+
<Row gap="lg" justify="center">
|
|
53
|
+
Content
|
|
54
|
+
</Row>
|
|
55
|
+
);
|
|
56
|
+
const row = container.firstChild as HTMLElement;
|
|
57
|
+
expect(row).toHaveClass("col-row");
|
|
58
|
+
expect(row).toHaveClass("col-row-gap-lg");
|
|
59
|
+
expect(row).toHaveClass("col-row-justify-center");
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe("Gap Utilities", () => {
|
|
64
|
+
it("applies gap-0 utility class", () => {
|
|
65
|
+
const { container } = render(<Row gap="0">Content</Row>);
|
|
66
|
+
const row = container.firstChild as HTMLElement;
|
|
67
|
+
expect(row).toHaveClass("col-row-gap-0");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("applies gap-xs utility class", () => {
|
|
71
|
+
const { container } = render(<Row gap="xs">Content</Row>);
|
|
72
|
+
const row = container.firstChild as HTMLElement;
|
|
73
|
+
expect(row).toHaveClass("col-row-gap-xs");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("applies gap-sm utility class", () => {
|
|
77
|
+
const { container } = render(<Row gap="sm">Content</Row>);
|
|
78
|
+
const row = container.firstChild as HTMLElement;
|
|
79
|
+
expect(row).toHaveClass("col-row-gap-sm");
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("applies gap-md utility class", () => {
|
|
83
|
+
const { container } = render(<Row gap="md">Content</Row>);
|
|
84
|
+
const row = container.firstChild as HTMLElement;
|
|
85
|
+
expect(row).toHaveClass("col-row-gap-md");
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("applies gap-lg utility class", () => {
|
|
89
|
+
const { container } = render(<Row gap="lg">Content</Row>);
|
|
90
|
+
const row = container.firstChild as HTMLElement;
|
|
91
|
+
expect(row).toHaveClass("col-row-gap-lg");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("applies gap-xl utility class", () => {
|
|
95
|
+
const { container } = render(<Row gap="xl">Content</Row>);
|
|
96
|
+
const row = container.firstChild as HTMLElement;
|
|
97
|
+
expect(row).toHaveClass("col-row-gap-xl");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("does not apply gap class when gap is undefined", () => {
|
|
101
|
+
const { container } = render(<Row>Content</Row>);
|
|
102
|
+
const row = container.firstChild as HTMLElement;
|
|
103
|
+
expect(row.className).not.toMatch(/col-row-gap-/);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
describe("Justify Content Utilities", () => {
|
|
108
|
+
it("applies justify-start utility class", () => {
|
|
109
|
+
const { container } = render(<Row justify="start">Content</Row>);
|
|
110
|
+
const row = container.firstChild as HTMLElement;
|
|
111
|
+
expect(row).toHaveClass("col-row-justify-start");
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("applies justify-center utility class", () => {
|
|
115
|
+
const { container } = render(<Row justify="center">Content</Row>);
|
|
116
|
+
const row = container.firstChild as HTMLElement;
|
|
117
|
+
expect(row).toHaveClass("col-row-justify-center");
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("applies justify-end utility class", () => {
|
|
121
|
+
const { container } = render(<Row justify="end">Content</Row>);
|
|
122
|
+
const row = container.firstChild as HTMLElement;
|
|
123
|
+
expect(row).toHaveClass("col-row-justify-end");
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("applies justify-between utility class", () => {
|
|
127
|
+
const { container } = render(<Row justify="between">Content</Row>);
|
|
128
|
+
const row = container.firstChild as HTMLElement;
|
|
129
|
+
expect(row).toHaveClass("col-row-justify-between");
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("applies justify-around utility class", () => {
|
|
133
|
+
const { container } = render(<Row justify="around">Content</Row>);
|
|
134
|
+
const row = container.firstChild as HTMLElement;
|
|
135
|
+
expect(row).toHaveClass("col-row-justify-around");
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("applies justify-evenly utility class", () => {
|
|
139
|
+
const { container } = render(<Row justify="evenly">Content</Row>);
|
|
140
|
+
const row = container.firstChild as HTMLElement;
|
|
141
|
+
expect(row).toHaveClass("col-row-justify-evenly");
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("does not apply justify class when justify is undefined", () => {
|
|
145
|
+
const { container } = render(<Row>Content</Row>);
|
|
146
|
+
const row = container.firstChild as HTMLElement;
|
|
147
|
+
expect(row.className).not.toMatch(/col-row-justify-/);
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
describe("Align Items Utilities", () => {
|
|
152
|
+
it("applies align-start utility class", () => {
|
|
153
|
+
const { container } = render(<Row align="start">Content</Row>);
|
|
154
|
+
const row = container.firstChild as HTMLElement;
|
|
155
|
+
expect(row).toHaveClass("col-row-align-start");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("applies align-center utility class", () => {
|
|
159
|
+
const { container } = render(<Row align="center">Content</Row>);
|
|
160
|
+
const row = container.firstChild as HTMLElement;
|
|
161
|
+
expect(row).toHaveClass("col-row-align-center");
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("applies align-end utility class", () => {
|
|
165
|
+
const { container } = render(<Row align="end">Content</Row>);
|
|
166
|
+
const row = container.firstChild as HTMLElement;
|
|
167
|
+
expect(row).toHaveClass("col-row-align-end");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("applies align-baseline utility class", () => {
|
|
171
|
+
const { container } = render(<Row align="baseline">Content</Row>);
|
|
172
|
+
const row = container.firstChild as HTMLElement;
|
|
173
|
+
expect(row).toHaveClass("col-row-align-baseline");
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("applies align-stretch utility class", () => {
|
|
177
|
+
const { container } = render(<Row align="stretch">Content</Row>);
|
|
178
|
+
const row = container.firstChild as HTMLElement;
|
|
179
|
+
expect(row).toHaveClass("col-row-align-stretch");
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("does not apply align class when align is undefined", () => {
|
|
183
|
+
const { container } = render(<Row>Content</Row>);
|
|
184
|
+
const row = container.firstChild as HTMLElement;
|
|
185
|
+
expect(row.className).not.toMatch(/col-row-align-/);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe("Wrap Utilities", () => {
|
|
190
|
+
it("does not apply wrap class for default wrap value", () => {
|
|
191
|
+
const { container } = render(<Row wrap="wrap">Content</Row>);
|
|
192
|
+
const row = container.firstChild as HTMLElement;
|
|
193
|
+
expect(row.className).not.toMatch(/col-row-wrap/);
|
|
194
|
+
expect(row.className).not.toMatch(/col-row-nowrap/);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("applies nowrap utility class", () => {
|
|
198
|
+
const { container } = render(<Row wrap="nowrap">Content</Row>);
|
|
199
|
+
const row = container.firstChild as HTMLElement;
|
|
200
|
+
expect(row).toHaveClass("col-row-nowrap");
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("applies wrap-reverse utility class", () => {
|
|
204
|
+
const { container } = render(<Row wrap="wrap-reverse">Content</Row>);
|
|
205
|
+
const row = container.firstChild as HTMLElement;
|
|
206
|
+
expect(row).toHaveClass("col-row-wrap-reverse");
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
describe("Combined Utilities", () => {
|
|
211
|
+
it("applies multiple utility classes together", () => {
|
|
212
|
+
const { container } = render(
|
|
213
|
+
<Row gap="lg" justify="center" align="center" wrap="nowrap">
|
|
214
|
+
Content
|
|
215
|
+
</Row>
|
|
216
|
+
);
|
|
217
|
+
const row = container.firstChild as HTMLElement;
|
|
218
|
+
expect(row).toHaveClass("col-row");
|
|
219
|
+
expect(row).toHaveClass("col-row-gap-lg");
|
|
220
|
+
expect(row).toHaveClass("col-row-justify-center");
|
|
221
|
+
expect(row).toHaveClass("col-row-align-center");
|
|
222
|
+
expect(row).toHaveClass("col-row-nowrap");
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
describe("Custom Classes", () => {
|
|
227
|
+
it("merges className prop with utility classes", () => {
|
|
228
|
+
const { container } = render(
|
|
229
|
+
<Row className="custom-class" gap="md">
|
|
230
|
+
Content
|
|
231
|
+
</Row>
|
|
232
|
+
);
|
|
233
|
+
const row = container.firstChild as HTMLElement;
|
|
234
|
+
expect(row).toHaveClass("col-row");
|
|
235
|
+
expect(row).toHaveClass("col-row-gap-md");
|
|
236
|
+
expect(row).toHaveClass("custom-class");
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it("merges classes prop with utility classes", () => {
|
|
240
|
+
const { container } = render(
|
|
241
|
+
<Row classes="another-class" justify="center">
|
|
242
|
+
Content
|
|
243
|
+
</Row>
|
|
244
|
+
);
|
|
245
|
+
const row = container.firstChild as HTMLElement;
|
|
246
|
+
expect(row).toHaveClass("col-row");
|
|
247
|
+
expect(row).toHaveClass("col-row-justify-center");
|
|
248
|
+
expect(row).toHaveClass("another-class");
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it("merges both className and classes props", () => {
|
|
252
|
+
const { container } = render(
|
|
253
|
+
<Row className="class-one" classes="class-two">
|
|
254
|
+
Content
|
|
255
|
+
</Row>
|
|
256
|
+
);
|
|
257
|
+
const row = container.firstChild as HTMLElement;
|
|
258
|
+
expect(row).toHaveClass("col-row");
|
|
259
|
+
expect(row).toHaveClass("class-one");
|
|
260
|
+
expect(row).toHaveClass("class-two");
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
describe("Proportional Layout Mode", () => {
|
|
265
|
+
it("applies col-row-proportional class when alwaysProportional is true", () => {
|
|
266
|
+
const { container } = render(
|
|
267
|
+
<Row alwaysProportional>
|
|
268
|
+
<div className="col-6">Column 1</div>
|
|
269
|
+
<div className="col-6">Column 2</div>
|
|
270
|
+
</Row>
|
|
271
|
+
);
|
|
272
|
+
const row = container.firstChild as HTMLElement;
|
|
273
|
+
expect(row).toHaveClass("col-row-proportional");
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it("does not apply col-row-proportional class by default", () => {
|
|
277
|
+
const { container } = render(
|
|
278
|
+
<Row>
|
|
279
|
+
<div className="col-6">Column 1</div>
|
|
280
|
+
<div className="col-6">Column 2</div>
|
|
281
|
+
</Row>
|
|
282
|
+
);
|
|
283
|
+
const row = container.firstChild as HTMLElement;
|
|
284
|
+
expect(row).not.toHaveClass("col-row-proportional");
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it("does not apply col-row-proportional class when explicitly false", () => {
|
|
288
|
+
const { container } = render(
|
|
289
|
+
<Row alwaysProportional={false}>
|
|
290
|
+
<div className="col-6">Column 1</div>
|
|
291
|
+
<div className="col-6">Column 2</div>
|
|
292
|
+
</Row>
|
|
293
|
+
);
|
|
294
|
+
const row = container.firstChild as HTMLElement;
|
|
295
|
+
expect(row).not.toHaveClass("col-row-proportional");
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it("combines alwaysProportional with other row utilities", () => {
|
|
299
|
+
const { container } = render(
|
|
300
|
+
<Row alwaysProportional gap="lg" justify="center">
|
|
301
|
+
<div className="col-4">Column</div>
|
|
302
|
+
</Row>
|
|
303
|
+
);
|
|
304
|
+
const row = container.firstChild as HTMLElement;
|
|
305
|
+
expect(row).toHaveClass("col-row");
|
|
306
|
+
expect(row).toHaveClass("col-row-proportional");
|
|
307
|
+
expect(row).toHaveClass("col-row-gap-lg");
|
|
308
|
+
expect(row).toHaveClass("col-row-justify-center");
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it("preserves base class with proportional mode", () => {
|
|
312
|
+
const { container } = render(
|
|
313
|
+
<Row alwaysProportional>Content</Row>
|
|
314
|
+
);
|
|
315
|
+
const row = container.firstChild as HTMLElement;
|
|
316
|
+
expect(row).toHaveClass("col-row");
|
|
317
|
+
expect(row).toHaveClass("col-row-proportional");
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
describe("Ref Forwarding", () => {
|
|
322
|
+
it("forwards ref to the underlying element", () => {
|
|
323
|
+
const ref = { current: null };
|
|
324
|
+
render(<Row ref={ref}>Content</Row>);
|
|
325
|
+
expect(ref.current).toBeInstanceOf(HTMLDivElement);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it("forwards ref with custom element type", () => {
|
|
329
|
+
const ref = { current: null };
|
|
330
|
+
render(
|
|
331
|
+
<Row ref={ref} as="section">
|
|
332
|
+
Content
|
|
333
|
+
</Row>
|
|
334
|
+
);
|
|
335
|
+
expect(ref.current).toBeInstanceOf(HTMLElement);
|
|
336
|
+
expect((ref.current as unknown as HTMLElement).tagName).toBe("SECTION");
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
describe("Additional Props", () => {
|
|
341
|
+
it("passes through additional HTML attributes", () => {
|
|
342
|
+
const { container } = render(
|
|
343
|
+
<Row data-testid="test-row" aria-label="Test Row">
|
|
344
|
+
Content
|
|
345
|
+
</Row>
|
|
346
|
+
);
|
|
347
|
+
const row = container.firstChild as HTMLElement;
|
|
348
|
+
expect(row).toHaveAttribute("data-testid", "test-row");
|
|
349
|
+
expect(row).toHaveAttribute("aria-label", "Test Row");
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it("handles id prop", () => {
|
|
353
|
+
const { container } = render(<Row id="my-row">Content</Row>);
|
|
354
|
+
const row = container.firstChild as HTMLElement;
|
|
355
|
+
expect(row).toHaveAttribute("id", "my-row");
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import UI from "../ui";
|
|
3
|
+
import type { RowProps } from "./row.types";
|
|
4
|
+
|
|
5
|
+
// Re-export types for convenience
|
|
6
|
+
export type { RowProps } from "./row.types";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Row - A flex container component for 12-column layouts.
|
|
10
|
+
*
|
|
11
|
+
* Row provides a type-safe React wrapper around the .col-row utility class,
|
|
12
|
+
* allowing developers to create responsive column layouts with customizable
|
|
13
|
+
* gap, alignment, and wrapping behavior. Always includes the .col-row base
|
|
14
|
+
* class and adds variant utilities based on props.
|
|
15
|
+
*
|
|
16
|
+
* ## Key Features
|
|
17
|
+
* - **Flex Container**: Display flex with wrap enabled by default
|
|
18
|
+
* - **Customizable Gap**: Control spacing between columns with gap prop
|
|
19
|
+
* - **Alignment Control**: Justify and align props for layout control
|
|
20
|
+
* - **Polymorphic**: Render as any semantic HTML element
|
|
21
|
+
* - **Type-Safe**: Full TypeScript support with literal types
|
|
22
|
+
*
|
|
23
|
+
* ## Use Cases
|
|
24
|
+
* - Multi-column layouts
|
|
25
|
+
* - Responsive grid systems
|
|
26
|
+
* - Card grids
|
|
27
|
+
* - Dashboard layouts
|
|
28
|
+
* - Form layouts
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* // Basic two-column layout
|
|
32
|
+
* <Row>
|
|
33
|
+
* <Col span={6}>Left column</Col>
|
|
34
|
+
* <Col span={6}>Right column</Col>
|
|
35
|
+
* </Row>
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* // Custom gap and centered alignment
|
|
39
|
+
* <Row gap="lg" justify="center" align="center">
|
|
40
|
+
* <Col span={4}>Column 1</Col>
|
|
41
|
+
* <Col span={4}>Column 2</Col>
|
|
42
|
+
* <Col span={4}>Column 3</Col>
|
|
43
|
+
* </Row>
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* // Semantic HTML with list elements
|
|
47
|
+
* <Row as="ul" gap="md">
|
|
48
|
+
* <Col as="li" span={4}>Item 1</Col>
|
|
49
|
+
* <Col as="li" span={4}>Item 2</Col>
|
|
50
|
+
* <Col as="li" span={4}>Item 3</Col>
|
|
51
|
+
* </Row>
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* // Proportional layout - maintains columns on tablets and larger
|
|
55
|
+
* <Row alwaysProportional gap="lg">
|
|
56
|
+
* <Col span={6}>Column 1 (50% on tablets+)</Col>
|
|
57
|
+
* <Col span={6}>Column 2 (50% on tablets+)</Col>
|
|
58
|
+
* </Row>
|
|
59
|
+
*
|
|
60
|
+
* @see {@link RowProps} for complete props documentation
|
|
61
|
+
*/
|
|
62
|
+
export const Row = React.forwardRef<HTMLElement, RowProps>(
|
|
63
|
+
(
|
|
64
|
+
{
|
|
65
|
+
gap,
|
|
66
|
+
justify,
|
|
67
|
+
align,
|
|
68
|
+
wrap,
|
|
69
|
+
alwaysProportional = false,
|
|
70
|
+
as = "div",
|
|
71
|
+
className,
|
|
72
|
+
classes,
|
|
73
|
+
children,
|
|
74
|
+
...props
|
|
75
|
+
},
|
|
76
|
+
ref
|
|
77
|
+
) => {
|
|
78
|
+
// Build utility classes array - ALWAYS include base class
|
|
79
|
+
const utilityClasses: string[] = ["col-row"];
|
|
80
|
+
|
|
81
|
+
// Gap utilities - override default gap
|
|
82
|
+
if (gap) {
|
|
83
|
+
utilityClasses.push(`col-row-gap-${gap}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Justify content utilities
|
|
87
|
+
if (justify) {
|
|
88
|
+
utilityClasses.push(`col-row-justify-${justify}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Align items utilities
|
|
92
|
+
if (align) {
|
|
93
|
+
utilityClasses.push(`col-row-align-${align}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Wrap utilities - only add if not default "wrap"
|
|
97
|
+
if (wrap && wrap !== "wrap") {
|
|
98
|
+
utilityClasses.push(`col-row-${wrap}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Proportional layout mode - prevents stacking on tablets and larger
|
|
102
|
+
if (alwaysProportional) {
|
|
103
|
+
utilityClasses.push("col-row-proportional");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Merge all classes: utilities + className + classes
|
|
107
|
+
const allClasses = [...utilityClasses, className, classes]
|
|
108
|
+
.filter(Boolean)
|
|
109
|
+
.join(" ");
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<UI as={as} ref={ref} classes={allClasses} {...props}>
|
|
113
|
+
{children}
|
|
114
|
+
</UI>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
Row.displayName = "Row";
|
|
120
|
+
|
|
121
|
+
export default Row;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { ComponentProps } from "../../types/component-props";
|
|
2
|
+
import type {
|
|
3
|
+
RowElement,
|
|
4
|
+
SpacingScale,
|
|
5
|
+
JustifyContent,
|
|
6
|
+
AlignItems,
|
|
7
|
+
FlexWrap,
|
|
8
|
+
} from "../../types/layout-primitives";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Props for the Row component
|
|
12
|
+
*
|
|
13
|
+
* Row provides a flex container for column layouts with customizable gap,
|
|
14
|
+
* justify, align, and wrap properties. Always renders with the .col-row
|
|
15
|
+
* base class and adds variant utilities based on props.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // Basic row with default settings
|
|
19
|
+
* <Row>
|
|
20
|
+
* <Col span={6}>Column 1</Col>
|
|
21
|
+
* <Col span={6}>Column 2</Col>
|
|
22
|
+
* </Row>
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // Custom gap and centering
|
|
26
|
+
* <Row gap="lg" justify="center" align="center">
|
|
27
|
+
* <Col span={4}>Centered content</Col>
|
|
28
|
+
* </Row>
|
|
29
|
+
*/
|
|
30
|
+
export interface RowProps
|
|
31
|
+
extends Partial<ComponentProps>,
|
|
32
|
+
Omit<React.HTMLAttributes<HTMLElement>, "className"> {
|
|
33
|
+
/**
|
|
34
|
+
* Gap size between columns
|
|
35
|
+
* Maps to --spacing-* CSS custom properties
|
|
36
|
+
* @default undefined (uses .col-row default gap)
|
|
37
|
+
*/
|
|
38
|
+
gap?: SpacingScale;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Horizontal alignment of columns (justify-content)
|
|
42
|
+
* @default undefined (flex-start)
|
|
43
|
+
*/
|
|
44
|
+
justify?: JustifyContent;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Vertical alignment of columns (align-items)
|
|
48
|
+
* @default undefined (stretch)
|
|
49
|
+
*/
|
|
50
|
+
align?: AlignItems;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Flex wrap behavior
|
|
54
|
+
* @default "wrap"
|
|
55
|
+
*/
|
|
56
|
+
wrap?: FlexWrap;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* When true, columns maintain their proportional layout on tablets and larger
|
|
60
|
+
* instead of stacking to 100% width on all mobile devices (< 768px).
|
|
61
|
+
*
|
|
62
|
+
* Wrapping behavior with this prop:
|
|
63
|
+
* - Mobile phones (< 480px): Columns still stack at 100% width
|
|
64
|
+
* - Tablets & larger (≥ 480px): Columns maintain proportional layout
|
|
65
|
+
*
|
|
66
|
+
* Use this when you want columns to stay side-by-side on tablets and desktops
|
|
67
|
+
* but still provide mobile-friendly stacking on phones.
|
|
68
|
+
*
|
|
69
|
+
* @default false
|
|
70
|
+
* @example
|
|
71
|
+
* <Row alwaysProportional>
|
|
72
|
+
* <Col span={6}>Column 1</Col>
|
|
73
|
+
* <Col span={6}>Column 2</Col>
|
|
74
|
+
* </Row>
|
|
75
|
+
*/
|
|
76
|
+
alwaysProportional?: boolean;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Element type to render
|
|
80
|
+
* @default "div"
|
|
81
|
+
*/
|
|
82
|
+
as?: RowElement;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Additional CSS classes
|
|
86
|
+
*/
|
|
87
|
+
className?: string;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Child elements (typically Col components)
|
|
91
|
+
*/
|
|
92
|
+
children?: React.ReactNode;
|
|
93
|
+
}
|
package/src/index.scss
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
@use "./components/grid/grid.scss";
|
|
20
20
|
@use "./components/dialog/dialog.scss";
|
|
21
21
|
@use "./sass/_grid.scss" as grid-legacy;
|
|
22
|
+
@use "./sass/_columns.scss";
|
|
22
23
|
@use "./components/badge/badge.scss";
|
|
23
24
|
@use "./components/nav/nav.scss";
|
|
24
25
|
@use "./components/form/form.scss";
|
package/src/index.ts
CHANGED
|
@@ -122,6 +122,8 @@ export { Box, type BoxProps } from "./components/box/box";
|
|
|
122
122
|
export { Stack, type StackProps } from "./components/stack/stack";
|
|
123
123
|
export { Cluster, type ClusterProps } from "./components/cluster/cluster";
|
|
124
124
|
export { default as Grid, GridItem, type GridProps, type GridItemProps } from "./components/grid/grid";
|
|
125
|
+
export { Row, type RowProps } from "./components/row/row";
|
|
126
|
+
export { Col, type ColProps } from "./components/col/col";
|
|
125
127
|
export { default as Flex } from "./components/flexbox/flex";
|
|
126
128
|
export type {
|
|
127
129
|
FlexProps,
|