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,369 @@
|
|
|
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 {calculateZoomLevel} from '@lexical/utils';
|
|
12
|
+
import {useEffect, useMemo, useRef, useState} from 'react';
|
|
13
|
+
import * as React from 'react';
|
|
14
|
+
|
|
15
|
+
import Styles from './ColorPicker.module.less';
|
|
16
|
+
import TextInput from './TextInput';
|
|
17
|
+
|
|
18
|
+
let skipAddingToHistoryStack = false;
|
|
19
|
+
|
|
20
|
+
interface ColorPickerProps {
|
|
21
|
+
color: string;
|
|
22
|
+
onChange?: (value: string, skipHistoryStack: boolean) => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function parseAllowedColor(input: string) {
|
|
26
|
+
return /^rgb\(\d+, \d+, \d+\)$/.test(input) ? input : '';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const basicColors = [
|
|
30
|
+
'#d0021b',
|
|
31
|
+
'#f5a623',
|
|
32
|
+
'#f8e71c',
|
|
33
|
+
'#8b572a',
|
|
34
|
+
'#7ed321',
|
|
35
|
+
'#417505',
|
|
36
|
+
'#bd10e0',
|
|
37
|
+
'#9013fe',
|
|
38
|
+
'#4a90e2',
|
|
39
|
+
'#50e3c2',
|
|
40
|
+
'#b8e986',
|
|
41
|
+
'#000000',
|
|
42
|
+
'#4a4a4a',
|
|
43
|
+
'#9b9b9b',
|
|
44
|
+
'#ffffff',
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
const WIDTH = 214;
|
|
48
|
+
const HEIGHT = 150;
|
|
49
|
+
|
|
50
|
+
export default function ColorPicker({
|
|
51
|
+
color,
|
|
52
|
+
onChange,
|
|
53
|
+
}: Readonly<ColorPickerProps>): JSX.Element {
|
|
54
|
+
const [selfColor, setSelfColor] = useState(transformColor('hex', color));
|
|
55
|
+
const [inputColor, setInputColor] = useState(color);
|
|
56
|
+
const innerDivRef = useRef(null);
|
|
57
|
+
|
|
58
|
+
const saturationPosition = useMemo(
|
|
59
|
+
() => ({
|
|
60
|
+
x: (selfColor.hsv.s / 100) * WIDTH,
|
|
61
|
+
y: ((100 - selfColor.hsv.v) / 100) * HEIGHT,
|
|
62
|
+
}),
|
|
63
|
+
[selfColor.hsv.s, selfColor.hsv.v],
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const huePosition = useMemo(
|
|
67
|
+
() => ({
|
|
68
|
+
x: (selfColor.hsv.h / 360) * WIDTH,
|
|
69
|
+
}),
|
|
70
|
+
[selfColor.hsv],
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const onSetHex = (hex: string) => {
|
|
74
|
+
setInputColor(hex);
|
|
75
|
+
if (/^#[0-9A-Fa-f]{6}$/i.test(hex)) {
|
|
76
|
+
const newColor = transformColor('hex', hex);
|
|
77
|
+
setSelfColor(newColor);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const onMoveSaturation = ({x, y}: Position) => {
|
|
82
|
+
const newHsv = {
|
|
83
|
+
...selfColor.hsv,
|
|
84
|
+
s: (x / WIDTH) * 100,
|
|
85
|
+
v: 100 - (y / HEIGHT) * 100,
|
|
86
|
+
};
|
|
87
|
+
const newColor = transformColor('hsv', newHsv);
|
|
88
|
+
setSelfColor(newColor);
|
|
89
|
+
setInputColor(newColor.hex);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const onMoveHue = ({x}: Position) => {
|
|
93
|
+
const newHsv = {...selfColor.hsv, h: (x / WIDTH) * 360};
|
|
94
|
+
const newColor = transformColor('hsv', newHsv);
|
|
95
|
+
|
|
96
|
+
setSelfColor(newColor);
|
|
97
|
+
setInputColor(newColor.hex);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
// Check if the dropdown is actually active
|
|
102
|
+
if (innerDivRef.current !== null && onChange) {
|
|
103
|
+
onChange(selfColor.hex, skipAddingToHistoryStack);
|
|
104
|
+
setInputColor(selfColor.hex);
|
|
105
|
+
}
|
|
106
|
+
}, [selfColor, onChange]);
|
|
107
|
+
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
if (color === undefined) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const newColor = transformColor('hex', color);
|
|
113
|
+
setSelfColor(newColor);
|
|
114
|
+
setInputColor(newColor.hex);
|
|
115
|
+
}, [color]);
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<div
|
|
119
|
+
className={Styles['color-picker-wrapper']}
|
|
120
|
+
style={{width: WIDTH}}
|
|
121
|
+
ref={innerDivRef}>
|
|
122
|
+
<TextInput label="Hex" onChange={onSetHex} value={inputColor} />
|
|
123
|
+
<div className="color-picker-basic-color">
|
|
124
|
+
{basicColors.map((basicColor) => (
|
|
125
|
+
<button
|
|
126
|
+
className={basicColor === selfColor.hex ? ' active' : ''}
|
|
127
|
+
key={basicColor}
|
|
128
|
+
style={{backgroundColor: basicColor}}
|
|
129
|
+
onClick={() => {
|
|
130
|
+
setInputColor(basicColor);
|
|
131
|
+
setSelfColor(transformColor('hex', basicColor));
|
|
132
|
+
}}
|
|
133
|
+
/>
|
|
134
|
+
))}
|
|
135
|
+
</div>
|
|
136
|
+
<MoveWrapper
|
|
137
|
+
className="color-picker-saturation"
|
|
138
|
+
style={{backgroundColor: `hsl(${selfColor.hsv.h}, 100%, 50%)`}}
|
|
139
|
+
onChange={onMoveSaturation}>
|
|
140
|
+
<div
|
|
141
|
+
className="color-picker-saturation_cursor"
|
|
142
|
+
style={{
|
|
143
|
+
backgroundColor: selfColor.hex,
|
|
144
|
+
left: saturationPosition.x,
|
|
145
|
+
top: saturationPosition.y,
|
|
146
|
+
}}
|
|
147
|
+
/>
|
|
148
|
+
</MoveWrapper>
|
|
149
|
+
<MoveWrapper className="color-picker-hue" onChange={onMoveHue}>
|
|
150
|
+
<div
|
|
151
|
+
className="color-picker-hue_cursor"
|
|
152
|
+
style={{
|
|
153
|
+
backgroundColor: `hsl(${selfColor.hsv.h}, 100%, 50%)`,
|
|
154
|
+
left: huePosition.x,
|
|
155
|
+
}}
|
|
156
|
+
/>
|
|
157
|
+
</MoveWrapper>
|
|
158
|
+
<div
|
|
159
|
+
className="color-picker-color"
|
|
160
|
+
style={{backgroundColor: selfColor.hex}}
|
|
161
|
+
/>
|
|
162
|
+
</div>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface Position {
|
|
167
|
+
x: number;
|
|
168
|
+
y: number;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
interface MoveWrapperProps {
|
|
172
|
+
className?: string;
|
|
173
|
+
style?: React.CSSProperties;
|
|
174
|
+
onChange: (position: Position) => void;
|
|
175
|
+
children: JSX.Element;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function MoveWrapper({className, style, onChange, children}: MoveWrapperProps) {
|
|
179
|
+
const divRef = useRef<HTMLDivElement>(null);
|
|
180
|
+
const draggedRef = useRef(false);
|
|
181
|
+
|
|
182
|
+
const move = (e: React.MouseEvent | MouseEvent): void => {
|
|
183
|
+
if (divRef.current) {
|
|
184
|
+
const {current: div} = divRef;
|
|
185
|
+
const {width, height, left, top} = div.getBoundingClientRect();
|
|
186
|
+
const zoom = calculateZoomLevel(div);
|
|
187
|
+
const x = clamp(e.clientX / zoom - left, width, 0);
|
|
188
|
+
const y = clamp(e.clientY / zoom - top, height, 0);
|
|
189
|
+
|
|
190
|
+
onChange({x, y});
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const onMouseDown = (e: React.MouseEvent): void => {
|
|
195
|
+
if (e.button !== 0) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
move(e);
|
|
200
|
+
|
|
201
|
+
const onMouseMove = (_e: MouseEvent): void => {
|
|
202
|
+
draggedRef.current = true;
|
|
203
|
+
skipAddingToHistoryStack = true;
|
|
204
|
+
move(_e);
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const onMouseUp = (_e: MouseEvent): void => {
|
|
208
|
+
if (draggedRef.current) {
|
|
209
|
+
skipAddingToHistoryStack = false;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
document.removeEventListener('mousemove', onMouseMove, false);
|
|
213
|
+
document.removeEventListener('mouseup', onMouseUp, false);
|
|
214
|
+
|
|
215
|
+
move(_e);
|
|
216
|
+
draggedRef.current = false;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
document.addEventListener('mousemove', onMouseMove, false);
|
|
220
|
+
document.addEventListener('mouseup', onMouseUp, false);
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
return (
|
|
224
|
+
<div
|
|
225
|
+
ref={divRef}
|
|
226
|
+
className={className}
|
|
227
|
+
style={style}
|
|
228
|
+
onMouseDown={onMouseDown}>
|
|
229
|
+
{children}
|
|
230
|
+
</div>
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function clamp(value: number, max: number, min: number) {
|
|
235
|
+
return value > max ? max : value < min ? min : value;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
interface RGB {
|
|
239
|
+
b: number;
|
|
240
|
+
g: number;
|
|
241
|
+
r: number;
|
|
242
|
+
}
|
|
243
|
+
interface HSV {
|
|
244
|
+
h: number;
|
|
245
|
+
s: number;
|
|
246
|
+
v: number;
|
|
247
|
+
}
|
|
248
|
+
interface Color {
|
|
249
|
+
hex: string;
|
|
250
|
+
hsv: HSV;
|
|
251
|
+
rgb: RGB;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export function toHex(value: string): string {
|
|
255
|
+
if (!value.startsWith('#')) {
|
|
256
|
+
const ctx = document.createElement('canvas').getContext('2d');
|
|
257
|
+
|
|
258
|
+
if (!ctx) {
|
|
259
|
+
throw new Error('2d context not supported or canvas already initialized');
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
ctx.fillStyle = value;
|
|
263
|
+
|
|
264
|
+
return ctx.fillStyle;
|
|
265
|
+
} else if (value.length === 4 || value.length === 5) {
|
|
266
|
+
value = value
|
|
267
|
+
.split('')
|
|
268
|
+
.map((v, i) => (i ? v + v : '#'))
|
|
269
|
+
.join('');
|
|
270
|
+
|
|
271
|
+
return value;
|
|
272
|
+
} else if (value.length === 7 || value.length === 9) {
|
|
273
|
+
return value;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return '#000000';
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function hex2rgb(hex: string): RGB {
|
|
280
|
+
const rbgArr = (
|
|
281
|
+
hex
|
|
282
|
+
.replace(
|
|
283
|
+
/^#?([a-f\d])([a-f\d])([a-f\d])$/i,
|
|
284
|
+
(m, r, g, b) => '#' + r + r + g + g + b + b,
|
|
285
|
+
)
|
|
286
|
+
.substring(1)
|
|
287
|
+
.match(/.{2}/g) || []
|
|
288
|
+
).map((x) => parseInt(x, 16));
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
b: rbgArr[2],
|
|
292
|
+
g: rbgArr[1],
|
|
293
|
+
r: rbgArr[0],
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function rgb2hsv({r, g, b}: RGB): HSV {
|
|
298
|
+
r /= 255;
|
|
299
|
+
g /= 255;
|
|
300
|
+
b /= 255;
|
|
301
|
+
|
|
302
|
+
const max = Math.max(r, g, b);
|
|
303
|
+
const d = max - Math.min(r, g, b);
|
|
304
|
+
|
|
305
|
+
const h = d
|
|
306
|
+
? (max === r
|
|
307
|
+
? (g - b) / d + (g < b ? 6 : 0)
|
|
308
|
+
: max === g
|
|
309
|
+
? 2 + (b - r) / d
|
|
310
|
+
: 4 + (r - g) / d) * 60
|
|
311
|
+
: 0;
|
|
312
|
+
const s = max ? (d / max) * 100 : 0;
|
|
313
|
+
const v = max * 100;
|
|
314
|
+
|
|
315
|
+
return {h, s, v};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function hsv2rgb({h, s, v}: HSV): RGB {
|
|
319
|
+
s /= 100;
|
|
320
|
+
v /= 100;
|
|
321
|
+
|
|
322
|
+
const i = ~~(h / 60);
|
|
323
|
+
const f = h / 60 - i;
|
|
324
|
+
const p = v * (1 - s);
|
|
325
|
+
const q = v * (1 - s * f);
|
|
326
|
+
const t = v * (1 - s * (1 - f));
|
|
327
|
+
const index = i % 6;
|
|
328
|
+
|
|
329
|
+
const r = Math.round([v, q, p, p, t, v][index] * 255);
|
|
330
|
+
const g = Math.round([t, v, v, q, p, p][index] * 255);
|
|
331
|
+
const b = Math.round([p, p, t, v, v, q][index] * 255);
|
|
332
|
+
|
|
333
|
+
return {b, g, r};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function rgb2hex({b, g, r}: RGB): string {
|
|
337
|
+
return '#' + [r, g, b].map((x) => x.toString(16).padStart(2, '0')).join('');
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function transformColor<M extends keyof Color, C extends Color[M]>(
|
|
341
|
+
format: M,
|
|
342
|
+
color: C,
|
|
343
|
+
): Color {
|
|
344
|
+
let hex: Color['hex'] = toHex('#121212');
|
|
345
|
+
let rgb: Color['rgb'] = hex2rgb(hex);
|
|
346
|
+
let hsv: Color['hsv'] = rgb2hsv(rgb);
|
|
347
|
+
|
|
348
|
+
if (format === 'hex') {
|
|
349
|
+
const value = color as Color['hex'];
|
|
350
|
+
|
|
351
|
+
hex = toHex(value);
|
|
352
|
+
rgb = hex2rgb(hex);
|
|
353
|
+
hsv = rgb2hsv(rgb);
|
|
354
|
+
} else if (format === 'rgb') {
|
|
355
|
+
const value = color as Color['rgb'];
|
|
356
|
+
|
|
357
|
+
rgb = value;
|
|
358
|
+
hex = rgb2hex(rgb);
|
|
359
|
+
hsv = rgb2hsv(rgb);
|
|
360
|
+
} else if (format === 'hsv') {
|
|
361
|
+
const value = color as Color['hsv'];
|
|
362
|
+
|
|
363
|
+
hsv = value;
|
|
364
|
+
rgb = hsv2rgb(hsv);
|
|
365
|
+
hex = rgb2hex(rgb);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return {hex, hsv, rgb};
|
|
369
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
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
|
+
.ContentEditable__root {
|
|
10
|
+
border: 0;
|
|
11
|
+
font-size: 15px;
|
|
12
|
+
display: block;
|
|
13
|
+
position: relative;
|
|
14
|
+
outline: 0;
|
|
15
|
+
// padding: 8px 46px 40px;
|
|
16
|
+
min-height: 150px;
|
|
17
|
+
& > [instance='true'] {
|
|
18
|
+
position: relative;
|
|
19
|
+
background-color: #f9f9f9;
|
|
20
|
+
border-left: 26px solid #e6e6e6;
|
|
21
|
+
padding: 0 10px;
|
|
22
|
+
margin-bottom: 6px;
|
|
23
|
+
> [number='true'] {
|
|
24
|
+
left: 10px;
|
|
25
|
+
}
|
|
26
|
+
> [bar='true'] {
|
|
27
|
+
& [data-bar='right'] {
|
|
28
|
+
right: 10px;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
& [instance='true'] {
|
|
32
|
+
border-top: 6px solid transparent;
|
|
33
|
+
&::before {
|
|
34
|
+
content: '';
|
|
35
|
+
display: block;
|
|
36
|
+
background-color: #fff;
|
|
37
|
+
height: 6px;
|
|
38
|
+
position: absolute;
|
|
39
|
+
top: -6px;
|
|
40
|
+
left: -36px;
|
|
41
|
+
right: -10px;
|
|
42
|
+
|
|
43
|
+
}
|
|
44
|
+
> [bar='true'] {
|
|
45
|
+
& [data-bar='left'] {
|
|
46
|
+
left: -10px;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/* @media (max-width: 1025px) {
|
|
53
|
+
.ContentEditable__root {
|
|
54
|
+
padding-left: 8px;
|
|
55
|
+
padding-right: 8px;
|
|
56
|
+
}
|
|
57
|
+
} */
|
|
58
|
+
|
|
59
|
+
.ContentEditable__placeholder {
|
|
60
|
+
font-size: 15px;
|
|
61
|
+
color: #999;
|
|
62
|
+
overflow: hidden;
|
|
63
|
+
position: absolute;
|
|
64
|
+
text-overflow: ellipsis;
|
|
65
|
+
top: 8px;
|
|
66
|
+
left: 46px;
|
|
67
|
+
right: 28px;
|
|
68
|
+
user-select: none;
|
|
69
|
+
white-space: nowrap;
|
|
70
|
+
display: inline-block;
|
|
71
|
+
pointer-events: none;
|
|
72
|
+
}
|
|
73
|
+
@media (max-width: 1025px) {
|
|
74
|
+
.ContentEditable__placeholder {
|
|
75
|
+
left: 8px;
|
|
76
|
+
right: 8px;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -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
|
+
import type {JSX} from 'react';
|
|
10
|
+
|
|
11
|
+
import {ContentEditable} from '@lexical/react/LexicalContentEditable';
|
|
12
|
+
import * as React from 'react';
|
|
13
|
+
|
|
14
|
+
import Styles from './ContentEditable.module.less';
|
|
15
|
+
|
|
16
|
+
type Props = {
|
|
17
|
+
className?: string;
|
|
18
|
+
placeholderClassName?: string;
|
|
19
|
+
placeholder: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default function LexicalContentEditable({
|
|
23
|
+
className,
|
|
24
|
+
placeholder,
|
|
25
|
+
placeholderClassName,
|
|
26
|
+
}: Props): JSX.Element {
|
|
27
|
+
return (
|
|
28
|
+
<ContentEditable
|
|
29
|
+
className={className ?? Styles.ContentEditable__root}
|
|
30
|
+
aria-placeholder={placeholder}
|
|
31
|
+
placeholder={
|
|
32
|
+
<div
|
|
33
|
+
className={
|
|
34
|
+
placeholderClassName ?? Styles.ContentEditable__placeholder
|
|
35
|
+
}>
|
|
36
|
+
{placeholder}
|
|
37
|
+
</div>
|
|
38
|
+
}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
.DialogActions {
|
|
10
|
+
display: flex;
|
|
11
|
+
flex-direction: row;
|
|
12
|
+
justify-content: right;
|
|
13
|
+
margin-top: 20px;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.DialogButtonsList {
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
justify-content: right;
|
|
20
|
+
button {
|
|
21
|
+
margin-bottom: 20px;
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/Dialog.tsx
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
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 {ReactNode} from 'react';
|
|
13
|
+
|
|
14
|
+
import Styles from './Dialog.module.less';
|
|
15
|
+
|
|
16
|
+
type Props = Readonly<{
|
|
17
|
+
'data-test-id'?: string;
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
}>;
|
|
20
|
+
|
|
21
|
+
export function DialogButtonsList({children}: Props): JSX.Element {
|
|
22
|
+
return <div className={Styles.DialogButtonsList}>{children}</div>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function DialogActions({
|
|
26
|
+
'data-test-id': dataTestId,
|
|
27
|
+
children,
|
|
28
|
+
}: Props): JSX.Element {
|
|
29
|
+
return (
|
|
30
|
+
<div className={Styles.DialogActions} data-test-id={dataTestId}>
|
|
31
|
+
{children}
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
.dropdown {
|
|
2
|
+
z-index: 100;
|
|
3
|
+
display: block;
|
|
4
|
+
position: fixed;
|
|
5
|
+
box-shadow:
|
|
6
|
+
0 12px 28px 0 rgba(0, 0, 0, 0.2),
|
|
7
|
+
0 2px 4px 0 rgba(0, 0, 0, 0.1),
|
|
8
|
+
inset 0 0 0 1px rgba(255, 255, 255, 0.5);
|
|
9
|
+
// border-radius: 8px;
|
|
10
|
+
min-height: 40px;
|
|
11
|
+
background-color: #fff;
|
|
12
|
+
z-index: 1000;
|
|
13
|
+
:global {
|
|
14
|
+
.item {
|
|
15
|
+
margin: 0 8px 0 8px;
|
|
16
|
+
padding: 8px;
|
|
17
|
+
color: #050505;
|
|
18
|
+
cursor: pointer;
|
|
19
|
+
line-height: 16px;
|
|
20
|
+
font-size: 15px;
|
|
21
|
+
display: flex;
|
|
22
|
+
align-content: center;
|
|
23
|
+
flex-direction: row;
|
|
24
|
+
flex-shrink: 0;
|
|
25
|
+
justify-content: space-between;
|
|
26
|
+
background-color: #fff;
|
|
27
|
+
// border-radius: 8px;
|
|
28
|
+
border: 0;
|
|
29
|
+
max-width: 250px;
|
|
30
|
+
min-width: 100px;
|
|
31
|
+
&:first-child {
|
|
32
|
+
margin-top: 8px;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&:last-child {
|
|
36
|
+
margin-bottom: 8px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
&:hover {
|
|
40
|
+
background-color: #eee;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
&.wide {
|
|
44
|
+
align-items: center;
|
|
45
|
+
width: 248px;
|
|
46
|
+
|
|
47
|
+
.icon-text-container {
|
|
48
|
+
display: flex;
|
|
49
|
+
|
|
50
|
+
.text {
|
|
51
|
+
min-width: 120px;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.shortcut {
|
|
57
|
+
color: #939393;
|
|
58
|
+
align-self: flex-end;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.active {
|
|
62
|
+
display: flex;
|
|
63
|
+
width: 20px;
|
|
64
|
+
height: 20px;
|
|
65
|
+
background-size: contain;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.text {
|
|
69
|
+
display: flex;
|
|
70
|
+
line-height: 20px;
|
|
71
|
+
flex-grow: 1;
|
|
72
|
+
min-width: 150px;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.icon {
|
|
76
|
+
display: flex;
|
|
77
|
+
width: 20px;
|
|
78
|
+
height: 20px;
|
|
79
|
+
user-select: none;
|
|
80
|
+
margin-right: 12px;
|
|
81
|
+
line-height: 16px;
|
|
82
|
+
background-size: contain;
|
|
83
|
+
background-position: center;
|
|
84
|
+
background-repeat: no-repeat;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.divider {
|
|
89
|
+
width: auto;
|
|
90
|
+
background-color: #eee;
|
|
91
|
+
margin: 4px 8px;
|
|
92
|
+
height: 1px;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|