@kolkrabbi/kol-component 0.76.4 → 0.77.1

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.76.4",
3
+ "version": "0.77.1",
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",
package/src/index.js CHANGED
@@ -70,7 +70,7 @@ export { default as AlignmentGrid } from './molecules/AlignmentGrid.jsx'
70
70
  export { default as ImageBlock } from './molecules/ImageBlock.jsx'
71
71
  export { default as SelectionOverlay } from './atoms/SelectionOverlay.jsx'
72
72
  export { default as VideoBlock, getEmbedUrl } from './molecules/VideoBlock.jsx'
73
- export { default as CardFeatureItem } from './molecules/CardFeatureItem.jsx'
73
+ export { default as SectionCardItem, default as CardFeatureItem } from './molecules/SectionCardItem.jsx'
74
74
  export { default as CodeBlock } from './molecules/CodeBlock.jsx'
75
75
  export { default as ColorInputRow } from './molecules/ColorInputRow.jsx'
76
76
  export { default as ColorRamp } from './molecules/ColorRamp.jsx'
@@ -1,133 +1,6 @@
1
- import { Icon } from '@kolkrabbi/kol-icons'
2
-
3
- /* taxonomy-ok: nests only kol-icons's Icon (a package import the
4
- * relative-import check can't see). */
5
-
6
1
  /**
7
- * CardFeatureItem — fixed-height feature card: a title + optional icon
8
- * header, a flexible visual middle, and a mono description footer. The
9
- * card's visual is polymorphic: an `.svg` URL string renders as a
10
- * `mask-image` block tinted with `currentColor` (theme-correct line-art),
11
- * any other string renders as a cover-fit `<img>`, a ReactNode renders
12
- * as-is, and no visual falls back to a large 96px `Icon` (the header's
13
- * `icon` name). The grid child of FeaturesCardSection.
14
- *
15
- * Optionally the whole card is a link. `http*` / `mailto` hrefs open in a
16
- * new tab; any other href renders a plain same-tab anchor with an
17
- * `onNavigate(event)` seam — an SPA consumer intercepts there
18
- * (preventDefault + its router) instead of this component importing one.
19
- *
20
- * Title and description render exactly as authored — no casing transforms;
21
- * author strings in their final case at the call site.
22
- *
23
- * @param {ReactNode} title header heading (kol-helper-16)
24
- * @param {string} icon Icon name for the header (16px); also the 96px no-visual fallback
25
- * @param {string|ReactNode} visual image URL, `.svg` mask URL, or inline node
26
- * @param {ReactNode} description footer line (kol-mono-12, muted)
27
- * @param {string} backgroundColor card background utility class
28
- * @param {string} href link target; `http*`/`mailto` → new tab, else plain same-tab anchor
29
- * @param {Function} onNavigate (event) => void — click seam on the same-tab anchor (SPA intercept)
30
- * @param {'auto'|'9/6'|'10/6'|'16/9'|'1/1'} imageAspectRatio aspect class on the visual middle
31
- * @param {string} imagePosition `<img>` object-position
2
+ * @deprecated 2026-08-26 `CardFeatureItem` is `SectionCardItem` under its old
3
+ * name (the section family: the composition is the card, its parts are card
4
+ * items). Alias kept; removed at the next major.
32
5
  */
