@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.
|
|
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/
|
|
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
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
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
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
980
|
-
*
|
|
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
|
|
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 `
|
|
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
|
-
<
|
|
60
|
+
<SectionCardItem
|
|
61
61
|
key={index}
|
|
62
62
|
title={feature.title}
|
|
63
63
|
icon={feature.icon}
|