@kolkrabbi/kol-component 0.64.0 → 0.65.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.64.0",
3
+ "version": "0.65.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",
@@ -111,6 +111,20 @@ export default function SearchInput({
111
111
  * served the second case and silently broke the first. */
112
112
  const fieldH = fieldHeight ?? square
113
113
 
114
+ /* THE GLYPH WAITS FOR THE COLLAPSE. Mounting it the instant `isOpen` flips
115
+ * put a search icon inside a 200px pill that was still shrinking around it —
116
+ * the one frame of the animation that looks like a bug. It reappears at
117
+ * 520ms, just under the 600ms `.kol-expand` width transition, so it lands as
118
+ * the pill arrives rather than riding it down. Opening hides it immediately:
119
+ * the field should take the space at once. */
120
+ const [glyphIn, setGlyphIn] = useState(!open)
121
+ useEffect(() => {
122
+ if (!expanding) return undefined
123
+ if (isOpen) { setGlyphIn(false); return undefined }
124
+ const t = setTimeout(() => setGlyphIn(true), 520)
125
+ return () => clearTimeout(t)
126
+ }, [expanding, isOpen])
127
+
114
128
  /* Escape closes, and so does clicking away — a field that can only be closed
115
129
  * by emptying it and blurring is a trap, and this one had neither wired. The
116
130
  * listener only exists while open. */
@@ -147,7 +161,7 @@ export default function SearchInput({
147
161
  2026-08-15). Once the field is open the caret is the affordance;
148
162
  keeping the magnifier there spends the widest part of the pill
149
163
  restating what the blinking cursor already says. */}
150
- {!isOpen && (
164
+ {glyphIn && !isOpen && (
151
165
  <button
152
166
  type="button"
153
167
  className="flex items-center justify-center rounded-full text-auto flex-shrink-0 border border-transparent transition-colors hover:border-oq-08"
@@ -81,12 +81,13 @@ 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
- /* 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
- titleClassName = 'kol-helper-14',
89
- titleUppercase = false,
84
+ /* MONO + UPPERCASE (user rulings 2026-08-15). Mono because the title is a
85
+ * NAME that can run long, and `kol-helper-*` is line-height-1 chrome carrying
86
+ * 500 weight and 0.06em tracking it should not inherit. Uppercase because it
87
+ * is still part of the header strip. Both knobs, set independently — which is
88
+ * the whole reason they are two props. */
89
+ titleClassName = 'kol-mono-14',
90
+ titleUppercase = true,
90
91
  labelClassName = 'kol-helper-12 text-fg-96',
91
92
  labelUppercase = true,
92
93
  tagVariant = 'primary',