@kolkrabbi/kol-component 0.85.0 → 0.87.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-component",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.87.0",
|
|
4
4
|
"description": "KOL design-system components — atoms through organisms, emitting canonical kol-* classes. Pairs with @kolkrabbi/kol-theme for styling.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -31,8 +31,18 @@ import usePrefersReducedMotion from '../hooks/usePrefersReducedMotion.js'
|
|
|
31
31
|
* ties it to the root font-size, so a user bumping their browser text size
|
|
32
32
|
* silently re-counts the columns of every wall in the estate.
|
|
33
33
|
*
|
|
34
|
+
* `cols` is the PAGE's call (ContentCollectionCols, kol-website 2026-08-27 —
|
|
35
|
+
* user: "translate that to something usable, consistent"): every filtered grid
|
|
36
|
+
* on the website was ruled as a COLUMN COUNT (`/stack`: one below md, three
|
|
37
|
+
* from md), and back-solving a `min` that happens to yield three on the
|
|
38
|
+
* container ladder is a number nobody picked. `cols={N}` says the count;
|
|
39
|
+
* `min` stays the default for the fluid wall above. Literal class strings —
|
|
40
|
+
* a class built at runtime is never emitted.
|
|
41
|
+
*
|
|
34
42
|
* @param {string} form 'grid' | 'list'
|
|
35
43
|
* @param {string} min grid track minimum, card form (default 320px)
|
|
44
|
+
* @param {number} cols OPT-IN column count, grid form: 1 below md, N from
|
|
45
|
+
* md (2–6). Wins over `min`; the list form ignores it
|
|
36
46
|
* @param {string} listMin OPT-IN: makes the list multi-column too, for a dense
|
|
37
47
|
* file-browser cut. Unset = one full-width column
|
|
38
48
|
* @param {number} gap px between items. UNSET reads the token for the
|
|
@@ -43,9 +53,19 @@ import usePrefersReducedMotion from '../hooks/usePrefersReducedMotion.js'
|
|
|
43
53
|
* nine call sites. Pass a number only to differ
|
|
44
54
|
* @param {boolean} stagger enter animation on/off (reduced motion wins)
|
|
45
55
|
*/
|
|
56
|
+
const COLS = {
|
|
57
|
+
1: 'grid-cols-1',
|
|
58
|
+
2: 'grid-cols-1 md:grid-cols-2',
|
|
59
|
+
3: 'grid-cols-1 md:grid-cols-3',
|
|
60
|
+
4: 'grid-cols-1 md:grid-cols-4',
|
|
61
|
+
5: 'grid-cols-1 md:grid-cols-5',
|
|
62
|
+
6: 'grid-cols-1 md:grid-cols-6',
|
|
63
|
+
}
|
|
64
|
+
|
|
46
65
|
export default function ContentCollection({
|
|
47
66
|
form = 'grid',
|
|
48
67
|
min = '320px',
|
|
68
|
+
cols,
|
|
49
69
|
listMin,
|
|
50
70
|
gap,
|
|
51
71
|
stagger = true,
|
|
@@ -61,15 +81,19 @@ export default function ContentCollection({
|
|
|
61
81
|
? `${gap}px`
|
|
62
82
|
: `var(--kol-gap-wall-${form === 'list' ? 'list' : 'grid'})`
|
|
63
83
|
|
|
84
|
+
const colsCls = form !== 'list' && COLS[cols] ? COLS[cols] : ''
|
|
64
85
|
return (
|
|
65
86
|
<ul
|
|
66
87
|
key={form}
|
|
67
|
-
className={`m-0 list-none p-0 ${className}`.trim()}
|
|
88
|
+
className={`m-0 list-none p-0 ${colsCls} ${className}`.replace(/\s+/g, ' ').trim()}
|
|
68
89
|
style={{
|
|
69
90
|
display: 'grid',
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
91
|
+
/* with `cols` the classes carry the tracks — an inline template would outrank them */
|
|
92
|
+
gridTemplateColumns: colsCls
|
|
93
|
+
? undefined
|
|
94
|
+
: form === 'list'
|
|
95
|
+
? (listMin ? `repeat(auto-fill, minmax(${listMin}, 1fr))` : '1fr')
|
|
96
|
+
: `repeat(auto-fill, minmax(${min}, 1fr))`,
|
|
73
97
|
gap: g,
|
|
74
98
|
}}
|
|
75
99
|
>
|
|
@@ -120,9 +120,9 @@ function MediaLayer({ media }) {
|
|
|
120
120
|
* @param {ReactNode|{src, kind, poster, srcSet, alt}|Array} media background (media) / the half (split) / an ARRAY of slides → carousel
|
|
121
121
|
* @param {number} overlayOpacity 0–100 surface-primary scrim over the media (default 0)
|
|
122
122
|
* @param {boolean} veil bottom-heavy gradient over the media
|
|
123
|
-
* @param {'center'|'end'} justify content vertically centred, or pinned to the foot
|
|
123
|
+
* @param {'center'|'end'} justify content vertically centred, or pinned to the foot (with `foot`, the pb ramp plus `overlap` — the text clears the card)
|
|
124
124
|
* @param {ReactNode} foot a node rendered across the hero's bottom edge
|
|
125
|
-
* @param {number} overlap how far `foot` rises into the hero, px (default 250)
|
|
125
|
+
* @param {number} overlap how far `foot` rises into the hero, px (default 250); published on the section as `--kol-section-foot-overlap`
|
|
126
126
|
* @param {boolean} autoPlay · {number} autoPlayInterval · {'stack'|'header'} navPosition carousel only
|
|
127
127
|
* @param {Function} renderTitle · {string} ctaLabel · {Function} onNavigate · {boolean} showTitle · showDescription · showCta ·
|
|
128
128
|
* {string} titleClassName · descriptionClassName · {Object} options carousel only — FeaturedCarousel's
|
|
@@ -311,10 +311,23 @@ export default function SectionHero({
|
|
|
311
311
|
))
|
|
312
312
|
: children)
|
|
313
313
|
|
|
314
|
-
|
|
314
|
+
/* `justify="end"` + `foot` (SectionHeroFootClearance, kol-website
|
|
315
|
+
* 2026-08-27 — user, dev vs live: "why can't you make it the same?"): the
|
|
316
|
+
* foot rises `overlap` px into the hero, so the content's bottom inset is
|
|
317
|
+
* the pb ramp PLUS the overlap — the text clears the card at any overlap.
|
|
318
|
+
* The ramp is a custom property so the sum is one literal class; `overlap`
|
|
319
|
+
* is published on the section as --kol-section-foot-overlap (0 without a
|
|
320
|
+
* foot). */
|
|
321
|
+
/* the bottom inset is never the `p-*` shorthand: `md:p-10` sits in a later
|
|
322
|
+
* media query than a bare `pb-*` and would win it back at ≥768 (measured —
|
|
323
|
+
* the old `pb-32 sm:pb-40` ramp lost to it between 768 and 1023 too). */
|
|
324
|
+
const justifyCls = justify === 'end'
|
|
325
|
+
? 'items-end [--kol-section-pb:8rem] sm:[--kol-section-pb:10rem] lg:[--kol-section-pb:12rem] xl:[--kol-section-pb:14rem] pb-[calc(var(--kol-section-pb)+var(--kol-section-foot-overlap,0px))]'
|
|
326
|
+
: 'items-center pb-6 md:pb-10'
|
|
327
|
+
const footVar = foot ? { '--kol-section-foot-overlap': `${overlap}px` } : undefined
|
|
315
328
|
|
|
316
329
|
return withFoot(
|
|
317
|
-
<section ref={themeRef} data-theme={themeStamp} className={`kol-full-bleed-hero relative isolate w-full overflow-hidden ${themed} ${heightCls} ${fullBleed ? 'w-screen ml-[calc(50%-50vw)]' : ''} ${className}`.replace(/\s+/g, ' ').trim()}>
|
|
330
|
+
<section ref={themeRef} data-theme={themeStamp} className={`kol-full-bleed-hero relative isolate w-full overflow-hidden ${themed} ${heightCls} ${fullBleed ? 'w-screen ml-[calc(50%-50vw)]' : ''} ${className}`.replace(/\s+/g, ' ').trim()} style={footVar}>
|
|
318
331
|
<MediaLayer media={media} />
|
|
319
332
|
{overlayOpacity > 0 && (
|
|
320
333
|
<div
|
|
@@ -324,7 +337,7 @@ export default function SectionHero({
|
|
|
324
337
|
/>
|
|
325
338
|
)}
|
|
326
339
|
{veil && <div aria-hidden="true" className="kol-section-hero-veil absolute inset-0" />}
|
|
327
|
-
<div className={`relative z-10 flex h-full w-full ${justifyCls} ${alignCls}
|
|
340
|
+
<div className={`relative z-10 flex h-full w-full ${justifyCls} ${alignCls} px-6 pt-6 md:px-10 md:pt-10`}>
|
|
328
341
|
{content}
|
|
329
342
|
</div>
|
|
330
343
|
</section>,
|