@kolkrabbi/kol-component 0.82.0 → 0.83.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.82.0",
3
+ "version": "0.83.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",
@@ -1,6 +1,7 @@
1
1
  import SectionCardItem from '../molecules/SectionCardItem.jsx'
2
2
  import SectionText, { HEADLINE_ROLE } from '../molecules/SectionText.jsx'
3
3
  import useSectionTheme from '../hooks/useSectionTheme.js'
4
+ import { minHeightClass } from './sectionHeights.js'
4
5
 
5
6
  /**
6
7
  * SectionCards — the "N-up feature cards" band: a `SectionText` header over a
@@ -18,6 +19,8 @@ import useSectionTheme from '../hooks/useSectionTheme.js'
18
19
  * `inverse` = the paired theme of the nearest live one, following the toggle;
19
20
  * `light` / `dark` pinned; omit to inherit. Stamps `data-theme` on the root and
20
21
  * paints its surface — every token inside resolves to the other theme's.
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
21
24
  * @param {{title, icon, visual, description, href, backgroundColor, imageAspectRatio}[]} features
22
25
  * @param {ReactNode} label · headline · body the header (heading-03 + mono lede by default)
23
26
  * @param {ReactNode} actions centred action row under the cards
@@ -29,6 +32,7 @@ import useSectionTheme from '../hooks/useSectionTheme.js'
29
32
  */
