Skip to content

Instantly share code, notes, and snippets.

@berkaytheunicorn
Last active June 22, 2020 10:43
Show Gist options
  • Save berkaytheunicorn/5a1e58520e020183bd26aaa9ea0dc3e5 to your computer and use it in GitHub Desktop.
Save berkaytheunicorn/5a1e58520e020183bd26aaa9ea0dc3e5 to your computer and use it in GitHub Desktop.
import React from "react";
import { useIntersect } from "../../../utils/hooks/useIntersect";
import { useUI } from "../../_UI";
import { BoxWrapper, LineOverlay } from "./styled";
export default props => {
const { style, children, $appearance } = props;
const ui = useUI(props, [
"onClick",
"$transparent",
"$direction",
"$sticky",
"$align",
"$liquid",
"$liquidWidth",
"$grow",
"$shrink",
"$clearfix",
"$overflow",
"$spacingTolerance",
"image"
]);
if (props.$sticky) {
const [ref, entry] = useIntersect({
threshold: [1]
});
return (
<BoxWrapper
ref={ref}
stuck={entry.intersectionRatio < 1}
style={style}
{...ui.props}
>
{$appearance == "line" && <LineOverlay {...ui.props} />}
{children}
</BoxWrapper>
);
}
return (
<BoxWrapper style={style} {...ui.props}>
{$appearance == "line" && <LineOverlay {...ui.props} />}
{children}
</BoxWrapper>
);
};
export const isIntersectionObserverSupported = () => {
if (typeof window !== "undefined") {
if (
!"IntersectionObserver" in window &&
!"IntersectionObserverEntry" in window &&
!"intersectionRatio" in window.IntersectionObserverEntry.prototype
) {
return false;
}
return true;
}
return false;
};
import styled, { css } from "styled-components";
import {
debug,
alignment,
gutter,
radius,
paint,
border,
clearfix
} from "../../../../utils/mixins";
import { UI } from "../../../../constants";
const { cond, or } = UI;
const { _ } = UI.scoped("primitives");
export const LineOverlay = styled.div`
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 2px solid ${_`palette.contrast.main`};
${radius()};
`;
export const BoxWrapper = styled.div`
${paint({ bg: 1, fg: 1, interaction: "bg" })};
${alignment()};
${gutter({ type: "margin" })};
${gutter({ type: "padding" })};
${radius()};
${border()};
${clearfix({ useProps: true })};
cursor: ${cond({ if: "props.onClick", then: "pointer" })};
width: ${cond({
if: or("props.$liquid", "props.$liquidWidth"),
then: "100%"
})};
height: ${cond({ if: "props.$liquid", then: "100%", else: "auto" })};
background-image: ${cond({
if: "props.image",
then: `url(${_`props.image`})`
})};
background-size: cover;
background-repeat: no-repeat;
background-position: center;
overflow: ${_`props.$overflow`};
position: relative;
${p =>
p.$sticky &&
css`
position: -webkit-sticky;
position: sticky;
z-index: 98;
top: ${p.$sticky == "top" ? "-1px" : null};
bottom: ${p.$sticky == "bottom" ? "-1px" : null};
margin-top: ${p.$sticky == "top" ? "1px" : null};
margin-bottom: ${p.$sticky == "bottom" ? "1px" : null};
${p =>
p.stuck &&
p.$sticky == "bottom" &&
css`
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
`}
${p =>
p.stuck &&
p.$sticky == "top" &&
css`
border-top-left-radius: 0px;
border-top-right-radius: 0px;
`}
`};
& > div > svg > * {
fill: ${_`palette.contrast.main`};
}
${debug({ useProps: 1 })};
`;
import { useEffect, useRef, useState } from "react";
import { isIntersectionObserverSupported } from "../browser/isSupported";
export const useIntersect = ({ root = null, rootMargin, threshold = 0 }) => {
const [entry, updateEntry] = useState({});
const [node, setNode] = useState(null);
if (isIntersectionObserverSupported()) {
const observer = useRef(
new window.IntersectionObserver(([entry]) => updateEntry(entry), {
root,
rootMargin,
threshold,
}),
);
useEffect(() => {
const { current: currentObserver } = observer;
currentObserver.disconnect();
if (node) currentObserver.observe(node);
return () => currentObserver.disconnect();
}, [node]);
}
return [setNode, entry];
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment