@kolkrabbi/kol-shell 0.16.1 → 0.17.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 +2 -2
- package/src/AppShell.jsx +8 -1
- package/src/NavRail.jsx +59 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-shell",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.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",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@kolkrabbi/kol-component": "^0.126.0",
|
|
24
|
-
"@kolkrabbi/kol-icons": "^0.24.0",
|
|
25
24
|
"@kolkrabbi/kol-framework": "^0.35.0",
|
|
25
|
+
"@kolkrabbi/kol-icons": "^0.24.0",
|
|
26
26
|
"@kolkrabbi/kol-theme": "^0.88.0"
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
package/src/AppShell.jsx
CHANGED
|
@@ -21,6 +21,12 @@ import TouchDeviceOverlay, { useTouchPrimary } from './TouchDeviceOverlay.jsx'
|
|
|
21
21
|
* `kol-framework.css` is no longer required by the shell (it was, for one
|
|
22
22
|
* grid rule, 0.13–0.15).
|
|
23
23
|
*
|
|
24
|
+
* `railComponent` (RailTwoLevelSections, kol-fxr 2026-08-28) — the rail is
|
|
25
|
+
* rendered directly here, so proving a rail change in a consumer meant forking
|
|
26
|
+
* BOTH this file and `NavRail`. Pass a component with `NavRail`'s props to
|
|
27
|
+
* render your own; default is `NavRail`. A seam for experiments, not an
|
|
28
|
+
* invitation to keep a fork.
|
|
29
|
+
*
|
|
24
30
|
* @param {Array} props.items nav items `{ icon, path, label }`
|
|
25
31
|
* @param {Array} props.bottomItems items pinned below the theme toggle
|
|
26
32
|
* @param {Object} props.logomark `{ svgUrl, title }` — the rail's header mark, at the top in both states, navigates to '/'
|
|
@@ -62,6 +68,7 @@ export default function AppShell({
|
|
|
62
68
|
currentPath,
|
|
63
69
|
onNavigate,
|
|
64
70
|
iconComponent,
|
|
71
|
+
railComponent: Rail = NavRail,
|
|
65
72
|
railToggleKey,
|
|
66
73
|
touch = 'shell',
|
|
67
74
|
appName,
|
|
@@ -122,7 +129,7 @@ export default function AppShell({
|
|
|
122
129
|
>
|
|
123
130
|
{touch === 'overlay' && <TouchDeviceOverlay appName={appName} />}
|
|
124
131
|
{!navHidden && (
|
|
125
|
-
<
|
|
132
|
+
<Rail
|
|
126
133
|
items={items}
|
|
127
134
|
bottomItems={bottomItems}
|
|
128
135
|
logomark={logomark}
|
package/src/NavRail.jsx
CHANGED
|
@@ -34,7 +34,30 @@ import Logomark from './Logomark.jsx'
|
|
|
34
34
|
* has animation and gsap") — `.kol-rail-grab` in kol-theme's kol-animation.css,
|
|
35
35
|
* its pointer numbers in kol-component's `utilities/motion` (`GRAB`).
|
|
36
36
|
*
|
|
37
|
-
*
|
|
37
|
+
* TWO LEVELS (RailTwoLevelSections, kol-fxr 2026-08-28 — user: "the NAV has 20px
|
|
38
|
+
* icons in 32px containers, maybe level below has 12px icons in 20px container
|
|
39
|
+
* aligned to right? … you expand you see that they have main 56 items each, which
|
|
40
|
+
* you won't be aware of until you actually open labs, which should not happen
|
|
41
|
+
* automatically"). An item with `sub` is a SECTION: the same L1 row, plus a caret.
|
|
42
|
+
* Its rows are L2 — a 12px glyph in a 20px box, indented so its glyph column sits
|
|
43
|
+
* to the RIGHT of L1's (glyph x 14 → 30), resting a rung quieter at `oq-64` and
|
|
44
|
+
* going `oq-96` when it is the route. fxr's labs chrome is ~44 rows across four
|
|
45
|
+
* method sections; on one level they flatten into an icon column built for five
|
|
46
|
+
* destinations and the section names have nowhere to render at all.
|
|
47
|
+
*
|
|
48
|
+
* L2 is NOT a `Button`: the icon-button ladder is sm 28 / md 32 / lg 36 and this
|
|
49
|
+
* rung is 20 — there is nothing below sm, and adding one is a change to that
|
|
50
|
+
* ladder's law, which is the user's call and not this ticket's. The row is
|
|
51
|
+
* written directly and keys `aria-current`, so kol-theme's
|
|
52
|
+
* `.kol-shell-rail .kol-btn-nav` active rules still reach it. A sub row with no
|
|
53
|
+
* `icon` renders label-only, as it did before this level existed.
|
|
54
|
+
*
|
|
55
|
+
* NOTHING AUTO-EXPANDS. An L2 row is behind BOTH the rail's clipped width and its
|
|
56
|
+
* section's own disclosure, and `open` starts `false` with no prop to get it
|
|
57
|
+
* wrong — arriving on a route reveals nothing, by construction rather than by a
|
|
58
|
+
* flag a consumer has to remember.
|
|
59
|
+
*
|
|
60
|
+
* @param {Array} items `{ icon, path, label, sub?: [{ icon?, path, label }] }`
|
|
38
61
|
* @param {Array} bottomItems pinned below the rule (Settings)
|
|
39
62
|
* @param {Object} logomark `{ svgUrl, title }` — the mark, and the app name beside it when open
|
|
40
63
|
* @param {string} currentPath active match: '/' exact, else prefix → aria-current="page"
|
|
@@ -138,6 +161,12 @@ function useRailDrag(railRef, grabRef, onSnap) {
|
|
|
138
161
|
|
|
139
162
|
/* one row: the rung exactly where the closed rail had it, then the label and
|
|
140
163
|
* (with `sub`) the chevron — the row clips to the rail's width */
|
|
164
|
+
/* the L2 glyph goes through the same injection seam Button gives L1 */
|
|
165
|
+
function IconAt({ name, size, component }) {
|
|
166
|
+
const Cmp = component || Icon
|
|
167
|
+
return <Cmp name={name} size={size} />
|
|
168
|
+
}
|
|
169
|
+
|
|
141
170
|
function RailItem({ icon, path, label, sub, currentPath, onNavigate, iconComponent, railOpen }) {
|
|
142
171
|
const [open, setOpen] = useState(false)
|
|
143
172
|
const active = path === '/' ? currentPath === '/' : currentPath.startsWith(path)
|
|
@@ -184,16 +213,37 @@ function RailItem({ icon, path, label, sub, currentPath, onNavigate, iconCompone
|
|
|
184
213
|
/>
|
|
185
214
|
)}
|
|
186
215
|
</div>
|
|
187
|
-
{railOpen && open && sub.map((s) =>
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
216
|
+
{railOpen && open && sub.map((s) => {
|
|
217
|
+
const on = s.path === '/' ? currentPath === '/' : currentPath.startsWith(s.path)
|
|
218
|
+
return (
|
|
219
|
+
<div
|
|
220
|
+
key={s.path}
|
|
221
|
+
/* 18px of gutter puts the 20px box at x 26, so its 12px glyph starts
|
|
222
|
+
* at 30 — one step right of L1's 20-in-32 at 14 (measured in fxr) */
|
|
223
|
+
className="flex items-center gap-3 w-full overflow-hidden shrink-0 cursor-pointer"
|
|
224
|
+
style={{ paddingLeft: 18 }}
|
|
191
225
|
onClick={() => onNavigate?.(s.path)}
|
|
226
|
+
aria-current={on ? 'page' : undefined}
|
|
227
|
+
title={s.label}
|
|
192
228
|
>
|
|
193
|
-
{s.
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
229
|
+
{s.icon && (
|
|
230
|
+
<span
|
|
231
|
+
className="w-5 h-5 shrink-0 inline-flex items-center justify-center"
|
|
232
|
+
style={{ color: on ? 'var(--kol-oq-96)' : 'var(--kol-oq-64)' }}
|
|
233
|
+
aria-hidden="true"
|
|
234
|
+
>
|
|
235
|
+
<IconAt name={s.icon} size={12} component={iconComponent} />
|
|
236
|
+
</span>
|
|
237
|
+
)}
|
|
238
|
+
<span
|
|
239
|
+
className="kol-helper-12 uppercase flex-1 min-w-0 truncate"
|
|
240
|
+
style={{ color: on ? 'var(--kol-oq-96)' : 'var(--kol-oq-64)' }}
|
|
241
|
+
>
|
|
242
|
+
{s.label}
|
|
243
|
+
</span>
|
|
244
|
+
</div>
|
|
245
|
+
)
|
|
246
|
+
})}
|
|
197
247
|
</>
|
|
198
248
|
)
|
|
199
249
|
}
|