UNPKG

@fastkit/vue-scroller

Version:

A library for controlling the scrolling state of elements and components in Vue applications.

326 lines (324 loc) 8.22 kB
import { Scroller } from '@fastkit/scroller'; export * from '@fastkit/scroller'; import { defineComponent, computed, createVNode, ref, onMounted, onBeforeUnmount, reactive } from 'vue'; import { defineTypedComponent } from '@fastkit/vue-utils'; var INITIAL_VALUE = null; var OBSERVER_READONLY_PROPS = [ "containerHeight", "containerWidth", "isDestroyed", "isPending", "isReady", "isRunning", "lastAxis", "lastDirection", "lastXDirection", "lastYDirection", "nowScrolling", "scrollEnabled", "scrollHeight", "scrollWidth", "scrollableX", "scrollableY", "state" ]; var OBSERVER_WRITABLE_PROPS = [ "scrollBottom", "scrollLeft", "scrollRight", "scrollTop" ]; var OBSERVER_PROPS = [...OBSERVER_READONLY_PROPS, ...OBSERVER_WRITABLE_PROPS]; function createDefaultState() { return reactive( Object.fromEntries(OBSERVER_PROPS.map((prop) => [prop, INITIAL_VALUE])) ); } function useScrollerControl(setting) { const isSelf = setting.el === "self"; const $target = isSelf ? null : void 0; const state = createDefaultState(); const elementRef = ref(null); const scroller = new Scroller({ ...setting, el: $target }); scroller.observe(state); const _scroller = { get elementRef() { return elementRef; }, get scroller() { return scroller; }, get containerHeight() { return state.containerHeight; }, get containerWidth() { return state.containerWidth; }, get isDestroyed() { return state.isDestroyed; }, get isPending() { return state.isPending; }, get isReady() { return state.isReady; }, get isRunning() { return state.isRunning; }, get lastAxis() { return state.lastAxis; }, get lastDirection() { return state.lastDirection; }, get lastXDirection() { return state.lastXDirection; }, get lastYDirection() { return state.lastYDirection; }, get nowScrolling() { return state.nowScrolling; }, get scrollEnabled() { return state.scrollEnabled; }, get scrollHeight() { return state.scrollHeight; }, get scrollWidth() { return state.scrollWidth; }, get scrollableX() { return state.scrollableX; }, get scrollableY() { return state.scrollableY; }, get state() { return state.state; }, get scrollBottom() { return state.scrollBottom; }, set scrollBottom(scrollBottom) { state.scrollBottom = scrollBottom; }, get scrollLeft() { return state.scrollLeft; }, set scrollLeft(scrollLeft) { state.scrollLeft = scrollLeft; }, get scrollRight() { return state.scrollRight; }, set scrollRight(scrollRight) { state.scrollRight = scrollRight; }, get scrollTop() { return state.scrollTop; }, set scrollTop(scrollTop) { state.scrollTop = scrollTop; }, ready() { return scroller.ready(); }, element() { return elementRef.value; }, start() { return scroller.start(); }, stop() { return scroller.stop(); }, destroy() { return scroller.destroy(); }, update() { return scroller.update(); }, toJSON() { return scroller.toJSON(); }, toString() { return scroller.toString(); }, cancel() { return scroller.cancel(); }, by(diffX, diffY, options) { return scroller.by(diffX, diffY, options); }, to(scrollPosition, options) { return scroller.to(scrollPosition, options); }, toElement(target, options) { return scroller.toElement(target, options); }, toSide(targets, options) { return scroller.toSide(targets, options); }, toTop(options) { return scroller.toTop(options); }, toRight(options) { return scroller.toRight(options); }, toBottom(options) { return scroller.toBottom(options); }, toLeft(options) { return scroller.toLeft(options); }, toLeftTop(options) { return scroller.toLeftTop(options); }, toLeftBottom(options) { return scroller.toLeftBottom(options); }, toRightTop(options) { return scroller.toRightTop(options); }, toRightBottom(options) { return scroller.toRightBottom(options); }, pushScrollStopper(stopper) { return scroller.pushScrollStopper(stopper); }, removeScrollStopper(stopper) { return scroller.removeScrollStopper(stopper); }, setScrollToElementAdditionalOffset(offset) { return scroller.setScrollToElementAdditionalOffset(offset); }, deleteScrollToElementAdditionalOffset() { return scroller.deleteScrollToElementAdditionalOffset(); } }; if (isSelf) { onMounted(() => { let el = elementRef.value; if (!el) return; if (!(el instanceof Element)) { el = el.$el; } if (!(el instanceof Element)) return; scroller.setElement(el); }); onBeforeUnmount(() => { _scroller.destroy(); }); } return _scroller; } var _documentScroller; function getDocumentScroller() { if (!_documentScroller) { _documentScroller = useScrollerControl({ el: "body" }); } return _documentScroller; } var DEFAULT_GUIDE_OFFSET = 20; var GuideTypes = ["top", "right", "bottom", "left"]; var scrollerProps = { settings: { type: Object, default: null }, /** * スクロール可能な辺にガイドとして影を表示する場合に設定する */ guide: [Boolean, Number], /** * スクロールするコンテナ要素のクラス名 */ containerClass: String }; var _ScrollerI = defineComponent({ name: "VScroller", props: scrollerProps, setup(props, ctx) { const settings = props.settings || {}; const scroller = useScrollerControl({ ...settings, el: settings.el || "self" }); const guideOffsetRef = computed(() => { const { guide } = props; if (typeof guide === "number") return guide; if (guide === true) return DEFAULT_GUIDE_OFFSET; return void 0; }); const scrollability = computed(() => { const guideOffset = guideOffsetRef.value || DEFAULT_GUIDE_OFFSET; const { scrollLeft, scrollTop, scrollRight, scrollBottom } = scroller; return { left: scrollLeft >= guideOffset, right: scrollRight >= guideOffset, top: scrollTop >= guideOffset, bottom: scrollBottom >= guideOffset, strict: { left: scrollLeft > 0, right: scrollRight > 0, top: scrollTop > 0, bottom: scrollBottom > 0 } }; }); const scrollerRef = { scroller, get scrollable() { return scrollability.value; } }; const guidesRef = computed(() => { const guideOffset = guideOffsetRef.value; if (guideOffset === void 0) return; const guides = []; const scrollable = scrollability.value; scrollable.left && guides.push("left"); scrollable.top && guides.push("top"); scrollable.right && guides.push("right"); scrollable.bottom && guides.push("bottom"); return guides; }); ctx.expose(scrollerRef); return () => { const guides = guidesRef.value; const { containerClass } = props; const $guides = guides && GuideTypes.map((type) => createVNode("div", { "class": ["v-scroller__guide", { [`v-scroller__guide--${type}`]: true, [`v-scroller__guide--active`]: guides.includes(type) }], "key": type }, null)); return createVNode("div", { "class": "v-scroller" }, [createVNode("div", { "class": ["v-scroller__container", containerClass], "ref": scroller.elementRef }, [ctx.slots.default?.()]), $guides]); }; } }); var VScroller = defineTypedComponent(_ScrollerI).$expose(); export { VScroller, _ScrollerI, getDocumentScroller, scrollerProps, useScrollerControl }; //# sourceMappingURL=vue-scroller.mjs.map //# sourceMappingURL=vue-scroller.mjs.map