@kolkrabbi/kol-component 0.326.0 → 0.327.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolkrabbi/kol-component",
3
- "version": "0.326.0",
3
+ "version": "0.327.0",
4
4
  "description": "The core component library",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -122,11 +122,21 @@ const openWidth = () => {
122
122
  * are now — inside `GRAB.range`, the middle band of the edge, so it never rides
123
123
  * up beside the logomark. One window listener, rAF-throttled. */
124
124
 
125
- /* THE DRAG — hold the pill and the width follows the pointer between closed and
126
- * open; release snaps to the nearer state, a click (no travel past GRAB.slop)
127
- * toggles. `onSnap` reports the resting state once — the sub rows render only
128
- * while open, because closed they would still take their height and push the
129
- * rungs below them. */
125
+ /* THE DRAG HOLDS ITS WIDTH (RailDragHoldsWidth, kol-fxr 2026-10-31 — user: *"you should be able to drag it however
126
+ * you want, it will just get reset on rail click"*). Hold the pill and the width follows the pointer between CLOSED
127
+ * and MAX; release leaves it exactly there, no snap. A click (no travel past GRAB.slop) still snaps collapsed ⇄
128
+ * expanded — any width past CLOSED closes, CLOSED opens to the open width — so a click resets a custom width.
129
+ *
130
+ * THE LABEL THRESHOLD (LABELS): below it the rail is icons only — labels, chevrons and the mark's title hide (the
131
+ * `@max-[…]:hidden` container query on the rows, measured on the rail's content box = LABELS − its px-2 gutter), never
132
+ * a label clipped in a narrow strip. `onSnap` reports from the same threshold: crossings during a drag report live,
133
+ * a snap reports its target once at the start of the tween (as before) — the sub rows render only while it is true,
134
+ * because closed they would still take their height and push the rungs below them.
135
+ *
136
+ * ONE AXIS: the gesture reads `pos` and `size` only. A side rail reads x and width; a top rail (variant="top", not
137
+ * built) swaps them for y and height — nothing else in here assumes a side. */
138
+ const RAIL_MAX = 560
139
+ const RAIL_LABELS = 160
130
140
  function useRailDrag(railRef, grabRef, onSnap, snapRef, enabled = true) {
131
141
  useEffect(() => {
132
142
  const strip = grabRef.current, rail = railRef.current, root = document.documentElement
@@ -137,11 +147,15 @@ function useRailDrag(railRef, grabRef, onSnap, snapRef, enabled = true) {
137
147
  * exactly the inline token a consumer could not reach without `!important`. */
138
148
  if (!enabled) return undefined
139
149
  if (!strip || !rail) return undefined
150
+ const pos = (e) => e.clientX
151
+ const size = () => rail.offsetWidth
140
152
  gsap.set(root, { [RAIL_W]: `${CLOSED}px` })
141
153
  let drag = null
154
+ let labelled = false
155
+ const report = (w) => { const on = w >= RAIL_LABELS; if (on !== labelled) { labelled = on; onSnap(on) } }
142
156
  const snapTo = (w) => {
143
157
  gsap.to(root, { [RAIL_W]: `${w}px`, ...GRAB.snap, overwrite: 'auto' })
144
- onSnap(w !== CLOSED)
158
+ report(w)
145
159
  }
146
160
  /* the ONLY way out of this effect (RailSectionPressOpensRail, kol-fxr
147
161
  * 2026-08-30). `snapTo` closes over the animation and the CLOSED/open
@@ -155,20 +169,21 @@ function useRailDrag(railRef, grabRef, onSnap, snapRef, enabled = true) {
155
169
  const onDown = (e) => {
156
170
  strip.setPointerCapture(e.pointerId)
157
171
  gsap.killTweensOf(root)
158
- drag = { x: e.clientX, w: rail.offsetWidth, open: openWidth(), moved: false }
172
+ drag = { p: pos(e), w: size(), moved: false }
159
173
  strip.classList.add('is-dragging')
160
174
  }
161
175
  const onMove = (e) => {
162
176
  if (!drag) return
163
- const dx = e.clientX - drag.x
164
- if (Math.abs(dx) > GRAB.slop) drag.moved = true
165
- root.style.setProperty(RAIL_W, `${Math.min(Math.max(drag.w + dx, CLOSED), drag.open)}px`)
177
+ const d = pos(e) - drag.p
178
+ if (Math.abs(d) > GRAB.slop) drag.moved = true
179
+ if (!drag.moved) return
180
+ const w = Math.min(Math.max(drag.w + d, CLOSED), RAIL_MAX)
181
+ root.style.setProperty(RAIL_W, `${w}px`)
182
+ report(w)
166
183
  }
167
184
  const onUp = () => {
168
185
  if (!drag) return
169
- const w = rail.offsetWidth
170
- const open = drag.open
171
- snapTo(drag.moved ? (w > (CLOSED + open) / 2 ? open : CLOSED) : (drag.w > CLOSED ? CLOSED : open))
186
+ if (!drag.moved) snapTo(drag.w > CLOSED ? CLOSED : openWidth())
172
187
  drag = null
173
188
  strip.classList.remove('is-dragging')
174
189
  }
@@ -250,13 +265,13 @@ function RailItem({ icon, path, to, label, sub, currentPath, onNavigate, iconCom
250
265
  />
251
266
  </Tooltip>
252
267
  <span
253
- className={`${RAIL_ROW.label} text-oq-96 flex-1 min-w-0 truncate cursor-pointer`}
268
+ className={`${RAIL_ROW.label} text-oq-96 flex-1 min-w-0 truncate cursor-pointer @max-[144px]/rail:hidden`}
254
269
  onClick={press}
255
270
  >
256
271
  {label}
257
272
  </span>
258
273
  {sub?.length > 0 && (
259
- <Tooltip label={label} placement="right" triggerClassName="inline-flex shrink-0">
274
+ <Tooltip label={label} placement="right" triggerClassName="inline-flex shrink-0 @max-[144px]/rail:hidden">
260
275
  <Button
261
276
  iconOnly={onEnter ? 'chevron-right' : open ? 'chevron-down' : 'chevron-right'}
262
277
  iconSize={16}
@@ -371,7 +386,7 @@ function AppRail({
371
386
  * trigger travelling to mid-screen, never the navigation's side. The
372
387
  * trigger is now pinned top-right in both states, so a left panel has
373
388
  * nothing to collide with and the drawer opens where the rail lives. */
374
- className="kol-shell-rail bg-surface-primary fixed inset-y-0 left-0 flex flex-col items-start pt-4 pb-4 px-2 gap-2 border-r border-fg-08"
389
+ className="@container/rail kol-shell-rail bg-surface-primary fixed inset-y-0 left-0 flex flex-col items-start pt-4 pb-4 px-2 gap-2 border-r border-fg-08"
375
390
  /* A drawer takes its own width, NOT the live rail token — that token is
376
391
  * zeroed in drawer mode so the content gets the whole viewport back. */
377
392
  style={{ width: drawer ? 'var(--kol-shell-drawer-width, 240px)' : `var(${RAIL_W})` }}
@@ -413,7 +428,7 @@ function AppRail({
413
428
  className="text-oq-96 cursor-pointer flex items-center gap-3 w-full overflow-hidden shrink-0 pt-1 mb-4"
414
429
  >
415
430
  <span className="w-8 flex justify-center shrink-0"><VectorLoader src={logomark.svgUrl} size={20} /></span>
416
- <span className="kol-helper-12 uppercase flex-1 min-w-0 truncate">{logomark.title}</span>
431
+ <span className="kol-helper-12 uppercase flex-1 min-w-0 truncate @max-[144px]/rail:hidden">{logomark.title}</span>
417
432
  </div>
418
433
  </Tooltip>
419
434
  )}