From 96f158e6167e997a02e6a57f0b9395c47f0265fa Mon Sep 17 00:00:00 2001 From: Cody Olsen Date: Fri, 4 Dec 2020 00:46:22 +0100 Subject: [PATCH] fix: v2 api ready, just need to clean up and write docs --- README.md | 6 + TODO.md | 82 ------- defaults.json | 16 ++ docs/fixtures/Button.tsx | 19 +- docs/fixtures/Container.tsx | 17 +- docs/style.css | 7 +- package-lock.json | 6 + package.json | 3 +- pages/fixtures/experiments.tsx | 142 +++++++++-- pages/fixtures/scrollable.tsx | 18 +- postcss.config.js | 16 +- src/BottomSheet.tsx | 411 +++++++++++++------------------- src/hooks/index.tsx | 5 +- src/hooks/useAriaHider.tsx | 4 +- src/hooks/useDimensions.tsx | 73 ------ src/hooks/useFocusTrap.tsx | 4 +- src/hooks/useReady.tsx | 38 +++ src/hooks/useReducedMotion.tsx | 4 +- src/hooks/useScrollLock.tsx | 9 +- src/hooks/useSnapPoints.tsx | 264 ++++++++++++++++---- src/hooks/useSnapResponder.tsx | 110 +++++++++ src/hooks/useSpring.tsx | 8 + src/hooks/useViewportHeight.tsx | 37 --- src/index.tsx | 42 +++- src/style.css | 10 +- src/types.ts | 7 +- src/utils.ts | 18 ++ 27 files changed, 818 insertions(+), 558 deletions(-) delete mode 100644 TODO.md create mode 100644 defaults.json delete mode 100644 src/hooks/useDimensions.tsx create mode 100644 src/hooks/useReady.tsx create mode 100644 src/hooks/useSnapResponder.tsx create mode 100644 src/hooks/useSpring.tsx delete mode 100644 src/hooks/useViewportHeight.tsx diff --git a/README.md b/README.md index 1ee66b63..f6199325 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,9 @@ # Work in progress! Hold off using this until `v2` is out, or you're gonna have a _bad time_! + +# Credits + +- Play icon used on frame overlays: https://fontawesome.com/icons/play-circle?style=regular +- Phone frame used in logo: https://www.figma.com/community/file/896042888090872154/Mono-Devices-1.0 +- iPhone frame used to wrap examples: https://www.figma.com/community/file/858143367356468985/(Variants)-iOS-%26-iPadOS-14-UI-Kit-for-Figma diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 9cbcbbf9..00000000 --- a/TODO.md +++ /dev/null @@ -1,82 +0,0 @@ -Dragging, and transitions, need to be completely outside reacts render loop. -Stop relying on memo stuff. -If react's render loop triggers, communicate to outside fn's via refs and the like. -A change to snap points affects how far one can drag. - -fix uneven icon that is being animated, the corner is driving me crazy... - -# Remaining critical stuff - -- respond to viewport height changes -- respond to snapTo callback -- fire events when stopping the dragging and transition to snap. -- respond to changes to snapPoints output -- don't respond to changes to defaultSnap, it shouldn't act like controlled height. -- optimize element resize observers, perhaps run them all in a chain. - -## package.json stuffs - -- add description. -- add keywords. -- update readme. - -# Credits - -- Play icon: https://fontawesome.com/icons/play-circle?style=regular -- Phone frame used in logo: https://www.figma.com/community/file/896042888090872154/Mono-Devices-1.0 -- iPhone frame used to wrap examples: https://www.figma.com/community/file/858143367356468985/(Variants)-iOS-%26-iPadOS-14-UI-Kit-for-Figma - -# Ok let's map this nonsense - -Consider using a - -```js -const [, nextTick] = useState(0) -nextTick((_) => ++_) -``` - -to force updates. -Fast way to check if there's new snapPoints generated: - -```js -var arr1 = [1, 2, 3, 4, 5] -var arr2 = [1, 2, 3, 4, 5] - -if (JSON.stringify(arr1) === JSON.stringify(arr2)) { - console.log('They are equal!') -} -``` - -# useState bad, bad bad bad and useViewportHeight and useElementSizeObserver both use it - -Rewrite to refs, the nextTick system. Create an initial step for getting all dimensions. Then setup observers that set refs. - -Faux plugin architecture. "Plugins" or "hooks" can register in an es6 map if they want to do work before the animation starts, while the bottom sheet is resting in the final state but opacity: 0. This allows setting up focus lock, scroll lock and more ahead of time. Hopefully alleviating a lot of jank. - -a transition to close can be cancelled if the open state is changed back to `true`. -open/close is fairly easy and stabl. snap to snap on the other hand, require diligence in making sure whoever cancels a snap transition, makes sure to send the animation on the right direction. - -## Big picture state machines - -- transitioning from closed to open. -- transition to closed while opening but not open. -- transition to open while closing. -- transition to closed after finished opening. -- while opening the user interrupts and starts dragging (should be fine, all work should be done by now.). -- while opening the user keyboard navs, maybe even fucks the scroll. - -- Some hooks care only about if we're on our way to open, or on our way to close. -- Other hooks care about the current drag state. -- Dragging is king, should not be interruptible, but may allow side effects that affect where/how dragging happens. -- Except if the window changes height, maybe respond to header and footer height changes too by interrupting. -- Focus set by keyboard nav or a screen reader can fuck things up. -- Consider two drag modes? One fast, but can get scroll fuckups, one that's like the current one, safe because it changes the height property. - -tailwind rsbs - -- focus-visible -- motion-reduce -- blue gray shades on content below header - -important: -show inertia location to predict where sheet slides on release diff --git a/defaults.json b/defaults.json new file mode 100644 index 00000000..ff51a554 --- /dev/null +++ b/defaults.json @@ -0,0 +1,16 @@ +{ + "customProperties": { + "--rsbs-antigap-scale-y": "0", + "--rsbs-backdrop-bg": "rgba(0, 0, 0, 0.6)", + "--rsbs-backdrop-opacity": "1", + "--rsbs-bg": "#fff", + "--rsbs-content-opacity": "1", + "--rsbs-handle-bg": "hsla(0, 0%, 0%, 0.14)", + "--rsbs-max-w": "auto", + "--rsbs-ml": "env(safe-area-inset-left)", + "--rsbs-mr": "env(safe-area-inset-right)", + "--rsbs-overlay-rounded": "16px", + "--rsbs-overlay-translate-y": "0px", + "--rsbs-overlay-h": "0px" + } +} diff --git a/docs/fixtures/Button.tsx b/docs/fixtures/Button.tsx index c513a6f0..0231adb2 100644 --- a/docs/fixtures/Button.tsx +++ b/docs/fixtures/Button.tsx @@ -1,24 +1,21 @@ -import cx from 'classnames' +import cx from 'classnames/dedupe' import { forwardRef } from 'react' import styles from './Button.module.css' type Props = { - textSize?: string - padding?: string + className?: Parameters[0] children: React.ReactNode -} & Omit, 'children'> +} & Omit< + React.PropsWithoutRef, + 'children' | 'className' +> const Button = forwardRef( - ( - { className, textSize = 'text-xl', padding = 'px-7 py-3', ...props }, - ref - ) => ( + ({ className, ...props }, ref) => ( @@ -59,6 +67,7 @@ function One() { function Two() { const [open, setOpen] = useState(false) + const [header, setHeader] = useState(false) function onDismiss() { setOpen(false) @@ -69,7 +78,7 @@ function Two() { } - defaultSnap={({ footerHeight }) => footerHeight} - snapPoints={({ minHeight, footerHeight }) => [footerHeight, minHeight]} + defaultSnap={({ headerHeight, footerHeight }) => + headerHeight + footerHeight + } + snapPoints={({ minHeight, headerHeight, footerHeight }) => [ + headerHeight + footerHeight, + minHeight, + ]} > -

