Skip to content

Commit

Permalink
feat: add pull to refresh to registry
Browse files Browse the repository at this point in the history
  • Loading branch information
malangcat committed Feb 11, 2025
1 parent 10d1b32 commit eca0dec
Show file tree
Hide file tree
Showing 14 changed files with 229 additions and 14 deletions.
2 changes: 2 additions & 0 deletions docs/components/example/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@
"progress-circle-preview": "import { ProgressCircle } from \"seed-design/ui/progress-circle\";\n\nexport default function ProgressCirclePreview() {\n return <ProgressCircle tone=\"neutral\" size=\"40\" />;\n}",
"progress-circle-small": "import { ProgressCircle } from \"seed-design/ui/progress-circle\";\n\nexport default function ProgressCirclePreview() {\n return <ProgressCircle size=\"40\" />;\n}",
"progress-circle-static-white": "import { ProgressCircle } from \"seed-design/ui/progress-circle\";\n\nexport default function ProgressCircleStaticWhite() {\n return (\n <div\n style={{\n display: \"flex\",\n flex: 1,\n width: \"100%\",\n alignItems: \"center\",\n justifyContent: \"center\",\n background: \"#000\",\n }}\n >\n <ProgressCircle tone=\"staticWhite\" />\n </div>\n );\n}",
"pull-to-refresh-preview": "import { AppBar, AppScreen } from \"@seed-design/stackflow\";\nimport { ActivityComponentType } from \"@stackflow/react/future\";\nimport { Stack } from \"seed-design/ui/layout\";\nimport {\n PullToRefreshContent,\n PullToRefreshIndicator,\n PullToRefreshRoot,\n} from \"seed-design/ui/pull-to-refresh\";\n\ndeclare module \"@stackflow/config\" {\n interface Register {\n \"pull-to-refresh-preview\": unknown;\n }\n}\n\nconst PullToRefreshPreview: ActivityComponentType<\"pull-to-refresh-preview\"> = () => {\n // AppScreen is imported from @seed-design/stackflow instead of snippet for demo purpose.\n // AppScreen snippet is integrating PullToRefresh, so it's not necessary to use it here.\n return (\n <AppScreen.Root>\n <AppBar.Root divider>\n <AppBar.Main>\n <AppBar.Title>Pull To Refresh</AppBar.Title>\n </AppBar.Main>\n </AppBar.Root>\n <PullToRefreshRoot\n asChild\n onPtrReady={() => {}}\n onPtrRefresh={async () => {\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }}\n >\n <AppScreen.Layer>\n <PullToRefreshIndicator />\n <PullToRefreshContent asChild>\n <Stack paddingX=\"spacingX.globalGutter\">\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Numquam autem deserunt\n reprehenderit ducimus sunt. Quod laudantium excepturi tempora fuga repellendus\n accusantium nam maiores? Quas debitis, neque ullam eligendi minus sit?\n </Stack>\n </PullToRefreshContent>\n </AppScreen.Layer>\n </PullToRefreshRoot>\n </AppScreen.Root>\n );\n};\n\nexport default PullToRefreshPreview;",
"pull-to-refresh-tabs": "import { ActivityComponentType } from \"@stackflow/react/future\";\nimport { AppBar, AppBarMain } from \"seed-design/ui/app-bar\";\nimport { AppScreen, AppScreenContent } from \"seed-design/ui/app-screen\";\nimport { Stack } from \"seed-design/ui/layout\";\nimport {\n PullToRefreshContent,\n PullToRefreshIndicator,\n PullToRefreshRoot,\n} from \"seed-design/ui/pull-to-refresh\";\nimport { TabsContent, TabsTrigger, TabsList, TabsRoot } from \"seed-design/ui/tabs\";\n\ndeclare module \"@stackflow/config\" {\n interface Register {\n \"pull-to-refresh-tabs\": unknown;\n }\n}\n\nconst PullToRefreshTabs: ActivityComponentType<\"pull-to-refresh-tabs\"> = () => {\n return (\n <AppScreen>\n <AppBar>\n <AppBarMain>Pull To Refresh</AppBarMain>\n </AppBar>\n <AppScreenContent>\n <TabsRoot defaultValue=\"1\" contentLayout=\"fill\">\n <TabsList>\n <TabsTrigger value=\"1\">Tab 1</TabsTrigger>\n <TabsTrigger value=\"2\">Tab 2</TabsTrigger>\n </TabsList>\n <TabsContent value=\"1\">\n <PullToRefreshRoot\n onPtrReady={() => {}}\n onPtrRefresh={async () => {\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }}\n >\n <PullToRefreshIndicator />\n <PullToRefreshContent asChild>\n <Stack paddingX=\"spacingX.globalGutter\">\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Numquam autem deserunt\n reprehenderit ducimus sunt. Quod laudantium excepturi tempora fuga repellendus\n accusantium nam maiores? Quas debitis, neque ullam eligendi minus sit?\n </Stack>\n </PullToRefreshContent>\n </PullToRefreshRoot>\n </TabsContent>\n <TabsContent value=\"2\">\n <Stack paddingX=\"spacingX.globalGutter\">PTR is not available in this tab.</Stack>\n </TabsContent>\n </TabsRoot>\n </AppScreenContent>\n </AppScreen>\n );\n};\n\nexport default PullToRefreshTabs;",
"radio-select-box-preview": "import { Stack } from \"@seed-design/react\";\nimport { RadioSelectBoxItem, RadioSelectBoxRoot } from \"seed-design/ui/select-box\";\n\nexport default function RadioSelectBoxPreview() {\n return (\n <RadioSelectBoxRoot defaultValue=\"apple\" aria-label=\"Fruit\">\n <Stack gap=\"spacingY.componentDefault\">\n <RadioSelectBoxItem value=\"apple\" label=\"Apple\" />\n <RadioSelectBoxItem\n value=\"melon\"\n label=\"Melon\"\n description=\"Elit cupidatat dolore fugiat enim veniam culpa.\"\n />\n <RadioSelectBoxItem value=\"mango\" label=\"Mango\" />\n </Stack>\n </RadioSelectBoxRoot>\n );\n}",
"radio-select-box-react-hook-form": "import { Column, Columns, Stack } from \"@seed-design/react\";\nimport { useCallback, type FormEvent } from \"react\";\nimport { useController, useForm } from \"react-hook-form\";\nimport { ActionButton } from \"seed-design/ui/action-button\";\nimport { RadioSelectBoxItem, RadioSelectBoxRoot } from \"seed-design/ui/select-box\";\n\nconst POSSIBLE_FRUIT_VALUES = [\"apple\", \"melon\", \"mango\"] as const;\n\ninterface FormValues {\n fruit: (typeof POSSIBLE_FRUIT_VALUES)[number];\n}\n\nexport default function RadioSelectBoxReactHookForm() {\n const { handleSubmit, reset, setValue, control } = useForm<FormValues>({\n defaultValues: {\n fruit: \"melon\",\n },\n });\n const { field } = useController({ name: \"fruit\", control });\n\n const onValid = useCallback((data: FormValues) => {\n window.alert(JSON.stringify(data, null, 2));\n }, []);\n\n const onReset = useCallback(\n (event: FormEvent) => {\n event.preventDefault();\n reset();\n },\n [reset],\n );\n\n return (\n <Stack gap=\"x3\" width=\"full\" as=\"form\" onSubmit={handleSubmit(onValid)} onReset={onReset}>\n <RadioSelectBoxRoot aria-label=\"Fruit\" {...field}>\n <Stack gap=\"spacingY.componentDefault\">\n {POSSIBLE_FRUIT_VALUES.map((value) => (\n <RadioSelectBoxItem key={value} value={value} label={value} />\n ))}\n </Stack>\n </RadioSelectBoxRoot>\n <Columns gap=\"x2\">\n <Column width=\"content\">\n <ActionButton type=\"reset\" variant=\"neutralWeak\">\n 초기화\n </ActionButton>\n </Column>\n <Column width=\"content\">\n <ActionButton\n type=\"button\"\n variant=\"neutralWeak\"\n onClick={() => setValue(\"fruit\", \"mango\")}\n >\n mango 선택\n </ActionButton>\n </Column>\n <Column>\n <ActionButton type=\"submit\">제출</ActionButton>\n </Column>\n </Columns>\n </Stack>\n );\n}",
"reaction-button-disabled": "import { IconFaceSmileCircleFill } from \"@daangn/react-monochrome-icon\";\nimport { ReactionButton } from \"seed-design/ui/reaction-button\";\n\nexport default function ReactionButtonDisabled() {\n return (\n <ReactionButton prefixIcon={<IconFaceSmileCircleFill />} disabled>\n 비활성\n </ReactionButton>\n );\n}",
Expand Down
50 changes: 50 additions & 0 deletions docs/components/example/pull-to-refresh-preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"use client";

