-
Notifications
You must be signed in to change notification settings - Fork 28
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
13 changed files
with
260 additions
and
146 deletions.
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,131 @@ | ||
"use client"; | ||
|
||
import { | ||
IconChevronLeftLine, | ||
IconXmarkLine, | ||
} from "@daangn/react-monochrome-icon"; | ||
import { | ||
AppBar as SeedAppBar, | ||
type AppBarIconButtonProps, | ||
} from "@seed-design/stackflow"; | ||
import { useActions, useActivity } from "@stackflow/react"; | ||
import * as React from "react"; | ||
import { forwardRef } from "react"; | ||
|
||
export const AppBar = SeedAppBar.Root; | ||
|
||
export const AppBarLeft = SeedAppBar.Left; | ||
|
||
export const AppBarRight = SeedAppBar.Right; | ||
|
||
export interface AppBarTitleProps | ||
extends Omit<SeedAppBar.TitleProps, "asChild"> { | ||
/** | ||
* The title of the app bar. | ||
* If children is provided as ReactElement, this prop will be ignored. | ||
*/ | ||
title?: string; | ||
|
||
/** | ||
* The subtitle of the app bar. | ||
* If children is provided as ReactElement, this prop will be ignored. | ||
*/ | ||
subtitle?: string; | ||
} | ||
|
||
export const AppBarTitle = forwardRef<HTMLDivElement, AppBarTitleProps>( | ||
({ title, subtitle, children, ...otherProps }, ref) => { | ||
if (React.isValidElement(children)) { | ||
return ( | ||
<SeedAppBar.Title {...otherProps} ref={ref}> | ||
{children} | ||
</SeedAppBar.Title> | ||
); | ||
} | ||
|
||
// TODO: shrink titleText size when subtitle is provided | ||
return ( | ||
<SeedAppBar.Title {...otherProps} ref={ref}> | ||
<SeedAppBar.TitleMain> | ||
<SeedAppBar.TitleText>{children ?? title}</SeedAppBar.TitleText> | ||
</SeedAppBar.TitleMain> | ||
{subtitle ? ( | ||
<SeedAppBar.SubtitleText>{subtitle}</SeedAppBar.SubtitleText> | ||
) : null} | ||
</SeedAppBar.Title> | ||
); | ||
}, | ||
); | ||
AppBarTitle.displayName = "AppBarTitle"; | ||
|
||
export const AppBarIconButton = SeedAppBar.IconButton; | ||
|
||
export const AppBarBackButton = forwardRef< | ||
HTMLButtonElement, | ||
AppBarIconButtonProps | ||
>(({ children = <IconChevronLeftLine />, onClick, ...otherProps }, ref) => { | ||
const activity = useActivity(); | ||
const actions = useActions(); | ||
|
||
const handleOnClick = (e: React.MouseEvent<HTMLButtonElement>) => { | ||
onClick?.(e); | ||
|
||
if (!e.defaultPrevented) { | ||
actions.pop(); | ||
} | ||
}; | ||
|
||
if (!activity) { | ||
return null; | ||
} | ||
if (activity.isRoot) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<SeedAppBar.IconButton | ||
ref={ref} | ||
aria-label="Go Back" | ||
type="button" | ||
onClick={handleOnClick} | ||
{...otherProps} | ||
> | ||
{children} | ||
</SeedAppBar.IconButton> | ||
); | ||
}); | ||
AppBarBackButton.displayName = "AppBarBackButton"; | ||
|
||
export const AppBarCloseButton = forwardRef< | ||
HTMLButtonElement, | ||
AppBarIconButtonProps | ||
>(({ children = <IconXmarkLine />, onClick, ...otherProps }, ref) => { | ||
const activity = useActivity(); | ||
|
||
const handleOnClick = (e: React.MouseEvent<HTMLButtonElement>) => { | ||
onClick?.(e); | ||
|
||
if (!e.defaultPrevented) { | ||
// you can do something here | ||
} | ||
}; | ||
|
||
const isRoot = !activity || activity.isRoot; | ||
|
||
if (!isRoot) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<AppBarIconButton | ||
ref={ref} | ||
aria-label="Close" | ||
type="button" | ||
onClick={handleOnClick} | ||
{...otherProps} | ||
> | ||
{children} | ||
</AppBarIconButton> | ||
); | ||
}); | ||
AppBarCloseButton.displayName = "AppBarCloseButton"; |
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,115 +1,69 @@ | ||
"use client"; | ||
|
||
import { | ||
IconChevronLeftLine, | ||
IconXmarkLine, | ||
} from "@daangn/react-monochrome-icon"; | ||
import { | ||
AppBar as SeedAppBar, | ||
AppScreen as SeedAppScreen, | ||
} from "@seed-design/stackflow"; | ||
import { useActions, useActivity } from "@stackflow/react"; | ||
import { forwardRef, useCallback } from "react"; | ||
import { PullToRefresh } from "@seed-design/react/primitive"; | ||
import { AppScreen as SeedAppScreen } from "@seed-design/stackflow"; | ||
import { useActions } from "@stackflow/react"; | ||
import { forwardRef } from "react"; | ||
import { ProgressCircle } from "../ui/progress-circle"; | ||
|
||
export type AppBarProps = SeedAppBar.RootProps; | ||
export interface AppScreenProps extends SeedAppScreen.RootProps {} | ||
|
||
export type AppScreenProps = SeedAppScreen.RootProps; | ||
|
||
export const AppBar = SeedAppBar.Root; | ||
|
||
export const Left = SeedAppBar.Left; | ||
|
||
export const Right = SeedAppBar.Right; | ||
|
||
export const Title = SeedAppBar.Title; | ||
|
||
export const IconButton = SeedAppBar.IconButton; | ||
|
||
export const BackButton = forwardRef< | ||
HTMLButtonElement, | ||
SeedAppBar.IconButtonProps | ||
>(({ children = <IconChevronLeftLine />, onClick, ...otherProps }, ref) => { | ||
const activity = useActivity(); | ||
const actions = useActions(); | ||
|
||
const handleOnClick = useCallback( | ||
(e: React.MouseEvent<HTMLButtonElement>) => { | ||
onClick?.(e); | ||
|
||
if (!e.defaultPrevented) { | ||
actions.pop(); | ||
} | ||
}, | ||
[actions], | ||
); | ||
|
||
if (!activity) { | ||
return null; | ||
} | ||
if (activity.isRoot) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<SeedAppBar.IconButton | ||
ref={ref} | ||
aria-label="Go Back" | ||
type="button" | ||
onClick={handleOnClick} | ||
{...otherProps} | ||
> | ||
{children} | ||
</SeedAppBar.IconButton> | ||
); | ||
}); | ||
BackButton.displayName = "BackButton"; | ||
export const AppScreen = forwardRef<HTMLDivElement, AppScreenProps>( | ||
({ children, onSwipeEnd, ...otherProps }, ref) => { | ||
const { pop } = useActions(); | ||
|
||
export const CloseButton = forwardRef< | ||
HTMLButtonElement, | ||
SeedAppBar.IconButtonProps | ||
>(({ children = <IconXmarkLine />, onClick, ...otherProps }, ref) => { | ||
const activity = useActivity(); | ||
return ( | ||
<SeedAppScreen.Root | ||
ref={ref} | ||
onSwipeEnd={({ swiped }) => { | ||
if (swiped) { | ||
pop(); | ||
} | ||
onSwipeEnd?.({ swiped }); | ||
}} | ||
{...otherProps} | ||
> | ||
<SeedAppScreen.Dim /> | ||
{children} | ||
<SeedAppScreen.Edge /> | ||
</SeedAppScreen.Root> | ||
); | ||
}, | ||
); | ||
AppScreen.displayName = "AppScreen"; | ||
|
||
const handleOnClick = useCallback( | ||
(e: React.MouseEvent<HTMLButtonElement>) => { | ||
onClick?.(e); | ||
export interface AppScreenContentProps extends SeedAppScreen.LayerProps { | ||
ptr?: boolean; | ||
|
||
if (!e.defaultPrevented) { | ||
// you can do something here | ||
} | ||
}, | ||
[], | ||
); | ||
onPtrReady?: () => void; | ||
|
||
const isRoot = !activity || activity.isRoot; | ||
onPtrRefresh?: () => Promise<void>; | ||
} | ||
|
||
if (!isRoot) { | ||
return null; | ||
export const AppScreenContent = forwardRef< | ||
HTMLDivElement, | ||
AppScreenContentProps | ||
>(({ children, ptr, onPtrReady, onPtrRefresh, ...otherProps }, ref) => { | ||
if (!ptr) { | ||
return ( | ||
<SeedAppScreen.Layer ref={ref} {...otherProps}> | ||
{children} | ||
</SeedAppScreen.Layer> | ||
); | ||
} | ||
|
||
return ( | ||
<IconButton | ||
ref={ref} | ||
aria-label="Close" | ||
type="button" | ||
onClick={handleOnClick} | ||
{...otherProps} | ||
<PullToRefresh.Root | ||
asChild | ||
onPtrReady={onPtrReady} | ||
onPtrRefresh={onPtrRefresh} | ||
> | ||
{children} | ||
</IconButton> | ||
<SeedAppScreen.Layer ref={ref} {...otherProps}> | ||
<PullToRefresh.Indicator> | ||
{(props) => <ProgressCircle tone="brand" {...props} />} | ||
</PullToRefresh.Indicator> | ||
<PullToRefresh.Content asChild>{children}</PullToRefresh.Content> | ||
</SeedAppScreen.Layer> | ||
</PullToRefresh.Root> | ||
); | ||
}); | ||
CloseButton.displayName = "CloseButton"; | ||
|
||
export const AppScreen = forwardRef<HTMLDivElement, AppScreenProps>( | ||
({ children, ...otherProps }, ref) => { | ||
return ( | ||
<SeedAppScreen.Root ref={ref} {...otherProps}> | ||
<SeedAppScreen.Dim /> | ||
<SeedAppScreen.Layer>{children}</SeedAppScreen.Layer> | ||
<SeedAppScreen.Edge /> | ||
</SeedAppScreen.Root> | ||
); | ||
}, | ||
); | ||
AppScreen.displayName = "AppScreen"; |
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
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
Oops, something went wrong.