@hero-design/rn-work-uikit 1.9.2 → 1.9.4
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/CHANGELOG.md +18 -0
- package/assets/fonts/hero-icons-mobile.ttf +0 -0
- package/lib/index.js +19732 -304
- package/package.json +2 -20
- package/src/components/FormGroup/index.tsx +1 -1
- package/src/components/RichTextEditor/EditorToolbar.tsx +30 -80
- package/src/components/RichTextEditor/MentionList.tsx +1 -1
- package/src/components/RichTextEditor/RichTextEditor.tsx +3 -13
- package/src/components/RichTextEditor/RichTextEditorInput.tsx +22 -2
- package/src/components/RichTextEditor/StyledRichTextEditor.tsx +0 -1
- package/src/components/RichTextEditor/__tests__/EditorToolbar.spec.tsx +40 -30
- package/src/components/RichTextEditor/__tests__/RichTextEditorInput.spec.tsx +38 -0
- package/src/components/RichTextEditor/__tests__/__snapshots__/EditorToolbar.spec.tsx.snap +0 -7
- package/src/components/RichTextEditor/constants.ts +18 -0
- package/src/components/RichTextEditor/hooks/useRichTextEditorEvents.ts +79 -0
- package/src/components/RichTextEditor/index.tsx +8 -1
- package/src/components/RichTextEditor/utils/events.ts +1 -13
- package/src/components/TextInput/ErrorOrHelpText.tsx +1 -1
- package/src/components/TextInput/FloatingLabel.tsx +1 -1
- package/src/components/TextInput/InputComponent.tsx +1 -1
- package/src/components/TextInput/MaxLengthMessage.tsx +1 -1
- package/src/components/TextInput/PrefixComponent.tsx +1 -1
- package/src/components/TextInput/StyledTextInput.tsx +0 -8
- package/src/components/TextInput/SuffixComponent.tsx +1 -1
- package/src/index.ts +2 -1
- package/src/theme/ThemeProvider.ts +1 -3
- package/src/utils/helpers.ts +1 -41
- package/.cursor/rules/performance-optimization.mdc +0 -64
- package/.cursor/rules/rn-work-uikit-rules.mdc +0 -202
- package/.cursor/rules/testing-rules.mdc +0 -114
- package/stats/1.9.2/rn-work-uikit-stats.html +0 -4844
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hero-design/rn-work-uikit",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "es/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@emotion/native": "^11.9.3",
|
|
24
24
|
"@emotion/react": "^11.9.3",
|
|
25
|
-
"@hero-design/rn": "^8.
|
|
25
|
+
"@hero-design/rn": "^8.113.0",
|
|
26
26
|
"hero-editor": "^1.17.0"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
@@ -55,15 +55,9 @@
|
|
|
55
55
|
"@hero-design/eslint-plugin": "9.2.1",
|
|
56
56
|
"@hero-design/react-native-month-year-picker": "^8.43.2",
|
|
57
57
|
"@ptomasroos/react-native-multi-slider": "^2.2.2",
|
|
58
|
-
"@react-native-community/cli": "15.0.1",
|
|
59
|
-
"@react-native-community/cli-platform-android": "15.0.1",
|
|
60
|
-
"@react-native-community/cli-platform-ios": "15.0.1",
|
|
61
58
|
"@react-native-community/datetimepicker": "8.2.0",
|
|
62
59
|
"@react-native-community/slider": "^4.5.1",
|
|
63
60
|
"@react-native/babel-preset": "0.77.3",
|
|
64
|
-
"@react-native/eslint-config": "0.77.3",
|
|
65
|
-
"@react-native/metro-config": "0.77.3",
|
|
66
|
-
"@react-native/typescript-config": "0.77.3",
|
|
67
61
|
"@rollup/plugin-alias": "^5.1.1",
|
|
68
62
|
"@rollup/plugin-babel": "^6.0.4",
|
|
69
63
|
"@rollup/plugin-commonjs": "^28.0.1",
|
|
@@ -72,32 +66,20 @@
|
|
|
72
66
|
"@rollup/plugin-replace": "^6.0.1",
|
|
73
67
|
"@rollup/plugin-typescript": "^12.1.1",
|
|
74
68
|
"@testing-library/jest-native": "^5.4.2",
|
|
75
|
-
"@testing-library/react-hooks": "^8.0.1",
|
|
76
69
|
"@testing-library/react-native": "^9.1.0",
|
|
77
70
|
"@types/jest": "^29.5.3",
|
|
78
71
|
"@types/react": "^18.2.0",
|
|
79
72
|
"@types/react-native-vector-icons": "^6.4.10",
|
|
80
73
|
"@types/react-test-renderer": "^19.1.0",
|
|
81
74
|
"@typescript-eslint/eslint-plugin": "^5.12.1",
|
|
82
|
-
"@typescript-eslint/parser": "^5.12.1",
|
|
83
75
|
"babel-plugin-inline-import": "^3.0.0",
|
|
84
76
|
"babel-plugin-module-resolver": "^5.0.2",
|
|
85
|
-
"config-tsconfig": "8.42.5",
|
|
86
77
|
"core-js": "^3.33.0",
|
|
87
78
|
"eslint": "^8.56.0",
|
|
88
|
-
"eslint-config-airbnb": "^19.0.4",
|
|
89
79
|
"eslint-config-hd": "8.42.5",
|
|
90
|
-
"eslint-config-prettier": "^8.5.0",
|
|
91
|
-
"eslint-import-resolver-typescript": "^3.5.2",
|
|
92
|
-
"eslint-plugin-import": "^2.32.0",
|
|
93
|
-
"eslint-plugin-jsx-a11y": "^6.5.1",
|
|
94
|
-
"eslint-plugin-prettier": "^4.0.0",
|
|
95
|
-
"eslint-plugin-react": "^7.37.5",
|
|
96
|
-
"eslint-plugin-react-hooks": "^4.3.0",
|
|
97
80
|
"jest": "^29.2.1",
|
|
98
81
|
"jest-environment-jsdom": "^29.2.1",
|
|
99
82
|
"jest-junit": "^16.0.0",
|
|
100
|
-
"prettier": "^2.5.1",
|
|
101
83
|
"prettier-config-hd": "8.42.4",
|
|
102
84
|
"react": "18.3.1",
|
|
103
85
|
"react-dom": "^18.2.0",
|
|
@@ -5,7 +5,7 @@ import { StyleSheet } from 'react-native';
|
|
|
5
5
|
import { Box, useTheme } from '@hero-design/rn';
|
|
6
6
|
import { generateBorderStyle, generateMarginStyle } from './utils';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
interface FormGroupProps extends ViewProps {
|
|
9
9
|
/**
|
|
10
10
|
* The children of the FormGroup. In order for the group styling to work,
|
|
11
11
|
* they must be either HD form components (TextInput, Select, Pickers,...) or enhanced HD input components
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
2
2
|
import type { ComponentType } from 'react';
|
|
3
3
|
import type { IconProps } from '@hero-design/rn';
|
|
4
4
|
import { Icon } from '@hero-design/rn';
|
|
5
|
-
import { ToolbarEvents } from './constants';
|
|
6
|
-
import { emitter } from './EditorEvent';
|
|
5
|
+
import { EditorEvents, ToolbarEvents } from './constants';
|
|
7
6
|
import {
|
|
8
7
|
StyledSeparator,
|
|
9
8
|
StyledToolbar,
|
|
10
9
|
StyledToolbarButton,
|
|
11
10
|
} from './StyledToolbar';
|
|
12
11
|
import type { ToolbarButtonName } from './types';
|
|
13
|
-
import
|
|
12
|
+
import useRichTextEditorEvents from './hooks/useRichTextEditorEvents';
|
|
14
13
|
|
|
15
14
|
type ToolbarButtonProps = {
|
|
16
15
|
icon: IconProps['icon'];
|
|
@@ -97,12 +96,6 @@ export interface EditorToolbarProps {
|
|
|
97
96
|
testID?: string;
|
|
98
97
|
}
|
|
99
98
|
|
|
100
|
-
type ButtonType = {
|
|
101
|
-
id: number;
|
|
102
|
-
buttonName: ToolbarButtonName;
|
|
103
|
-
selected: boolean;
|
|
104
|
-
};
|
|
105
|
-
|
|
106
99
|
const EditorToolbar = ({
|
|
107
100
|
name,
|
|
108
101
|
buttons = defaultButtons,
|
|
@@ -110,102 +103,59 @@ const EditorToolbar = ({
|
|
|
110
103
|
}: EditorToolbarProps) => {
|
|
111
104
|
const [show, setShow] = useState(false);
|
|
112
105
|
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
selected: false,
|
|
118
|
-
})
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
const [toolbarButtonArray, setToolbarButtonArray] = useState<ButtonType[]>(
|
|
122
|
-
initialToolbarButtonArray
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
const normalizeEventName = useCallback(
|
|
126
|
-
(event: string): string => `${name}/${event}`,
|
|
127
|
-
[name]
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
const toggleToolbarButton = useCallback(
|
|
131
|
-
({ buttonName: currentButtonName, selected: prevSelected }: ButtonType) => {
|
|
132
|
-
const currentButtonConfig = buttonConfigs[currentButtonName];
|
|
133
|
-
const isStandalone =
|
|
134
|
-
currentButtonConfig && currentButtonConfig.standalone;
|
|
135
|
-
|
|
136
|
-
setToolbarButtonArray((prevState) =>
|
|
137
|
-
prevState.map((updatingButton) => {
|
|
138
|
-
if (updatingButton.buttonName === currentButtonName) {
|
|
139
|
-
return {
|
|
140
|
-
...updatingButton,
|
|
141
|
-
selected: !prevSelected,
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const updatingButtonConfig = buttonConfigs[updatingButton.buttonName];
|
|
146
|
-
const shouldToggleOff =
|
|
147
|
-
!prevSelected &&
|
|
148
|
-
isStandalone &&
|
|
149
|
-
updatingButtonConfig &&
|
|
150
|
-
updatingButtonConfig.standalone;
|
|
151
|
-
|
|
152
|
-
return {
|
|
153
|
-
...updatingButton,
|
|
154
|
-
selected: shouldToggleOff ? false : updatingButton.selected,
|
|
155
|
-
};
|
|
156
|
-
})
|
|
157
|
-
);
|
|
158
|
-
},
|
|
159
|
-
[]
|
|
160
|
-
);
|
|
106
|
+
const { emitEvent, subscribeToEvents } = useRichTextEditorEvents(name);
|
|
107
|
+
const [toolbarButtonState, setToolbarButtonState] = useState<
|
|
108
|
+
Record<string, boolean>
|
|
109
|
+
>({});
|
|
161
110
|
|
|
162
111
|
useEffect(() => {
|
|
163
|
-
const removeFocusListener =
|
|
164
|
-
|
|
165
|
-
normalizeEventName('editor-focus'),
|
|
112
|
+
const removeFocusListener = subscribeToEvents(
|
|
113
|
+
EditorEvents.EditorFocus,
|
|
166
114
|
() => setShow(true)
|
|
167
115
|
);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
116
|
+
const removeBlurListener = subscribeToEvents(EditorEvents.EditorBlur, () =>
|
|
117
|
+
setShow(false)
|
|
118
|
+
);
|
|
119
|
+
const removeEditorChangeListener = subscribeToEvents(
|
|
120
|
+
EditorEvents.EditorChange,
|
|
121
|
+
({ toolbarState = {} }) => {
|
|
122
|
+
setToolbarButtonState(toolbarState);
|
|
123
|
+
}
|
|
173
124
|
);
|
|
174
125
|
|
|
175
126
|
return () => {
|
|
176
127
|
removeFocusListener();
|
|
177
128
|
removeBlurListener();
|
|
129
|
+
removeEditorChangeListener();
|
|
178
130
|
};
|
|
179
|
-
}, [
|
|
131
|
+
}, []);
|
|
180
132
|
|
|
181
133
|
const toolbarButtons = useMemo(
|
|
182
134
|
() =>
|
|
183
|
-
|
|
184
|
-
if (button
|
|
185
|
-
return <StyledSeparator key={
|
|
135
|
+
buttons.map((button, index) => {
|
|
136
|
+
if (button === '|') {
|
|
137
|
+
return <StyledSeparator key={index} />;
|
|
186
138
|
}
|
|
187
|
-
const config = buttonConfigs[button
|
|
139
|
+
const config = buttonConfigs[button];
|
|
188
140
|
if (config) {
|
|
189
141
|
return (
|
|
190
142
|
<ToolbarButton
|
|
191
|
-
key={button
|
|
143
|
+
key={button}
|
|
192
144
|
testID={config.icon}
|
|
193
145
|
icon={config.icon}
|
|
194
146
|
onPress={() => {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
null
|
|
200
|
-
);
|
|
147
|
+
emitEvent({
|
|
148
|
+
type: config.eventName,
|
|
149
|
+
data: null,
|
|
150
|
+
});
|
|
201
151
|
}}
|
|
202
|
-
selected={
|
|
152
|
+
selected={toolbarButtonState[config.eventName]}
|
|
203
153
|
/>
|
|
204
154
|
);
|
|
205
155
|
}
|
|
206
156
|
return null;
|
|
207
157
|
}),
|
|
208
|
-
[
|
|
158
|
+
[toolbarButtonState, buttons]
|
|
209
159
|
);
|
|
210
160
|
|
|
211
161
|
if (show) {
|
|
@@ -72,7 +72,7 @@ const MentionList = <TMetaData,>({
|
|
|
72
72
|
const { highlighted, meta } = options;
|
|
73
73
|
|
|
74
74
|
const highlightStyle = {
|
|
75
|
-
color: theme.colors.
|
|
75
|
+
color: theme.colors.primary,
|
|
76
76
|
borderRadius: theme.__hd__.richTextEditor.radii.mention,
|
|
77
77
|
padding: highlighted ? theme.__hd__.richTextEditor.space.mention : 0,
|
|
78
78
|
background: highlighted
|
|
@@ -5,11 +5,8 @@ import { plainSerializer } from 'hero-editor';
|
|
|
5
5
|
import { InternalTextInput } from '../TextInput';
|
|
6
6
|
import RichTextEditorInput from './RichTextEditorInput';
|
|
7
7
|
import { StyledWrapper } from './StyledRichTextEditor';
|
|
8
|
-
import type {
|
|
9
|
-
|
|
10
|
-
InternalRichTextEditorProps,
|
|
11
|
-
TextUnit,
|
|
12
|
-
} from './types';
|
|
8
|
+
import type { InternalRichTextEditorProps, TextUnit } from './types';
|
|
9
|
+
import { DEFAULT_VALUE } from './constants';
|
|
13
10
|
|
|
14
11
|
export interface RichTextEditorRef {
|
|
15
12
|
requestBlur: VoidFunction;
|
|
@@ -18,13 +15,6 @@ export interface RichTextEditorRef {
|
|
|
18
15
|
setReadOnly: (readOnly: boolean) => void;
|
|
19
16
|
}
|
|
20
17
|
|
|
21
|
-
const defaultValue: EditorValue = [
|
|
22
|
-
{
|
|
23
|
-
type: 'paragraph',
|
|
24
|
-
children: [{ text: '' }],
|
|
25
|
-
},
|
|
26
|
-
];
|
|
27
|
-
|
|
28
18
|
const RichTextEditor: ComponentType<InternalRichTextEditorProps> = ({
|
|
29
19
|
autoFocus = true,
|
|
30
20
|
name,
|
|
@@ -39,7 +29,7 @@ const RichTextEditor: ComponentType<InternalRichTextEditorProps> = ({
|
|
|
39
29
|
required,
|
|
40
30
|
testID,
|
|
41
31
|
forwardedRef,
|
|
42
|
-
value =
|
|
32
|
+
value = DEFAULT_VALUE,
|
|
43
33
|
groupStyleEnabled = false,
|
|
44
34
|
}: InternalRichTextEditorProps): ReactElement => {
|
|
45
35
|
const plain = useMemo(() => plainSerializer(value), [value]);
|
|
@@ -16,7 +16,7 @@ import { isAndroid } from '../../utils/helpers';
|
|
|
16
16
|
import { emitter } from './EditorEvent';
|
|
17
17
|
import * as Events from './utils/events';
|
|
18
18
|
import heroEditorApp from './heroEditorApp';
|
|
19
|
-
import { ToolbarEvents } from './constants';
|
|
19
|
+
import { DEFAULT_VALUE, ToolbarEvents } from './constants';
|
|
20
20
|
import type { EditorValue, RichTextEditorRef, TextUnit } from './types';
|
|
21
21
|
import {
|
|
22
22
|
postMessage,
|
|
@@ -44,7 +44,6 @@ const RichTextEditorInput = forwardRef<
|
|
|
44
44
|
>(
|
|
45
45
|
(
|
|
46
46
|
{
|
|
47
|
-
value,
|
|
48
47
|
name,
|
|
49
48
|
autoFocus,
|
|
50
49
|
placeholder,
|
|
@@ -53,6 +52,7 @@ const RichTextEditorInput = forwardRef<
|
|
|
53
52
|
forwardedRef,
|
|
54
53
|
onFocus,
|
|
55
54
|
onBlur,
|
|
55
|
+
value = DEFAULT_VALUE,
|
|
56
56
|
},
|
|
57
57
|
ref
|
|
58
58
|
) => {
|
|
@@ -107,6 +107,9 @@ const RichTextEditorInput = forwardRef<
|
|
|
107
107
|
body {
|
|
108
108
|
margin: 0;
|
|
109
109
|
}
|
|
110
|
+
a {
|
|
111
|
+
color: ${theme.__hd__.typography.colors.primary};
|
|
112
|
+
}
|
|
110
113
|
</style>
|
|
111
114
|
</head>
|
|
112
115
|
<body>
|
|
@@ -232,7 +235,13 @@ const RichTextEditorInput = forwardRef<
|
|
|
232
235
|
case '@hero-editor/webview/editor-change':
|
|
233
236
|
if (messageData) {
|
|
234
237
|
onChange(messageData.value);
|
|
238
|
+
Events.emit(
|
|
239
|
+
emitter,
|
|
240
|
+
normalizeEventName('editor-change'),
|
|
241
|
+
messageData
|
|
242
|
+
);
|
|
235
243
|
}
|
|
244
|
+
|
|
236
245
|
break;
|
|
237
246
|
case '@hero-editor/webview/cursor-change':
|
|
238
247
|
onCursorChange?.(messageData);
|
|
@@ -240,6 +249,15 @@ const RichTextEditorInput = forwardRef<
|
|
|
240
249
|
case '@hero-editor/webview/editor-layout':
|
|
241
250
|
handleEditorLayoutEvent(messageData);
|
|
242
251
|
break;
|
|
252
|
+
|
|
253
|
+
case '@hero-editor/webview/request-upsert-link':
|
|
254
|
+
Events.emit(
|
|
255
|
+
emitter,
|
|
256
|
+
normalizeEventName('request-upsert-link'),
|
|
257
|
+
messageData
|
|
258
|
+
);
|
|
259
|
+
break;
|
|
260
|
+
|
|
243
261
|
default:
|
|
244
262
|
break;
|
|
245
263
|
}
|
|
@@ -272,6 +290,8 @@ const RichTextEditorInput = forwardRef<
|
|
|
272
290
|
<View
|
|
273
291
|
style={{
|
|
274
292
|
height: webviewHeight,
|
|
293
|
+
flex: 1,
|
|
294
|
+
width: '100%',
|
|
275
295
|
}}
|
|
276
296
|
>
|
|
277
297
|
<StyledWebView
|
|
@@ -2,10 +2,10 @@ import React from 'react';
|
|
|
2
2
|
import { act, fireEvent, waitFor } from '@testing-library/react-native';
|
|
3
3
|
import type { RenderAPI } from '@testing-library/react-native';
|
|
4
4
|
import EditorToolbar from '../EditorToolbar';
|
|
5
|
-
import { emitter as
|
|
6
|
-
import { theme, ThemeProvider } from '../../../index';
|
|
7
|
-
import * as Events from '../utils/events';
|
|
5
|
+
import { emitter as editorEventEmitter } from '../EditorEvent';
|
|
8
6
|
import renderWithTheme from '../../../../testUtils/renderWithTheme';
|
|
7
|
+
import { theme } from '../../../index';
|
|
8
|
+
import * as Events from '../utils/events';
|
|
9
9
|
|
|
10
10
|
describe('EditorToolbar', () => {
|
|
11
11
|
it('should not render toolbar when the editor is not focused', () => {
|
|
@@ -24,7 +24,7 @@ describe('EditorToolbar', () => {
|
|
|
24
24
|
<EditorToolbar name="toolbar" testID="toolbar" />
|
|
25
25
|
);
|
|
26
26
|
act(() => {
|
|
27
|
-
|
|
27
|
+
editorEventEmitter.emit('toolbar/editor-focus');
|
|
28
28
|
});
|
|
29
29
|
await waitFor(() => wrapper.getByTestId('toolbar'));
|
|
30
30
|
});
|
|
@@ -47,15 +47,15 @@ describe('EditorToolbar', () => {
|
|
|
47
47
|
|
|
48
48
|
it('should hide toolbar when blur', async () => {
|
|
49
49
|
act(() => {
|
|
50
|
-
|
|
50
|
+
editorEventEmitter.emit('toolbar/editor-blur');
|
|
51
51
|
});
|
|
52
52
|
await waitFor(() => wrapper.queryAllByTestId('toolbar').length === 0);
|
|
53
53
|
expect(wrapper.queryAllByTestId('toolbar')).toHaveLength(0);
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
describe("should change button's background color when pressing", () => {
|
|
57
|
-
it('should send event and highlight buttons correctly',
|
|
58
|
-
const
|
|
57
|
+
it('should send event and highlight buttons correctly', () => {
|
|
58
|
+
const emittedEvents: string[] = [];
|
|
59
59
|
|
|
60
60
|
const eventNameAndTestIDArray = [
|
|
61
61
|
{
|
|
@@ -88,34 +88,16 @@ describe('EditorToolbar', () => {
|
|
|
88
88
|
},
|
|
89
89
|
];
|
|
90
90
|
|
|
91
|
-
eventNameAndTestIDArray.forEach(
|
|
92
|
-
Events.on(
|
|
93
|
-
|
|
91
|
+
eventNameAndTestIDArray.forEach(({ eventName, testID }) => {
|
|
92
|
+
Events.on(editorEventEmitter, eventName, () => {
|
|
93
|
+
emittedEvents.push(testID);
|
|
94
94
|
});
|
|
95
95
|
|
|
96
96
|
expect(wrapper.getByTestId(testID)).toHaveStyle({
|
|
97
97
|
backgroundColor: undefined,
|
|
98
98
|
});
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
fireEvent.press(wrapper.getByTestId(testID));
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
// rerender
|
|
105
|
-
wrapper.rerender(
|
|
106
|
-
<ThemeProvider theme={theme}>
|
|
107
|
-
<EditorToolbar name="toolbar" testID="toolbar" />
|
|
108
|
-
</ThemeProvider>
|
|
109
|
-
);
|
|
110
|
-
// match snapshot
|
|
111
|
-
// add waitfor to ensure the style is applied
|
|
112
|
-
await waitFor(() => {
|
|
113
|
-
expect(wrapper.getByTestId(testID)).toHaveStyle({
|
|
114
|
-
backgroundColor:
|
|
115
|
-
theme.__hd__.richTextEditor.colors
|
|
116
|
-
.toolbarButtonSelectedBackground,
|
|
117
|
-
});
|
|
118
|
-
});
|
|
100
|
+
fireEvent(wrapper.getByTestId(testID), 'press');
|
|
119
101
|
});
|
|
120
102
|
|
|
121
103
|
const standaloneButtonTestIDs = [
|
|
@@ -129,7 +111,7 @@ describe('EditorToolbar', () => {
|
|
|
129
111
|
});
|
|
130
112
|
});
|
|
131
113
|
|
|
132
|
-
expect(
|
|
114
|
+
expect(emittedEvents).toMatchObject([
|
|
133
115
|
'format-bold',
|
|
134
116
|
'format-italic',
|
|
135
117
|
'format-underlined',
|
|
@@ -139,6 +121,34 @@ describe('EditorToolbar', () => {
|
|
|
139
121
|
'format-heading2',
|
|
140
122
|
]);
|
|
141
123
|
});
|
|
124
|
+
|
|
125
|
+
it('should highlight buttons correctly', async () => {
|
|
126
|
+
act(() => {
|
|
127
|
+
editorEventEmitter.emit('toolbar/editor-change', {
|
|
128
|
+
toolbarState: {
|
|
129
|
+
bold: true,
|
|
130
|
+
italic: true,
|
|
131
|
+
underline: true,
|
|
132
|
+
'heading-one': true,
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
[
|
|
138
|
+
'format-bold',
|
|
139
|
+
'format-italic',
|
|
140
|
+
'format-underlined',
|
|
141
|
+
'format-heading1',
|
|
142
|
+
].forEach(async (testID) => {
|
|
143
|
+
await waitFor(() => {
|
|
144
|
+
expect(wrapper.getByTestId(testID)).toHaveStyle({
|
|
145
|
+
backgroundColor:
|
|
146
|
+
theme.__hd__.richTextEditor.colors
|
|
147
|
+
.toolbarButtonSelectedBackground,
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
142
152
|
});
|
|
143
153
|
});
|
|
144
154
|
});
|
|
@@ -133,4 +133,42 @@ describe('RichTextEditorInput', () => {
|
|
|
133
133
|
|
|
134
134
|
expect(onCursorChange).toHaveBeenCalledWith(cursorData);
|
|
135
135
|
});
|
|
136
|
+
|
|
137
|
+
it('handles request-upsert-link event from webview', () => {
|
|
138
|
+
const { getByTestId } = renderWithTheme(
|
|
139
|
+
<RichTextEditorInput
|
|
140
|
+
value={initialValue}
|
|
141
|
+
name="test-editor"
|
|
142
|
+
autoFocus={false}
|
|
143
|
+
placeholder="Type here..."
|
|
144
|
+
onChange={jest.fn()}
|
|
145
|
+
/>
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const webview = getByTestId('webview');
|
|
149
|
+
// Spy on emitter
|
|
150
|
+
const spy = jest.spyOn(Events, 'emit');
|
|
151
|
+
|
|
152
|
+
fireEvent(webview, 'message', {
|
|
153
|
+
nativeEvent: {
|
|
154
|
+
data: JSON.stringify({
|
|
155
|
+
type: '@hero-editor/webview/request-upsert-link',
|
|
156
|
+
data: {
|
|
157
|
+
text: 'Test',
|
|
158
|
+
url: 'https://test.com',
|
|
159
|
+
},
|
|
160
|
+
}),
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
expect(spy).toHaveBeenCalledWith(
|
|
164
|
+
emitter,
|
|
165
|
+
'test-editor/request-upsert-link',
|
|
166
|
+
{
|
|
167
|
+
text: 'Test',
|
|
168
|
+
url: 'https://test.com',
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
spy.mockRestore();
|
|
173
|
+
});
|
|
136
174
|
});
|
|
@@ -21,7 +21,6 @@ exports[`EditorToolbar when the editor is focused should render toolbar 1`] = `
|
|
|
21
21
|
>
|
|
22
22
|
<TouchableOpacity
|
|
23
23
|
onPress={[Function]}
|
|
24
|
-
selected={false}
|
|
25
24
|
style={
|
|
26
25
|
[
|
|
27
26
|
[
|
|
@@ -72,7 +71,6 @@ exports[`EditorToolbar when the editor is focused should render toolbar 1`] = `
|
|
|
72
71
|
</TouchableOpacity>
|
|
73
72
|
<TouchableOpacity
|
|
74
73
|
onPress={[Function]}
|
|
75
|
-
selected={false}
|
|
76
74
|
style={
|
|
77
75
|
[
|
|
78
76
|
[
|
|
@@ -123,7 +121,6 @@ exports[`EditorToolbar when the editor is focused should render toolbar 1`] = `
|
|
|
123
121
|
</TouchableOpacity>
|
|
124
122
|
<TouchableOpacity
|
|
125
123
|
onPress={[Function]}
|
|
126
|
-
selected={false}
|
|
127
124
|
style={
|
|
128
125
|
[
|
|
129
126
|
[
|
|
@@ -191,7 +188,6 @@ exports[`EditorToolbar when the editor is focused should render toolbar 1`] = `
|
|
|
191
188
|
/>
|
|
192
189
|
<TouchableOpacity
|
|
193
190
|
onPress={[Function]}
|
|
194
|
-
selected={false}
|
|
195
191
|
style={
|
|
196
192
|
[
|
|
197
193
|
[
|
|
@@ -242,7 +238,6 @@ exports[`EditorToolbar when the editor is focused should render toolbar 1`] = `
|
|
|
242
238
|
</TouchableOpacity>
|
|
243
239
|
<TouchableOpacity
|
|
244
240
|
onPress={[Function]}
|
|
245
|
-
selected={false}
|
|
246
241
|
style={
|
|
247
242
|
[
|
|
248
243
|
[
|
|
@@ -310,7 +305,6 @@ exports[`EditorToolbar when the editor is focused should render toolbar 1`] = `
|
|
|
310
305
|
/>
|
|
311
306
|
<TouchableOpacity
|
|
312
307
|
onPress={[Function]}
|
|
313
|
-
selected={false}
|
|
314
308
|
style={
|
|
315
309
|
[
|
|
316
310
|
[
|
|
@@ -361,7 +355,6 @@ exports[`EditorToolbar when the editor is focused should render toolbar 1`] = `
|
|
|
361
355
|
</TouchableOpacity>
|
|
362
356
|
<TouchableOpacity
|
|
363
357
|
onPress={[Function]}
|
|
364
|
-
selected={false}
|
|
365
358
|
style={
|
|
366
359
|
[
|
|
367
360
|
[
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { EditorValue } from './types';
|
|
2
|
+
|
|
1
3
|
export enum ToolbarEvents {
|
|
2
4
|
Bold = 'bold',
|
|
3
5
|
Italic = 'italic',
|
|
@@ -6,4 +8,20 @@ export enum ToolbarEvents {
|
|
|
6
8
|
NumberedList = 'numbered-list',
|
|
7
9
|
HeadingOne = 'heading-one',
|
|
8
10
|
HeadingTwo = 'heading-two',
|
|
11
|
+
AddLink = 'add-link',
|
|
12
|
+
ApplyLink = 'link',
|
|
9
13
|
}
|
|
14
|
+
|
|
15
|
+
export enum EditorEvents {
|
|
16
|
+
EditorFocus = 'editor-focus',
|
|
17
|
+
EditorBlur = 'editor-blur',
|
|
18
|
+
EditorChange = 'editor-change',
|
|
19
|
+
UpsertLink = 'request-upsert-link',
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const DEFAULT_VALUE: EditorValue = [
|
|
23
|
+
{
|
|
24
|
+
type: 'paragraph',
|
|
25
|
+
children: [{ text: '' }],
|
|
26
|
+
},
|
|
27
|
+
];
|