- Using onDismiss lets users close the sheet by swiping - it down, tapping on the backdrop or by hitting esc on - their keyboard. -

+
@@ -207,11 +222,17 @@ function Six() { setMaxHeight(half ? window.innerHeight / 2 : window.innerHeight) }, [half]) + const style = { ['--rsbs-bg' as any]: '#EFF6FF' } + if (half) { + // setting it to undefined removes it, so we don't have to hardcode the default rounding we want in this component + style['--rsbs-overlay-rounded' as any] = undefined + } + return ( <> setOpen(false)} @@ -227,17 +248,100 @@ function Six() { ) } -export default function ExperimentsFixturePage() { +function Seven() { + const [open, setOpen] = useState(false) + const [shift, setShift] = useState(false) + + useInterval(() => { + if (open) { + setShift((shift) => !shift) + } + }, 3000) + return ( <> - - - - - - - - + + setOpen(false)} + snapPoints={({ maxHeight }) => [maxHeight]} + > + maxHeight {shift ? 'shifted' : 'normal'} + ) } + +function Eight() { + const [open, setOpen] = useState(false) + const [defaultSnap, setDefaultSnap] = useState(200) + const reopenRef = useRef(false) + + return ( + <> + + setOpen(false)} + defaultSnap={defaultSnap} + snapPoints={({ minHeight, maxHeight }) => [minHeight, maxHeight]} + onSpringEnd={(event) => { + if (reopenRef.current && event.type === 'CLOSE') { + reopenRef.current = false + setOpen(true) + } + }} + // @TODO investigate missing opacity fade out on close if onDismiss isn't used + /* + footer={ + + } + //*/ + > + + + + + + ) +} + +export default function ExperimentsFixturePage() { + return ( + + + + + + + + + + + ) +} diff --git a/pages/fixtures/scrollable.tsx b/pages/fixtures/scrollable.tsx index fdb16db1..b55eb536 100644 --- a/pages/fixtures/scrollable.tsx +++ b/pages/fixtures/scrollable.tsx @@ -81,8 +81,10 @@ export default function ScrollableFixturePage() {