@kolkrabbi/kol-component 0.86.0 → 0.88.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.86.0",
3
+ "version": "0.88.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",
@@ -65,8 +65,8 @@ const HOVER = {
65
65
  catalog: 'var(--kol-surface-tertiary)',
66
66
  print: 'var(--kol-oq-04)',
67
67
  /* article and work take NO surface hover, and that is a decision not a gap:
68
- * article has no surface of its own (its media frame steps its border
69
- * instead), and work's whole hover IS the drawer rising. A second wash under
68
+ * article has no surface of its own (its media frame, when on, steps its
69
+ * border instead), and work's whole hover IS the drawer rising. A second wash under
70
70
  * either would be two answers to one question. */
71
71
  article: null,
72
72
  work: null,
@@ -75,16 +75,18 @@ const HOVER = {
75
75
 
76
76
  /* per-variant media treatment. `ring` sits OVER the artwork, `frame` UNDER it —
77
77
  * see ContentMedia. print rings because an A4 print on a light page has no edge
78
- * of its own; article frames because its media is a 16/9 thumbnail that rarely
79
- * fills its box. */
78
+ * of its own; article CAN frame (opt-in since 0.88.0) because its media is a
79
+ * 16/9 thumbnail that rarely fills its box. */
80
80
  const MEDIA = {
81
81
  /* zoom is for IMAGE-LED cards — where the artwork is the content and the
82
82
  * card is a frame around it. A catalog tile whose preview is a diagram, or
83
83
  * a default file card whose thumb is a 48px chip, gets nothing from it. */
84
84
  print: { ring: true, zoom: true },
85
85
  work: { zoom: true },
86
- /* ListingCard's card media steps its border on hover — fg-08 fg-16 */
87
- article: { frame: true, borderHover: true, zoom: true },
86
+ /* frame OFF by default (ListingCardThumbBorder, user 2026-08-27: "I hate
87
+ * border remove border"): the article thumb's hairline is opt-in —
88
+ * `frame` turns it on, and with it the fg-08 → fg-16 hover step */
89
+ article: { frame: false, borderHover: true, zoom: true },
88
90
  }
89
91
 
90
92
  export default function ContentCard({
@@ -31,8 +31,18 @@ import usePrefersReducedMotion from '../hooks/usePrefersReducedMotion.js'
31
31
  * ties it to the root font-size, so a user bumping their browser text size
32
32
  * silently re-counts the columns of every wall in the estate.
33
33
  *
34
+ * `cols` is the PAGE's call (ContentCollectionCols, kol-website 2026-08-27 —
35
+ * user: "translate that to something usable, consistent"): every filtered grid
36
+ * on the website was ruled as a COLUMN COUNT (`/stack`: one below md, three
37
+ * from md), and back-solving a `min` that happens to yield three on the
38
+ * container ladder is a number nobody picked. `cols={N}` says the count;
39
+ * `min` stays the default for the fluid wall above. Literal class strings —
40
+ * a class built at runtime is never emitted.
41
+ *
34
42
  * @param {string} form 'grid' | 'list'
35
43
  * @param {string} min grid track minimum, card form (default 320px)
44
+ * @param {number} cols OPT-IN column count, grid form: 1 below md, N from
45
+ * md (2–6). Wins over `min`; the list form ignores it
36
46
  * @param {string} listMin OPT-IN: makes the list multi-column too, for a dense
37
47
  * file-browser cut. Unset = one full-width column
38
48
  * @param {number} gap px between items. UNSET reads the token for the
@@ -43,9 +53,19 @@ import usePrefersReducedMotion from '../hooks/usePrefersReducedMotion.js'
43
53
  * nine call sites. Pass a number only to differ
44
54
  * @param {boolean} stagger enter animation on/off (reduced motion wins)
45
55
  */
56
+ const COLS = {
57
+ 1: 'grid-cols-1',
58
+ 2: 'grid-cols-1 md:grid-cols-2',
59
+ 3: 'grid-cols-1 md:grid-cols-3',
60
+ 4: 'grid-cols-1 md:grid-cols-4',
61
+ 5: 'grid-cols-1 md:grid-cols-5',
62
+ 6: 'grid-cols-1 md:grid-cols-6',
63
+ }
64
+
46
65
  export default function ContentCollection({
47
66
  form = 'grid',
48
67
  min = '320px',
68
+ cols,
49
69
  listMin,
50
70
  gap,
51
71
  stagger = true,
@@ -61,15 +81,19 @@ export default function ContentCollection({
61
81
  ? `${gap}px`
62
82
  : `var(--kol-gap-wall-${form === 'list' ? 'list' : 'grid'})`
63
83
 
84
+ const colsCls = form !== 'list' && COLS[cols] ? COLS[cols] : ''
64
85
  return (
65
86
  <ul
66
87
  key={form}
67
- className={`m-0 list-none p-0 ${className}`.trim()}
88
+ className={`m-0 list-none p-0 ${colsCls} ${className}`.replace(/\s+/g, ' ').trim()}
68
89
  style={{
69
90
  display: 'grid',
70
- gridTemplateColumns: form === 'list'
71
- ? (listMin ? `repeat(auto-fill, minmax(${listMin}, 1fr))` : '1fr')
72
- : `repeat(auto-fill, minmax(${min}, 1fr))`,
91
+ /* with `cols` the classes carry the tracks — an inline template would outrank them */
92
+ gridTemplateColumns: colsCls
93
+ ? undefined
94
+ : form === 'list'
95
+ ? (listMin ? `repeat(auto-fill, minmax(${listMin}, 1fr))` : '1fr')
96
+ : `repeat(auto-fill, minmax(${min}, 1fr))`,
73
97
  gap: g,
74
98
  }}
75
99
  >