@saas-ui/react 2.11.2 → 3.0.0-alpha.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/CHANGELOG.md +7 -154
- package/dist/index.cjs +8461 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +26 -0
- package/dist/index.d.ts +25 -7
- package/dist/index.js +8415 -35
- package/dist/index.js.map +1 -1
- package/package.json +24 -21
- package/src/components/accordion.tsx +47 -0
- package/src/components/action-bar.tsx +40 -0
- package/src/components/alert.tsx +51 -0
- package/src/components/app-shell/app-shell.recipe.ts +52 -0
- package/src/components/app-shell/app-shell.stories.tsx +51 -0
- package/src/components/app-shell/app-shell.tsx +94 -0
- package/src/components/app-shell/index.ts +3 -0
- package/src/components/avatar.tsx +74 -0
- package/src/components/blockquote.tsx +31 -0
- package/src/components/breadcrumbs/breadcrumb.stories.tsx +17 -0
- package/src/components/breadcrumbs/breadcrumb.tsx +36 -0
- package/src/components/breadcrumbs/index.ts +1 -0
- package/src/components/breadcrumbs/namespace.ts +8 -0
- package/src/components/button/button.recipe.ts +182 -0
- package/src/components/button/button.stories.tsx +99 -0
- package/src/components/button/button.tsx +55 -0
- package/src/components/button/index.ts +2 -0
- package/src/components/checkbox/checkbox.tsx +26 -0
- package/src/components/checkbox/index.ts +2 -0
- package/src/components/checkbox-card.tsx +57 -0
- package/src/components/checkbox.tsx +25 -0
- package/src/components/clipboard.tsx +107 -0
- package/src/components/close-button/close-button.stories.tsx +12 -0
- package/src/components/close-button/close-button.tsx +18 -0
- package/src/components/close-button/index.ts +2 -0
- package/src/components/color-mode.tsx +65 -0
- package/src/components/command/command.recipe.ts +17 -0
- package/src/components/command/command.stories.tsx +47 -0
- package/src/components/command/command.tsx +50 -0
- package/src/components/command/index.ts +1 -0
- package/src/components/data-list.tsx +37 -0
- package/src/components/dialog/dialog.tsx +66 -0
- package/src/components/dialog/index.ts +1 -0
- package/src/components/dialog/namespace.ts +18 -0
- package/src/components/drawer/drawer.tsx +56 -0
- package/src/components/drawer/index.ts +3 -0
- package/src/components/drawer/namespace.ts +19 -0
- package/src/components/empty-state.tsx +34 -0
- package/src/components/field.tsx +33 -0
- package/src/components/file-button.tsx +166 -0
- package/src/components/grid-list/grid-list.recipe.ts +113 -0
- package/src/components/hover-card.tsx +35 -0
- package/src/components/icon-badge/icon-badge.recipe.ts +57 -0
- package/src/components/icon-badge/icon-badge.stories.tsx +38 -0
- package/src/components/icon-badge/icon-badge.tsx +59 -0
- package/src/components/icon-badge/index.ts +2 -0
- package/src/components/icons/create-icon.tsx +41 -0
- package/src/components/icons/icons.tsx +121 -0
- package/src/components/icons/index.ts +1 -0
- package/src/components/input-group/index.ts +1 -0
- package/src/components/input-group/input-group.tsx +46 -0
- package/src/components/link/index.ts +2 -0
- package/src/components/link/link.stories.tsx +17 -0
- package/src/components/link/link.test.tsx +33 -0
- package/src/components/link/link.tsx +27 -0
- package/src/components/link-button.tsx +12 -0
- package/src/components/loading-overlay/index.ts +1 -0
- package/src/components/loading-overlay/loading-overlay.recipe.ts +61 -0
- package/src/components/loading-overlay/loading-overlay.stories.tsx +68 -0
- package/src/components/loading-overlay/loading-overlay.tsx +54 -0
- package/src/components/loading-overlay/namespace.ts +7 -0
- package/src/components/menu.tsx +108 -0
- package/src/components/native-select.tsx +57 -0
- package/src/components/navbar/index.ts +1 -0
- package/src/components/navbar/namespace.ts +9 -0
- package/src/components/navbar/navbar.recipe.ts +109 -0
- package/src/components/navbar/navbar.stories.tsx +435 -0
- package/src/components/navbar/navbar.test.tsx +49 -0
- package/src/components/navbar/navbar.tsx +39 -0
- package/src/components/number-input/index.ts +2 -0
- package/src/components/number-input/number-input.tsx +41 -0
- package/src/components/pagination.tsx +207 -0
- package/src/components/password-input/index.ts +2 -0
- package/src/components/password-input/password-input.tsx +98 -0
- package/src/components/persona/index.ts +2 -0
- package/src/components/persona/namespace.ts +18 -0
- package/src/components/persona/persona-primitive.tsx +220 -0
- package/src/components/persona/persona.recipe.ts +94 -0
- package/src/components/persona/persona.stories.tsx +101 -0
- package/src/components/persona/persona.tsx +143 -0
- package/src/components/pin-input/index.ts +2 -0
- package/src/components/pin-input/pin-input.tsx +36 -0
- package/src/components/popover.tsx +58 -0
- package/src/components/progress-circle.tsx +37 -0
- package/src/components/progress.tsx +40 -0
- package/src/components/prose.tsx +264 -0
- package/src/components/provider.tsx +12 -0
- package/src/components/radio/index.ts +2 -0
- package/src/components/radio/radio.tsx +27 -0
- package/src/components/radio-card.tsx +57 -0
- package/src/components/radio.tsx +24 -0
- package/src/components/rating.tsx +27 -0
- package/src/components/search-input/index.ts +2 -0
- package/src/components/search-input/search-input.stories.tsx +63 -0
- package/src/components/search-input/search-input.tsx +134 -0
- package/src/components/segmented-control.tsx +47 -0
- package/src/components/select/index.ts +1 -0
- package/src/components/select/namespace.ts +18 -0
- package/src/components/select/select.tsx +135 -0
- package/src/components/sidebar/index.ts +7 -0
- package/src/components/sidebar/namespace.ts +27 -0
- package/src/components/sidebar/sidebar-item.recipe.ts +65 -0
- package/src/components/sidebar/sidebar.recipe.ts +237 -0
- package/src/components/sidebar/sidebar.stories.tsx +903 -0
- package/src/components/sidebar/sidebar.tsx +204 -0
- package/src/components/skeleton.tsx +44 -0
- package/src/components/slider.tsx +53 -0
- package/src/components/spinner/index.ts +2 -0
- package/src/components/spinner/spinner.stories.tsx +19 -0
- package/src/components/spinner/spinner.tsx +21 -0
- package/src/components/stat.tsx +75 -0
- package/src/components/status.tsx +29 -0
- package/src/components/stepper-input.tsx +49 -0
- package/src/components/steps/index.ts +1 -0
- package/src/components/steps/namespace.ts +16 -0
- package/src/components/steps/steps.tsx +82 -0
- package/src/components/switch/index.ts +3 -0
- package/src/components/switch/switch.tsx +39 -0
- package/src/components/tag.tsx +39 -0
- package/src/components/timeline.tsx +17 -0
- package/src/components/toaster.tsx +43 -0
- package/src/components/toggle-tip.tsx +62 -0
- package/src/components/tooltip.tsx +46 -0
- package/src/index.ts +6 -7
- package/src/preset.ts +9 -0
- package/src/provider/index.ts +4 -0
- package/src/provider/sui-provider.tsx +34 -0
- package/src/provider/use-link.test.tsx +60 -0
- package/src/provider/use-link.tsx +13 -0
- package/src/theme/animation-styles.ts +53 -0
- package/src/theme/breakpoints.ts +11 -0
- package/src/theme/conditions.ts +26 -0
- package/src/theme/fluid-font-sizes.ts +65 -0
- package/src/theme/global-css.ts +94 -0
- package/src/theme/index.ts +72 -0
- package/src/theme/layer-styles.ts +116 -0
- package/src/theme/recipes/chakra/accordion.ts +145 -0
- package/src/theme/recipes/chakra/action-bar.ts +62 -0
- package/src/theme/recipes/chakra/alert.ts +157 -0
- package/src/theme/recipes/chakra/avatar.ts +141 -0
- package/src/theme/recipes/chakra/badge.ts +67 -0
- package/src/theme/recipes/chakra/blockquote.ts +83 -0
- package/src/theme/recipes/chakra/breadcrumb.ts +94 -0
- package/src/theme/recipes/chakra/card.ts +99 -0
- package/src/theme/recipes/chakra/checkbox-card.ts +212 -0
- package/src/theme/recipes/chakra/checkbox.ts +70 -0
- package/src/theme/recipes/chakra/checkmark.ts +83 -0
- package/src/theme/recipes/chakra/code.ts +17 -0
- package/src/theme/recipes/chakra/collapsible.ts +20 -0
- package/src/theme/recipes/chakra/container.ts +26 -0
- package/src/theme/recipes/chakra/data-list.ts +80 -0
- package/src/theme/recipes/chakra/dialog.ts +225 -0
- package/src/theme/recipes/chakra/drawer.ts +201 -0
- package/src/theme/recipes/chakra/editable.ts +88 -0
- package/src/theme/recipes/chakra/empty-state.ts +88 -0
- package/src/theme/recipes/chakra/field.ts +68 -0
- package/src/theme/recipes/chakra/fieldset.ts +62 -0
- package/src/theme/recipes/chakra/file-upload.ts +96 -0
- package/src/theme/recipes/chakra/heading.ts +27 -0
- package/src/theme/recipes/chakra/hover-card.ts +68 -0
- package/src/theme/recipes/chakra/icon.ts +30 -0
- package/src/theme/recipes/chakra/input-addon.ts +40 -0
- package/src/theme/recipes/chakra/input.ts +96 -0
- package/src/theme/recipes/chakra/kbd.ts +60 -0
- package/src/theme/recipes/chakra/link.ts +37 -0
- package/src/theme/recipes/chakra/list.ts +67 -0
- package/src/theme/recipes/chakra/mark.ts +27 -0
- package/src/theme/recipes/chakra/menu.ts +124 -0
- package/src/theme/recipes/chakra/native-select.ts +140 -0
- package/src/theme/recipes/chakra/number-input.ts +115 -0
- package/src/theme/recipes/chakra/pin-input.ts +27 -0
- package/src/theme/recipes/chakra/popover.ts +86 -0
- package/src/theme/recipes/chakra/progress-circle.ts +94 -0
- package/src/theme/recipes/chakra/progress.ts +127 -0
- package/src/theme/recipes/chakra/radio-card.ts +220 -0
- package/src/theme/recipes/chakra/radio-group.ts +72 -0
- package/src/theme/recipes/chakra/radiomark.ts +107 -0
- package/src/theme/recipes/chakra/rating-group.ts +94 -0
- package/src/theme/recipes/chakra/segment-group.ts +117 -0
- package/src/theme/recipes/chakra/select.ts +282 -0
- package/src/theme/recipes/chakra/separator.ts +51 -0
- package/src/theme/recipes/chakra/skeleton.ts +53 -0
- package/src/theme/recipes/chakra/skip-nav-link.ts +34 -0
- package/src/theme/recipes/chakra/slider.ts +178 -0
- package/src/theme/recipes/chakra/spinner.ts +32 -0
- package/src/theme/recipes/chakra/stat.ts +79 -0
- package/src/theme/recipes/chakra/status.ts +48 -0
- package/src/theme/recipes/chakra/steps.ts +218 -0
- package/src/theme/recipes/chakra/switch.ts +167 -0
- package/src/theme/recipes/chakra/table.ts +172 -0
- package/src/theme/recipes/chakra/tabs.ts +280 -0
- package/src/theme/recipes/chakra/tag.ts +131 -0
- package/src/theme/recipes/chakra/textarea.ts +88 -0
- package/src/theme/recipes/chakra/timeline.ts +138 -0
- package/src/theme/recipes/chakra/toast.ts +96 -0
- package/src/theme/recipes/chakra/tooltip.ts +40 -0
- package/src/theme/recipes.ts +46 -0
- package/src/theme/semantic-tokens/colors.ts +403 -0
- package/src/theme/semantic-tokens/radii.ts +7 -0
- package/src/theme/semantic-tokens/shadows.ts +52 -0
- package/src/theme/slot-recipes.ts +104 -0
- package/src/theme/text-styles.ts +39 -0
- package/src/theme/tokens/animations.ts +8 -0
- package/src/theme/tokens/aspect-ratios.ts +10 -0
- package/src/theme/tokens/blurs.ts +12 -0
- package/src/theme/tokens/borders.ts +9 -0
- package/src/theme/tokens/colors.ts +177 -0
- package/src/theme/tokens/cursor.ts +12 -0
- package/src/theme/tokens/durations.ts +11 -0
- package/src/theme/tokens/easings.ts +10 -0
- package/src/theme/tokens/font-sizes.ts +20 -0
- package/src/theme/tokens/font-weights.ts +13 -0
- package/src/theme/tokens/fonts.ts +15 -0
- package/src/theme/tokens/keyframes.ts +173 -0
- package/src/theme/tokens/letter-spacing.ts +9 -0
- package/src/theme/tokens/line-heights.ts +19 -0
- package/src/theme/tokens/radius.ts +18 -0
- package/src/theme/tokens/sizes.ts +71 -0
- package/src/theme/tokens/spacing.ts +38 -0
- package/src/theme/tokens/z-indices.ts +34 -0
- package/src/theme/utils.ts +46 -0
- package/dist/index.d.mts +0 -8
- package/dist/index.mjs +0 -11
- package/dist/index.mjs.map +0 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { forwardRef } from 'react'
|
|
2
|
+
|
|
3
|
+
import { RadioGroup as ChakraRadioGroup } from '@chakra-ui/react'
|
|
4
|
+
|
|
5
|
+
export interface RadioProps extends ChakraRadioGroup.ItemProps {
|
|
6
|
+
rootRef?: React.Ref<HTMLDivElement>
|
|
7
|
+
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const Radio = forwardRef<HTMLInputElement, RadioProps>(
|
|
11
|
+
function Radio(props, ref) {
|
|
12
|
+
const { children, inputProps, rootRef, ...rest } = props
|
|
13
|
+
return (
|
|
14
|
+
<ChakraRadioGroup.Item ref={rootRef} {...rest}>
|
|
15
|
+
<ChakraRadioGroup.ItemHiddenInput ref={ref} {...inputProps} />
|
|
16
|
+
<ChakraRadioGroup.ItemIndicator />
|
|
17
|
+
{children && (
|
|
18
|
+
<ChakraRadioGroup.ItemText>{children}</ChakraRadioGroup.ItemText>
|
|
19
|
+
)}
|
|
20
|
+
</ChakraRadioGroup.Item>
|
|
21
|
+
)
|
|
22
|
+
},
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
export type RadioGroupProps = ChakraRadioGroup.RootProps
|
|
26
|
+
|
|
27
|
+
export const RadioGroup = ChakraRadioGroup.Root
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { RadioCard } from "@chakra-ui/react"
|
|
2
|
+
import { Fragment, forwardRef } from "react"
|
|
3
|
+
|
|
4
|
+
interface RadioCardItemProps extends RadioCard.ItemProps {
|
|
5
|
+
icon?: React.ReactElement
|
|
6
|
+
label?: React.ReactNode
|
|
7
|
+
description?: React.ReactNode
|
|
8
|
+
addon?: React.ReactNode
|
|
9
|
+
indicator?: React.ReactNode | null
|
|
10
|
+
indicatorPlacement?: "start" | "end" | "inside"
|
|
11
|
+
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const RadioCardItem = forwardRef<HTMLInputElement, RadioCardItemProps>(
|
|
15
|
+
function RadioCardItem(props, ref) {
|
|
16
|
+
const {
|
|
17
|
+
inputProps,
|
|
18
|
+
label,
|
|
19
|
+
description,
|
|
20
|
+
addon,
|
|
21
|
+
icon,
|
|
22
|
+
indicator = <RadioCard.ItemIndicator />,
|
|
23
|
+
indicatorPlacement = "end",
|
|
24
|
+
...rest
|
|
25
|
+
} = props
|
|
26
|
+
|
|
27
|
+
const hasContent = label || description || icon
|
|
28
|
+
const ContentWrapper = indicator ? RadioCard.ItemContent : Fragment
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<RadioCard.Item {...rest}>
|
|
32
|
+
<RadioCard.ItemHiddenInput ref={ref} {...inputProps} />
|
|
33
|
+
<RadioCard.ItemControl>
|
|
34
|
+
{indicatorPlacement === "start" && indicator}
|
|
35
|
+
{hasContent && (
|
|
36
|
+
<ContentWrapper>
|
|
37
|
+
{icon}
|
|
38
|
+
{label && <RadioCard.ItemText>{label}</RadioCard.ItemText>}
|
|
39
|
+
{description && (
|
|
40
|
+
<RadioCard.ItemDescription>
|
|
41
|
+
{description}
|
|
42
|
+
</RadioCard.ItemDescription>
|
|
43
|
+
)}
|
|
44
|
+
{indicatorPlacement === "inside" && indicator}
|
|
45
|
+
</ContentWrapper>
|
|
46
|
+
)}
|
|
47
|
+
{indicatorPlacement === "end" && indicator}
|
|
48
|
+
</RadioCard.ItemControl>
|
|
49
|
+
{addon && <RadioCard.ItemAddon>{addon}</RadioCard.ItemAddon>}
|
|
50
|
+
</RadioCard.Item>
|
|
51
|
+
)
|
|
52
|
+
},
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
export const RadioCardRoot = RadioCard.Root
|
|
56
|
+
export const RadioCardLabel = RadioCard.Label
|
|
57
|
+
export const RadioCardItemIndicator = RadioCard.ItemIndicator
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { RadioGroup as ChakraRadioGroup } from "@chakra-ui/react"
|
|
2
|
+
import { forwardRef } 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 = 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
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { RatingGroup } from "@chakra-ui/react"
|
|
2
|
+
import { forwardRef } from "react"
|
|
3
|
+
|
|
4
|
+
export interface RatingProps extends RatingGroup.RootProps {
|
|
5
|
+
icon?: React.ReactElement
|
|
6
|
+
count?: number
|
|
7
|
+
label?: React.ReactNode
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const Rating = forwardRef<HTMLDivElement, RatingProps>(
|
|
11
|
+
function Rating(props, ref) {
|
|
12
|
+
const { icon, count = 5, label, ...rest } = props
|
|
13
|
+
return (
|
|
14
|
+
<RatingGroup.Root ref={ref} count={count} {...rest}>
|
|
15
|
+
{label && <RatingGroup.Label>{label}</RatingGroup.Label>}
|
|
16
|
+
<RatingGroup.HiddenInput />
|
|
17
|
+
<RatingGroup.Control>
|
|
18
|
+
{Array.from({ length: count }).map((_, index) => (
|
|
19
|
+
<RatingGroup.Item key={index} index={index + 1}>
|
|
20
|
+
<RatingGroup.ItemIndicator icon={icon} />
|
|
21
|
+
</RatingGroup.Item>
|
|
22
|
+
))}
|
|
23
|
+
</RatingGroup.Control>
|
|
24
|
+
</RatingGroup.Root>
|
|
25
|
+
)
|
|
26
|
+
},
|
|
27
|
+
)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import { Container, Stack } from '@chakra-ui/react'
|
|
4
|
+
import { StoryObj } from '@storybook/react'
|
|
5
|
+
import { RiCloseLine, RiSearch2Line } from 'react-icons/ri'
|
|
6
|
+
|
|
7
|
+
import { SearchInput, SearchInputProps } from './search-input'
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
title: 'Components/SearchInput',
|
|
11
|
+
component: SearchInput,
|
|
12
|
+
decorators: [
|
|
13
|
+
(Story: any) => (
|
|
14
|
+
<Container mt="40px">
|
|
15
|
+
<Story />
|
|
16
|
+
</Container>
|
|
17
|
+
),
|
|
18
|
+
],
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type Story = StoryObj<SearchInputProps>
|
|
22
|
+
|
|
23
|
+
export const Basic: Story = {}
|
|
24
|
+
|
|
25
|
+
export const Sizes: Story = {
|
|
26
|
+
render: () => {
|
|
27
|
+
return (
|
|
28
|
+
<Stack>
|
|
29
|
+
<SearchInput size="lg" />
|
|
30
|
+
<SearchInput size="md" />
|
|
31
|
+
<SearchInput size="sm" />
|
|
32
|
+
<SearchInput size="xs" />
|
|
33
|
+
</Stack>
|
|
34
|
+
)
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const Disabled: Story = {
|
|
39
|
+
args: {
|
|
40
|
+
disabled: true,
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const CustomIcons: Story = {
|
|
45
|
+
args: {
|
|
46
|
+
icon: <RiSearch2Line />,
|
|
47
|
+
resetIcon: <RiCloseLine />,
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const Controlled: Story = {
|
|
52
|
+
render: (props: any) => {
|
|
53
|
+
const [value, setValue] = useState('')
|
|
54
|
+
return (
|
|
55
|
+
<SearchInput
|
|
56
|
+
value={value}
|
|
57
|
+
onChange={({ target }) => setValue(target.value)}
|
|
58
|
+
onReset={() => setValue('')}
|
|
59
|
+
{...props}
|
|
60
|
+
/>
|
|
61
|
+
)
|
|
62
|
+
},
|
|
63
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Group,
|
|
5
|
+
IconButton,
|
|
6
|
+
type IconButtonProps,
|
|
7
|
+
Input,
|
|
8
|
+
InputElement,
|
|
9
|
+
InputProps,
|
|
10
|
+
mergeRefs,
|
|
11
|
+
useControllableState,
|
|
12
|
+
} from '@chakra-ui/react'
|
|
13
|
+
import { callAll } from '@saas-ui/core/utils'
|
|
14
|
+
|
|
15
|
+
import { CloseIcon, SearchIcon } from '#components/icons/index.ts'
|
|
16
|
+
|
|
17
|
+
export interface SearchInputProps extends InputProps {
|
|
18
|
+
value?: string
|
|
19
|
+
defaultValue?: string
|
|
20
|
+
placeholder?: string
|
|
21
|
+
icon?: React.ReactElement
|
|
22
|
+
resetIcon?: React.ReactElement
|
|
23
|
+
endElement?: React.ReactElement
|
|
24
|
+
onReset?: () => void
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>(
|
|
28
|
+
(props, ref) => {
|
|
29
|
+
const {
|
|
30
|
+
placeholder = 'Search',
|
|
31
|
+
value: valueProp,
|
|
32
|
+
defaultValue: defaultValueProp,
|
|
33
|
+
size,
|
|
34
|
+
variant,
|
|
35
|
+
width = 'full',
|
|
36
|
+
icon = <SearchIcon />,
|
|
37
|
+
resetIcon,
|
|
38
|
+
endElement: endElementProp,
|
|
39
|
+
onChange: onChangeProp,
|
|
40
|
+
onReset: onResetProp,
|
|
41
|
+
onKeyDown: onKeyDownProp,
|
|
42
|
+
disabled,
|
|
43
|
+
...inputProps
|
|
44
|
+
} = props
|
|
45
|
+
|
|
46
|
+
const inputRef = React.useRef<HTMLInputElement>(null)
|
|
47
|
+
|
|
48
|
+
const [value, setValue] = useControllableState({
|
|
49
|
+
value: valueProp,
|
|
50
|
+
defaultValue: defaultValueProp,
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
const onChange = React.useCallback(
|
|
54
|
+
(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
55
|
+
setValue(e.target.value)
|
|
56
|
+
},
|
|
57
|
+
[setValue],
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
const onKeyDown = React.useCallback(
|
|
61
|
+
(event: React.KeyboardEvent) => {
|
|
62
|
+
if (event.key === 'Escape') {
|
|
63
|
+
setValue('')
|
|
64
|
+
onReset()
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
[onResetProp, setValue],
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
const onReset = () => {
|
|
71
|
+
setValue('')
|
|
72
|
+
onResetProp?.()
|
|
73
|
+
inputRef.current?.focus()
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const showReset = value && !props.disabled
|
|
77
|
+
|
|
78
|
+
const endElement = showReset ? (
|
|
79
|
+
<SearchInputResetButton size={size}>{resetIcon}</SearchInputResetButton>
|
|
80
|
+
) : (
|
|
81
|
+
endElementProp
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<Group width={width}>
|
|
86
|
+
<InputElement
|
|
87
|
+
placement="start"
|
|
88
|
+
px="0"
|
|
89
|
+
aspectRatio="9/10"
|
|
90
|
+
fontSize={size}
|
|
91
|
+
>
|
|
92
|
+
{icon}
|
|
93
|
+
</InputElement>
|
|
94
|
+
<Input
|
|
95
|
+
type="text"
|
|
96
|
+
placeholder={placeholder}
|
|
97
|
+
variant={variant}
|
|
98
|
+
size={size}
|
|
99
|
+
value={value}
|
|
100
|
+
disabled={disabled}
|
|
101
|
+
ref={mergeRefs(ref, inputRef)}
|
|
102
|
+
onChange={callAll(onChange, onChangeProp)}
|
|
103
|
+
onKeyDown={callAll(onKeyDown, onKeyDownProp)}
|
|
104
|
+
ps="calc(var(--input-height) - var(--input-height) / 10)"
|
|
105
|
+
pe="calc(var(--input-height) - var(--input-height) / 10)"
|
|
106
|
+
{...inputProps}
|
|
107
|
+
/>
|
|
108
|
+
<InputElement placement="end">{endElement}</InputElement>
|
|
109
|
+
</Group>
|
|
110
|
+
)
|
|
111
|
+
},
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
const SearchInputResetButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
|
115
|
+
(props, ref) => {
|
|
116
|
+
const { children = <CloseIcon />, ...rest } = props
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<IconButton
|
|
120
|
+
ref={ref}
|
|
121
|
+
variant="ghost"
|
|
122
|
+
aria-label="Reset search"
|
|
123
|
+
me="-2"
|
|
124
|
+
aspectRatio="square"
|
|
125
|
+
height="calc(100% - {spacing.2})"
|
|
126
|
+
{...rest}
|
|
127
|
+
>
|
|
128
|
+
{children}
|
|
129
|
+
</IconButton>
|
|
130
|
+
)
|
|
131
|
+
},
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
SearchInput.displayName = 'SearchInput'
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { For, SegmentGroup } from "@chakra-ui/react"
|
|
4
|
+
import { forwardRef, useMemo } from "react"
|
|
5
|
+
|
|
6
|
+
interface Item {
|
|
7
|
+
value: string
|
|
8
|
+
label: React.ReactNode
|
|
9
|
+
disabled?: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface SegmentedControlProps extends SegmentGroup.RootProps {
|
|
13
|
+
items: Array<string | Item>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function normalize(items: Array<string | Item>): Item[] {
|
|
17
|
+
return items.map((item) => {
|
|
18
|
+
if (typeof item === "string") return { value: item, label: item }
|
|
19
|
+
return item
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const SegmentedControl = forwardRef<
|
|
24
|
+
HTMLDivElement,
|
|
25
|
+
SegmentedControlProps
|
|
26
|
+
>(function SegmentedControl(props, ref) {
|
|
27
|
+
const { items, ...rest } = props
|
|
28
|
+
const data = useMemo(() => normalize(items), [items])
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<SegmentGroup.Root ref={ref} {...rest}>
|
|
32
|
+
<SegmentGroup.Indicator />
|
|
33
|
+
<For each={data}>
|
|
34
|
+
{(item) => (
|
|
35
|
+
<SegmentGroup.Item
|
|
36
|
+
key={item.value}
|
|
37
|
+
value={item.value}
|
|
38
|
+
disabled={item.disabled}
|
|
39
|
+
>
|
|
40
|
+
<SegmentGroup.ItemText>{item.label}</SegmentGroup.ItemText>
|
|
41
|
+
<SegmentGroup.ItemHiddenInput />
|
|
42
|
+
</SegmentGroup.Item>
|
|
43
|
+
)}
|
|
44
|
+
</For>
|
|
45
|
+
</SegmentGroup.Root>
|
|
46
|
+
)
|
|
47
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * as Select from './namespace'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export {
|
|
2
|
+
SelectRoot as Root,
|
|
3
|
+
SelectTrigger as Trigger,
|
|
4
|
+
SelectContent as Content,
|
|
5
|
+
SelectItem as Item,
|
|
6
|
+
SelectLabel as Label,
|
|
7
|
+
SelectItemGroup as ItemGroup,
|
|
8
|
+
SelectItemText as ItemText,
|
|
9
|
+
SelectValueText as ValueText,
|
|
10
|
+
} from './select.tsx'
|
|
11
|
+
|
|
12
|
+
export type {
|
|
13
|
+
SelectRootProps as RootProps,
|
|
14
|
+
SelectTriggerProps as TriggerProps,
|
|
15
|
+
SelectContentProps as ContentProps,
|
|
16
|
+
SelectItemGroupProps as ItemGroupProps,
|
|
17
|
+
SelectValueTextProps as ValueTextProps,
|
|
18
|
+
} from './select.tsx'
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { forwardRef } from 'react'
|
|
4
|
+
|
|
5
|
+
import type { CollectionItem } from '@chakra-ui/react'
|
|
6
|
+
import { Portal, Select as SelectPrimitive } from '@chakra-ui/react'
|
|
7
|
+
|
|
8
|
+
import { CloseButton } from '#components/close-button'
|
|
9
|
+
|
|
10
|
+
export interface SelectTriggerProps extends SelectPrimitive.ControlProps {
|
|
11
|
+
clearable?: boolean
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const SelectTrigger = forwardRef<HTMLButtonElement, SelectTriggerProps>(
|
|
15
|
+
function SelectTrigger(props, ref) {
|
|
16
|
+
const { children, clearable, ...rest } = props
|
|
17
|
+
return (
|
|
18
|
+
<SelectPrimitive.Control {...rest}>
|
|
19
|
+
<SelectPrimitive.Trigger ref={ref}>{children}</SelectPrimitive.Trigger>
|
|
20
|
+
<SelectPrimitive.IndicatorGroup>
|
|
21
|
+
{clearable && <SelectClearTrigger />}
|
|
22
|
+
<SelectPrimitive.Indicator />
|
|
23
|
+
</SelectPrimitive.IndicatorGroup>
|
|
24
|
+
</SelectPrimitive.Control>
|
|
25
|
+
)
|
|
26
|
+
},
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
const SelectClearTrigger = forwardRef<
|
|
30
|
+
HTMLButtonElement,
|
|
31
|
+
SelectPrimitive.ClearTriggerProps
|
|
32
|
+
>(function SelectClearTrigger(props, ref) {
|
|
33
|
+
return (
|
|
34
|
+
<SelectPrimitive.ClearTrigger asChild {...props} ref={ref}>
|
|
35
|
+
<CloseButton
|
|
36
|
+
size="xs"
|
|
37
|
+
variant="plain"
|
|
38
|
+
focusVisibleRing="inside"
|
|
39
|
+
focusRingWidth="2px"
|
|
40
|
+
pointerEvents="auto"
|
|
41
|
+
/>
|
|
42
|
+
</SelectPrimitive.ClearTrigger>
|
|
43
|
+
)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
export interface SelectContentProps extends SelectPrimitive.ContentProps {
|
|
47
|
+
portalled?: boolean
|
|
48
|
+
portalRef?: React.RefObject<HTMLElement>
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const SelectContent = forwardRef<HTMLDivElement, SelectContentProps>(
|
|
52
|
+
function SelectContent(props, ref) {
|
|
53
|
+
const { portalled = true, portalRef, ...rest } = props
|
|
54
|
+
return (
|
|
55
|
+
<Portal disabled={!portalled} container={portalRef}>
|
|
56
|
+
<SelectPrimitive.Positioner>
|
|
57
|
+
<SelectPrimitive.Content {...rest} ref={ref} />
|
|
58
|
+
</SelectPrimitive.Positioner>
|
|
59
|
+
</Portal>
|
|
60
|
+
)
|
|
61
|
+
},
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
export const SelectItem = forwardRef<HTMLDivElement, SelectPrimitive.ItemProps>(
|
|
65
|
+
function SelectItem(props, ref) {
|
|
66
|
+
const { item, children, ...rest } = props
|
|
67
|
+
return (
|
|
68
|
+
<SelectPrimitive.Item key={item.value} item={item} {...rest} ref={ref}>
|
|
69
|
+
{children}
|
|
70
|
+
<SelectPrimitive.ItemIndicator />
|
|
71
|
+
</SelectPrimitive.Item>
|
|
72
|
+
)
|
|
73
|
+
},
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
export interface SelectValueTextProps
|
|
77
|
+
extends Omit<SelectPrimitive.ValueTextProps, 'children'> {
|
|
78
|
+
children?(items: CollectionItem[]): React.ReactNode
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const SelectValueText = forwardRef<
|
|
82
|
+
HTMLSpanElement,
|
|
83
|
+
SelectValueTextProps
|
|
84
|
+
>(function SelectValueText(props, ref) {
|
|
85
|
+
const { children, ...rest } = props
|
|
86
|
+
return (
|
|
87
|
+
<SelectPrimitive.ValueText {...rest} ref={ref}>
|
|
88
|
+
<SelectPrimitive.Context>
|
|
89
|
+
{(select) => {
|
|
90
|
+
const items = select.selectedItems
|
|
91
|
+
if (items.length === 0) return props.placeholder
|
|
92
|
+
if (children) return children(items)
|
|
93
|
+
if (items.length === 1)
|
|
94
|
+
return select.collection.stringifyItem(items[0])
|
|
95
|
+
return `${items.length} selected`
|
|
96
|
+
}}
|
|
97
|
+
</SelectPrimitive.Context>
|
|
98
|
+
</SelectPrimitive.ValueText>
|
|
99
|
+
)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
export interface SelectRootProps<T> extends SelectPrimitive.RootProps<T> {}
|
|
103
|
+
|
|
104
|
+
export const SelectRoot = forwardRef(function SelectRoot<
|
|
105
|
+
T extends CollectionItem,
|
|
106
|
+
>(props: SelectRootProps<T>, ref: React.Ref<HTMLDivElement>) {
|
|
107
|
+
return (
|
|
108
|
+
<SelectPrimitive.Root
|
|
109
|
+
{...props}
|
|
110
|
+
ref={ref}
|
|
111
|
+
positioning={{ sameWidth: true, ...props.positioning }}
|
|
112
|
+
/>
|
|
113
|
+
)
|
|
114
|
+
}) as <T extends CollectionItem>(
|
|
115
|
+
props: SelectRootProps<T> & React.RefAttributes<HTMLDivElement>,
|
|
116
|
+
) => React.ReactElement
|
|
117
|
+
|
|
118
|
+
export interface SelectItemGroupProps extends SelectPrimitive.ItemGroupProps {
|
|
119
|
+
label: React.ReactNode
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export const SelectItemGroup = forwardRef<HTMLDivElement, SelectItemGroupProps>(
|
|
123
|
+
function SelectItemGroup(props, ref) {
|
|
124
|
+
const { children, label, ...rest } = props
|
|
125
|
+
return (
|
|
126
|
+
<SelectPrimitive.ItemGroup {...rest} ref={ref}>
|
|
127
|
+
<SelectPrimitive.ItemGroupLabel>{label}</SelectPrimitive.ItemGroupLabel>
|
|
128
|
+
{children}
|
|
129
|
+
</SelectPrimitive.ItemGroup>
|
|
130
|
+
)
|
|
131
|
+
},
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
export const SelectLabel = SelectPrimitive.Label
|
|
135
|
+
export const SelectItemText = SelectPrimitive.ItemText
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export {
|
|
2
|
+
SidebarProvider as Provider,
|
|
3
|
+
SidebarRoot as Root,
|
|
4
|
+
SidebarTrigger as Trigger,
|
|
5
|
+
SidebarFlyoutTrigger as FlyoutTrigger,
|
|
6
|
+
SidebarBackdrop as Backdrop,
|
|
7
|
+
SidebarHeader as Header,
|
|
8
|
+
SidebarBody as Body,
|
|
9
|
+
SidebarFooter as Footer,
|
|
10
|
+
SidebarTrack as Track,
|
|
11
|
+
SidebarGroup as Group,
|
|
12
|
+
SidebarGroupHeader as GroupHeader,
|
|
13
|
+
SidebarGroupTitle as GroupTitle,
|
|
14
|
+
SidebarGroupEndElement as GroupEndElement,
|
|
15
|
+
SidebarGroupContent as GroupContent,
|
|
16
|
+
SidebarNavItem as NavItem,
|
|
17
|
+
SidebarNavButton as NavButton,
|
|
18
|
+
SidebarNavItemEndElement as NavItemEndElement,
|
|
19
|
+
} from './sidebar.tsx'
|
|
20
|
+
|
|
21
|
+
export type {
|
|
22
|
+
SidebarRootProps as RootProps,
|
|
23
|
+
SidebarNavButtonProps as NavButtonProps,
|
|
24
|
+
SidebarFlyoutTriggerProps as FlyoutTriggerProps,
|
|
25
|
+
SidebarProviderProps as ProviderProps,
|
|
26
|
+
SidebarTriggerProps as TriggerProps,
|
|
27
|
+
} from './sidebar.tsx'
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { defineSlotRecipe } from '@chakra-ui/react'
|
|
2
|
+
|
|
3
|
+
export const sidebarNavItemSlotRecipe = defineSlotRecipe({
|
|
4
|
+
className: 'sui-sidebar-nav-item',
|
|
5
|
+
slots: ['item', 'button'],
|
|
6
|
+
base: {
|
|
7
|
+
item: {
|
|
8
|
+
position: 'relative',
|
|
9
|
+
},
|
|
10
|
+
button: {
|
|
11
|
+
display: 'flex',
|
|
12
|
+
alignItems: 'center',
|
|
13
|
+
gap: 2,
|
|
14
|
+
isolation: 'isolate',
|
|
15
|
+
width: '100%',
|
|
16
|
+
textOverflow: 'ellipsis',
|
|
17
|
+
overflow: 'hidden',
|
|
18
|
+
whiteSpace: 'nowrap',
|
|
19
|
+
cursor: 'button',
|
|
20
|
+
transitionProperty: 'common',
|
|
21
|
+
transitionDuration: 'fast',
|
|
22
|
+
focusVisibleRing: 'outside',
|
|
23
|
+
'& > svg': {
|
|
24
|
+
boxSize: 4,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
variants: {
|
|
29
|
+
variant: {
|
|
30
|
+
muted: {
|
|
31
|
+
button: {
|
|
32
|
+
bg: 'transparent',
|
|
33
|
+
color: 'sidebar.accent.fg/85',
|
|
34
|
+
_hover: {
|
|
35
|
+
bg: 'sidebar.accent.bg/90',
|
|
36
|
+
color: 'sidebar.accent.fg',
|
|
37
|
+
},
|
|
38
|
+
_active: {
|
|
39
|
+
bg: 'sidebar.accent.bg',
|
|
40
|
+
color: 'sidebar.accent.fg',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
size: {
|
|
46
|
+
md: {
|
|
47
|
+
item: {
|
|
48
|
+
fontSize: 'sm',
|
|
49
|
+
},
|
|
50
|
+
button: {
|
|
51
|
+
borderRadius: 'md',
|
|
52
|
+
px: 2,
|
|
53
|
+
height: 8,
|
|
54
|
+
'&:has(:nth-child(3))': {
|
|
55
|
+
pe: 0,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
defaultVariants: {
|
|
62
|
+
variant: 'muted',
|
|
63
|
+
size: 'md',
|
|
64
|
+
},
|
|
65
|
+
})
|