@prose-reader/react-reader 1.117.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -0
- package/package.json +36 -0
- package/src/common/useFullscreen.ts +44 -0
- package/src/components/ui/avatar.tsx +74 -0
- package/src/components/ui/checkbox.tsx +25 -0
- package/src/components/ui/close-button.tsx +17 -0
- package/src/components/ui/color-mode.tsx +75 -0
- package/src/components/ui/dialog.tsx +62 -0
- package/src/components/ui/drawer.tsx +52 -0
- package/src/components/ui/field.tsx +33 -0
- package/src/components/ui/input-group.tsx +53 -0
- package/src/components/ui/popover.tsx +59 -0
- package/src/components/ui/progress.tsx +34 -0
- package/src/components/ui/provider.tsx +12 -0
- package/src/components/ui/radio.tsx +24 -0
- package/src/components/ui/slider.tsx +82 -0
- package/src/components/ui/toggle-tip.tsx +70 -0
- package/src/components/ui/tooltip.tsx +46 -0
- package/src/context/ReactReaderProvider.tsx +14 -0
- package/src/context/context.ts +6 -0
- package/src/context/useReader.ts +9 -0
- package/src/index.ts +2 -0
- package/src/navigation/QuickMenu/BottomBar.tsx +65 -0
- package/src/navigation/QuickMenu/PaginationInfoSection.tsx +62 -0
- package/src/navigation/QuickMenu/QuickBar.tsx +40 -0
- package/src/navigation/QuickMenu/QuickMenu.tsx +22 -0
- package/src/navigation/QuickMenu/Scrubber.tsx +138 -0
- package/src/navigation/QuickMenu/TimeIndicator.tsx +29 -0
- package/src/navigation/QuickMenu/TopBar.tsx +72 -0
- package/src/navigation/useNavigationContext.ts +46 -0
- package/src/pagination/usePagination.ts +29 -0
- package/src/settings/useSettings.ts +9 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.app.json +26 -0
- package/tsconfig.json +7 -0
- package/tsconfig.node.json +22 -0
- package/vite.config.ts +32 -0
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# React + TypeScript + Vite
|
|
2
|
+
|
|
3
|
+
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
|
4
|
+
|
|
5
|
+
Currently, two official plugins are available:
|
|
6
|
+
|
|
7
|
+
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
|
8
|
+
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
|
9
|
+
|
|
10
|
+
## Expanding the ESLint configuration
|
|
11
|
+
|
|
12
|
+
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
|
13
|
+
|
|
14
|
+
- Configure the top-level `parserOptions` property like this:
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
export default tseslint.config({
|
|
18
|
+
languageOptions: {
|
|
19
|
+
// other options...
|
|
20
|
+
parserOptions: {
|
|
21
|
+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
|
22
|
+
tsconfigRootDir: import.meta.dirname,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
})
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
|
|
29
|
+
- Optionally add `...tseslint.configs.stylisticTypeChecked`
|
|
30
|
+
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
// eslint.config.js
|
|
34
|
+
import react from 'eslint-plugin-react'
|
|
35
|
+
|
|
36
|
+
export default tseslint.config({
|
|
37
|
+
// Set the react version
|
|
38
|
+
settings: { react: { version: '18.3' } },
|
|
39
|
+
plugins: {
|
|
40
|
+
// Add the react plugin
|
|
41
|
+
react,
|
|
42
|
+
},
|
|
43
|
+
rules: {
|
|
44
|
+
// other rules...
|
|
45
|
+
// Enable its recommended rules
|
|
46
|
+
...react.configs.recommended.rules,
|
|
47
|
+
...react.configs['jsx-runtime'].rules,
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@prose-reader/react-reader",
|
|
3
|
+
"private": false,
|
|
4
|
+
"version": "1.117.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "vite build --watch --mode development",
|
|
12
|
+
"build": "tsc -b && vite build"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@eslint/js": "^9.17.0",
|
|
16
|
+
"@types/react": "^19.0.0",
|
|
17
|
+
"@types/react-dom": "^19.0.0",
|
|
18
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
19
|
+
"globals": "^15.14.0",
|
|
20
|
+
"react": "^19.0.0",
|
|
21
|
+
"react-dom": "^19.0.0",
|
|
22
|
+
"rollup-plugin-node-externals": "^8.0.0",
|
|
23
|
+
"typescript": "~5.6.2",
|
|
24
|
+
"vite": "^6.0.5"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"@chakra-ui/react": "3.x",
|
|
28
|
+
"@emotion/react": "11.x",
|
|
29
|
+
"@prose-reader/core": "^1.169.0",
|
|
30
|
+
"rc-slider": "11.1.x",
|
|
31
|
+
"react": "19.x",
|
|
32
|
+
"react-dom": "19.x",
|
|
33
|
+
"react-icons": "^5.4.0",
|
|
34
|
+
"reactjrx": "1.x"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { useEffect } from "react"
|
|
2
|
+
|
|
3
|
+
import { useCallback } from "react"
|
|
4
|
+
|
|
5
|
+
import { useState } from "react"
|
|
6
|
+
|
|
7
|
+
export const useFullscreen = () => {
|
|
8
|
+
const [isFullscreen, setIsFullscreen] = useState(false)
|
|
9
|
+
|
|
10
|
+
const onToggleFullscreenClick = useCallback(() => {
|
|
11
|
+
if (document.fullscreenElement) {
|
|
12
|
+
return document
|
|
13
|
+
.exitFullscreen()
|
|
14
|
+
.catch(console.error)
|
|
15
|
+
.then(() => {
|
|
16
|
+
setIsFullscreen(false)
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return document.documentElement
|
|
21
|
+
.requestFullscreen({ navigationUI: "hide" })
|
|
22
|
+
.catch(console.error)
|
|
23
|
+
.then(() => {
|
|
24
|
+
setIsFullscreen(true)
|
|
25
|
+
})
|
|
26
|
+
}, [])
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
function fullscreenchangeHandler() {
|
|
30
|
+
setIsFullscreen(!!document.fullscreenElement)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
document.addEventListener("fullscreenchange", fullscreenchangeHandler)
|
|
34
|
+
|
|
35
|
+
return () => {
|
|
36
|
+
document.removeEventListener("fullscreenchange", fullscreenchangeHandler)
|
|
37
|
+
}
|
|
38
|
+
}, [])
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
isFullscreen,
|
|
42
|
+
onToggleFullscreenClick,
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import type { GroupProps, SlotRecipeProps } from "@chakra-ui/react"
|
|
4
|
+
import { Avatar as ChakraAvatar, Group } from "@chakra-ui/react"
|
|
5
|
+
import * as React from "react"
|
|
6
|
+
|
|
7
|
+
type ImageProps = React.ImgHTMLAttributes<HTMLImageElement>
|
|
8
|
+
|
|
9
|
+
export interface AvatarProps extends ChakraAvatar.RootProps {
|
|
10
|
+
name?: string
|
|
11
|
+
src?: string
|
|
12
|
+
srcSet?: string
|
|
13
|
+
loading?: ImageProps["loading"]
|
|
14
|
+
icon?: React.ReactElement
|
|
15
|
+
fallback?: React.ReactNode
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(
|
|
19
|
+
function Avatar(props, ref) {
|
|
20
|
+
const { name, src, srcSet, loading, icon, fallback, children, ...rest } =
|
|
21
|
+
props
|
|
22
|
+
return (
|
|
23
|
+
<ChakraAvatar.Root ref={ref} {...rest}>
|
|
24
|
+
<AvatarFallback name={name} icon={icon}>
|
|
25
|
+
{fallback}
|
|
26
|
+
</AvatarFallback>
|
|
27
|
+
<ChakraAvatar.Image src={src} srcSet={srcSet} loading={loading} />
|
|
28
|
+
{children}
|
|
29
|
+
</ChakraAvatar.Root>
|
|
30
|
+
)
|
|
31
|
+
},
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
interface AvatarFallbackProps extends ChakraAvatar.FallbackProps {
|
|
35
|
+
name?: string
|
|
36
|
+
icon?: React.ReactElement
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const AvatarFallback = React.forwardRef<HTMLDivElement, AvatarFallbackProps>(
|
|
40
|
+
function AvatarFallback(props, ref) {
|
|
41
|
+
const { name, icon, children, ...rest } = props
|
|
42
|
+
return (
|
|
43
|
+
<ChakraAvatar.Fallback ref={ref} {...rest}>
|
|
44
|
+
{children}
|
|
45
|
+
{name != null && children == null && <>{getInitials(name)}</>}
|
|
46
|
+
{name == null && children == null && (
|
|
47
|
+
<ChakraAvatar.Icon asChild={!!icon}>{icon}</ChakraAvatar.Icon>
|
|
48
|
+
)}
|
|
49
|
+
</ChakraAvatar.Fallback>
|
|
50
|
+
)
|
|
51
|
+
},
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
function getInitials(name: string) {
|
|
55
|
+
const names = name.trim().split(" ")
|
|
56
|
+
const firstName = names[0] != null ? names[0] : ""
|
|
57
|
+
const lastName = names.length > 1 ? names[names.length - 1] : ""
|
|
58
|
+
return firstName && lastName
|
|
59
|
+
? `${firstName.charAt(0)}${lastName.charAt(0)}`
|
|
60
|
+
: firstName.charAt(0)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface AvatarGroupProps extends GroupProps, SlotRecipeProps<"avatar"> {}
|
|
64
|
+
|
|
65
|
+
export const AvatarGroup = React.forwardRef<HTMLDivElement, AvatarGroupProps>(
|
|
66
|
+
function AvatarGroup(props, ref) {
|
|
67
|
+
const { size, variant, borderless, ...rest } = props
|
|
68
|
+
return (
|
|
69
|
+
<ChakraAvatar.PropsProvider value={{ size, variant, borderless }}>
|
|
70
|
+
<Group gap="0" spaceX="-3" ref={ref} {...rest} />
|
|
71
|
+
</ChakraAvatar.PropsProvider>
|
|
72
|
+
)
|
|
73
|
+
},
|
|
74
|
+
)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Checkbox as ChakraCheckbox } from "@chakra-ui/react"
|
|
2
|
+
import * as React from "react"
|
|
3
|
+
|
|
4
|
+
export interface CheckboxProps extends ChakraCheckbox.RootProps {
|
|
5
|
+
icon?: React.ReactNode
|
|
6
|
+
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
|
|
7
|
+
rootRef?: React.Ref<HTMLLabelElement>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
|
|
11
|
+
function Checkbox(props, ref) {
|
|
12
|
+
const { icon, children, inputProps, rootRef, ...rest } = props
|
|
13
|
+
return (
|
|
14
|
+
<ChakraCheckbox.Root ref={rootRef} {...rest}>
|
|
15
|
+
<ChakraCheckbox.HiddenInput ref={ref} {...inputProps} />
|
|
16
|
+
<ChakraCheckbox.Control>
|
|
17
|
+
{icon || <ChakraCheckbox.Indicator />}
|
|
18
|
+
</ChakraCheckbox.Control>
|
|
19
|
+
{children != null && (
|
|
20
|
+
<ChakraCheckbox.Label>{children}</ChakraCheckbox.Label>
|
|
21
|
+
)}
|
|
22
|
+
</ChakraCheckbox.Root>
|
|
23
|
+
)
|
|
24
|
+
},
|
|
25
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ButtonProps } from "@chakra-ui/react"
|
|
2
|
+
import { IconButton as ChakraIconButton } from "@chakra-ui/react"
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { LuX } from "react-icons/lu"
|
|
5
|
+
|
|
6
|
+
export type CloseButtonProps = ButtonProps
|
|
7
|
+
|
|
8
|
+
export const CloseButton = React.forwardRef<
|
|
9
|
+
HTMLButtonElement,
|
|
10
|
+
CloseButtonProps
|
|
11
|
+
>(function CloseButton(props, ref) {
|
|
12
|
+
return (
|
|
13
|
+
<ChakraIconButton variant="ghost" aria-label="Close" ref={ref} {...props}>
|
|
14
|
+
{props.children ?? <LuX />}
|
|
15
|
+
</ChakraIconButton>
|
|
16
|
+
)
|
|
17
|
+
})
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import type { IconButtonProps } from "@chakra-ui/react"
|
|
4
|
+
import { ClientOnly, IconButton, Skeleton } from "@chakra-ui/react"
|
|
5
|
+
import { ThemeProvider, useTheme } from "next-themes"
|
|
6
|
+
import type { ThemeProviderProps } from "next-themes"
|
|
7
|
+
import * as React from "react"
|
|
8
|
+
import { LuMoon, LuSun } from "react-icons/lu"
|
|
9
|
+
|
|
10
|
+
export interface ColorModeProviderProps extends ThemeProviderProps {}
|
|
11
|
+
|
|
12
|
+
export function ColorModeProvider(props: ColorModeProviderProps) {
|
|
13
|
+
return (
|
|
14
|
+
<ThemeProvider attribute="class" disableTransitionOnChange {...props} />
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type ColorMode = "light" | "dark"
|
|
19
|
+
|
|
20
|
+
export interface UseColorModeReturn {
|
|
21
|
+
colorMode: ColorMode
|
|
22
|
+
setColorMode: (colorMode: ColorMode) => void
|
|
23
|
+
toggleColorMode: () => void
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function useColorMode(): UseColorModeReturn {
|
|
27
|
+
const { resolvedTheme, setTheme } = useTheme()
|
|
28
|
+
const toggleColorMode = () => {
|
|
29
|
+
setTheme(resolvedTheme === "light" ? "dark" : "light")
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
colorMode: resolvedTheme as ColorMode,
|
|
33
|
+
setColorMode: setTheme,
|
|
34
|
+
toggleColorMode,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function useColorModeValue<T>(light: T, dark: T) {
|
|
39
|
+
const { colorMode } = useColorMode()
|
|
40
|
+
return colorMode === "dark" ? dark : light
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function ColorModeIcon() {
|
|
44
|
+
const { colorMode } = useColorMode()
|
|
45
|
+
return colorMode === "dark" ? <LuMoon /> : <LuSun />
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface ColorModeButtonProps extends Omit<IconButtonProps, "aria-label"> {}
|
|
49
|
+
|
|
50
|
+
export const ColorModeButton = React.forwardRef<
|
|
51
|
+
HTMLButtonElement,
|
|
52
|
+
ColorModeButtonProps
|
|
53
|
+
>(function ColorModeButton(props, ref) {
|
|
54
|
+
const { toggleColorMode } = useColorMode()
|
|
55
|
+
return (
|
|
56
|
+
<ClientOnly fallback={<Skeleton boxSize="8" />}>
|
|
57
|
+
<IconButton
|
|
58
|
+
onClick={toggleColorMode}
|
|
59
|
+
variant="ghost"
|
|
60
|
+
aria-label="Toggle color mode"
|
|
61
|
+
size="sm"
|
|
62
|
+
ref={ref}
|
|
63
|
+
{...props}
|
|
64
|
+
css={{
|
|
65
|
+
_icon: {
|
|
66
|
+
width: "5",
|
|
67
|
+
height: "5",
|
|
68
|
+
},
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
<ColorModeIcon />
|
|
72
|
+
</IconButton>
|
|
73
|
+
</ClientOnly>
|
|
74
|
+
)
|
|
75
|
+
})
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Dialog as ChakraDialog, Portal } from "@chakra-ui/react"
|
|
2
|
+
import { CloseButton } from "./close-button"
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
|
|
5
|
+
interface DialogContentProps extends ChakraDialog.ContentProps {
|
|
6
|
+
portalled?: boolean
|
|
7
|
+
portalRef?: React.RefObject<HTMLElement>
|
|
8
|
+
backdrop?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const DialogContent = React.forwardRef<
|
|
12
|
+
HTMLDivElement,
|
|
13
|
+
DialogContentProps
|
|
14
|
+
>(function DialogContent(props, ref) {
|
|
15
|
+
const {
|
|
16
|
+
children,
|
|
17
|
+
portalled = true,
|
|
18
|
+
portalRef,
|
|
19
|
+
backdrop = true,
|
|
20
|
+
...rest
|
|
21
|
+
} = props
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Portal disabled={!portalled} container={portalRef}>
|
|
25
|
+
{backdrop && <ChakraDialog.Backdrop />}
|
|
26
|
+
<ChakraDialog.Positioner>
|
|
27
|
+
<ChakraDialog.Content ref={ref} {...rest} asChild={false}>
|
|
28
|
+
{children}
|
|
29
|
+
</ChakraDialog.Content>
|
|
30
|
+
</ChakraDialog.Positioner>
|
|
31
|
+
</Portal>
|
|
32
|
+
)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
export const DialogCloseTrigger = React.forwardRef<
|
|
36
|
+
HTMLButtonElement,
|
|
37
|
+
ChakraDialog.CloseTriggerProps
|
|
38
|
+
>(function DialogCloseTrigger(props, ref) {
|
|
39
|
+
return (
|
|
40
|
+
<ChakraDialog.CloseTrigger
|
|
41
|
+
position="absolute"
|
|
42
|
+
top="2"
|
|
43
|
+
insetEnd="2"
|
|
44
|
+
{...props}
|
|
45
|
+
asChild
|
|
46
|
+
>
|
|
47
|
+
<CloseButton size="sm" ref={ref}>
|
|
48
|
+
{props.children}
|
|
49
|
+
</CloseButton>
|
|
50
|
+
</ChakraDialog.CloseTrigger>
|
|
51
|
+
)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
export const DialogRoot = ChakraDialog.Root
|
|
55
|
+
export const DialogFooter = ChakraDialog.Footer
|
|
56
|
+
export const DialogHeader = ChakraDialog.Header
|
|
57
|
+
export const DialogBody = ChakraDialog.Body
|
|
58
|
+
export const DialogBackdrop = ChakraDialog.Backdrop
|
|
59
|
+
export const DialogTitle = ChakraDialog.Title
|
|
60
|
+
export const DialogDescription = ChakraDialog.Description
|
|
61
|
+
export const DialogTrigger = ChakraDialog.Trigger
|
|
62
|
+
export const DialogActionTrigger = ChakraDialog.ActionTrigger
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Drawer as ChakraDrawer, Portal } from "@chakra-ui/react"
|
|
2
|
+
import { CloseButton } from "./close-button"
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
|
|
5
|
+
interface DrawerContentProps extends ChakraDrawer.ContentProps {
|
|
6
|
+
portalled?: boolean
|
|
7
|
+
portalRef?: React.RefObject<HTMLElement>
|
|
8
|
+
offset?: ChakraDrawer.ContentProps["padding"]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const DrawerContent = React.forwardRef<
|
|
12
|
+
HTMLDivElement,
|
|
13
|
+
DrawerContentProps
|
|
14
|
+
>(function DrawerContent(props, ref) {
|
|
15
|
+
const { children, portalled = true, portalRef, offset, ...rest } = props
|
|
16
|
+
return (
|
|
17
|
+
<Portal disabled={!portalled} container={portalRef}>
|
|
18
|
+
<ChakraDrawer.Positioner padding={offset}>
|
|
19
|
+
<ChakraDrawer.Content ref={ref} {...rest} asChild={false}>
|
|
20
|
+
{children}
|
|
21
|
+
</ChakraDrawer.Content>
|
|
22
|
+
</ChakraDrawer.Positioner>
|
|
23
|
+
</Portal>
|
|
24
|
+
)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
export const DrawerCloseTrigger = React.forwardRef<
|
|
28
|
+
HTMLButtonElement,
|
|
29
|
+
ChakraDrawer.CloseTriggerProps
|
|
30
|
+
>(function DrawerCloseTrigger(props, ref) {
|
|
31
|
+
return (
|
|
32
|
+
<ChakraDrawer.CloseTrigger
|
|
33
|
+
position="absolute"
|
|
34
|
+
top="2"
|
|
35
|
+
insetEnd="2"
|
|
36
|
+
{...props}
|
|
37
|
+
asChild
|
|
38
|
+
>
|
|
39
|
+
<CloseButton size="sm" ref={ref} />
|
|
40
|
+
</ChakraDrawer.CloseTrigger>
|
|
41
|
+
)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
export const DrawerTrigger = ChakraDrawer.Trigger
|
|
45
|
+
export const DrawerRoot = ChakraDrawer.Root
|
|
46
|
+
export const DrawerFooter = ChakraDrawer.Footer
|
|
47
|
+
export const DrawerHeader = ChakraDrawer.Header
|
|
48
|
+
export const DrawerBody = ChakraDrawer.Body
|
|
49
|
+
export const DrawerBackdrop = ChakraDrawer.Backdrop
|
|
50
|
+
export const DrawerDescription = ChakraDrawer.Description
|
|
51
|
+
export const DrawerTitle = ChakraDrawer.Title
|
|
52
|
+
export const DrawerActionTrigger = ChakraDrawer.ActionTrigger
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Field as ChakraField } from "@chakra-ui/react"
|
|
2
|
+
import * as React from "react"
|
|
3
|
+
|
|
4
|
+
export interface FieldProps extends Omit<ChakraField.RootProps, "label"> {
|
|
5
|
+
label?: React.ReactNode
|
|
6
|
+
helperText?: React.ReactNode
|
|
7
|
+
errorText?: React.ReactNode
|
|
8
|
+
optionalText?: React.ReactNode
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const Field = React.forwardRef<HTMLDivElement, FieldProps>(
|
|
12
|
+
function Field(props, ref) {
|
|
13
|
+
const { label, children, helperText, errorText, optionalText, ...rest } =
|
|
14
|
+
props
|
|
15
|
+
return (
|
|
16
|
+
<ChakraField.Root ref={ref} {...rest}>
|
|
17
|
+
{label && (
|
|
18
|
+
<ChakraField.Label>
|
|
19
|
+
{label}
|
|
20
|
+
<ChakraField.RequiredIndicator fallback={optionalText} />
|
|
21
|
+
</ChakraField.Label>
|
|
22
|
+
)}
|
|
23
|
+
{children}
|
|
24
|
+
{helperText && (
|
|
25
|
+
<ChakraField.HelperText>{helperText}</ChakraField.HelperText>
|
|
26
|
+
)}
|
|
27
|
+
{errorText && (
|
|
28
|
+
<ChakraField.ErrorText>{errorText}</ChakraField.ErrorText>
|
|
29
|
+
)}
|
|
30
|
+
</ChakraField.Root>
|
|
31
|
+
)
|
|
32
|
+
},
|
|
33
|
+
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { BoxProps, InputElementProps } from "@chakra-ui/react"
|
|
2
|
+
import { Group, InputElement } from "@chakra-ui/react"
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
|
|
5
|
+
export interface InputGroupProps extends BoxProps {
|
|
6
|
+
startElementProps?: InputElementProps
|
|
7
|
+
endElementProps?: InputElementProps
|
|
8
|
+
startElement?: React.ReactNode
|
|
9
|
+
endElement?: React.ReactNode
|
|
10
|
+
children: React.ReactElement<InputElementProps>
|
|
11
|
+
startOffset?: InputElementProps["paddingStart"]
|
|
12
|
+
endOffset?: InputElementProps["paddingEnd"]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
|
|
16
|
+
function InputGroup(props, ref) {
|
|
17
|
+
const {
|
|
18
|
+
startElement,
|
|
19
|
+
startElementProps,
|
|
20
|
+
endElement,
|
|
21
|
+
endElementProps,
|
|
22
|
+
children,
|
|
23
|
+
startOffset = "6px",
|
|
24
|
+
endOffset = "6px",
|
|
25
|
+
...rest
|
|
26
|
+
} = props
|
|
27
|
+
|
|
28
|
+
const child =
|
|
29
|
+
React.Children.only<React.ReactElement<InputElementProps>>(children)
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<Group ref={ref} {...rest}>
|
|
33
|
+
{startElement && (
|
|
34
|
+
<InputElement pointerEvents="none" {...startElementProps}>
|
|
35
|
+
{startElement}
|
|
36
|
+
</InputElement>
|
|
37
|
+
)}
|
|
38
|
+
{React.cloneElement(child, {
|
|
39
|
+
...(startElement && {
|
|
40
|
+
ps: `calc(var(--input-height) - ${startOffset})`,
|
|
41
|
+
}),
|
|
42
|
+
...(endElement && { pe: `calc(var(--input-height) - ${endOffset})` }),
|
|
43
|
+
...children.props,
|
|
44
|
+
})}
|
|
45
|
+
{endElement && (
|
|
46
|
+
<InputElement placement="end" {...endElementProps}>
|
|
47
|
+
{endElement}
|
|
48
|
+
</InputElement>
|
|
49
|
+
)}
|
|
50
|
+
</Group>
|
|
51
|
+
)
|
|
52
|
+
},
|
|
53
|
+
)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Popover as ChakraPopover, Portal } from "@chakra-ui/react"
|
|
2
|
+
import { CloseButton } from "./close-button"
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
|
|
5
|
+
interface PopoverContentProps extends ChakraPopover.ContentProps {
|
|
6
|
+
portalled?: boolean
|
|
7
|
+
portalRef?: React.RefObject<HTMLElement>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const PopoverContent = React.forwardRef<
|
|
11
|
+
HTMLDivElement,
|
|
12
|
+
PopoverContentProps
|
|
13
|
+
>(function PopoverContent(props, ref) {
|
|
14
|
+
const { portalled = true, portalRef, ...rest } = props
|
|
15
|
+
return (
|
|
16
|
+
<Portal disabled={!portalled} container={portalRef}>
|
|
17
|
+
<ChakraPopover.Positioner>
|
|
18
|
+
<ChakraPopover.Content ref={ref} {...rest} />
|
|
19
|
+
</ChakraPopover.Positioner>
|
|
20
|
+
</Portal>
|
|
21
|
+
)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
export const PopoverArrow = React.forwardRef<
|
|
25
|
+
HTMLDivElement,
|
|
26
|
+
ChakraPopover.ArrowProps
|
|
27
|
+
>(function PopoverArrow(props, ref) {
|
|
28
|
+
return (
|
|
29
|
+
<ChakraPopover.Arrow {...props} ref={ref}>
|
|
30
|
+
<ChakraPopover.ArrowTip />
|
|
31
|
+
</ChakraPopover.Arrow>
|
|
32
|
+
)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
export const PopoverCloseTrigger = React.forwardRef<
|
|
36
|
+
HTMLButtonElement,
|
|
37
|
+
ChakraPopover.CloseTriggerProps
|
|
38
|
+
>(function PopoverCloseTrigger(props, ref) {
|
|
39
|
+
return (
|
|
40
|
+
<ChakraPopover.CloseTrigger
|
|
41
|
+
position="absolute"
|
|
42
|
+
top="1"
|
|
43
|
+
insetEnd="1"
|
|
44
|
+
{...props}
|
|
45
|
+
asChild
|
|
46
|
+
ref={ref}
|
|
47
|
+
>
|
|
48
|
+
<CloseButton size="sm" />
|
|
49
|
+
</ChakraPopover.CloseTrigger>
|
|
50
|
+
)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
export const PopoverTitle = ChakraPopover.Title
|
|
54
|
+
export const PopoverDescription = ChakraPopover.Description
|
|
55
|
+
export const PopoverFooter = ChakraPopover.Footer
|
|
56
|
+
export const PopoverHeader = ChakraPopover.Header
|
|
57
|
+
export const PopoverRoot = ChakraPopover.Root
|
|
58
|
+
export const PopoverBody = ChakraPopover.Body
|
|
59
|
+
export const PopoverTrigger = ChakraPopover.Trigger
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Progress as ChakraProgress } from "@chakra-ui/react"
|
|
2
|
+
import { InfoTip } from "./toggle-tip"
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
|
|
5
|
+
export const ProgressBar = React.forwardRef<
|
|
6
|
+
HTMLDivElement,
|
|
7
|
+
ChakraProgress.TrackProps
|
|
8
|
+
>(function ProgressBar(props, ref) {
|
|
9
|
+
return (
|
|
10
|
+
<ChakraProgress.Track {...props} ref={ref}>
|
|
11
|
+
<ChakraProgress.Range />
|
|
12
|
+
</ChakraProgress.Track>
|
|
13
|
+
)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export interface ProgressLabelProps extends ChakraProgress.LabelProps {
|
|
17
|
+
info?: React.ReactNode
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const ProgressLabel = React.forwardRef<
|
|
21
|
+
HTMLDivElement,
|
|
22
|
+
ProgressLabelProps
|
|
23
|
+
>(function ProgressLabel(props, ref) {
|
|
24
|
+
const { children, info, ...rest } = props
|
|
25
|
+
return (
|
|
26
|
+
<ChakraProgress.Label {...rest} ref={ref}>
|
|
27
|
+
{children}
|
|
28
|
+
{info && <InfoTip>{info}</InfoTip>}
|
|
29
|
+
</ChakraProgress.Label>
|
|
30
|
+
)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
export const ProgressRoot = ChakraProgress.Root
|
|
34
|
+
export const ProgressValueText = ChakraProgress.ValueText
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { ChakraProvider, defaultSystem } from "@chakra-ui/react"
|
|
4
|
+
import { ColorModeProvider, type ColorModeProviderProps } from "./color-mode"
|
|
5
|
+
|
|
6
|
+
export function Provider(props: ColorModeProviderProps) {
|
|
7
|
+
return (
|
|
8
|
+
<ChakraProvider value={defaultSystem}>
|
|
9
|
+
<ColorModeProvider {...props} />
|
|
10
|
+
</ChakraProvider>
|
|
11
|
+
)
|
|
12
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { RadioGroup as ChakraRadioGroup } from "@chakra-ui/react"
|
|
2
|
+
import * as React from "react"
|
|
3
|
+
|
|
4
|
+
export interface RadioProps extends ChakraRadioGroup.ItemProps {
|
|
5
|
+
rootRef?: React.Ref<HTMLDivElement>
|
|
6
|
+
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const Radio = React.forwardRef<HTMLInputElement, RadioProps>(
|
|
10
|
+
function Radio(props, ref) {
|
|
11
|
+
const { children, inputProps, rootRef, ...rest } = props
|
|
12
|
+
return (
|
|
13
|
+
<ChakraRadioGroup.Item ref={rootRef} {...rest}>
|
|
14
|
+
<ChakraRadioGroup.ItemHiddenInput ref={ref} {...inputProps} />
|
|
15
|
+
<ChakraRadioGroup.ItemIndicator />
|
|
16
|
+
{children && (
|
|
17
|
+
<ChakraRadioGroup.ItemText>{children}</ChakraRadioGroup.ItemText>
|
|
18
|
+
)}
|
|
19
|
+
</ChakraRadioGroup.Item>
|
|
20
|
+
)
|
|
21
|
+
},
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
export const RadioGroup = ChakraRadioGroup.Root
|