@kolkrabbi/kol-component 0.83.0 → 0.85.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.83.0",
3
+ "version": "0.85.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",
@@ -20,7 +20,7 @@ import { minHeightClass } from './sectionHeights.js'
20
20
  * `light` / `dark` pinned; omit to inherit. Stamps `data-theme` on the root and
21
21
  * paints its surface — every token inside resolves to the other theme's.
22
22
  * @param {'full'|'80'|'60'|string} [height='60'] min-height on the family's ladder — full = 100dvh,
23
- * 80 = 70svh / 80vh, 60 = 50svh / 60vh (default); content stays vertically centred inside it
23
+ * 80 = 70svh / 80vh, 60 = 50svh / 60vh (default), 40 = 35svh / 40vh; content stays vertically centred inside it
24
24
  * @param {{title, icon, visual, description, href, backgroundColor, imageAspectRatio}[]} features
25
25
  * @param {ReactNode} label · headline · body the header (heading-03 + mono lede by default)
26
26
  * @param {ReactNode} actions centred action row under the cards
@@ -16,7 +16,7 @@ import { minHeightClass } from './sectionHeights.js'
16
16
  * way to render SectionText. FoundryCTA is its deprecated alias.
17
17
  *
18
18
  * @param {'full'|'80'|'60'|string} [height='60'] min-height on the family's ladder — full = 100dvh,
19
- * 80 = 70svh / 80vh, 60 = 50svh / 60vh (default); content stays vertically centred inside it
19
+ * 80 = 70svh / 80vh, 60 = 50svh / 60vh (default), 40 = 35svh / 40vh; content stays vertically centred inside it
20
20
  * @param {'editorial'|'centered'} variant
21
21
  * @param {ReactNode} headline · body · actions centered: the SectionText slots
22
22
  * @param {ReactNode} eyebrow left-column display wordmark (kol-sans-display-01)
@@ -12,7 +12,7 @@ import { minHeightClass } from './sectionHeights.js'
12
12
  * @param {ReactNode} label · headline · body · actions the header (SectionText)
13
13
  * @param {string} [headlineSize='heading-02']
14
14
  * @param {'full'|'80'|'60'|string} [height='60'] min-height on the family's ladder — full = 100dvh,
15
- * 80 = 70svh / 80vh, 60 = 50svh / 60vh (default); content stays vertically centred inside it
15
+ * 80 = 70svh / 80vh, 60 = 50svh / 60vh (default), 40 = 35svh / 40vh; content stays vertically centred inside it
16
16
  * @param {{ q: ReactNode, a: ReactNode, meta?: ReactNode }[]} items
17
17
  * @param {boolean} [singleOpen=false] opening one panel closes the others
18
18
  * @param {number} [defaultOpen] index open on mount (singleOpen) — omit for all closed