import { AppBar, AppScreen } from "@seed-design/stackflow";
import { ActivityComponentType } from "@stackflow/react/future";
import { Stack } from "seed-design/ui/layout";
import {
PullToRefreshContent,
PullToRefreshIndicator,
PullToRefreshRoot,
} from "seed-design/ui/pull-to-refresh";

declare module "@stackflow/config" {
interface Register {
"pull-to-refresh-preview": unknown;
}
}

const PullToRefreshPreview: ActivityComponentType<"pull-to-refresh-preview"> = () => {
// AppScreen is imported from @seed-design/stackflow instead of snippet for demo purpose.
// AppScreen snippet is integrating PullToRefresh, so it's not necessary to use it here.
return (
<AppScreen.Root>
<AppBar.Root divider>
<AppBar.Main>
<AppBar.Title>Pull To Refresh</AppBar.Title>
</AppBar.Main>
</AppBar.Root>
<PullToRefreshRoot
asChild
onPtrReady={() => {}}
onPtrRefresh={async () => {
await new Promise((resolve) => setTimeout(resolve, 1000));
}}
>
<AppScreen.Layer>
<PullToRefreshIndicator />
<PullToRefreshContent asChild>
<Stack paddingX="spacingX.globalGutter">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Numquam autem deserunt
reprehenderit ducimus sunt. Quod laudantium excepturi tempora fuga repellendus
accusantium nam maiores? Quas debitis, neque ullam eligendi minus sit?
</Stack>
</PullToRefreshContent>
</AppScreen.Layer>
</PullToRefreshRoot>
</AppScreen.Root>
);
};

