@sticky-aside/core 1.0.0 → 1.0.1
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 +22 -0
- package/dist/presenter.js +9 -1
- package/dist/presenter.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,11 +6,33 @@ A short panel stays pinned to the top. A tall panel scrolls with the page, pins
|
|
|
6
6
|
npm install @sticky-aside/core
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
+
```html
|
|
10
|
+
<aside class="column">
|
|
11
|
+
<div class="panel">…</div>
|
|
12
|
+
</aside>
|
|
13
|
+
```
|
|
14
|
+
|
|
9
15
|
```ts
|
|
10
16
|
import { createStickyAside } from '@sticky-aside/core'
|
|
11
17
|
import '@sticky-aside/core/offsets.css'
|
|
12
18
|
|
|
19
|
+
const wrapper = document.querySelector('.column')
|
|
20
|
+
const content = document.querySelector('.panel')
|
|
21
|
+
|
|
13
22
|
const aside = createStickyAside({ wrapper, content })
|
|
14
23
|
```
|
|
15
24
|
|
|
25
|
+
`wrapper` is the column that stays in the layout. `content` is the panel that moves and pins. The core sets `position: relative` and `height: 100%` on the wrapper.
|
|
26
|
+
|
|
27
|
+
`offsets.css` defines `sticky-aside-top` and `sticky-aside-bottom`. Set the gap with CSS variables on an ancestor (default `0px`):
|
|
28
|
+
|
|
29
|
+
```css
|
|
30
|
+
.column {
|
|
31
|
+
--sticky-aside-top: 40px;
|
|
32
|
+
--sticky-aside-bottom: 16px;
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or skip that stylesheet and pass your own `topClass` / `bottomClass` to `createStickyAside` / `setClasses`.
|
|
37
|
+
|
|
16
38
|
Vue, React, and Svelte adapters are `@sticky-aside/vue`, `@sticky-aside/react`, and `@sticky-aside/svelte`. The full guide is in the [repository README](https://github.com/maprox/sticky-aside#readme).
|
package/dist/presenter.js
CHANGED
|
@@ -73,6 +73,9 @@ function getStickyModelAtEdges({ model, frame }) {
|
|
|
73
73
|
function isFullyVisible(frame) {
|
|
74
74
|
return frame.measure.height >= frame.content.height;
|
|
75
75
|
}
|
|
76
|
+
function isCoveringTopOffset(frame) {
|
|
77
|
+
return frame.content.top >= 0 && frame.content.top < frame.measure.top;
|
|
78
|
+
}
|
|
76
79
|
function isMeasureInside(frame) {
|
|
77
80
|
return frame.measure.top >= frame.wrapper.top && frame.measure.bottom <= frame.wrapper.bottom;
|
|
78
81
|
}
|
|
@@ -125,7 +128,10 @@ function getNewStickyModel(model, frame) {
|
|
|
125
128
|
frame
|
|
126
129
|
});
|
|
127
130
|
if (frame.reason === REASON.resize) {
|
|
128
|
-
if (isMeasureInside(frame))
|
|
131
|
+
if (isMeasureInside(frame)) {
|
|
132
|
+
if (isFullyVisible(frame) || isCoveringTopOffset(frame)) return getPinnedStickyModel(model, "top");
|
|
133
|
+
return model;
|
|
134
|
+
}
|
|
129
135
|
return getRelativeStickyModel({
|
|
130
136
|
model: getClearedLockModel(model),
|
|
131
137
|
frame
|
|
@@ -222,12 +228,14 @@ function createStickyAsidePresenter(view, options) {
|
|
|
222
228
|
}
|
|
223
229
|
function apply(reason) {
|
|
224
230
|
if (isStopped) return;
|
|
231
|
+
const previousState = painted;
|
|
225
232
|
view.paintMeasure();
|
|
226
233
|
const reading = view.read();
|
|
227
234
|
model = getNewStickyModel(model, getStickyFrame(session, reading, isScrollingUp, reason));
|
|
228
235
|
const paint = getStickyPaint(model, session, reading.wrapper.width);
|
|
229
236
|
view.paint(paint);
|
|
230
237
|
report(paint.state);
|
|
238
|
+
if (reason === REASON.scroll && previousState !== void 0 && previousState !== "flow" && previousState !== "off" && paint.state === "flow") apply(REASON.scroll);
|
|
231
239
|
}
|
|
232
240
|
function onScroll() {
|
|
233
241
|
const scrollY = view.read().metrics.scrollY;
|
package/dist/presenter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presenter.js","names":[],"sources":["../src/model/constants.ts","../src/model/utils.ts","../src/model/step.ts","../src/presenter/constants.ts","../src/presenter/utils.ts","../src/presenter/presenter.ts"],"sourcesContent":["export const MODE = {\n relative: 'relative',\n fixedTop: 'fixed-top',\n fixedBottom: 'fixed-bottom',\n fixedLocked: 'fixed-locked',\n} as const\n\nexport const REASON = {\n scroll: 'scroll',\n resize: 'resize',\n lock: 'lock',\n unlock: 'unlock',\n} as const\n","import { MODE, REASON } from '#core/model/constants.ts'\nimport type { StickyFrame, StickyModel } from '#core/model/types.ts'\n\nexport interface StickyStep {\n model: StickyModel\n frame: StickyFrame\n}\n\nexport function getClearedLockModel(model: StickyModel): StickyModel {\n return {\n ...model,\n locked: false,\n lockedTop: null,\n }\n}\n\nexport function getPinnedStickyModel(model: StickyModel, edge: 'top' | 'bottom'): StickyModel {\n return {\n ...model,\n mode: edge === 'top' ? MODE.fixedTop : MODE.fixedBottom,\n locked: false,\n }\n}\n\nexport function getLockedStickyModel({ model, frame }: StickyStep): StickyModel {\n const lockedTop = model.lockedTop ?? frame.content.top\n const isPastTop = !frame.allowLockedOverflowTop && frame.wrapper.top > lockedTop\n const isPastBottom = !frame.allowLockedOverflowBottom &&\n lockedTop + frame.content.height > frame.wrapper.top + frame.wrapper.height\n\n if (isPastTop || isPastBottom) {\n return getRelativeStickyModel({\n model: {\n ...model,\n locked: true,\n lockedTop,\n },\n frame,\n })\n }\n\n return {\n ...model,\n mode: MODE.fixedLocked,\n locked: true,\n lockedTop,\n }\n}\n\nexport function getRelativeStickyModel({ model, frame }: StickyStep): StickyModel {\n let containerTop = Math.max(frame.content.top - frame.wrapper.top, 0)\n if (!allowsBottomGap(frame)) {\n containerTop = getClampedContainerTop(containerTop, frame)\n }\n\n return {\n mode: MODE.relative,\n containerTop,\n locked: model.locked,\n lockedTop: model.locked ? model.lockedTop : null,\n }\n}\n\nexport function getStickyModelAtEdges({ model, frame }: StickyStep): StickyModel {\n const isMeasureBelow = frame.measure.bottom > frame.wrapper.bottom\n const isAlreadyAtBottom = Math.round(frame.content.bottom) === Math.round(frame.wrapper.bottom)\n const isAlreadyAtTop = frame.content.top === 0\n\n if ((isMeasureBelow && isAlreadyAtBottom) || (!isMeasureBelow && isAlreadyAtTop)) {\n return model\n }\n\n const containerTop = getClampedContainerTop(isMeasureBelow ? frame.wrapper.height : 0, frame)\n\n return {\n mode: MODE.relative,\n containerTop,\n locked: false,\n lockedTop: null,\n }\n}\n\nexport function isFullyVisible(frame: StickyFrame): boolean {\n return frame.measure.height >= frame.content.height\n}\n\nexport function isMeasureInside(frame: StickyFrame): boolean {\n return frame.measure.top >= frame.wrapper.top && frame.measure.bottom <= frame.wrapper.bottom\n}\n\nexport function isOutsideViewport(frame: StickyFrame): boolean {\n return frame.scrollY < 0 || frame.scrollY > frame.documentHeight - frame.viewportHeight\n}\n\nexport function isFixed(model: StickyModel): boolean {\n return model.mode !== MODE.relative\n}\n\nexport function isScrollingOpposite({ model, frame }: StickyStep): boolean {\n const isFixedTop = model.mode === MODE.fixedTop || model.mode === MODE.fixedLocked\n\n return (frame.scrollingUp && !isFixedTop) || (!frame.scrollingUp && isFixedTop)\n}\n\nfunction allowsBottomGap(frame: StickyFrame): boolean {\n return frame.reason === REASON.unlock && frame.allowLockedOverflowBottom\n}\n\nfunction getClampedContainerTop(containerTop: number, frame: StickyFrame): number {\n const bottomGap = frame.wrapper.height - (containerTop + frame.content.height)\n let next = containerTop\n if (bottomGap < 0) {\n next += bottomGap\n }\n\n return next < 0 ? 0 : next\n}\n","import { MODE, REASON } from '#core/model/constants.ts'\nimport type { Box, StickyFrame, StickyModel } from '#core/model/types.ts'\nimport {\n getClearedLockModel,\n getLockedStickyModel,\n getPinnedStickyModel,\n getRelativeStickyModel,\n getStickyModelAtEdges,\n isFixed,\n isFullyVisible,\n isMeasureInside,\n isOutsideViewport,\n isScrollingOpposite,\n} from '#core/model/utils.ts'\n\nexport type { Box, StickyFrame, StickyModel }\n\nexport function getInitialStickyModel(): StickyModel {\n return {\n mode: MODE.relative,\n containerTop: 0,\n locked: false,\n lockedTop: null,\n }\n}\n\nexport function getNewStickyModel(model: StickyModel, frame: StickyFrame): StickyModel {\n if (frame.disabled) {\n return model\n }\n\n if (frame.reason === REASON.unlock) {\n return getRelativeStickyModel({ model: getClearedLockModel(model), frame })\n }\n\n if (frame.reason === REASON.lock) {\n return getLockedStickyModel({\n model: {\n ...model,\n locked: true,\n lockedTop: frame.content.top,\n },\n frame,\n })\n }\n\n if (frame.locked) {\n return getLockedStickyModel({ model, frame })\n }\n\n if (frame.reason === REASON.resize) {\n if (isMeasureInside(frame)) {\n return isFullyVisible(frame) ? getPinnedStickyModel(model, 'top') : model\n }\n\n return getRelativeStickyModel({ model: getClearedLockModel(model), frame })\n }\n\n if (isFixed(model)) {\n const isReleasing =\n (!isMeasureInside(frame) && !isOutsideViewport(frame)) ||\n (!isFullyVisible(frame) && isScrollingOpposite({ model, frame }))\n\n return isReleasing ? getRelativeStickyModel({ model: getClearedLockModel(model), frame }) : model\n }\n\n if (isMeasureInside(frame)) {\n if (isFullyVisible(frame)) {\n return getPinnedStickyModel(model, 'top')\n }\n\n if (frame.scrollingUp && frame.content.top > frame.measure.top) {\n return getPinnedStickyModel(model, 'top')\n }\n\n if (!frame.scrollingUp && frame.content.bottom < frame.measure.bottom) {\n return getPinnedStickyModel(model, 'bottom')\n }\n\n return model\n }\n\n return getStickyModelAtEdges({ model, frame })\n}\n","export const DEFAULTS = {\n disabled: false,\n locked: false,\n allowLockedOverflowTop: false,\n allowLockedOverflowBottom: false,\n} as const\n","import { MODE } from '#core/model/constants.ts'\nimport type { StickyFrame, StickyModel, StickyReason } from '#core/model/types.ts'\nimport { DEFAULTS } from '#core/presenter/constants.ts'\nimport type { Session } from '#core/presenter/types.ts'\nimport type { StickyAsidePresenterOptions, StickyPaint, StickyReading } from '#core/types.ts'\n\nexport function getSession(options: StickyAsidePresenterOptions): Session {\n return {\n disabled: options.disabled ?? DEFAULTS.disabled,\n locked: options.locked ?? DEFAULTS.locked,\n allowLockedOverflowTop: options.allowLockedOverflowTop ?? DEFAULTS.allowLockedOverflowTop,\n allowLockedOverflowBottom: options.allowLockedOverflowBottom ?? DEFAULTS.allowLockedOverflowBottom,\n }\n}\n\nexport function getStickyFrame(\n session: Session,\n reading: StickyReading,\n isScrollingUp: boolean,\n reason: StickyReason,\n): StickyFrame {\n return {\n disabled: session.disabled,\n locked: session.locked,\n allowLockedOverflowTop: session.allowLockedOverflowTop,\n allowLockedOverflowBottom: session.allowLockedOverflowBottom,\n scrollingUp: isScrollingUp,\n scrollY: reading.metrics.scrollY,\n viewportHeight: reading.metrics.viewportHeight,\n documentHeight: reading.metrics.documentHeight,\n wrapper: reading.wrapper,\n content: reading.content,\n measure: reading.measure,\n reason,\n }\n}\n\nexport function getStickyPaint(model: StickyModel, session: Session, wrapperWidth: number): StickyPaint {\n if (session.disabled) {\n return {\n state: 'off',\n }\n }\n\n if (model.mode === MODE.relative) {\n return {\n state: 'flow',\n top: model.containerTop,\n }\n }\n\n if (model.mode === MODE.fixedBottom) {\n return {\n state: 'bottom',\n width: wrapperWidth,\n }\n }\n\n if (model.mode === MODE.fixedLocked) {\n return {\n state: 'locked',\n top: model.lockedTop ?? 0,\n width: wrapperWidth,\n }\n }\n\n return {\n state: 'top',\n width: wrapperWidth,\n }\n}\n","import { REASON } from '#core/model/constants.ts'\nimport { getInitialStickyModel, getNewStickyModel } from '#core/model/step.ts'\nimport type { StickyReason } from '#core/model/types.ts'\nimport { getSession, getStickyFrame, getStickyPaint } from '#core/presenter/utils.ts'\nimport type {\n StickyAsideClasses,\n StickyAsideController,\n StickyAsidePresenterOptions,\n StickyAsideState,\n StickyAsideView,\n} from '#core/types.ts'\n\nexport function createStickyAsidePresenter(\n view: StickyAsideView,\n options: StickyAsidePresenterOptions,\n): StickyAsideController {\n const session = getSession(options)\n let model = getInitialStickyModel()\n let isScrollingUp = false\n let isStopped = false\n let painted: StickyAsideState | undefined\n let lastScrollY = view.read().metrics.scrollY\n\n function report(state: StickyAsideState) {\n if (isStopped || state === painted) {\n return\n }\n\n painted = state\n options.onStateChange?.(state)\n }\n\n function apply(reason: StickyReason) {\n if (isStopped) {\n return\n }\n\n view.paintMeasure()\n const reading = view.read()\n model = getNewStickyModel(model, getStickyFrame(session, reading, isScrollingUp, reason))\n const paint = getStickyPaint(model, session, reading.wrapper.width)\n view.paint(paint)\n report(paint.state)\n }\n\n function onScroll() {\n const scrollY = view.read().metrics.scrollY\n isScrollingUp = scrollY < lastScrollY\n lastScrollY = scrollY\n apply(REASON.scroll)\n }\n\n function onResize() {\n apply(REASON.resize)\n }\n\n function update(reason: Extract<StickyReason, 'scroll' | 'resize'> = REASON.resize) {\n apply(reason)\n }\n\n function setLocked(isLocked: boolean) {\n if (isStopped || isLocked === session.locked) {\n return\n }\n\n session.locked = isLocked\n apply(isLocked ? REASON.lock : REASON.unlock)\n }\n\n function setDisabled(isDisabled: boolean) {\n if (isStopped || isDisabled === session.disabled) {\n return\n }\n\n session.disabled = isDisabled\n apply(REASON.resize)\n }\n\n function setClasses(next: StickyAsideClasses) {\n if (isStopped) {\n return\n }\n\n view.setClasses(next)\n apply(REASON.resize)\n }\n\n function setAllowLockedOverflow(isAllowTop: boolean, isAllowBottom: boolean) {\n if (isStopped) {\n return\n }\n\n session.allowLockedOverflowTop = isAllowTop\n session.allowLockedOverflowBottom = isAllowBottom\n apply(REASON.resize)\n }\n\n function getState() {\n return painted ?? 'off'\n }\n\n function getModel() {\n return model\n }\n\n const unsubscribe = view.subscribe({\n scroll: onScroll,\n resize: onResize,\n })\n\n function destroy() {\n if (isStopped) {\n return\n }\n\n isStopped = true\n unsubscribe()\n view.destroy()\n }\n\n apply(session.locked ? REASON.lock : REASON.resize)\n\n return {\n update,\n setLocked,\n setDisabled,\n setClasses,\n setAllowLockedOverflow,\n destroy,\n getState,\n getModel,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"presenter.js","names":[],"sources":["../src/model/constants.ts","../src/model/utils.ts","../src/model/step.ts","../src/presenter/constants.ts","../src/presenter/utils.ts","../src/presenter/presenter.ts"],"sourcesContent":["export const MODE = {\n relative: 'relative',\n fixedTop: 'fixed-top',\n fixedBottom: 'fixed-bottom',\n fixedLocked: 'fixed-locked',\n} as const\n\nexport const REASON = {\n scroll: 'scroll',\n resize: 'resize',\n lock: 'lock',\n unlock: 'unlock',\n} as const\n","import { MODE, REASON } from '#core/model/constants.ts'\nimport type { StickyFrame, StickyModel } from '#core/model/types.ts'\n\nexport interface StickyStep {\n model: StickyModel\n frame: StickyFrame\n}\n\nexport function getClearedLockModel(model: StickyModel): StickyModel {\n return {\n ...model,\n locked: false,\n lockedTop: null,\n }\n}\n\nexport function getPinnedStickyModel(model: StickyModel, edge: 'top' | 'bottom'): StickyModel {\n return {\n ...model,\n mode: edge === 'top' ? MODE.fixedTop : MODE.fixedBottom,\n locked: false,\n }\n}\n\nexport function getLockedStickyModel({ model, frame }: StickyStep): StickyModel {\n const lockedTop = model.lockedTop ?? frame.content.top\n const isPastTop = !frame.allowLockedOverflowTop && frame.wrapper.top > lockedTop\n const isPastBottom = !frame.allowLockedOverflowBottom &&\n lockedTop + frame.content.height > frame.wrapper.top + frame.wrapper.height\n\n if (isPastTop || isPastBottom) {\n return getRelativeStickyModel({\n model: {\n ...model,\n locked: true,\n lockedTop,\n },\n frame,\n })\n }\n\n return {\n ...model,\n mode: MODE.fixedLocked,\n locked: true,\n lockedTop,\n }\n}\n\nexport function getRelativeStickyModel({ model, frame }: StickyStep): StickyModel {\n let containerTop = Math.max(frame.content.top - frame.wrapper.top, 0)\n if (!allowsBottomGap(frame)) {\n containerTop = getClampedContainerTop(containerTop, frame)\n }\n\n return {\n mode: MODE.relative,\n containerTop,\n locked: model.locked,\n lockedTop: model.locked ? model.lockedTop : null,\n }\n}\n\nexport function getStickyModelAtEdges({ model, frame }: StickyStep): StickyModel {\n const isMeasureBelow = frame.measure.bottom > frame.wrapper.bottom\n const isAlreadyAtBottom = Math.round(frame.content.bottom) === Math.round(frame.wrapper.bottom)\n const isAlreadyAtTop = frame.content.top === 0\n\n if ((isMeasureBelow && isAlreadyAtBottom) || (!isMeasureBelow && isAlreadyAtTop)) {\n return model\n }\n\n const containerTop = getClampedContainerTop(isMeasureBelow ? frame.wrapper.height : 0, frame)\n\n return {\n mode: MODE.relative,\n containerTop,\n locked: false,\n lockedTop: null,\n }\n}\n\nexport function isFullyVisible(frame: StickyFrame): boolean {\n return frame.measure.height >= frame.content.height\n}\n\nexport function isCoveringTopOffset(frame: StickyFrame): boolean {\n return frame.content.top >= 0 && frame.content.top < frame.measure.top\n}\n\nexport function isMeasureInside(frame: StickyFrame): boolean {\n return frame.measure.top >= frame.wrapper.top && frame.measure.bottom <= frame.wrapper.bottom\n}\n\nexport function isOutsideViewport(frame: StickyFrame): boolean {\n return frame.scrollY < 0 || frame.scrollY > frame.documentHeight - frame.viewportHeight\n}\n\nexport function isFixed(model: StickyModel): boolean {\n return model.mode !== MODE.relative\n}\n\nexport function isScrollingOpposite({ model, frame }: StickyStep): boolean {\n const isFixedTop = model.mode === MODE.fixedTop || model.mode === MODE.fixedLocked\n\n return (frame.scrollingUp && !isFixedTop) || (!frame.scrollingUp && isFixedTop)\n}\n\nfunction allowsBottomGap(frame: StickyFrame): boolean {\n return frame.reason === REASON.unlock && frame.allowLockedOverflowBottom\n}\n\nfunction getClampedContainerTop(containerTop: number, frame: StickyFrame): number {\n const bottomGap = frame.wrapper.height - (containerTop + frame.content.height)\n let next = containerTop\n if (bottomGap < 0) {\n next += bottomGap\n }\n\n return next < 0 ? 0 : next\n}\n","import { MODE, REASON } from '#core/model/constants.ts'\nimport type { Box, StickyFrame, StickyModel } from '#core/model/types.ts'\nimport {\n getClearedLockModel,\n getLockedStickyModel,\n getPinnedStickyModel,\n getRelativeStickyModel,\n getStickyModelAtEdges,\n isCoveringTopOffset,\n isFixed,\n isFullyVisible,\n isMeasureInside,\n isOutsideViewport,\n isScrollingOpposite,\n} from '#core/model/utils.ts'\n\nexport type { Box, StickyFrame, StickyModel }\n\nexport function getInitialStickyModel(): StickyModel {\n return {\n mode: MODE.relative,\n containerTop: 0,\n locked: false,\n lockedTop: null,\n }\n}\n\nexport function getNewStickyModel(model: StickyModel, frame: StickyFrame): StickyModel {\n if (frame.disabled) {\n return model\n }\n\n if (frame.reason === REASON.unlock) {\n return getRelativeStickyModel({ model: getClearedLockModel(model), frame })\n }\n\n if (frame.reason === REASON.lock) {\n return getLockedStickyModel({\n model: {\n ...model,\n locked: true,\n lockedTop: frame.content.top,\n },\n frame,\n })\n }\n\n if (frame.locked) {\n return getLockedStickyModel({ model, frame })\n }\n\n if (frame.reason === REASON.resize) {\n if (isMeasureInside(frame)) {\n if (isFullyVisible(frame) || isCoveringTopOffset(frame)) {\n return getPinnedStickyModel(model, 'top')\n }\n\n return model\n }\n\n return getRelativeStickyModel({ model: getClearedLockModel(model), frame })\n }\n\n if (isFixed(model)) {\n const isReleasing =\n (!isMeasureInside(frame) && !isOutsideViewport(frame)) ||\n (!isFullyVisible(frame) && isScrollingOpposite({ model, frame }))\n\n return isReleasing ? getRelativeStickyModel({ model: getClearedLockModel(model), frame }) : model\n }\n\n if (isMeasureInside(frame)) {\n if (isFullyVisible(frame)) {\n return getPinnedStickyModel(model, 'top')\n }\n\n if (frame.scrollingUp && frame.content.top > frame.measure.top) {\n return getPinnedStickyModel(model, 'top')\n }\n\n if (!frame.scrollingUp && frame.content.bottom < frame.measure.bottom) {\n return getPinnedStickyModel(model, 'bottom')\n }\n\n return model\n }\n\n return getStickyModelAtEdges({ model, frame })\n}\n","export const DEFAULTS = {\n disabled: false,\n locked: false,\n allowLockedOverflowTop: false,\n allowLockedOverflowBottom: false,\n} as const\n","import { MODE } from '#core/model/constants.ts'\nimport type { StickyFrame, StickyModel, StickyReason } from '#core/model/types.ts'\nimport { DEFAULTS } from '#core/presenter/constants.ts'\nimport type { Session } from '#core/presenter/types.ts'\nimport type { StickyAsidePresenterOptions, StickyPaint, StickyReading } from '#core/types.ts'\n\nexport function getSession(options: StickyAsidePresenterOptions): Session {\n return {\n disabled: options.disabled ?? DEFAULTS.disabled,\n locked: options.locked ?? DEFAULTS.locked,\n allowLockedOverflowTop: options.allowLockedOverflowTop ?? DEFAULTS.allowLockedOverflowTop,\n allowLockedOverflowBottom: options.allowLockedOverflowBottom ?? DEFAULTS.allowLockedOverflowBottom,\n }\n}\n\nexport function getStickyFrame(\n session: Session,\n reading: StickyReading,\n isScrollingUp: boolean,\n reason: StickyReason,\n): StickyFrame {\n return {\n disabled: session.disabled,\n locked: session.locked,\n allowLockedOverflowTop: session.allowLockedOverflowTop,\n allowLockedOverflowBottom: session.allowLockedOverflowBottom,\n scrollingUp: isScrollingUp,\n scrollY: reading.metrics.scrollY,\n viewportHeight: reading.metrics.viewportHeight,\n documentHeight: reading.metrics.documentHeight,\n wrapper: reading.wrapper,\n content: reading.content,\n measure: reading.measure,\n reason,\n }\n}\n\nexport function getStickyPaint(model: StickyModel, session: Session, wrapperWidth: number): StickyPaint {\n if (session.disabled) {\n return {\n state: 'off',\n }\n }\n\n if (model.mode === MODE.relative) {\n return {\n state: 'flow',\n top: model.containerTop,\n }\n }\n\n if (model.mode === MODE.fixedBottom) {\n return {\n state: 'bottom',\n width: wrapperWidth,\n }\n }\n\n if (model.mode === MODE.fixedLocked) {\n return {\n state: 'locked',\n top: model.lockedTop ?? 0,\n width: wrapperWidth,\n }\n }\n\n return {\n state: 'top',\n width: wrapperWidth,\n }\n}\n","import { REASON } from '#core/model/constants.ts'\nimport { getInitialStickyModel, getNewStickyModel } from '#core/model/step.ts'\nimport type { StickyReason } from '#core/model/types.ts'\nimport { getSession, getStickyFrame, getStickyPaint } from '#core/presenter/utils.ts'\nimport type {\n StickyAsideClasses,\n StickyAsideController,\n StickyAsidePresenterOptions,\n StickyAsideState,\n StickyAsideView,\n} from '#core/types.ts'\n\nexport function createStickyAsidePresenter(\n view: StickyAsideView,\n options: StickyAsidePresenterOptions,\n): StickyAsideController {\n const session = getSession(options)\n let model = getInitialStickyModel()\n let isScrollingUp = false\n let isStopped = false\n let painted: StickyAsideState | undefined\n let lastScrollY = view.read().metrics.scrollY\n\n function report(state: StickyAsideState) {\n if (isStopped || state === painted) {\n return\n }\n\n painted = state\n options.onStateChange?.(state)\n }\n\n function apply(reason: StickyReason) {\n if (isStopped) {\n return\n }\n\n const previousState = painted\n view.paintMeasure()\n const reading = view.read()\n model = getNewStickyModel(model, getStickyFrame(session, reading, isScrollingUp, reason))\n const paint = getStickyPaint(model, session, reading.wrapper.width)\n view.paint(paint)\n report(paint.state)\n\n const didReleaseToFlow = reason === REASON.scroll &&\n previousState !== undefined &&\n previousState !== 'flow' &&\n previousState !== 'off' &&\n paint.state === 'flow'\n if (didReleaseToFlow) {\n apply(REASON.scroll)\n }\n }\n\n function onScroll() {\n const scrollY = view.read().metrics.scrollY\n isScrollingUp = scrollY < lastScrollY\n lastScrollY = scrollY\n apply(REASON.scroll)\n }\n\n function onResize() {\n apply(REASON.resize)\n }\n\n function update(reason: Extract<StickyReason, 'scroll' | 'resize'> = REASON.resize) {\n apply(reason)\n }\n\n function setLocked(isLocked: boolean) {\n if (isStopped || isLocked === session.locked) {\n return\n }\n\n session.locked = isLocked\n apply(isLocked ? REASON.lock : REASON.unlock)\n }\n\n function setDisabled(isDisabled: boolean) {\n if (isStopped || isDisabled === session.disabled) {\n return\n }\n\n session.disabled = isDisabled\n apply(REASON.resize)\n }\n\n function setClasses(next: StickyAsideClasses) {\n if (isStopped) {\n return\n }\n\n view.setClasses(next)\n apply(REASON.resize)\n }\n\n function setAllowLockedOverflow(isAllowTop: boolean, isAllowBottom: boolean) {\n if (isStopped) {\n return\n }\n\n session.allowLockedOverflowTop = isAllowTop\n session.allowLockedOverflowBottom = isAllowBottom\n apply(REASON.resize)\n }\n\n function getState() {\n return painted ?? 'off'\n }\n\n function getModel() {\n return model\n }\n\n const unsubscribe = view.subscribe({\n scroll: onScroll,\n resize: onResize,\n })\n\n function destroy() {\n if (isStopped) {\n return\n }\n\n isStopped = true\n unsubscribe()\n view.destroy()\n }\n\n apply(session.locked ? REASON.lock : REASON.resize)\n\n return {\n update,\n setLocked,\n setDisabled,\n setClasses,\n setAllowLockedOverflow,\n destroy,\n getState,\n getModel,\n }\n}\n"],"mappings":"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"}
|