@kolkrabbi/kol-component 0.57.1 → 0.59.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.59.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,5 +1,6 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from 'react'
|
|
2
2
|
import { Icon } from '@kolkrabbi/kol-icons'
|
|
3
|
+
import { glyphSize } from '../hooks/glyphLadders.js'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* SearchInput — controlled search field on the .kol-control shell. The
|
|
@@ -76,21 +77,34 @@ export default function SearchInput({
|
|
|
76
77
|
if (expanding && isOpen) inputRef.current?.focus()
|
|
77
78
|
}, [expanding, isOpen])
|
|
78
79
|
|
|
80
|
+
/* the pinned squares, 05-control-chrome.md — sm 28 · md 32 · lg 36 */
|
|
81
|
+
const square = { sm: 28, md: 32, lg: 36 }[size] ?? 32
|
|
82
|
+
|
|
79
83
|
if (expanding) {
|
|
80
84
|
return (
|
|
81
85
|
<div
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
86
|
+
/* THE FILL BELONGS TO THE FIELD, NOT THE TRIGGER. At rest this is a
|
|
87
|
+
glyph you click, and it must read as one — bare, exactly like the
|
|
88
|
+
filter icon it sits beside. `bg-fg-04` was unconditional, so the
|
|
89
|
+
collapsed pill rendered as a filled circle next to a bare glyph and
|
|
90
|
+
the pair looked like two different kinds of control. */
|
|
91
|
+
/* THE SQUARE FOLLOWS THE LADDER, and it follows `size` like every other
|
|
92
|
+
control: sm 28 · md 32 · lg 36 (hooks/glyphLadders.js). This was a
|
|
93
|
+
hardcoded 36 — the LG square — so an expanding search sat beside a
|
|
94
|
+
`kol-btn-md` filter button at two different sizes. */
|
|
95
|
+
className={`kol-expand flex items-center rounded-full ${isOpen ? 'bg-fg-04' : ''} ${className}`.trim()}
|
|
96
|
+
style={{ height: square, width: isOpen ? expandedWidth : square }}
|
|
85
97
|
>
|
|
86
98
|
<button
|
|
87
99
|
type="button"
|
|
88
|
-
className={`flex items-center justify-center
|
|
100
|
+
className={`flex items-center justify-center rounded-full text-auto flex-shrink-0 border border-transparent ${isOpen ? '' : 'transition-colors hover:border-oq-16'}`}
|
|
101
|
+
style={{ width: square, height: square }}
|
|
89
102
|
onClick={() => !isOpen && setOpen(true)}
|
|
90
103
|
aria-label={triggerLabel}
|
|
91
104
|
aria-expanded={isOpen}
|
|
92
105
|
>
|
|
93
|
-
|
|
106
|
+
{/* SOLO ladder — the glyph moves WITH the square, never independently */}
|
|
107
|
+
<Icon name="search" size={glyphSize(size, true)} className="text-oq-80" />
|
|
94
108
|
</button>
|
|
95
109
|
{isOpen && (
|
|
96
110
|
<input
|
|
@@ -237,7 +237,18 @@ const ContentFilters = ({
|
|
|
237
237
|
* child refuses to shrink past its content, so a scrollable body pushed
|
|
238
238
|
* the whole card taller instead of scrolling inside it. */
|
|
239
239
|
<div className={`w-full ${className}`.trim()} style={{ display: 'flex', flexDirection: 'column', flex: 1, minHeight: 0 }}>
|
|
240
|
-
|
|
240
|
+
{/* ONE VERTICAL RHYTHM for the whole block, chosen together instead of
|
|
241
|
+
* four independent literals (header mb-4, divider mb-4, strip row pb-4,
|
|
242
|
+
* body mt-8 — none of which knew about the others):
|
|
243
|
+
*
|
|
244
|
+
* header → divider 12 the divider belongs TO the header, close
|
|
245
|
+
* divider → strip 12 same, it belongs to what follows
|
|
246
|
+
* strip → content 24 the one real break, wall starts here
|
|
247
|
+
*
|
|
248
|
+
* 12/12/24 on the --kol-spacing-* rungs. The old 16/16/32 spaced the
|
|
249
|
+
* divider equally from both sides, so it read as a free-floating line
|
|
250
|
+
* rather than the header's own baseline. */}
|
|
251
|
+
<div className="flex items-center justify-between" style={{ marginBottom: 'var(--kol-spacing-3)' }}>
|
|
241
252
|
<div className="flex items-center gap-6">
|
|
242
253
|
{/* IconFrame, NOT a kol-btn span: this is decoration and clicks
|
|
243
254
|
* nothing, so it must not wear a button's chrome. The atom exists
|
|
@@ -249,19 +260,23 @@ const ContentFilters = ({
|
|
|
249
260
|
</h2>
|
|
250
261
|
<Divider variant="vertical" className="self-stretch py-1" />
|
|
251
262
|
<div className="flex items-center gap-1">
|
|
252
|
-
|
|
253
|
-
|
|
263
|
+
{/* IconFrame, not a kol-btn with its chrome cancelled inline.
|
|
264
|
+
* 05-control-chrome.md:109 — "any icon-only control in chrome is
|
|
265
|
+
* IconFrame; nothing hand-writes the square". This wore
|
|
266
|
+
* `kol-btn-md kol-btn-icon` and then removed the background, the
|
|
267
|
+
* border and the colour by inline style, which is the whole button
|
|
268
|
+
* paid for and thrown away — and it left the control with no
|
|
269
|
+
* states at all while the search beside it had hover.
|
|
270
|
+
*
|
|
271
|
+
* `nav` rests at oq-64 and lights to full ink when the panel is
|
|
272
|
+
* open, so the toggle finally SHOWS that it is on. */}
|
|
273
|
+
<IconFrame
|
|
274
|
+
name="filter"
|
|
275
|
+
variant={isExpanded ? 'primary' : 'nav'}
|
|
276
|
+
size="md"
|
|
254
277
|
onClick={() => setIsExpanded(!isExpanded)}
|
|
255
|
-
className="kol-btn kol-btn-md kol-btn-icon"
|
|
256
278
|
aria-label="Toggle filters"
|
|
257
|
-
|
|
258
|
-
>
|
|
259
|
-
{/* SOLO ladder, md rung — a 32px square takes a 20px glyph.
|
|
260
|
-
* Both header glyphs were 16 (the sm rung) in md boxes, which is
|
|
261
|
-
* the exact hand-transcription hooks/glyphLadders.js exists to
|
|
262
|
-
* stop and the one ActionButton's docstring already names. */}
|
|
263
|
-
<IconSeam name="filter" size={glyphSize('md', true)} />
|
|
264
|
-
</button>
|
|
279
|
+
/>
|
|
265
280
|
{/* THE SEARCH IS `SearchInput expanding` — the DS component, fully
|
|
266
281
|
* round, the same pill the nav shelf uses (user ruling
|
|
267
282
|
* 2026-08-15). This organism hand-rolled its own: a rounded-sm box
|
|
@@ -321,7 +336,9 @@ const ContentFilters = ({
|
|
|
321
336
|
</div>
|
|
322
337
|
</div>
|
|
323
338
|
|
|
324
|
-
|
|
339
|
+
{/* Divider takes className, NOT style — a style prop here is silently
|
|
340
|
+
* dropped, which is how this margin nearly went missing. */}
|
|
341
|
+
<Divider className="mb-3" />
|
|
325
342
|
|
|
326
343
|
{/* BELOW the divider: the filter GROUPS only. Left-aligned columns —
|
|
327
344
|
* label above values — visible only while the filter toggle is open.
|
|
@@ -337,7 +354,7 @@ const ContentFilters = ({
|
|
|
337
354
|
* the whole row on `isExpanded` hid the strip until you opened filters,
|
|
338
355
|
* which is not a state anyone would guess at. */}
|
|
339
356
|
{(isExpanded || (layoutPlacement === 'below' && layoutStrip)) && (
|
|
340
|
-
<div className="flex items-start justify-between gap-16
|
|
357
|
+
<div className="flex items-start justify-between gap-16">
|
|
341
358
|
<div className="flex min-w-0 flex-1 items-start gap-16">
|
|
342
359
|
{isExpanded && filterGroups.map((group) => renderFilterGroup(group))}
|
|
343
360
|
{isExpanded && activeFilters.size > 0 && (
|
|
@@ -369,7 +386,7 @@ const ContentFilters = ({
|
|
|
369
386
|
</div>
|
|
370
387
|
)}
|
|
371
388
|
|
|
372
|
-
<div
|
|
389
|
+
<div style={{ marginTop: 'var(--kol-spacing-6)', display: 'flex', flexDirection: 'column', flex: 1, minHeight: 0 }}>
|
|
373
390
|
{renderItem(filteredItems, viewMode, layout)}
|
|
374
391
|
</div>
|
|
375
392
|
</div>
|