onchain-lexical-ui 0.0.1
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 +5 -0
- package/package.json +221 -0
- package/src/Button.module.less +36 -0
- package/src/Button.tsx +50 -0
- package/src/ColorPicker.module.less +89 -0
- package/src/ColorPicker.tsx +369 -0
- package/src/ContentEditable.module.less +78 -0
- package/src/ContentEditable.tsx +41 -0
- package/src/Dialog.module.less +23 -0
- package/src/Dialog.tsx +34 -0
- package/src/DropDown.module.less +95 -0
- package/src/DropDown.tsx +267 -0
- package/src/DropdownColorPicker.tsx +41 -0
- package/src/EditorShellStyles/index.module.less +43 -0
- package/src/EditorShellStyles/index.tsx +18 -0
- package/src/EquationEditor.module.less +41 -0
- package/src/EquationEditor.tsx +49 -0
- package/src/ExcalidrawModal.module.less +62 -0
- package/src/ExcalidrawModal.tsx +252 -0
- package/src/FileInput.tsx +40 -0
- package/src/FlashMessage.module.less +28 -0
- package/src/FlashMessage.tsx +31 -0
- package/src/Icon/index.module.less +4 -0
- package/src/Icon/index.tsx +32 -0
- package/src/ImageResizer.tsx +317 -0
- package/src/Input.module.less +38 -0
- package/src/KatexEquationAlterer.module.less +41 -0
- package/src/KatexEquationAlterer.tsx +84 -0
- package/src/KatexRenderer.tsx +73 -0
- package/src/Modal.module.less +65 -0
- package/src/Modal.tsx +176 -0
- package/src/Select.module.less +41 -0
- package/src/Select.tsx +37 -0
- package/src/Skeleton.module.less +67 -0
- package/src/Skeleton.tsx +28 -0
- package/src/Switch.tsx +38 -0
- package/src/TextInput.tsx +48 -0
- package/src/utils/joinClasses.ts +13 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
@import './const.less';
|
|
10
|
+
|
|
11
|
+
.Input__wrapper {
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: row;
|
|
14
|
+
align-items: center;
|
|
15
|
+
margin-bottom: 10px;
|
|
16
|
+
}
|
|
17
|
+
.Input__label {
|
|
18
|
+
display: flex;
|
|
19
|
+
flex: 1;
|
|
20
|
+
color: #666;
|
|
21
|
+
}
|
|
22
|
+
.Input__input {
|
|
23
|
+
display: flex;
|
|
24
|
+
flex: 2;
|
|
25
|
+
border: 1px solid #999;
|
|
26
|
+
padding-top: 7px;
|
|
27
|
+
padding-bottom: 7px;
|
|
28
|
+
padding-left: 10px;
|
|
29
|
+
padding-right: 10px;
|
|
30
|
+
font-size: 16px;
|
|
31
|
+
border-radius: 0px;
|
|
32
|
+
min-width: 0;
|
|
33
|
+
height: @inputHeight;
|
|
34
|
+
&:focus-visible {
|
|
35
|
+
outline: none;
|
|
36
|
+
border-color: @themeColor;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
.KatexEquationAlterer_defaultRow {
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: row;
|
|
13
|
+
margin-top: 10px;
|
|
14
|
+
margin-bottom: 10px;
|
|
15
|
+
justify-content: space-between;
|
|
16
|
+
overflow: hidden;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.KatexEquationAlterer_dialogActions {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: row;
|
|
22
|
+
overflow: hidden;
|
|
23
|
+
margin-top: 20px;
|
|
24
|
+
margin-bottom: 0;
|
|
25
|
+
justify-content: right;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.KatexEquationAlterer_centerRow {
|
|
29
|
+
display: flex;
|
|
30
|
+
flex-direction: 'row';
|
|
31
|
+
margin-top: 10px;
|
|
32
|
+
margin-bottom: 10px;
|
|
33
|
+
justify-content: center;
|
|
34
|
+
overflow: hidden;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.KatexEquationAlterer_textArea {
|
|
38
|
+
width: 100%;
|
|
39
|
+
resize: none;
|
|
40
|
+
padding: 7px;
|
|
41
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {JSX} from 'react';
|
|
10
|
+
|
|
11
|
+
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
|
12
|
+
import * as React from 'react';
|
|
13
|
+
import {useCallback, useState} from 'react';
|
|
14
|
+
import {ErrorBoundary} from 'react-error-boundary';
|
|
15
|
+
|
|
16
|
+
import Button from './Button';
|
|
17
|
+
import Styles from './KatexEquationAlterer.module.less';
|
|
18
|
+
import KatexRenderer from './KatexRenderer';
|
|
19
|
+
|
|
20
|
+
type Props = {
|
|
21
|
+
initialEquation?: string;
|
|
22
|
+
onConfirm: (equation: string, inline: boolean) => void;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default function KatexEquationAlterer({
|
|
26
|
+
onConfirm,
|
|
27
|
+
initialEquation = '',
|
|
28
|
+
}: Props): JSX.Element {
|
|
29
|
+
const [editor] = useLexicalComposerContext();
|
|
30
|
+
const [equation, setEquation] = useState<string>(initialEquation);
|
|
31
|
+
const [inline, setInline] = useState<boolean>(true);
|
|
32
|
+
|
|
33
|
+
const onClick = useCallback(() => {
|
|
34
|
+
onConfirm(equation, inline);
|
|
35
|
+
}, [onConfirm, equation, inline]);
|
|
36
|
+
|
|
37
|
+
const onCheckboxChange = useCallback(() => {
|
|
38
|
+
setInline(!inline);
|
|
39
|
+
}, [setInline, inline]);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<>
|
|
43
|
+
<div className={Styles.KatexEquationAlterer_defaultRow}>
|
|
44
|
+
Inline
|
|
45
|
+
<input type="checkbox" checked={inline} onChange={onCheckboxChange} />
|
|
46
|
+
</div>
|
|
47
|
+
<div className={Styles.KatexEquationAlterer_defaultRow}>Equation </div>
|
|
48
|
+
<div className={Styles.KatexEquationAlterer_centerRow}>
|
|
49
|
+
{inline ? (
|
|
50
|
+
<input
|
|
51
|
+
onChange={(event) => {
|
|
52
|
+
setEquation(event.target.value);
|
|
53
|
+
}}
|
|
54
|
+
value={equation}
|
|
55
|
+
className={Styles.KatexEquationAlterer_textArea}
|
|
56
|
+
/>
|
|
57
|
+
) : (
|
|
58
|
+
<textarea
|
|
59
|
+
onChange={(event) => {
|
|
60
|
+
setEquation(event.target.value);
|
|
61
|
+
}}
|
|
62
|
+
value={equation}
|
|
63
|
+
className={Styles.KatexEquationAlterer_textArea}
|
|
64
|
+
/>
|
|
65
|
+
)}
|
|
66
|
+
</div>
|
|
67
|
+
<div className={Styles.KatexEquationAlterer_defaultRow}>
|
|
68
|
+
Visualization{' '}
|
|
69
|
+
</div>
|
|
70
|
+
<div className={Styles.KatexEquationAlterer_centerRow}>
|
|
71
|
+
<ErrorBoundary onError={(e) => editor._onError(e)} fallback={null}>
|
|
72
|
+
<KatexRenderer
|
|
73
|
+
equation={equation}
|
|
74
|
+
inline={false}
|
|
75
|
+
onDoubleClick={() => null}
|
|
76
|
+
/>
|
|
77
|
+
</ErrorBoundary>
|
|
78
|
+
</div>
|
|
79
|
+
<div className={Styles.KatexEquationAlterer_dialogActions}>
|
|
80
|
+
<Button onClick={onClick}>Confirm</Button>
|
|
81
|
+
</div>
|
|
82
|
+
</>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {JSX} from 'react';
|
|
10
|
+
|
|
11
|
+
import katex from 'katex';
|
|
12
|
+
import * as React from 'react';
|
|
13
|
+
import {useEffect, useRef} from 'react';
|
|
14
|
+
|
|
15
|
+
export default function KatexRenderer({
|
|
16
|
+
equation,
|
|
17
|
+
inline,
|
|
18
|
+
height,
|
|
19
|
+
onDoubleClick,
|
|
20
|
+
}: Readonly<{
|
|
21
|
+
equation: string;
|
|
22
|
+
inline: boolean;
|
|
23
|
+
height?: React.CSSProperties['height'];
|
|
24
|
+
onDoubleClick: () => void;
|
|
25
|
+
}>): JSX.Element {
|
|
26
|
+
const katexElementRef = useRef(null);
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
const katexElement = katexElementRef.current;
|
|
30
|
+
|
|
31
|
+
if (katexElement !== null) {
|
|
32
|
+
katex.render(equation, katexElement, {
|
|
33
|
+
displayMode: !inline, // true === block display //
|
|
34
|
+
errorColor: '#cc0000',
|
|
35
|
+
output: 'html',
|
|
36
|
+
strict: 'warn',
|
|
37
|
+
throwOnError: false,
|
|
38
|
+
trust: false,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}, [equation, inline]);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
// We use an empty image tag either side to ensure Android doesn't try and compose from the
|
|
45
|
+
// inner text from Katex. There didn't seem to be any other way of making this work,
|
|
46
|
+
// without having a physical space.
|
|
47
|
+
<>
|
|
48
|
+
<img
|
|
49
|
+
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
|
50
|
+
width="0"
|
|
51
|
+
height="0"
|
|
52
|
+
alt=""
|
|
53
|
+
/>
|
|
54
|
+
<span
|
|
55
|
+
role="button"
|
|
56
|
+
tabIndex={-1}
|
|
57
|
+
onDoubleClick={onDoubleClick}
|
|
58
|
+
ref={katexElementRef}
|
|
59
|
+
style={{
|
|
60
|
+
display: 'inline-block',
|
|
61
|
+
height,
|
|
62
|
+
width: !inline ? '100%' : undefined,
|
|
63
|
+
}}
|
|
64
|
+
/>
|
|
65
|
+
<img
|
|
66
|
+
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
|
67
|
+
width="0"
|
|
68
|
+
height="0"
|
|
69
|
+
alt=""
|
|
70
|
+
/>
|
|
71
|
+
</>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
@import './const.less';
|
|
10
|
+
|
|
11
|
+
.Modal__overlay {
|
|
12
|
+
display: flex;
|
|
13
|
+
justify-content: center;
|
|
14
|
+
align-items: center;
|
|
15
|
+
position: fixed;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
top: 0px;
|
|
18
|
+
bottom: 0px;
|
|
19
|
+
left: 0px;
|
|
20
|
+
right: 0px;
|
|
21
|
+
background-color: transparent;
|
|
22
|
+
flex-grow: 0px;
|
|
23
|
+
flex-shrink: 1px;
|
|
24
|
+
z-index: 999;
|
|
25
|
+
}
|
|
26
|
+
.Modal__modal {
|
|
27
|
+
min-height: 100px;
|
|
28
|
+
min-width: 300px;
|
|
29
|
+
display: flex;
|
|
30
|
+
flex-grow: 0px;
|
|
31
|
+
background-color: #fff;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
position: relative;
|
|
34
|
+
box-shadow: 0 0 10px 0px #00000024;
|
|
35
|
+
border: 1px solid @themeColor;;
|
|
36
|
+
}
|
|
37
|
+
.Modal__titleBox {
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
height: 40px;
|
|
41
|
+
justify-content: space-between;
|
|
42
|
+
padding: 0 20px;
|
|
43
|
+
cursor: all-scroll;
|
|
44
|
+
border-bottom: 1px solid #ccc;
|
|
45
|
+
background-color: @themeColor;
|
|
46
|
+
}
|
|
47
|
+
.Modal__contentBox {
|
|
48
|
+
padding: 24px 20px;
|
|
49
|
+
}
|
|
50
|
+
.Modal__title {
|
|
51
|
+
color: #fff;
|
|
52
|
+
font-size: 13px;
|
|
53
|
+
font-weight: 600;
|
|
54
|
+
margin: 0px;
|
|
55
|
+
}
|
|
56
|
+
.Modal__closeButton {
|
|
57
|
+
color: #fff;
|
|
58
|
+
border: 0px;
|
|
59
|
+
justify-content: center;
|
|
60
|
+
align-items: center;
|
|
61
|
+
display: flex;
|
|
62
|
+
text-align: center;
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
background-color: transparent;
|
|
65
|
+
}
|
package/src/Modal.tsx
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
9
|
+
/* eslint-disable lexical/no-optional-chaining */
|
|
10
|
+
|
|
11
|
+
import type {JSX} from 'react';
|
|
12
|
+
|
|
13
|
+
import {isDOMNode} from 'lexical';
|
|
14
|
+
import * as React from 'react';
|
|
15
|
+
import {ReactNode, useEffect, useRef} from 'react';
|
|
16
|
+
import {createPortal} from 'react-dom';
|
|
17
|
+
import Draggable, {DraggableData, DraggableEvent} from 'react-draggable';
|
|
18
|
+
|
|
19
|
+
import Styles from './Modal.module.less';
|
|
20
|
+
|
|
21
|
+
function PortalImpl({
|
|
22
|
+
onClose,
|
|
23
|
+
children,
|
|
24
|
+
title,
|
|
25
|
+
closeOnClickOutside,
|
|
26
|
+
}: {
|
|
27
|
+
children: ReactNode;
|
|
28
|
+
closeOnClickOutside: boolean;
|
|
29
|
+
onClose: () => void;
|
|
30
|
+
title: string;
|
|
31
|
+
}) {
|
|
32
|
+
const modalRef = useRef<HTMLDivElement>(null);
|
|
33
|
+
const [fixed, setFixed] = React.useState(true);
|
|
34
|
+
const [disabled, setDisabled] = React.useState(true);
|
|
35
|
+
const [bounds, setBounds] = React.useState({
|
|
36
|
+
bottom: 0,
|
|
37
|
+
left: 0,
|
|
38
|
+
right: 0,
|
|
39
|
+
top: 0,
|
|
40
|
+
});
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (modalRef.current !== null) {
|
|
43
|
+
modalRef.current.focus();
|
|
44
|
+
}
|
|
45
|
+
}, []);
|
|
46
|
+
const onStart = React.useCallback(
|
|
47
|
+
(event: DraggableEvent, uiData: DraggableData) => {
|
|
48
|
+
const {clientWidth, clientHeight} = window.document.documentElement;
|
|
49
|
+
const targetRect = modalRef.current?.getBoundingClientRect();
|
|
50
|
+
if (!targetRect) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
setBounds({
|
|
54
|
+
bottom: clientHeight - (targetRect.bottom - uiData.y),
|
|
55
|
+
left: -targetRect.left + uiData.x,
|
|
56
|
+
right: clientWidth - (targetRect.right - uiData.x),
|
|
57
|
+
top: -targetRect.top + uiData.y,
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
[],
|
|
61
|
+
);
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
let modalOverlayElement: HTMLElement | null = null;
|
|
64
|
+
const handler = (event: KeyboardEvent) => {
|
|
65
|
+
if (event.key === 'Escape') {
|
|
66
|
+
onClose();
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const clickOutsideHandler = (event: MouseEvent) => {
|
|
70
|
+
const target = event.target;
|
|
71
|
+
if (
|
|
72
|
+
modalRef.current !== null &&
|
|
73
|
+
isDOMNode(target) &&
|
|
74
|
+
!modalRef.current.contains(target) &&
|
|
75
|
+
closeOnClickOutside
|
|
76
|
+
) {
|
|
77
|
+
onClose();
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const modelElement = modalRef.current;
|
|
81
|
+
if (modelElement !== null) {
|
|
82
|
+
modalOverlayElement = modelElement.parentElement;
|
|
83
|
+
if (modalOverlayElement !== null) {
|
|
84
|
+
modalOverlayElement.addEventListener('click', clickOutsideHandler);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
window.addEventListener('keydown', handler);
|
|
89
|
+
|
|
90
|
+
return () => {
|
|
91
|
+
window.removeEventListener('keydown', handler);
|
|
92
|
+
if (modalOverlayElement !== null) {
|
|
93
|
+
modalOverlayElement?.removeEventListener('click', clickOutsideHandler);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}, [closeOnClickOutside, onClose]);
|
|
97
|
+
|
|
98
|
+
const onDialog = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
|
99
|
+
const target = e.target;
|
|
100
|
+
if (
|
|
101
|
+
target instanceof HTMLDivElement &&
|
|
102
|
+
target.getAttribute('data-modal-root') &&
|
|
103
|
+
!fixed
|
|
104
|
+
) {
|
|
105
|
+
onClose();
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<div
|
|
111
|
+
className={Styles.Modal__overlay}
|
|
112
|
+
data-modal-root={true}
|
|
113
|
+
role="presentation"
|
|
114
|
+
onClick={onDialog}>
|
|
115
|
+
<Draggable bounds={bounds} disabled={disabled} onStart={onStart}>
|
|
116
|
+
<div className={Styles.Modal__modal} tabIndex={-1} ref={modalRef}>
|
|
117
|
+
<div
|
|
118
|
+
className={Styles.Modal__titleBox}
|
|
119
|
+
onMouseEnter={() => {
|
|
120
|
+
if (disabled) {
|
|
121
|
+
setDisabled(false);
|
|
122
|
+
}
|
|
123
|
+
}}
|
|
124
|
+
onMouseLeave={() => {
|
|
125
|
+
setDisabled(true);
|
|
126
|
+
}}>
|
|
127
|
+
{' '}
|
|
128
|
+
<span className={Styles.Modal__title}>{title}</span>
|
|
129
|
+
<button
|
|
130
|
+
className={Styles.Modal__closeButton}
|
|
131
|
+
aria-label="Close modal"
|
|
132
|
+
type="button"
|
|
133
|
+
onClick={onClose}>
|
|
134
|
+
<svg
|
|
135
|
+
fill-rule="evenodd"
|
|
136
|
+
viewBox="64 64 896 896"
|
|
137
|
+
focusable="false"
|
|
138
|
+
data-icon="close"
|
|
139
|
+
width="1em"
|
|
140
|
+
height="1em"
|
|
141
|
+
fill="currentColor"
|
|
142
|
+
aria-hidden="true">
|
|
143
|
+
<path d="M799.86 166.31c.02 0 .04.02.08.06l57.69 57.7c.04.03.05.05.06.08a.12.12 0 010 .06c0 .03-.02.05-.06.09L569.93 512l287.7 287.7c.04.04.05.06.06.09a.12.12 0 010 .07c0 .02-.02.04-.06.08l-57.7 57.69c-.03.04-.05.05-.07.06a.12.12 0 01-.07 0c-.03 0-.05-.02-.09-.06L512 569.93l-287.7 287.7c-.04.04-.06.05-.09.06a.12.12 0 01-.07 0c-.02 0-.04-.02-.08-.06l-57.69-57.7c-.04-.03-.05-.05-.06-.07a.12.12 0 010-.07c0-.03.02-.05.06-.09L454.07 512l-287.7-287.7c-.04-.04-.05-.06-.06-.09a.12.12 0 010-.07c0-.02.02-.04.06-.08l57.7-57.69c.03-.04.05-.05.07-.06a.12.12 0 01.07 0c.03 0 .05.02.09.06L512 454.07l287.7-287.7c.04-.04.06-.05.09-.06a.12.12 0 01.07 0z" />
|
|
144
|
+
</svg>
|
|
145
|
+
</button>
|
|
146
|
+
</div>
|
|
147
|
+
<div className={Styles.Modal__contentBox}>
|
|
148
|
+
<div className={Styles.Modal__content}>{children}</div>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
</Draggable>
|
|
152
|
+
</div>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export default function Modal({
|
|
157
|
+
onClose,
|
|
158
|
+
children,
|
|
159
|
+
title,
|
|
160
|
+
closeOnClickOutside = false,
|
|
161
|
+
}: {
|
|
162
|
+
children: ReactNode;
|
|
163
|
+
closeOnClickOutside?: boolean;
|
|
164
|
+
onClose: () => void;
|
|
165
|
+
title: string;
|
|
166
|
+
}): JSX.Element {
|
|
167
|
+
return createPortal(
|
|
168
|
+
<PortalImpl
|
|
169
|
+
onClose={onClose}
|
|
170
|
+
title={title}
|
|
171
|
+
closeOnClickOutside={closeOnClickOutside}>
|
|
172
|
+
{children}
|
|
173
|
+
</PortalImpl>,
|
|
174
|
+
document.body,
|
|
175
|
+
);
|
|
176
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
:root {
|
|
10
|
+
--select-border: #393939;
|
|
11
|
+
--select-focus: #101484;
|
|
12
|
+
--select-arrow: var(--select-border);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.select {
|
|
16
|
+
appearance: none;
|
|
17
|
+
-webkit-appearance: none;
|
|
18
|
+
-moz-appearance: none;
|
|
19
|
+
background-color: transparent;
|
|
20
|
+
border: none;
|
|
21
|
+
padding: 0 1em 0 0;
|
|
22
|
+
margin: 0;
|
|
23
|
+
font-family: inherit;
|
|
24
|
+
font-size: inherit;
|
|
25
|
+
cursor: inherit;
|
|
26
|
+
line-height: inherit;
|
|
27
|
+
|
|
28
|
+
z-index: 1;
|
|
29
|
+
outline: none;
|
|
30
|
+
|
|
31
|
+
min-width: 160px;
|
|
32
|
+
max-width: 290px;
|
|
33
|
+
border: 1px solid var(--select-border);
|
|
34
|
+
border-radius: 0.25em;
|
|
35
|
+
padding: 0.25em 0.5em;
|
|
36
|
+
font-size: 1rem;
|
|
37
|
+
cursor: pointer;
|
|
38
|
+
line-height: 1.4;
|
|
39
|
+
background: linear-gradient(to bottom, #ffffff 0%, #e5e5e5 100%);
|
|
40
|
+
|
|
41
|
+
}
|
package/src/Select.tsx
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {JSX} from 'react';
|
|
10
|
+
|
|
11
|
+
import * as React from 'react';
|
|
12
|
+
|
|
13
|
+
import Styles from './Input.module.less';
|
|
14
|
+
import SelectStyles from './Select.module.less';
|
|
15
|
+
|
|
16
|
+
type SelectIntrinsicProps = JSX.IntrinsicElements['select'];
|
|
17
|
+
interface SelectProps extends SelectIntrinsicProps {
|
|
18
|
+
label: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default function Select({
|
|
22
|
+
children,
|
|
23
|
+
label,
|
|
24
|
+
className,
|
|
25
|
+
...other
|
|
26
|
+
}: SelectProps): JSX.Element {
|
|
27
|
+
return (
|
|
28
|
+
<div className={Styles.Input__wrapper}>
|
|
29
|
+
<label style={{marginTop: '-1em'}} className={Styles.Input__label}>
|
|
30
|
+
{label}
|
|
31
|
+
</label>
|
|
32
|
+
<select {...other} className={className || SelectStyles.select}>
|
|
33
|
+
{children}
|
|
34
|
+
</select>
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
.skeleton {
|
|
2
|
+
display: inline-block;
|
|
3
|
+
:global {
|
|
4
|
+
div {
|
|
5
|
+
display: inline-block;
|
|
6
|
+
}
|
|
7
|
+
div[data-type='avatar'] {
|
|
8
|
+
width: 60px;
|
|
9
|
+
height: 60px;
|
|
10
|
+
border-radius: 50%;
|
|
11
|
+
background: #e0e0e0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
div[data-type='block'] {
|
|
15
|
+
height: 15px;
|
|
16
|
+
background: #e0e0e0;
|
|
17
|
+
border-radius: 2px;
|
|
18
|
+
position: relative;
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
div[data-type='rect'] {
|
|
23
|
+
height: 120px;
|
|
24
|
+
border-radius: 2px;
|
|
25
|
+
background: #e0e0e0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
div[data-type='title'] {
|
|
29
|
+
height: 25px;
|
|
30
|
+
background: #e0e0e0;
|
|
31
|
+
border-radius: 2px;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
div[data-type='text'] {
|
|
35
|
+
height: 16px;
|
|
36
|
+
background: #e0e0e0;
|
|
37
|
+
border-radius: 2px;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
div[data-type='button'] {
|
|
41
|
+
height: 36px;
|
|
42
|
+
width: 100px;
|
|
43
|
+
border-radius: 50%;
|
|
44
|
+
background: #e0e0e0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
div.animated :local {
|
|
48
|
+
background: linear-gradient(
|
|
49
|
+
90deg,
|
|
50
|
+
#f0f0f0 25%,
|
|
51
|
+
#e0e0e0 50%,
|
|
52
|
+
#f0f0f0 75%
|
|
53
|
+
);
|
|
54
|
+
background-size: 200% 100%;
|
|
55
|
+
animation: shimmer 1.5s infinite;
|
|
56
|
+
@keyframes shimmer {
|
|
57
|
+
from {
|
|
58
|
+
background-position: -200% 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
to {
|
|
62
|
+
background-position: 200% 0;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
package/src/Skeleton.tsx
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import Styles from './Skeleton.module.less';
|
|
9
|
+
|
|
10
|
+
interface SkeletonProps extends BaseComponentProps {
|
|
11
|
+
type: 'avatar' | 'block' | 'text' | 'button' | 'rect' | 'title';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default function Skeleton({
|
|
15
|
+
className,
|
|
16
|
+
style,
|
|
17
|
+
type,
|
|
18
|
+
}: SkeletonProps): JSX.Element {
|
|
19
|
+
return (
|
|
20
|
+
<div className={Styles.skeleton}>
|
|
21
|
+
<div
|
|
22
|
+
data-type={type}
|
|
23
|
+
className={`${className ?? ''} ${Styles.skeleton} animated`}
|
|
24
|
+
style={style}
|
|
25
|
+
/>
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
package/src/Switch.tsx
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {JSX} from 'react';
|
|
10
|
+
|
|
11
|
+
import * as React from 'react';
|
|
12
|
+
import {useMemo} from 'react';
|
|
13
|
+
|
|
14
|
+
export default function Switch({
|
|
15
|
+
checked,
|
|
16
|
+
onClick,
|
|
17
|
+
text,
|
|
18
|
+
id,
|
|
19
|
+
}: Readonly<{
|
|
20
|
+
checked: boolean;
|
|
21
|
+
id?: string;
|
|
22
|
+
onClick: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
|
23
|
+
text: string;
|
|
24
|
+
}>): JSX.Element {
|
|
25
|
+
const buttonId = useMemo(() => 'id_' + Math.floor(Math.random() * 10000), []);
|
|
26
|
+
return (
|
|
27
|
+
<div className="switch" id={id}>
|
|
28
|
+
<label htmlFor={buttonId}>{text}</label>
|
|
29
|
+
<button
|
|
30
|
+
role="switch"
|
|
31
|
+
aria-checked={checked}
|
|
32
|
+
id={buttonId}
|
|
33
|
+
onClick={onClick}>
|
|
34
|
+
<span />
|
|
35
|
+
</button>
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
}
|