@kolkrabbi/kol-component 0.141.0 → 0.143.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 +1 -1
- package/src/index.js +3 -0
- package/src/molecules/ContentCard.jsx +14 -4
- package/src/utilities/useGrabEdge.js +61 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-component",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.143.0",
|
|
4
4
|
"description": "KOL design-system components — atoms through organisms, emitting canonical kol-* classes. Pairs with @kolkrabbi/kol-theme for styling.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/src/index.js
CHANGED
|
@@ -152,6 +152,9 @@ export { parseFrontmatter } from './utilities/frontmatter.js'
|
|
|
152
152
|
export { readCover } from './utilities/id3.js'
|
|
153
153
|
export { kindOf, extOf, isSystemFile, KINDS, KIND_LABEL, DEFAULT_KINDS, isSegment, groupSegments, groupVariants, posterFor, partition } from './utilities/mediaKinds.js'
|
|
154
154
|
export { nearestRatio, RATIOS } from './utilities/ratios.js'
|
|
155
|
+
/* the grab gesture — shared so kol-shell's NavRail and kol-framework's
|
|
156
|
+
* useDragResize wear ONE implementation (OneGrabGestureBothRails, 2026-08-30) */
|
|
157
|
+
export { default as useGrabEdge } from './utilities/useGrabEdge.js'
|
|
155
158
|
export { default as markdownToHtml, inlineToHtml } from './utilities/markdownToHtml.js'
|
|
156
159
|
export { default as RecordManager } from './organisms/RecordManager.jsx'
|
|
157
160
|
export { default as SpectrumGrid } from './organisms/SpectrumGrid.jsx'
|
|
@@ -58,9 +58,19 @@ const BOX = {
|
|
|
58
58
|
/* typeface's card is a FIXED 500px tall specimen board, not a ratio — the
|
|
59
59
|
* shipped item is `h-[500px]`, and a ratio re-crops the glyph at every
|
|
60
60
|
* column width, which is the one thing a specimen must not do. */
|
|
61
|
-
/* REST COLOURS ONLY (
|
|
62
|
-
*
|
|
63
|
-
*
|
|
61
|
+
/* REST COLOURS ONLY, TAKEN FROM THE ROW (TypefaceCardRestSkinFix, kol-website
|
|
62
|
+
* 2026-08-30). Filled surface, no outline — `ContentRow`'s showcase pair.
|
|
63
|
+
*
|
|
64
|
+
* 0.140.0 copied `BOX.showcase` from THIS map instead, because it is the
|
|
65
|
+
* entry sitting next to this one. That was wrong: `showcase`'s CARD is a
|
|
66
|
+
* `drawer` — outlined and unfilled — and the ask was to match the ROW, which
|
|
67
|
+
* is filled with no outline. Every /foundry grid card shipped as an outlined
|
|
68
|
+
* empty box, the opposite of the rows beside it.
|
|
69
|
+
*
|
|
70
|
+
* "Make the card look like the row" means READ THE ROW'S BOX. The two maps
|
|
71
|
+
* share variant names and not treatments.
|
|
72
|
+
*
|
|
73
|
+
* `layout`, `pad`, `height`, the RATIO, REVEAL_BG, MEDIA and every
|
|
64
74
|
* hover treatment are untouched and deliberately different.
|
|
65
75
|
*
|
|
66
76
|
* NOT derived with a spread. The row's version of this ask was resolved that
|
|
@@ -68,7 +78,7 @@ const BOX = {
|
|
|
68
78
|
* it is keyed by variant NAME — a second ticket to undo. `RATIO`, `REVEAL_BG`
|
|
69
79
|
* and `MEDIA` here are separate name-keyed maps too; a spread cannot reach
|
|
70
80
|
* them either. Two values, set by hand. */
|
|
71
|
-
showcaseCanvas: { layout: 'canvas', border: 'var(--kol-
|
|
81
|
+
showcaseCanvas: { layout: 'canvas', border: 'transparent', bg: 'var(--kol-surface-secondary)', pad: 'var(--kol-pad-card-lg)', height: 500 },
|
|
72
82
|
}
|
|
73
83
|
|
|
74
84
|
/* HOVER is a bg STEP on the opaque tier, per 05-control-chrome.md's state model
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
import { GRAB } from './motion.js'
|
|
3
|
+
import gsap from 'gsap'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* useGrabEdge — the proximity-wake grab pill, for ANY resizable edge.
|
|
7
|
+
*
|
|
8
|
+
* Lifted out of kol-shell's `NavRail` 2026-08-30 (OneGrabGestureBothRails,
|
|
9
|
+
* kol-fxr — user: *"why dont we use the grab animation and other sidenav
|
|
10
|
+
* settings to be consistent?"*). fxr's `/labs` renders two rails on one screen,
|
|
11
|
+
* the shell's on the left and a params rail on the right, and only the left one
|
|
12
|
+
* came alive as the cursor neared it. Two implementations of one gesture in two
|
|
13
|
+
* packages, and neither was consumer code, so no consumer could converge them.
|
|
14
|
+
*
|
|
15
|
+
* It lives in kol-component because that is the only package BOTH rails can
|
|
16
|
+
* reach: kol-shell dropped its kol-framework peer in 0.16.0, so shell cannot
|
|
17
|
+
* import framework's hook and framework cannot import shell's. `gsap` and the
|
|
18
|
+
* `GRAB` tuning constants were already here.
|
|
19
|
+
*
|
|
20
|
+
* WHAT IT DOES. Watches the pointer; within `GRAB.near` of the handle's centre
|
|
21
|
+
* line it adds `is-near` (hysteresis out at `GRAB.sleep`, so the pill does not
|
|
22
|
+
* flicker on the boundary) and travels the pill along the edge to meet the
|
|
23
|
+
* cursor — bipolar from the middle across `GRAB.range` of the height, so it
|
|
24
|
+
* never rides up under a logomark. `GRAB.stick` is the dwell: a move smaller
|
|
25
|
+
* than that leaves the pill where it is, which is what stops it twitching.
|
|
26
|
+
*
|
|
27
|
+
* The element needs the `.kol-rail-grab` class for the drawing (kol-animation.css);
|
|
28
|
+
* this hook only supplies `is-near` and `--kol-rail-grab-y`.
|
|
29
|
+
*
|
|
30
|
+
* @param {React.RefObject<HTMLElement>} ref the grab handle
|
|
31
|
+
*/
|
|
32
|
+
export default function useGrabEdge(ref) {
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
let raf = 0
|
|
35
|
+
const onMove = ({ clientX, clientY }) => {
|
|
36
|
+
if (raf) return
|
|
37
|
+
raf = requestAnimationFrame(() => {
|
|
38
|
+
raf = 0
|
|
39
|
+
const h = ref.current
|
|
40
|
+
if (!h) return
|
|
41
|
+
const r = h.getBoundingClientRect()
|
|
42
|
+
const dist = Math.abs(clientX - (r.left + r.width / 2))
|
|
43
|
+
const near = dist <= GRAB.near || (h.classList.contains('is-near') && dist <= GRAB.sleep)
|
|
44
|
+
h.classList.toggle('is-near', near)
|
|
45
|
+
if (!near) return
|
|
46
|
+
/* the travel band: bipolar from the middle, GRAB.range of the height */
|
|
47
|
+
const edge = (r.height * (1 - GRAB.range)) / 2
|
|
48
|
+
const along = Math.min(Math.max(clientY - r.top, edge), r.height - edge)
|
|
49
|
+
if (h.dataset.grabSeeded && Math.abs(along - Number(h.dataset.grabTarget)) < GRAB.stick) return
|
|
50
|
+
h.dataset.grabTarget = String(along)
|
|
51
|
+
const vars = { '--kol-rail-grab-y': `${along}px` }
|
|
52
|
+
/* the CSS fallback is 50%, a percentage — nothing to tween from, so the
|
|
53
|
+
* first sighting sets and every move after tweens */
|
|
54
|
+
if (h.dataset.grabSeeded) gsap.to(h, { ...vars, ...GRAB.travel, overwrite: 'auto' })
|
|
55
|
+
else { gsap.set(h, vars); h.dataset.grabSeeded = '1' }
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
window.addEventListener('pointermove', onMove)
|
|
59
|
+
return () => { window.removeEventListener('pointermove', onMove); cancelAnimationFrame(raf) }
|
|
60
|
+
}, [ref])
|
|
61
|
+
}
|