33
- export default function CardFeatureItem({
34
- title,
35
- icon,
36
- visual,
37
- description,
38
- backgroundColor = 'bg-surface-primary',
39
- href,
40
- onNavigate,
41
- imageAspectRatio = 'auto',
42
- imagePosition = 'center',
43
- }) {
44
- const isSvgUrl = typeof visual === 'string' && visual.endsWith('.svg')
45
-
46
- const aspectClasses = {
47
- 'auto': '',
48
- '9/6': 'aspect-[9/6]',
49
- '10/6': 'aspect-[10/6]',
50
- '16/9': 'aspect-video',
51
- '1/1': 'aspect-square',
52
- }
53
- const aspectClass = aspectClasses[imageAspectRatio] || ''
54
-
55
- const content = (
56
- <>
57
- <div className="w-full flex items-center justify-between gap-2">
58
- <h3 className="kol-helper-16">{title}</h3>
59
- {icon && <Icon name={icon} size={16} className="shrink-0" />}
60
- </div>
61
-
62
- {/* kol-card-feature-visual: zooms 1.03 on card hover (chrome in
63
- * kol-theme — CardFeatureHoverZoom 2026-08-12); all three visual
64
- * forms ride the same wrapper, reduced-motion opts out. */}
65
- <div className={`kol-card-feature-visual w-full flex-1 flex items-center justify-center overflow-hidden ${aspectClass}`.trim()}>
66
- {visual ? (
67
- typeof visual === 'string' ? (
68
- isSvgUrl ? (
69
- /* currentColor line-art: the SVG paints as a mask over bg-current */
70
- <div
71
- className="w-full h-full bg-current rounded"
72
- style={{
73
- maskImage: `url(${visual})`,
74
- maskSize: 'contain',
75
- maskRepeat: 'no-repeat',
76
- maskPosition: 'center',
77
- WebkitMaskImage: `url(${visual})`,
78
- WebkitMaskSize: 'contain',
79
- WebkitMaskRepeat: 'no-repeat',
80
- WebkitMaskPosition: 'center',
81
- }}
82
- />
83
- ) : (
84
- <img
85
- src={visual}
86
- alt={typeof title === 'string' ? title : ''}
87
- className="w-full h-full object-cover rounded"
88
- style={{ objectPosition: imagePosition }}
89
- />
90
- )
91
- ) : (
92
- visual
93
- )
94
- ) : (
95
- <Icon name={icon} size={96} />
96
- )}
97
- </div>
98
-
99
- <p className="kol-mono-12 text-fg-48">{description}</p>
100
- </>
101
- )
102
-
103
- const baseClasses = `kol-card-feature w-full flex-1 h-[304px] md:h-72 p-4 md:p-6 gap-4 ${backgroundColor} rounded border border-fg-08 flex flex-col justify-between items-start overflow-hidden`
104
-
105
- if (href) {
106
- const isExternal = href.startsWith('http') || href.startsWith('mailto')
107
-
108
- if (isExternal) {
109
- return (
110
- <a
111
- href={href}
112
- className={`${baseClasses} hover:border-fg-32 transition-colors duration-300`}
113
- target="_blank"
114
- rel="noreferrer noopener"
115
- >
116
- {content}
117
- </a>
118
- )
119
- }
120
-
121
- return (
122
- <a
123
- href={href}
124
- onClick={onNavigate}
125
- className={`${baseClasses} hover:border-fg-24 transition-colors duration-300`}
126
- >
127
- {content}
128
- </a>
129
- )
130
- }
131
-
132
- return <div className={baseClasses}>{content}</div>
133
- }
6
+ export { default } from './SectionCardItem.jsx'
@@ -1,6 +1,7 @@
1
1
  import { MenuItem as MenuTrigger } from './MenuItem.jsx'
2
2
 
