@fpkit/acss 3.3.0 → 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.
Files changed (51) hide show
  1. package/libs/components/alert/alert.min.min.css +2 -0
  2. package/libs/components/badge/badge.min.min.css +2 -0
  3. package/libs/components/box/box.min.min.css +2 -0
  4. package/libs/components/breadcrumbs/breadcrumb.min.min.css +2 -0
  5. package/libs/components/buttons/button.min.min.css +2 -0
  6. package/libs/components/cards/card-style.min.min.css +2 -0
  7. package/libs/components/cards/card.min.min.css +2 -0
  8. package/libs/components/cluster/cluster.min.min.css +2 -0
  9. package/libs/components/details/details.min.min.css +2 -0
  10. package/libs/components/dialog/dialog.min.min.css +2 -0
  11. package/libs/components/flexbox/flex.min.min.css +2 -0
  12. package/libs/components/form/form.min.min.css +2 -0
  13. package/libs/components/grid/grid.min.min.css +2 -0
  14. package/libs/components/icons/icon.min.min.css +2 -0
  15. package/libs/components/images/img.min.min.css +2 -0
  16. package/libs/components/layout/landmarks.min.min.css +2 -0
  17. package/libs/components/link/link.min.min.css +2 -0
  18. package/libs/components/list/list.min.min.css +2 -0
  19. package/libs/components/nav/nav.min.min.css +2 -0
  20. package/libs/components/progress/progress.min.min.css +2 -0
  21. package/libs/components/stack/stack.min.min.css +2 -0
  22. package/libs/components/styles/index.min.min.css +2 -0
  23. package/libs/components/tag/tag.min.min.css +2 -0
  24. package/libs/components/text-to-speech/text-to-speech.min.min.css +2 -0
  25. package/libs/index.cjs +22 -20
  26. package/libs/index.cjs.map +1 -1
  27. package/libs/index.css +1 -1
  28. package/libs/index.css.map +1 -1
  29. package/libs/index.d.cts +275 -1
  30. package/libs/index.d.ts +275 -1
  31. package/libs/index.js +9 -9
  32. package/libs/index.js.map +1 -1
  33. package/package.json +2 -2
  34. package/src/components/col/README.mdx +532 -0
  35. package/src/components/col/col.stories.tsx +424 -0
  36. package/src/components/col/col.test.tsx +321 -0
  37. package/src/components/col/col.tsx +105 -0
  38. package/src/components/col/col.types.ts +76 -0
  39. package/src/components/row/README.mdx +324 -0
  40. package/src/components/row/row.stories.tsx +595 -0
  41. package/src/components/row/row.test.tsx +358 -0
  42. package/src/components/row/row.tsx +121 -0
  43. package/src/components/row/row.types.ts +93 -0
  44. package/src/index.scss +1 -0
  45. package/src/index.ts +2 -0
  46. package/src/sass/README.mdx +597 -0
  47. package/src/sass/_columns.scss +198 -0
  48. package/src/sass/columns.stories.tsx +456 -0
  49. package/src/styles/index.css +340 -0
  50. package/src/styles/index.css.map +1 -1
  51. package/src/types/layout-primitives.ts +61 -0
