@kolkrabbi/kol-shell 0.37.0 → 0.38.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 +4 -4
- package/src/AppShell.jsx +14 -3
- package/src/NavRail.jsx +29 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-shell",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.38.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-
|
|
23
|
+
"@kolkrabbi/kol-theme": "^0.123.0",
|
|
24
24
|
"@kolkrabbi/kol-icons": "^0.25.0",
|
|
25
|
-
"@kolkrabbi/kol-
|
|
26
|
-
"@kolkrabbi/kol-
|
|
25
|
+
"@kolkrabbi/kol-component": "^0.156.0",
|
|
26
|
+
"@kolkrabbi/kol-framework": "^0.36.0"
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
|
29
29
|
"src",
|
package/src/AppShell.jsx
CHANGED
|
@@ -99,6 +99,13 @@ const CODE_FOR_KEY = {
|
|
|
99
99
|
'-': 'Minus', '=': 'Equal',
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
/* A STABLE DEFAULT (ShellDrawerOpenOnUnstableDep, kol-mirror 2026-09-01 —
|
|
103
|
+
* found by the user on his phone): `drawerOpenOn = []` in the signature was a
|
|
104
|
+
* fresh array every render, and it sat in an effect's deps, so the route effect
|
|
105
|
+
* re-ran on every render and closed the drawer straight after every tap. The
|
|
106
|
+
* trigger did nothing on every consumer taking the default. */
|
|
107
|
+
const NO_PATHS = []
|
|
108
|
+
|
|
102
109
|
export default function AppShell({
|
|
103
110
|
items,
|
|
104
111
|
bottomItems,
|
|
@@ -115,7 +122,7 @@ export default function AppShell({
|
|
|
115
122
|
settingsPath,
|
|
116
123
|
settingsKey,
|
|
117
124
|
drawerBelow = 768,
|
|
118
|
-
drawerOpenOn =
|
|
125
|
+
drawerOpenOn = NO_PATHS,
|
|
119
126
|
children,
|
|
120
127
|
}) {
|
|
121
128
|
const [navHidden, setNavHidden] = useState(false)
|
|
@@ -205,10 +212,14 @@ export default function AppShell({
|
|
|
205
212
|
/* …unless the destination is one where nav IS the page (`drawerOpenOn`):
|
|
206
213
|
* there the entry OPENS it. Runs on mount, on the fold and on navigation
|
|
207
214
|
* alike — `drawer` is a dep — so a phone arriving on home gets the rail. */
|
|
215
|
+
/* Keyed on the BOOLEAN, not the array: a consumer's inline `['/']` is a new
|
|
216
|
+
* identity every render too (the showcase set passes one), and the effect
|
|
217
|
+
* must fire on route entry only — never on a re-render, or it undoes the tap. */
|
|
218
|
+
const opensHere = drawerOpenOn.some((p) => (p === '/' ? currentPath === '/' : currentPath.startsWith(p)))
|
|
208
219
|
useEffect(() => {
|
|
209
|
-
if (drawer) setDrawerOpen(
|
|
220
|
+
if (drawer) setDrawerOpen(opensHere)
|
|
210
221
|
else setNavHidden(false)
|
|
211
|
-
}, [currentPath, drawer,
|
|
222
|
+
}, [currentPath, drawer, opensHere])
|
|
212
223
|
|
|
213
224
|
/* THE WASH ALSO GOES ON THE ROOT (2026-08-30). It is set on the content
|
|
214
225
|
* wrapper below, which every page inherits — but a PORTALLED surface does
|
package/src/NavRail.jsx
CHANGED
|
@@ -119,7 +119,9 @@ function useRailDrag(railRef, grabRef, onSnap, snapRef, enabled = true) {
|
|
|
119
119
|
* a consumer setting `--kol-shell-rail-width` from outside widens the rail
|
|
120
120
|
* but leaves `railOpen` false, and the L2 rows render behind it: a wide,
|
|
121
121
|
* EMPTY rail, worse than the dead press this fixes. */
|
|
122
|
-
|
|
122
|
+
/* `(false)` closes, anything else opens — the same seam the L2 rows use
|
|
123
|
+
* to open, now also the tap opener's toggle */
|
|
124
|
+
if (snapRef) snapRef.current = (open = true) => snapTo(open === false ? CLOSED : openWidth())
|
|
123
125
|
const onDown = (e) => {
|
|
124
126
|
strip.setPointerCapture(e.pointerId)
|
|
125
127
|
gsap.killTweensOf(root)
|
|
@@ -295,7 +297,32 @@ export default function NavRail({
|
|
|
295
297
|
* zeroed in drawer mode so the content gets the whole viewport back. */
|
|
296
298
|
style={{ width: drawer ? 'var(--kol-shell-drawer-width, 240px)' : `var(${RAIL_W})` }}
|
|
297
299
|
>
|
|
298
|
-
{!drawer &&
|
|
300
|
+
{!drawer && (
|
|
301
|
+
/* A BUTTON, with a glyph a thumb can find (ShellRailCollapsedWithTapOpen,
|
|
302
|
+
* kol-mirror 2026-09-01 — user: "i means collapsed variant not
|
|
303
|
+
* expanded"): `touch="shell"` is the only mode that keeps the 48px rail
|
|
304
|
+
* visible, and its only opener was this 8px strip, invisible until a
|
|
305
|
+
* pointer HOVERED near it — a thumb never does, so on a phone the rail
|
|
306
|
+
* could not be opened at all. The strip already toggled on a click (a
|
|
307
|
+
* press with no travel); it just had no affordance and no hit area on
|
|
308
|
+
* touch. Under `(pointer: coarse)` the theme shows `.kol-rail-grab-tap`
|
|
309
|
+
* — a 24px disc on the line — and widens the strip to it; on a fine
|
|
310
|
+
* pointer nothing changes, the ruled grab stays. The drag hook binds
|
|
311
|
+
* pointer events, so a button works exactly as the div did, and it now
|
|
312
|
+
* says what it is. Enter/Space toggle for the keyboard. */
|
|
313
|
+
<button
|
|
314
|
+
type="button"
|
|
315
|
+
ref={grabRef}
|
|
316
|
+
className="kol-rail-grab"
|
|
317
|
+
aria-label={railOpen ? 'Collapse navigation' : 'Expand navigation'}
|
|
318
|
+
aria-expanded={railOpen}
|
|
319
|
+
onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); snapOpenRef.current?.(!railOpen) } }}
|
|
320
|
+
>
|
|
321
|
+
<span className="kol-rail-grab-tap" aria-hidden="true">
|
|
322
|
+
<IconAt name={railOpen ? 'chevron-left' : 'chevron-right'} size={12} component={iconComponent} />
|
|
323
|
+
</span>
|
|
324
|
+
</button>
|
|
325
|
+
)}
|
|
299
326
|
{logomark && (
|
|
300
327
|
/* the mark, and the app name beside it when open — uppercase like the
|
|
301
328
|
* rows (user 2026-08-28: "uppercase CONSISTENCY"). The `w-8` centring box
|