@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.
Files changed (63) hide show
  1. package/libs/chunk-KAR3HDXK.js +8 -0
  2. package/libs/chunk-KAR3HDXK.js.map +1 -0
  3. package/libs/chunk-M5JARVJD.cjs +18 -0
  4. package/libs/chunk-M5JARVJD.cjs.map +1 -0
  5. package/libs/components/alert/alert.min.min.css +2 -0
  6. package/libs/components/badge/badge.min.min.css +2 -0
  7. package/libs/components/box/box.min.min.css +2 -0
  8. package/libs/components/breadcrumbs/breadcrumb.min.min.css +2 -0
  9. package/libs/components/buttons/button.min.min.css +2 -0
  10. package/libs/components/card.cjs +6 -6
  11. package/libs/components/card.js +1 -1
  12. package/libs/components/cards/card-style.min.min.css +2 -0
  13. package/libs/components/cards/card.min.min.css +2 -0
  14. package/libs/components/cluster/cluster.min.min.css +2 -0
  15. package/libs/components/details/details.min.min.css +2 -0
  16. package/libs/components/dialog/dialog.min.min.css +2 -0
  17. package/libs/components/flexbox/flex.min.min.css +2 -0
  18. package/libs/components/form/form.min.min.css +2 -0
  19. package/libs/components/grid/grid.min.min.css +2 -0
  20. package/libs/components/icons/icon.min.min.css +2 -0
  21. package/libs/components/images/img.min.min.css +2 -0
  22. package/libs/components/layout/landmarks.min.min.css +2 -0
  23. package/libs/components/link/link.min.min.css +2 -0
  24. package/libs/components/list/list.min.min.css +2 -0
  25. package/libs/components/nav/nav.min.min.css +2 -0
  26. package/libs/components/progress/progress.min.min.css +2 -0
  27. package/libs/components/stack/stack.min.min.css +2 -0
  28. package/libs/components/styles/index.min.min.css +2 -0
  29. package/libs/components/tag/tag.min.min.css +2 -0
  30. package/libs/components/text-to-speech/text-to-speech.min.min.css +2 -0
  31. package/libs/index.cjs +27 -25
  32. package/libs/index.cjs.map +1 -1
  33. package/libs/index.css +1 -1
  34. package/libs/index.css.map +1 -1
  35. package/libs/index.d.cts +275 -1
  36. package/libs/index.d.ts +275 -1
  37. package/libs/index.js +10 -10
  38. package/libs/index.js.map +1 -1
  39. package/package.json +2 -2
  40. package/src/components/cards/card.stories.tsx +1 -1
  41. package/src/components/cards/card.tsx +46 -41
  42. package/src/components/col/README.mdx +532 -0
  43. package/src/components/col/col.stories.tsx +424 -0
  44. package/src/components/col/col.test.tsx +321 -0
  45. package/src/components/col/col.tsx +105 -0
  46. package/src/components/col/col.types.ts +76 -0
  47. package/src/components/row/README.mdx +324 -0
  48. package/src/components/row/row.stories.tsx +595 -0
  49. package/src/components/row/row.test.tsx +358 -0
  50. package/src/components/row/row.tsx +121 -0
  51. package/src/components/row/row.types.ts +93 -0
  52. package/src/index.scss +1 -0
  53. package/src/index.ts +2 -0
  54. package/src/sass/README.mdx +597 -0
  55. package/src/sass/_columns.scss +198 -0
  56. package/src/sass/columns.stories.tsx +456 -0
  57. package/src/styles/index.css +340 -0
  58. package/src/styles/index.css.map +1 -1
  59. package/src/types/layout-primitives.ts +61 -0
  60. package/libs/chunk-OU52NIKA.js +0 -8
  61. package/libs/chunk-OU52NIKA.js.map +0 -1
  62. package/libs/chunk-WWPLBWCQ.cjs +0 -18
  63. package/libs/chunk-WWPLBWCQ.cjs.map +0 -1