3
3
  /**
4
+ * @deprecated 2026-07-02 — alias of MenuItem (menu-family unify). Drops when nobody imports it (04-retirements.md).
4
5
  * MenuPopover — DEPRECATED alias of MenuItem (2026-07-02 menu-family
5
6
  * unification).
6
7
  *
@@ -0,0 +1,137 @@
1
+ import { Icon } from '@kolkrabbi/kol-icons'
2
+
3
+ /* taxonomy-ok: nests only kol-icons's Icon (a package import the
4
+ * relative-import check can't see). */
5
+
6
+ /**
7
+ * SectionCardItem — the card SectionCards is made of. Renamed from
8
+ * CardFeatureItem 2026-08-26 (user: the composition is the card, so its parts
9
+ * are card ITEMS); `CardFeatureItem` stays as a deprecated alias.
10
+ *
11
+ * SectionCardItem — fixed-height feature card: a title + optional icon
12
+ * header, a flexible visual middle, and a mono description footer. The
13
+ * card's visual is polymorphic: an `.svg` URL string renders as a
14
+ * `mask-image` block tinted with `currentColor` (theme-correct line-art),
15
+ * any other string renders as a cover-fit `<img>`, a ReactNode renders
16
+ * as-is, and no visual falls back to a large 96px `Icon` (the header's
17
+ * `icon` name). The grid child of FeaturesCardSection.
18
+ *
19
+ * Optionally the whole card is a link. `http*` / `mailto` hrefs open in a
20
+ * new tab; any other href renders a plain same-tab anchor with an
21
+ * `onNavigate(event)` seam — an SPA consumer intercepts there
22
+ * (preventDefault + its router) instead of this component importing one.
23
+ *
24
+ * Title and description render exactly as authored — no casing transforms;
25
+ * author strings in their final case at the call site.
26
+ *
27
+ * @param {ReactNode} title header heading (kol-helper-16)
28
+ * @param {string} icon Icon name for the header (16px); also the 96px no-visual fallback
29
+ * @param {string|ReactNode} visual image URL, `.svg` mask URL, or inline node
30
+ * @param {ReactNode} description footer line (kol-mono-12, muted)
31
+ * @param {string} backgroundColor card background utility class
32
+ * @param {string} href link target; `http*`/`mailto` → new tab, else plain same-tab anchor
33
+ * @param {Function} onNavigate (event) => void — click seam on the same-tab anchor (SPA intercept)
34
+ * @param {'auto'|'9/6'|'10/6'|'16/9'|'1/1'} imageAspectRatio aspect class on the visual middle
35
+ * @param {string} imagePosition `<img>` object-position
36
+ */
37
+ export default function SectionCardItem({
38
+ title,
39
+ icon,
40
+ visual,
41
+ description,
42
+ backgroundColor = 'bg-surface-primary',
43
+ href,
44
+ onNavigate,
45
+ imageAspectRatio = 'auto',
46
+ imagePosition = 'center',
47
+ }) {
48
+ const isSvgUrl = typeof visual === 'string' && visual.endsWith('.svg')
49
+
50
+ const aspectClasses = {
51
+ 'auto': '',
52
+ '9/6': 'aspect-[9/6]',
53
+ '10/6': 'aspect-[10/6]',
54
+ '16/9': 'aspect-video',
55
+ '1/1': 'aspect-square',
56
+ }
57
+ const aspectClass = aspectClasses[imageAspectRatio] || ''
58
+
59
+ const content = (
60
+ <>
61
+ <div className="w-full flex items-center justify-between gap-2">
62
+ <h3 className="kol-helper-16">{title}</h3>
63
+ {icon && <Icon name={icon} size={16} className="shrink-0" />}
64
+ </div>
65
+
66
+ {/* kol-card-feature-visual: zooms 1.03 on card hover (chrome in
67
+ * kol-theme — CardFeatureHoverZoom 2026-08-12); all three visual
68
+ * forms ride the same wrapper, reduced-motion opts out. */}
69
+ <div className={`kol-card-feature-visual w-full flex-1 flex items-center justify-center overflow-hidden ${aspectClass}`.trim()}>
70
+ {visual ? (
71
+ typeof visual === 'string' ? (
72
+ isSvgUrl ? (
73
+ /* currentColor line-art: the SVG paints as a mask over bg-current */
74
+ <div
75
+ className="w-full h-full bg-current rounded"
76
+ style={{
77
+ maskImage: `url(${visual})`,
78
+ maskSize: 'contain',
79
+ maskRepeat: 'no-repeat',
80
+ maskPosition: 'center',
81
+ WebkitMaskImage: `url(${visual})`,
82
+ WebkitMaskSize: 'contain',
83
+ WebkitMaskRepeat: 'no-repeat',
84
+ WebkitMaskPosition: 'center',
85
+ }}
86
+ />
87
+ ) : (
88
+ <img
89
+ src={visual}
90
+ alt={typeof title === 'string' ? title : ''}
91
+ className="w-full h-full object-cover rounded"
92
+ style={{ objectPosition: imagePosition }}
93
+ />
94
+ )
95
+ ) : (
96
+ visual
97
+ )
98
+ ) : (
99
+ <Icon name={icon} size={96} />
100
+ )}
101
+ </div>
102
+
103
+ <p className="kol-mono-12 text-fg-48">{description}</p>
104
+ </>
105
+ )
106
+
107
+ const baseClasses = `kol-card-feature w-full flex-1 h-[304px] md:h-72 p-4 md:p-6 gap-4 ${backgroundColor} rounded border border-fg-08 flex flex-col justify-between items-start overflow-hidden`
108
+
109
+ if (href) {
110
+ const isExternal = href.startsWith('http') || href.startsWith('mailto')
111
+
112
+ if (isExternal) {
113
+ return (
114
+ <a
115
+ href={href}
116
+ className={`${baseClasses} hover:border-fg-32 transition-colors duration-300`}
117
+ target="_blank"
118
+ rel="noreferrer noopener"
119
+ >
120
+ {content}
121
+ </a>
122
+ )
123
+ }
124
+
125
+ return (
126
+ <a
127
+ href={href}
128
+ onClick={onNavigate}
129
+ className={`${baseClasses} hover:border-fg-24 transition-colors duration-300`}
130
+ >
131
+ {content}
132
+ </a>
133
+ )
134
+ }
135
+
136
+ return <div className={baseClasses}>{content}</div>
137
+ }
@@ -961,8 +961,9 @@ export default function MediaLibrary({
961
961
  return withProvider(<BrowserShell onSelect={onSelect} />, opts)
962
962
  }
963
963
 
964
- /** Alias — `MediaLibrary variant="modal"`. Kept so existing call sites and the
965
- * fxr editor's `onPick` naming keep working. */
964
+ /** @deprecated 2026-08-01 alias of `MediaLibrary variant="modal"`. Kept so
965
+ * existing call sites and the fxr editor's `onPick` naming keep working;
966
+ * drops when nobody imports it (04-retirements.md). */
966
967
  export function MediaPicker({ open, client, accept = 'all', onClose, onPick }) {
967
968
  return (
968
969
  <MediaLibrary
@@ -976,8 +977,8 @@ export function MediaPicker({ open, client, accept = 'all', onClose, onPick }) {
976
977
  )
977
978
  }
978
979
 
979
- /** Alias — `MediaLibrary variant="page"`. Without `onSelect` the actions offer
980
- * Copy URL + download only, which is the read-only page a brand book wants. */
980
+ /** @deprecated 2026-08-01 alias of `MediaLibrary variant="page"`. Drops when
981
+ * nobody imports it (04-retirements.md). */
981
982
  export function MediaBrowser({ client, accept = 'all', onSelect = null, ...rest }) {
982
983
  return <MediaLibrary variant="page" client={client} accept={accept} onSelect={onSelect} {...rest} />
983
984
  }
@@ -1,9 +1,9 @@
1
- import CardFeatureItem from '../molecules/CardFeatureItem.jsx'
1
+ import SectionCardItem from '../molecules/SectionCardItem.jsx'
2
2
  import SectionText, { HEADLINE_ROLE } from '../molecules/SectionText.jsx'
3
3
 
4
4
  /**
5
5
  * SectionCards — the "N-up feature cards" band: a `SectionText` header over a
6
- * responsive row of `CardFeatureItem` cards, capped by an optional centred
6
+ * responsive row of `SectionCardItem` cards, capped by an optional centred
7
7
  * action row. `FeaturesCardSection` is this component under its old name and
8
8
  * prop names (`headerLabel` → `headline`, `headerDescription` → `body`,
9
9
  * `ctas` → `actions`; alias kept).
@@ -57,7 +57,7 @@ export default function SectionCards({
57
57
  {features.length > 0 && (
58
58
  <div className={cardsWrapperClassName}>
59
59
  {features.map((feature, index) => (
60
- <CardFeatureItem
60
+ <SectionCardItem
61
61
  key={index}
62
62
  title={feature.title}
63
63
  icon={feature.icon}