@daniel-wrz/react-components-scrollbar
Version:
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
189 lines (184 loc) • 7.57 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
Scrollbar: () => scrollbar_default
});
module.exports = __toCommonJS(src_exports);
// src/components/scrollbar/scrollbar.tsx
var import_react = __toESM(require("react"), 1);
// src/components/scrollbar/scrollbar-logic.ts
var InitScrollbarAction = class {
content;
container;
constructor(content, container) {
this.container = container;
this.content = content;
}
};
var SetThumbDraggingAction = class {
dragging;
thumbPosition;
constructor(dragging, thumbPosition) {
this.dragging = dragging;
this.thumbPosition = thumbPosition;
}
};
var ScrollbarReducer = (state, action) => {
switch (action.constructor) {
case InitScrollbarAction: {
const data = action;
return {
...state,
thumbHeight: ScrollbarServices.setThumbHeight(data.content, data.container, 20),
scrollingFactor: ScrollbarServices.calculateScrollingFactor(data.content, data.container)
};
}
case SetThumbDraggingAction: {
const data = action;
return {
...state,
thumbIsDraging: data.dragging,
thumbPosition: data.thumbPosition
};
}
default:
return state;
}
};
var ScrollbarServices = {
calculateScrollingFactor: (content, container) => {
if (content && container) {
const { scrollHeight: contentTotalHeight } = content;
const { clientHeight: containerHeight } = container;
return contentTotalHeight / containerHeight;
}
return 0;
},
setThumbHeight: (content, container, minThum) => {
if (content && container) {
const { scrollHeight: contentTotalHeight } = content;
const { clientHeight: containerHeight } = container;
const value = containerHeight / contentTotalHeight * containerHeight;
if (value === containerHeight) return 0;
return Math.max(value, minThum);
}
return 0;
}
};
// src/components/scrollbar/scrollbar.tsx
var Scrollbar = ({ children }) => {
const containerRef = (0, import_react.useRef)(null);
const contentRef = (0, import_react.useRef)(null);
const thumbRef = (0, import_react.useRef)(null);
const trackRef = (0, import_react.useRef)(null);
const observer = (0, import_react.useRef)(null);
const [state, dispatch] = (0, import_react.useReducer)(ScrollbarReducer, { thumbHeight: 0, thumbIsDraging: false, scrollingFactor: 0 });
const calculateThumb = () => dispatch(new InitScrollbarAction(contentRef.current, containerRef.current));
const handleThumbMousedown = (e) => {
if (!state.thumbIsDraging && thumbRef.current) {
e.preventDefault();
e.stopPropagation();
const top = parseInt(thumbRef.current.style.top || "0", 10);
dispatch(new SetThumbDraggingAction(true, e.clientY - top));
}
};
const handleScrollingContent = (0, import_react.useCallback)(() => {
const container = containerRef.current;
const content = contentRef.current;
const thumb = thumbRef.current;
if (content && thumb && container) {
const { clientHeight: containerHeight } = container;
const { clientHeight: thumbHeight } = thumb;
const position = content.scrollTop / state.scrollingFactor;
const v = Math.min(position, containerHeight - thumbHeight);
thumb.style.top = `${v}px`;
}
}, [state.scrollingFactor]);
const stopScrolling = (0, import_react.useCallback)((e) => {
dispatch(new SetThumbDraggingAction(false, 0));
}, []);
const startDragingThumb = (0, import_react.useCallback)((e) => {
if (state.thumbIsDraging) {
e.preventDefault();
e.stopPropagation();
const content = contentRef.current;
const container = containerRef.current;
const thumb = thumbRef.current;
if (state.thumbIsDraging && thumb && content && container) {
const { clientHeight: containerHeight } = container;
const { clientHeight: thumbHeight } = thumb;
const delta = e.clientY - state.thumbPosition;
const v = Math.min(Math.max(delta, 0), containerHeight - thumbHeight);
content.scrollTop = v * state.scrollingFactor;
}
}
}, [state.thumbIsDraging]);
(0, import_react.useEffect)(() => {
var _a, _b;
if (contentRef.current) {
const content = contentRef.current;
observer.current = new ResizeObserver(() => {
calculateThumb();
});
observer.current.observe(content);
(_a = thumbRef.current) == null ? void 0 : _a.addEventListener("mousedown", handleThumbMousedown);
(_b = contentRef.current) == null ? void 0 : _b.addEventListener("scroll", handleScrollingContent);
return () => {
var _a2, _b2, _c;
(_a2 = observer.current) == null ? void 0 : _a2.unobserve(content);
(_b2 = thumbRef.current) == null ? void 0 : _b2.removeEventListener("mousedown", handleThumbMousedown);
(_c = contentRef.current) == null ? void 0 : _c.removeEventListener("scroll", handleScrollingContent);
};
}
}, [handleScrollingContent]);
(0, import_react.useEffect)(() => {
document.addEventListener("mouseup", stopScrolling);
document.addEventListener("mousemove", startDragingThumb);
return () => {
document.removeEventListener("mousemove", startDragingThumb);
document.removeEventListener("mouseup", stopScrolling);
};
}, [startDragingThumb, stopScrolling]);
return /* @__PURE__ */ import_react.default.createElement("div", { className: "s-container", ref: containerRef }, /* @__PURE__ */ import_react.default.createElement("div", { className: "s-content", ref: contentRef }, children), /* @__PURE__ */ import_react.default.createElement("div", { className: "s-scrollbar " + (state.thumbHeight === 0 ? "s-hide" : "") }, /* @__PURE__ */ import_react.default.createElement("div", { className: "s-track", ref: trackRef }, /* @__PURE__ */ import_react.default.createElement(
"div",
{
className: "s-thumb",
ref: thumbRef,
style: {
height: `${state.thumbHeight}px`
}
}
))));
};
var scrollbar_default = Scrollbar;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Scrollbar
});