@kolkrabbi/kol-shell 0.36.0 → 0.37.1

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/AppShell.jsx +25 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolkrabbi/kol-shell",
3
- "version": "0.36.0",
3
+ "version": "0.37.1",
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,9 +20,9 @@
20
20
  "react-dom": "^18.3.0 || ^19.0.0"
21
21
  },
22
22
  "devDependencies": {
23
- "@kolkrabbi/kol-component": "^0.153.0",
24
- "@kolkrabbi/kol-icons": "^0.25.0",
25
23
  "@kolkrabbi/kol-framework": "^0.36.0",
24
+ "@kolkrabbi/kol-component": "^0.156.0",
25
+ "@kolkrabbi/kol-icons": "^0.25.0",
26
26
  "@kolkrabbi/kol-theme": "^0.122.0"
27
27
  },
28
28
  "files": [
package/src/AppShell.jsx CHANGED
@@ -56,6 +56,14 @@ import TouchDeviceOverlay, { useTouchPrimary } from './TouchDeviceOverlay.jsx'
56
56
  * `bare` renders the children with NO shell on a coarse-pointer device unless
57
57
  * localStorage `kol-desktop` is '1' (fxr's gate); `overlay` keeps the shell and
58
58
  * mounts TouchDeviceOverlay once (monitor's)
59
+ * @param {string[]} [props.drawerOpenOn=[]] paths whose ENTRY opens the drawer (ShellDrawerOpenOnRoute,
60
+ * kol-mirror 2026-09-01 — user: "the rail should load open on home, not
61
+ * everywhere"): a home that is a catalog IS navigation, and arriving there
62
+ * with the nav folded hides the one thing the page is for. Matched like the
63
+ * rail's active row — `'/'` exact, anything else by prefix. Every other path
64
+ * keeps the close-on-navigate rule; above `drawerBelow` there is no drawer
65
+ * and the list is inert. A list, not a boolean: the policy is per-route and
66
+ * the shell already owns the route.
59
67
  * @param {string} props.appName TouchDeviceOverlay's subject
60
68
  * @param {boolean} props.navKeys Option+1…9 navigates to the rail's nth ROW through `onNavigate` — with a
61
69
  * `logomark` that is the mark ('/') then the items, which is the order on
@@ -91,6 +99,13 @@ const CODE_FOR_KEY = {
91
99
  '-': 'Minus', '=': 'Equal',
92
100
  }
93
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
+
94
109
  export default function AppShell({
95
110
  items,
96
111
  bottomItems,
@@ -107,6 +122,7 @@ export default function AppShell({
107
122
  settingsPath,
108
123
  settingsKey,
109
124
  drawerBelow = 768,
125
+ drawerOpenOn = NO_PATHS,
110
126
  children,
111
127
  }) {
112
128
  const [navHidden, setNavHidden] = useState(false)
@@ -193,10 +209,17 @@ export default function AppShell({
193
209
  * `setNavHidden(false)` also made `navHidden` unusable as a consumer seam —
194
210
  * child effects run before parent effects, so a consumer hiding the rail on a
195
211
  * path change was overwritten in the same commit. */
212
+ /* …unless the destination is one where nav IS the page (`drawerOpenOn`):
213
+ * there the entry OPENS it. Runs on mount, on the fold and on navigation
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)))
196
219
  useEffect(() => {
197
- if (drawer) setDrawerOpen(false)
220
+ if (drawer) setDrawerOpen(opensHere)
198
221
  else setNavHidden(false)
199
- }, [currentPath, drawer])
222
+ }, [currentPath, drawer, opensHere])
200
223
 
201
224
  /* THE WASH ALSO GOES ON THE ROOT (2026-08-30). It is set on the content
202
225
  * wrapper below, which every page inherits — but a PORTALLED surface does