@sunggang/ui-lib 0.0.4 → 0.0.5
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/.eslintrc.json +18 -0
- package/.storybook/main.js +14 -0
- package/.storybook/preview.js +1 -0
- package/.storybook/tailwind-imports.css +81 -0
- package/components.json +15 -0
- package/package.json +8 -4
- package/postcss.config.js +10 -0
- package/project.json +31 -0
- package/src/components/ui/switch.tsx +27 -0
- package/src/index.ts +7 -0
- package/src/lib/DropImage/index.stories.tsx +42 -0
- package/src/lib/DropImage/index.tsx +110 -0
- package/src/lib/Modal/BaseModal.jsx +52 -0
- package/src/lib/Modal/ErrorContent.tsx +21 -0
- package/src/lib/Modal/FullScreenModal.jsx +39 -0
- package/src/lib/Modal/Modal.tsx +36 -0
- package/src/lib/Modal/ModalContent.tsx +60 -0
- package/src/lib/Modal/NoticeModal.jsx +91 -0
- package/src/lib/Modal/index.jsx +1 -0
- package/src/lib/Spin/index.tsx +20 -0
- package/src/lib/Switch/index.stories.tsx +24 -0
- package/src/lib/UploadImage/BaseTemplate.tsx +73 -0
- package/src/lib/UploadImage/CustomUpload.stories.tsx +52 -0
- package/src/lib/UploadImage/CustomUpload.tsx +95 -0
- package/src/lib/hello-server.tsx +4 -0
- package/src/lib/uiLibrary.spec.tsx +10 -0
- package/src/lib/uiLibrary.tsx +14 -0
- package/src/lib/utils.ts +6 -0
- package/src/server.ts +2 -0
- package/storybook-static/249.d700bcb8.iframe.bundle.js +95 -0
- package/storybook-static/249.d700bcb8.iframe.bundle.js.LICENSE.txt +25 -0
- package/storybook-static/249.d700bcb8.iframe.bundle.js.map +1 -0
- package/storybook-static/272.859c45b5.iframe.bundle.js +1 -0
- package/storybook-static/297.86b29044.iframe.bundle.js +1 -0
- package/storybook-static/301.7b83a51f.iframe.bundle.js +1 -0
- package/storybook-static/311.5beb2d3d.iframe.bundle.js +1 -0
- package/storybook-static/312.aa18d841.iframe.bundle.js +1 -0
- package/storybook-static/501.1fba3663.iframe.bundle.js +1 -0
- package/storybook-static/754.9ec23ac4.iframe.bundle.js +1 -0
- package/storybook-static/777.4b1d90f9.iframe.bundle.js +1 -0
- package/storybook-static/794.2230a3f3.iframe.bundle.js +1 -0
- package/storybook-static/852.18487f4c.iframe.bundle.js +402 -0
- package/storybook-static/852.18487f4c.iframe.bundle.js.LICENSE.txt +23 -0
- package/storybook-static/852.18487f4c.iframe.bundle.js.map +1 -0
- package/storybook-static/DropImage-index-stories.befa1b35.iframe.bundle.js +1 -0
- package/storybook-static/Switch-index-stories.9cfb2ba1.iframe.bundle.js +1 -0
- package/storybook-static/UploadImage-CustomUpload-stories.521444aa.iframe.bundle.js +1 -0
- package/storybook-static/favicon.svg +7 -0
- package/storybook-static/iframe.html +370 -0
- package/storybook-static/index.html +151 -0
- package/storybook-static/index.json +1 -0
- package/storybook-static/main.6f3c811b.iframe.bundle.js +1 -0
- package/storybook-static/project.json +1 -0
- package/storybook-static/runtime~main.28408b82.iframe.bundle.js +1 -0
- package/storybook-static/sb-addons/essentials-actions-2/manager-bundle.js +3 -0
- package/storybook-static/sb-addons/essentials-actions-2/manager-bundle.js.LEGAL.txt +0 -0
- package/storybook-static/sb-addons/essentials-backgrounds-3/manager-bundle.js +12 -0
- package/storybook-static/sb-addons/essentials-backgrounds-3/manager-bundle.js.LEGAL.txt +0 -0
- package/storybook-static/sb-addons/essentials-controls-1/manager-bundle.js +79 -0
- package/storybook-static/sb-addons/essentials-controls-1/manager-bundle.js.LEGAL.txt +28 -0
- package/storybook-static/sb-addons/essentials-measure-6/manager-bundle.js +3 -0
- package/storybook-static/sb-addons/essentials-measure-6/manager-bundle.js.LEGAL.txt +0 -0
- package/storybook-static/sb-addons/essentials-outline-7/manager-bundle.js +3 -0
- package/storybook-static/sb-addons/essentials-outline-7/manager-bundle.js.LEGAL.txt +0 -0
- package/storybook-static/sb-addons/essentials-toolbars-5/manager-bundle.js +3 -0
- package/storybook-static/sb-addons/essentials-toolbars-5/manager-bundle.js.LEGAL.txt +0 -0
- package/storybook-static/sb-addons/essentials-viewport-4/manager-bundle.js +3 -0
- package/storybook-static/sb-addons/essentials-viewport-4/manager-bundle.js.LEGAL.txt +0 -0
- package/storybook-static/sb-addons/storybook-core-server-presets-0/common-manager-bundle.js +3 -0
- package/storybook-static/sb-addons/storybook-core-server-presets-0/common-manager-bundle.js.LEGAL.txt +0 -0
- package/storybook-static/sb-common-assets/fonts.css +31 -0
- package/storybook-static/sb-common-assets/nunito-sans-bold-italic.woff2 +0 -0
- package/storybook-static/sb-common-assets/nunito-sans-bold.woff2 +0 -0
- package/storybook-static/sb-common-assets/nunito-sans-italic.woff2 +0 -0
- package/storybook-static/sb-common-assets/nunito-sans-regular.woff2 +0 -0
- package/storybook-static/sb-manager/WithTooltip-Y7J54OF7-KHQOWZXS.js +1 -0
- package/storybook-static/sb-manager/chunk-3F3RRPB3.js +347 -0
- package/storybook-static/sb-manager/chunk-62YMTM65.js +6 -0
- package/storybook-static/sb-manager/chunk-AQBE2B7B.js +183 -0
- package/storybook-static/sb-manager/chunk-Q3RBXCN3.js +231 -0
- package/storybook-static/sb-manager/chunk-XP3HGWTR.js +1 -0
- package/storybook-static/sb-manager/chunk-YME6VNXZ.js +9 -0
- package/storybook-static/sb-manager/formatter-B5HCVTEV-7DCBOGO6.js +58 -0
- package/storybook-static/sb-manager/globals-module-info.js +1 -0
- package/storybook-static/sb-manager/globals-runtime.js +1 -0
- package/storybook-static/sb-manager/globals.js +1 -0
- package/storybook-static/sb-manager/index.js +1 -0
- package/storybook-static/sb-manager/runtime.js +1 -0
- package/storybook-static/sb-manager/syntaxhighlighter-JOJW2KGS-WAFIMSO6.js +1 -0
- package/storybook-static/sb-preview/globals.js +1 -0
- package/storybook-static/sb-preview/runtime.js +128 -0
- package/tailwind.config.js +76 -0
- package/tsconfig.json +25 -0
- package/tsconfig.lib.json +29 -0
- package/tsconfig.storybook.json +31 -0
- package/index.esm.d.ts +0 -1
- package/index.esm.js +0 -5755
- package/src/index.d.ts +0 -4
- package/src/lib/DropImage/index.d.ts +0 -14
- package/src/lib/Modal/ErrorContent.d.ts +0 -7
- package/src/lib/Modal/Modal.d.ts +0 -7
- package/src/lib/Modal/ModalContent.d.ts +0 -10
- package/src/lib/Spin/index.d.ts +0 -5
- package/src/lib/UploadImage/BaseTemplate.d.ts +0 -7
- package/src/lib/UploadImage/CustomUpload.d.ts +0 -10
- package/src/lib/hello-server.d.ts +0 -1
- package/src/lib/uiLibrary.d.ts +0 -4
- package/src/server.d.ts +0 -1
- /package/{index.esm.css → src/lib/uiLibrary.module.css} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Modal';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function Spin(props: {
|
|
2
|
+
show: boolean;
|
|
3
|
+
overlayBackground?: 'bg-[#00000055]' | undefined;
|
|
4
|
+
}) {
|
|
5
|
+
const { show, overlayBackground = 'bg-[#00000055]' } = props;
|
|
6
|
+
return show ? (
|
|
7
|
+
<div
|
|
8
|
+
className={[
|
|
9
|
+
'fixed flex justify-center items-center w-full h-full left-0 top-0 z-[9999] overflow-hidden',
|
|
10
|
+
overlayBackground,
|
|
11
|
+
].join(' ')}
|
|
12
|
+
>
|
|
13
|
+
<div className="top-2/4 left-2/4">
|
|
14
|
+
<div className="w-10 h-10 rounded-full border-4 border-solid border-[#ffffff33] border-t-[#dbdbdb] animate-spin" />
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
) : null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default Spin;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Meta, StoryFn } from '@storybook/react';
|
|
2
|
+
import { Switch } from '../../components/ui/switch';
|
|
3
|
+
|
|
4
|
+
interface SwitchProps {
|
|
5
|
+
id?: string;
|
|
6
|
+
onCheckedChange?: () => void;
|
|
7
|
+
disabled: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
component: Switch,
|
|
12
|
+
title: 'Switch',
|
|
13
|
+
} as Meta;
|
|
14
|
+
|
|
15
|
+
const Template: StoryFn<SwitchProps> = (args) => {
|
|
16
|
+
return <Switch {...args} />;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const Base = Template.bind({});
|
|
20
|
+
Base.args = {
|
|
21
|
+
id: 'ad-123',
|
|
22
|
+
onCheckedChange: () => ({}),
|
|
23
|
+
disabled: false,
|
|
24
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { useState, useEffect, FC } from 'react';
|
|
2
|
+
import { Icon } from '@iconify/react';
|
|
3
|
+
|
|
4
|
+
interface BaseTemplateProps {
|
|
5
|
+
file?: File | null;
|
|
6
|
+
imageUrl?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const BaseTemplate: FC<BaseTemplateProps> = ({ file, imageUrl }) => {
|
|
10
|
+
const [tempImage, setTempImage] = useState<string | null>(null);
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
let fileReader: FileReader | null;
|
|
14
|
+
let isCancel = false;
|
|
15
|
+
|
|
16
|
+
if (file) {
|
|
17
|
+
fileReader = new FileReader();
|
|
18
|
+
fileReader.onload = (e) => {
|
|
19
|
+
const { result } = e.target as FileReader;
|
|
20
|
+
if (result && !isCancel) {
|
|
21
|
+
setTempImage(result.toString());
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
fileReader.readAsDataURL(file);
|
|
25
|
+
}
|
|
26
|
+
return () => {
|
|
27
|
+
setTempImage(null);
|
|
28
|
+
isCancel = true;
|
|
29
|
+
if (fileReader && fileReader.readyState === 1) {
|
|
30
|
+
fileReader.abort();
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}, [file]);
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div className="max-w-sm mx-auto bg-white rounded-lg shadow-md overflow-hidden items-center">
|
|
37
|
+
<div className="px-4 py-6 w-72 h-56">
|
|
38
|
+
{tempImage || imageUrl ? (
|
|
39
|
+
<img
|
|
40
|
+
className="w-full h-full object-contain border-dashed border-2 border-gray-400 p-6 rounded-lg"
|
|
41
|
+
src={tempImage || imageUrl}
|
|
42
|
+
alt=""
|
|
43
|
+
/>
|
|
44
|
+
) : (
|
|
45
|
+
<div
|
|
46
|
+
id="image-preview"
|
|
47
|
+
className="max-w-sm p-6 bg-gray-100 border-dashed border-2 border-gray-400 rounded-lg items-center mx-auto text-center cursor-pointer"
|
|
48
|
+
>
|
|
49
|
+
<div className="cursor-pointer">
|
|
50
|
+
<div className="flex justify-center">
|
|
51
|
+
<Icon
|
|
52
|
+
icon="material-symbols:upload"
|
|
53
|
+
width="2.5rem"
|
|
54
|
+
height="2.5rem"
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<p className="font-normal text-sm text-gray-400 py-4">
|
|
59
|
+
圖片僅支援 png、jpg、jpeg
|
|
60
|
+
</p>
|
|
61
|
+
|
|
62
|
+
<h5 className="mb-2 text-xl font-bold tracking-tight text-gray-700">
|
|
63
|
+
上傳圖片
|
|
64
|
+
</h5>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
)}
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export default BaseTemplate;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import type { Meta, StoryFn } from '@storybook/react';
|
|
3
|
+
import { CustomUpload } from './CustomUpload';
|
|
4
|
+
|
|
5
|
+
interface CustomUploadProps {
|
|
6
|
+
file?: File | null;
|
|
7
|
+
setFile?: any;
|
|
8
|
+
imageUrl?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
component: CustomUpload,
|
|
13
|
+
title: 'CustomUpload',
|
|
14
|
+
} as Meta;
|
|
15
|
+
|
|
16
|
+
const demoIcon =
|
|
17
|
+
'https://gobobook.s3.ap-northeast-1.amazonaws.com/regions/DEV/vaadin_golf.svg';
|
|
18
|
+
|
|
19
|
+
const Template: StoryFn<CustomUploadProps> = (args) => {
|
|
20
|
+
const [file, setFile] = useState(null);
|
|
21
|
+
return <CustomUpload {...args} file={file} setFile={setFile} />;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const CustomerTemplate: StoryFn<CustomUploadProps> = (args) => {
|
|
25
|
+
const [file, setFile] = useState(null);
|
|
26
|
+
return (
|
|
27
|
+
<CustomUpload {...args} file={file} setFile={setFile}>
|
|
28
|
+
<div className="border border-solid border-gray-400 p-4">
|
|
29
|
+
<div>圖片僅支援 png、jpg、jpeg</div>
|
|
30
|
+
<div>點擊上傳</div>
|
|
31
|
+
</div>
|
|
32
|
+
</CustomUpload>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const Base = Template.bind({});
|
|
37
|
+
Base.args = {
|
|
38
|
+
file: null,
|
|
39
|
+
setFile: () => {
|
|
40
|
+
return;
|
|
41
|
+
},
|
|
42
|
+
imageUrl: demoIcon,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const Customer = CustomerTemplate.bind({});
|
|
46
|
+
Customer.args = {
|
|
47
|
+
file: null,
|
|
48
|
+
setFile: () => {
|
|
49
|
+
return;
|
|
50
|
+
},
|
|
51
|
+
imageUrl: '',
|
|
52
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import React, { useState, useRef, ChangeEvent } from 'react';
|
|
2
|
+
import ErrorContent from '../Modal/ErrorContent';
|
|
3
|
+
import Modal from '../Modal';
|
|
4
|
+
import BaseTemplate from './BaseTemplate';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
interface CustomUploadProps {
|
|
8
|
+
className?: string;
|
|
9
|
+
children?: React.ReactNode;
|
|
10
|
+
file?: File | null;
|
|
11
|
+
setFile?: any;
|
|
12
|
+
imageUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const CustomUpload: React.FC<CustomUploadProps> = ({
|
|
16
|
+
className,
|
|
17
|
+
children,
|
|
18
|
+
file,
|
|
19
|
+
setFile,
|
|
20
|
+
imageUrl,
|
|
21
|
+
}) => {
|
|
22
|
+
const imageMimeType = /image\/(png|jpg|jpeg)/i;
|
|
23
|
+
const DEFAULT_IMAGE_SIZE_LIMIT_IN_BYTES = 5120000; // 5000 KB
|
|
24
|
+
|
|
25
|
+
const [modal, setModal] = useState<React.ReactNode | null>(null);
|
|
26
|
+
|
|
27
|
+
const hiddenFileInput = useRef<HTMLInputElement | null>(null);
|
|
28
|
+
|
|
29
|
+
const handleImageClick = () => {
|
|
30
|
+
hiddenFileInput.current?.click();
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const handleImageChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
34
|
+
const currentFile = event.target.files?.[0];
|
|
35
|
+
|
|
36
|
+
if (!currentFile) {
|
|
37
|
+
setFile(null);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (currentFile && !currentFile.type?.match(imageMimeType)) {
|
|
42
|
+
setModal(
|
|
43
|
+
<ErrorContent setModal={setModal} errmsg="圖片僅支援 png、jpg、jpeg!" />
|
|
44
|
+
);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (currentFile && currentFile.size > DEFAULT_IMAGE_SIZE_LIMIT_IN_BYTES) {
|
|
49
|
+
setModal(
|
|
50
|
+
<ErrorContent
|
|
51
|
+
setModal={setModal}
|
|
52
|
+
errmsg={
|
|
53
|
+
<span>
|
|
54
|
+
選擇的檔案大小:
|
|
55
|
+
{String((currentFile.size / 1024 / 1024).toFixed(3))}
|
|
56
|
+
{' MB'}
|
|
57
|
+
<br />
|
|
58
|
+
<hr />
|
|
59
|
+
上限:
|
|
60
|
+
{String(
|
|
61
|
+
(DEFAULT_IMAGE_SIZE_LIMIT_IN_BYTES / 1024 / 1024).toFixed(3)
|
|
62
|
+
)}
|
|
63
|
+
{' MB'}
|
|
64
|
+
</span>
|
|
65
|
+
}
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
setFile(currentFile);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<>
|
|
76
|
+
<button
|
|
77
|
+
className={className ? [className].join(' ') : ''}
|
|
78
|
+
type="button"
|
|
79
|
+
onClick={handleImageClick}
|
|
80
|
+
>
|
|
81
|
+
{children || <BaseTemplate file={file} imageUrl={imageUrl} />}
|
|
82
|
+
<input
|
|
83
|
+
type="file"
|
|
84
|
+
ref={hiddenFileInput}
|
|
85
|
+
accept=".png, .jpg, .jpeg"
|
|
86
|
+
onChange={handleImageChange}
|
|
87
|
+
className="hidden"
|
|
88
|
+
/>
|
|
89
|
+
</button>
|
|
90
|
+
{modal && <Modal modal={modal} unsetModal={setModal} />}
|
|
91
|
+
</>
|
|
92
|
+
);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export default CustomUpload;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { render } from '@testing-library/react';
|
|
2
|
+
|
|
3
|
+
import UiLibrary from './uiLibrary';
|
|
4
|
+
|
|
5
|
+
describe('UiLibrary', () => {
|
|
6
|
+
it('should render successfully', () => {
|
|
7
|
+
const { baseElement } = render(<UiLibrary />);
|
|
8
|
+
expect(baseElement).toBeTruthy();
|
|
9
|
+
});
|
|
10
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import styles from './uiLibrary.module.css';
|
|
2
|
+
|
|
3
|
+
/* eslint-disable-next-line */
|
|
4
|
+
export interface UiLibraryProps {}
|
|
5
|
+
|
|
6
|
+
export function UiLibrary(props: UiLibraryProps) {
|
|
7
|
+
return (
|
|
8
|
+
<div className={styles['container']}>
|
|
9
|
+
<h1>Welcome to UiLibrary!</h1>
|
|
10
|
+
</div>
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default UiLibrary;
|
package/src/lib/utils.ts
ADDED
package/src/server.ts
ADDED