@@ -0,0 +1,321 @@
1
+ import React from "react";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { describe, it, expect } from "vitest";
4
+ import { Col } from "./col";
5
+
6
+ describe("Col Component", () => {
7
+ describe("Rendering", () => {
8
+ it("renders with default props", () => {
9
+ render(<Col>Test content</Col>);
10
+ expect(screen.getByText("Test content")).toBeInTheDocument();
11
+ });
12
+
13
+ it("renders as div by default", () => {
14
+ const { container } = render(<Col>Content</Col>);
15
+ const col = container.firstChild as HTMLElement;
16
+ expect(col.tagName).toBe("DIV");
17
+ });
18
+
19
+ it("renders as specified element type", () => {
20
+ const { container } = render(<Col as="section">Content</Col>);
21
+ const col = container.firstChild as HTMLElement;
22
+ expect(col.tagName).toBe("SECTION");
23
+ });
24
+
25
+ it("renders as li element", () => {
26
+ const { container } = render(<Col as="li">Content</Col>);
27
+ const col = container.firstChild as HTMLElement;
28
+ expect(col.tagName).toBe("LI");
29
+ });
30
+
31
+ it("renders children correctly", () => {
32
+ render(
33
+ <Col>
34
+ <span>Child 1</span>
35
+ <span>Child 2</span>
36
+ </Col>
37
+ );
38
+ expect(screen.getByText("Child 1")).toBeInTheDocument();
39
+ expect(screen.getByText("Child 2")).toBeInTheDocument();
40
+ });
41
+ });
42
+
43
+ describe("No Base Class", () => {
44
+ it("has no classes when no props provided", () => {
45
+ const { container } = render(<Col>Content</Col>);
46
+ const col = container.firstChild as HTMLElement;
47
+ expect(col.className).toBe("");
48
+ });
49
+
50
+ it("does not have a base .col class", () => {
51
+ const { container } = render(<Col span={6}>Content</Col>);
52
+ const col = container.firstChild as HTMLElement;
53
+ expect(col.classList.contains("col")).toBe(false);
54
+ });
55
+ });
56
+
57
+ describe("Span Utilities", () => {
58
+ it("applies col-1 utility class", () => {
59
+ const { container } = render(<Col span={1}>Content</Col>);
60
+ const col = container.firstChild as HTMLElement;
61
+ expect(col).toHaveClass("col-1");
62
+ });
63
+
64
+ it("applies col-6 utility class", () => {
65
+ const { container } = render(<Col span={6}>Content</Col>);
66
+ const col = container.firstChild as HTMLElement;
67
+ expect(col).toHaveClass("col-6");
68
+ });
69
+
70
+ it("applies col-12 utility class", () => {
71
+ const { container } = render(<Col span={12}>Content</Col>);
72
+ const col = container.firstChild as HTMLElement;
73
+ expect(col).toHaveClass("col-12");
74
+ });
75
+
76
+ it("does not apply span class when span is undefined", () => {
77
+ const { container } = render(<Col>Content</Col>);
78
+ const col = container.firstChild as HTMLElement;
79
+ expect(col.className).not.toMatch(/col-\d+/);
80
+ });
81
+
82
+ // Test all span values
83
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].forEach((spanValue) => {
84
+ it(`applies col-${spanValue} for span={${spanValue}}`, () => {
85
+ const { container } = render(<Col span={spanValue as 1}>Content</Col>);
86
+ const col = container.firstChild as HTMLElement;
87
+ expect(col).toHaveClass(`col-${spanValue}`);
88
+ });
89
+ });
90
+ });
91
+
92
+ describe("Auto Width", () => {
93
+ it("applies col-auto utility class", () => {
94
+ const { container } = render(<Col auto>Content</Col>);
95
+ const col = container.firstChild as HTMLElement;
96
+ expect(col).toHaveClass("col-auto");
97
+ });
98
+
99
+ it("auto overrides span when both provided", () => {
100
+ const { container } = render(<Col auto span={6}>Content</Col>);
101
+ const col = container.firstChild as HTMLElement;
102
+ expect(col).toHaveClass("col-auto");
103
+ expect(col).not.toHaveClass("col-6");
104
+ });
105
+
106
+ it("does not apply auto class when auto is false", () => {
107
+ const { container } = render(<Col auto={false} span={6}>Content</Col>);
108
+ const col = container.firstChild as HTMLElement;
109
+ expect(col).not.toHaveClass("col-auto");
110
+ expect(col).toHaveClass("col-6");
111
+ });
112
+ });
113
+
114
+ describe("Offset Utilities", () => {
115
+ it("applies col-offset-0 utility class", () => {
116
+ const { container } = render(<Col offset={0}>Content</Col>);
117
+ const col = container.firstChild as HTMLElement;
118
+ expect(col).toHaveClass("col-offset-0");
119
+ });
120
+
121
+ it("applies col-offset-3 utility class", () => {
122
+ const { container } = render(<Col offset={3}>Content</Col>);
123
+ const col = container.firstChild as HTMLElement;
124
+ expect(col).toHaveClass("col-offset-3");
125
+ });
126
+
127
+ it("applies col-offset-11 utility class", () => {
128
+ const { container } = render(<Col offset={11}>Content</Col>);
129
+ const col = container.firstChild as HTMLElement;
130
+ expect(col).toHaveClass("col-offset-11");
131
+ });
132
+
133
+ it("does not apply offset class when offset is undefined", () => {
134
+ const { container } = render(<Col span={6}>Content</Col>);
135
+ const col = container.firstChild as HTMLElement;
136
+ expect(col.className).not.toMatch(/col-offset-/);
137
+ });
138
+
139
+ // Test all offset values
140
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].forEach((offsetValue) => {
141
+ it(`applies col-offset-${offsetValue} for offset={${offsetValue}}`, () => {
142
+ const { container } = render(
143
+ <Col offset={offsetValue as 0}>Content</Col>
144
+ );
145
+ const col = container.firstChild as HTMLElement;
146
+ expect(col).toHaveClass(`col-offset-${offsetValue}`);
147
+ });
148
+ });
149
+ });
150
+
151
+ describe("Order Utilities", () => {
152
+ it("applies col-order-first utility class", () => {
153
+ const { container } = render(<Col order="first">Content</Col>);
154
+ const col = container.firstChild as HTMLElement;
155
+ expect(col).toHaveClass("col-order-first");
156
+ });
157
+
158
+ it("applies col-order-last utility class", () => {
159
+ const { container } = render(<Col order="last">Content</Col>);
160
+ const col = container.firstChild as HTMLElement;
161
+ expect(col).toHaveClass("col-order-last");
162
+ });
163
+
164
+ it("applies col-order-0 utility class", () => {
165
+ const { container } = render(<Col order={0}>Content</Col>);
166
+ const col = container.firstChild as HTMLElement;
167
+ expect(col).toHaveClass("col-order-0");
168
+ });
169
+
170
+ it("applies col-order-5 utility class", () => {
171
+ const { container } = render(<Col order={5}>Content</Col>);
172
+ const col = container.firstChild as HTMLElement;
173
+ expect(col).toHaveClass("col-order-5");
174
+ });
175
+
176
+ it("applies col-order-12 utility class", () => {
177
+ const { container } = render(<Col order={12}>Content</Col>);
178
+ const col = container.firstChild as HTMLElement;
179
+ expect(col).toHaveClass("col-order-12");
180
+ });
181
+
182
+ it("does not apply order class when order is undefined", () => {
183
+ const { container } = render(<Col span={6}>Content</Col>);
184
+ const col = container.firstChild as HTMLElement;
185
+ expect(col.className).not.toMatch(/col-order-/);
186
+ });
187
+
188
+ // Test numeric order values
189
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].forEach((orderValue) => {
190
+ it(`applies col-order-${orderValue} for order={${orderValue}}`, () => {
191
+ const { container } = render(
192
+ <Col order={orderValue as 0}>Content</Col>
193
+ );
194
+ const col = container.firstChild as HTMLElement;
195
+ expect(col).toHaveClass(`col-order-${orderValue}`);
196
+ });
197
+ });
198
+ });
199
+
200
+ describe("Combined Props", () => {
201
+ it("applies span and offset together", () => {
202
+ const { container } = render(<Col span={6} offset={3}>Content</Col>);
203
+ const col = container.firstChild as HTMLElement;
204
+ expect(col).toHaveClass("col-6");
205
+ expect(col).toHaveClass("col-offset-3");
206
+ });
207
+
208
+ it("applies span and order together", () => {
209
+ const { container } = render(<Col span={4} order={2}>Content</Col>);
210
+ const col = container.firstChild as HTMLElement;
211
+ expect(col).toHaveClass("col-4");
212
+ expect(col).toHaveClass("col-order-2");
213
+ });
214
+
215
+ it("applies span, offset, and order together", () => {
216
+ const { container } = render(
217
+ <Col span={4} offset={2} order="first">
218
+ Content
219
+ </Col>
220
+ );
221
+ const col = container.firstChild as HTMLElement;
222
+ expect(col).toHaveClass("col-4");
223
+ expect(col).toHaveClass("col-offset-2");
224
+ expect(col).toHaveClass("col-order-first");
225
+ });
226
+
227
+ it("applies auto, offset, and order together", () => {
228
+ const { container } = render(
229
+ <Col auto offset={1} order="last">
230
+ Content
231
+ </Col>
232
+ );
233
+ const col = container.firstChild as HTMLElement;
234
+ expect(col).toHaveClass("col-auto");
235
+ expect(col).toHaveClass("col-offset-1");
236
+ expect(col).toHaveClass("col-order-last");
237
+ });
238
+ });
239
+
240
+ describe("Custom Classes", () => {
241
+ it("merges className prop with utility classes", () => {
242
+ const { container } = render(
243
+ <Col className="custom-class" span={6}>
244
+ Content
245
+ </Col>
246
+ );
247
+ const col = container.firstChild as HTMLElement;
248
+ expect(col).toHaveClass("col-6");
249
+ expect(col).toHaveClass("custom-class");
250
+ });
251
+
252
+ it("merges classes prop with utility classes", () => {
253
+ const { container } = render(
254
+ <Col classes="another-class" span={4}>
255
+ Content
256
+ </Col>
257
+ );
258
+ const col = container.firstChild as HTMLElement;
259
+ expect(col).toHaveClass("col-4");
260
+ expect(col).toHaveClass("another-class");
261
+ });
262
+
263
+ it("merges both className and classes props", () => {
264
+ const { container } = render(
265
+ <Col className="class-one" classes="class-two" span={6}>
266
+ Content
267
+ </Col>
268
+ );
269
+ const col = container.firstChild as HTMLElement;
270
+ expect(col).toHaveClass("col-6");
271
+ expect(col).toHaveClass("class-one");
272
+ expect(col).toHaveClass("class-two");
273
+ });
274
+
275
+ it("allows custom classes without utility props", () => {
276
+ const { container } = render(
277
+ <Col className="custom-only">Content</Col>
278
+ );
279
+ const col = container.firstChild as HTMLElement;
280
+ expect(col).toHaveClass("custom-only");
281
+ });
282
+ });
283
+
284
+ describe("Ref Forwarding", () => {
285
+ it("forwards ref to the underlying element", () => {
286
+ const ref = { current: null };
287
+ render(<Col ref={ref}>Content</Col>);
288
+ expect(ref.current).toBeInstanceOf(HTMLDivElement);
289
+ });
290
+
291
+ it("forwards ref with custom element type", () => {
292
+ const ref = { current: null };
293
+ render(
294
+ <Col ref={ref} as="section">
295
+ Content
296
+ </Col>
297
+ );
298
+ expect(ref.current).toBeInstanceOf(HTMLElement);
299
+ expect((ref.current as unknown as HTMLElement).tagName).toBe("SECTION");
300
+ });
301
+ });
302
+
303
+ describe("Additional Props", () => {
304
+ it("passes through additional HTML attributes", () => {
305
+ const { container } = render(
306
+ <Col data-testid="test-col" aria-label="Test Column" span={6}>
307
+ Content
308
+ </Col>
309
+ );
310
+ const col = container.firstChild as HTMLElement;
311
+ expect(col).toHaveAttribute("data-testid", "test-col");
312
+ expect(col).toHaveAttribute("aria-label", "Test Column");
313
+ });
314
+
315
+ it("handles id prop", () => {
316
+ const { container } = render(<Col id="my-col" span={6}>Content</Col>);
317
+ const col = container.firstChild as HTMLElement;
318
+ expect(col).toHaveAttribute("id", "my-col");
319
+ });
320
+ });
321
+ });
@@ -0,0 +1,105 @@
1
+ import React from "react";
2
+ import UI from "../ui";
3
+ import type { ColProps } from "./col.types";
4
+
5
+ // Re-export types for convenience
6
+ export type { ColProps } from "./col.types";
7
+
8
+ /**
9
+ * Col - A column component for 12-column layouts.
10
+ *
11
+ * Col provides a type-safe React wrapper around column utility classes,
12
+ * allowing developers to create responsive columns with span, offset, order,
13
+ * and auto-width options. Unlike Row, Col has no base class - it's pure
14
+ * utility class composition.
15
+ *
16
+ * ## Key Features
17
+ * - **No base class**: Pure utility class mapping (follows Grid.Item pattern)
18
+ * - **Span control**: 1-12 column widths via span prop
19
+ * - **Offset positioning**: Push columns right with offset prop
20
+ * - **Visual reordering**: Change order with order prop
21
+ * - **Auto-width**: Content-based width with auto prop
22
+ * - **Polymorphic**: Render as any semantic HTML element
23
+ * - **Type-Safe**: Full TypeScript support with literal types
24
+ *
25
+ * ## Use Cases
26
+ * - Responsive column layouts
27
+ * - Grid-based designs
28
+ * - Content positioning
29
+ * - Visual reordering
30
+ *
31
+ * @example
32
+ * // Basic 50% column
33
+ * <Col span={6}>Half width column</Col>
34
+ *
35
+ * @example
36
+ * // Centered column with offset
37
+ * <Col span={6} offset={3}>Centered column</Col>
38
+ *
39
+ * @example
40
+ * // Auto-width column
41
+ * <Col auto>Content-based width</Col>
42
+ *
43
+ * @example
44
+ * // Reordered column
45
+ * <Col span={6} order="first">Appears first visually</Col>
46
+ *
47
+ * @example
48
+ * // Semantic HTML
49
+ * <Row as="ul">
50
+ * <Col as="li" span={4}>List item</Col>
51
+ * </Row>
52
+ *
53
+ * @see {@link ColProps} for complete props documentation
54
+ */
55
+ export const Col = React.forwardRef<HTMLElement, ColProps>(
56
+ (
57
+ {
58
+ span,
59
+ offset,
60
+ order,
61
+ auto = false,
62
+ as = "div",
63
+ className,
64
+ classes,
65
+ children,
66
+ ...props
67
+ },
68
+ ref
69
+ ) => {
70
+ // Build utility classes array - NO base class
71
+ const utilityClasses: string[] = [];
72
+
73
+ // Auto takes precedence over span
74
+ if (auto) {
75
+ utilityClasses.push("col-auto");
76
+ } else if (span) {
77
+ utilityClasses.push(`col-${span}`);
78
+ }
79
+
80
+ // Offset utilities
81
+ if (offset !== undefined) {
82
+ utilityClasses.push(`col-offset-${offset}`);
83
+ }
84
+
85
+ // Order utilities
86
+ if (order !== undefined) {
87
+ utilityClasses.push(`col-order-${order}`);
88
+ }
89
+
90
+ // Merge all classes: utilities + className + classes
91
+ const allClasses = [...utilityClasses, className, classes]
92
+ .filter(Boolean)
93
+ .join(" ");
94
+
95
+ return (
96
+ <UI as={as} ref={ref} classes={allClasses} {...props}>
97
+ {children}
98
+ </UI>
99
+ );
100
+ }
101
+ );
102
+
103
+ Col.displayName = "Col";
104
+
105
+ export default Col;
@@ -0,0 +1,76 @@
1
+ import type { ComponentProps } from "../../types/component-props";
2
+ import type {
3
+ ColElement,
4
+ ColumnSpan,
5
+ ColumnOffset,
6
+ ColumnOrder,
7
+ } from "../../types/layout-primitives";
8
+
9
+ /**
10
+ * Props for the Col component
11
+ *
12
+ * Col provides a column element for use within Row containers. Maps React
13
+ * props to column utility classes (.col-*, .col-offset-*, .col-order-*,
14
+ * .col-auto) without a base class. Pure utility class composition.
15
+ *
16
+ * @example
17
+ * // Basic column with 50% width
18
+ * <Col span={6}>Column content</Col>
19
+ *
20
+ * @example
21
+ * // Column with offset and order
22
+ * <Col span={4} offset={2} order={1}>
23
+ * Offset and reordered
24
+ * </Col>
25
+ */
26
+ export interface ColProps
27
+ extends Partial<ComponentProps>,
28
+ Omit<React.HTMLAttributes<HTMLElement>, "className"> {
29
+ /**
30
+ * Column span (1-12)
31
+ * Maps to .col-{span} utility class
32
+ * Ignored if auto is true
33
+ * @default undefined
34
+ */
35
+ span?: ColumnSpan;
36
+
37
+ /**
38
+ * Column offset (0-11)
39
+ * Pushes column to the right using margin-inline-start
40
+ * Maps to .col-offset-{offset} utility class
41
+ * @default undefined
42
+ */
43
+ offset?: ColumnOffset;
44
+
45
+ /**
46
+ * Column order
47
+ * Controls visual order using flexbox order property
48
+ * Maps to .col-order-{order} utility class
49
+ * @default undefined
50
+ */
51
+ order?: ColumnOrder;
52
+
53
+ /**
54
+ * Auto-width column
55
+ * When true, uses .col-auto (content-based width)
56
+ * Takes precedence over span prop
57
+ * @default false
58
+ */
59
+ auto?: boolean;
60
+
61
+ /**
62
+ * Element type to render
63
+ * @default "div"
64
+ */
65
+ as?: ColElement;
66
+
67
+ /**
68
+ * Additional CSS classes
69
+ */
70
+ className?: string;
71
+
72
+ /**
73
+ * Child elements
74
+ */
75
+ children?: React.ReactNode;
76
+ }