@kolkrabbi/kol-shell 0.47.0 → 0.48.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-shell",
3
- "version": "0.47.0",
3
+ "version": "0.48.0",
4
4
  "private": false,
5
5
  "description": "KOL application shell — fixed 48px NavRail + AppShell layout root, PageShell/PageHeader scaffolds, ContentFilters catalog organism, GridCard, SettingsScaffold, WalkthroughPanel, ShortcutsOverlay. App chrome (kol-framework owns site chrome). Nav items, content, shortcuts and settings are consumer-injected. Sits above @kolkrabbi/kol-{theme,component,framework}.",
6
6
  "license": "MIT",
@@ -14,16 +14,16 @@
14
14
  "peerDependencies": {
15
15
  "@kolkrabbi/kol-component": ">=0.174.0",
16
16
  "@kolkrabbi/kol-icons": ">=0.16.0",
17
- "@kolkrabbi/kol-theme": ">=0.137.0",
17
+ "@kolkrabbi/kol-theme": ">=0.138.0",
18
18
  "gsap": "^3.13.0",
19
19
  "react": "^18.3.0 || ^19.0.0",
20
20
  "react-dom": "^18.3.0 || ^19.0.0"
21
21
  },
22
22
  "devDependencies": {
23
- "@kolkrabbi/kol-component": "^0.176.0",
24
- "@kolkrabbi/kol-framework": "^0.41.0",
25
23
  "@kolkrabbi/kol-icons": "^0.25.0",
26
- "@kolkrabbi/kol-theme": "^0.137.0"
24
+ "@kolkrabbi/kol-component": "^0.177.0",
25
+ "@kolkrabbi/kol-framework": "^0.42.0",
26
+ "@kolkrabbi/kol-theme": "^0.138.0"
27
27
  },
28
28
  "files": [
29
29
  "src",
@@ -1,3 +1,4 @@
1
+ import { useCallback, useRef, useState } from 'react'
1
2
  import { ContentCard, ContentFilters, ContentRow } from '@kolkrabbi/kol-component'
2
3
  import PageShell from './PageShell.jsx'
3
4
  import { PageHeader } from '@kolkrabbi/kol-component'
@@ -124,8 +125,32 @@ export default function CatalogPage({
124
125
  style,
125
126
  }) {
126
127
  const open = walkthrough?.open === true
128
+ /* THE TRACK COUNT, MEASURED (CatalogFilterFirstGroupTrackCount, 2026-09-03).
129
+ * `.kol-catalog-grid` and `.kol-filters-first` both read `--kol-catalog-n`
130
+ * from the page: up to 6 tracks, none narrower than `minColumn`, gap 24 —
131
+ * `min(6, floor((W + 24) / (minColumn + 24)))`, exactly what the old inline
132
+ * `auto-fill` resolved to, now a number the filter row can read too. In JS
133
+ * because the CSS form (`round()` over a length ÷ length) is Chromium-only —
134
+ * theme 0.137.0 rendered ONE column in Firefox. `undefined` until measured
135
+ * → the theme's fallback of 6, the pre-0.137.0 geometry. */
136
+ const [cols, setCols] = useState(null)
137
+ const observer = useRef(null)
138
+ /* a CALLBACK ref: the grid mounts and unmounts with the layout toggle, and a
139
+ * callback ref sees both — an effect keyed on a value out of this scope does
140
+ * not (the first cut referenced `renderItem`'s `layout` here and threw) */
141
+ const gridRef = useCallback((el) => {
142
+ observer.current?.disconnect()
143
+ observer.current = null
144
+ if (!el) return
145
+ const measure = (W) => setCols((c) => { const n = Math.max(1, Math.min(6, Math.floor((W + 24) / (minColumn + 24)))); return c === n ? c : n })
146
+ measure(el.getBoundingClientRect().width)
147
+ const ro = new ResizeObserver(([entry]) => measure(entry.contentRect.width))
148
+ ro.observe(el)
149
+ observer.current = ro
150
+ }, [minColumn])
151
+
127
152
  return (
128
- <PageShell width={width} className={className} style={{ overflow: 'hidden', '--kol-catalog-min': `${minColumn}px`, ...style }}>
153
+ <PageShell width={width} className={className} style={{ overflow: 'hidden', '--kol-catalog-n': cols ?? undefined, ...style }}>
129
154
  {header && <PageHeader {...header} />}
130
155
  <div style={{ flex: 1, position: 'relative' }}>
131
156
  {open && <WalkthroughPanel steps={walkthrough.steps} iconComponent={walkthrough.iconComponent} />}
@@ -161,10 +186,10 @@ export default function CatalogPage({
161
186
  * six-column ruling — below the ceiling the hide-set is
162
187
  * desktop-only geometry. */
163
188
  return (
164
- /* the catalog grid is a CLASS (`.kol-catalog-grid`, kol-theme ≥0.137.0) so the
165
- * filter row's first group can read the track count it renders; `minColumn`
166
- * reaches it as `--kol-catalog-min` on the page (set on PageShell above) */
167
- <div className={layout === 'list' ? undefined : 'kol-catalog-grid'} style={layout === 'list' ? (listLayout === 'stack' ? { display: 'flex', flexDirection: 'column', gap: 8 } : { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(min(100%, max(240px, calc((100% - 3 * 8px) / 4))), 1fr))', gap: 8 }) : undefined}>
189
+ /* the catalog grid is a CLASS (`.kol-catalog-grid`, kol-theme ≥0.138.0) reading
190
+ * `--kol-catalog-n`, the count measured above and set on PageShell the same
191
+ * number the filter row's first group reads */
192
+ <div ref={layout === 'list' ? undefined : gridRef} className={layout === 'list' ? undefined : 'kol-catalog-grid'} style={layout === 'list' ? (listLayout === 'stack' ? { display: 'flex', flexDirection: 'column', gap: 8 } : { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(min(100%, max(240px, calc((100% - 3 * 8px) / 4))), 1fr))', gap: 8 }) : undefined}>
168
193
  {rows.map((item, i) => {
169
194
  if (hidden.has(i)) return null
170
195
  const c = cards[i]