@@ -18,6 +18,7 @@ const HEIGHTS = {
18
18
  full: 'h-dvh',
19
19
  80: 'h-[70svh] md:h-[80vh]',
20
20
  60: 'h-[50svh] md:h-[60vh]',
21
+ 40: 'h-[35svh] md:h-[40vh]',
21
22
  screen: 'h-dvh',
22
23
  lg: 'h-[440px] md:h-[640px]',
23
24
  md: 'h-[320px] md:h-[440px]',
@@ -32,6 +33,7 @@ const SPLIT_HEIGHTS = {
32
33
  full: 'min-h-dvh',
33
34
  80: 'min-h-[70svh] md:min-h-[80vh]',
34
35
  60: 'min-h-[50svh] md:min-h-[60vh]',
36
+ 40: 'min-h-[35svh] md:min-h-[40vh]',
35
37
  screen: 'min-h-dvh',
36
38
  lg: 'min-h-dvh',
37
39
  md: 'min-h-[50svh] md:min-h-[60vh]',
@@ -126,7 +128,7 @@ function MediaLayer({ media }) {
126
128
  * {string} titleClassName · descriptionClassName · {Object} options carousel only — FeaturedCarousel's
127
129
  * seams, forwarded whole (SectionHeroCarouselSeams, 2026-08-26: the foundry index sets each
128
130
  * slide's title in the typeface's own font and routes the CTA through the SPA)
129
- * @param {string} height 'full' | '80' | '60' (viewport tiers) · 'lg' | 'md' | 'screen' (aliases) · or a height class string
131
+ * @param {string} height 'full' | '80' | '60' | '40' (viewport tiers) · 'lg' | 'md' | 'screen' (aliases) · or a height class string
130
132
  * @param {ReactNode} label · headline · body · actions the composed text (SectionText)
131
133
  * @param {object} slotClass · slotStyle per-slot class / style, forwarded to SectionText (a consumer's reveal seam)
132
134
  * @param {string} headlineSize role; defaults per variant — media 'display-04', split 'heading-02'
@@ -31,7 +31,11 @@ import { minHeightClass } from './sectionHeights.js'
31
31
  * @param {{num: ReactNode, label: string}[]} meta stats strip (mutually exclusive with `actions`)
32
32
  * @param {ReactNode} actions button row
33
33
  * @param {ReactNode} media image / video / interactive node for the visual column
34
- * @param {string} [ratio='4/5'] aspect ratio of the media frame
34
+ * @param {string} [ratio='4/5'] aspect ratio of the media frame. THE FRAME IS BOUNDED BY THE
35
+ * RUNG (SectionSplitMediaBounded, 2026-08-27): its height is the section's `height` rung minus
36
+ * the vertical padding, its width follows the ratio (capped at the column). Before, the frame
37
+ * was as wide as its column and set the section's height itself, so `40` · `60` · `80`
38
+ * rendered identically — a ladder that only floors is decorative for a card with media.
35
39
  * @param {boolean} [mediaHover=false] zoom the media on frame hover (the CardFeatureItem numbers)
36
40
  * @param {boolean} [mediaClip=true] the frame clips its media (overflow hidden + radius). `false`
37
41
  * for a node that transforms in 3D (a tilt card) — the frame keeps its ratio and radius,
@@ -40,7 +44,7 @@ import { minHeightClass } from './sectionHeights.js'
40
44
  * mutually exclusive in practice — pick one.
41
45
  * @param {'right'|'left'|'center'} [align='right'] media side, or centred single column
42
46
  * @param {'full'|'80'|'60'|string} [height='60'] min-height on the family's ladder — full = 100dvh,
43
- * 80 = 70svh / 80vh, 60 = 50svh / 60vh (default); the columns stay vertically centred inside it
47
+ * 80 = 70svh / 80vh, 60 = 50svh / 60vh (default), 40 = 35svh / 40vh; the columns stay vertically centred inside it
44
48
  * @param {ReactNode} caption mono caption + gradient veil over the media
45
49
  * @param {string} bgImage inline cover background on the section
46
50
  * @param {boolean} fullBleed span the full viewport width
@@ -86,7 +90,7 @@ export default function SectionSplit({
86
90
  <section
87
91
  ref={themeRef}
88
92
  data-theme={themeStamp}
89
- className={`kol-section-split flex flex-col justify-center px-5 py-16 md:px-8 md:py-24 lg:px-14 lg:py-32 ${minHeightClass(height)} ${bleed} ${className}`.replace(/\s+/g, ' ').trim()}
93
+ className={`kol-section-split flex flex-col justify-center px-5 py-16 md:px-8 md:py-24 lg:px-14 lg:py-32 [--kol-section-py:4rem] md:[--kol-section-py:6rem] lg:[--kol-section-py:8rem] ${minHeightClass(height)} ${bleed} ${className}`.replace(/\s+/g, ' ').trim()}
90
94
  style={sectionStyle}
91
95
  >
92
96
  {/* ONE cap for the whole section family (user ruling 2026-08-26): the shell's
@@ -120,9 +124,12 @@ export default function SectionSplit({
120
124
  )}
121
125
  </SectionText>
122
126
  {media && (
127
+ /* height = the rung minus the padding; width follows the ratio and
128
+ * caps at the column — the media takes its size from the section,
129
+ * never gives it */
123
130
  <div
124
- className={`kol-section-split-visual relative rounded-[var(--kol-radius-sm)] ${mediaClip ? 'overflow-hidden' : ''} ${mediaHover ? 'is-hoverable' : ''} ${mediaFirst ? 'order-1' : ''} ${centred ? 'w-full max-w-[640px]' : ''}`.replace(/\s+/g, ' ').trim()}
125
- style={{ aspectRatio: ratio }}
131
+ className={`kol-section-split-visual relative w-auto max-w-full justify-self-center rounded-[var(--kol-radius-sm)] ${mediaClip ? 'overflow-hidden' : ''} ${mediaHover ? 'is-hoverable' : ''} ${mediaFirst ? 'order-1' : ''} ${centred ? 'max-w-[640px]' : ''}`.replace(/\s+/g, ' ').trim()}
132
+ style={{ aspectRatio: ratio, height: 'calc(var(--kol-section-h, 60vh) - 2 * var(--kol-section-py, 4rem))' }}
126
133
  >
127
134
  {media}
128
135
  {caption && <div className="kol-section-split-visual-veil" aria-hidden="true" />}
@@ -4,9 +4,15 @@
4
4
  * Same three names as SectionHero's presets; literal strings — a class built
5
5
  * at runtime is not a class (the SPLIT_HEIGHTS lesson). Anything else passes
6
6
  * through as a class string. */
7
+ /* Each rung also publishes itself as `--kol-section-h`, so a child that must
8
+ * be BOUNDED by the rung — the split's media frame (SectionSplitMediaBounded,
9
+ * 2026-08-27) — can read it. Literal strings, every one. */
7
10
  export const MIN_HEIGHTS = {
8
- full: 'min-h-dvh',
9
- 80: 'min-h-[70svh] md:min-h-[80vh]',
10
- 60: 'min-h-[50svh] md:min-h-[60vh]',
11
+ full: 'min-h-dvh [--kol-section-h:100dvh]',
12
+ 80: 'min-h-[70svh] md:min-h-[80vh] [--kol-section-h:70svh] md:[--kol-section-h:80vh]',
13
+ 60: 'min-h-[50svh] md:min-h-[60vh] [--kol-section-h:50svh] md:[--kol-section-h:60vh]',
14
+ /* 40 (SectionHeightForty, 2026-08-27): the rung below 60 for a page-foot
15
+ * CTA or a cards band that wants less air; default stays 60 everywhere */
16
+ 40: 'min-h-[35svh] md:min-h-[40vh] [--kol-section-h:35svh] md:[--kol-section-h:40vh]',
11
17
  }
12
18
  export const minHeightClass = (height) => MIN_HEIGHTS[height] || height