export default PullToRefreshPreview;
58 changes: 58 additions & 0 deletions docs/components/example/pull-to-refresh-tabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"use client";

import { ActivityComponentType } from "@stackflow/react/future";
import { AppBar, AppBarMain } from "seed-design/ui/app-bar";
import { AppScreen, AppScreenContent } from "seed-design/ui/app-screen";
import { Stack } from "seed-design/ui/layout";
import {
PullToRefreshContent,
PullToRefreshIndicator,
PullToRefreshRoot,
} from "seed-design/ui/pull-to-refresh";
import { TabsContent, TabsTrigger, TabsList, TabsRoot } from "seed-design/ui/tabs";

declare module "@stackflow/config" {
interface Register {
"pull-to-refresh-tabs": unknown;
}
}

const PullToRefreshTabs: ActivityComponentType<"pull-to-refresh-tabs"> = () => {
return (
<AppScreen>
<AppBar>
<AppBarMain>Pull To Refresh</AppBarMain>
</AppBar>
<AppScreenContent>
<TabsRoot defaultValue="1" contentLayout="fill">
<TabsList>
<TabsTrigger value="1">Tab 1</TabsTrigger>
<TabsTrigger value="2">Tab 2</TabsTrigger>
</TabsList>
<TabsContent value="1">
<PullToRefreshRoot
onPtrReady={() => {}}
onPtrRefresh={async () => {
await new Promise((resolve) => setTimeout(resolve, 1000));
}}
>
<PullToRefreshIndicator />
<PullToRefreshContent asChild>
<Stack paddingX="spacingX.globalGutter">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Numquam autem deserunt
reprehenderit ducimus sunt. Quod laudantium excepturi tempora fuga repellendus
accusantium nam maiores? Quas debitis, neque ullam eligendi minus sit?
</Stack>
</PullToRefreshContent>
</PullToRefreshRoot>
</TabsContent>
<TabsContent value="2">
<Stack paddingX="spacingX.globalGutter">PTR is not available in this tab.</Stack>
</TabsContent>
</TabsRoot>
</AppScreenContent>
</AppScreen>
);
};

export default PullToRefreshTabs;
30 changes: 30 additions & 0 deletions docs/content/docs/react/components/pull-to-refresh.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
title: Pull To Refresh
description: "이 문서는 정리 중이에요. 문의 내용은 #_design_core 채널을 찾아주세요."
---

<StackflowExample names={["pull-to-refresh-preview"]} />

## Installation

<Installation name="pull-to-refresh" />

## Props

### PullToRefreshRoot

<ReactTypeTable path="./registry/ui/pull-to-refresh.tsx" name="PullToRefreshRootProps" />

### PullToRefreshIndicator

<ReactTypeTable path="./registry/ui/pull-to-refresh.tsx" name="PullToRefreshIndicatorProps" />

### PullToRefreshContent

<ReactTypeTable path="./registry/ui/pull-to-refresh.tsx" name="PullToRefreshContentProps" />

## Examples

### PTR in Tabs

