@fpkit/acss 3.1.0 → 3.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/libs/{chunk-2NRIP6RB.cjs → chunk-2C3YLBWP.cjs} +3 -3
- package/libs/{chunk-NWJDAHP6.cjs → chunk-2GJHKWEK.cjs} +3 -3
- package/libs/{chunk-FVROL3V5.js → chunk-2JCDEC32.js} +3 -3
- package/libs/{chunk-IRLFZ3OL.js → chunk-3XJC4XUG.js} +2 -2
- package/libs/{chunk-23ANBDCR.js → chunk-4I5MF54P.js} +3 -3
- package/libs/chunk-4I5MF54P.js.map +1 -0
- package/libs/chunk-5CJPTDK3.cjs +31 -0
- package/libs/chunk-5CJPTDK3.cjs.map +1 -0
- package/libs/{chunk-E4OSROCA.cjs → chunk-5QSNJQVH.cjs} +3 -3
- package/libs/{chunk-O3JIHC5M.cjs → chunk-6BUJZ4DJ.cjs} +3 -3
- package/libs/{chunk-WXBFBWYF.cjs → chunk-AFINOD2L.cjs} +3 -3
- package/libs/{chunk-HRRHPLER.js → chunk-AWZLSWDO.js} +2 -2
- package/libs/chunk-DDSXKOUB.js +7 -0
- package/libs/chunk-DDSXKOUB.js.map +1 -0
- package/libs/{chunk-CWRNJA4P.js → chunk-DIJBIOFE.js} +3 -3
- package/libs/chunk-EJ6KYBFE.cjs +13 -0
- package/libs/chunk-EJ6KYBFE.cjs.map +1 -0
- package/libs/{chunk-GUJSMQ3V.cjs → chunk-EKJYOCLY.cjs} +3 -3
- package/libs/{chunk-X5RKCLDC.cjs → chunk-F64GE6RG.cjs} +4 -4
- package/libs/chunk-FMIM3332.js +8 -0
- package/libs/chunk-FMIM3332.js.map +1 -0
- package/libs/{chunk-5RAWNUVD.js → chunk-IBUTNPTQ.js} +2 -2
- package/libs/chunk-IWP4VJEP.cjs +18 -0
- package/libs/chunk-IWP4VJEP.cjs.map +1 -0
- package/libs/{chunk-ZFJ4U45S.js → chunk-KDMX3FAW.js} +2 -2
- package/libs/{chunk-DYFAUAB7.cjs → chunk-LXODKKA3.cjs} +4 -4
- package/libs/chunk-M7JLT62Q.js +9 -0
- package/libs/chunk-M7JLT62Q.js.map +1 -0
- package/libs/{chunk-IQ76HGVP.js → chunk-MBWI67UT.js} +2 -2
- package/libs/{chunk-O5XAJ7BY.cjs → chunk-NCGVF2QS.cjs} +4 -4
- package/libs/{chunk-W2UIN7EV.cjs → chunk-NPWHQVYB.cjs} +3 -3
- package/libs/{chunk-G55UJ53G.cjs → chunk-NZVSXRTB.cjs} +3 -3
- package/libs/chunk-NZVSXRTB.cjs.map +1 -0
- package/libs/{chunk-43TK2ICH.js → chunk-PMWL5XZ4.js} +3 -3
- package/libs/{chunk-KVKQLRJG.js → chunk-TF3GQKOY.js} +2 -2
- package/libs/chunk-TNEJXNZA.cjs +22 -0
- package/libs/chunk-TNEJXNZA.cjs.map +1 -0
- package/libs/{chunk-IEB64SWY.js → chunk-U5VA34SU.js} +2 -2
- package/libs/chunk-UGMP72J2.js +8 -0
- package/libs/chunk-UGMP72J2.js.map +1 -0
- package/libs/{chunk-MGPWZRBX.cjs → chunk-URBGDUFN.cjs} +6 -6
- package/libs/{chunk-QKHPHMG2.js → chunk-ZF6Y7W57.js} +5 -5
- package/libs/component-props-50e69975.d.ts +66 -0
- package/libs/components/box/box.css +1 -0
- package/libs/components/box/box.css.map +1 -0
- package/libs/components/box/box.min.css +3 -0
- package/libs/components/breadcrumbs/breadcrumb.cjs +6 -6
- package/libs/components/breadcrumbs/breadcrumb.js +3 -3
- package/libs/components/button.cjs +4 -4
- package/libs/components/button.d.cts +10 -3
- package/libs/components/button.d.ts +10 -3
- package/libs/components/button.js +2 -2
- package/libs/components/card.cjs +7 -7
- package/libs/components/card.d.cts +13 -85
- package/libs/components/card.d.ts +13 -85
- package/libs/components/card.js +2 -2
- package/libs/components/cards/card.css +1 -1
- package/libs/components/cards/card.css.map +1 -1
- package/libs/components/cards/card.min.css +2 -2
- package/libs/components/cluster/cluster.css +1 -0
- package/libs/components/cluster/cluster.css.map +1 -0
- package/libs/components/cluster/cluster.min.css +3 -0
- package/libs/components/dialog/dialog.cjs +7 -7
- package/libs/components/dialog/dialog.js +5 -5
- package/libs/components/form/fields.cjs +4 -4
- package/libs/components/form/fields.js +2 -2
- package/libs/components/form/textarea.cjs +4 -4
- package/libs/components/form/textarea.js +2 -2
- package/libs/components/grid/grid.css +1 -0
- package/libs/components/grid/grid.css.map +1 -0
- package/libs/components/grid/grid.min.css +3 -0
- package/libs/components/heading/heading.cjs +3 -3
- package/libs/components/heading/heading.js +2 -2
- package/libs/components/icons/icon.cjs +4 -4
- package/libs/components/icons/icon.d.cts +2 -2
- package/libs/components/icons/icon.d.ts +2 -2
- package/libs/components/icons/icon.js +2 -2
- package/libs/components/link/link.cjs +6 -6
- package/libs/components/link/link.js +2 -2
- package/libs/components/list/list.cjs +5 -5
- package/libs/components/list/list.js +2 -2
- package/libs/components/modal.cjs +4 -4
- package/libs/components/modal.d.cts +1 -1
- package/libs/components/modal.d.ts +1 -1
- package/libs/components/modal.js +3 -3
- package/libs/components/nav/nav.cjs +7 -7
- package/libs/components/nav/nav.js +3 -3
- package/libs/components/popover/popover.cjs +4 -4
- package/libs/components/popover/popover.d.cts +1 -1
- package/libs/components/popover/popover.d.ts +1 -1
- package/libs/components/popover/popover.js +1 -1
- package/libs/components/stack/stack.css +1 -0
- package/libs/components/stack/stack.css.map +1 -0
- package/libs/components/stack/stack.min.css +3 -0
- package/libs/components/tables/table.cjs +4 -4
- package/libs/components/tables/table.d.cts +2 -2
- package/libs/components/tables/table.d.ts +2 -2
- package/libs/components/tables/table.js +1 -1
- package/libs/components/text/text.cjs +5 -5
- package/libs/components/text/text.js +2 -2
- package/libs/hooks.cjs +4 -4
- package/libs/hooks.js +3 -3
- package/libs/{icons-287fce3a.d.ts → icons-df8e744f.d.ts} +1 -1
- package/libs/icons.cjs +3 -3
- package/libs/icons.d.cts +2 -2
- package/libs/icons.d.ts +2 -2
- package/libs/icons.js +2 -2
- package/libs/index.cjs +74 -73
- 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 +925 -6
- package/libs/index.d.ts +925 -6
- package/libs/index.js +30 -30
- package/libs/index.js.map +1 -1
- package/package.json +2 -2
- package/src/App.tsx +1 -3
- package/src/components/alert/STYLES.mdx +790 -0
- package/src/components/badge/STYLES.mdx +610 -0
- package/src/components/box/README.mdx +401 -0
- package/src/components/box/STYLES.mdx +360 -0
- package/src/components/box/box.scss +245 -0
- package/src/components/box/box.stories.tsx +395 -0
- package/src/components/box/box.test.tsx +425 -0
- package/src/components/box/box.tsx +170 -0
- package/src/components/box/box.types.ts +166 -0
- package/src/components/breadcrumbs/STYLES.mdx +99 -0
- package/src/components/breadcrumbs/bc-item.tsx +0 -1
- package/src/components/buttons/STYLES.mdx +766 -0
- package/src/components/cards/STYLES.mdx +835 -0
- package/src/components/cards/card.scss +29 -21
- package/src/components/cards/card.tsx +13 -3
- package/src/components/cards/card.types.ts +13 -0
- package/src/components/cluster/README.mdx +595 -0
- package/src/components/cluster/STYLES.mdx +626 -0
- package/src/components/cluster/cluster.scss +86 -0
- package/src/components/cluster/cluster.stories.tsx +385 -0
- package/src/components/cluster/cluster.test.tsx +655 -0
- package/src/components/cluster/cluster.tsx +94 -0
- package/src/components/cluster/cluster.types.ts +75 -0
- package/src/components/details/STYLES.mdx +445 -0
- package/src/components/dialog/STYLES.mdx +888 -0
- package/src/components/flexbox/STYLES.mdx +857 -0
- package/src/components/flexbox/flex.stories.tsx +842 -141
- package/src/components/flexbox/flex.types.ts +25 -6
- package/src/components/form/STYLES.mdx +821 -0
- package/src/components/grid/README.mdx +709 -0
- package/src/components/grid/STYLES.mdx +785 -0
- package/src/components/grid/grid.scss +287 -0
- package/src/components/grid/grid.stories.tsx +486 -0
- package/src/components/grid/grid.test.tsx +981 -0
- package/src/components/grid/grid.tsx +222 -0
- package/src/components/grid/grid.types.ts +344 -0
- package/src/components/icons/STYLES.mdx +56 -0
- package/src/components/icons/components/arrow-right.tsx +0 -5
- package/src/components/images/STYLES.mdx +75 -0
- package/src/components/kit.tsx +8 -4
- package/src/components/layout/STYLES.mdx +556 -0
- package/src/components/link/STYLES.mdx +75 -0
- package/src/components/list/STYLES.mdx +631 -0
- package/src/components/nav/STYLES.mdx +460 -0
- package/src/components/popover/popover.tsx +1 -1
- package/src/components/progress/STYLES.mdx +64 -0
- package/src/components/stack/README.mdx +400 -0
- package/src/components/stack/STYLES.mdx +414 -0
- package/src/components/stack/stack.scss +109 -0
- package/src/components/stack/stack.stories.tsx +559 -0
- package/src/components/stack/stack.test.tsx +426 -0
- package/src/components/stack/stack.tsx +141 -0
- package/src/components/stack/stack.types.ts +133 -0
- package/src/components/tables/table-elements.tsx +1 -1
- package/src/components/tables/table.tsx +2 -2
- package/src/components/tag/STYLES.mdx +105 -0
- package/src/components/text-to-speech/STYLES.mdx +80 -0
- package/src/components/text-to-speech/TextToSpeech.tsx +0 -4
- package/src/components/text-to-speech/useTextToSpeech.tsx +2 -6
- package/src/components/ui.tsx +3 -3
- package/src/decorators/instructions.tsx +22 -18
- package/src/hooks/popover/popover.tsx +1 -1
- package/src/index.scss +5 -1
- package/src/index.ts +305 -12
- package/src/sass/GLOBALS-STYLES.md +631 -0
- package/src/sass/_globals.scss +45 -24
- package/src/styles/box/box.css +220 -0
- package/src/styles/box/box.css.map +1 -0
- package/src/styles/cards/card.css +22 -17
- package/src/styles/cards/card.css.map +1 -1
- package/src/styles/cluster/cluster.css +71 -0
- package/src/styles/cluster/cluster.css.map +1 -0
- package/src/styles/grid/grid.css +238 -0
- package/src/styles/grid/grid.css.map +1 -0
- package/src/styles/index.css +667 -49
- package/src/styles/index.css.map +1 -1
- package/src/styles/stack/stack.css +86 -0
- package/src/styles/stack/stack.css.map +1 -0
- package/src/types/component-props.ts +42 -13
- package/src/types/layout-primitives.ts +48 -0
- package/src/types/shared.ts +10 -26
- package/libs/chunk-23ANBDCR.js.map +0 -1
- package/libs/chunk-5QD3DWFI.js +0 -9
- package/libs/chunk-5QD3DWFI.js.map +0 -1
- package/libs/chunk-6WTC4JXH.cjs +0 -31
- package/libs/chunk-6WTC4JXH.cjs.map +0 -1
- package/libs/chunk-ENTCUJ3A.cjs +0 -13
- package/libs/chunk-ENTCUJ3A.cjs.map +0 -1
- package/libs/chunk-G55UJ53G.cjs.map +0 -1
- package/libs/chunk-HHLNOC5T.js +0 -7
- package/libs/chunk-HHLNOC5T.js.map +0 -1
- package/libs/chunk-KK47SYZI.js +0 -8
- package/libs/chunk-KK47SYZI.js.map +0 -1
- package/libs/chunk-US2I5GI7.cjs +0 -22
- package/libs/chunk-US2I5GI7.cjs.map +0 -1
- package/libs/chunk-W5TKWBFC.cjs +0 -18
- package/libs/chunk-W5TKWBFC.cjs.map +0 -1
- package/libs/chunk-Y2PFDELK.js +0 -8
- package/libs/chunk-Y2PFDELK.js.map +0 -1
- package/libs/component-props-67d978a2.d.ts +0 -38
- /package/libs/{chunk-2NRIP6RB.cjs.map → chunk-2C3YLBWP.cjs.map} +0 -0
- /package/libs/{chunk-NWJDAHP6.cjs.map → chunk-2GJHKWEK.cjs.map} +0 -0
- /package/libs/{chunk-FVROL3V5.js.map → chunk-2JCDEC32.js.map} +0 -0
- /package/libs/{chunk-IRLFZ3OL.js.map → chunk-3XJC4XUG.js.map} +0 -0
- /package/libs/{chunk-E4OSROCA.cjs.map → chunk-5QSNJQVH.cjs.map} +0 -0
- /package/libs/{chunk-O3JIHC5M.cjs.map → chunk-6BUJZ4DJ.cjs.map} +0 -0
- /package/libs/{chunk-WXBFBWYF.cjs.map → chunk-AFINOD2L.cjs.map} +0 -0
- /package/libs/{chunk-HRRHPLER.js.map → chunk-AWZLSWDO.js.map} +0 -0
- /package/libs/{chunk-CWRNJA4P.js.map → chunk-DIJBIOFE.js.map} +0 -0
- /package/libs/{chunk-GUJSMQ3V.cjs.map → chunk-EKJYOCLY.cjs.map} +0 -0
- /package/libs/{chunk-X5RKCLDC.cjs.map → chunk-F64GE6RG.cjs.map} +0 -0
- /package/libs/{chunk-5RAWNUVD.js.map → chunk-IBUTNPTQ.js.map} +0 -0
- /package/libs/{chunk-ZFJ4U45S.js.map → chunk-KDMX3FAW.js.map} +0 -0
- /package/libs/{chunk-DYFAUAB7.cjs.map → chunk-LXODKKA3.cjs.map} +0 -0
- /package/libs/{chunk-IQ76HGVP.js.map → chunk-MBWI67UT.js.map} +0 -0
- /package/libs/{chunk-O5XAJ7BY.cjs.map → chunk-NCGVF2QS.cjs.map} +0 -0
- /package/libs/{chunk-W2UIN7EV.cjs.map → chunk-NPWHQVYB.cjs.map} +0 -0
- /package/libs/{chunk-43TK2ICH.js.map → chunk-PMWL5XZ4.js.map} +0 -0
- /package/libs/{chunk-KVKQLRJG.js.map → chunk-TF3GQKOY.js.map} +0 -0
- /package/libs/{chunk-IEB64SWY.js.map → chunk-U5VA34SU.js.map} +0 -0
- /package/libs/{chunk-MGPWZRBX.cjs.map → chunk-URBGDUFN.cjs.map} +0 -0
- /package/libs/{chunk-QKHPHMG2.js.map → chunk-ZF6Y7W57.js.map} +0 -0
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
import { Meta } from '@storybook/addon-docs/blocks';
|
|
2
|
+
import * as ClusterStories from './cluster.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={ClusterStories} title="Styles/Cluster" />
|
|
5
|
+
|
|
6
|
+
# Cluster Component Styles
|
|
7
|
+
|
|
8
|
+
Complete CSS reference for the Cluster layout primitive component.
|
|
9
|
+
|
|
10
|
+
## CSS Architecture
|
|
11
|
+
|
|
12
|
+
The Cluster component uses a **utility-class system** with CSS custom properties for theming. All spacing values use the unified spacing scale with fluid `clamp()` for responsive design.
|
|
13
|
+
|
|
14
|
+
**Key Characteristics:**
|
|
15
|
+
- **Zero Runtime:** All styling via CSS classes (no JavaScript)
|
|
16
|
+
- **Fluid Spacing:** CSS clamp() for responsive gaps without media queries
|
|
17
|
+
- **Rem Units:** All measurements in rem (1rem = 16px base)
|
|
18
|
+
- **CSS Variables:** Themable via CSS custom properties
|
|
19
|
+
|
|
20
|
+
## Base Styles
|
|
21
|
+
|
|
22
|
+
### `.cluster`
|
|
23
|
+
|
|
24
|
+
Base flexbox container with wrapping enabled.
|
|
25
|
+
|
|
26
|
+
```css
|
|
27
|
+
.cluster {
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-wrap: wrap;
|
|
30
|
+
gap: var(--spacing-sm); /* Default: clamp(0.5rem, 0.45rem + 0.35vw, 0.75rem) */
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Default Behavior:**
|
|
35
|
+
- Displays items in a horizontal row
|
|
36
|
+
- Wraps items to next line when container width is exceeded
|
|
37
|
+
- Default gap: `--spacing-sm` (8-12px responsive)
|
|
38
|
+
|
|
39
|
+
## Gap Utilities
|
|
40
|
+
|
|
41
|
+
Control spacing between items using the unified spacing scale.
|
|
42
|
+
|
|
43
|
+
### `.cluster-gap-0`
|
|
44
|
+
|
|
45
|
+
Remove all gap spacing.
|
|
46
|
+
|
|
47
|
+
```css
|
|
48
|
+
.cluster-gap-0 {
|
|
49
|
+
gap: 0;
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Usage:** `<Cluster gap="0">`
|
|
54
|
+
**Value:** `0`
|
|
55
|
+
|
|
56
|
+
### `.cluster-gap-xs`
|
|
57
|
+
|
|
58
|
+
Extra small gap spacing.
|
|
59
|
+
|
|
60
|
+
```css
|
|
61
|
+
.cluster-gap-xs {
|
|
62
|
+
gap: var(--spacing-xs);
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Usage:** `<Cluster gap="xs">`
|
|
67
|
+
**Value:** `clamp(0.25rem, 0.2rem + 0.25vw, 0.5rem)` (4-8px)
|
|
68
|
+
**Use Case:** Tight spacing for badges or compact tags
|
|
69
|
+
|
|
70
|
+
### `.cluster-gap-sm`
|
|
71
|
+
|
|
72
|
+
Small gap spacing.
|
|
73
|
+
|
|
74
|
+
```css
|
|
75
|
+
.cluster-gap-sm {
|
|
76
|
+
gap: var(--spacing-sm);
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Usage:** `<Cluster gap="sm">`
|
|
81
|
+
**Value:** `clamp(0.5rem, 0.45rem + 0.35vw, 0.75rem)` (8-12px)
|
|
82
|
+
**Use Case:** Default for tag clouds and keyword lists
|
|
83
|
+
|
|
84
|
+
### `.cluster-gap-md`
|
|
85
|
+
|
|
86
|
+
Medium gap spacing.
|
|
87
|
+
|
|
88
|
+
```css
|
|
89
|
+
.cluster-gap-md {
|
|
90
|
+
gap: var(--spacing-md);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Usage:** `<Cluster gap="md">`
|
|
95
|
+
**Value:** `clamp(0.75rem, 0.65rem + 0.45vw, 1.125rem)` (12-18px)
|
|
96
|
+
**Use Case:** Button groups and navigation links
|
|
97
|
+
|
|
98
|
+
### `.cluster-gap-lg`
|
|
99
|
+
|
|
100
|
+
Large gap spacing.
|
|
101
|
+
|
|
102
|
+
```css
|
|
103
|
+
.cluster-gap-lg {
|
|
104
|
+
gap: var(--spacing-lg);
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Usage:** `<Cluster gap="lg">`
|
|
109
|
+
**Value:** `clamp(1rem, 0.85rem + 0.6vw, 1.5rem)` (16-24px)
|
|
110
|
+
**Use Case:** Spacious navigation or large buttons
|
|
111
|
+
|
|
112
|
+
### `.cluster-gap-xl`
|
|
113
|
+
|
|
114
|
+
Extra large gap spacing.
|
|
115
|
+
|
|
116
|
+
```css
|
|
117
|
+
.cluster-gap-xl {
|
|
118
|
+
gap: var(--spacing-xl);
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Usage:** `<Cluster gap="xl">`
|
|
123
|
+
**Value:** `clamp(1.5rem, 1.25rem + 0.75vw, 2rem)` (24-32px)
|
|
124
|
+
**Use Case:** Very spacious layouts with large items
|
|
125
|
+
|
|
126
|
+
## Justify Utilities
|
|
127
|
+
|
|
128
|
+
Control horizontal alignment of items (justify-content).
|
|
129
|
+
|
|
130
|
+
### `.cluster-justify-start`
|
|
131
|
+
|
|
132
|
+
Align items to the start (left in LTR).
|
|
133
|
+
|
|
134
|
+
```css
|
|
135
|
+
.cluster-justify-start {
|
|
136
|
+
justify-content: flex-start;
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Usage:** `<Cluster justify="start">`
|
|
141
|
+
**Behavior:** Items aligned to left (or right in RTL)
|
|
142
|
+
|
|
143
|
+
### `.cluster-justify-center`
|
|
144
|
+
|
|
145
|
+
Center items horizontally.
|
|
146
|
+
|
|
147
|
+
```css
|
|
148
|
+
.cluster-justify-center {
|
|
149
|
+
justify-content: center;
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Usage:** `<Cluster justify="center">`
|
|
154
|
+
**Behavior:** Items centered horizontally within container
|
|
155
|
+
**Use Case:** Centered tag clouds or navigation
|
|
156
|
+
|
|
157
|
+
### `.cluster-justify-end`
|
|
158
|
+
|
|
159
|
+
Align items to the end (right in LTR).
|
|
160
|
+
|
|
161
|
+
```css
|
|
162
|
+
.cluster-justify-end {
|
|
163
|
+
justify-content: flex-end;
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Usage:** `<Cluster justify="end">`
|
|
168
|
+
**Behavior:** Items aligned to right (or left in RTL)
|
|
169
|
+
**Use Case:** Right-aligned action buttons
|
|
170
|
+
|
|
171
|
+
### `.cluster-justify-between`
|
|
172
|
+
|
|
173
|
+
Distribute items with space between.
|
|
174
|
+
|
|
175
|
+
```css
|
|
176
|
+
.cluster-justify-between {
|
|
177
|
+
justify-content: space-between;
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Usage:** `<Cluster justify="between">`
|
|
182
|
+
**Behavior:** First item at start, last item at end, equal space between
|
|
183
|
+
**Use Case:** Distributed navigation links
|
|
184
|
+
|
|
185
|
+
## Align Utilities
|
|
186
|
+
|
|
187
|
+
Control vertical alignment of items within each row (align-items).
|
|
188
|
+
|
|
189
|
+
### `.cluster-align-start`
|
|
190
|
+
|
|
191
|
+
Align items to the top of the row.
|
|
192
|
+
|
|
193
|
+
```css
|
|
194
|
+
.cluster-align-start {
|
|
195
|
+
align-items: flex-start;
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Usage:** `<Cluster align="start">`
|
|
200
|
+
**Behavior:** Items aligned to top of the row
|
|
201
|
+
**Use Case:** Items with varying heights
|
|
202
|
+
|
|
203
|
+
### `.cluster-align-center`
|
|
204
|
+
|
|
205
|
+
Center items vertically within the row.
|
|
206
|
+
|
|
207
|
+
```css
|
|
208
|
+
.cluster-align-center {
|
|
209
|
+
align-items: center;
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Usage:** `<Cluster align="center">`
|
|
214
|
+
**Behavior:** Items centered vertically within row
|
|
215
|
+
**Use Case:** Mixed content (icons + text)
|
|
216
|
+
|
|
217
|
+
### `.cluster-align-end`
|
|
218
|
+
|
|
219
|
+
Align items to the bottom of the row.
|
|
220
|
+
|
|
221
|
+
```css
|
|
222
|
+
.cluster-align-end {
|
|
223
|
+
align-items: flex-end;
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Usage:** `<Cluster align="end">`
|
|
228
|
+
**Behavior:** Items aligned to bottom of the row
|
|
229
|
+
|
|
230
|
+
### `.cluster-align-baseline`
|
|
231
|
+
|
|
232
|
+
Align items by their text baseline.
|
|
233
|
+
|
|
234
|
+
```css
|
|
235
|
+
.cluster-align-baseline {
|
|
236
|
+
align-items: baseline;
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Usage:** `<Cluster align="baseline">`
|
|
241
|
+
**Behavior:** Text baselines aligned across items
|
|
242
|
+
**Use Case:** Navigation links or text-based buttons
|
|
243
|
+
|
|
244
|
+
## CSS Custom Properties
|
|
245
|
+
|
|
246
|
+
### Global Spacing Scale
|
|
247
|
+
|
|
248
|
+
Defined in `_globals.scss`:
|
|
249
|
+
|
|
250
|
+
```scss
|
|
251
|
+
:root {
|
|
252
|
+
--spacing-0: 0;
|
|
253
|
+
--spacing-xs: clamp(0.25rem, 0.2rem + 0.25vw, 0.5rem); /* 4-8px */
|
|
254
|
+
--spacing-sm: clamp(0.5rem, 0.45rem + 0.35vw, 0.75rem); /* 8-12px */
|
|
255
|
+
--spacing-md: clamp(0.75rem, 0.65rem + 0.45vw, 1.125rem); /* 12-18px */
|
|
256
|
+
--spacing-lg: clamp(1rem, 0.85rem + 0.6vw, 1.5rem); /* 16-24px */
|
|
257
|
+
--spacing-xl: clamp(1.5rem, 1.25rem + 0.75vw, 2rem); /* 24-32px */
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Theming
|
|
262
|
+
|
|
263
|
+
Override spacing scale globally:
|
|
264
|
+
|
|
265
|
+
```css
|
|
266
|
+
:root {
|
|
267
|
+
/* Custom spacing for larger gaps */
|
|
268
|
+
--spacing-md: 1.5rem;
|
|
269
|
+
--spacing-lg: 2rem;
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Or per component:
|
|
274
|
+
|
|
275
|
+
```tsx
|
|
276
|
+
<Cluster
|
|
277
|
+
gap="md"
|
|
278
|
+
styles={{
|
|
279
|
+
'--spacing-md': '2rem',
|
|
280
|
+
} as React.CSSProperties}
|
|
281
|
+
>
|
|
282
|
+
<Tag>React</Tag>
|
|
283
|
+
</Cluster>
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Responsive Behavior
|
|
287
|
+
|
|
288
|
+
### Fluid Spacing
|
|
289
|
+
|
|
290
|
+
Gap values automatically adjust based on viewport width using CSS clamp():
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
Viewport Width → Gap Size
|
|
294
|
+
320px (mobile) → Minimum (e.g., 0.5rem for sm)
|
|
295
|
+
~800px (tablet) → Middle value (interpolated)
|
|
296
|
+
1280px+ (desktop) → Maximum (e.g., 0.75rem for sm)
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**No media queries needed!** The spacing scales smoothly between min and max values.
|
|
300
|
+
|
|
301
|
+
### Wrapping Behavior
|
|
302
|
+
|
|
303
|
+
Items automatically wrap to the next line when:
|
|
304
|
+
- Container width is insufficient for all items
|
|
305
|
+
- Sum of item widths + gaps exceeds container width
|
|
306
|
+
|
|
307
|
+
**Example:**
|
|
308
|
+
|
|
309
|
+
```
|
|
310
|
+
Container: 600px
|
|
311
|
+
Items: 8 buttons (120px each)
|
|
312
|
+
Gap: 1rem (16px)
|
|
313
|
+
|
|
314
|
+
Row 1: 4 buttons (120 × 4 = 480px) + (16 × 3 = 48px gaps) = 528px ✓
|
|
315
|
+
Row 2: 4 buttons (wraps to next line)
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Class Generation
|
|
319
|
+
|
|
320
|
+
The Cluster component generates classes based on props:
|
|
321
|
+
|
|
322
|
+
```tsx
|
|
323
|
+
<Cluster gap="md" justify="center" align="baseline">
|
|
324
|
+
Content
|
|
325
|
+
</Cluster>
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
**Generated classes:**
|
|
329
|
+
```html
|
|
330
|
+
<div class="cluster cluster-gap-md cluster-justify-center cluster-align-baseline">
|
|
331
|
+
Content
|
|
332
|
+
</div>
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## Combining with Custom Styles
|
|
336
|
+
|
|
337
|
+
### Custom Classes
|
|
338
|
+
|
|
339
|
+
```tsx
|
|
340
|
+
<Cluster className="custom-cluster" gap="sm">
|
|
341
|
+
<Tag>React</Tag>
|
|
342
|
+
</Cluster>
|
|
343
|
+
|
|
344
|
+
<style>
|
|
345
|
+
.custom-cluster {
|
|
346
|
+
max-width: 40rem; /* 640px */
|
|
347
|
+
margin-inline: auto;
|
|
348
|
+
padding: 1rem;
|
|
349
|
+
background: var(--bg-subtle, #f9f9f9);
|
|
350
|
+
border-radius: 0.5rem;
|
|
351
|
+
}
|
|
352
|
+
</style>
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Inline Styles
|
|
356
|
+
|
|
357
|
+
```tsx
|
|
358
|
+
<Cluster
|
|
359
|
+
gap="md"
|
|
360
|
+
styles={{
|
|
361
|
+
maxWidth: '600px',
|
|
362
|
+
marginInline: 'auto',
|
|
363
|
+
padding: '1.5rem',
|
|
364
|
+
}}
|
|
365
|
+
>
|
|
366
|
+
<Button>Action 1</Button>
|
|
367
|
+
<Button>Action 2</Button>
|
|
368
|
+
</Cluster>
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## SCSS Source
|
|
372
|
+
|
|
373
|
+
**File:** `src/components/cluster/cluster.scss`
|
|
374
|
+
|
|
375
|
+
```scss
|
|
376
|
+
/**
|
|
377
|
+
* Cluster Component Styles
|
|
378
|
+
*
|
|
379
|
+
* Utility classes for the Cluster layout primitive.
|
|
380
|
+
* Provides wrapping flex layout for inline groups (tags, badges, buttons).
|
|
381
|
+
* All spacing values use the unified spacing scale from globals.
|
|
382
|
+
* All units are in rem (1rem = 16px base).
|
|
383
|
+
*/
|
|
384
|
+
|
|
385
|
+
// ============================================================================
|
|
386
|
+
// Base Cluster
|
|
387
|
+
// ============================================================================
|
|
388
|
+
|
|
389
|
+
.cluster {
|
|
390
|
+
display: flex;
|
|
391
|
+
flex-wrap: wrap;
|
|
392
|
+
gap: var(--spacing-sm); // Default small gap for inline items
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// ============================================================================
|
|
396
|
+
// Gap Utilities
|
|
397
|
+
// ============================================================================
|
|
398
|
+
|
|
399
|
+
.cluster-gap-0 {
|
|
400
|
+
gap: 0;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.cluster-gap-xs {
|
|
404
|
+
gap: var(--spacing-xs);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.cluster-gap-sm {
|
|
408
|
+
gap: var(--spacing-sm);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.cluster-gap-md {
|
|
412
|
+
gap: var(--spacing-md);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.cluster-gap-lg {
|
|
416
|
+
gap: var(--spacing-lg);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.cluster-gap-xl {
|
|
420
|
+
gap: var(--spacing-xl);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// ============================================================================
|
|
424
|
+
// Justify Utilities (Horizontal Alignment)
|
|
425
|
+
// ============================================================================
|
|
426
|
+
|
|
427
|
+
.cluster-justify-start {
|
|
428
|
+
justify-content: flex-start;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.cluster-justify-center {
|
|
432
|
+
justify-content: center;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.cluster-justify-end {
|
|
436
|
+
justify-content: flex-end;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.cluster-justify-between {
|
|
440
|
+
justify-content: space-between;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// ============================================================================
|
|
444
|
+
// Align Utilities (Vertical Alignment)
|
|
445
|
+
// ============================================================================
|
|
446
|
+
|
|
447
|
+
.cluster-align-start {
|
|
448
|
+
align-items: flex-start;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
.cluster-align-center {
|
|
452
|
+
align-items: center;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
.cluster-align-end {
|
|
456
|
+
align-items: flex-end;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
.cluster-align-baseline {
|
|
460
|
+
align-items: baseline;
|
|
461
|
+
}
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
## Compiled CSS Output
|
|
465
|
+
|
|
466
|
+
**Location:** `libs/components/cluster/cluster.css`
|
|
467
|
+
|
|
468
|
+
The SCSS is compiled to compressed CSS:
|
|
469
|
+
|
|
470
|
+
```css
|
|
471
|
+
.cluster{display:flex;flex-wrap:wrap;gap:var(--spacing-sm)}.cluster-gap-0{gap:0}.cluster-gap-xs{gap:var(--spacing-xs)}.cluster-gap-sm{gap:var(--spacing-sm)}.cluster-gap-md{gap:var(--spacing-md)}.cluster-gap-lg{gap:var(--spacing-lg)}.cluster-gap-xl{gap:var(--spacing-xl)}.cluster-justify-start{justify-content:flex-start}.cluster-justify-center{justify-content:center}.cluster-justify-end{justify-content:flex-end}.cluster-justify-between{justify-content:space-between}.cluster-align-start{align-items:flex-start}.cluster-align-center{align-items:center}.cluster-align-end{align-items:flex-end}.cluster-align-baseline{align-items:baseline}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
**Minified Size:** ~400 bytes (gzipped: ~200 bytes)
|
|
475
|
+
|
|
476
|
+
## Performance
|
|
477
|
+
|
|
478
|
+
### Bundle Size
|
|
479
|
+
- **SCSS Source:** 1.8 KB
|
|
480
|
+
- **Compiled CSS:** 0.4 KB
|
|
481
|
+
- **Gzipped:** 0.2 KB
|
|
482
|
+
|
|
483
|
+
### Runtime Performance
|
|
484
|
+
- **Zero JavaScript:** All layout via CSS
|
|
485
|
+
- **No Re-renders:** Static utility classes
|
|
486
|
+
- **GPU Accelerated:** Flexbox handled by browser compositor
|
|
487
|
+
|
|
488
|
+
### Loading Strategy
|
|
489
|
+
- **Critical CSS:** Include `.cluster` base class
|
|
490
|
+
- **Lazy Load:** Load gap/justify/align utilities on demand
|
|
491
|
+
|
|
492
|
+
## Browser Support
|
|
493
|
+
|
|
494
|
+
| Feature | Chrome | Firefox | Safari | Edge |
|
|
495
|
+
|---------|--------|---------|--------|------|
|
|
496
|
+
| Flexbox | ✅ 29+ | ✅ 28+ | ✅ 9+ | ✅ 12+ |
|
|
497
|
+
| flex-wrap | ✅ 29+ | ✅ 28+ | ✅ 9+ | ✅ 12+ |
|
|
498
|
+
| gap (flexbox) | ✅ 84+ | ✅ 63+ | ✅ 14.1+ | ✅ 84+ |
|
|
499
|
+
| CSS clamp() | ✅ 79+ | ✅ 75+ | ✅ 13.1+ | ✅ 79+ |
|
|
500
|
+
|
|
501
|
+
**Fallback:** For browsers without flexbox gap support, use margin on child elements.
|
|
502
|
+
|
|
503
|
+
## Accessibility
|
|
504
|
+
|
|
505
|
+
### Semantic HTML
|
|
506
|
+
|
|
507
|
+
Use appropriate elements via the `as` prop:
|
|
508
|
+
|
|
509
|
+
```tsx
|
|
510
|
+
<Cluster as="nav"> {/* <nav> for navigation */}
|
|
511
|
+
<Cluster as="ul"> {/* <ul> for lists */}
|
|
512
|
+
<Cluster as="section"> {/* <section> for grouped content */}
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### Focus Order
|
|
516
|
+
|
|
517
|
+
Flexbox maintains DOM order for keyboard navigation:
|
|
518
|
+
|
|
519
|
+
```tsx
|
|
520
|
+
<Cluster gap="md">
|
|
521
|
+
<button>First</button> {/* Tab order: 1 */}
|
|
522
|
+
<button>Second</button> {/* Tab order: 2 */}
|
|
523
|
+
<button>Third</button> {/* Tab order: 3 */}
|
|
524
|
+
</Cluster>
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
Even when wrapped, focus order follows DOM structure.
|
|
528
|
+
|
|
529
|
+
### Screen Readers
|
|
530
|
+
|
|
531
|
+
Provide ARIA labels for non-semantic containers:
|
|
532
|
+
|
|
533
|
+
```tsx
|
|
534
|
+
<Cluster aria-label="Technology tags">
|
|
535
|
+
<Tag>React</Tag>
|
|
536
|
+
<Tag>TypeScript</Tag>
|
|
537
|
+
</Cluster>
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
## Migration from Legacy Styles
|
|
541
|
+
|
|
542
|
+
### From Inline Flex
|
|
543
|
+
|
|
544
|
+
**Before:**
|
|
545
|
+
```css
|
|
546
|
+
.tag-cloud {
|
|
547
|
+
display: inline-flex;
|
|
548
|
+
flex-wrap: wrap;
|
|
549
|
+
gap: 8px;
|
|
550
|
+
}
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
**After:**
|
|
554
|
+
```tsx
|
|
555
|
+
<Cluster gap="sm" className="tag-cloud">
|
|
556
|
+
<Tag>React</Tag>
|
|
557
|
+
</Cluster>
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### From Float Layouts
|
|
561
|
+
|
|
562
|
+
**Before:**
|
|
563
|
+
```css
|
|
564
|
+
.tags {
|
|
565
|
+
overflow: auto; /* Clearfix */
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
.tags > * {
|
|
569
|
+
float: left;
|
|
570
|
+
margin-right: 8px;
|
|
571
|
+
margin-bottom: 8px;
|
|
572
|
+
}
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
**After:**
|
|
576
|
+
```tsx
|
|
577
|
+
<Cluster gap="sm">
|
|
578
|
+
<Tag>React</Tag>
|
|
579
|
+
</Cluster>
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
### From Grid with Auto-Fill
|
|
583
|
+
|
|
584
|
+
**Before:**
|
|
585
|
+
```css
|
|
586
|
+
.grid {
|
|
587
|
+
display: grid;
|
|
588
|
+
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
|
589
|
+
gap: 1rem;
|
|
590
|
+
}
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
**After (if items have varying widths):**
|
|
594
|
+
```tsx
|
|
595
|
+
<Cluster gap="md">
|
|
596
|
+
<Button>Short</Button>
|
|
597
|
+
<Button>Medium Length</Button>
|
|
598
|
+
<Button>Very Long Button Text</Button>
|
|
599
|
+
</Cluster>
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
## Related Documentation
|
|
603
|
+
|
|
604
|
+
- **README.mdx** - Component usage and patterns
|
|
605
|
+
- **cluster.stories.tsx** - Interactive examples
|
|
606
|
+
- **cluster.test.tsx** - Unit tests and behavior
|
|
607
|
+
- **_globals.scss** - Global spacing scale definitions
|
|
608
|
+
|
|
609
|
+
## Version History
|
|
610
|
+
|
|
611
|
+
- **v0.5.11** - Initial release of Cluster component
|
|
612
|
+
- Unified spacing scale
|
|
613
|
+
- Gap, justify, and align utilities
|
|
614
|
+
- Polymorphic `as` prop
|
|
615
|
+
- TypeScript types and comprehensive tests
|
|
616
|
+
|
|
617
|
+
## Resources
|
|
618
|
+
|
|
619
|
+
- **Flexbox Guide:** [MDN Flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout)
|
|
620
|
+
- **CSS clamp():** [MDN clamp()](https://developer.mozilla.org/en-US/docs/Web/CSS/clamp)
|
|
621
|
+
- **Spacing Scale:** See `_globals.scss` for complete scale
|
|
622
|
+
- **Component Composition:** See README.mdx for patterns
|
|
623
|
+
|
|
624
|
+
## License
|
|
625
|
+
|
|
626
|
+
MIT
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cluster Component Styles
|
|
3
|
+
*
|
|
4
|
+
* Utility classes for the Cluster layout primitive.
|
|
5
|
+
* Provides wrapping flex layout for inline groups (tags, badges, buttons).
|
|
6
|
+
* All spacing values use the unified spacing scale from globals.
|
|
7
|
+
* All units are in rem (1rem = 16px base).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Base Cluster
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
.cluster {
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-wrap: wrap;
|
|
17
|
+
gap: var(--spacing-sm); // Default small gap for inline items
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Gap Utilities
|
|
22
|
+
// ============================================================================
|
|
23
|
+
|
|
24
|
+
.cluster-gap-0 {
|
|
25
|
+
gap: 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.cluster-gap-xs {
|
|
29
|
+
gap: var(--spacing-xs);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.cluster-gap-sm {
|
|
33
|
+
gap: var(--spacing-sm);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.cluster-gap-md {
|
|
37
|
+
gap: var(--spacing-md);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.cluster-gap-lg {
|
|
41
|
+
gap: var(--spacing-lg);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.cluster-gap-xl {
|
|
45
|
+
gap: var(--spacing-xl);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ============================================================================
|
|
49
|
+
// Justify Utilities (Horizontal Alignment)
|
|
50
|
+
// ============================================================================
|
|
51
|
+
|
|
52
|
+
.cluster-justify-start {
|
|
53
|
+
justify-content: flex-start;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.cluster-justify-center {
|
|
57
|
+
justify-content: center;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.cluster-justify-end {
|
|
61
|
+
justify-content: flex-end;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.cluster-justify-between {
|
|
65
|
+
justify-content: space-between;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ============================================================================
|
|
69
|
+
// Align Utilities (Vertical Alignment)
|
|
70
|
+
// ============================================================================
|
|
71
|
+
|
|
72
|
+
.cluster-align-start {
|
|
73
|
+
align-items: flex-start;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.cluster-align-center {
|
|
77
|
+
align-items: center;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.cluster-align-end {
|
|
81
|
+
align-items: flex-end;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.cluster-align-baseline {
|
|
85
|
+
align-items: baseline;
|
|
86
|
+
}
|