@kolkrabbi/kol-shell 0.28.0 → 0.29.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.
Files changed (2) hide show
  1. package/package.json +3 -3
  2. package/src/NavRail.jsx +33 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolkrabbi/kol-shell",
3
- "version": "0.28.0",
3
+ "version": "0.29.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",
@@ -20,10 +20,10 @@
20
20
  "react-dom": "^18.3.0 || ^19.0.0"
21
21
  },
22
22
  "devDependencies": {
23
+ "@kolkrabbi/kol-component": "^0.138.0",
23
24
  "@kolkrabbi/kol-icons": "^0.25.0",
24
- "@kolkrabbi/kol-component": "^0.137.0",
25
25
  "@kolkrabbi/kol-framework": "^0.35.0",
26
- "@kolkrabbi/kol-theme": "^0.108.0"
26
+ "@kolkrabbi/kol-theme": "^0.111.0"
27
27
  },
28
28
  "files": [
29
29
  "src",
package/src/NavRail.jsx CHANGED
@@ -119,7 +119,7 @@ function useGrabEdge(ref) {
119
119
  * toggles. `onSnap` reports the resting state once — the sub rows render only
120
120
  * while open, because closed they would still take their height and push the
121
121
  * rungs below them. */
122
- function useRailDrag(railRef, grabRef, onSnap) {
122
+ function useRailDrag(railRef, grabRef, onSnap, snapRef) {
123
123
  useEffect(() => {
124
124
  const strip = grabRef.current, rail = railRef.current, root = document.documentElement
125
125
  if (!strip || !rail) return undefined
@@ -129,6 +129,13 @@ function useRailDrag(railRef, grabRef, onSnap) {
129
129
  gsap.to(root, { [RAIL_W]: `${w}px`, ...GRAB.snap, overwrite: 'auto' })
130
130
  onSnap(w !== CLOSED)
131
131
  }
132
+ /* the ONLY way out of this effect (RailSectionPressOpensRail, kol-fxr
133
+ * 2026-08-30). `snapTo` closes over the animation and the CLOSED/open
134
+ * ladder, so a section press has to reach it rather than reimplement it —
135
+ * a consumer setting `--kol-shell-rail-width` from outside widens the rail
136
+ * but leaves `railOpen` false, and the L2 rows render behind it: a wide,
137
+ * EMPTY rail, worse than the dead press this fixes. */
138
+ if (snapRef) snapRef.current = () => snapTo(openWidth())
132
139
  const onDown = (e) => {
133
140
  strip.setPointerCapture(e.pointerId)
134
141
  gsap.killTweensOf(root)
@@ -159,7 +166,7 @@ function useRailDrag(railRef, grabRef, onSnap) {
159
166
  strip.removeEventListener('pointerup', onUp)
160
167
  strip.removeEventListener('pointercancel', onUp)
161
168
  }
162
- }, [railRef, grabRef, onSnap])
169
+ }, [railRef, grabRef, onSnap, snapRef])
163
170
  }
164
171
 
165
172
  /* one row: the rung exactly where the closed rail had it, then the label and
@@ -170,8 +177,26 @@ function IconAt({ name, size, component }) {
170
177
  return <Cmp name={name} size={size} />
171
178
  }
172
179
 
173
- function RailItem({ icon, path, label, sub, currentPath, onNavigate, iconComponent, railOpen }) {
180
+ function RailItem({ icon, path, label, sub, currentPath, onNavigate, iconComponent, railOpen, onOpenRail }) {
174
181
  const [open, setOpen] = useState(false)
182
+ /* A SECTION ROW IS NOT A DESTINATION (RailSectionPressOpensRail, kol-fxr
183
+ * 2026-08-30 — user: *"if I press effects from collapsed nav it should maybe
184
+ * open? currently pressing it does nothing"*).
185
+ *
186
+ * Closed, the row clips to 48px and the disclosure caret sits OUTSIDE that
187
+ * clip, so the only reachable control was the icon — which called
188
+ * `onNavigate` with a path no consumer dispatches, because a section has no
189
+ * action. A guaranteed dead press, in the rail's default state.
190
+ *
191
+ * Pressing it now opens the rail and expands that section. This is the
192
+ * behaviour `SideNav` had before the flat-rail reversal. It does not fight
193
+ * "nothing auto-expands" — that rule is about ARRIVING on a route; this is an
194
+ * explicit press. */
195
+ const isSection = sub?.length > 0
196
+ const press = () => {
197
+ if (isSection && !railOpen) { onOpenRail?.(); setOpen(true); return }
198
+ onNavigate?.(path)
199
+ }
175
200
  const active = path === '/' ? currentPath === '/' : currentPath.startsWith(path)
176
201
  return (
177
202
  <>
@@ -190,13 +215,13 @@ function RailItem({ icon, path, label, sub, currentPath, onNavigate, iconCompone
190
215
  * and too dim on an icon rail (user: "make the color .96 on every icon
191
216
  * in the rail") */
192
217
  style={{ color: 'var(--kol-oq-96)' }}
193
- onClick={() => onNavigate?.(path)}
218
+ onClick={press}
194
219
  title={label}
195
220
  aria-label={label}
196
221
  />
197
222
  <span
198
223
  className="kol-helper-12 uppercase text-oq-96 flex-1 min-w-0 truncate cursor-pointer"
199
- onClick={() => onNavigate?.(path)}
224
+ onClick={press}
200
225
  >
201
226
  {label}
202
227
  </span>
@@ -263,11 +288,12 @@ export default function NavRail({
263
288
  const railRef = useRef(null)
264
289
  const grabRef = useRef(null)
265
290
  const [railOpen, setRailOpen] = useState(false)
291
+ const snapOpenRef = useRef(null)
266
292
  useGrabEdge(grabRef)
267
- useRailDrag(railRef, grabRef, setRailOpen)
293
+ useRailDrag(railRef, grabRef, setRailOpen, snapOpenRef)
268
294
  if (hidden) return null
269
295
  const row = (item) => (
270
- <RailItem key={item.path} {...item} currentPath={currentPath} onNavigate={onNavigate} iconComponent={iconComponent} railOpen={railOpen} />
296
+ <RailItem key={item.path} {...item} currentPath={currentPath} onNavigate={onNavigate} iconComponent={iconComponent} railOpen={railOpen} onOpenRail={() => snapOpenRef.current?.()} />
271
297
  )
272
298
  return (
273
299
  <div