-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
325 additions
and
1 deletion.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
{ | ||
"name": "@seed-design/react-pull-to-refresh", | ||
"version": "0.0.0", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/daangn/seed-design.git", | ||
"directory": "packages/react-headless/pull-to-refresh" | ||
}, | ||
"sideEffects": false, | ||
"exports": { | ||
".": { | ||
"types": "./lib/index.d.ts", | ||
"require": "./lib/index.js", | ||
"import": "./lib/index.mjs" | ||
}, | ||
"./package.json": "./package.json" | ||
}, | ||
"main": "./lib/index.js", | ||
"files": [ | ||
"lib", | ||
"src" | ||
], | ||
"scripts": { | ||
"prepack": "yarn build", | ||
"clean": "rm -rf lib", | ||
"build": "nanobundle build" | ||
}, | ||
"dependencies": { | ||
"@radix-ui/react-compose-refs": "^1.1.1", | ||
"@seed-design/dom-utils": "0.0.0-alpha-20241030023710", | ||
"@seed-design/react-primitive": "0.0.0" | ||
}, | ||
"devDependencies": { | ||
"nanobundle": "^1.6.0" | ||
}, | ||
"peerDependencies": { | ||
"react": ">=18.0.0", | ||
"react-dom": ">=18.0.0" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"ultra": { | ||
"concurrent": [ | ||
"dev", | ||
"build" | ||
] | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
packages/react-headless/pull-to-refresh/src/PullToRefresh.namespace.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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
export { | ||
PullToRefreshRoot as Root, | ||
PullToRefreshIndicator as Indicator, | ||
PullToRefreshContainer as Container, | ||
type PullToRefreshRootProps as RootProps, | ||
type PullToRefreshIndicatorProps as IndicatorProps, | ||
type PullToRefreshContainerProps as ContainerProps, | ||
} from "./PullToRefresh"; |
42 changes: 42 additions & 0 deletions
42
packages/react-headless/pull-to-refresh/src/PullToRefresh.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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { mergeProps } from "@seed-design/dom-utils"; | ||
import { Primitive, type PrimitiveProps } from "@seed-design/react-primitive"; | ||
import { forwardRef } from "react"; | ||
import { | ||
usePullToRefresh, | ||
type PullToRefreshIndicatorRenderProps, | ||
type UsePullToRefreshProps, | ||
} from "./usePullToRefresh"; | ||
import { PullToRefreshProvider, usePullToRefreshContext } from "./usePullToRefreshContext"; | ||
import { composeRefs } from "@radix-ui/react-compose-refs"; | ||
|
||
export interface PullToRefreshRootProps extends UsePullToRefreshProps { | ||
children?: React.ReactNode; | ||
} | ||
|
||
export const PullToRefreshRoot = ({ children, ...otherProps }: PullToRefreshRootProps) => { | ||
const api = usePullToRefresh(otherProps); | ||
|
||
return <PullToRefreshProvider value={api}>{children}</PullToRefreshProvider>; | ||
}; | ||
|
||
export interface PullToRefreshIndicatorProps { | ||
render: (props: PullToRefreshIndicatorRenderProps) => React.ReactNode; | ||
} | ||
|
||
export const PullToRefreshIndicator = ({ render }: PullToRefreshIndicatorProps) => { | ||
const { getIndicatorRenderProps } = usePullToRefreshContext(); | ||
return render(getIndicatorRenderProps()); | ||
}; | ||
|
||
export interface PullToRefreshContainerProps | ||
extends PrimitiveProps, | ||
React.HTMLAttributes<HTMLDivElement> {} | ||
|
||
export const PullToRefreshContainer = forwardRef<HTMLDivElement, PullToRefreshContainerProps>( | ||
(props, ref) => { | ||
const { refs, containerProps } = usePullToRefreshContext(); | ||
const mergedProps = mergeProps(containerProps, props); | ||
return <Primitive.div ref={composeRefs(refs.containerRef, ref)} {...mergedProps} />; | ||
}, | ||
); | ||
PullToRefreshContainer.displayName = "PullToRefreshContainer"; |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
export { | ||
PullToRefreshRoot, | ||
PullToRefreshIndicator, | ||
PullToRefreshContainer, | ||
type PullToRefreshRootProps, | ||
type PullToRefreshIndicatorProps, | ||
type PullToRefreshContainerProps, | ||
} from "./PullToRefresh"; | ||
|
||
export { | ||
usePullToRefreshContext, | ||
type UsePullToRefreshContext, | ||
} from "./usePullToRefreshContext"; | ||
|
||
export * as PullToRefresh from "./PullToRefresh.namespace"; |
137 changes: 137 additions & 0 deletions
137
packages/react-headless/pull-to-refresh/src/usePullToRefresh.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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
import { elementProps } from "@seed-design/dom-utils"; | ||
import { useRef, useState } from "react"; | ||
|
||
interface UsePullToRefreshStateProps { | ||
/** | ||
* The threshold value to trigger the refresh. | ||
* @default 80 | ||
*/ | ||
threshold?: number; | ||
|
||
onReady?: () => void; | ||
|
||
onRefresh?: () => Promise<void>; | ||
} | ||
|
||
interface PullToRefreshContext { | ||
y0: number; | ||
|
||
displacement: number; | ||
|
||
displacementRatio: number; | ||
} | ||
|
||
export type PullToRefreshState = "idle" | "pulling" | "ready" | "loading"; | ||
|
||
function usePullToRefreshState(props: UsePullToRefreshStateProps) { | ||
const threshold = props.threshold ?? 80; | ||
|
||
const [state, setState] = useState("idle"); | ||
const containerRef = useRef<HTMLDivElement | null>(null); | ||
const contextRef = useRef<PullToRefreshContext>({ | ||
y0: 0, | ||
displacement: 0, | ||
displacementRatio: 0, | ||
}); | ||
|
||
function setContext({ y0, displacement }: Omit<PullToRefreshContext, "displacementRatio">) { | ||
contextRef.current = { | ||
y0, | ||
displacement, | ||
displacementRatio: displacement / threshold, | ||
}; | ||
containerRef.current?.style.setProperty("--ptr-displacement", `${displacement}px`); | ||
} | ||
|
||
const events = { | ||
start: ({ y0 }: { y0: number }) => { | ||
if (state !== "idle") { | ||
return; | ||
} | ||
setContext({ y0, displacement: 0 }); | ||
setState("pulling"); | ||
}, | ||
move: ({ y }: { y: number }) => { | ||
if (state !== "pulling" && state !== "ready") { | ||
return; | ||
} | ||
|
||
const { y0 } = contextRef.current; | ||
const displacement = y - y0; | ||
setContext({ y0, displacement }); | ||
|
||
if (displacement > threshold) { | ||
setState("ready"); | ||
props.onReady?.(); | ||
} else { | ||
setState("pulling"); | ||
} | ||
}, | ||
end: () => { | ||
if (state === "ready" && props.onRefresh) { | ||
setState("loading"); | ||
props.onRefresh().then(() => { | ||
setState("idle"); | ||
setContext({ y0: 0, displacement: 0 }); | ||
}); | ||
} else { | ||
setState("idle"); | ||
setContext({ y0: 0, displacement: 0 }); | ||
} | ||
}, | ||
}; | ||
|
||
return { | ||
state, | ||
refs: { containerRef }, | ||
contextRef, | ||
events, | ||
}; | ||
} | ||
|
||
export interface UsePullToRefreshProps extends UsePullToRefreshStateProps {} | ||
|
||
export interface PullToRefreshIndicatorRenderProps { | ||
minValue: number; | ||
maxValue: number; | ||
value: number; | ||
} | ||
|
||
export type UsePullToRefreshReturn = ReturnType<typeof usePullToRefresh>; | ||
|
||
export function usePullToRefresh(props: UsePullToRefreshProps) { | ||
const { state, contextRef, refs, events } = usePullToRefreshState(props); | ||
|
||
const stateProps = elementProps({ | ||
"data-ptr-state": state, | ||
}); | ||
|
||
return { | ||
state, | ||
|
||
refs, | ||
stateProps, | ||
getIndicatorRenderProps: () => { | ||
return { | ||
minValue: 0, | ||
maxValue: 100, | ||
value: contextRef.current.displacementRatio * 100, | ||
}; | ||
}, | ||
containerProps: elementProps({ | ||
...stateProps, | ||
onTouchStart: (e: React.TouchEvent) => { | ||
events.start({ y0: e.touches[0].clientY }); | ||
}, | ||
onTouchMove: (e: React.TouchEvent) => { | ||
events.move({ y: e.touches[0].clientY }); | ||
}, | ||
onTouchEnd: () => { | ||
events.end(); | ||
}, | ||
style: { | ||
transform: "translateY(var(--ptr-displacement, 0))", | ||
}, | ||
}), | ||
}; | ||
} |
21 changes: 21 additions & 0 deletions
21
packages/react-headless/pull-to-refresh/src/usePullToRefreshContext.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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { createContext, useContext } from "react"; | ||
import type { UsePullToRefreshReturn } from "./usePullToRefresh"; | ||
|
||
export interface UsePullToRefreshContext extends UsePullToRefreshReturn {} | ||
|
||
const PullToRefreshContext = createContext<UsePullToRefreshContext | null>(null); | ||
|
||
export const PullToRefreshProvider = PullToRefreshContext.Provider; | ||
|
||
export function usePullToRefreshContext<T extends boolean | undefined = true>({ | ||
strict = true, | ||
}: { strict?: T } = {}): T extends false | ||
? UsePullToRefreshContext | null | ||
: UsePullToRefreshContext { | ||
const context = useContext(PullToRefreshContext); | ||
if (!context && strict) { | ||
throw new Error("usePullToRefreshContext must be used within a PullToRefresh"); | ||
} | ||
|
||
return context as UsePullToRefreshContext; | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"compilerOptions": { | ||
"target": "ESNext", | ||
"module": "ESNext", | ||
"moduleDetection": "force", | ||
"moduleResolution": "Bundler", | ||
"verbatimModuleSyntax": true, | ||
|
||
"strict": true, | ||
"skipLibCheck": true, | ||
"noFallthroughCasesInSwitch": true, | ||
"noPropertyAccessFromIndexSignature": true, | ||
"noUnusedLocals": true, | ||
"noUnusedParameters": true, | ||
|
||
"rootDir": "src", | ||
"outDir": "lib", | ||
"jsx": "react-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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from "@seed-design/react-checkbox"; | ||
export * from "@seed-design/react-radio-group"; | ||
export * from "@seed-design/react-pull-to-refresh"; |
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