This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { RefObject, useEffect, useState } from 'react'; | |
export interface ScrollPos { | |
top: number; | |
left: number; | |
} | |
export function useScrollPos(elRef: RefObject<HTMLElement>, disabled?: boolean): ScrollPos { | |
const [scrollPos, setScrollPos] = useState({ top: 0, left: 0 }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Why? | |
- Tiny compared to existing solutions | |
- No frills or stupid class hashing, just for portability of providing components with CSS included | |
- Discourage dynamism -> While the CSS will update if you pass in variables, `insertRule` is more | |
efficient for highly dynamic CSS. But highly dynamic CSS is a code smell. Conditional selectors and | |
CSS Variables can achieve most use cases whilst being far more performant. | |
*/ | |
import { useRef, useEffect } from 'react'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function MyApp({ theme }) { | |
const cssTheme = useMemo(() => makeCssTheme(theme, 'xx'), [theme]); | |
return ( | |
<div style={cssTheme}> | |
{/* | |
Any component in here now has access to: | |
var(--xx-buttonPadding), var(--xx-background) etc. | |
*/} | |
</div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default function App() { | |
const [theme, dispatch] = useGlobalState(appState, state => state.theme); | |
return ( | |
<div style={{ background: theme.background }}> | |
<button onClick={() => dispatch('toggleTheme')}>Toggle theme</button> | |
<p style={{ color: theme.text }}> | |
You're enjoying the {theme.name} theme | |
</p> | |
</div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const darkTheme = { | |
name: 'dark', | |
background: 'black', | |
text: 'white', | |
} | |
const lightTheme = { | |
name: 'light', | |
background: 'white', | |
text: 'black', |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function useGlobalState(globalState, stateGetter) { | |
const [state, setState] = useState(stateGetter(globalState.state)); | |
// We don't want to re-create the listener as we want to unlisten on unmount | |
// of the component which uses this hook, so we "tunnel" the state in. | |
const stateRef = useRef(state); | |
stateRef.current = state; | |
const listener = useRef(nextState => { | |
const stateUpdate = stateGetter(nextState); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class GlobalState { | |
state = {}; | |
listeners = []; | |
constructor(reducer, initialState = {}) { | |
this.reducer = reducer; | |
this.state = initialState; | |
this.devTools = typeof window !== 'undefined' && window?.__REDUX_DEVTOOLS_EXTENSION__?.connect(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let startX = 0; | |
let startY = 0; | |
function handleTouchStart(e) { | |
startX = e.changedTouches[0].screenX; | |
startY = e.changedTouches[0].screenY; | |
} | |
function handleTouchEnd(e) { | |
const diffX = e.changedTouches[0].screenX - startX; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
declare global { | |
interface DOMRectReadOnly { | |
readonly x: number; | |
readonly y: number; | |
readonly width: number; | |
readonly height: number; | |
readonly top: number; | |
readonly right: number; | |
readonly bottom: number; | |
readonly left: number; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useRef, useCallback, useEffect, useState } from 'react'; | |
import { ResizeObserver as ResizeObserverPolyfill } from '@juggle/resize-observer'; | |
const ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill; | |
export default function useResizeObserver() { | |
const [size, setSize] = useState({ width: 0, height: 0 }); | |
const resizeObserver = useRef(null); | |
const onResize = useCallback(entries => { |