@kolkrabbi/kol-shell 0.63.0 → 0.64.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/AppStudio.jsx +9 -5
- package/src/NavRail.jsx +21 -1
- package/src/index.js +2 -0
- package/src/railSlot.jsx +28 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-shell",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.64.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The application shell",
|
|
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.246.0",
|
|
24
|
-
"@kolkrabbi/kol-icons": "^0.33.1",
|
|
25
23
|
"@kolkrabbi/kol-framework": "^0.49.0",
|
|
26
|
-
"@kolkrabbi/kol-theme": "^0.
|
|
24
|
+
"@kolkrabbi/kol-theme": "^0.174.0",
|
|
25
|
+
"@kolkrabbi/kol-icons": "^0.38.0",
|
|
26
|
+
"@kolkrabbi/kol-component": "^0.261.0"
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
|
29
29
|
"src",
|
package/src/AppStudio.jsx
CHANGED
|
@@ -28,8 +28,12 @@ import PageShell from './PageShell.jsx'
|
|
|
28
28
|
*
|
|
29
29
|
* @param {Object} app AppHub's `{ name, subtitle, logomark, about, links }`
|
|
30
30
|
* @param {Object} home HubHome's props — the landing Catalog (required: a Studio opens on Home)
|
|
31
|
-
* @param {Object} [library] CatalogPage's props
|
|
32
|
-
*
|
|
31
|
+
* @param {Object} [library] CatalogPage's props — or `children` (a router, for pages under the
|
|
32
|
+
* slot: `/library/:id`), which renders in place of the CatalogPage —
|
|
33
|
+
* plus `{ path, label, icon }`
|
|
34
|
+
* @param {Object} [create] `{ header (PageHeader props), children, path, label, icon }`;
|
|
35
|
+
* `shell: false` renders `children` bare — for a Create that owns its
|
|
36
|
+
* PageShell (a fixed canvas beside a scrolling list)
|
|
33
37
|
* @param {Object} [use] `{ children, path, label, icon }` — the tool
|
|
34
38
|
* @param {Array} [pages] `[{ path, icon, label, children }]` — opt-in pages, after Use
|
|
35
39
|
* @param {Object} [settings] HubSettings' props
|
|
@@ -63,10 +67,10 @@ export default function AppStudio({
|
|
|
63
67
|
|
|
64
68
|
let page = null
|
|
65
69
|
if (lib && at(lib.path)) {
|
|
66
|
-
const { path: _p, label: _l, icon: _i, ...props } = lib
|
|
67
|
-
page = <CatalogPage {...props} />
|
|
70
|
+
const { path: _p, label: _l, icon: _i, children, ...props } = lib
|
|
71
|
+
page = children ?? <CatalogPage {...props} />
|
|
68
72
|
} else if (make && at(make.path)) {
|
|
69
|
-
page = (
|
|
73
|
+
page = make.shell === false ? make.children : (
|
|
70
74
|
<PageShell>
|
|
71
75
|
{make.header && <PageHeader size="sm" {...make.header} />}
|
|
72
76
|
{make.children}
|
package/src/NavRail.jsx
CHANGED
|
@@ -9,6 +9,7 @@ import { GRAB } from '@kolkrabbi/kol-component/utilities/motion'
|
|
|
9
9
|
import { useGrabEdge } from '@kolkrabbi/kol-component'
|
|
10
10
|
import { Icon } from '@kolkrabbi/kol-icons'
|
|
11
11
|
import Logomark from './Logomark.jsx'
|
|
12
|
+
import { useRailSlot } from './railSlot.jsx'
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* NavRail — the flat rail. ONE fixed column, every child a direct child of it
|
|
@@ -70,6 +71,11 @@ import Logomark from './Logomark.jsx'
|
|
|
70
71
|
* @param {boolean} drawer off-canvas mode: no grab, no drag, no token writes, rows always
|
|
71
72
|
* labelled, and the rail sizes itself from `--kol-shell-drawer-width` (default 240px).
|
|
72
73
|
* AppShell sets this from `touch="drawer"` — see ShellRailNoDrawerOnMobile, 2026-08-31.
|
|
74
|
+
* Under a `RailSlotProvider` the opened width also carries a CONSUMER SLOT below the rows
|
|
75
|
+
* (NavRailConsumerSlot, kol-monitor 2026-10-15) — content that is not a row list (monitor's module
|
|
76
|
+
* catalog: rows that insert, not paths). Always mounted so portalled content keeps its state across
|
|
77
|
+
* open/close; zero tall and clipped while closed. No provider → no slot, the render unchanged.
|
|
78
|
+
*
|
|
73
79
|
* @param {boolean} [fade=true] the list fades out at its foot — the workshop rail's fade
|
|
74
80
|
* (2026-10-01), here too on the user's word (2026-10-02). The rows sit in their own scroll
|
|
75
81
|
* region between the mark and the pinned bottom rows, so a list longer than the window scrolls
|
|
@@ -299,6 +305,13 @@ export default function NavRail({
|
|
|
299
305
|
* ten rows each, which is where an accordion stops reading. */
|
|
300
306
|
const [entered, setEntered] = useState(null)
|
|
301
307
|
const snapOpenRef = useRef(null)
|
|
308
|
+
const slotRef = useRef(null)
|
|
309
|
+
const ctx = useRailSlot()
|
|
310
|
+
const setSlot = ctx?.setSlot
|
|
311
|
+
const setCtxOpen = ctx?.setRailOpen
|
|
312
|
+
const slotOpen = drawer || railOpen
|
|
313
|
+
useEffect(() => { setSlot?.(slotRef.current); return () => setSlot?.(null) }, [setSlot, hidden])
|
|
314
|
+
useEffect(() => { setCtxOpen?.(slotOpen) }, [setCtxOpen, slotOpen])
|
|
302
315
|
/* the grab strip is not rendered in drawer mode, so the hook's ref stays null
|
|
303
316
|
* and it no-ops on its own — no second argument needed */
|
|
304
317
|
useGrabEdge(grabRef)
|
|
@@ -363,7 +376,7 @@ export default function NavRail({
|
|
|
363
376
|
{/* THE LIST IS ITS OWN REGION (2026-10-02): it takes the room between the mark and the pinned
|
|
364
377
|
* bottom rows — what the bare spacer used to hold — scrolls when the rows outrun the window,
|
|
365
378
|
* and fades at its foot unless `fade={false}`. Same column, same gap, as the rail's own. */}
|
|
366
|
-
<div className={`kol-shell-rail-list flex min-h-0 w-full flex-1 flex-col items-start gap-2 overflow-y-auto overflow-x-hidden ${fade ? 'kol-shell-rail-list--fade' : ''}`.trim()}>
|
|
379
|
+
<div style={ctx && slotOpen ? { flex: '0 1 auto' } : undefined} className={`kol-shell-rail-list flex min-h-0 w-full flex-1 flex-col items-start gap-2 overflow-y-auto overflow-x-hidden ${fade ? 'kol-shell-rail-list--fade' : ''}`.trim()}>
|
|
367
380
|
{section ? (
|
|
368
381
|
<>
|
|
369
382
|
<RailItem icon="arrow-left" path={section.path} label={section.label} currentPath="" onNavigate={() => setEntered(null)} iconComponent={iconComponent} railOpen={drawer || railOpen} />
|
|
@@ -371,6 +384,13 @@ export default function NavRail({
|
|
|
371
384
|
</>
|
|
372
385
|
) : items.map(row)}
|
|
373
386
|
</div>
|
|
387
|
+
{ctx && (
|
|
388
|
+
<div
|
|
389
|
+
ref={slotRef}
|
|
390
|
+
className="kol-shell-rail-slot w-full min-h-0 overflow-x-hidden"
|
|
391
|
+
style={{ flex: slotOpen ? '1 1 auto' : '0 0 0px', overflowY: slotOpen ? 'auto' : 'hidden' }}
|
|
392
|
+
/>
|
|
393
|
+
)}
|
|
374
394
|
{/* the rule runs the full rail width, out past the px-2 */}
|
|
375
395
|
{bottomItems.length > 0 && <div className="self-stretch -mx-2 border-t border-fg-08" />}
|
|
376
396
|
{bottomItems.map(row)}
|
package/src/index.js
CHANGED
|
@@ -39,3 +39,5 @@ export { default as HubHome } from './HubHome.jsx'
|
|
|
39
39
|
export { default as HubSettings } from './HubSettings.jsx'
|
|
40
40
|
// the Studio — the Hub + Home · Library · Create · Use · pages · Settings, the workstation (apps review §6c, 2026-09-29)
|
|
41
41
|
export { default as AppStudio } from './AppStudio.jsx'
|
|
42
|
+
// a consumer slot in the opened rail — the page portals into it (NavRailConsumerSlot, kol-monitor 2026-10-15)
|
|
43
|
+
export { RailSlotProvider, useRailSlot } from './railSlot.jsx'
|
package/src/railSlot.jsx
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createContext, useContext, useMemo, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* RailSlotProvider / useRailSlot — a consumer slot in NavRail's opened width (NavRailConsumerSlot,
|
|
5
|
+
* kol-monitor 2026-10-15). The rail renders in AppShell's own tree, outside the page's providers,
|
|
6
|
+
* so it cannot read page state and the page cannot render into it. The rail publishes its slot's
|
|
7
|
+
* DOM node here instead, and the page portals into it with its own state:
|
|
8
|
+
*
|
|
9
|
+
* <RailSlotProvider><AppStudio … /></RailSlotProvider>
|
|
10
|
+
* const rail = useRailSlot(); rail?.slot && createPortal(<Panel />, rail.slot)
|
|
11
|
+
*
|
|
12
|
+
* The provider goes ABOVE the shell so the rail and the page both see it. No provider → no slot,
|
|
13
|
+
* and the rail renders as it did. `railOpen` mirrors the rail's open state for the page.
|
|
14
|
+
*
|
|
15
|
+
* Monitor's shape (`src/hooks/useRailSlot.jsx`), shipped so its NavRail fork can retire.
|
|
16
|
+
*/
|
|
17
|
+
const RailSlotContext = createContext(null)
|
|
18
|
+
|
|
19
|
+
export function useRailSlot() {
|
|
20
|
+
return useContext(RailSlotContext)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function RailSlotProvider({ children }) {
|
|
24
|
+
const [slot, setSlot] = useState(null)
|
|
25
|
+
const [railOpen, setRailOpen] = useState(false)
|
|
26
|
+
const value = useMemo(() => ({ slot, setSlot, railOpen, setRailOpen }), [slot, railOpen])
|
|
27
|
+
return <RailSlotContext.Provider value={value}>{children}</RailSlotContext.Provider>
|
|
28
|
+
}
|