indicate
Version:
Scroll indicator for elements with scrollable overflow.
1,111 lines (1,099 loc) • 34.3 kB
JavaScript
// theme/default.ts
var defaultTheme = {
indicator: (_, options, direction) => ({
background: `linear-gradient(to ${direction}, rgba(255, 255, 255, 0), ${options.color})`,
// Initially not visible.
opacity: "0",
display: "flex"
}),
hide: (indicator) => {
indicator.style.opacity = "0";
indicator.style.pointerEvents = "none";
if (!indicator.style.transition) {
indicator.style.transition = "opacity 300ms linear";
}
},
show: (indicator) => {
indicator.style.opacity = "1";
indicator.style.pointerEvents = "auto";
}
};
// helper.ts
var log = (messageKey, objects = null) => {
if (process.env.NODE_ENV !== "production") {
const Messages = {
IntersectionObserver: "Browser doesn't support IntersectionObserver",
ExistingInstance: "An instance for this element already exists",
RemoveNoInstance: "remove() no instance found for element",
InvalidElement: "Initialized failed due to invalid element",
InvalidTheme: "Invalid value provided to theme option",
ReactMultipleChildren: "When using React with childAsElement option there can only be a single child node at the top, falling back to adding a wrapper element",
ReactMissingRef: "When using React with childAsElement option a ref to the child node is required, falling back to adding a wrapper element",
ReactFragmentRef: "Cannot use a Fragment in conjunction with childAsElement"
};
const prefixedMessage = `indicate: ${Messages[messageKey]}.`;
if (objects) {
console.warn(prefixedMessage, objects);
} else {
console.warn(prefixedMessage);
}
}
};
var isInline = (element) => {
const computedStyleDisplay = window.getComputedStyle(element).getPropertyValue("display");
if (computedStyleDisplay.startsWith("inline")) {
return computedStyleDisplay;
}
return false;
};
var isTable = (element) => element.tagName.toLowerCase() === "table";
var hideScrollbarClass = "hide-indicate-scrollbar";
var hideScrollbarStyleSheet;
var hideScrollbarWithWebkitPseudoClass = (element) => {
element.classList.add(hideScrollbarClass);
if (hideScrollbarStyleSheet) {
return;
}
hideScrollbarStyleSheet = document.createElement("style");
const { sheet } = document.head.appendChild(hideScrollbarStyleSheet);
sheet.insertRule(`.${hideScrollbarClass}::-webkit-scrollbar { display: none; }`);
};
var removeHideScrollbarStyle = (element, innerWrapper) => {
element.classList.remove(hideScrollbarClass);
innerWrapper.classList.remove(hideScrollbarClass);
if (!hideScrollbarStyleSheet || document.querySelector(`.${hideScrollbarClass}`)) {
return;
}
hideScrollbarStyleSheet.remove();
hideScrollbarStyleSheet = void 0;
};
var wrapElementIn = (element, wrapper) => {
element.parentNode.insertBefore(wrapper, element);
wrapper.append(element);
};
var createSvgLine = (x1, y1, x2, y2, rounded) => {
const line = document.createElementNS("http://www.w3.org/2000/svg", "line");
if (rounded) {
line.setAttribute("stroke-linecap", "round");
}
line.setAttribute("stroke-width", "20");
line.setAttribute("x1", x1);
line.setAttribute("y1", y1);
line.setAttribute("x2", x2);
line.setAttribute("y2", y2);
return line;
};
var arrowIcon = (icon, color) => {
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("viewBox", "0 0 120 120");
svg.setAttribute("stroke", color);
if (icon === "arrow-rounded") {
svg.appendChild(createSvgLine("10", "60", "110", "60", true));
svg.appendChild(createSvgLine("108.213", "57.3553", "61.5442", "10.6863", true));
svg.appendChild(createSvgLine("61.5442", "109.213", "108.213", "62.5442", true));
} else if (icon === "pointer-rounded") {
svg.appendChild(createSvgLine("43.1421", "11", "91.2254", "59.0833", true));
svg.appendChild(createSvgLine("91.2254", "60.1421", "43.1421", "108.225", true));
} else if (icon === "arrow") {
svg.appendChild(createSvgLine("0", "60", "120", "60"));
svg.appendChild(createSvgLine("62.9289", "112.929", "113.284", "62.5736"));
svg.appendChild(createSvgLine("113.284", "57.4264", "62.929", "7.07109"));
} else {
svg.appendChild(createSvgLine("37.0711", "6.92893", "96.8923", "66.7502"));
svg.appendChild(createSvgLine("96.468", "53.0711", "37.0711", "112.468"));
}
return svg;
};
// options.ts
var defaultOptions = {
arrow: {
position: "center",
icon: "arrow-rounded",
color: "#000000"
},
color: "#FFFFFF",
width: "20px",
click: {
denominator: 2
},
hideScrollbar: true,
moveStylesToWrapper: false
};
var getOptions = (options = {}) => {
const shallowMerge = {
...defaultOptions,
...options
};
if (typeof shallowMerge.arrow === "object") {
shallowMerge.arrow = {
...defaultOptions.arrow,
...shallowMerge.arrow
};
}
if (typeof shallowMerge.click === "object") {
shallowMerge.click = {
...defaultOptions.click,
...shallowMerge.click
};
}
if (shallowMerge.arrow === true) {
shallowMerge.arrow = defaultOptions.arrow;
}
if (shallowMerge.click === true) {
shallowMerge.click = defaultOptions.click;
}
if (shallowMerge.theme && typeof shallowMerge.theme !== "object") {
log("InvalidTheme", { theme: shallowMerge.theme });
delete shallowMerge.theme;
} else if (!shallowMerge.theme) {
shallowMerge.theme = defaultTheme;
}
return shallowMerge;
};
// types.ts
var Direction = /* @__PURE__ */ ((Direction3) => {
Direction3["left"] = "left";
Direction3["right"] = "right";
Direction3["top"] = "top";
Direction3["bottom"] = "bottom";
return Direction3;
})(Direction || {});
var directions = [
"left" /* left */,
"right" /* right */,
"top" /* top */,
"bottom" /* bottom */
];
var isHorizontal = (direction) => direction === "left" /* left */ || direction === "right" /* right */;
var isVertical = (direction) => direction === "top" /* top */ || direction === "bottom" /* bottom */;
// style.ts
var directionToRotation = {
["left" /* left */]: 180,
["right" /* right */]: 0,
["top" /* top */]: 270,
["bottom" /* bottom */]: 90
};
var add = (element, properties) => {
Object.keys(properties).forEach((property) => {
element.style[property] = properties[property];
});
};
var alignment = (direction, options, observer = false) => {
const style = {};
const horizontal = isHorizontal(direction);
const vertical = isVertical(direction);
if (horizontal) {
style.top = "0";
}
if (vertical) {
style.left = "0";
}
const size = observer ? "1px" : options.width;
style.width = horizontal ? size : "100%";
style.height = vertical ? size : "100%";
return style;
};
var base = {
indicator: (_, options, direction) => {
const style = {
position: "absolute",
// Initially hidden.
display: "none",
cursor: options.click ? "pointer" : "inherit",
[direction]: "0"
};
if (isHorizontal(direction)) {
style.alignItems = options.arrow && options.arrow.position !== "center" ? `flex-${options.arrow.position}` : "center";
style.justifyContent = "center";
} else {
style.justifyContent = options.arrow && options.arrow.position !== "center" ? `flex-${options.arrow.position}` : "center";
style.alignItems = "center";
}
return { ...style, ...alignment(direction, options) };
},
hide: (indicator) => {
indicator.style.display = "none";
},
show: (indicator) => {
indicator.style.display = "flex";
},
arrow: (_, __, direction) => ({
width: "12px",
height: "12px",
display: "block",
transform: `rotate(${directionToRotation[direction]}deg)`
}),
outerWrapper: (_, __, ___, inline) => {
const styles = { position: "relative" };
if (inline) {
styles.display = inline === "inline" ? "inline-block" : inline;
}
return styles;
},
element: (element, _, table, inline) => {
const styles = {};
if (inline) {
styles.display = inline === "inline" ? "inline-block" : inline;
styles.verticalAlign = "top";
}
if (!table && element.style.overflow !== "scroll") {
styles.overflow = "auto";
}
if (table) {
styles.position = "relative";
styles.display = "inline-block";
styles.verticalAlign = "top";
}
return styles;
},
innerWrapper: (element, _, table) => {
const styles = {
position: "relative",
display: "inline-flex",
// Avoid small bottom space otherwise added by inline-.
verticalAlign: "top"
};
if (table && element && element.style.overflow !== "scroll") {
styles.overflow = "auto";
}
return styles;
},
observer: (_, options, direction) => ({
position: "absolute",
pointerEvents: "none",
[direction]: "0",
...alignment(direction, options, true)
})
};
var apply = (method, ...args) => {
if (typeof method === "object") {
return method;
}
const result = method(...args);
if (typeof result === "object") {
return result;
}
return void 0;
};
var applyBaseTheme = (key, element, options, args) => {
if (["show", "hide"].includes(key) && options.theme[key]) {
return {};
}
return apply(base[key], element, options, ...args);
};
var theme = (element, key, options, ...args) => {
let userProperties;
if (options.theme && options.theme[key]) {
userProperties = apply(options.theme[key], element, options, ...args);
}
let baseProperties = applyBaseTheme(key, element, options, args);
if (typeof options.inlineStyles === "object" && typeof options.inlineStyles[key] === "object") {
baseProperties = { ...baseProperties, ...options.inlineStyles[key] };
}
const styles = userProperties ? { ...baseProperties, ...userProperties } : baseProperties;
if (styles && Object.keys(styles).length) {
add(element, styles);
}
};
var hideScrollbar = (element) => {
add(element, {
// Hide scrollbar in IE and Edge.
// @ts-ignore
"-ms-overflow-style": "none",
// Hide scrollbar in Firefox.
"scrollbar-width": "none"
});
};
// feature/click.ts
var scrollHorizontal = (direction, element, denominator) => {
const position = element.scrollLeft;
let scrollOffset = element.offsetWidth / denominator;
if (direction === "left" /* left */) {
scrollOffset = -scrollOffset;
}
element.scrollTo({
left: position + scrollOffset,
behavior: "smooth"
});
};
var scrollVertical = (direction, element, denominator) => {
const position = element.scrollTop;
let scrollOffset = element.offsetHeight / denominator;
if (direction === "top" /* top */) {
scrollOffset = -scrollOffset;
}
element.scrollTo({
top: position + scrollOffset,
behavior: "smooth"
});
};
var handleIndicatorClick = (direction, element, denominator) => {
if (isHorizontal(direction)) {
scrollHorizontal(direction, element, denominator);
} else {
scrollVertical(direction, element, denominator);
}
};
var registerClickListener = (direction, element, instance) => {
if (!instance.options.click) {
return;
}
const { denominator } = instance.options.click;
const scrollableElement = instance.table ? instance.innerWrapper : instance.element;
if (instance.options.click) {
element.addEventListener(
"click",
handleIndicatorClick.bind(null, direction, scrollableElement, denominator)
);
}
};
// feature/table.ts
var wrapTable = ({ element, options }) => {
const outerWrapper = options.outerWrapper ?? document.createElement("div");
theme(outerWrapper, "outerWrapper", options, true, false);
if (!options.outerWrapper) {
wrapElementIn(element, outerWrapper);
}
const innerWrapper = options.innerWrapper ?? document.createElement("div");
theme(innerWrapper, "innerWrapper", options, true, false);
innerWrapper.style.overflow = "auto";
innerWrapper.style.display = "";
if (!options.innerWrapper) {
wrapElementIn(element, innerWrapper);
}
return { outerWrapper, innerWrapper };
};
// feature/move-styles.ts
var move = (element, wrapper, options) => {
if (!options.moveStylesToWrapper) {
return;
}
wrapper.className += ` ${element.className}`;
element.className = "";
wrapper.style.cssText += element.style.cssText;
element.style.cssText = null;
};
var undoMove = (element, wrapper, instance) => {
if (!instance.options.moveStylesToWrapper) {
return;
}
if (instance.table && wrapper.style.position === "relative") {
wrapper.style.position = "";
}
element.className += ` ${wrapper.className}`;
element.style.cssText += wrapper.style.cssText;
};
// element.ts
var wrapContentsWith = (element, wrapper) => {
wrapper.innerHTML = element.innerHTML;
element.innerHTML = "";
element.appendChild(wrapper);
};
var wrap = ({
element,
options,
table,
inline
}) => {
if (table) {
return wrapTable({ element, options });
}
const outerWrapper = options.outerWrapper ?? document.createElement("div");
theme(outerWrapper, "outerWrapper", options, table, inline);
if (!options.outerWrapper) {
wrapElementIn(element, outerWrapper);
}
const innerWrapper = options.innerWrapper ?? document.createElement("div");
theme(innerWrapper, "innerWrapper", options, table, inline);
if (!options.innerWrapper) {
wrapContentsWith(element, innerWrapper);
}
return { outerWrapper, innerWrapper };
};
var createInstance = (element, options) => {
const table = isTable(element);
const inline = isInline(element);
const getSpansByDirection = () => {
const result = {};
directions.forEach((direction) => {
result[direction] = document.createElement("span");
});
return result;
};
const { outerWrapper, innerWrapper } = wrap({
element,
options,
table,
inline
});
move(element, outerWrapper, options);
theme(element, "element", options, table, inline);
if (options.hideScrollbar) {
const scrollableElement = table ? innerWrapper : element;
hideScrollbar(scrollableElement);
hideScrollbarWithWebkitPseudoClass(scrollableElement);
}
return {
outerWrapper,
innerWrapper,
element,
indicator: getSpansByDirection(),
observer: getSpansByDirection(),
options,
table,
inline
};
};
var addArrow = (instance, indicator, direction) => {
const options = instance.options.arrow;
if (!options) {
return;
}
let arrow = null;
if (options.image) {
arrow = document.createElement("img");
arrow.src = options.image;
arrow.alt = `indicate arrow ${direction}`;
} else if (options.markup && options.markup !== "") {
if (typeof options.markup === "string") {
arrow = document.createElement("span");
arrow.innerHTML = options.markup;
} else {
arrow = options.markup;
}
} else {
arrow = arrowIcon(options.icon, options.color);
}
theme(arrow, "arrow", instance.options, direction);
indicator.append(arrow);
};
var addIndicators = (instance) => {
directions.forEach((direction) => {
const indicator = instance.indicator[direction];
theme(indicator, "indicator", instance.options, direction);
instance.outerWrapper.append(indicator);
registerClickListener(direction, indicator, instance);
addArrow(instance, indicator, direction);
});
};
var addObservers = (instance) => {
directions.forEach((direction) => {
const observer = instance.observer[direction];
theme(observer, "observer", instance.options, direction);
if (instance.table) {
instance.element.append(observer);
} else {
instance.innerWrapper.append(observer);
}
});
};
// observer.ts
var handleObservation = (instance, entries) => {
const visibilities = [];
entries.forEach(
(entry) => directions.forEach((direction) => {
const isMatch = entry.target === instance.observer[direction];
if (isMatch) {
visibilities.push({ direction, visible: entry.isIntersecting });
}
})
);
visibilities.forEach((visibility) => {
if (visibility.visible) {
theme(instance.indicator[visibility.direction], "hide", instance.options);
} else {
theme(instance.indicator[visibility.direction], "show", instance.options);
}
});
};
var observe = (instance) => {
const observer = new IntersectionObserver(handleObservation.bind(null, instance), {
root: instance.table ? instance.innerWrapper : instance.element,
// Only parts of element inside the root element are counted.
rootMargin: "0px",
// Even if only 10% of the observer is visible, trigger handler.
threshold: 0.1
});
instance.intersectionObserver = observer;
directions.forEach((direction) => observer.observe(instance.observer[direction]));
};
// instance.ts
var instances = /* @__PURE__ */ new Map();
var wrappers = /* @__PURE__ */ new Map();
var getDOMNodes = (element) => {
if (typeof element === "string") {
const elements = document.querySelectorAll(element);
if (elements.length) {
return elements;
}
}
if (element instanceof NodeList && element.length) {
return element;
}
if (element instanceof HTMLElement && element.isConnected) {
return [element];
}
log("InvalidElement", { element });
return false;
};
var hasExistingInstance = (options, element) => {
let found = false;
if (instances.get(element)) {
found = true;
}
if (options.moveStylesToWrapper && !found && element.childNodes.length > 0 && instances.get(element.childNodes[0])) {
found = true;
}
if (found) {
log("ExistingInstance", { element });
}
return found;
};
var initialize = (options, element) => {
if (hasExistingInstance(options, element)) {
return;
}
const instance = createInstance(element, options);
addIndicators(instance);
addObservers(instance);
instances.set(element, instance);
wrappers.set(instance.outerWrapper, instance);
observe(instance);
};
var indicate = (element, options) => {
const elements = getDOMNodes(element);
const instanceOptions = getOptions(options);
if (!elements) {
return;
}
if (!IntersectionObserver) {
log("IntersectionObserver");
return;
}
elements.forEach(initialize.bind(null, instanceOptions));
};
var remove = (element) => {
const elements = getDOMNodes(element);
if (!elements) {
return;
}
elements.forEach((currentElement) => {
const instance = instances.get(currentElement) || wrappers.get(currentElement);
if (!instance) {
log("RemoveNoInstance", { element: currentElement });
return;
}
directions.forEach((direction) => {
instance.indicator[direction].remove();
instance.observer[direction].remove();
});
instance.intersectionObserver.disconnect();
removeHideScrollbarStyle(instance.element, instance.innerWrapper);
undoMove(instance.element, instance.outerWrapper, instance);
if (!instance.options.outerWrapper) {
instance.outerWrapper.replaceWith(...Array.from(instance.outerWrapper.childNodes));
}
if (!instance.options.innerWrapper) {
if (instance.table) {
instance.innerWrapper.replaceWith(...Array.from(instance.innerWrapper.childNodes));
} else {
const contents = instance.innerWrapper.innerHTML;
instance.innerWrapper.remove();
currentElement.innerHTML = contents;
}
}
instances.delete(currentElement);
wrappers.delete(currentElement);
});
};
// react.tsx
import {
useEffect,
useRef,
createElement,
cloneElement,
Children,
forwardRef,
useCallback,
useState
} from "react";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
var initialVisibility = (horizontal, vertical) => ({
["top" /* top */]: false,
["right" /* right */]: !vertical,
["bottom" /* bottom */]: !horizontal,
["left" /* left */]: false
});
var childrenValid = (children, childRef) => {
let valid = true;
if (Children.count(children) !== 1) {
log("ReactMultipleChildren", { children });
valid = false;
}
if (valid && Children.toArray(children)[0].type.toString() === Symbol("react.fragment").toString()) {
log("ReactFragmentRef", { children });
valid = false;
}
if (!childRef) {
log("ReactMissingRef");
valid = false;
}
return valid;
};
var hideScrollbarClass2 = "hide-indicate-scrollbar";
var getClassName = (className, hideScrollbar2) => {
if (className === "undefined") {
className = void 0;
}
if (!className && !hideScrollbar2) {
return void 0;
}
return [className, hideScrollbar2 && hideScrollbarClass2].filter(Boolean).join(" ");
};
var defaultArrowProps = {
position: "center",
icon: "arrow-rounded",
color: "#000000"
};
var directionToRotation2 = {
["left" /* left */]: 180,
["right" /* right */]: 0,
["top" /* top */]: 270,
["bottom" /* bottom */]: 90
};
function Arrow({
icon,
color,
markup,
image,
direction,
theme: theme2
}) {
const style = {
width: 12,
height: 12,
display: "block",
transform: `rotate(${directionToRotation2[direction]}deg)`,
...theme2.arrow
};
if (image) {
return /* @__PURE__ */ jsx("img", { style, src: image, alt: `indicate arrow ${direction}` });
}
if (markup) {
return /* @__PURE__ */ jsx("span", { style, children: markup });
}
if (icon === "arrow-rounded") {
return /* @__PURE__ */ jsxs("svg", { style, viewBox: "0 0 120 120", stroke: color, children: [
/* @__PURE__ */ jsx("line", { strokeWidth: 20, strokeLinecap: "round", x1: "10", y1: "60", x2: "110", y2: "60" }),
/* @__PURE__ */ jsx(
"line",
{
strokeWidth: 20,
strokeLinecap: "round",
x1: "108.213",
y1: "57.3553",
x2: "61.5442",
y2: "10.6863"
}
),
/* @__PURE__ */ jsx(
"line",
{
strokeWidth: 20,
strokeLinecap: "round",
x1: "61.5442",
y1: "109.213",
x2: "108.213",
y2: "62.5442"
}
)
] });
}
if (icon === "pointer-rounded") {
return /* @__PURE__ */ jsxs("svg", { style, viewBox: "0 0 120 120", stroke: color, children: [
/* @__PURE__ */ jsx(
"line",
{
strokeWidth: 20,
strokeLinecap: "round",
x1: "43.1421",
y1: "11",
x2: "91.2254",
y2: "59.0833"
}
),
/* @__PURE__ */ jsx(
"line",
{
strokeWidth: 20,
strokeLinecap: "round",
x1: "91.2254",
y1: "60.1421",
x2: "43.1421",
y2: "108.225"
}
)
] });
}
if (icon === "arrow") {
return /* @__PURE__ */ jsxs("svg", { style, viewBox: "0 0 120 120", stroke: color, children: [
/* @__PURE__ */ jsx("line", { strokeWidth: 20, x1: "0", y1: "60", x2: "120", y2: "60" }),
/* @__PURE__ */ jsx("line", { strokeWidth: 20, x1: "62.9289", y1: "112.929", x2: "113.284", y2: "62.5736" }),
/* @__PURE__ */ jsx("line", { strokeWidth: 20, x1: "113.284", y1: "57.4264", x2: "62.929", y2: "7.07109" })
] });
}
return /* @__PURE__ */ jsxs("svg", { style, viewBox: "0 0 120 120", stroke: color, children: [
/* @__PURE__ */ jsx("line", { strokeWidth: 20, x1: "37.0711", y1: "6.92893", x2: "96.8923", y2: "66.7502" }),
/* @__PURE__ */ jsx("line", { strokeWidth: 20, x1: "96.468", y1: "53.0711", x2: "37.0711", y2: "112.468" })
] });
}
var getArrowPosition = (arrow) => {
const position = arrow.position ?? "center";
if (position === "center") {
return position;
}
return `flex-${position}`;
};
var getInline = (tag, display) => {
if (display && display.startsWith("inline")) {
return true;
}
return ["a", "code", "cite", "span", "strong", "b", "textarea"].includes(String(tag));
};
function Observers({
observersRef,
as: ObserverElementType = "span",
theme: theme2
}) {
return /* @__PURE__ */ jsx(Fragment, { children: directions.map((direction) => /* @__PURE__ */ jsx(
ObserverElementType,
{
ref: observersRef[direction],
style: {
position: "absolute",
top: isHorizontal(direction) ? "0" : "auto",
left: isVertical(direction) ? "0" : "auto",
[direction]: "0",
width: isVertical(direction) ? "100%" : 1,
height: isHorizontal(direction) ? "100%" : 1,
...theme2.observer
}
},
direction
)) });
}
function Indicators({
visibility,
click,
arrow,
indicatorsRef,
handleIndicatorClick: handleIndicatorClick2,
width,
color,
theme: theme2
}) {
return /* @__PURE__ */ jsx(Fragment, { children: directions.map((direction, index) => /* @__PURE__ */ jsx(
"span",
{
style: {
display: "flex",
opacity: visibility[direction] ? 1 : 0,
pointerEvents: visibility[direction] ? "auto" : "none",
background: `linear-gradient(to ${direction}, rgba(255, 255, 255, 0), ${color})`,
transition: "opacity 300ms linear",
position: "absolute",
cursor: click ? "pointer" : "inherit",
top: isHorizontal(direction) ? "0" : "auto",
left: isVertical(direction) ? "0" : "auto",
[direction]: "0",
alignItems: getArrowPosition(arrow),
justifyContent: getArrowPosition(arrow),
width: isHorizontal(direction) ? width : "100%",
height: isVertical(direction) ? width : "100%",
...theme2.indicator,
...visibility[direction] ? theme2.show && theme2.show(indicatorsRef[index]) : theme2.show && theme2.hide(indicatorsRef[index])
},
role: "button",
"aria-label": `Scroll ${direction}.`,
tabIndex: 0,
onKeyDown: () => {
},
ref: indicatorsRef[index],
onClick: click ? () => handleIndicatorClick2(direction) : null,
children: arrow && /* @__PURE__ */ jsx(Arrow, { ...defaultArrowProps, ...arrow, direction, theme: theme2 })
},
direction
)) });
}
var createDirectionRefsObject = () => directions.reduce((item, direction) => {
item[direction] = useRef();
return item;
}, {});
var Indicate = forwardRef(
({
as = "div",
children,
childAsElement,
horizontal = false,
vertical = false,
click = { scrollDenominator: 4 },
color = "#FFFFFF",
width = "20px",
style,
innerStyle,
outerStyle,
outerWrapperProps,
innerWrapperProps,
arrow = defaultArrowProps,
hideScrollbar: hideScrollbar2 = true,
className,
moveStylesToWrapper = false,
theme: theme2 = {},
...props
}, childRef) => {
const outerWrapperRef = useRef();
const elementRef = useRef();
const innerWrapperRef = useRef();
const indicatorsRef = useRef([]);
const isInline2 = getInline(as, style && style.display);
const observersRef = createDirectionRefsObject();
const [visibility, setVisibility] = useState(initialVisibility(horizontal, vertical));
const sharedVisibility = useRef(visibility);
let content = null;
const handleIndicatorClick2 = useCallback((direction) => {
const horizontalCurrent = isHorizontal(direction);
const position = horizontalCurrent ? elementRef.current.scrollLeft : elementRef.current.scrollTop;
const denominator = click.scrollDenominator;
let scrollOffset = (horizontalCurrent ? elementRef.current.offsetWidth : elementRef.current.offsetHeight) / denominator;
if (direction === "left" /* left */ || direction === "top" /* top */) {
scrollOffset = -scrollOffset;
}
elementRef.current.scrollTo({
[horizontalCurrent ? "left" /* left */ : "top" /* top */]: position + scrollOffset,
behavior: "smooth"
});
}, []);
if (arrow === true) {
arrow = defaultArrowProps;
}
const handleObservation2 = useCallback(
(entries) => {
const visibilities = [];
const newState = { ...sharedVisibility.current };
entries.forEach(
(entry) => directions.forEach((direction) => {
const isMatch = entry.target === observersRef[direction].current;
if (isMatch) {
visibilities.push({ direction, visible: entry.isIntersecting });
}
})
);
visibilities.forEach((currentVisibility) => {
if (currentVisibility.visible) {
newState[currentVisibility.direction] = false;
} else {
newState[currentVisibility.direction] = true;
}
});
if (newState.top !== sharedVisibility.current.top || newState.right !== sharedVisibility.current.right || newState.bottom !== sharedVisibility.current.bottom || newState.left !== sharedVisibility.current.left) {
sharedVisibility.current = newState;
setVisibility(newState);
}
},
[visibility, observersRef, sharedVisibility]
);
const observe2 = useCallback((element) => {
const observer = new IntersectionObserver(handleObservation2, {
root: element,
// Only parts of element inside the root element are counted.
rootMargin: "0px",
// Even if only 10% of the observer is visible, trigger handler.
threshold: 0.1
});
directions.forEach((direction) => {
observer.observe(observersRef[direction].current);
});
return () => observer.disconnect();
}, []);
useEffect(() => {
const element = elementRef?.current ?? childRef?.current;
const disconnectObserver = observe2(element);
return disconnectObserver;
}, []);
if (childAsElement && childrenValid(children, childRef)) {
const innerChildrenModifiable = Children.toArray(children.props.children);
innerChildrenModifiable.push(
/* @__PURE__ */ jsx(Observers, { observersRef, theme: theme2 }, "observers")
);
content = cloneElement(children, {
...props,
className,
children: createElement(
"div",
{
style: {
// Transferring styles from child to inner wrapper.
...!moveStylesToWrapper && children.props.style,
display: "inline-flex",
position: "relative",
verticalAlign: "top",
...innerStyle,
...theme2.innerWrapper
},
ref: innerWrapperRef,
...innerWrapperProps
},
innerChildrenModifiable
),
style: {
position: "relative",
overflow: "auto",
verticalAlign: "top",
...hideScrollbar2 && {
msOverflowStyle: "none",
scrollbarWidth: "none"
},
...style,
...theme2.element
}
});
} else if (as === "table") {
content = /* @__PURE__ */ jsx(
"div",
{
ref: elementRef,
style: {
position: "relative",
overflow: "auto",
verticalAlign: "top",
...style,
...theme2.element
},
children: /* @__PURE__ */ jsxs(
"table",
{
ref: innerWrapperRef,
style: {
display: "inline-block",
position: "relative",
verticalAlign: "top",
...innerStyle,
...theme2.innerWrapper
},
children: [
children,
/* @__PURE__ */ jsx(Observers, { as: "tbody", observersRef, theme: theme2 })
]
}
)
}
);
} else if (isInline2) {
content = /* @__PURE__ */ jsx(
"div",
{
ref: elementRef,
style: {
...style,
display: "inline-block",
overflow: "auto",
verticalAlign: "top",
...theme2.element
},
children: createElement(
as,
{
ref: innerWrapperRef,
style: {
position: "relative",
verticalAlign: "top",
display: "inline-flex",
...innerStyle,
...theme2.innerWrapper
}
},
/* @__PURE__ */ jsxs(Fragment, { children: [
children,
/* @__PURE__ */ jsx(Observers, { observersRef, theme: theme2 })
] })
)
}
);
} else {
content = createElement(
as,
{
ref: elementRef,
className: getClassName(className, hideScrollbar2),
style: {
overflow: "auto",
...hideScrollbar2 && {
msOverflowStyle: "none",
scrollbarWidth: "none"
},
...style,
...theme2.element
},
...props
},
/* @__PURE__ */ jsxs(
"div",
{
style: {
position: "relative",
display: "inline-flex",
verticalAlign: "top",
...innerStyle,
...theme2.innerWrapper
},
ref: innerWrapperRef,
...innerWrapperProps,
children: [
children,
/* @__PURE__ */ jsx(Observers, { observersRef, theme: theme2 })
]
}
)
);
}
return /* @__PURE__ */ jsxs(
"div",
{
style: {
...outerStyle,
position: "relative",
...isInline2 && { display: "inline-block" },
...theme2.outerWrapper,
...childAsElement && moveStylesToWrapper && children.props.style
},
ref: outerWrapperRef,
...outerWrapperProps,
children: [
hideScrollbar2 && /* @__PURE__ */ jsx("style", { children: `.${hideScrollbarClass2}::-webkit-scrollbar { display: none; }` }),
content,
/* @__PURE__ */ jsx(
Indicators,
{
visibility,
click,
arrow,
indicatorsRef,
handleIndicatorClick: handleIndicatorClick2,
width,
color,
theme: theme2
}
)
]
}
);
}
);
export {
Direction,
Indicate,
defaultOptions,
indicate,
remove
};
//# sourceMappingURL=index.js.map