@kolkrabbi/kol-component 0.59.0 → 0.60.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.60.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",
|
|
@@ -43,8 +43,29 @@ import { glyphSize } from '../hooks/glyphLadders.js'
|
|
|
43
43
|
* @param {string} className extra classes on the shell
|
|
44
44
|
*/
|
|
45
45
|
|
|
46
|
+
/* ONE type system and ONE glyph system for the whole component.
|
|
47
|
+
*
|
|
48
|
+
* It had two of each. The chromed path typed on `kol-mono-*` while the
|
|
49
|
+
* expanding path typed on `kol-helper-*`; the chromed path drew a FLAT 14px
|
|
50
|
+
* glyph at every size (`{ sm: 14, md: 14 }` — a size table that does not size)
|
|
51
|
+
* while the expanding path read the SOLO ladder. So the same component
|
|
52
|
+
* rendered two different fields depending on which branch you hit, and neither
|
|
53
|
+
* matched the IconFrame sitting next to it.
|
|
54
|
+
*
|
|
55
|
+
* Type is the mono ramp — a search field holds a query that can wrap, and
|
|
56
|
+
* `kol-helper-*` is line-height-1 chrome.
|
|
57
|
+
*
|
|
58
|
+
* The GLYPH READS BOTH LADDERS, because this component has both cases and they
|
|
59
|
+
* are the exact split `glyphLadders.js` exists for:
|
|
60
|
+
*
|
|
61
|
+
* SOLO the collapsed `expanding` trigger — a glyph ALONE in a pinned
|
|
62
|
+
* square, nothing beside it. 16 / 20 / 24.
|
|
63
|
+
* ADJACENT the leading glyph inside an open field, sitting in the input's
|
|
64
|
+
* line box beside the query text. 14 / 16 / 18.
|
|
65
|
+
*
|
|
66
|
+
* The flat `{ sm: 14, md: 14 }` it used to carry was the ADJACENT sm rung
|
|
67
|
+
* frozen for both sizes — right ladder, no size. */
|
|
46
68
|
const SIZE_TYPE = { sm: 'kol-mono-12', md: 'kol-mono-14' }
|
|
47
|
-
const ICON_SIZE = { sm: 14, md: 14 }
|
|
48
69
|
|
|
49
70
|
export default function SearchInput({
|
|
50
71
|
value = '',
|
|
@@ -115,7 +136,7 @@ export default function SearchInput({
|
|
|
115
136
|
readOnly={!onChange || undefined}
|
|
116
137
|
placeholder={placeholder}
|
|
117
138
|
spellCheck={false}
|
|
118
|
-
className=
|
|
139
|
+
className={`bg-transparent outline-none ${SIZE_TYPE[size] ?? SIZE_TYPE.md} flex-1 text-oq-80 caret-current pr-4 min-w-0 appearance-none [&::-webkit-search-cancel-button]:hidden`}
|
|
119
140
|
onKeyDown={(e) => { if (e.key === 'Escape') setOpen(false) }}
|
|
120
141
|
{...inputProps}
|
|
121
142
|
/>
|
|
@@ -149,7 +170,8 @@ export default function SearchInput({
|
|
|
149
170
|
aria-hidden="true"
|
|
150
171
|
className={`flex items-center shrink-0 ${bare ? 'text-fg-48' : 'text-auto opacity-50'}`}
|
|
151
172
|
>
|
|
152
|
-
|
|
173
|
+
{/* ADJACENT — this glyph sits in the field's line box beside the query */}
|
|
174
|
+
<Icon name="search" size={glyphSize(size)} />
|
|
153
175
|
</span>
|
|
154
176
|
<input
|
|
155
177
|
type="search"
|
|
@@ -21,7 +21,7 @@ import IconFrame from '../atoms/IconFrame.jsx'
|
|
|
21
21
|
* @param {Array} props.filterGroups — [{label, key, values}, ...]
|
|
22
22
|
* @param {Function} props.renderItem — (filteredItems, viewMode, layout) => ReactNode
|
|
23
23
|
* @param {Array} props.viewModeOptions — optional view mode options for the view strip
|
|
24
|
-
* @param {string} props.defaultViewMode — default view mode (
|
|
24
|
+
* @param {string} props.defaultViewMode — default view mode (falls back to the FIRST option)
|
|
25
25
|
* @param {Function} props.onFilterChange — optional callback when filters change
|
|
26
26
|
* @param {Array} props.mutuallyExclusiveFilters — filter keys that should be mutually exclusive
|
|
27
27
|
* @param {Array} props.customFilterKeys — filter keys handled by renderItem, not by ContentFilters
|
|
@@ -52,9 +52,14 @@ const ContentFilters = ({
|
|
|
52
52
|
viewModeOptions,
|
|
53
53
|
viewMode: viewModeProp,
|
|
54
54
|
onViewModeChange,
|
|
55
|
-
|
|
55
|
+
/* NO literal default. A strip always has exactly one active item, so the
|
|
56
|
+
* fallback must be the FIRST OPTION, not a guess — `'list'` matched nothing
|
|
57
|
+
* in a RECENT/SAVED strip, so any consumer that passed options without also
|
|
58
|
+
* passing a default rendered BOTH items in the rest state and the strip
|
|
59
|
+
* looked broken rather than unset. Same for `defaultLayout`. */
|
|
60
|
+
defaultViewMode,
|
|
56
61
|
layoutOptions,
|
|
57
|
-
defaultLayout
|
|
62
|
+
defaultLayout,
|
|
58
63
|
/* WHERE the LIST/GRID strip sits — the two arrangements kol-monitor and
|
|
59
64
|
* kol-website each settled on, made interchangeable (user ruling 2026-08-15).
|
|
60
65
|
*
|
|
@@ -95,9 +100,9 @@ const ContentFilters = ({
|
|
|
95
100
|
const IconSeam = iconComponent || Icon
|
|
96
101
|
const [activeFilters, setActiveFilters] = useState(new Set())
|
|
97
102
|
const [isExpanded, setIsExpanded] = useState(false)
|
|
98
|
-
const [internalViewMode, setInternalViewMode] = useState(defaultViewMode)
|
|
103
|
+
const [internalViewMode, setInternalViewMode] = useState(defaultViewMode ?? viewModeOptions?.[0]?.value)
|
|
99
104
|
const viewMode = viewModeProp !== undefined ? viewModeProp : internalViewMode
|
|
100
|
-
const [layout, setLayout] = useState(defaultLayout)
|
|
105
|
+
const [layout, setLayout] = useState(defaultLayout ?? layoutOptions?.[0]?.value ?? 'grid')
|
|
101
106
|
const [searchOpen, setSearchOpen] = useState(false)
|
|
102
107
|
const [searchText, setSearchText] = useState('')
|
|
103
108
|
|
|
@@ -294,6 +299,12 @@ const ContentFilters = ({
|
|
|
294
299
|
onChange={(e) => setSearchText(e.target.value)}
|
|
295
300
|
expandedWidth={200}
|
|
296
301
|
triggerLabel="Search"
|
|
302
|
+
/* NO placeholder. The field opens from a glyph you just clicked —
|
|
303
|
+
* the caret is the affordance, and a greyed "Search…" sitting in
|
|
304
|
+
* a 200px pill is the widest thing in the header saying the least.
|
|
305
|
+
* The organism's own field never had one. */
|
|
306
|
+
placeholder=""
|
|
307
|
+
size="md"
|
|
297
308
|
/>
|
|
298
309
|
{headerActions}
|
|
299
310
|
</div>
|