30
33
  export default function SectionCards({
31
34
  theme,
35
+ height = '60',
32
36
  features = [],
33
37
  label,
34
38
  headline,
@@ -53,7 +57,7 @@ export default function SectionCards({
53
57
  }) {
54
58
  const [themeRef, themeStamp] = useSectionTheme(theme)
55
59
  return (
56
- <section ref={themeRef} data-theme={themeStamp} className={`w-full ${theme ? 'bg-surface-primary' : ''} ${sectionClassName}`.replace(/\s+/g, ' ').trim()}>
60
+ <section ref={themeRef} data-theme={themeStamp} className={`w-full flex flex-col justify-center ${minHeightClass(height)} ${theme ? 'bg-surface-primary' : ''} ${sectionClassName}`.replace(/\s+/g, ' ').trim()}>
57
61
  <div className={wrapperClassName}>
58
62
  {(label || headline || body) && (
59
63
  <SectionText
@@ -1,5 +1,6 @@
1
1
  import Button from '../atoms/Button.jsx'
2
2
  import SectionText from '../molecules/SectionText.jsx'
3
+ import { minHeightClass } from './sectionHeights.js'
3
4
 
4
5
  /**
5
6
  * SectionCta — the editorial two-column contact/CTA band: a large display
@@ -14,6 +15,8 @@ import SectionText from '../molecules/SectionText.jsx'
14
15
  * heading, a mono line and Buttons, centred — which was `FoundryCTA`, a second
15
16
  * way to render SectionText. FoundryCTA is its deprecated alias.
16
17
  *
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
17
20
  * @param {'editorial'|'centered'} variant
18
21
  * @param {ReactNode} headline · body · actions centered: the SectionText slots
19
22
  * @param {ReactNode} eyebrow left-column display wordmark (kol-sans-display-01)
@@ -26,6 +29,7 @@ import SectionText from '../molecules/SectionText.jsx'
26
29
  */
27
30
  export default function SectionCta({
28
31
  variant = 'editorial',
32
+ height = '60',
29
33
  headline,
30
34
  body,
31
35
  actions,
@@ -41,8 +45,8 @@ export default function SectionCta({
41
45
  }) {
42
46
  if (variant === 'centered') {
43
47
  return (
44
- <section className={`w-full py-24 ${className}`.trim()}>
45
- <div className="max-w-[var(--kol-container-max,var(--kol-content-shell,1800px))] mx-auto">
48
+ <section className={`w-full flex flex-col justify-center py-24 ${minHeightClass(height)} ${className}`.replace(/\s+/g, ' ').trim()}>
49
+ <div className="w-full max-w-[var(--kol-container-max,var(--kol-content-shell,1800px))] mx-auto">
46
50
  <div className="w-32 h-px bg-fg-24 mx-auto mb-8" />
47
51
  <SectionText
48
52
  align="center"
@@ -68,7 +72,7 @@ export default function SectionCta({
68
72
  ...(email ? [{ label: contactLabel, value: email, href: `mailto:${email}` }] : []),
69
73
  ]
70
74
  return (
71
- <section className={`w-full bg-auto ${className}`.trim()}>
75
+ <section className={`w-full bg-auto flex flex-col justify-center ${minHeightClass(height)} ${className}`.replace(/\s+/g, ' ').trim()}>
72
76
  {/* the family's ONE cap — the shell's --kol-container-max ladder (user
73
77
  * ruling 2026-08-26; the 1600 SectionCtaEditorial asked for was a third
74
78
  * number beside split's 1200 and cards' 1400) — the surface stays full
@@ -1,6 +1,7 @@
1
1
  import { useState } from 'react'
2
2
  import { Accordion, AccordionPanel } from '../molecules/Accordion.jsx'
3
3
  import SectionText from '../molecules/SectionText.jsx'
4
+ import { minHeightClass } from './sectionHeights.js'
4
5
 
5
6
  /**
6
7
  * SectionFaq — a `SectionText` header over an `Accordion` of question /
@@ -10,6 +11,8 @@ import SectionText from '../molecules/SectionText.jsx'
10
11
  *
11
12
  * @param {ReactNode} label · headline · body · actions the header (SectionText)
12
13
  * @param {string} [headlineSize='heading-02']
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
13
16
  * @param {{ q: ReactNode, a: ReactNode, meta?: ReactNode }[]} items
14
17
  * @param {boolean} [singleOpen=false] opening one panel closes the others
15
18
  * @param {number} [defaultOpen] index open on mount (singleOpen) — omit for all closed
@@ -24,6 +27,7 @@ export default function SectionFaq({
24
27
  items = [],
25
28
  singleOpen = false,
26
29
  defaultOpen,
30
+ height = '60',
27
31
  slotClass,
28
32
  slotStyle,
29
33
  className = '',
@@ -33,8 +37,8 @@ export default function SectionFaq({
33
37
  }) {
34
38
  const [open, setOpen] = useState(defaultOpen ?? null)
35
39
  return (
36
- <section className={`kol-section-faq w-full px-5 py-16 md:px-8 md:py-24 lg:px-14 ${className}`.trim()}>
37
- <div className="max-w-[var(--kol-container-max,var(--kol-content-shell,1800px))] mx-auto">
40
+ <section className={`kol-section-faq w-full flex flex-col justify-center px-5 py-16 md:px-8 md:py-24 lg:px-14 ${minHeightClass(height)} ${className}`.replace(/\s+/g, ' ').trim()}>
41
+ <div className="w-full max-w-[var(--kol-container-max,var(--kol-content-shell,1800px))] mx-auto">
38
42
  <div className={innerClassName}>
39
43
  {(label || headline || body || actions) && (
40
44
  <SectionText label={label} headline={headline} headlineSize={headlineSize} body={body} actions={actions} slotClass={slotClass} slotStyle={slotStyle} />
@@ -1,5 +1,6 @@
1
1
  import SectionText from '../molecules/SectionText.jsx'
2
2
  import useSectionTheme from '../hooks/useSectionTheme.js'
3
+ import { minHeightClass } from './sectionHeights.js'
3
4
 
4
5
  /**
5
6
  * SectionSplit — the media-and-text split section, on `SectionText` (the
@@ -46,16 +47,6 @@ import useSectionTheme from '../hooks/useSectionTheme.js'
46
47
  * @param {object} slotClass · slotStyle per-slot class / style on the text block (reveal seam)
47
48
  * @param {string} className · innerClassName · columnClassName layout seams
48
49
  */
49
- /* The family's height ladder, as MIN-height — content may still grow, the two
50
- * columns stay centred (SectionSplitHeight, kol-website 2026-08-27: "we need
51
- * to set some sizes"). Same three names as SectionHero's presets, literal
52
- * strings (the SPLIT_HEIGHTS lesson — a class built at runtime is not a
53
- * class); anything else passes through as a class string. */
54
- const MIN_HEIGHTS = {
55
- full: 'min-h-dvh',
56
- 80: 'min-h-[70svh] md:min-h-[80vh]',
57
- 60: 'min-h-[50svh] md:min-h-[60vh]',
58
- }
59
50
 
60
51
  export default function SectionSplit({
61
52
  theme,
@@ -95,7 +86,7 @@ export default function SectionSplit({
95
86
  <section
96
87
  ref={themeRef}
97
88
  data-theme={themeStamp}
98
- 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 ${MIN_HEIGHTS[height] || height} ${bleed} ${className}`.replace(/\s+/g, ' ').trim()}
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()}
99
90
  style={sectionStyle}
100
91
  >
101
92
  {/* ONE cap for the whole section family (user ruling 2026-08-26): the shell's
@@ -0,0 +1,12 @@
1
+ /* The section family's height ladder, as MIN-height — content may still grow,
2
+ * the content stays vertically centred inside it (SectionSplitHeight →
3
+ * SectionHeightLadder, kol-website 2026-08-27: "we need to set some sizes").
4
+ * Same three names as SectionHero's presets; literal strings — a class built
5
+ * at runtime is not a class (the SPLIT_HEIGHTS lesson). Anything else passes
6
+ * through as a class string. */
7
+ 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
+ }
12
+ export const minHeightClass = (height) => MIN_HEIGHTS[height] || height