@kolkrabbi/kol-component 0.58.0 → 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.58.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,6 +77,9 @@ 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
@@ -84,20 +88,23 @@ export default function SearchInput({
84
88
  filter icon it sits beside. `bg-fg-04` was unconditional, so the
85
89
  collapsed pill rendered as a filled circle next to a bare glyph and
86
90
  the pair looked like two different kinds of control. */
87
- className={`kol-expand flex items-center rounded-full h-9 ${isOpen ? 'bg-fg-04' : ''} ${className}`.trim()}
88
- /* motion is `.kol-expand` in kol-theme; only the WIDTH is per-instance */
89
- style={{ width: isOpen ? expandedWidth : 36 }}
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 }}
90
97
  >
91
98
  <button
92
99
  type="button"
93
- className={`flex items-center justify-center w-9 h-9 rounded-full text-auto flex-shrink-0 border border-transparent ${isOpen ? '' : 'transition-colors hover:border-fg-12'}`}
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 }}
94
102
  onClick={() => !isOpen && setOpen(true)}
95
103
  aria-label={triggerLabel}
96
104
  aria-expanded={isOpen}
97
105
  >
98
- {/* SOLO ladder, md rung a 36px trigger is the md square and takes
99
- a 20px glyph, not the sm rung's 16 */}
100
- <Icon name="search" size={20} className="text-fg-80" />
106
+ {/* SOLO ladder — the glyph moves WITH the square, never independently */}
107
+ <Icon name="search" size={glyphSize(size, true)} className="text-oq-80" />
101
108
  </button>
102
109
  {isOpen && (
103
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
- <div className="flex items-center justify-between mb-4">
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
- <button
253
- type="button"
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
- style={{ background: 'transparent', border: 'none', cursor: 'pointer', color: 'inherit' }}
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
- <Divider className="mb-4" />
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 pb-4">
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 className="mt-8" style={{ display: 'flex', flexDirection: 'column', flex: 1, minHeight: 0 }}>
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>