@donglegeyu/ui-core 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.
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+ import { Card as SemiCard, CardProps as SemiCardProps } from '@douyinfe/semi-ui';
3
+
4
+ export interface CardProps extends SemiCardProps {
5
+ /** 卡片标题 */
6
+ title?: string;
7
+ /** 是否显示边框 */
8
+ bordered?: boolean;
9
+ /** 是否悬浮 */
10
+ hoverable?: boolean;
11
+ /** 卡片内容 */
12
+ children?: React.ReactNode;
13
+ /** 卡片操作区 */
14
+ extra?: React.ReactNode;
15
+ }
16
+
17
+ /**
18
+ * 公司 Card 组件
19
+ * 基于 Semi Design Card 二次封装
20
+ */
21
+ export const Card: React.FC<CardProps> = ({
22
+ title,
23
+ bordered = true,
24
+ hoverable = false,
25
+ children,
26
+ extra,
27
+ className,
28
+ style,
29
+ ...restProps
30
+ }) => {
31
+ const classes = [
32
+ 'company-card',
33
+ hoverable ? 'company-card--hoverable' : '',
34
+ className || '',
35
+ ].filter(Boolean).join(' ');
36
+
37
+ return (
38
+ <SemiCard
39
+ title={title}
40
+ bordered={bordered}
41
+ className={classes}
42
+ style={style}
43
+ extra={extra}
44
+ {...restProps}
45
+ >
46
+ {children}
47
+ </SemiCard>
48
+ );
49
+ };
50
+
51
+ Card.displayName = 'Card';
@@ -0,0 +1,2 @@
1
+ export { Card } from './Card';
2
+ export type { CardProps } from './Card';
@@ -0,0 +1,47 @@
1
+ import React from 'react';
2
+ import { Form as SemiForm, FormProps as SemiFormProps, useForm } from '@douyinfe/semi-ui';
3
+
4
+ export interface FormItemProps {
5
+ field: string;
6
+ label: string;
7
+ rules?: Array<{ required?: boolean; message?: string; [key: string]: any }>;
8
+ children: React.ReactNode;
9
+ }
10
+
11
+ export interface FormProps extends Omit<SemiFormProps, 'form'> {
12
+ /** 表单实例 */
13
+ form?: ReturnType<typeof useForm>;
14
+ /** 提交回调 */
15
+ onSubmit?: (values: Record<string, any>) => void;
16
+ /** 表单项 */
17
+ children: React.ReactNode;
18
+ }
19
+
20
+ /**
21
+ * 公司 Form 组件
22
+ * 基于 Semi Design Form 二次封装
23
+ */
24
+ export const Form: React.FC<FormProps> = ({ form, onSubmit, children, layout = 'horizontal', labelPosition = 'left', ...restProps }) => {
25
+ const formApi = form || useForm();
26
+
27
+ const handleSubmit = (values: Record<string, any>, errors: any) => {
28
+ if (!errors && onSubmit) {
29
+ onSubmit(values);
30
+ }
31
+ };
32
+
33
+ return (
34
+ <SemiForm
35
+ form={formApi}
36
+ onSubmit={handleSubmit}
37
+ layout={layout}
38
+ labelPosition={labelPosition}
39
+ {...restProps}
40
+ >
41
+ {children}
42
+ </SemiForm>
43
+ );
44
+ };
45
+
46
+ Form.Item = SemiForm.Input;
47
+ Form.displayName = 'Form';
@@ -0,0 +1,2 @@
1
+ export { Form } from './Form';
2
+ export type { FormProps, FormItemProps } from './Form';
@@ -0,0 +1,47 @@
1
+ import React from 'react';
2
+ import { Input as SemiInput, InputProps as SemiInputProps } from '@douyinfe/semi-ui';
3
+
4
+ export type InputSize = 'small' | 'medium' | 'large';
5
+
6
+ export interface InputProps extends Omit<SemiInputProps, 'size'> {
7
+ /** 输入框尺寸 */
8
+ size?: InputSize;
9
+ /** 是否显示清除按钮 */
10
+ allowClear?: boolean;
11
+ /** 前缀图标 */
12
+ prefix?: React.ReactNode;
13
+ /** 后缀图标 */
14
+ suffix?: React.ReactNode;
15
+ /** 值变化回调 */
16
+ onChange?: (value: string, e: React.ChangeEvent<HTMLInputElement>) => void;
17
+ }
18
+
19
+ /**
20
+ * 公司 Input 组件
21
+ * 基于 Semi Design Input 二次封装
22
+ */
23
+ export const Input: React.FC<InputProps> = React.forwardRef<HTMLInputElement, InputProps>(
24
+ ({ size = 'medium', allowClear = false, prefix, suffix, className, style, ...restProps }, ref) => {
25
+ const semiSize = size === 'small' ? 'small' : size === 'large' ? 'large' : 'default';
26
+
27
+ const classes = [
28
+ 'company-input',
29
+ className || '',
30
+ ].filter(Boolean).join(' ');
31
+
32
+ return (
33
+ <SemiInput
34
+ ref={ref}
35
+ size={semiSize}
36
+ showClear={allowClear}
37
+ prefix={prefix}
38
+ suffix={suffix}
39
+ className={classes}
40
+ style={style}
41
+ {...restProps}
42
+ />
43
+ );
44
+ }
45
+ );
46
+
47
+ Input.displayName = 'Input';
@@ -0,0 +1,2 @@
1
+ export { Input } from './Input';
2
+ export type { InputProps, InputSize } from './Input';
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import { Layout as SemiLayout, Sider, Header, Content, Footer } from '@douyinfe/semi-ui';
3
+
4
+ export interface LayoutProps {
5
+ className?: string;
6
+ style?: React.CSSProperties;
7
+ children: React.ReactNode;
8
+ }
9
+
10
+ /**
11
+ * 公司 Layout 组件
12
+ * 基于 Semi Design Layout 二次封装
13
+ */
14
+ export const Layout: React.FC<LayoutProps> & {
15
+ Sider: typeof Sider;
16
+ Header: typeof Header;
17
+ Content: typeof Content;
18
+ Footer: typeof Footer;
19
+ } = ({ className, style, children }) => {
20
+ return (
21
+ <SemiLayout className={['company-layout', className].filter(Boolean).join(' ')} style={style}>
22
+ {children}
23
+ </SemiLayout>
24
+ );
25
+ };
26
+
27
+ Layout.Sider = Sider;
28
+ Layout.Header = Header;
29
+ Layout.Content = Content;
30
+ Layout.Footer = Footer;
31
+ Layout.displayName = 'Layout';
@@ -0,0 +1,2 @@
1
+ export { Layout } from './Layout';
2
+ export type { LayoutProps } from './Layout';
@@ -0,0 +1,58 @@
1
+ import React from 'react';
2
+ import { Modal as SemiModal, ModalProps as SemiModalProps } from '@douyinfe/semi-ui';
3
+
4
+ export type ModalSize = 'small' | 'medium' | 'large';
5
+
6
+ export interface ModalProps extends Omit<SemiModalProps, 'size'> {
7
+ /** 弹窗尺寸 */
8
+ size?: ModalSize;
9
+ /** 是否显示 */
10
+ visible: boolean;
11
+ /** 标题 */
12
+ title: string;
13
+ /** 确认按钮文字 */
14
+ okText?: string;
15
+ /** 取消按钮文字 */
16
+ cancelText?: string;
17
+ /** 确认回调 */
18
+ onOk?: () => void;
19
+ /** 取消回调 */
20
+ onCancel?: () => void;
21
+ /** 弹窗内容 */
22
+ children?: React.ReactNode;
23
+ }
24
+
25
+ /**
26
+ * 公司 Modal 组件
27
+ * 基于 Semi Design Modal 二次封装
28
+ */
29
+ export const Modal: React.FC<ModalProps> = ({
30
+ visible,
31
+ title,
32
+ okText = '确定',
33
+ cancelText = '取消',
34
+ size = 'medium',
35
+ children,
36
+ onOk,
37
+ onCancel,
38
+ ...restProps
39
+ }) => {
40
+ const semiSize = size === 'small' ? 'small' : size === 'large' ? 'large' : 'default';
41
+
42
+ return (
43
+ <SemiModal
44
+ visible={visible}
45
+ title={title}
46
+ okText={okText}
47
+ cancelText={cancelText}
48
+ size={semiSize}
49
+ onOk={onOk}
50
+ onCancel={onCancel}
51
+ {...restProps}
52
+ >
53
+ {children}
54
+ </SemiModal>
55
+ );
56
+ };
57
+
58
+ Modal.displayName = 'Modal';
@@ -0,0 +1,2 @@
1
+ export { Modal } from './Modal';
2
+ export type { ModalProps, ModalSize } from './Modal';
@@ -0,0 +1,55 @@
1
+ import React from 'react';
2
+ import { Select as SemiSelect, SelectProps as SemiSelectProps } from '@douyinfe/semi-ui';
3
+
4
+ export type SelectSize = 'small' | 'medium' | 'large';
5
+
6
+ export interface SelectProps<T = any> extends Omit<SemiSelectProps, 'size'> {
7
+ /** 选择器尺寸 */
8
+ size?: SelectSize;
9
+ /** 是否显示清除按钮 */
10
+ allowClear?: boolean;
11
+ /** 占位符 */
12
+ placeholder?: string;
13
+ /** 是否多选 */
14
+ multiple?: boolean;
15
+ /** 选项数据 */
16
+ options?: Array<{ label: string; value: T; disabled?: boolean }>;
17
+ /** 值变化回调 */
18
+ onChange?: (value: T | T[], option: any) => void;
19
+ }
20
+
21
+ /**
22
+ * 公司 Select 组件
23
+ * 基于 Semi Design Select 二次封装
24
+ */
25
+ export const Select = React.forwardRef(
26
+ <T = any,>(
27
+ { size = 'medium', allowClear = false, multiple = false, options = [], placeholder, className, style, ...restProps }: SelectProps<T>,
28
+ ref: React.Ref<HTMLDivElement>
29
+ ) => {
30
+ const semiSize = size === 'small' ? 'small' : size === 'large' ? 'large' : 'default';
31
+
32
+ const classes = [
33
+ 'company-select',
34
+ className || '',
35
+ ].filter(Boolean).join(' ');
36
+
37
+ return (
38
+ <SemiSelect
39
+ ref={ref}
40
+ size={semiSize}
41
+ showClear={allowClear}
42
+ multiple={multiple}
43
+ placeholder={placeholder}
44
+ optionList={options}
45
+ className={classes}
46
+ style={style}
47
+ {...restProps}
48
+ />
49
+ );
50
+ }
51
+ ) as <T = any>(
52
+ props: SelectProps<T> & { ref?: React.Ref<HTMLDivElement> }
53
+ ) => React.ReactElement;
54
+
55
+ Select.displayName = 'Select';
@@ -0,0 +1,2 @@
1
+ export { Select } from './Select';
2
+ export type { SelectProps, SelectSize } from './Select';
@@ -0,0 +1,71 @@
1
+ import React from 'react';
2
+ import { Table as SemiTable, TableProps as SemiTableProps } from '@douyinfe/semi-ui';
3
+
4
+ export interface TableColumn<T = any> {
5
+ title: string;
6
+ dataIndex: string;
7
+ key?: string;
8
+ width?: number | string;
9
+ align?: 'left' | 'center' | 'right';
10
+ fixed?: 'left' | 'right';
11
+ sorter?: boolean | ((a: T, b: T) => number);
12
+ render?: (value: any, record: T, index: number) => React.ReactNode;
13
+ }
14
+
15
+ export interface TableProps<T = any> extends Omit<SemiTableProps<T>, 'columns'> {
16
+ /** 列配置 */
17
+ columns: TableColumn<T>[];
18
+ /** 数据源 */
19
+ dataSource: T[];
20
+ /** 是否显示边框 */
21
+ bordered?: boolean;
22
+ /** 是否显示斑马纹 */
23
+ striped?: boolean;
24
+ /** 行选择配置 */
25
+ rowSelection?: {
26
+ type?: 'checkbox' | 'radio';
27
+ selectedRowKeys?: React.Key[];
28
+ onChange?: (selectedRowKeys: React.Key[], selectedRows: T[]) => void;
29
+ };
30
+ /** 分页配置 */
31
+ pagination?: {
32
+ current?: number;
33
+ pageSize?: number;
34
+ total?: number;
35
+ onChange?: (page: number, pageSize: number) => void;
36
+ };
37
+ }
38
+
39
+ /**
40
+ * 公司 Table 组件
41
+ * 基于 Semi Design Table 二次封装
42
+ */
43
+ export const Table = React.forwardRef(
44
+ <T extends Record<string, any> = any,>(
45
+ { columns, dataSource, bordered = true, striped = false, rowSelection, pagination, className, style, ...restProps }: TableProps<T>,
46
+ ref: React.Ref<HTMLDivElement>
47
+ ) => {
48
+ const classes = [
49
+ 'company-table',
50
+ striped ? 'company-table--striped' : '',
51
+ className || '',
52
+ ].filter(Boolean).join(' ');
53
+
54
+ return (
55
+ <div ref={ref} className={classes} style={style}>
56
+ <SemiTable
57
+ columns={columns as SemiTableProps<T>['columns']}
58
+ dataSource={dataSource}
59
+ bordered={bordered}
60
+ rowSelection={rowSelection}
61
+ pagination={pagination}
62
+ {...restProps}
63
+ />
64
+ </div>
65
+ );
66
+ }
67
+ ) as <T extends Record<string, any> = any>(
68
+ props: TableProps<T> & { ref?: React.Ref<HTMLDivElement> }
69
+ ) => React.ReactElement;
70
+
71
+ Table.displayName = 'Table';
@@ -0,0 +1,2 @@
1
+ export { Table } from './Table';
2
+ export type { TableProps, TableColumn } from './Table';
package/src/index.ts ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @company/ui-core - 公司 UI 组件库
3
+ * 基于 Semi Design 二次封装
4
+ */
5
+
6
+ // Theme
7
+ export { CompanyThemeProvider } from './theme/provider';
8
+ export { theme, colorTokens, spacingTokens, borderRadiusTokens, fontSizeTokens, fontWeightTokens, boxShadowTokens, transitionTokens, zIndexTokens } from './theme/tokens';
9
+ export type { Theme, ColorTokens, SpacingTokens } from './theme/tokens';
10
+
11
+ // Components - 基础组件
12
+ export { Button } from './components/Button';
13
+ export type { ButtonProps, ButtonType, ButtonSize } from './components/Button';
14
+
15
+ export { Input } from './components/Input';
16
+ export type { InputProps, InputSize } from './components/Input';
17
+
18
+ export { Select } from './components/Select';
19
+ export type { SelectProps, SelectSize } from './components/Select';
20
+
21
+ export { Table } from './components/Table';
22
+ export type { TableProps, TableColumn } from './components/Table';
23
+
24
+ export { Form } from './components/Form';
25
+ export type { FormProps, FormItemProps } from './components/Form';
26
+
27
+ export { Modal } from './components/Modal';
28
+ export type { ModalProps, ModalSize } from './components/Modal';
29
+
30
+ export { Layout } from './components/Layout';
31
+ export type { LayoutProps } from './components/Layout';
32
+
33
+ export { Card } from './components/Card';
34
+ export type { CardProps } from './components/Card';
@@ -0,0 +1,2 @@
1
+ export { theme, colorTokens, spacingTokens, borderRadiusTokens, fontSizeTokens, fontWeightTokens, boxShadowTokens, transitionTokens, zIndexTokens } from './tokens';
2
+ export type { Theme, ColorTokens, SpacingTokens } from './tokens';
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import { ConfigProvider } from '@douyinfe/semi-ui';
3
+ import { theme } from './tokens';
4
+
5
+ interface CompanyThemeProviderProps {
6
+ children: React.ReactNode;
7
+ }
8
+
9
+ /**
10
+ * 公司主题提供者
11
+ * 将 Design Tokens 注入到 Semi Design 的 ConfigProvider
12
+ */
13
+ export const CompanyThemeProvider: React.FC<CompanyThemeProviderProps> = ({ children }) => {
14
+ const semiTheme = {
15
+ light: {
16
+ '--semi-color-primary': theme.color.primary['500'],
17
+ '--semi-color-primary-hover': theme.color.primary['600'],
18
+ '--semi-color-primary-active': theme.color.primary['700'],
19
+ '--semi-color-primary-disabled': theme.color.primary['300'],
20
+ '--semi-color-success': theme.color.success.DEFAULT,
21
+ '--semi-color-warning': theme.color.warning.DEFAULT,
22
+ '--semi-color-danger': theme.color.error.DEFAULT,
23
+ '--semi-color-info': theme.color.info.DEFAULT,
24
+ },
25
+ };
26
+
27
+ return (
28
+ <ConfigProvider theme={semiTheme}>
29
+ {children}
30
+ </ConfigProvider>
31
+ );
32
+ };
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Design Tokens - 公司设计规范
3
+ * 所有样式变量集中管理,AI 只需调用组件,无需写样式
4
+ */
5
+
6
+ export const colorTokens = {
7
+ // 主色系
8
+ primary: {
9
+ 50: '#e6f7ff',
10
+ 100: '#bae7ff',
11
+ 200: '#91d5ff',
12
+ 300: '#69c0ff',
13
+ 400: '#40a9ff',
14
+ 500: '#1677ff', // 主色
15
+ 600: '#0958d9',
16
+ 700: '#003eb3',
17
+ 800: '#002c8c',
18
+ 900: '#001d66',
19
+ },
20
+ // 语义色
21
+ success: {
22
+ light: '#f6ffed',
23
+ DEFAULT: '#52c41a',
24
+ dark: '#389e0d',
25
+ },
26
+ warning: {
27
+ light: '#fffbe6',
28
+ DEFAULT: '#faad14',
29
+ dark: '#d48806',
30
+ },
31
+ error: {
32
+ light: '#fff2f0',
33
+ DEFAULT: '#ff4d4f',
34
+ dark: '#cf1322',
35
+ },
36
+ info: {
37
+ light: '#e6f7ff',
38
+ DEFAULT: '#1677ff',
39
+ dark: '#0958d9',
40
+ },
41
+ // 中性色
42
+ neutral: {
43
+ 50: '#ffffff',
44
+ 100: '#fafafa',
45
+ 200: '#f5f5f5',
46
+ 300: '#f0f0f0',
47
+ 400: '#d9d9d9',
48
+ 500: '#bfbfbf',
49
+ 600: '#8c8c8c',
50
+ 700: '#595959',
51
+ 800: '#434343',
52
+ 900: '#262626',
53
+ 950: '#141414',
54
+ },
55
+ } as const;
56
+
57
+ export const spacingTokens = {
58
+ xs: '4px',
59
+ sm: '8px',
60
+ md: '16px',
61
+ lg: '24px',
62
+ xl: '32px',
63
+ '2xl': '48px',
64
+ '3xl': '64px',
65
+ } as const;
66
+
67
+ export const borderRadiusTokens = {
68
+ none: '0',
69
+ sm: '4px',
70
+ md: '8px',
71
+ lg: '12px',
72
+ xl: '16px',
73
+ full: '9999px',
74
+ } as const;
75
+
76
+ export const fontSizeTokens = {
77
+ xs: '12px',
78
+ sm: '14px',
79
+ md: '16px',
80
+ lg: '18px',
81
+ xl: '20px',
82
+ '2xl': '24px',
83
+ '3xl': '30px',
84
+ '4xl': '36px',
85
+ } as const;
86
+
87
+ export const fontWeightTokens = {
88
+ light: 300,
89
+ normal: 400,
90
+ medium: 500,
91
+ semibold: 600,
92
+ bold: 700,
93
+ } as const;
94
+
95
+ export const boxShadowTokens = {
96
+ sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
97
+ md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
98
+ lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
99
+ xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
100
+ } as const;
101
+
102
+ export const transitionTokens = {
103
+ fast: '150ms ease',
104
+ base: '200ms ease',
105
+ slow: '300ms ease',
106
+ } as const;
107
+
108
+ export const zIndexTokens = {
109
+ dropdown: 1000,
110
+ sticky: 1020,
111
+ fixed: 1030,
112
+ modalBackdrop: 1040,
113
+ modal: 1050,
114
+ popover: 1060,
115
+ tooltip: 1070,
116
+ } as const;
117
+
118
+ // 导出完整 theme 对象
119
+ export const theme = {
120
+ color: colorTokens,
121
+ spacing: spacingTokens,
122
+ borderRadius: borderRadiusTokens,
123
+ fontSize: fontSizeTokens,
124
+ fontWeight: fontWeightTokens,
125
+ boxShadow: boxShadowTokens,
126
+ transition: transitionTokens,
127
+ zIndex: zIndexTokens,
128
+ } as const;
129
+
130
+ export type Theme = typeof theme;
131
+ export type ColorTokens = typeof colorTokens;
132
+ export type SpacingTokens = typeof spacingTokens;
package/tsconfig.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+ "moduleResolution": "bundler",
9
+ "allowImportingTsExtensions": true,
10
+ "resolveJsonModule": true,
11
+ "isolatedModules": true,
12
+ "noEmit": true,
13
+ "jsx": "react-jsx",
14
+ "strict": false,
15
+ "noUnusedLocals": false,
16
+ "noUnusedParameters": false,
17
+ "noFallthroughCasesInSwitch": true,
18
+ "declaration": true,
19
+ "declarationDir": "./dist",
20
+ "baseUrl": ".",
21
+ "paths": {
22
+ "@/*": ["./src/*"]
23
+ }
24
+ },
25
+ "include": ["src"],
26
+ "exclude": ["node_modules", "dist", "**/*.test.tsx"]
27
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,39 @@
1
+ import { defineConfig } from 'vite';
2
+ import react from '@vitejs/plugin-react';
3
+ import { resolve } from 'path';
4
+ import dts from 'rollup-plugin-dts';
5
+
6
+ export default defineConfig({
7
+ plugins: [react()],
8
+ build: {
9
+ lib: {
10
+ entry: {
11
+ index: resolve(__dirname, 'src/index.ts'),
12
+ 'theme/index': resolve(__dirname, 'src/theme/index.ts'),
13
+ },
14
+ formats: ['es', 'cjs'],
15
+ fileName: (format, entryName) => {
16
+ const ext = format === 'es' ? 'esm.js' : 'cjs.js';
17
+ return `${entryName}.${ext}`;
18
+ },
19
+ },
20
+ rollupOptions: {
21
+ external: ['react', 'react-dom', '@douyinfe/semi-ui', '@douyinfe/semi-icons'],
22
+ output: {
23
+ globals: {
24
+ react: 'React',
25
+ 'react-dom': 'ReactDOM',
26
+ '@douyinfe/semi-ui': 'SemiUI',
27
+ '@douyinfe/semi-icons': 'SemiIcons',
28
+ },
29
+ },
30
+ },
31
+ sourcemap: true,
32
+ minify: false,
33
+ },
34
+ resolve: {
35
+ alias: {
36
+ '@': resolve(__dirname, 'src'),
37
+ },
38
+ },
39
+ });