onchain-lexical-ui 0.0.13 → 0.0.14

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "onchain-lexical-ui",
3
3
  "license": "MIT",
4
- "version": "0.0.13",
4
+ "version": "0.0.14",
5
5
  "sideEffects": false,
6
6
  "dependencies": {
7
7
  "@ant-design/icons": "^6.0.0",
@@ -10,7 +10,8 @@
10
10
  "@lexical/utils": "^0.30.0",
11
11
  "katex": "^0.16.22",
12
12
  "lexical": "0.30.0",
13
- "onchain-lexical-context": "^0.0.13",
13
+ "onchain-lexical-context": "^0.0.14",
14
+ "onchain-utility": "^0.0.15",
14
15
  "react-draggable": "^4.5.0"
15
16
  },
16
17
  "browser": {
@@ -6,20 +6,40 @@
6
6
  *
7
7
  *
8
8
  */
9
+ @import './const.less';
9
10
 
10
11
  .Button__root {
11
- padding-top: 10px;
12
- padding-bottom: 10px;
13
- padding-left: 15px;
14
- padding-right: 15px;
12
+ color: #333;
13
+ padding-top: 5px;
14
+ padding-bottom: 5px;
15
+ padding-left: 5px;
16
+ padding-right: 5px;
15
17
  border: 0px;
16
- background-color: #eee;
17
18
  border-radius: 2px;
18
19
  cursor: pointer;
19
- font-size: 14px;
20
- }
21
- .Button__root:hover {
22
- background-color: #ddd;
20
+ font-size: 12px;
21
+ height: 30px;
22
+ min-width: 72px;
23
+ transition: background-color 0.3s;
24
+ &:hover {
25
+ background-color: #ddd;
26
+ }
27
+ &[data-type='primary'] {
28
+ color: #fff;
29
+ background-color: @themeColor;
30
+ &:hover {
31
+ background-color: @themeColorHover;
32
+ }
33
+ }
34
+
35
+ &.Button__disabled {
36
+ color: #999;
37
+ cursor: not-allowed;
38
+ &[data-type='primary'],
39
+ &:hover {
40
+ background-color: #eee;
41
+ }
42
+ }
23
43
  }
24
44
  .Button__small {
25
45
  padding-top: 5px;
@@ -28,9 +48,3 @@
28
48
  padding-right: 10px;
29
49
  font-size: 13px;
30
50
  }
31
- .Button__disabled {
32
- cursor: not-allowed;
33
- }
34
- .Button__disabled:hover {
35
- background-color: #eee;
36
- }
package/src/Button.tsx CHANGED
@@ -22,6 +22,7 @@ export default function Button({
22
22
  disabled,
23
23
  small,
24
24
  title,
25
+ type,
25
26
  }: {
26
27
  'data-test-id'?: string;
27
28
  children: ReactNode;
@@ -30,6 +31,7 @@ export default function Button({
30
31
  onClick: () => void;
31
32
  small?: boolean;
32
33
  title?: string;
34
+ type?: 'primary';
33
35
  }): JSX.Element {
34
36
  return (
35
37
  <button
@@ -43,6 +45,7 @@ export default function Button({
43
45
  onClick={onClick}
44
46
  title={title}
45
47
  aria-label={title}
48
+ data-type={type}
46
49
  {...(dataTestId && {'data-test-id': dataTestId})}>
47
50
  {children}
48
51
  </button>
@@ -44,7 +44,7 @@ const basicColors = [
44
44
  '#ffffff',
45
45
  ];
46
46
 
47
- const WIDTH = 214;
47
+ const WIDTH = 267;
48
48
  const HEIGHT = 150;
49
49
 
50
50
  export default function ColorPicker({
@@ -116,7 +116,7 @@ export default function ColorPicker({
116
116
 
117
117
  return (
118
118
  <div
119
- className={Styles['color-picker-wrapper']}
119
+ className={`${Styles['color-picker-wrapper']} color-picker-wrapper`}
120
120
  style={{width: WIDTH}}
121
121
  ref={innerDivRef}>
122
122
  <TextInput label="Hex" onChange={onSetHex} value={inputColor} />
@@ -18,6 +18,8 @@
18
18
  flex-direction: column;
19
19
  justify-content: right;
20
20
  button {
21
- margin-bottom: 20px;
21
+ &:not(:nth-last-child(1)) {
22
+ margin-bottom: 20px;
23
+ }
22
24
  }
23
25
  }
package/src/DropDown.tsx CHANGED
@@ -194,6 +194,25 @@ function DropDownItems({
194
194
  );
195
195
  }
196
196
 
197
+ export type ShouldUpdateFunc<T> = (prev?: T, next?: T) => boolean;
198
+
199
+ const defaultShouldUpdate = <T,>(a?: T, b?: T) => !Object.is(a, b);
200
+
201
+ function usePrevious<T>(
202
+ state: T,
203
+ shouldUpdate: ShouldUpdateFunc<T> = defaultShouldUpdate,
204
+ ): T | undefined {
205
+ const prevRef = useRef<T>();
206
+ const curRef = useRef<T>();
207
+
208
+ if (shouldUpdate(curRef.current, state)) {
209
+ prevRef.current = curRef.current;
210
+ curRef.current = state;
211
+ }
212
+
213
+ return prevRef.current;
214
+ }
215
+
197
216
  export default function DropDown({
198
217
  disabled = false,
199
218
  showIcon = true,
@@ -226,6 +245,7 @@ export default function DropDown({
226
245
  const [showDropDown, setShowDropDown] = useState(false);
227
246
  const {extra} = useSettings();
228
247
  const [zIndex, setZIndex] = useState(100);
248
+ const previousShowDropDown = usePrevious(showDropDown);
229
249
 
230
250
  const handleClose = () => {
231
251
  setShowDropDown(false);
@@ -235,13 +255,15 @@ export default function DropDown({
235
255
  };
236
256
 
237
257
  useEffect(() => {
238
- if (showDropDown) {
239
- if (extra.getZIndex) {
240
- setZIndex(extra.getZIndex());
241
- }
242
- } else {
243
- if (extra.reduceZIndex) {
244
- extra.reduceZIndex();
258
+ if (Boolean(previousShowDropDown) !== showDropDown) {
259
+ if (showDropDown) {
260
+ if (extra.getZIndex) {
261
+ setZIndex(extra.getZIndex());
262
+ }
263
+ } else {
264
+ if (extra.reduceZIndex) {
265
+ extra.reduceZIndex();
266
+ }
245
267
  }
246
268
  }
247
269
  }, [showDropDown]);
@@ -4,7 +4,7 @@
4
4
  width: 100%;
5
5
  // border-radius: 2px;
6
6
  // max-width: 1100px;
7
- color: #000;
7
+ color: #333;
8
8
  position: relative;
9
9
  font-weight: 400;
10
10
  height: 100%;
package/src/FileInput.tsx CHANGED
@@ -6,15 +6,15 @@
6
6
  *
7
7
  */
8
8
 
9
- import type {JSX} from 'react';
10
-
11
- import * as React from 'react';
9
+ import {DeleteOutlined, UploadOutlined} from '@ant-design/icons';
10
+ import {type JSX, useState} from 'react';
12
11
 
13
12
  import Styles from './Input.module.less';
14
13
 
15
14
  type Props = Readonly<{
16
15
  'data-test-id'?: string;
17
16
  accept?: string;
17
+ placeholder?: string;
18
18
  label: string;
19
19
  onChange: (files: FileList | null) => void;
20
20
  }>;
@@ -22,19 +22,46 @@ type Props = Readonly<{
22
22
  export default function FileInput({
23
23
  accept,
24
24
  label,
25
+ placeholder = '选择文件',
25
26
  onChange,
26
27
  'data-test-id': dataTestId,
27
28
  }: Props): JSX.Element {
29
+ const [files, setFiles] = useState<File[]>([]);
28
30
  return (
29
31
  <div className={Styles.Input__wrapper}>
30
32
  <label className={Styles.Input__label}>{label}</label>
31
- <input
32
- type="file"
33
- accept={accept}
34
- className={Styles.Input__input}
35
- onChange={(e) => onChange(e.target.files)}
36
- data-test-id={dataTestId}
37
- />
33
+ <div className={`${Styles.Input__input} ${Styles.file}`}>
34
+ {!files.length ? (
35
+ <label htmlFor="file-upload">
36
+ <UploadOutlined />
37
+ {placeholder}
38
+ </label>
39
+ ) : (
40
+ <span className={Styles.content}>
41
+ <span className={Styles.name}>
42
+ {files.map((file) => file.name)}
43
+ </span>
44
+ <span className={Styles.delete}>
45
+ <DeleteOutlined
46
+ onClick={() => {
47
+ onChange(null);
48
+ setFiles([]);
49
+ }}
50
+ />
51
+ </span>
52
+ </span>
53
+ )}
54
+ <input
55
+ id="file-upload"
56
+ type="file"
57
+ accept={accept}
58
+ onChange={(e) => {
59
+ setFiles(Array.from(e.target.files || []));
60
+ onChange(e.target.files);
61
+ }}
62
+ data-test-id={dataTestId}
63
+ />
64
+ </div>
38
65
  </div>
39
66
  );
40
67
  }
@@ -6,7 +6,7 @@
6
6
  *
7
7
  *
8
8
  */
9
- @import './const.less';
9
+ @import './const.less';
10
10
 
11
11
  .Input__wrapper {
12
12
  display: flex;
@@ -16,23 +16,72 @@
16
16
  }
17
17
  .Input__label {
18
18
  display: flex;
19
- flex: 1;
19
+ width: 80px;
20
+ flex-shrink: 0;
20
21
  color: #666;
22
+ font-size: 14px;
23
+ &::after {
24
+ content: ':';
25
+ }
21
26
  }
22
27
  .Input__input {
23
28
  display: flex;
24
- flex: 2;
29
+ width: 100%;
30
+ color: #333;
25
31
  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
+ padding: 7px 10px;
33
+ font-size: 12px;
34
+ border-radius: 2px;
32
35
  min-width: 0;
33
36
  height: @inputHeight;
37
+ &.file {
38
+ border: none;
39
+ padding: 0;
40
+ align-items: center;
41
+ justify-content: flex-start;
42
+ > input[type='file'] {
43
+ display: none;
44
+ }
45
+ > label {
46
+ display: inline-block;
47
+ border: none;
48
+ height: 30px;
49
+ line-height: 20px;
50
+ padding: 5px 0px;
51
+ cursor: pointer;
52
+ color: #333;
53
+ border-radius: 2px;
54
+ transition: background-color 0.3s;
55
+ &:hover {
56
+ color: @themeColor;
57
+ }
58
+ > span:nth-of-type(1) {
59
+ margin-right: 2px;
60
+ }
61
+ }
62
+ > .content {
63
+ width: 100%;
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: space-between;
67
+ >.name {
68
+ max-width: 160px;
69
+ overflow: hidden;
70
+ text-overflow: ellipsis;
71
+ white-space: nowrap;
72
+ }
73
+ .delete {
74
+ &:hover {
75
+ color: @themeColor;
76
+ }
77
+ }
78
+ }
79
+ }
34
80
  &:focus-visible {
35
81
  outline: none;
36
82
  border-color: @themeColor;
37
- };
83
+ }
84
+ &[type='file'] {
85
+ padding-top: 5px !important;
86
+ }
38
87
  }
@@ -6,14 +6,56 @@
6
6
  *
7
7
  *
8
8
  */
9
+ @import './const.less';
9
10
 
10
11
  .KatexEquationAlterer_defaultRow {
12
+ width: 260px;
11
13
  display: flex;
12
14
  flex-direction: row;
13
15
  margin-top: 10px;
14
16
  margin-bottom: 10px;
15
17
  justify-content: space-between;
16
18
  overflow: hidden;
19
+ font-size: 14px;
20
+ input[type='checkbox'] {
21
+ appearance: none;
22
+ -moz-appearance: none;
23
+ -webkit-appearance: none;
24
+ width: 16px;
25
+ height: 16px;
26
+ border: 1px solid #ccc;
27
+ border-radius: 2px;
28
+ background-color: #fff;
29
+ cursor: pointer;
30
+ position: relative;
31
+ &:checked {
32
+ &::before {
33
+ content: '';
34
+ position: absolute;
35
+ top: -1px;
36
+ left: -1px;
37
+ width: 16px;
38
+ height: 16px;
39
+ background-color: @themeColor;
40
+ border-radius: 2px;
41
+ }
42
+ &::after {
43
+ content: '';
44
+ cursor: pointer;
45
+ border-color: #fff;
46
+ border-style: solid;
47
+ position: absolute;
48
+ display: block;
49
+ top: 2px;
50
+ width: 3px;
51
+ left: 5px;
52
+ right: 7px;
53
+ height: 6px;
54
+ transform: rotate(45deg);
55
+ border-width: 0 2px 2px 0;
56
+ }
57
+ }
58
+ }
17
59
  }
18
60
 
19
61
  .KatexEquationAlterer_dialogActions {
@@ -26,16 +68,26 @@
26
68
  }
27
69
 
28
70
  .KatexEquationAlterer_centerRow {
71
+ width: 260px;
29
72
  display: flex;
30
73
  flex-direction: 'row';
31
74
  margin-top: 10px;
32
75
  margin-bottom: 10px;
33
76
  justify-content: center;
34
77
  overflow: hidden;
78
+ font-size: 12px;
79
+ &.preview {
80
+ overflow-x: auto;
81
+ height: 58px;
82
+ }
83
+ &.empty * {
84
+ color: #8a8a8a !important;
85
+ }
35
86
  }
36
87
 
37
88
  .KatexEquationAlterer_textArea {
38
89
  width: 100%;
39
90
  resize: none;
40
91
  padding: 7px;
92
+ min-height: 50px;
41
93
  }
@@ -9,7 +9,7 @@
9
9
  import type {JSX} from 'react';
10
10
 
11
11
  import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
12
- import * as React from 'react';
12
+ import {translateI18n} from 'onchain-utility/language';
13
13
  import {useCallback, useState} from 'react';
14
14
  import {ErrorBoundary} from 'react-error-boundary';
15
15
 
@@ -38,46 +38,61 @@ export default function KatexEquationAlterer({
38
38
  setInline(!inline);
39
39
  }, [setInline, inline]);
40
40
 
41
+ const placeholder = translateI18n('[TODO] Please enter a equation', {
42
+ placeholder: '请输入方程式',
43
+ });
44
+
41
45
  return (
42
46
  <>
43
47
  <div className={Styles.KatexEquationAlterer_defaultRow}>
44
- Inline
48
+ <span>
49
+ {translateI18n('[TODO] Inline', {
50
+ placeholder: '行内方程式',
51
+ })}
52
+ :
53
+ </span>
45
54
  <input type="checkbox" checked={inline} onChange={onCheckboxChange} />
46
55
  </div>
47
- <div className={Styles.KatexEquationAlterer_defaultRow}>Equation </div>
56
+ <div className={Styles.KatexEquationAlterer_defaultRow}>
57
+ {translateI18n('[TODO] Equation', {
58
+ placeholder: '方程式',
59
+ })}
60
+ :
61
+ </div>
48
62
  <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
- )}
63
+ <textarea
64
+ onChange={(event) => {
65
+ setEquation(event.target.value);
66
+ }}
67
+ value={equation}
68
+ placeholder={placeholder}
69
+ className={Styles.KatexEquationAlterer_textArea}
70
+ />
66
71
  </div>
67
72
  <div className={Styles.KatexEquationAlterer_defaultRow}>
68
- Visualization{' '}
73
+ {translateI18n('[TODO] Visualization', {
74
+ placeholder: '预览',
75
+ })}
76
+ :
69
77
  </div>
70
- <div className={Styles.KatexEquationAlterer_centerRow}>
78
+ <div
79
+ className={`${Styles.KatexEquationAlterer_centerRow} ${
80
+ Styles.preview
81
+ } ${equation ? '' : Styles.empty}`}>
71
82
  <ErrorBoundary onError={(e) => editor._onError(e)} fallback={null}>
72
83
  <KatexRenderer
73
- equation={equation}
84
+ equation={equation || placeholder}
74
85
  inline={false}
75
86
  onDoubleClick={() => null}
76
87
  />
77
88
  </ErrorBoundary>
78
89
  </div>
79
90
  <div className={Styles.KatexEquationAlterer_dialogActions}>
80
- <Button onClick={onClick}>Confirm</Button>
91
+ <Button type="primary" onClick={onClick}>
92
+ {translateI18n('[TODO] Confirm', {
93
+ placeholder: '确认',
94
+ })}
95
+ </Button>
81
96
  </div>
82
97
  </>
83
98
  );
@@ -39,13 +39,18 @@
39
39
  align-items: center;
40
40
  height: 40px;
41
41
  justify-content: space-between;
42
- padding: 0 20px;
42
+ padding: 0 16px;
43
43
  cursor: all-scroll;
44
44
  border-bottom: 1px solid #ccc;
45
45
  background-color: @themeColor;
46
46
  }
47
47
  .Modal__contentBox {
48
- padding: 24px 20px;
48
+ padding: 16px 16px;
49
+ :global {
50
+ .color-picker-wrapper {
51
+ padding: 0;
52
+ }
53
+ }
49
54
  }
50
55
  .Modal__title {
51
56
  color: #fff;
@@ -62,4 +67,5 @@
62
67
  text-align: center;
63
68
  cursor: pointer;
64
69
  background-color: transparent;
70
+ padding: 0;
65
71
  }
package/src/TextInput.tsx CHANGED
@@ -16,6 +16,7 @@ import Styles from './Input.module.less';
16
16
  type Props = Readonly<{
17
17
  'data-test-id'?: string;
18
18
  label: string;
19
+ labelWidth?: number;
19
20
  onChange: (val: string) => void;
20
21
  placeholder?: string;
21
22
  value: string;
@@ -24,6 +25,7 @@ type Props = Readonly<{
24
25
 
25
26
  export default function TextInput({
26
27
  label,
28
+ labelWidth,
27
29
  value,
28
30
  onChange,
29
31
  placeholder = '',
@@ -32,7 +34,9 @@ export default function TextInput({
32
34
  }: Props): JSX.Element {
33
35
  return (
34
36
  <div className={Styles.Input__wrapper}>
35
- <label className={Styles.Input__label}>{label}</label>
37
+ <label style={{width: labelWidth}} className={Styles.Input__label}>
38
+ {label}
39
+ </label>
36
40
  <input
37
41
  type={type}
38
42
  className={Styles.Input__input}