View useScrollPos.ts
This file contains 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 }); |
View CSS.tsx
This file contains 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'; |
View MyApp.jsx
This file contains 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> |
View app.js
This file contains 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> |
View appState.js
This file contains 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', |
View useGlobalState.js
This file contains 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); |
View GlobalState.js
This file contains 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(); | |
} |
View swipeDetection.js
This file contains 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; |
View ResizeObserver.ts
This file contains 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; |
View useResizeObserver.js
This file contains 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 => { |