@@ -0,0 +1,595 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { within, expect } from "storybook/test";
3
+ import { Row } from "./row";
4
+
5
+ const meta: Meta<typeof Row> = {
6
+ title: "FP.React Components/Layout/Row",
7
+ component: Row,
8
+ tags: ["autodocs", "rc", "layout"],
9
+ parameters: {
10
+ docs: {
11
+ description: {
12
+ component:
13
+ "Row provides a flex container for 12-column layouts with customizable gap, alignment, and wrapping. Always includes the `.col-row` base class and adds variant utilities based on props. Use with Col components for responsive column layouts.",
14
+ },
15
+ },
16
+ },
17
+ argTypes: {
18
+ gap: {
19
+ control: "select",
20
+ options: ["0", "xs", "sm", "md", "lg", "xl"],
21
+ description: "Gap size between columns",
22
+ },
23
+ justify: {
24
+ control: "select",
25
+ options: ["start", "center", "end", "between", "around", "evenly"],
26
+ description: "Horizontal alignment (justify-content)",
27
+ },
28
+ align: {
29
+ control: "select",
30
+ options: ["start", "center", "end", "baseline", "stretch"],
31
+ description: "Vertical alignment (align-items)",
32
+ },
33
+ wrap: {
34
+ control: "select",
35
+ options: ["wrap", "nowrap", "wrap-reverse"],
36
+ description: "Flex wrap behavior",
37
+ },
38
+ alwaysProportional: {
39
+ control: "boolean",
40
+ description:
41
+ "Maintains proportional layout on tablets+ (≥480px). Columns still stack on phones (<480px).",
42
+ },
43
+ as: {
44
+ control: "select",
45
+ options: ["div", "section", "article", "ul", "ol", "nav"],
46
+ description: "Element type to render",
47
+ },
48
+ },
49
+ };
50
+
51
+ export default meta;
52
+ type Story = StoryObj<typeof meta>;
53
+
54
+ /**
55
+ * Default Row with basic two-column layout.
56
+ * Demonstrates the simplest usage with 50/50 columns.
57
+ */
58
+ export const Default: Story = {
59
+ args: {
60
+ children: (
61
+ <>
62
+ <div
63
+ className="col-6"
64
+ style={{
65
+ padding: "1rem",
66
+ background: "#e0f2fe",
67
+ border: "1px solid #0284c7",
68
+ borderRadius: "0.25rem",
69
+ }}
70
+ >
71
+ Column 1 (50%)
72
+ </div>
73
+ <div
74
+ className="col-6"
75
+ style={{
76
+ padding: "1rem",
77
+ background: "#fce7f3",
78
+ border: "1px solid #db2777",
79
+ borderRadius: "0.25rem",
80
+ }}
81
+ >
82
+ Column 2 (50%)
83
+ </div>
84
+ </>
85
+ ),
86
+ },
87
+ play: async ({ canvasElement, step }) => {
88
+ const canvas = within(canvasElement);
89
+
90
+ await step("Row renders with .col-row class", async () => {
91
+ const row = canvasElement.querySelector(".col-row");
92
+ expect(row).toBeInTheDocument();
93
+ });
94
+
95
+ await step("Columns render correctly", async () => {
96
+ expect(canvas.getByText(/Column 1/)).toBeInTheDocument();
97
+ expect(canvas.getByText(/Column 2/)).toBeInTheDocument();
98
+ });
99
+ },
100
+ };
101
+
102
+ /**
103
+ * Custom Gap - Demonstrates all gap size options.
104
+ * Shows how gap prop controls spacing between columns.
105
+ */
106
+ export const CustomGap: Story = {
107
+ args: {
108
+ gap: "xl",
109
+ children: (
110
+ <>
111
+ <div
112
+ className="col-4"
113
+ style={{
114
+ padding: "1rem",
115
+ background: "#dbeafe",
116
+ border: "1px solid #3b82f6",
117
+ borderRadius: "0.25rem",
118
+ }}
119
+ >
120
+ Column 1
121
+ </div>
122
+ <div
123
+ className="col-4"
124
+ style={{
125
+ padding: "1rem",
126
+ background: "#dbeafe",
127
+ border: "1px solid #3b82f6",
128
+ borderRadius: "0.25rem",
129
+ }}
130
+ >
131
+ Column 2
132
+ </div>
133
+ <div
134
+ className="col-4"
135
+ style={{
136
+ padding: "1rem",
137
+ background: "#dbeafe",
138
+ border: "1px solid #3b82f6",
139
+ borderRadius: "0.25rem",
140
+ }}
141
+ >
142
+ Column 3
143
+ </div>
144
+ </>
145
+ ),
146
+ },
147
+ play: async ({ canvasElement, step }) => {
148
+ await step("Row has gap-xl utility class", async () => {
149
+ const row = canvasElement.querySelector(".col-row-gap-xl");
150
+ expect(row).toBeInTheDocument();
151
+ });
152
+ },
153
+ };
154
+
155
+ /**
156
+ * Justify Content - Demonstrates horizontal alignment options.
157
+ * Shows center, end, space-between, space-around, and space-evenly.
158
+ */
159
+ export const JustifyContent: Story = {
160
+ args: {
161
+ justify: "center",
162
+ children: (
163
+ <>
164
+ <div
165
+ className="col-3"
166
+ style={{
167
+ padding: "1rem",
168
+ background: "#fef3c7",
169
+ border: "1px solid #f59e0b",
170
+ borderRadius: "0.25rem",
171
+ }}
172
+ >
173
+ Centered
174
+ </div>
175
+ <div
176
+ className="col-3"
177
+ style={{
178
+ padding: "1rem",
179
+ background: "#fef3c7",
180
+ border: "1px solid #f59e0b",
181
+ borderRadius: "0.25rem",
182
+ }}
183
+ >
184
+ Content
185
+ </div>
186
+ </>
187
+ ),
188
+ },
189
+ play: async ({ canvasElement, step }) => {
190
+ await step("Row has justify-center utility class", async () => {
191
+ const row = canvasElement.querySelector(".col-row-justify-center");
192
+ expect(row).toBeInTheDocument();
193
+ });
194
+ },
195
+ };
196
+
197
+ /**
198
+ * Align Items - Demonstrates vertical alignment options.
199
+ * Uses columns with different heights to show alignment effect.
200
+ */
201
+ export const AlignItems: Story = {
202
+ args: {
203
+ align: "center",
204
+ children: (
205
+ <>
206
+ <div
207
+ className="col-4"
208
+ style={{
209
+ padding: "1rem",
210
+ background: "#d1fae5",
211
+ border: "1px solid #10b981",
212
+ borderRadius: "0.25rem",
213
+ minHeight: "6rem",
214
+ }}
215
+ >
216
+ Tall Column
217
+ </div>
218
+ <div
219
+ className="col-4"
220
+ style={{
221
+ padding: "1rem",
222
+ background: "#d1fae5",
223
+ border: "1px solid #10b981",
224
+ borderRadius: "0.25rem",
225
+ }}
226
+ >
227
+ Short
228
+ </div>
229
+ <div
230
+ className="col-4"
231
+ style={{
232
+ padding: "1rem",
233
+ background: "#d1fae5",
234
+ border: "1px solid #10b981",
235
+ borderRadius: "0.25rem",
236
+ minHeight: "4rem",
237
+ }}
238
+ >
239
+ Medium
240
+ </div>
241
+ </>
242
+ ),
243
+ },
244
+ play: async ({ canvasElement, step }) => {
245
+ await step("Row has align-center utility class", async () => {
246
+ const row = canvasElement.querySelector(".col-row-align-center");
247
+ expect(row).toBeInTheDocument();
248
+ });
249
+ },
250
+ };
251
+
252
+ /**
253
+ * Complex Layout - Demonstrates combining multiple features.
254
+ * Shows gap, justify, align, and various column spans together.
255
+ */
256
+ export const ComplexLayout: Story = {
257
+ args: {
258
+ gap: "lg",
259
+ justify: "between",
260
+ align: "stretch",
261
+ children: (
262
+ <>
263
+ <div
264
+ className="col-3"
265
+ style={{
266
+ padding: "1rem",
267
+ background: "#e9d5ff",
268
+ border: "1px solid #a855f7",
269
+ borderRadius: "0.25rem",
270
+ }}
271
+ >
272
+ Col 3
273
+ </div>
274
+ <div
275
+ className="col-6"
276
+ style={{
277
+ padding: "1rem",
278
+ background: "#e9d5ff",
279
+ border: "1px solid #a855f7",
280
+ borderRadius: "0.25rem",
281
+ }}
282
+ >
283
+ Col 6 (Main Content)
284
+ </div>
285
+ <div
286
+ className="col-3"
287
+ style={{
288
+ padding: "1rem",
289
+ background: "#e9d5ff",
290
+ border: "1px solid #a855f7",
291
+ borderRadius: "0.25rem",
292
+ }}
293
+ >
294
+ Col 3
295
+ </div>
296
+ </>
297
+ ),
298
+ },
299
+ play: async ({ canvasElement, step }) => {
300
+ await step("Row has all utility classes", async () => {
301
+ const row = canvasElement.querySelector(
302
+ ".col-row.col-row-gap-lg.col-row-justify-between.col-row-align-stretch"
303
+ );
304
+ expect(row).toBeInTheDocument();
305
+ });
306
+ },
307
+ };
308
+
309
+ /**
310
+ * Responsive Behavior - Demonstrates mobile-first responsive behavior.
311
+ * Columns stack vertically on mobile (<48rem) and display side-by-side on desktop.
312
+ */
313
+ export const ResponsiveBehavior: Story = {
314
+ args: {
315
+ gap: "md",
316
+ children: (
317
+ <>
318
+ <div
319
+ className="col-12 col-md-4"
320
+ style={{
321
+ padding: "1rem",
322
+ background: "#fef08a",
323
+ border: "1px solid #eab308",
324
+ borderRadius: "0.25rem",
325
+ }}
326
+ >
327
+ 100% mobile, 33% desktop
328
+ </div>
329
+ <div
330
+ className="col-12 col-md-4"
331
+ style={{
332
+ padding: "1rem",
333
+ background: "#fef08a",
334
+ border: "1px solid #eab308",
335
+ borderRadius: "0.25rem",
336
+ }}
337
+ >
338
+ 100% mobile, 33% desktop
339
+ </div>
340
+ <div
341
+ className="col-12 col-md-4"
342
+ style={{
343
+ padding: "1rem",
344
+ background: "#fef08a",
345
+ border: "1px solid #eab308",
346
+ borderRadius: "0.25rem",
347
+ }}
348
+ >
349
+ 100% mobile, 33% desktop
350
+ </div>
351
+ </>
352
+ ),
353
+ },
354
+ parameters: {
355
+ docs: {
356
+ description: {
357
+ story:
358
+ "Resize the viewport to see responsive behavior. Columns stack on mobile (<768px) and display in a row on desktop (>=768px).",
359
+ },
360
+ },
361
+ },
362
+ };
363
+
364
+ /**
365
+ * Responsive Stacking - Default mobile-first behavior.
366
+ * Below 768px, columns stack vertically at 100% width.
367
+ * Demonstrates the default responsive stacking behavior.
368
+ */
369
+ export const ResponsiveStacking: Story = {
370
+ args: {
371
+ gap: "md",
372
+ children: (
373
+ <>
374
+ <div
375
+ className="col-6"
376
+ style={{
377
+ padding: "1rem",
378
+ background: "#e0e7ff",
379
+ border: "1px solid #6366f1",
380
+ borderRadius: "0.25rem",
381
+ }}
382
+ >
383
+ Column 1 (col-6)
384
+ </div>
385
+ <div
386
+ className="col-6"
387
+ style={{
388
+ padding: "1rem",
389
+ background: "#dbeafe",
390
+ border: "1px solid #3b82f6",
391
+ borderRadius: "0.25rem",
392
+ }}
393
+ >
394
+ Column 2 (col-6)
395
+ </div>
396
+ </>
397
+ ),
398
+ },
399
+ parameters: {
400
+ docs: {
401
+ description: {
402
+ story:
403
+ "Default responsive behavior. Columns stack on mobile (< 768px) and display side-by-side on desktop (≥ 768px).",
404
+ },
405
+ },
406
+ },
407
+ play: async ({ canvasElement, step }) => {
408
+ await step("Row renders without proportional class", async () => {
409
+ const row = canvasElement.querySelector(".col-row");
410
+ expect(row).toBeInTheDocument();
411
+ expect(row).not.toHaveClass("col-row-proportional");
412
+ });
413
+ },
414
+ };
415
+
416
+ /**
417
+ * Always Proportional - Maintains layout on tablets and larger.
418
+ * Columns stack on phones (< 480px) but maintain 50/50 split on tablets+ (≥ 480px).
419
+ * Prevents wrapping on tablets and desktop while still stacking on phones.
420
+ */
421
+ export const AlwaysProportional: Story = {
422
+ args: {
423
+ alwaysProportional: true,
424
+ gap: "md",
425
+ children: (
426
+ <>
427
+ <div
428
+ className="col-6"
429
+ style={{
430
+ padding: "1rem",
431
+ background: "#e0e7ff",
432
+ border: "1px solid #6366f1",
433
+ borderRadius: "0.25rem",
434
+ }}
435
+ >
436
+ Column 1 (50% on tablets+)
437
+ </div>
438
+ <div
439
+ className="col-6"
440
+ style={{
441
+ padding: "1rem",
442
+ background: "#dbeafe",
443
+ border: "1px solid #3b82f6",
444
+ borderRadius: "0.25rem",
445
+ }}
446
+ >
447
+ Column 2 (50% on tablets+)
448
+ </div>
449
+ </>
450
+ ),
451
+ },
452
+ parameters: {
453
+ docs: {
454
+ description: {
455
+ story:
456
+ "Proportional layout mode. Columns still stack on phones (< 480px) but maintain their proportional widths on tablets (≥ 480px) and larger. Resize to see the difference from default behavior.",
457
+ },
458
+ },
459
+ },
460
+ play: async ({ canvasElement, step }) => {
461
+ await step("Row has proportional class", async () => {
462
+ const row = canvasElement.querySelector(".col-row-proportional");
463
+ expect(row).toBeInTheDocument();
464
+ });
465
+ },
466
+ };
467
+
468
+ /**
469
+ * Three Column Proportional - Multiple columns with proportional layout.
470
+ * Demonstrates three-column layout that maintains proportions on tablets and larger.
471
+ */
472
+ export const ThreeColumnsProportional: Story = {
473
+ args: {
474
+ alwaysProportional: true,
475
+ gap: "sm",
476
+ children: (
477
+ <>
478
+ <div
479
+ className="col-4"
480
+ style={{
481
+ padding: "1rem",
482
+ background: "#e0e7ff",
483
+ border: "1px solid #6366f1",
484
+ borderRadius: "0.25rem",
485
+ }}
486
+ >
487
+ 33.33%
488
+ </div>
489
+ <div
490
+ className="col-4"
491
+ style={{
492
+ padding: "1rem",
493
+ background: "#dbeafe",
494
+ border: "1px solid #3b82f6",
495
+ borderRadius: "0.25rem",
496
+ }}
497
+ >
498
+ 33.33%
499
+ </div>
500
+ <div
501
+ className="col-4"
502
+ style={{
503
+ padding: "1rem",
504
+ background: "#fce7f3",
505
+ border: "1px solid #db2777",
506
+ borderRadius: "0.25rem",
507
+ }}
508
+ >
509
+ 33.33%
510
+ </div>
511
+ </>
512
+ ),
513
+ },
514
+ parameters: {
515
+ docs: {
516
+ description: {
517
+ story:
518
+ "Three-column layout with proportional mode. Columns remain in a 3-column layout on tablets and desktop, but stack on phones.",
519
+ },
520
+ },
521
+ },
522
+ play: async ({ canvasElement, step }) => {
523
+ await step("Row has proportional class", async () => {
524
+ const row = canvasElement.querySelector(".col-row-proportional");
525
+ expect(row).toBeInTheDocument();
526
+ });
527
+
528
+ await step("All three columns render", async () => {
529
+ const columns = canvasElement.querySelectorAll(".col-4");
530
+ expect(columns).toHaveLength(3);
531
+ });
532
+ },
533
+ };
534
+
535
+ /**
536
+ * Semantic HTML - Demonstrates using different element types.
537
+ * Shows Row as a <ul> with column items as <li> elements.
538
+ */
539
+ export const SemanticHTML: Story = {
540
+ args: {
541
+ as: "ul",
542
+ gap: "md",
543
+ children: (
544
+ <>
545
+ <li
546
+ className="col-4"
547
+ style={{
548
+ padding: "1rem",
549
+ background: "#fed7aa",
550
+ border: "1px solid #fb923c",
551
+ borderRadius: "0.25rem",
552
+ listStyle: "none",
553
+ }}
554
+ >
555
+ List Item 1
556
+ </li>
557
+ <li
558
+ className="col-4"
559
+ style={{
560
+ padding: "1rem",
561
+ background: "#fed7aa",
562
+ border: "1px solid #fb923c",
563
+ borderRadius: "0.25rem",
564
+ listStyle: "none",
565
+ }}
566
+ >
567
+ List Item 2
568
+ </li>
569
+ <li
570
+ className="col-4"
571
+ style={{
572
+ padding: "1rem",
573
+ background: "#fed7aa",
574
+ border: "1px solid #fb923c",
575
+ borderRadius: "0.25rem",
576
+ listStyle: "none",
577
+ }}
578
+ >
579
+ List Item 3
580
+ </li>
581
+ </>
582
+ ),
583
+ },
584
+ play: async ({ canvasElement, step }) => {
585
+ await step("Row renders as <ul> element", async () => {
586
+ const row = canvasElement.querySelector("ul.col-row");
587
+ expect(row).toBeInTheDocument();
588
+ });
589
+
590
+ await step("Children render as <li> elements", async () => {
591
+ const listItems = canvasElement.querySelectorAll("li.col-4");
592
+ expect(listItems).toHaveLength(3);
593
+ });
594
+ },
595
+ };