@brandocms/jupiter 5.0.0-beta.17 → 5.0.0-beta.19
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/README.md
CHANGED
|
@@ -949,6 +949,10 @@ when the original header is visible.
|
|
|
949
949
|
- Pin header when scroll is forced (`application.scrollTo`, clicking anchors etc)
|
|
950
950
|
- `unPinOnResize` - default `false`
|
|
951
951
|
- Unpin header when window is resized
|
|
952
|
+
- `headerHeightTracksPin` - default `true`
|
|
953
|
+
- Set per section (under `default` / `sections`). Whether `--header-height` drops
|
|
954
|
+
to `0px` while the header is unpinned. Set `false` for a header that never
|
|
955
|
+
retracts — see [CSS variables](#css-variables) under FixedHeader.
|
|
952
956
|
|
|
953
957
|
- Events
|
|
954
958
|
- `onMainVisible`
|
|
@@ -978,7 +982,8 @@ its space is still reserved.
|
|
|
978
982
|
|
|
979
983
|
### Options
|
|
980
984
|
|
|
981
|
-
Same options as FixedHeader - see FixedHeader documentation below
|
|
985
|
+
Same options as FixedHeader - see FixedHeader documentation below, including
|
|
986
|
+
`headerHeightTracksPin` and the [CSS variables](#css-variables) section.
|
|
982
987
|
|
|
983
988
|
|
|
984
989
|
## FixedHeader
|
package/package.json
CHANGED
|
@@ -80,6 +80,7 @@ const DEFAULT_OPTIONS = {
|
|
|
80
80
|
|
|
81
81
|
default: {
|
|
82
82
|
onClone: (h) => h.el.cloneNode(true),
|
|
83
|
+
headerHeightTracksPin: true,
|
|
83
84
|
canvas: window,
|
|
84
85
|
beforeEnter: (h) => {
|
|
85
86
|
set(h.el, { opacity: 0 })
|
|
@@ -450,11 +451,25 @@ export default class DoubleHeader {
|
|
|
450
451
|
|
|
451
452
|
/**
|
|
452
453
|
* Update the --header-height CSS variable on :root.
|
|
453
|
-
*
|
|
454
|
-
*
|
|
454
|
+
*
|
|
455
|
+
* Measured from `el`, the main header — `auxEl` is the clone. By default this
|
|
456
|
+
* is how much header is *visible*, the measured height when pinned and 0 when
|
|
457
|
+
* unpinned, so anything positioned under the bar follows it out of the way as
|
|
458
|
+
* the clone retracts.
|
|
459
|
+
*
|
|
460
|
+
* That is wrong for a header configured never to retract, whether through
|
|
461
|
+
* `preventUnpin` or by no-opping `onPin` / `onUnpin`. The bar stays put, but
|
|
462
|
+
* `_pinned` still flips on every change of scroll direction, so the variable
|
|
463
|
+
* drops to 0 and back while nothing moves. Any layout sized from it then grows
|
|
464
|
+
* and shrinks the document under the reader. Scroll anchoring absorbs that
|
|
465
|
+
* mid-page, but not at the very bottom, where the scroll offset is clamped to
|
|
466
|
+
* the document and the page visibly jumps instead.
|
|
467
|
+
*
|
|
468
|
+
* `headerHeightTracksPin: false` publishes the measured height throughout.
|
|
455
469
|
*/
|
|
456
470
|
_updateHeaderHeight() {
|
|
457
|
-
const
|
|
471
|
+
const tracksPin = this.opts.headerHeightTracksPin !== false
|
|
472
|
+
const height = tracksPin && !this._pinned ? '0px' : `${this.el.clientHeight}px`
|
|
458
473
|
document.documentElement.style.setProperty('--header-height', height)
|
|
459
474
|
}
|
|
460
475
|
|
|
@@ -57,6 +57,12 @@ const DEFAULT_OPTIONS = {
|
|
|
57
57
|
snapDuration: 0.5, // Duration of snap animation in seconds (0.3-1.0, lower = faster/snappier)
|
|
58
58
|
snapBounce: 0.15, // Spring bounce amount (0-1, 0 = no bounce, higher = more bouncy)
|
|
59
59
|
|
|
60
|
+
// Edge spring (loop: false) — a throw past either end keeps its speed, runs
|
|
61
|
+
// past the edge and springs back, instead of gliding in slowly
|
|
62
|
+
edgeStiffness: 260, // Pull back towards the edge (higher = shorter overshoot)
|
|
63
|
+
edgeDamping: 29, // Damping of the pull (29 at 260 is just under critical: one overshoot, no wobble)
|
|
64
|
+
edgeElasticity: 0.55, // Dragging past an end follows the finger with this much give (0 = hard stop at the edge)
|
|
65
|
+
|
|
60
66
|
speed: {
|
|
61
67
|
sm: 0.1, // Speed for mobile (multiplier)
|
|
62
68
|
lg: 0.35, // Speed for desktop (multiplier)
|
|
@@ -910,7 +916,9 @@ function horizontalLoop(app, items, config) {
|
|
|
910
916
|
indexSetByNav = false
|
|
911
917
|
startX = e.clientX
|
|
912
918
|
startY = e.clientY
|
|
913
|
-
|
|
919
|
+
// Grabbed past an end (mid-bounce): continue from the drag distance that
|
|
920
|
+
// shows the row there, or the rubber band would jump
|
|
921
|
+
startPosition = shouldLoop ? position.get() : unstretch(position.get())
|
|
914
922
|
velocityTracker = [{ x: e.clientX, time: e.timeStamp }]
|
|
915
923
|
hasDragged = false // Reset - will be set true if movement exceeds threshold
|
|
916
924
|
axisDecided = false // Reset - will be decided on first significant movement
|
|
@@ -1030,9 +1038,8 @@ function horizontalLoop(app, items, config) {
|
|
|
1030
1038
|
// For looping, position grows freely - items wrap as groups
|
|
1031
1039
|
position.set(newPosition)
|
|
1032
1040
|
} else {
|
|
1033
|
-
// For non-looping,
|
|
1034
|
-
|
|
1035
|
-
position.set(clampedPos)
|
|
1041
|
+
// For non-looping, past either end the row gives with resistance
|
|
1042
|
+
position.set(stretch(newPosition))
|
|
1036
1043
|
}
|
|
1037
1044
|
}
|
|
1038
1045
|
|
|
@@ -1093,6 +1100,18 @@ function horizontalLoop(app, items, config) {
|
|
|
1093
1100
|
if (overallDelta > 0 && velocity < 0) velocity = 0
|
|
1094
1101
|
if (overallDelta < 0 && velocity > 0) velocity = 0
|
|
1095
1102
|
|
|
1103
|
+
// Released past an end: always spring back to it, whatever the velocity
|
|
1104
|
+
if (!shouldLoop && outOfBounds(position.get())) {
|
|
1105
|
+
inertiaAnimation = throwPastEdge(-velocity * config.throwVelocityMultiplier)
|
|
1106
|
+
inertiaAnimation
|
|
1107
|
+
.then(() => {
|
|
1108
|
+
inertiaAnimation = null
|
|
1109
|
+
updateIndexDisplay()
|
|
1110
|
+
})
|
|
1111
|
+
.catch(() => { inertiaAnimation = null })
|
|
1112
|
+
return
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1096
1115
|
// If snap is enabled, always use it (GSAP-style: snap modifies inertia target)
|
|
1097
1116
|
// Otherwise use old logic: inertia if velocity, or resume crawl
|
|
1098
1117
|
if (config.snap) {
|
|
@@ -1124,6 +1143,15 @@ function horizontalLoop(app, items, config) {
|
|
|
1124
1143
|
const velocityMultiplier = reducedMotion ? config.throwVelocityMultiplier * 0.3 : config.throwVelocityMultiplier
|
|
1125
1144
|
const motionVelocity = -velocity * velocityMultiplier
|
|
1126
1145
|
|
|
1146
|
+
// A throw that would land past either end springs off the edge instead
|
|
1147
|
+
if (!reducedMotion && throwsPastEdge(currentPos, motionVelocity)) {
|
|
1148
|
+
inertiaAnimation = throwPastEdge(motionVelocity)
|
|
1149
|
+
inertiaAnimation
|
|
1150
|
+
.then(() => { inertiaAnimation = null })
|
|
1151
|
+
.catch(() => { inertiaAnimation = null })
|
|
1152
|
+
return
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1127
1155
|
// Estimate target for Motion.js (it recomputes internally for type: 'inertia',
|
|
1128
1156
|
// but we pass a reasonable target to avoid a zero-distance animation)
|
|
1129
1157
|
const power = config.throwPower
|
|
@@ -1162,6 +1190,142 @@ function horizontalLoop(app, items, config) {
|
|
|
1162
1190
|
})
|
|
1163
1191
|
}
|
|
1164
1192
|
|
|
1193
|
+
function outOfBounds(pos) {
|
|
1194
|
+
return pos > maxScrollPosition || pos < 0
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
/**
|
|
1198
|
+
* Rubber band for dragging past an end of a non-looping row — the curve
|
|
1199
|
+
* iOS uses, (1 - 1 / (x·c/d + 1)) · d: the row follows the pointer at
|
|
1200
|
+
* `edgeElasticity` of its speed at the edge, slower the further out, and
|
|
1201
|
+
* never further than its own width. `stretch` maps drag distance to the
|
|
1202
|
+
* shown position, `unstretch` inverts it, `stretchRate` is the slope.
|
|
1203
|
+
*/
|
|
1204
|
+
function stretch(raw) {
|
|
1205
|
+
const c = config.edgeElasticity
|
|
1206
|
+
if (!c) return Math.max(0, Math.min(maxScrollPosition, raw))
|
|
1207
|
+
const d = containerWidth || container.offsetWidth
|
|
1208
|
+
const band = over => (1 - 1 / ((over * c) / d + 1)) * d
|
|
1209
|
+
if (raw > maxScrollPosition) return maxScrollPosition + band(raw - maxScrollPosition)
|
|
1210
|
+
if (raw < 0) return -band(-raw)
|
|
1211
|
+
return raw
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
function unstretch(shown) {
|
|
1215
|
+
const c = config.edgeElasticity
|
|
1216
|
+
if (!c || !outOfBounds(shown)) return shown
|
|
1217
|
+
const d = containerWidth || container.offsetWidth
|
|
1218
|
+
const over = shown > maxScrollPosition ? shown - maxScrollPosition : -shown
|
|
1219
|
+
const raw = (d / c) * (1 / (1 - Math.min(over, d - 1) / d) - 1)
|
|
1220
|
+
return shown > maxScrollPosition ? maxScrollPosition + raw : -raw
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
function stretchRate(shown) {
|
|
1224
|
+
const c = config.edgeElasticity
|
|
1225
|
+
if (!c || !outOfBounds(shown)) return 1
|
|
1226
|
+
const d = containerWidth || container.offsetWidth
|
|
1227
|
+
const over = shown > maxScrollPosition ? shown - maxScrollPosition : -shown
|
|
1228
|
+
// dy/dx = c / (x·c/d + 1)², written in terms of the shown overshoot
|
|
1229
|
+
return c * (1 - over / d) ** 2
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
/**
|
|
1233
|
+
* Whether a throw would come to rest past either end of a non-looping row.
|
|
1234
|
+
* Uses Motion's own inertia arithmetic: it rests at origin + power * velocity.
|
|
1235
|
+
*/
|
|
1236
|
+
function throwsPastEdge(currentPos, motionVelocity) {
|
|
1237
|
+
if (shouldLoop) return false
|
|
1238
|
+
if (outOfBounds(currentPos)) return true
|
|
1239
|
+
const ideal = currentPos + config.throwPower * motionVelocity
|
|
1240
|
+
return ideal > maxScrollPosition || ideal < 0
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* Throw into an end of a non-looping row: keep the speed, reach the edge,
|
|
1245
|
+
* run past it and spring back.
|
|
1246
|
+
*
|
|
1247
|
+
* The plain inertia animations clamp their target to the row (snap via
|
|
1248
|
+
* `modifyTarget`), and Motion then rescales the whole throw to that shorter
|
|
1249
|
+
* distance — so a hard throw near the end crawled the last stretch on the
|
|
1250
|
+
* exponential tail, two seconds of it. Motion's own `min`/`max` bounce
|
|
1251
|
+
* cannot help: the clamped target never reaches the boundary, and its
|
|
1252
|
+
* spring is handed a velocity in px/ms rather than px/s (see the TODO in
|
|
1253
|
+
* motion-dom's inertia generator), so it barely overshoots when it does.
|
|
1254
|
+
*
|
|
1255
|
+
* Motion's inertia is closed-form — x(t) = target - A·e^(-t/τ), with
|
|
1256
|
+
* A = power · velocity and target = origin + A — so the moment it crosses
|
|
1257
|
+
* the edge, and its speed there, are known up front. Phase one is a tween
|
|
1258
|
+
* to the edge whose easing *is* that curve; phase two a spring to the edge
|
|
1259
|
+
* starting at that speed, which carries it past and back.
|
|
1260
|
+
*
|
|
1261
|
+
* Not a listener on the value: starting the spring from inside the decay's
|
|
1262
|
+
* own `change` notification left the value NaN (the decay was mid-frame),
|
|
1263
|
+
* and the row froze with every later drag computing from NaN.
|
|
1264
|
+
*
|
|
1265
|
+
* Returns Motion-like controls — `stop()` and a thenable — so
|
|
1266
|
+
* `onPointerDown` interrupts it like any other animation.
|
|
1267
|
+
*/
|
|
1268
|
+
function throwPastEdge(motionVelocity) {
|
|
1269
|
+
const origin = position.get()
|
|
1270
|
+
// Already past an end (released mid-stretch): back to that end, starting
|
|
1271
|
+
// at the speed the row is actually moving on screen — the pointer's,
|
|
1272
|
+
// slowed by the rubber band.
|
|
1273
|
+
const outside = outOfBounds(origin)
|
|
1274
|
+
const edge = outside
|
|
1275
|
+
? (origin > maxScrollPosition ? maxScrollPosition : 0)
|
|
1276
|
+
: (motionVelocity > 0 ? maxScrollPosition : 0)
|
|
1277
|
+
findNearestSnapPoint(edge) // lands on the last (or first) item: keep the index in step
|
|
1278
|
+
|
|
1279
|
+
const tau = config.throwResistance // ms
|
|
1280
|
+
const amplitude = config.throwPower * motionVelocity
|
|
1281
|
+
const beyond = origin + amplitude - edge // how far past the edge the decay would rest
|
|
1282
|
+
// Time (ms) the decay takes to reach the edge, and its speed there (px/s)
|
|
1283
|
+
const tEdge = outside ? 0 : Math.max(0, -tau * Math.log(beyond / amplitude))
|
|
1284
|
+
const edgeVelocity = outside
|
|
1285
|
+
? motionVelocity * stretchRate(origin)
|
|
1286
|
+
: (beyond / tau) * 1000
|
|
1287
|
+
|
|
1288
|
+
let current = null
|
|
1289
|
+
let stopped = false
|
|
1290
|
+
let resolve
|
|
1291
|
+
const done = new Promise(r => { resolve = r })
|
|
1292
|
+
|
|
1293
|
+
const bounce = () => {
|
|
1294
|
+
if (stopped) return
|
|
1295
|
+
current = animate(position, edge, {
|
|
1296
|
+
type: 'spring',
|
|
1297
|
+
velocity: edgeVelocity,
|
|
1298
|
+
stiffness: config.edgeStiffness,
|
|
1299
|
+
damping: config.edgeDamping,
|
|
1300
|
+
restSpeed: 10,
|
|
1301
|
+
restDelta: 0.5,
|
|
1302
|
+
})
|
|
1303
|
+
current.then(resolve, resolve)
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
if (tEdge < 1 || edge === origin) {
|
|
1307
|
+
bounce()
|
|
1308
|
+
} else {
|
|
1309
|
+
const span = edge - origin
|
|
1310
|
+
current = animate(position, edge, {
|
|
1311
|
+
duration: tEdge / 1000,
|
|
1312
|
+
// The decay's own curve, normalised to 0..1 over the way to the edge
|
|
1313
|
+
ease: p => (amplitude * (1 - Math.exp((-p * tEdge) / tau))) / span,
|
|
1314
|
+
})
|
|
1315
|
+
current.then(bounce, () => {})
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
return {
|
|
1319
|
+
stop() {
|
|
1320
|
+
stopped = true
|
|
1321
|
+
current?.stop()
|
|
1322
|
+
resolve()
|
|
1323
|
+
},
|
|
1324
|
+
then: (onResolve, onReject) => done.then(onResolve, onReject),
|
|
1325
|
+
catch: onReject => done.catch(onReject),
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1165
1329
|
/**
|
|
1166
1330
|
* Find the nearest snap point to a given position
|
|
1167
1331
|
* @param {number} targetPos - Position to find nearest snap point for
|
|
@@ -1248,6 +1412,18 @@ function horizontalLoop(app, items, config) {
|
|
|
1248
1412
|
const motionVelocity =
|
|
1249
1413
|
-velocity * config.throwVelocityMultiplier * config.snapVelocityMultiplier
|
|
1250
1414
|
|
|
1415
|
+
// A throw that would land past either end springs off the edge instead
|
|
1416
|
+
if (throwsPastEdge(currentPos, motionVelocity)) {
|
|
1417
|
+
snapAnimation = throwPastEdge(motionVelocity)
|
|
1418
|
+
snapAnimation
|
|
1419
|
+
.then(() => {
|
|
1420
|
+
snapAnimation = null
|
|
1421
|
+
updateIndexDisplay()
|
|
1422
|
+
})
|
|
1423
|
+
.catch(() => { snapAnimation = null })
|
|
1424
|
+
return
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1251
1427
|
// Calculate ideal inertia target (Motion will recalculate, but we need a non-zero animation)
|
|
1252
1428
|
// This ensures Motion starts the inertia physics
|
|
1253
1429
|
const idealTarget =
|
|
@@ -1909,6 +2085,9 @@ export default class Looper {
|
|
|
1909
2085
|
snapVelocityMultiplier: this.opts.snapVelocityMultiplier,
|
|
1910
2086
|
snapDuration: this.opts.snapDuration,
|
|
1911
2087
|
snapBounce: this.opts.snapBounce,
|
|
2088
|
+
edgeStiffness: this.opts.edgeStiffness,
|
|
2089
|
+
edgeDamping: this.opts.edgeDamping,
|
|
2090
|
+
edgeElasticity: this.opts.edgeElasticity,
|
|
1912
2091
|
minimumMovement: this.opts.minimumMovement,
|
|
1913
2092
|
touchMinimumMovement: this.opts.touchMinimumMovement,
|
|
1914
2093
|
},
|
|
@@ -52,6 +52,7 @@ import { set } from '../../utils/motion-helpers'
|
|
|
52
52
|
/**
|
|
53
53
|
* @typedef {Object} StickyHeaderSectionOptions
|
|
54
54
|
* @property {boolean} [unPinOnResize=true] - Whether to unpin header on window resize
|
|
55
|
+
* @property {boolean} [headerHeightTracksPin=true] - Whether --header-height drops to 0 when the header unpins. Set false for a header that never retracts.
|
|
55
56
|
* @property {Window|HTMLElement} [canvas=window] - Scrolling element
|
|
56
57
|
* @property {string|null} [intersects=null] - Selector for elements to check intersection with
|
|
57
58
|
* @property {Function} [beforeEnter] - Called before header enters
|
|
@@ -155,6 +156,7 @@ const DEFAULT_OPTIONS = {
|
|
|
155
156
|
|
|
156
157
|
default: {
|
|
157
158
|
unPinOnResize: true,
|
|
159
|
+
headerHeightTracksPin: true,
|
|
158
160
|
canvas: window,
|
|
159
161
|
intersects: null,
|
|
160
162
|
beforeEnter: (h) => {
|
|
@@ -609,10 +611,24 @@ export default class StickyHeader {
|
|
|
609
611
|
|
|
610
612
|
/**
|
|
611
613
|
* Update the --header-height CSS variable on :root.
|
|
612
|
-
*
|
|
614
|
+
*
|
|
615
|
+
* By default this is how much header is *visible* — the measured height when
|
|
616
|
+
* pinned, 0 when unpinned — so anything positioned under the bar follows it
|
|
617
|
+
* out of the way as it retracts.
|
|
618
|
+
*
|
|
619
|
+
* That is wrong for a header configured never to retract, whether through
|
|
620
|
+
* `preventUnpin` or by no-opping `onPin` / `onUnpin`. The bar stays put, but
|
|
621
|
+
* `_pinned` still flips on every change of scroll direction, so the variable
|
|
622
|
+
* drops to 0 and back while nothing moves. Any layout sized from it then grows
|
|
623
|
+
* and shrinks the document under the reader. Scroll anchoring absorbs that
|
|
624
|
+
* mid-page, but not at the very bottom, where the scroll offset is clamped to
|
|
625
|
+
* the document and the page visibly jumps instead.
|
|
626
|
+
*
|
|
627
|
+
* `headerHeightTracksPin: false` publishes the measured height throughout.
|
|
613
628
|
*/
|
|
614
629
|
_updateHeaderHeight() {
|
|
615
|
-
const
|
|
630
|
+
const tracksPin = this.opts.headerHeightTracksPin !== false
|
|
631
|
+
const height = tracksPin && !this._pinned ? '0px' : `${this.el.clientHeight}px`
|
|
616
632
|
document.documentElement.style.setProperty('--header-height', height)
|
|
617
633
|
}
|
|
618
634
|
|
|
@@ -48,8 +48,21 @@ export default class DoubleHeader {
|
|
|
48
48
|
small(): void;
|
|
49
49
|
/**
|
|
50
50
|
* Update the --header-height CSS variable on :root.
|
|
51
|
-
*
|
|
52
|
-
*
|
|
51
|
+
*
|
|
52
|
+
* Measured from `el`, the main header — `auxEl` is the clone. By default this
|
|
53
|
+
* is how much header is *visible*, the measured height when pinned and 0 when
|
|
54
|
+
* unpinned, so anything positioned under the bar follows it out of the way as
|
|
55
|
+
* the clone retracts.
|
|
56
|
+
*
|
|
57
|
+
* That is wrong for a header configured never to retract, whether through
|
|
58
|
+
* `preventUnpin` or by no-opping `onPin` / `onUnpin`. The bar stays put, but
|
|
59
|
+
* `_pinned` still flips on every change of scroll direction, so the variable
|
|
60
|
+
* drops to 0 and back while nothing moves. Any layout sized from it then grows
|
|
61
|
+
* and shrinks the document under the reader. Scroll anchoring absorbs that
|
|
62
|
+
* mid-page, but not at the very bottom, where the scroll offset is clamped to
|
|
63
|
+
* the document and the page visibly jumps instead.
|
|
64
|
+
*
|
|
65
|
+
* `headerHeightTracksPin: false` publishes the measured height throughout.
|
|
53
66
|
*/
|
|
54
67
|
_updateHeaderHeight(): void;
|
|
55
68
|
shouldUnpin(toleranceExceeded: any): any;
|
|
@@ -59,7 +59,20 @@ export default class StickyHeader {
|
|
|
59
59
|
small(): void;
|
|
60
60
|
/**
|
|
61
61
|
* Update the --header-height CSS variable on :root.
|
|
62
|
-
*
|
|
62
|
+
*
|
|
63
|
+
* By default this is how much header is *visible* — the measured height when
|
|
64
|
+
* pinned, 0 when unpinned — so anything positioned under the bar follows it
|
|
65
|
+
* out of the way as it retracts.
|
|
66
|
+
*
|
|
67
|
+
* That is wrong for a header configured never to retract, whether through
|
|
68
|
+
* `preventUnpin` or by no-opping `onPin` / `onUnpin`. The bar stays put, but
|
|
69
|
+
* `_pinned` still flips on every change of scroll direction, so the variable
|
|
70
|
+
* drops to 0 and back while nothing moves. Any layout sized from it then grows
|
|
71
|
+
* and shrinks the document under the reader. Scroll anchoring absorbs that
|
|
72
|
+
* mid-page, but not at the very bottom, where the scroll offset is clamped to
|
|
73
|
+
* the document and the page visibly jumps instead.
|
|
74
|
+
*
|
|
75
|
+
* `headerHeightTracksPin: false` publishes the measured height throughout.
|
|
63
76
|
*/
|
|
64
77
|
_updateHeaderHeight(): void;
|
|
65
78
|
notAltBg(): void;
|
|
@@ -143,6 +156,10 @@ export type StickyHeaderSectionOptions = {
|
|
|
143
156
|
* - Whether to unpin header on window resize
|
|
144
157
|
*/
|
|
145
158
|
unPinOnResize?: boolean;
|
|
159
|
+
/**
|
|
160
|
+
* - Whether --header-height drops to 0 when the header unpins. Set false for a header that never retracts.
|
|
161
|
+
*/
|
|
162
|
+
headerHeightTracksPin?: boolean;
|
|
146
163
|
/**
|
|
147
164
|
* - Scrolling element
|
|
148
165
|
*/
|