@kolkrabbi/kol-framework 0.15.1 → 0.16.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/kol-framework.css +30 -0
- package/package.json +2 -2
- package/src/SideNav.jsx +56 -24
package/kol-framework.css
CHANGED
|
@@ -112,6 +112,36 @@ body {
|
|
|
112
112
|
* said 1800 — same element, two answers (lobby/WidthSystemContradictions). */
|
|
113
113
|
@media (min-width: 1920px) { :root { --kol-container-max: var(--kol-content-shell, 1800px); } }
|
|
114
114
|
|
|
115
|
+
/* SideNav's own box — IN RULES, not utilities (2026-08-09, defect found by
|
|
116
|
+
* the kol-website session during 0.15.1 verify): this whole file lives in
|
|
117
|
+
* @layer components, so a Tailwind utility the JSX stamps on the same element
|
|
118
|
+
* outranks every rule here — the collapsed overrides below silently lost to
|
|
119
|
+
* py-2 / pl-6 / Icon's own inline-flex. Same law as type: a component's box
|
|
120
|
+
* lives in its own rule, never a utility racing it. The JSX keeps only
|
|
121
|
+
* type/color utilities on these elements. */
|
|
122
|
+
.kol-sidenav-hop {
|
|
123
|
+
display: flex;
|
|
124
|
+
align-items: center;
|
|
125
|
+
gap: 0.75rem;
|
|
126
|
+
width: 100%;
|
|
127
|
+
position: relative;
|
|
128
|
+
padding: 0.5rem 2.5rem 0.5rem 1.5rem;
|
|
129
|
+
}
|
|
130
|
+
/* the caret rides a PLAIN span (Icon stamps inline-flex on its own element,
|
|
131
|
+
* which would outrank the collapsed display:none) */
|
|
132
|
+
.kol-sidenav-hop-caret {
|
|
133
|
+
position: absolute;
|
|
134
|
+
top: 0.75rem;
|
|
135
|
+
right: 0.75rem;
|
|
136
|
+
}
|
|
137
|
+
.kol-sidenav-list {
|
|
138
|
+
display: flex;
|
|
139
|
+
flex-direction: column;
|
|
140
|
+
gap: 0.125rem;
|
|
141
|
+
margin-bottom: 0.5rem;
|
|
142
|
+
}
|
|
143
|
+
.kol-sidenav-footer { padding-inline: 1.5rem 1rem; }
|
|
144
|
+
|
|
115
145
|
/* :root[data-sidenav="collapsed"] — the manual collapse, rebuilt DELIBERATELY
|
|
116
146
|
* 2026-08-09 (lobby: SideNavGrabResize) after the 2026-07-29 removal of the
|
|
117
147
|
* renderer-less stamp. SideNav's grab edge (useDragResize.js) owns the state
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "KOL app shell — sidenav, layout, theme toggle, footer, heroes + brand color layer. SideNav takes nav data as props so the tree stays app-local.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"app-shell"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@kolkrabbi/kol-component": "0.
|
|
30
|
+
"@kolkrabbi/kol-component": "0.28.0",
|
|
31
31
|
"@kolkrabbi/kol-icons": "0.10.0"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
package/src/SideNav.jsx
CHANGED
|
@@ -62,6 +62,16 @@ export default function SideNav({
|
|
|
62
62
|
const isPageActive = (to) => (isActive ? isActive(to) : pathname === to)
|
|
63
63
|
const isActiveCat = (cat) => pagesOf(cat).some((p) => isPageActive(p.to))
|
|
64
64
|
|
|
65
|
+
/* Every navigation closes the mobile drawer — the prop sat accepted-but-
|
|
66
|
+
* unread until the kol-website session flagged it (2026-08-09) — and, from
|
|
67
|
+
* the collapsed rail, expands the sidebar ("pressing any icon would expand
|
|
68
|
+
* the sidebar", same ruling as the chip removal). */
|
|
69
|
+
const handleNavigate = (e) => {
|
|
70
|
+
onNavigate?.(e)
|
|
71
|
+
onCloseDrawer?.()
|
|
72
|
+
if (collapsed) toggleCollapsed()
|
|
73
|
+
}
|
|
74
|
+
|
|
65
75
|
/* Which categories are disclosed. INDEPENDENT per category (elder ruling
|
|
66
76
|
* 2026-08-01) — arriving somewhere must not silently close wherever you
|
|
67
77
|
* were. Loads closed, in-memory only (elder ruling 2026-08-06). */
|
|
@@ -71,6 +81,7 @@ export default function SideNav({
|
|
|
71
81
|
next.has(id) ? next.delete(id) : next.add(id)
|
|
72
82
|
return next
|
|
73
83
|
})
|
|
84
|
+
const discloseCat = (id) => setOpenCats((prev) => new Set(prev).add(id))
|
|
74
85
|
|
|
75
86
|
/* One collapse contract, two gestures — the hook owns the stamp, the
|
|
76
87
|
* storage schema and the state; the chip Button and the grab edge both
|
|
@@ -84,19 +95,24 @@ export default function SideNav({
|
|
|
84
95
|
className={`kol-sidenav sticky top-0 self-start h-dvh flex flex-col z-20${background ? ' bg-surface-primary border-r border-fg-08' : ''}${collapsed ? ' is-collapsed' : ''}${drawerOpen ? ' is-drawer-open' : ''}`}
|
|
85
96
|
>
|
|
86
97
|
{/* The elder A/B (closed 2026-08-01): the DS Button IS the collapse
|
|
87
|
-
* control
|
|
88
|
-
*
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
* control — EXPANDED ONLY (user ruling 2026-08-09, verbatim: "REMOVE
|
|
99
|
+
* chevron from collapsed view … from collapsed view pressing any icon
|
|
100
|
+
* would expand the sidebar!"). The collapsed rail's expand affordance
|
|
101
|
+
* is the rows themselves. Offset is half the pinned sm square,
|
|
102
|
+
* centring it on the rail's edge. */}
|
|
103
|
+
{!collapsed && (
|
|
104
|
+
<Button
|
|
105
|
+
variant="primary"
|
|
106
|
+
size="sm"
|
|
107
|
+
radius="full"
|
|
108
|
+
iconOnly="chevron-left"
|
|
109
|
+
aria-label="Collapse sidebar"
|
|
110
|
+
aria-expanded
|
|
111
|
+
title="Collapse"
|
|
112
|
+
onClick={toggleCollapsed}
|
|
113
|
+
className="kol-sidenav-toggle absolute top-5 right-[-0.875rem] z-[2]"
|
|
114
|
+
/>
|
|
115
|
+
)}
|
|
100
116
|
|
|
101
117
|
<div className="kol-sidenav-scroll flex-1 flex flex-col justify-between overflow-y-auto pt-4 pb-4 [scrollbar-width:thin]">
|
|
102
118
|
<nav aria-label="Sections">
|
|
@@ -105,7 +121,10 @@ export default function SideNav({
|
|
|
105
121
|
const pages = pagesOf(cat)
|
|
106
122
|
const isOpen = openCats.has(cat.id)
|
|
107
123
|
const isLink = !pages.length && cat.to
|
|
108
|
-
|
|
124
|
+
/* Box utilities deliberately absent — the hop's layout lives in
|
|
125
|
+
* .kol-sidenav-hop (kol-framework.css): a utility here would
|
|
126
|
+
* outrank the collapsed-state overrides (2026-08-09 defect). */
|
|
127
|
+
const rowCls = 'kol-sidenav-hop kol-helper-12 text-emphasis no-underline'
|
|
109
128
|
const glyph = (
|
|
110
129
|
<span className="kol-sidenav-hop-icon inline-flex items-center justify-center w-5 h-5 shrink-0" aria-hidden="true">
|
|
111
130
|
<Icon name={cat.icon} size={16} />
|
|
@@ -119,7 +138,7 @@ export default function SideNav({
|
|
|
119
138
|
to={cat.to}
|
|
120
139
|
end
|
|
121
140
|
className={({ isActive: navActive }) => `${rowCls}${(isActive ? isActive(cat.to) : navActive) ? ' is-active' : ''}`}
|
|
122
|
-
onClick={
|
|
141
|
+
onClick={handleNavigate}
|
|
123
142
|
>
|
|
124
143
|
{glyph}
|
|
125
144
|
<span className="kol-sidenav-hop-label flex-1 min-w-0">{cat.label}</span>
|
|
@@ -129,15 +148,28 @@ export default function SideNav({
|
|
|
129
148
|
type="button"
|
|
130
149
|
className={`${rowCls} bg-transparent border-0 cursor-pointer text-left${isActiveCat(cat) ? ' is-active' : ''}`}
|
|
131
150
|
aria-expanded={isOpen}
|
|
132
|
-
|
|
151
|
+
/* Collapsed rail: the click meant "open this" — expand the
|
|
152
|
+
* rail AND disclose the category, or the tap is wasted on
|
|
153
|
+
* an expand that lands on a closed tree. */
|
|
154
|
+
onClick={() => {
|
|
155
|
+
if (collapsed) {
|
|
156
|
+
toggleCollapsed()
|
|
157
|
+
discloseCat(cat.id)
|
|
158
|
+
} else {
|
|
159
|
+
toggleCat(cat.id)
|
|
160
|
+
}
|
|
161
|
+
}}
|
|
133
162
|
>
|
|
134
163
|
{glyph}
|
|
135
164
|
<span className="kol-sidenav-hop-label flex-1 min-w-0">{cat.label}</span>
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
className={`kol-sidenav-hop-caret
|
|
140
|
-
|
|
165
|
+
{/* plain wrapper span — Icon stamps inline-flex on its own
|
|
166
|
+
* element, which would outrank the rail's display:none */}
|
|
167
|
+
<span
|
|
168
|
+
className={`kol-sidenav-hop-caret transition-transform duration-150${isOpen ? '' : ' -rotate-90'}`}
|
|
169
|
+
aria-hidden="true"
|
|
170
|
+
>
|
|
171
|
+
<Icon name="chevron-down" size={12} />
|
|
172
|
+
</span>
|
|
141
173
|
</button>
|
|
142
174
|
)
|
|
143
175
|
return (
|
|
@@ -151,7 +183,7 @@ export default function SideNav({
|
|
|
151
183
|
) : head}
|
|
152
184
|
|
|
153
185
|
{!isLink && isOpen && (
|
|
154
|
-
<ul className="kol-sidenav-list
|
|
186
|
+
<ul className="kol-sidenav-list">
|
|
155
187
|
{pages.map((page) => (
|
|
156
188
|
<li key={page.to}>
|
|
157
189
|
<NavLink
|
|
@@ -159,7 +191,7 @@ export default function SideNav({
|
|
|
159
191
|
end
|
|
160
192
|
style={pageStyle}
|
|
161
193
|
className={({ isActive: navActive }) => ((isActive ? isActive(page.to) : navActive) ? pageActiveCls : pageCls)}
|
|
162
|
-
onClick={
|
|
194
|
+
onClick={handleNavigate}
|
|
163
195
|
>
|
|
164
196
|
{page.label}
|
|
165
197
|
</NavLink>
|
|
@@ -180,7 +212,7 @@ export default function SideNav({
|
|
|
180
212
|
</div>
|
|
181
213
|
</div>
|
|
182
214
|
|
|
183
|
-
<div className="kol-sidenav-footer flex items-center
|
|
215
|
+
<div className="kol-sidenav-footer flex items-center h-14 border-t border-fg-08 min-w-0">
|
|
184
216
|
<a
|
|
185
217
|
href="https://kolkrabbi.io"
|
|
186
218
|
target="_blank"
|