myshell-react-lib 0.1.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 +268 -0
- package/dist/assets/audio-playing.json +3657 -0
- package/dist/index.cjs +9654 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1431 -0
- package/dist/index.d.ts +1431 -0
- package/dist/index.js +8788 -0
- package/dist/index.js.map +1 -0
- package/package.json +140 -0
- package/src/common/assets/audio-playing.json +3657 -0
- package/src/common/constants/constants.ts +24 -0
- package/src/common/constants/types/common.ts +10 -0
- package/src/common/hooks/useAudioPlayer.tsx +198 -0
- package/src/common/hooks/useDevice.ts +26 -0
- package/src/common/hooks/useNativeBridge.ts +42 -0
- package/src/common/hooks/useNotification.tsx +179 -0
- package/src/common/hooks/useWindowWidth.ts +19 -0
- package/src/common/utils/common-helper.ts +81 -0
- package/src/components/ItemDemo.tsx +15 -0
- package/src/components/accordion.tsx +126 -0
- package/src/components/alert-dialog.tsx +148 -0
- package/src/components/alert.tsx +65 -0
- package/src/components/aspect-ratio.tsx +7 -0
- package/src/components/audio-player.tsx +58 -0
- package/src/components/avatar.tsx +133 -0
- package/src/components/badge.tsx +65 -0
- package/src/components/button/button.styles.ts +258 -0
- package/src/components/button/button.tsx +215 -0
- package/src/components/button/icon-button.styles.ts +101 -0
- package/src/components/button/icon-button.tsx +100 -0
- package/src/components/button/index.tsx +3 -0
- package/src/components/button/link-button.tsx +184 -0
- package/src/components/cascader.tsx +175 -0
- package/src/components/checkbox.tsx +135 -0
- package/src/components/command.tsx +155 -0
- package/src/components/context-menu.tsx +198 -0
- package/src/components/count-down.tsx +83 -0
- package/src/components/custom-notification.tsx +95 -0
- package/src/components/dialog.tsx +158 -0
- package/src/components/drawer.tsx +116 -0
- package/src/components/dropdown-menu.tsx +196 -0
- package/src/components/energy-progress.tsx +55 -0
- package/src/components/form.tsx +201 -0
- package/src/components/group.tsx +9 -0
- package/src/components/guide.tsx +243 -0
- package/src/components/icon.tsx +89 -0
- package/src/components/icons/outline/DownIcon.tsx +18 -0
- package/src/components/icons/outline/FilterIcon.tsx +21 -0
- package/src/components/icons/outline/arrow-left.tsx +16 -0
- package/src/components/icons/outline/arrow-up-tray.tsx +16 -0
- package/src/components/icons/outline/check-circle.tsx +17 -0
- package/src/components/icons/outline/config.tsx +42 -0
- package/src/components/icons/outline/pencil-square.tsx +16 -0
- package/src/components/icons/outline/trash.tsx +17 -0
- package/src/components/icons/outline/window.tsx +16 -0
- package/src/components/icons/outline/x-circle.tsx +17 -0
- package/src/components/icons/outline/x-mark.tsx +16 -0
- package/src/components/icons/solid/audio-playing.tsx +31 -0
- package/src/components/icons/solid/caret-down.tsx +14 -0
- package/src/components/icons/solid/code.tsx +18 -0
- package/src/components/icons/solid/drag.tsx +14 -0
- package/src/components/icons/solid/phone.tsx +23 -0
- package/src/components/icons/solid/rectangle-group.tsx +14 -0
- package/src/components/image.tsx +151 -0
- package/src/components/input.tsx +118 -0
- package/src/components/label.tsx +26 -0
- package/src/components/link.tsx +123 -0
- package/src/components/marquee/index.css +15 -0
- package/src/components/marquee/marquee.tsx +220 -0
- package/src/components/masonry.tsx +138 -0
- package/src/components/menubar.tsx +234 -0
- package/src/components/mobile/m-tooltip.tsx +34 -0
- package/src/components/modal.tsx +561 -0
- package/src/components/navigation-bar.tsx +100 -0
- package/src/components/number-input.tsx +143 -0
- package/src/components/page-content.tsx +16 -0
- package/src/components/popover.tsx +191 -0
- package/src/components/progress.tsx +80 -0
- package/src/components/radio-group.tsx +44 -0
- package/src/components/scroll-area.tsx +49 -0
- package/src/components/search-bar.tsx +140 -0
- package/src/components/secondary-navigation-bar.tsx +307 -0
- package/src/components/select.tsx +273 -0
- package/src/components/separator.tsx +31 -0
- package/src/components/sheet.tsx +143 -0
- package/src/components/skeleton.tsx +20 -0
- package/src/components/slider.tsx +160 -0
- package/src/components/spinner.tsx +48 -0
- package/src/components/swiper/index.module.scss +88 -0
- package/src/components/swiper/index.tsx +319 -0
- package/src/components/switch.tsx +67 -0
- package/src/components/tabs.tsx +325 -0
- package/src/components/textarea.tsx +71 -0
- package/src/components/toast/toast.tsx +182 -0
- package/src/components/toast/toaster.tsx +160 -0
- package/src/components/toast/use-toast.tsx +248 -0
- package/src/components/toggle-group.tsx +64 -0
- package/src/components/toggle.tsx +46 -0
- package/src/components/tooltip.tsx +283 -0
- package/src/components/typography.tsx +437 -0
- package/src/index.ts +66 -0
- package/src/lib/utils.ts +62 -0
- package/src/stories/Accordion.stories.tsx +64 -0
- package/src/stories/AccordionItem.stories.tsx +48 -0
- package/src/stories/Avatar.stories.ts +58 -0
- package/src/stories/Badge.stories.tsx +40 -0
- package/src/stories/BannerSwiper.stories.tsx +102 -0
- package/src/stories/Button.stories.tsx +543 -0
- package/src/stories/Checkbox.stories.tsx +161 -0
- package/src/stories/Configure.mdx +341 -0
- package/src/stories/CssProperties.mdx +30 -0
- package/src/stories/Description.stories.ts +70 -0
- package/src/stories/Display.stories.ts +64 -0
- package/src/stories/FeaturedSwiper.stories.tsx +6978 -0
- package/src/stories/GridSwiper.stories.tsx +1407 -0
- package/src/stories/Guide.stories.tsx +247 -0
- package/src/stories/Heading.stories.ts +89 -0
- package/src/stories/Icon.stories.ts +77 -0
- package/src/stories/IconButton.stories.tsx +301 -0
- package/src/stories/IconTextButton.stories.ts +59 -0
- package/src/stories/Image.stories.ts +55 -0
- package/src/stories/Input.stories.tsx +203 -0
- package/src/stories/Modal.stories.tsx +144 -0
- package/src/stories/NavigationBar.stories.tsx +81 -0
- package/src/stories/Notification.stories.tsx +276 -0
- package/src/stories/Popover.stories.tsx +100 -0
- package/src/stories/SearchBar.stories.ts +43 -0
- package/src/stories/SecondaryNavigationBar.stories.tsx +199 -0
- package/src/stories/Select.stories.tsx +107 -0
- package/src/stories/Separator.stories.tsx +49 -0
- package/src/stories/Spinner.stories.tsx +48 -0
- package/src/stories/SubHeading.stories.ts +64 -0
- package/src/stories/Swich.stories.tsx +69 -0
- package/src/stories/Tabs.stories.tsx +90 -0
- package/src/stories/Text.stories.ts +78 -0
- package/src/stories/Textarea.stories.tsx +155 -0
- package/src/stories/Toast.stories.tsx +424 -0
- package/src/stories/Tooltip.stories.tsx +244 -0
- package/src/stories/ViewAutoSwiper.stories.tsx +1408 -0
- package/src/styles/components-dark.scss +212 -0
- package/src/styles/components-light.scss +210 -0
- package/src/styles/design-dark.scss +330 -0
- package/src/styles/design-light.scss +345 -0
- package/src/styles/design2-dark.scss +319 -0
- package/src/styles/design2-light.scss +364 -0
- package/src/styles/font.css +19 -0
- package/src/styles/global.scss +251 -0
- package/src/styles/md-viewer.scss +155 -0
- package/src/styles/new-tokens.scss +255 -0
- package/src/styles/tokens.scss +401 -0
- package/src/types/scss.d.ts +24 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { Decimal } from 'decimal.js';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { cn } from '@/lib/utils';
|
|
5
|
+
|
|
6
|
+
import { Input } from './input';
|
|
7
|
+
|
|
8
|
+
export type INumberInputProps = Omit<
|
|
9
|
+
React.InputHTMLAttributes<HTMLInputElement>,
|
|
10
|
+
'size'
|
|
11
|
+
> & {
|
|
12
|
+
rounded?:
|
|
13
|
+
| 'default'
|
|
14
|
+
| 'none'
|
|
15
|
+
| 'sm'
|
|
16
|
+
| 'md'
|
|
17
|
+
| 'lg'
|
|
18
|
+
| 'xl'
|
|
19
|
+
| '2xl'
|
|
20
|
+
| '3xl'
|
|
21
|
+
| 'full'
|
|
22
|
+
| null
|
|
23
|
+
| undefined;
|
|
24
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | null | undefined;
|
|
25
|
+
isFull?: boolean;
|
|
26
|
+
controls?: boolean;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
enum Operation {
|
|
30
|
+
minus = 'minus',
|
|
31
|
+
plus = 'plus',
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const NumberInput = React.forwardRef<HTMLInputElement, INumberInputProps>(
|
|
35
|
+
({ className, type, controls, ...props }, ref) => {
|
|
36
|
+
const inputRef = React.useRef<HTMLInputElement>(null);
|
|
37
|
+
const { min, max, step = 1, onChange } = props;
|
|
38
|
+
const hideControls = controls === false;
|
|
39
|
+
const updateValue = (event: any, operation?: Operation) => {
|
|
40
|
+
event.stopPropagation();
|
|
41
|
+
event.preventDefault();
|
|
42
|
+
const inputElement = inputRef.current;
|
|
43
|
+
const decimalValue = new Decimal(inputElement?.value || 0);
|
|
44
|
+
const decimalStep = new Decimal(step);
|
|
45
|
+
const newValue = (
|
|
46
|
+
operation ? decimalValue[operation](decimalStep) : decimalValue
|
|
47
|
+
).toNumber();
|
|
48
|
+
|
|
49
|
+
// Validate against min and max values if defined
|
|
50
|
+
if (
|
|
51
|
+
(min !== undefined && newValue < Number(min)) ||
|
|
52
|
+
(max !== undefined && newValue > Number(max))
|
|
53
|
+
) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (inputElement) {
|
|
58
|
+
if (operation) {
|
|
59
|
+
inputElement.value = newValue.toString();
|
|
60
|
+
}
|
|
61
|
+
onChange?.({
|
|
62
|
+
target: { value: Number(inputElement.value) },
|
|
63
|
+
} as unknown as React.ChangeEvent<HTMLInputElement>);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const onBlur = (e: any) => {
|
|
68
|
+
const newValue = e.target.value;
|
|
69
|
+
const inputElement = inputRef.current;
|
|
70
|
+
if (!inputElement) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (min !== undefined && newValue < Number(min)) {
|
|
74
|
+
inputElement.value = String(min);
|
|
75
|
+
} else if (max !== undefined && newValue > Number(max)) {
|
|
76
|
+
inputElement.value = String(max);
|
|
77
|
+
} else {
|
|
78
|
+
inputElement.value = String(Number(inputElement.value));
|
|
79
|
+
}
|
|
80
|
+
onChange?.({
|
|
81
|
+
target: { value: Number(inputElement.value) },
|
|
82
|
+
} as unknown as React.ChangeEvent<HTMLInputElement>);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const handleIncrement = (e: any) => updateValue(e, Operation.plus);
|
|
86
|
+
const handleDecrement = (e: any) => updateValue(e, Operation.minus);
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div className={cn('relative w-full', className)}>
|
|
90
|
+
<Input
|
|
91
|
+
type="number"
|
|
92
|
+
ref={inputRef}
|
|
93
|
+
{...props}
|
|
94
|
+
value={props.value}
|
|
95
|
+
onChange={updateValue}
|
|
96
|
+
className={`${hideControls ? 'text-center' : 'pr-10'}`}
|
|
97
|
+
onBlur={onBlur}
|
|
98
|
+
/>
|
|
99
|
+
{hideControls ? null : (
|
|
100
|
+
<div className="absolute top-0 right-3 py-2.5 h-full flex flex-col items-center justify-center space-y-0.5">
|
|
101
|
+
<div
|
|
102
|
+
className="text-Colors-Text-Default bg-surface-accent-gray-subtler rounded-full w-[22px] h-[14px] cursor-pointer flex justify-center items-center"
|
|
103
|
+
onClick={handleIncrement}
|
|
104
|
+
>
|
|
105
|
+
<svg
|
|
106
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
107
|
+
width="20"
|
|
108
|
+
height="14"
|
|
109
|
+
viewBox="0 0 20 14"
|
|
110
|
+
fill="none"
|
|
111
|
+
>
|
|
112
|
+
<path
|
|
113
|
+
d="M6.90169 9H13.0983C13.8493 9 14.27 8.24649 13.806 7.7324L10.7077 4.29945C10.3474 3.90018 9.65265 3.90018 9.29231 4.29945L6.19399 7.7324C5.73001 8.24649 6.15069 9 6.90169 9Z"
|
|
114
|
+
fill="#414345"
|
|
115
|
+
/>
|
|
116
|
+
</svg>
|
|
117
|
+
</div>
|
|
118
|
+
<div
|
|
119
|
+
className="text-Colors-Text-Default bg-surface-accent-gray-subtler rounded-full w-[22px] h-[14px] cursor-pointer flex justify-center items-center"
|
|
120
|
+
onClick={handleDecrement}
|
|
121
|
+
>
|
|
122
|
+
<svg
|
|
123
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
124
|
+
width="20"
|
|
125
|
+
height="14"
|
|
126
|
+
viewBox="0 0 20 14"
|
|
127
|
+
fill="none"
|
|
128
|
+
>
|
|
129
|
+
<path
|
|
130
|
+
d="M13.0983 5L6.90169 5C6.15069 5 5.73001 5.75351 6.19399 6.2676L9.29231 9.70055C9.65265 10.0998 10.3474 10.0998 10.7077 9.70055L13.806 6.2676C14.27 5.75351 13.8493 5 13.0983 5Z"
|
|
131
|
+
fill="#414345"
|
|
132
|
+
/>
|
|
133
|
+
</svg>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
)}
|
|
137
|
+
</div>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
NumberInput.displayName = 'NumberInput';
|
|
142
|
+
|
|
143
|
+
export { NumberInput };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { cn } from '@/lib/utils';
|
|
4
|
+
|
|
5
|
+
function PageContent({ children }: { children: React.ReactNode }) {
|
|
6
|
+
return (
|
|
7
|
+
<section
|
|
8
|
+
className={cn(
|
|
9
|
+
'page-content relative h-full flex-1 flex flex-col overflow-hidden bg-Colors-Background-Normal-Primary-Default text-Colors-Text-Default rounded-none md:rounded-2xl'
|
|
10
|
+
)}
|
|
11
|
+
>
|
|
12
|
+
{children}
|
|
13
|
+
</section>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
export default PageContent;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/* eslint-disable react/require-default-props */
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
|
6
|
+
import * as React from 'react';
|
|
7
|
+
|
|
8
|
+
import { cn } from '@/lib/utils';
|
|
9
|
+
import { Description } from './typography';
|
|
10
|
+
|
|
11
|
+
// const Popover = ({
|
|
12
|
+
// disabled = false,
|
|
13
|
+
// open,
|
|
14
|
+
// ...props
|
|
15
|
+
// }: React.ComponentProps<typeof PopoverPrimitive.Root> & { disabled?: boolean }) => (
|
|
16
|
+
// <PopoverPrimitive.Root open={disabled ? false : open} {...props} />
|
|
17
|
+
// );
|
|
18
|
+
|
|
19
|
+
const PopoverRoot = PopoverPrimitive.Root;
|
|
20
|
+
const PopoverTrigger = PopoverPrimitive.Trigger;
|
|
21
|
+
const PopoverAnchor = PopoverPrimitive.Anchor;
|
|
22
|
+
const PopoverClose = PopoverPrimitive.Close;
|
|
23
|
+
|
|
24
|
+
export interface PopoverContentExs {
|
|
25
|
+
/**
|
|
26
|
+
* 是否展示箭头
|
|
27
|
+
*/
|
|
28
|
+
showArrow?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* 消息类型
|
|
31
|
+
*/
|
|
32
|
+
variant?: 'default' | 'info' | 'message';
|
|
33
|
+
/**
|
|
34
|
+
* 气泡方向
|
|
35
|
+
*/
|
|
36
|
+
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
37
|
+
/**
|
|
38
|
+
* 气泡箭头位置
|
|
39
|
+
*/
|
|
40
|
+
align?: 'start' | 'center' | 'end';
|
|
41
|
+
modal?: boolean;
|
|
42
|
+
container?: HTMLElement | null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* PopoverContent
|
|
47
|
+
*/
|
|
48
|
+
const PopoverContent = React.forwardRef<
|
|
49
|
+
React.ElementRef<typeof PopoverPrimitive.Content>,
|
|
50
|
+
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> &
|
|
51
|
+
PopoverContentExs
|
|
52
|
+
>(
|
|
53
|
+
(
|
|
54
|
+
{
|
|
55
|
+
className,
|
|
56
|
+
align = 'center',
|
|
57
|
+
variant = 'default',
|
|
58
|
+
side = 'top',
|
|
59
|
+
sideOffset = 4,
|
|
60
|
+
alignOffset = 0,
|
|
61
|
+
arrowPadding = 0,
|
|
62
|
+
showArrow = true,
|
|
63
|
+
children,
|
|
64
|
+
container,
|
|
65
|
+
...props
|
|
66
|
+
},
|
|
67
|
+
ref
|
|
68
|
+
) => (
|
|
69
|
+
<PopoverPrimitive.Portal container={container}>
|
|
70
|
+
<PopoverPrimitive.Content
|
|
71
|
+
ref={ref}
|
|
72
|
+
align={align}
|
|
73
|
+
alignOffset={alignOffset}
|
|
74
|
+
sideOffset={sideOffset}
|
|
75
|
+
arrowPadding={arrowPadding}
|
|
76
|
+
side={side}
|
|
77
|
+
forceMount
|
|
78
|
+
className={cn(
|
|
79
|
+
'relative z-[49] mx-4 w-fit max-w-72 rounded-lg border border-opaque p-3 text-left text-xs shadow-modal-default outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 [&[data-state=open]>span]:animate-none',
|
|
80
|
+
variant === 'default'
|
|
81
|
+
? 'bg-alpha-100 text-Colors-Text-Default'
|
|
82
|
+
: variant === 'info'
|
|
83
|
+
? 'bg-surface-accent-yellow-subtle text-Colors-Text-Warning-Bolder'
|
|
84
|
+
: 'bg-Colors-Utility-Lake-Blue-50 text-Colors-Text-Static-White',
|
|
85
|
+
className
|
|
86
|
+
)}
|
|
87
|
+
{...props}
|
|
88
|
+
>
|
|
89
|
+
{children}
|
|
90
|
+
{showArrow && (
|
|
91
|
+
<PopoverPrimitive.Arrow
|
|
92
|
+
width={16}
|
|
93
|
+
height={6}
|
|
94
|
+
className={cn(
|
|
95
|
+
'visible',
|
|
96
|
+
variant === 'default'
|
|
97
|
+
? 'fill-alpha-100'
|
|
98
|
+
: variant === 'info'
|
|
99
|
+
? 'fill-surface-accent-yellow-subtle'
|
|
100
|
+
: 'fill-Colors-Utility-Lake-Blue-50'
|
|
101
|
+
)}
|
|
102
|
+
/>
|
|
103
|
+
)}
|
|
104
|
+
</PopoverPrimitive.Content>
|
|
105
|
+
</PopoverPrimitive.Portal>
|
|
106
|
+
)
|
|
107
|
+
);
|
|
108
|
+
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
|
109
|
+
|
|
110
|
+
const Popover = ({
|
|
111
|
+
disabled = false,
|
|
112
|
+
open,
|
|
113
|
+
title,
|
|
114
|
+
content,
|
|
115
|
+
anchor,
|
|
116
|
+
children,
|
|
117
|
+
className,
|
|
118
|
+
triggerClassName,
|
|
119
|
+
hasOpenState = false,
|
|
120
|
+
isMTooltip = false,
|
|
121
|
+
modal = false,
|
|
122
|
+
openChangeCallback,
|
|
123
|
+
...props
|
|
124
|
+
}: Omit<React.ComponentProps<typeof PopoverPrimitive.Content>, 'content'> &
|
|
125
|
+
PopoverContentExs & {
|
|
126
|
+
open?: boolean;
|
|
127
|
+
disabled?: boolean;
|
|
128
|
+
triggerClassName?: string;
|
|
129
|
+
title?: string;
|
|
130
|
+
// pop内容 string或者node
|
|
131
|
+
content?: string | React.ReactNode;
|
|
132
|
+
anchor?: React.ReactNode;
|
|
133
|
+
hasOpenState?: boolean;
|
|
134
|
+
isMTooltip?: boolean;
|
|
135
|
+
openChangeCallback?: (open: boolean) => void;
|
|
136
|
+
}) => {
|
|
137
|
+
return (
|
|
138
|
+
<PopoverRoot
|
|
139
|
+
open={disabled ? false : open}
|
|
140
|
+
modal={modal}
|
|
141
|
+
onOpenChange={openChangeCallback}
|
|
142
|
+
{...props}
|
|
143
|
+
>
|
|
144
|
+
{anchor}
|
|
145
|
+
{content && (
|
|
146
|
+
<>
|
|
147
|
+
<div
|
|
148
|
+
className={cn(
|
|
149
|
+
hasOpenState && 'data-[state=open]:bg-surface-hovered',
|
|
150
|
+
triggerClassName
|
|
151
|
+
)}
|
|
152
|
+
onClick={(e) => {
|
|
153
|
+
if (isMTooltip) {
|
|
154
|
+
e.preventDefault();
|
|
155
|
+
e.stopPropagation();
|
|
156
|
+
}
|
|
157
|
+
}}
|
|
158
|
+
>
|
|
159
|
+
<PopoverTrigger asChild>
|
|
160
|
+
<div
|
|
161
|
+
className={cn(
|
|
162
|
+
hasOpenState && 'data-[state=open]:bg-surface-hovered',
|
|
163
|
+
triggerClassName
|
|
164
|
+
)}
|
|
165
|
+
>
|
|
166
|
+
{children}
|
|
167
|
+
</div>
|
|
168
|
+
</PopoverTrigger>
|
|
169
|
+
</div>
|
|
170
|
+
<PopoverContent
|
|
171
|
+
{...props}
|
|
172
|
+
className={cn('w-fit max-w-[324px]', className)}
|
|
173
|
+
onCloseAutoFocus={(e) => e.preventDefault()}
|
|
174
|
+
>
|
|
175
|
+
{title && (
|
|
176
|
+
<p className="mb-1">
|
|
177
|
+
<Description size="lg" weight="medium" className="text-inherit">
|
|
178
|
+
{title}
|
|
179
|
+
</Description>
|
|
180
|
+
</p>
|
|
181
|
+
)}
|
|
182
|
+
{content}
|
|
183
|
+
</PopoverContent>
|
|
184
|
+
</>
|
|
185
|
+
)}
|
|
186
|
+
{!content && children}
|
|
187
|
+
</PopoverRoot>
|
|
188
|
+
);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
export { Popover, PopoverAnchor, PopoverContent, PopoverRoot };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as ProgressPrimitive from '@radix-ui/react-progress';
|
|
2
|
+
|
|
3
|
+
import { clamp } from '../common/utils/common-helper';
|
|
4
|
+
import { cn } from '@/lib/utils';
|
|
5
|
+
|
|
6
|
+
export type ProgressProps = {
|
|
7
|
+
/**
|
|
8
|
+
* 进度条的当前值
|
|
9
|
+
*/
|
|
10
|
+
value: number;
|
|
11
|
+
/**
|
|
12
|
+
* 进度条的最大值
|
|
13
|
+
*/
|
|
14
|
+
max: number;
|
|
15
|
+
/**
|
|
16
|
+
* 进度条的自定义类名
|
|
17
|
+
*/
|
|
18
|
+
className?: string;
|
|
19
|
+
/**
|
|
20
|
+
* 进度条指示器的自定义类名
|
|
21
|
+
*/
|
|
22
|
+
indicatorClassName?: string;
|
|
23
|
+
/**
|
|
24
|
+
* 进度条的标签内容
|
|
25
|
+
*/
|
|
26
|
+
label?: React.ReactNode;
|
|
27
|
+
/**
|
|
28
|
+
* 进度条的高度
|
|
29
|
+
*/
|
|
30
|
+
height?: number;
|
|
31
|
+
/**
|
|
32
|
+
* 进度条的宽度
|
|
33
|
+
*/
|
|
34
|
+
width?: number;
|
|
35
|
+
/**
|
|
36
|
+
* 进度条最小宽度
|
|
37
|
+
*/
|
|
38
|
+
minWidth?: number;
|
|
39
|
+
/**
|
|
40
|
+
* 进度条最大宽度
|
|
41
|
+
*/
|
|
42
|
+
maxWidth?: number;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const Progress = ({
|
|
46
|
+
value,
|
|
47
|
+
max,
|
|
48
|
+
className,
|
|
49
|
+
indicatorClassName,
|
|
50
|
+
label,
|
|
51
|
+
height = 20,
|
|
52
|
+
width = 75,
|
|
53
|
+
minWidth = 60,
|
|
54
|
+
maxWidth = 220,
|
|
55
|
+
}: ProgressProps) => {
|
|
56
|
+
const widthValue = `${clamp(
|
|
57
|
+
width + (Math.max(max, value).toString().length - 3) * 12,
|
|
58
|
+
minWidth,
|
|
59
|
+
maxWidth
|
|
60
|
+
)}px`;
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<ProgressPrimitive.Root
|
|
64
|
+
value={value}
|
|
65
|
+
max={Math.max(value, max)}
|
|
66
|
+
className={cn('relative overflow-hidden', className)}
|
|
67
|
+
style={{ height: `${height}px`, width: widthValue }}
|
|
68
|
+
>
|
|
69
|
+
<ProgressPrimitive.Indicator
|
|
70
|
+
className={cn('h-full transition-all', indicatorClassName)}
|
|
71
|
+
style={{ width: `${(value / max) * 100}%` }}
|
|
72
|
+
/>
|
|
73
|
+
{label && (
|
|
74
|
+
<div className="absolute inset-0 flex items-center justify-center px-1">
|
|
75
|
+
{label}
|
|
76
|
+
</div>
|
|
77
|
+
)}
|
|
78
|
+
</ProgressPrimitive.Root>
|
|
79
|
+
);
|
|
80
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
4
|
+
import { Circle } from 'lucide-react';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
|
|
7
|
+
import { cn } from '@/lib/utils';
|
|
8
|
+
|
|
9
|
+
const RadioGroup = React.forwardRef<
|
|
10
|
+
React.ElementRef<typeof RadioGroupPrimitive.Root>,
|
|
11
|
+
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
|
|
12
|
+
>(({ className, ...props }, ref) => {
|
|
13
|
+
return (
|
|
14
|
+
<RadioGroupPrimitive.Root
|
|
15
|
+
className={cn('grid gap-2', className)}
|
|
16
|
+
{...props}
|
|
17
|
+
ref={ref}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
|
|
22
|
+
|
|
23
|
+
const RadioGroupItem = React.forwardRef<
|
|
24
|
+
React.ElementRef<typeof RadioGroupPrimitive.Item>,
|
|
25
|
+
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
|
|
26
|
+
>(({ className, ...props }, ref) => {
|
|
27
|
+
return (
|
|
28
|
+
<RadioGroupPrimitive.Item
|
|
29
|
+
ref={ref}
|
|
30
|
+
className={cn(
|
|
31
|
+
'aspect-square h-5 w-5 rounded-full border-[1.5px] border-pressed text-transparent aria-checked:border-[6px] aria-checked:border-Colors-Utility-Lake-Blue-40 ring-offset-cc-Focus-Rings-Brand-default focus:outline-none focus-visible:ring-2 focus-visible:ring-cc-Focus-Rings-Brand-default focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-30',
|
|
32
|
+
className
|
|
33
|
+
)}
|
|
34
|
+
{...props}
|
|
35
|
+
>
|
|
36
|
+
<RadioGroupPrimitive.Indicator className="flex items-center justify-center">
|
|
37
|
+
<Circle className="h-2 w-2 fill-current text-current" />
|
|
38
|
+
</RadioGroupPrimitive.Indicator>
|
|
39
|
+
</RadioGroupPrimitive.Item>
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
|
|
43
|
+
|
|
44
|
+
export { RadioGroup, RadioGroupItem };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
|
|
6
|
+
import { cn } from '@/lib/utils';
|
|
7
|
+
|
|
8
|
+
const ScrollArea = React.forwardRef<
|
|
9
|
+
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
|
|
11
|
+
>(({ className, children, ...props }, ref) => (
|
|
12
|
+
<ScrollAreaPrimitive.Root
|
|
13
|
+
ref={ref}
|
|
14
|
+
className={cn('relative overflow-hidden', className)}
|
|
15
|
+
type="always"
|
|
16
|
+
{...props}
|
|
17
|
+
>
|
|
18
|
+
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
|
|
19
|
+
{children}
|
|
20
|
+
</ScrollAreaPrimitive.Viewport>
|
|
21
|
+
<ScrollBar />
|
|
22
|
+
<ScrollAreaPrimitive.Corner />
|
|
23
|
+
</ScrollAreaPrimitive.Root>
|
|
24
|
+
));
|
|
25
|
+
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
|
|
26
|
+
|
|
27
|
+
const ScrollBar = React.forwardRef<
|
|
28
|
+
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
|
29
|
+
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
|
30
|
+
>(({ className, orientation = 'vertical', ...props }, ref) => (
|
|
31
|
+
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
|
32
|
+
ref={ref}
|
|
33
|
+
orientation={orientation}
|
|
34
|
+
className={cn(
|
|
35
|
+
'flex touch-none select-none transition-colors',
|
|
36
|
+
orientation === 'vertical' &&
|
|
37
|
+
'h-full w-2 border-l border-l-transparent p-[1px]',
|
|
38
|
+
orientation === 'horizontal' &&
|
|
39
|
+
'h-2 flex-col border-t border-t-transparent p-[1px]',
|
|
40
|
+
className
|
|
41
|
+
)}
|
|
42
|
+
{...props}
|
|
43
|
+
>
|
|
44
|
+
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border-hovered hover:bg-border-pressed" />
|
|
45
|
+
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
|
46
|
+
));
|
|
47
|
+
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
|
|
48
|
+
|
|
49
|
+
export { ScrollArea, ScrollBar };
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import MagnifyingGlassIcon from '@heroicons/react/24/outline/esm/MagnifyingGlassIcon';
|
|
2
|
+
import XMarkIcon from '@heroicons/react/24/outline/esm/XMarkIcon';
|
|
3
|
+
import { cva } from 'class-variance-authority';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { useEffect } from 'react';
|
|
6
|
+
|
|
7
|
+
import { cn } from '@/lib/utils';
|
|
8
|
+
|
|
9
|
+
import { Icon } from './icon';
|
|
10
|
+
import { IconButton } from './button/icon-button';
|
|
11
|
+
import { Input } from './input';
|
|
12
|
+
|
|
13
|
+
export type SearchInputProps = React.InputHTMLAttributes<HTMLInputElement>;
|
|
14
|
+
export type SearchBarProps = {
|
|
15
|
+
/**
|
|
16
|
+
* searchBar样式覆盖
|
|
17
|
+
*/
|
|
18
|
+
className?: string;
|
|
19
|
+
/**
|
|
20
|
+
* input样式覆盖
|
|
21
|
+
*/
|
|
22
|
+
inputClassName?: string;
|
|
23
|
+
/*
|
|
24
|
+
* 外部传入的值
|
|
25
|
+
*/
|
|
26
|
+
searchValue?: string;
|
|
27
|
+
/**
|
|
28
|
+
* 点击或键盘按下回车时触发回调函数
|
|
29
|
+
*/
|
|
30
|
+
onSearchChange: (value: string) => void;
|
|
31
|
+
/**
|
|
32
|
+
* placeholder值
|
|
33
|
+
*/
|
|
34
|
+
placeholder?: string;
|
|
35
|
+
/**
|
|
36
|
+
* 大小 sm(default) | md
|
|
37
|
+
*
|
|
38
|
+
* @default sm
|
|
39
|
+
*/
|
|
40
|
+
size?: 'md' | 'sm' | 'xs';
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 是否圆角
|
|
44
|
+
*/
|
|
45
|
+
roundedFill?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* 值改变时触发回调函数
|
|
48
|
+
*/
|
|
49
|
+
onValueChange?: (value: string) => void;
|
|
50
|
+
} & Omit<SearchInputProps, 'size'>;
|
|
51
|
+
|
|
52
|
+
const searchBarVariants = cva('rounded-md', {
|
|
53
|
+
variants: {
|
|
54
|
+
size: {
|
|
55
|
+
md: 'h-11',
|
|
56
|
+
sm: 'h-10',
|
|
57
|
+
xs: 'h-9',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
defaultVariants: {
|
|
61
|
+
size: 'sm',
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
function SearchBar({
|
|
66
|
+
className,
|
|
67
|
+
inputClassName,
|
|
68
|
+
placeholder,
|
|
69
|
+
type,
|
|
70
|
+
size,
|
|
71
|
+
readOnly,
|
|
72
|
+
searchValue,
|
|
73
|
+
roundedFill,
|
|
74
|
+
onSearchChange,
|
|
75
|
+
onValueChange,
|
|
76
|
+
...props
|
|
77
|
+
}: SearchBarProps) {
|
|
78
|
+
const [value, setValue] = React.useState('');
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
setValue(searchValue || '');
|
|
81
|
+
}, [searchValue]);
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<div
|
|
85
|
+
className={cn('relative w-full', searchBarVariants({ size }), className)}
|
|
86
|
+
>
|
|
87
|
+
<Icon
|
|
88
|
+
component={MagnifyingGlassIcon}
|
|
89
|
+
size="lg"
|
|
90
|
+
className="absolute top-1/2 -translate-y-1/2 left-3 z-10 text-Colors-Foreground-Subtlest cursor-pointer"
|
|
91
|
+
onClick={() => {
|
|
92
|
+
onSearchChange(value);
|
|
93
|
+
}}
|
|
94
|
+
/>
|
|
95
|
+
<Input
|
|
96
|
+
type={type}
|
|
97
|
+
placeholder={placeholder}
|
|
98
|
+
rounded={roundedFill ? 'full' : 'md'}
|
|
99
|
+
size={size}
|
|
100
|
+
className={cn(
|
|
101
|
+
'relative w-full px-9 flex space-x-2 text-base shadow-none placeholder:text-Colors-Text-Subtlest',
|
|
102
|
+
{
|
|
103
|
+
'focus-visible:ring-transparent': readOnly,
|
|
104
|
+
},
|
|
105
|
+
'border-cc-Search-Bar-border-default bg-cc-Search-Bar-bg-default hover:bg-cc-Search-Bar-bg-hover focus-visible:shadow-cc-Focus-Rings-Brand-default',
|
|
106
|
+
className
|
|
107
|
+
)}
|
|
108
|
+
value={value}
|
|
109
|
+
onChange={(e) => {
|
|
110
|
+
setValue(e.target.value);
|
|
111
|
+
onValueChange?.(e.target.value);
|
|
112
|
+
}}
|
|
113
|
+
onKeyDown={(e) => {
|
|
114
|
+
if (e.key === 'Enter' && !(e.shiftKey || e.altKey)) {
|
|
115
|
+
(e.target as HTMLInputElement).blur();
|
|
116
|
+
onSearchChange(value);
|
|
117
|
+
}
|
|
118
|
+
}}
|
|
119
|
+
{...props}
|
|
120
|
+
/>
|
|
121
|
+
{value && (
|
|
122
|
+
<IconButton
|
|
123
|
+
className="absolute top-1/2 -translate-y-1/2 right-1.5 z-10 rounded-full text-Colors-Foreground-Subtle"
|
|
124
|
+
onClick={() => {
|
|
125
|
+
onSearchChange('');
|
|
126
|
+
setValue('');
|
|
127
|
+
onValueChange?.('');
|
|
128
|
+
}}
|
|
129
|
+
size="sm"
|
|
130
|
+
variant="plain"
|
|
131
|
+
icon={XMarkIcon}
|
|
132
|
+
/>
|
|
133
|
+
)}
|
|
134
|
+
</div>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
SearchBar.displayName = 'SearchBar';
|
|
139
|
+
|
|
140
|
+
export { SearchBar };
|