<StackflowExample names={["pull-to-refresh-tabs"]} />
5 changes: 4 additions & 1 deletion docs/public/__registry__/ui/app-screen.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
"@seed-design/react",
"@seed-design/stackflow"
],
"innerDependencies": [
"ui:pull-to-refresh"
],
"registries": [
{
"name": "app-screen.tsx",
"type": "ui",
"content": "\"use client\";\n\nimport { PullToRefresh } from \"@seed-design/react/primitive\";\nimport { AppScreen as SeedAppScreen } from \"@seed-design/stackflow\";\nimport { useActions } from \"@stackflow/react\";\nimport { forwardRef } from \"react\";\nimport { ProgressCircle } from \"../ui/progress-circle\";\n\nexport interface AppScreenProps extends SeedAppScreen.RootProps {}\n\nexport const AppScreen = forwardRef<HTMLDivElement, AppScreenProps>(\n ({ children, onSwipeBackEnd, ...otherProps }, ref) => {\n const { pop } = useActions();\n\n return (\n <SeedAppScreen.Root\n ref={ref}\n onSwipeBackEnd={({ swiped }) => {\n if (swiped) {\n pop();\n }\n onSwipeBackEnd?.({ swiped });\n }}\n {...otherProps}\n >\n <SeedAppScreen.Dim />\n {children}\n <SeedAppScreen.Edge />\n </SeedAppScreen.Root>\n );\n },\n);\nAppScreen.displayName = \"AppScreen\";\n\nexport interface AppScreenContentProps extends SeedAppScreen.LayerProps {\n ptr?: boolean;\n\n onPtrReady?: () => void;\n\n onPtrRefresh?: () => Promise<void>;\n}\n\nexport const AppScreenContent = forwardRef<\n HTMLDivElement,\n AppScreenContentProps\n>(({ children, ptr, onPtrReady, onPtrRefresh, ...otherProps }, ref) => {\n if (!ptr) {\n return (\n <SeedAppScreen.Layer ref={ref} {...otherProps}>\n {children}\n </SeedAppScreen.Layer>\n );\n }\n\n return (\n <PullToRefresh.Root\n asChild\n onPtrReady={onPtrReady}\n onPtrRefresh={onPtrRefresh}\n >\n <SeedAppScreen.Layer ref={ref} {...otherProps}>\n <PullToRefresh.Indicator>\n {(props) => <ProgressCircle tone=\"brand\" {...props} />}\n </PullToRefresh.Indicator>\n <PullToRefresh.Content asChild>{children}</PullToRefresh.Content>\n </SeedAppScreen.Layer>\n </PullToRefresh.Root>\n );\n});\n"
"content": "\"use client\";\n\nimport {\n PullToRefreshRoot,\n PullToRefreshContent,\n PullToRefreshIndicator,\n} from \"./pull-to-refresh\";\nimport { AppScreen as SeedAppScreen } from \"@seed-design/stackflow\";\nimport { useActions } from \"@stackflow/react\";\nimport { forwardRef } from \"react\";\n\nexport interface AppScreenProps extends SeedAppScreen.RootProps {}\n\nexport const AppScreen = forwardRef<HTMLDivElement, AppScreenProps>(\n ({ children, onSwipeBackEnd, ...otherProps }, ref) => {\n const { pop } = useActions();\n\n return (\n <SeedAppScreen.Root\n ref={ref}\n onSwipeBackEnd={({ swiped }) => {\n if (swiped) {\n pop();\n }\n onSwipeBackEnd?.({ swiped });\n }}\n {...otherProps}\n >\n <SeedAppScreen.Dim />\n {children}\n <SeedAppScreen.Edge />\n </SeedAppScreen.Root>\n );\n },\n);\nAppScreen.displayName = \"AppScreen\";\n\nexport interface AppScreenContentProps extends SeedAppScreen.LayerProps {\n ptr?: boolean;\n\n onPtrReady?: () => void;\n\n onPtrRefresh?: () => Promise<void>;\n}\n\nexport const AppScreenContent = forwardRef<\n HTMLDivElement,\n AppScreenContentProps\n>(({ children, ptr, onPtrReady, onPtrRefresh, ...otherProps }, ref) => {\n if (!ptr) {\n return (\n <SeedAppScreen.Layer ref={ref} {...otherProps}>\n {children}\n </SeedAppScreen.Layer>\n );\n }\n\n return (\n <PullToRefreshRoot\n asChild\n onPtrReady={onPtrReady}\n onPtrRefresh={onPtrRefresh}\n >\n <SeedAppScreen.Layer ref={ref} {...otherProps}>\n <PullToRefreshIndicator />\n <PullToRefreshContent asChild>{children}</PullToRefreshContent>\n </SeedAppScreen.Layer>\n </PullToRefreshRoot>\n );\n});\n"
},
{
"name": "app-bar.tsx",
Expand Down
15 changes: 15 additions & 0 deletions docs/public/__registry__/ui/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
"ui:app-screen.tsx",
"ui:app-bar.tsx"
],
"innerDependencies": [
"ui:pull-to-refresh"
],
"dependencies": [
"@seed-design/react",
"@seed-design/stackflow"
Expand Down Expand Up @@ -94,6 +97,18 @@
"ui:avatar.tsx"
]
},
{
"name": "pull-to-refresh",
"dependencies": [
"@seed-design/react"
],
"innerDependencies": [
"ui:progress-circle"
],
"files": [
"ui:pull-to-refresh.tsx"
]
},
{
"name": "action-button",
"dependencies": [
Expand Down
16 changes: 16 additions & 0 deletions docs/public/__registry__/ui/pull-to-refresh.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "pull-to-refresh",
"dependencies": [
"@seed-design/react"
],
"innerDependencies": [
"ui:progress-circle"
],
"registries": [
{
"name": "pull-to-refresh.tsx",
"type": "ui",
"content": "\"use client\";\n\nimport { PullToRefresh } from \"@seed-design/react\";\nimport { forwardRef } from \"react\";\nimport { ProgressCircle } from \"./progress-circle\";\n\nexport interface PullToRefreshRootProps extends PullToRefresh.RootProps {}\n\nexport const PullToRefreshRoot = PullToRefresh.Root;\n\nexport interface PullToRefreshIndicatorProps\n extends Omit<PullToRefresh.IndicatorProps, \"children\"> {}\n\nexport const PullToRefreshIndicator = forwardRef<\n HTMLDivElement,\n PullToRefreshIndicatorProps\n>(({ ...otherProps }, ref) => {\n return (\n <PullToRefresh.Indicator ref={ref} {...otherProps}>\n {(props) => <ProgressCircle size=\"24\" tone=\"brand\" {...props} />}\n </PullToRefresh.Indicator>\n );\n});\n\nexport interface PullToRefreshContentProps extends PullToRefresh.ContentProps {}\n\nexport const PullToRefreshContent = PullToRefresh.Content;\n"
}
]
}
7 changes: 7 additions & 0 deletions docs/registry/registry-ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const registryUI: RegistryUI = [
{
name: "app-screen",
files: ["ui:app-screen.tsx", "ui:app-bar.tsx"],
innerDependencies: ["ui:pull-to-refresh"],
dependencies: ["@seed-design/react", "@seed-design/stackflow"],
},
{
Expand Down Expand Up @@ -50,6 +51,12 @@ export const registryUI: RegistryUI = [
dependencies: ["@seed-design/react"],
files: ["ui:avatar.tsx"],
},
{
name: "pull-to-refresh",
dependencies: ["@seed-design/react"],
innerDependencies: ["ui:progress-circle"],
files: ["ui:pull-to-refresh.tsx"],
},
{
name: "action-button",
dependencies: ["@seed-design/react"],
Expand Down
17 changes: 9 additions & 8 deletions docs/registry/ui/app-screen.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
"use client";

import { PullToRefresh } from "@seed-design/react/primitive";
import {
PullToRefreshRoot,
PullToRefreshContent,
PullToRefreshIndicator,
} from "./pull-to-refresh";
import { AppScreen as SeedAppScreen } from "@seed-design/stackflow";
import { useActions } from "@stackflow/react";
import { forwardRef } from "react";
import { ProgressCircle } from "../ui/progress-circle";

export interface AppScreenProps extends SeedAppScreen.RootProps {}

Expand Down Expand Up @@ -53,17 +56,15 @@ export const AppScreenContent = forwardRef<
}

return (
<PullToRefresh.Root
<PullToRefreshRoot
asChild
onPtrReady={onPtrReady}
onPtrRefresh={onPtrRefresh}
>
<SeedAppScreen.Layer ref={ref} {...otherProps}>
<PullToRefresh.Indicator>
{(props) => <ProgressCircle tone="brand" {...props} />}
</PullToRefresh.Indicator>
<PullToRefresh.Content asChild>{children}</PullToRefresh.Content>
<PullToRefreshIndicator />
<PullToRefreshContent asChild>{children}</PullToRefreshContent>
</SeedAppScreen.Layer>
</PullToRefresh.Root>
</PullToRefreshRoot>
);
});
Loading

0 comments on commit eca0dec

Please sign in to comment.