@kolkrabbi/kol-component 0.61.0 → 0.63.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.61.0",
3
+ "version": "0.63.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",
@@ -81,6 +81,8 @@ export default function SearchInput({
81
81
  open,
82
82
  onOpenChange,
83
83
  expandedWidth = 280,
84
+ iconSize,
85
+ fieldHeight,
84
86
  triggerLabel = 'Open search',
85
87
  className = '',
86
88
  ...inputProps
@@ -100,11 +102,14 @@ export default function SearchInput({
100
102
 
101
103
  /* the pinned squares, 05-control-chrome.md — sm 28 · md 32 · lg 36 */
102
104
  const square = { sm: 28, md: 32, lg: 36 }[size] ?? 32
103
- /* THE OPEN FIELD IS SHORTER THAN THE TRIGGER'S HIT AREA. The square is the
104
- * click target and it is INVISIBLE at rest (no fill), so the pill does not
105
- * have to inherit its height at 32 the field read as a chunky input beside
106
- * two bare glyphs. It sits one rung down and centres inside the same box. */
107
- const fieldH = square - 4
105
+ /* THE OPEN FIELD'S HEIGHT IS ITS OWN KNOB, defaulting to the square.
106
+ *
107
+ * /work's pill is `h-9` open AND closed, sitting level with a 36px toggle
108
+ * that is the shipped design and the default must reproduce it. But a field
109
+ * beside two BARE 32px glyphs (ContentFilters) read as chunky at the full
110
+ * square, so that surface asks for a shorter one. Deriving it (`square - 4`)
111
+ * served the second case and silently broke the first. */
112
+ const fieldH = fieldHeight ?? square
108
113
 
109
114
  /* Escape closes, and so does clicking away — a field that can only be closed
110
115
  * by emptying it and blurring is a trap, and this one had neither wired. The
@@ -145,7 +150,7 @@ export default function SearchInput({
145
150
  {!isOpen && (
146
151
  <button
147
152
  type="button"
148
- className="flex items-center justify-center rounded-full text-auto flex-shrink-0 border border-transparent transition-colors hover:border-oq-16"
153
+ className="flex items-center justify-center rounded-full text-auto flex-shrink-0 border border-transparent transition-colors hover:border-oq-08"
149
154
  style={{ width: square, height: square }}
150
155
  onClick={() => setOpen(true)}
151
156
  aria-label={triggerLabel}
@@ -154,7 +159,7 @@ export default function SearchInput({
154
159
  {/* SOLO ladder, and NO ink class — it inherits from its chrome
155
160
  exactly as IconFrame's glyph does, so it cannot drift from the
156
161
  icon beside it. */}
157
- <Icon name="search" size={glyphSize(size, true)} />
162
+ <Icon name="search" size={iconSize ?? glyphSize(size, true)} />
158
163
  </button>
159
164
  )}
160
165
  {isOpen && (
@@ -201,7 +206,7 @@ export default function SearchInput({
201
206
  className={`flex items-center shrink-0 ${bare ? 'text-fg-48' : 'text-auto opacity-50'}`}
202
207
  >
203
208
  {/* ADJACENT — this glyph sits in the field's line box beside the query */}
204
- <Icon name="search" size={glyphSize(size)} />
209
+ <Icon name="search" size={iconSize ?? glyphSize(size)} />
205
210
  </span>
206
211
  <input
207
212
  type="search"
@@ -81,12 +81,12 @@ 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
- /* The title is the SAME as RECENT/SAVED (user ruling 2026-08-15) same
85
- * rung, same casing, same tracking. It sits at the other end of the same
86
- * row, so a different treatment reads as two unrelated things rather than
87
- * one strip of chrome. */
84
+ /* SENTENCE CASE (user ruling 2026-08-15, reversing the uppercase pass an
85
+ * hour earlier). The title is a NAME, not a label the strips are chrome and
86
+ * wear caps; the thing being filtered keeps its own casing. Same rung as
87
+ * RECENT/SAVED, different casing, and that difference is the point. */
88
88
  titleClassName = 'kol-helper-14',
89
- titleUppercase = true,
89
+ titleUppercase = false,
90
90
  labelClassName = 'kol-helper-12 text-fg-96',
91
91
  labelUppercase = true,
92
92
  tagVariant = 'primary',
@@ -102,7 +102,11 @@ const ContentFilters = ({
102
102
  * pair moves to the opaque tier so it never washes out over a tinted surface. */
103
103
  stripActiveClassName = 'text-oq-96',
104
104
  stripRestClassName = 'text-oq-48 hover:text-oq-64',
105
- countClassName = 'kol-helper-12 text-fg-64',
105
+ /* THE COUNT IS PART OF THE STRIP IT SITS ON — same rung as LIST/GRID
106
+ * (`kol-helper-12`), same opaque tier. It carried `text-fg-64`, a
107
+ * translucent value on neither the active nor the rest rung, so it read as a
108
+ * third state that means nothing. It is static information: the REST ink. */
109
+ countClassName = 'kol-helper-12 text-oq-48',
106
110
  }) => {
107
111
  /* Icon seam — consumers on a local icon shelf pass their own component
108
112
  * rather than being forced onto the DS set. Needs `filter` + `search`. */
@@ -321,6 +325,9 @@ const ContentFilters = ({
321
325
  * The organism's own field never had one. */
322
326
  placeholder=""
323
327
  size="md"
328
+ /* a rung under the 32 square: this field sits beside two BARE
329
+ * glyphs, and at the full square it read as a chunky input. */
330
+ fieldHeight={28}
324
331
  />
325
332
  {headerActions}
326
333
  </div>
@@ -404,7 +411,9 @@ const ContentFilters = ({
404
411
  * toggle, so it takes neither the 96 active nor the 32 rest. */}
405
412
  {/* ONE LINE — the count sits BESIDE LIST/GRID, not stacked above it.
406
413
  * They are the same strip of chrome reading left to right. */}
407
- <div className="flex flex-shrink-0 items-center gap-4">
414
+ {/* ONE LINE, and the count needs room off the strip — at gap-4 the
415
+ * two read as one run of text rather than a label and a control. */}
416
+ <div className="flex flex-shrink-0 items-center gap-6">
408
417
  {showCount && isExpanded && (
409
418
  <span className={countClassName} style={{ letterSpacing: 1 }}>
410
419
  {filteredItems.length} of {totalCount}