@kolkrabbi/kol-component 0.65.0 → 0.67.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.67.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",
|
package/src/atoms/Divider.jsx
CHANGED
|
@@ -10,15 +10,24 @@ import React from 'react'
|
|
|
10
10
|
* @param {Object} props
|
|
11
11
|
* @param {string} props.variant - 'horizontal' or 'vertical' (default: 'horizontal')
|
|
12
12
|
* @param {string} props.className - Additional classes
|
|
13
|
+
* @param {number} props.height - vertical variant only: the rule's height in px
|
|
14
|
+
* (default 16 — sized to the type it separates, not to the row)
|
|
13
15
|
* @param {string} props.opacity - Opacity level (01, 02, 04, 08, 12, 16, 24, 32, 48, 64, 80, 88, 96) (default: '08')
|
|
14
16
|
*/
|
|
15
|
-
const Divider = ({ variant = 'horizontal', className = '', opacity = '08', inverse = false }) => {
|
|
17
|
+
const Divider = ({ variant = 'horizontal', className = '', opacity = '08', inverse = false, height = 16 }) => {
|
|
16
18
|
const isVertical = variant === 'vertical'
|
|
17
19
|
const opacityClass = inverse ? `bg-fg-inverse-${opacity}` : `bg-fg-${opacity}`
|
|
18
20
|
|
|
19
21
|
if (isVertical) {
|
|
22
|
+
/* THE RULE IS CENTRED ON WHAT IT SEPARATES, not stretched to the row.
|
|
23
|
+
*
|
|
24
|
+
* This hardcoded `self-stretch` AHEAD of `className`, so the wrapper always
|
|
25
|
+
* filled the flex line — a row whose height comes from 32px icon buttons
|
|
26
|
+
* gave a rule taller than the 18px type beside it, and any `self-*` passed
|
|
27
|
+
* from a call site lost to the hardcoded one. `align-self: center` with an
|
|
28
|
+
* explicit height puts it back on the type; `height` stays overridable. */
|
|
20
29
|
return (
|
|
21
|
-
<div className={`
|
|
30
|
+
<div className={`flex self-center items-center justify-center ${className}`.trim()} style={{ height }}>
|
|
22
31
|
<div className={opacityClass} style={{ width: '1px', height: '100%' }} />
|
|
23
32
|
</div>
|
|
24
33
|
)
|
|
@@ -55,6 +55,12 @@ import AssetPlaceholder from '../utilities/AssetPlaceholder.jsx'
|
|
|
55
55
|
* @param {boolean} ring hairline border OVER the media, inset
|
|
56
56
|
* @param {boolean} zoom the artwork creeps up inside its frame on the
|
|
57
57
|
* CARD's hover — image-led variants only
|
|
58
|
+
* @param {boolean} fillHeight size from the HEIGHT instead of the width: the
|
|
59
|
+
* media fills its parent's height and its width
|
|
60
|
+
* follows the ratio. What every ROW wants — a
|
|
61
|
+
* thumb sized off the row's own height keeps the
|
|
62
|
+
* row's rhythm, where a fixed width leaves it
|
|
63
|
+
* floating in a tall row.
|
|
58
64
|
* @param {ReactNode} children the real media
|
|
59
65
|
*/
|
|
60
66
|
const FIT = {
|
|
@@ -73,6 +79,7 @@ export default function ContentMedia({
|
|
|
73
79
|
borderHover,
|
|
74
80
|
ring = false,
|
|
75
81
|
zoom = false,
|
|
82
|
+
fillHeight = false,
|
|
76
83
|
children,
|
|
77
84
|
className = '',
|
|
78
85
|
}) {
|
|
@@ -82,7 +89,7 @@ export default function ContentMedia({
|
|
|
82
89
|
const round = radius ? 'rounded-[var(--kol-radius-sm)]' : ''
|
|
83
90
|
return (
|
|
84
91
|
<div
|
|
85
|
-
className={`relative w-full overflow-hidden ${round} ${FIT[fit] ?? FIT.cover} ${frame ? 'bg-fg-04 border border-fg-08' : ''} ${border ? 'border border-fg-08' : ''} ${zoom ? 'kol-media-zoom' : ''} ${borderHover ? 'transition-colors hover:border-fg-16' : ''} ${ratio == null ? 'h-full' : ''} ${className}`.trim()}
|
|
92
|
+
className={`relative ${fillHeight ? 'h-full w-auto' : 'w-full'} overflow-hidden ${round} ${FIT[fit] ?? FIT.cover} ${frame ? 'bg-fg-04 border border-fg-08' : ''} ${border ? 'border border-fg-08' : ''} ${zoom ? 'kol-media-zoom' : ''} ${borderHover ? 'transition-colors hover:border-fg-16' : ''} ${ratio == null ? 'h-full' : ''} ${className}`.trim()}
|
|
86
93
|
style={{ ...(ratio != null ? { aspectRatio: ratio } : null), background: bg }}
|
|
87
94
|
>
|
|
88
95
|
{children}
|
|
@@ -100,8 +100,14 @@ export default function ContentRow({
|
|
|
100
100
|
) : (
|
|
101
101
|
<>
|
|
102
102
|
{thumbPx > 0 && (
|
|
103
|
-
|
|
103
|
+
/* THE THUMB FILLS THE ROW'S HEIGHT and its width follows the ratio
|
|
104
|
+
* (user ruling 2026-08-15, true for EVERY row variant). `--kol-row-thumb`
|
|
105
|
+
* is now a MINIMUM height, not a fixed width: a thumb sized off its own
|
|
106
|
+
* width floated in the top-left of a tall row with the rest of the row
|
|
107
|
+
* empty beside it, which is what a `work` row at 160 looked like. */
|
|
108
|
+
<div className="kol-row-thumb shrink-0 self-stretch">
|
|
104
109
|
<ContentMedia
|
|
110
|
+
fillHeight
|
|
105
111
|
ratio={ratio ?? box.ratio}
|
|
106
112
|
border={box.thumbBorder ?? false}
|
|
107
113
|
bg={box.thumbBg}
|
|
@@ -168,8 +168,11 @@ export default function ContentText({
|
|
|
168
168
|
const parts = slots.map((s, j) => render(s, j)).filter(Boolean)
|
|
169
169
|
if (!parts.length) return null
|
|
170
170
|
if (kind === 'stack') {
|
|
171
|
+
/* items-start + text-left: a trailing column reads DOWN, so its labels
|
|
172
|
+
* need one left edge. Right-aligned, `Client` / `Collection` / `Typeface`
|
|
173
|
+
* gave the column a ragged edge on the side the eye actually scans. */
|
|
171
174
|
return (
|
|
172
|
-
<div key={`stack-${i}`} className="flex w-full min-w-0 flex-col" style={{ gap: STACK[variant] ?? 'var(--kol-spacing-1)' }}>
|
|
175
|
+
<div key={`stack-${i}`} className="flex w-full min-w-0 flex-col items-start text-left" style={{ gap: STACK[variant] ?? 'var(--kol-spacing-1)' }}>
|
|
173
176
|
{parts}
|
|
174
177
|
</div>
|
|
175
178
|
)
|
|
@@ -190,7 +193,7 @@ export default function ContentText({
|
|
|
190
193
|
* empty space sat between the two columns. */}
|
|
191
194
|
{kind === 'between' && parts.length > 1
|
|
192
195
|
? parts.map((p, j) => (
|
|
193
|
-
<div key={j} className={j === 0 ? 'min-w-0 flex-1' : 'shrink-0'}>{p}</div>
|
|
196
|
+
<div key={j} className={j === 0 ? 'min-w-0 flex-1' : 'shrink-0 text-left'}>{p}</div>
|
|
194
197
|
))
|
|
195
198
|
: parts}
|
|
196
199
|
</div>
|
|
@@ -81,12 +81,11 @@ const ContentFilters = ({
|
|
|
81
81
|
/* THE LOOK SEAMS. Every one defaults to what the component shipped, so
|
|
82
82
|
* passing nothing renders exactly as before — these exist because the
|
|
83
83
|
* hardcoded values were the wrong call for every consumer but one. */
|
|
84
|
-
/*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
|
|
89
|
-
titleClassName = 'kol-mono-14',
|
|
84
|
+
/* HELPER + UPPERCASE. The title is part of the header STRIP — same chrome as
|
|
85
|
+
* RECENT/SAVED beside it — and helper is the single-line ramp that strip
|
|
86
|
+
* runs on. Casing and ramp are separate props precisely so a consumer whose
|
|
87
|
+
* titles wrap can move to `kol-mono-14` without losing the casing. */
|
|
88
|
+
titleClassName = 'kol-helper-14',
|
|
90
89
|
titleUppercase = true,
|
|
91
90
|
labelClassName = 'kol-helper-12 text-fg-96',
|
|
92
91
|
labelUppercase = true,
|
|
@@ -277,7 +276,7 @@ const ContentFilters = ({
|
|
|
277
276
|
{titleIcon && <IconFrame name={titleIcon} variant="secondary" size="md" />}
|
|
278
277
|
<span className={titleClassName} style={titleUppercase ? { textTransform: 'uppercase', letterSpacing: 1 } : undefined}>{title}</span>
|
|
279
278
|
</h2>
|
|
280
|
-
<Divider variant="vertical"
|
|
279
|
+
<Divider variant="vertical" />
|
|
281
280
|
<div className="flex items-center gap-1">
|
|
282
281
|
{/* IconFrame, not a kol-btn with its chrome cancelled inline.
|
|
283
282
|
* 05-control-chrome.md:109 — "any icon-only control in chrome is
|