@kolkrabbi/kol-component 0.154.0 → 0.155.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 +1 -1
- package/src/molecules/ProfileCard.jsx +45 -11
- package/src/organisms/SectionCards.jsx +1 -1
- package/src/organisms/SectionCta.jsx +1 -1
- package/src/organisms/SectionFaq.jsx +1 -1
- package/src/organisms/SectionHero.jsx +1 -1
- package/src/organisms/SectionNewsletter.jsx +1 -1
- package/src/organisms/SectionSplit.jsx +1 -1
- /package/src/{organisms → utilities}/sectionSurface.js +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-component",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.155.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",
|
|
@@ -2,6 +2,8 @@ import { useId, useState } from 'react'
|
|
|
2
2
|
import { Icon } from '@kolkrabbi/kol-icons'
|
|
3
3
|
import IconFrame from '../atoms/IconFrame.jsx'
|
|
4
4
|
import { Tooltip } from '../utilities/Popover.jsx'
|
|
5
|
+
import useSectionTheme from '../hooks/useSectionTheme.js'
|
|
6
|
+
import { surfaceClass } from '../utilities/sectionSurface.js'
|
|
5
7
|
|
|
6
8
|
/* taxonomy-ok: nests kol-icons's Icon (a package import the relative-import
|
|
7
9
|
* check can't see). */
|
|
@@ -12,7 +14,20 @@ import { Tooltip } from '../utilities/Popover.jsx'
|
|
|
12
14
|
* a square photo with a disclosure control inset on it, and a SHELF that opens
|
|
13
15
|
* under it (vertical) or beside it (horizontal) — logo, name, mailto, a rack of
|
|
14
16
|
* socials. The shelf is `bg-surface-inverse` / `text-auto-inverse` at every
|
|
15
|
-
* theme: the inverse of the page is the design, not a bug.
|
|
17
|
+
* theme by default: the inverse of the page is the design, not a bug.
|
|
18
|
+
*
|
|
19
|
+
* THE SHELF HAS SEAMS (user, 2026-09-01: "is it dark in light mode? are there
|
|
20
|
+
* light/dark or color variants on the shelf? variant on toggle? variant on
|
|
21
|
+
* logo? padding?"), on the mechanisms the section family already uses:
|
|
22
|
+
* `shelfTheme` is the section `theme` stamp (`data-theme` on the shelf, so
|
|
23
|
+
* every token inside — text, logo ink via currentColor, the mailto's underline
|
|
24
|
+
* — resolves to that theme and `inverse` follows the toggle); `shelfBackground`
|
|
25
|
+
* is the section `background` prop (a named surface or a raw token); with a
|
|
26
|
+
* theme stamped the default paint is that theme's `primary`, without one it is
|
|
27
|
+
* `inverse` with inverse ink, exactly as shipped. `controlVariant` goes straight
|
|
28
|
+
* to the disclosure's `IconFrame`; `pad` is `ContentCard`'s — one step on
|
|
29
|
+
* `--kol-pad-card-*`, overriding the size ramp's padding. The logo is a slot
|
|
30
|
+
* and stays one: its ink follows the shelf, a coloured mark is the asset's.
|
|
16
31
|
*
|
|
17
32
|
* THE SHELF SIZES TO ITS CONTENT. The source held it in a fixed box
|
|
18
33
|
* (`h-60`/`h-44`/`h-32`/`h-24`, `overflow-hidden`) and every vertical size
|
|
@@ -47,13 +62,17 @@ import { Tooltip } from '../utilities/Popover.jsx'
|
|
|
47
62
|
*
|
|
48
63
|
* @param {string} image photo URL — square, `object-cover object-top`
|
|
49
64
|
* @param {string} alt the photo's alt (default: `name`)
|
|
50
|
-
* @param {ReactNode} logo the lockup — sized by the ramp
|
|
65
|
+
* @param {ReactNode} logo the lockup — sized by the ramp: the node and any svg inside it take the ramp's height, width auto; `text-auto-inverse`
|
|
51
66
|
* @param {string} name the person
|
|
52
67
|
* @param {string} email rendered as a `mailto:`
|
|
53
68
|
* @param {Array} socials `[{ icon, href, label }]` — one Icon-in-Tooltip each, external links
|
|
54
69
|
* @param {'xl'|'lg'|'md'|'sm'} size the ramp + width cap (680 · 480 · 320 · 200); default xl
|
|
55
70
|
* @param {'vertical'|'horizontal'} orientation shelf under the photo (card grows) or beside it (card holds its square, photo crops)
|
|
56
71
|
* @param {string} variant alias for the source's names — `'lg-h'` = `size="lg" orientation="horizontal"`, any other value = `size`
|
|
72
|
+
* @param {'inverse'|'light'|'dark'} shelfTheme the shelf's theme scope — stamps `data-theme`; `inverse` = the paired theme of the page, following the toggle; omit for the shipped inverse-surface look
|
|
73
|
+
* @param {'primary'|'secondary'|'tertiary'|'inverse'|'auto'|'none'|string} shelfBackground the shelf's surface — a named surface or a raw utility / token string; default `inverse`, or `primary` once a `shelfTheme` is stamped
|
|
74
|
+
* @param {'primary'|'secondary'|'accent'|'outline'|'ghost'|'nav'|'grey'|'danger'} controlVariant the disclosure's `IconFrame` variant (default `secondary`)
|
|
75
|
+
* @param {'sm'|'md'|'lg'} pad shelf padding on `--kol-pad-card-*` (12 · 16 · 24), overriding the size ramp's
|
|
57
76
|
* @param {boolean} open controlled open state
|
|
58
77
|
* @param {boolean} defaultOpen uncontrolled initial state (default false)
|
|
59
78
|
* @param {Function} onOpenChange `(open) => void`
|
|
@@ -81,6 +100,10 @@ export default function ProfileCard({
|
|
|
81
100
|
size = 'xl',
|
|
82
101
|
orientation = 'vertical',
|
|
83
102
|
variant,
|
|
103
|
+
shelfTheme,
|
|
104
|
+
shelfBackground,
|
|
105
|
+
controlVariant = 'secondary',
|
|
106
|
+
pad,
|
|
84
107
|
open,
|
|
85
108
|
defaultOpen = false,
|
|
86
109
|
onOpenChange,
|
|
@@ -99,11 +122,19 @@ export default function ProfileCard({
|
|
|
99
122
|
}
|
|
100
123
|
const shelfId = useId()
|
|
101
124
|
|
|
125
|
+
/* the shelf's paint and ink: stamped → that theme's own tokens (`text-auto`
|
|
126
|
+
* resolves inside the stamp); unstamped → the shipped inverse pair */
|
|
127
|
+
const [themeRef, themeStamp] = useSectionTheme(shelfTheme)
|
|
128
|
+
const shelfBg = surfaceClass(shelfBackground, shelfTheme ? 'primary' : 'inverse')
|
|
129
|
+
const ink = !shelfTheme && shelfBg === 'bg-surface-inverse' ? 'text-auto-inverse' : 'text-auto'
|
|
130
|
+
const padStyle = pad ? { padding: `var(--kol-pad-card-${pad})` } : undefined
|
|
131
|
+
const padCls = pad ? '' : ramp.pad
|
|
132
|
+
|
|
102
133
|
const control = (
|
|
103
134
|
<div className={`absolute ${ramp.control}`}>
|
|
104
135
|
<IconFrame
|
|
105
136
|
name={isOpen ? 'minus' : 'plus'}
|
|
106
|
-
variant=
|
|
137
|
+
variant={controlVariant}
|
|
107
138
|
size="md"
|
|
108
139
|
radius="full"
|
|
109
140
|
aria-expanded={isOpen}
|
|
@@ -117,15 +148,18 @@ export default function ProfileCard({
|
|
|
117
148
|
<img src={image} alt={alt ?? name ?? ''} className="w-full h-full object-cover object-top" loading="lazy" />
|
|
118
149
|
)
|
|
119
150
|
const lockup = logo != null && (
|
|
120
|
-
|
|
151
|
+
/* `[&_svg]` not `[&>svg]`: a brand `Asset` wraps its svg, so the site had to
|
|
152
|
+
* re-add the sizing on the node it passed — the slot sizes whatever it is
|
|
153
|
+
* handed, wrapped or bare */
|
|
154
|
+
<div className={`inline-flex ${ramp.logo} ${ink} [&>*]:h-full [&_svg]:h-full [&_svg]:w-auto`}>{logo}</div>
|
|
121
155
|
)
|
|
122
156
|
const contact = (
|
|
123
157
|
<div className={`flex flex-col ${horizontal ? 'gap-1.5' : 'gap-1'} antialiased`} style={{ lineHeight: 1 }}>
|
|
124
|
-
{name && <span className={`${ramp.text}
|
|
158
|
+
{name && <span className={`${ramp.text} ${ink}`}>{name}</span>}
|
|
125
159
|
{email && (
|
|
126
160
|
<a
|
|
127
161
|
href={`mailto:${email}`}
|
|
128
|
-
className={`${ramp.text}
|
|
162
|
+
className={`${ramp.text} ${ink} underline decoration-2 decoration-transparent hover:decoration-current transition-all`}
|
|
129
163
|
>
|
|
130
164
|
{email}
|
|
131
165
|
</a>
|
|
@@ -141,7 +175,7 @@ export default function ProfileCard({
|
|
|
141
175
|
target="_blank"
|
|
142
176
|
rel="noopener noreferrer"
|
|
143
177
|
aria-label={label}
|
|
144
|
-
className={`${ramp.iconBox} flex items-center justify-center
|
|
178
|
+
className={`${ramp.iconBox} flex items-center justify-center ${ink} transition-transform hover:scale-125`}
|
|
145
179
|
>
|
|
146
180
|
<Icon name={icon} size={ramp.iconSize} />
|
|
147
181
|
</a>
|
|
@@ -158,8 +192,8 @@ export default function ProfileCard({
|
|
|
158
192
|
>
|
|
159
193
|
{/* Shelf — LEFT. The inner column holds the open width so the text does
|
|
160
194
|
* not reflow while the track animates. */}
|
|
161
|
-
<div id={shelfId} className=
|
|
162
|
-
<div className={`h-full ${
|
|
195
|
+
<div id={shelfId} ref={themeRef} data-theme={themeStamp} className={`min-w-0 overflow-hidden ${shelfBg}`}>
|
|
196
|
+
<div className={`h-full ${padCls} flex flex-col justify-between items-start`} style={{ width: HORIZONTAL.shelf, ...padStyle }}>
|
|
163
197
|
{lockup}
|
|
164
198
|
<div className="flex flex-col gap-8">
|
|
165
199
|
{contact}
|
|
@@ -189,8 +223,8 @@ export default function ProfileCard({
|
|
|
189
223
|
className="grid transition-[grid-template-rows] duration-300 ease-in-out"
|
|
190
224
|
style={{ gridTemplateRows: isOpen ? '1fr' : '0fr' }}
|
|
191
225
|
>
|
|
192
|
-
<div id={shelfId} className=
|
|
193
|
-
<div className={`${
|
|
226
|
+
<div id={shelfId} ref={themeRef} data-theme={themeStamp} className={`min-h-0 overflow-hidden ${shelfBg}`}>
|
|
227
|
+
<div className={`${padCls} flex justify-between items-end`} style={padStyle}>
|
|
194
228
|
<div className="self-stretch flex flex-col justify-between items-start">
|
|
195
229
|
{lockup}
|
|
196
230
|
{contact}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import SectionCardItem from '../molecules/SectionCardItem.jsx'
|
|
2
2
|
import { FULL_BLEED } from './sectionBleed.js'
|
|
3
|
-
import { surfaceClass } from '
|
|
3
|
+
import { surfaceClass } from '../utilities/sectionSurface.js'
|
|
4
4
|
import SectionText, { HEADLINE_ROLE } from '../molecules/SectionText.jsx'
|
|
5
5
|
import useSectionTheme from '../hooks/useSectionTheme.js'
|
|
6
6
|
import { minHeightClass } from './sectionHeights.js'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Button from '../atoms/Button.jsx'
|
|
2
2
|
import { FULL_BLEED } from './sectionBleed.js'
|
|
3
|
-
import { surfaceClass } from '
|
|
3
|
+
import { surfaceClass } from '../utilities/sectionSurface.js'
|
|
4
4
|
import SectionText from '../molecules/SectionText.jsx'
|
|
5
5
|
import { minHeightClass } from './sectionHeights.js'
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useState } from 'react'
|
|
2
2
|
import { FULL_BLEED } from './sectionBleed.js'
|
|
3
|
-
import { surfaceClass } from '
|
|
3
|
+
import { surfaceClass } from '../utilities/sectionSurface.js'
|
|
4
4
|
import { Accordion, AccordionPanel } from '../molecules/Accordion.jsx'
|
|
5
5
|
import SectionText from '../molecules/SectionText.jsx'
|
|
6
6
|
import { minHeightClass } from './sectionHeights.js'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isValidElement } from 'react'
|
|
2
2
|
import { FULL_BLEED, bleedClass } from './sectionBleed.js'
|
|
3
|
-
import { surfaceClass } from '
|
|
3
|
+
import { surfaceClass } from '../utilities/sectionSurface.js'
|
|
4
4
|
import HlsVideo from '../atoms/HlsVideo.jsx'
|
|
5
5
|
import Image from '../atoms/Image.jsx'
|
|
6
6
|
import OverlayGlassPanel from '../utilities/OverlayGlassPanel.jsx'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useId, useState } from 'react'
|
|
2
2
|
import { bleedClass } from './sectionBleed.js'
|
|
3
|
-
import { surfaceClass } from '
|
|
3
|
+
import { surfaceClass } from '../utilities/sectionSurface.js'
|
|
4
4
|
import Input from '../atoms/Input.jsx'
|
|
5
5
|
import Button from '../atoms/Button.jsx'
|
|
6
6
|
import SectionText from '../molecules/SectionText.jsx'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import SectionText from '../molecules/SectionText.jsx'
|
|
2
2
|
import { FULL_BLEED } from './sectionBleed.js'
|
|
3
|
-
import { surfaceClass } from '
|
|
3
|
+
import { surfaceClass } from '../utilities/sectionSurface.js'
|
|
4
4
|
import useSectionTheme from '../hooks/useSectionTheme.js'
|
|
5
5
|
import { minHeightClass } from './sectionHeights.js'
|
|
6
6
|
|
|
File without changes
|