@akinon/ui-editor 1.0.5 → 1.0.7-rc.0
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/dist/cjs/i18n/translations/en.d.ts +1 -0
- package/dist/cjs/i18n/translations/en.d.ts.map +1 -1
- package/dist/cjs/i18n/translations/en.js +1 -0
- package/dist/cjs/i18n/translations/tr.d.ts +1 -0
- package/dist/cjs/i18n/translations/tr.d.ts.map +1 -1
- package/dist/cjs/i18n/translations/tr.js +1 -0
- package/dist/cjs/tiptap/components/__tests__/html-code-viewer.test.js +0 -8
- package/dist/cjs/tiptap/components/__tests__/html-code-viewer.test.tsx +0 -11
- package/dist/cjs/tiptap/components/__tests__/tiptap.test.js +53 -12
- package/dist/cjs/tiptap/components/__tests__/tiptap.test.tsx +79 -13
- package/dist/cjs/tiptap/components/html-code-viewer.d.ts.map +1 -1
- package/dist/cjs/tiptap/components/html-code-viewer.js +1 -24
- package/dist/cjs/tiptap/components/menu-bar/__tests__/action-toolbar.test.js +7 -7
- package/dist/cjs/tiptap/components/menu-bar/__tests__/action-toolbar.test.tsx +7 -0
- package/dist/cjs/tiptap/components/menu-bar/__tests__/index.test.js +1 -0
- package/dist/cjs/tiptap/components/menu-bar/__tests__/index.test.tsx +1 -0
- package/dist/cjs/tiptap/components/menu-bar/action-toolbar.d.ts +2 -1
- package/dist/cjs/tiptap/components/menu-bar/action-toolbar.d.ts.map +1 -1
- package/dist/cjs/tiptap/components/menu-bar/action-toolbar.js +10 -2
- package/dist/cjs/tiptap/components/menu-bar/index.d.ts +2 -1
- package/dist/cjs/tiptap/components/menu-bar/index.d.ts.map +1 -1
- package/dist/cjs/tiptap/components/menu-bar/index.js +2 -2
- package/dist/cjs/tiptap/components/tiptap.d.ts.map +1 -1
- package/dist/cjs/tiptap/components/tiptap.js +23 -9
- package/dist/cjs/tiptap/constants/editor-config.d.ts +1 -0
- package/dist/cjs/tiptap/constants/editor-config.d.ts.map +1 -1
- package/dist/cjs/tiptap/constants/editor-config.js +1 -0
- package/dist/cjs/tiptap/utils/__tests__/clean-html.test.js +26 -7
- package/dist/cjs/tiptap/utils/__tests__/clean-html.test.ts +29 -7
- package/dist/cjs/tiptap/utils/prettier-format.js +1 -1
- package/dist/esm/i18n/translations/en.d.ts +1 -0
- package/dist/esm/i18n/translations/en.d.ts.map +1 -1
- package/dist/esm/i18n/translations/en.js +1 -0
- package/dist/esm/i18n/translations/tr.d.ts +1 -0
- package/dist/esm/i18n/translations/tr.d.ts.map +1 -1
- package/dist/esm/i18n/translations/tr.js +1 -0
- package/dist/esm/tiptap/components/__tests__/html-code-viewer.test.js +0 -8
- package/dist/esm/tiptap/components/__tests__/html-code-viewer.test.tsx +0 -11
- package/dist/esm/tiptap/components/__tests__/tiptap.test.js +53 -12
- package/dist/esm/tiptap/components/__tests__/tiptap.test.tsx +79 -13
- package/dist/esm/tiptap/components/html-code-viewer.d.ts.map +1 -1
- package/dist/esm/tiptap/components/html-code-viewer.js +1 -24
- package/dist/esm/tiptap/components/menu-bar/__tests__/action-toolbar.test.js +7 -7
- package/dist/esm/tiptap/components/menu-bar/__tests__/action-toolbar.test.tsx +7 -0
- package/dist/esm/tiptap/components/menu-bar/__tests__/index.test.js +1 -0
- package/dist/esm/tiptap/components/menu-bar/__tests__/index.test.tsx +1 -0
- package/dist/esm/tiptap/components/menu-bar/action-toolbar.d.ts +2 -1
- package/dist/esm/tiptap/components/menu-bar/action-toolbar.d.ts.map +1 -1
- package/dist/esm/tiptap/components/menu-bar/action-toolbar.js +10 -2
- package/dist/esm/tiptap/components/menu-bar/index.d.ts +2 -1
- package/dist/esm/tiptap/components/menu-bar/index.d.ts.map +1 -1
- package/dist/esm/tiptap/components/menu-bar/index.js +2 -2
- package/dist/esm/tiptap/components/tiptap.d.ts.map +1 -1
- package/dist/esm/tiptap/components/tiptap.js +23 -9
- package/dist/esm/tiptap/constants/editor-config.d.ts +1 -0
- package/dist/esm/tiptap/constants/editor-config.d.ts.map +1 -1
- package/dist/esm/tiptap/constants/editor-config.js +1 -0
- package/dist/esm/tiptap/utils/__tests__/clean-html.test.js +26 -7
- package/dist/esm/tiptap/utils/__tests__/clean-html.test.ts +29 -7
- package/dist/esm/tiptap/utils/prettier-format.js +1 -1
- package/package.json +12 -12
|
@@ -33,45 +33,45 @@ describe('ActionToolbar', () => {
|
|
|
33
33
|
});
|
|
34
34
|
});
|
|
35
35
|
it('should render all action buttons', () => {
|
|
36
|
-
render(React.createElement(ActionToolbar, { editor: editor, editorState: createEditorState(), isSourceMode: false, toggleSource: vi.fn() }));
|
|
36
|
+
render(React.createElement(ActionToolbar, { editor: editor, editorState: createEditorState(), isSourceMode: false, toggleSource: vi.fn(), onFormat: vi.fn() }));
|
|
37
37
|
expect(screen.getByTestId('action-button-format-undo')).toBeInTheDocument();
|
|
38
38
|
expect(screen.getByTestId('action-button-format-redo')).toBeInTheDocument();
|
|
39
39
|
expect(screen.getByTestId('action-button-eye-open')).toBeInTheDocument();
|
|
40
40
|
});
|
|
41
41
|
it('should handle undo click', () => {
|
|
42
42
|
const focusSpy = vi.spyOn(editor, 'chain');
|
|
43
|
-
render(React.createElement(ActionToolbar, { editor: editor, editorState: createEditorState({ canUndo: true }), isSourceMode: false, toggleSource: vi.fn() }));
|
|
43
|
+
render(React.createElement(ActionToolbar, { editor: editor, editorState: createEditorState({ canUndo: true }), isSourceMode: false, toggleSource: vi.fn(), onFormat: vi.fn() }));
|
|
44
44
|
const undoButton = screen.getByTestId('action-button-format-undo');
|
|
45
45
|
fireEvent.click(undoButton);
|
|
46
46
|
expect(focusSpy).toHaveBeenCalled();
|
|
47
47
|
});
|
|
48
48
|
it('should handle redo click', () => {
|
|
49
49
|
const focusSpy = vi.spyOn(editor, 'chain');
|
|
50
|
-
render(React.createElement(ActionToolbar, { editor: editor, editorState: createEditorState({ canRedo: true }), isSourceMode: false, toggleSource: vi.fn() }));
|
|
50
|
+
render(React.createElement(ActionToolbar, { editor: editor, editorState: createEditorState({ canRedo: true }), isSourceMode: false, toggleSource: vi.fn(), onFormat: vi.fn() }));
|
|
51
51
|
const redoButton = screen.getByTestId('action-button-format-redo');
|
|
52
52
|
fireEvent.click(redoButton);
|
|
53
53
|
expect(focusSpy).toHaveBeenCalled();
|
|
54
54
|
});
|
|
55
55
|
it('should handle toggle source click', () => {
|
|
56
56
|
const toggleSource = vi.fn();
|
|
57
|
-
render(React.createElement(ActionToolbar, { editor: editor, editorState: createEditorState(), isSourceMode: false, toggleSource: toggleSource }));
|
|
57
|
+
render(React.createElement(ActionToolbar, { editor: editor, editorState: createEditorState(), isSourceMode: false, toggleSource: toggleSource, onFormat: vi.fn() }));
|
|
58
58
|
const sourceButton = screen.getByTestId('action-button-eye-open');
|
|
59
59
|
fireEvent.click(sourceButton);
|
|
60
60
|
expect(toggleSource).toHaveBeenCalled();
|
|
61
61
|
});
|
|
62
62
|
it('should disable undo and redo when in source mode', () => {
|
|
63
|
-
render(React.createElement(ActionToolbar, { editor: editor, editorState: createEditorState({ canUndo: true, canRedo: true }), isSourceMode: true, toggleSource: vi.fn() }));
|
|
63
|
+
render(React.createElement(ActionToolbar, { editor: editor, editorState: createEditorState({ canUndo: true, canRedo: true }), isSourceMode: true, toggleSource: vi.fn(), onFormat: vi.fn() }));
|
|
64
64
|
expect(screen.getByTestId('action-button-format-undo')).toBeDisabled();
|
|
65
65
|
expect(screen.getByTestId('action-button-format-redo')).toBeDisabled();
|
|
66
66
|
});
|
|
67
67
|
it('should show eye-close icon and normal mode tooltip when isSourceMode is true', () => {
|
|
68
|
-
render(React.createElement(ActionToolbar, { editor: editor, editorState: createEditorState(), isSourceMode: true, toggleSource: vi.fn() }));
|
|
68
|
+
render(React.createElement(ActionToolbar, { editor: editor, editorState: createEditorState(), isSourceMode: true, toggleSource: vi.fn(), onFormat: vi.fn() }));
|
|
69
69
|
const sourceButton = screen.getByTestId('action-button-eye-close');
|
|
70
70
|
expect(sourceButton).toBeInTheDocument();
|
|
71
71
|
expect(sourceButton).toHaveAttribute('aria-label', 'Normal Mode');
|
|
72
72
|
});
|
|
73
73
|
it('should apply active class to source mode button when active', () => {
|
|
74
|
-
render(React.createElement(ActionToolbar, { editor: editor, editorState: createEditorState(), isSourceMode: true, toggleSource: vi.fn() }));
|
|
74
|
+
render(React.createElement(ActionToolbar, { editor: editor, editorState: createEditorState(), isSourceMode: true, toggleSource: vi.fn(), onFormat: vi.fn() }));
|
|
75
75
|
const sourceButton = screen.getByTestId('action-button-eye-close');
|
|
76
76
|
expect(sourceButton).toHaveClass('active');
|
|
77
77
|
});
|
|
@@ -105,6 +105,7 @@ describe('ActionToolbar', () => {
|
|
|
105
105
|
editorState={createEditorState()}
|
|
106
106
|
isSourceMode={false}
|
|
107
107
|
toggleSource={vi.fn()}
|
|
108
|
+
onFormat={vi.fn()}
|
|
108
109
|
/>
|
|
109
110
|
);
|
|
110
111
|
|
|
@@ -122,6 +123,7 @@ describe('ActionToolbar', () => {
|
|
|
122
123
|
editorState={createEditorState({ canUndo: true })}
|
|
123
124
|
isSourceMode={false}
|
|
124
125
|
toggleSource={vi.fn()}
|
|
126
|
+
onFormat={vi.fn()}
|
|
125
127
|
/>
|
|
126
128
|
);
|
|
127
129
|
|
|
@@ -140,6 +142,7 @@ describe('ActionToolbar', () => {
|
|
|
140
142
|
editorState={createEditorState({ canRedo: true })}
|
|
141
143
|
isSourceMode={false}
|
|
142
144
|
toggleSource={vi.fn()}
|
|
145
|
+
onFormat={vi.fn()}
|
|
143
146
|
/>
|
|
144
147
|
);
|
|
145
148
|
|
|
@@ -158,6 +161,7 @@ describe('ActionToolbar', () => {
|
|
|
158
161
|
editorState={createEditorState()}
|
|
159
162
|
isSourceMode={false}
|
|
160
163
|
toggleSource={toggleSource}
|
|
164
|
+
onFormat={vi.fn()}
|
|
161
165
|
/>
|
|
162
166
|
);
|
|
163
167
|
|
|
@@ -174,6 +178,7 @@ describe('ActionToolbar', () => {
|
|
|
174
178
|
editorState={createEditorState({ canUndo: true, canRedo: true })}
|
|
175
179
|
isSourceMode={true}
|
|
176
180
|
toggleSource={vi.fn()}
|
|
181
|
+
onFormat={vi.fn()}
|
|
177
182
|
/>
|
|
178
183
|
);
|
|
179
184
|
|
|
@@ -188,6 +193,7 @@ describe('ActionToolbar', () => {
|
|
|
188
193
|
editorState={createEditorState()}
|
|
189
194
|
isSourceMode={true}
|
|
190
195
|
toggleSource={vi.fn()}
|
|
196
|
+
onFormat={vi.fn()}
|
|
191
197
|
/>
|
|
192
198
|
);
|
|
193
199
|
|
|
@@ -203,6 +209,7 @@ describe('ActionToolbar', () => {
|
|
|
203
209
|
editorState={createEditorState()}
|
|
204
210
|
isSourceMode={true}
|
|
205
211
|
toggleSource={vi.fn()}
|
|
212
|
+
onFormat={vi.fn()}
|
|
206
213
|
/>
|
|
207
214
|
);
|
|
208
215
|
|
|
@@ -7,9 +7,10 @@ interface ActionToolbarProps {
|
|
|
7
7
|
editorState: EditorState;
|
|
8
8
|
isSourceMode: boolean;
|
|
9
9
|
toggleSource: () => void;
|
|
10
|
+
onFormat: () => Promise<void>;
|
|
10
11
|
disabled?: boolean;
|
|
11
12
|
hiddenButtons?: Array<ToolbarButtonId>;
|
|
12
13
|
}
|
|
13
|
-
export declare const ActionToolbar: ({ editor, editorState, isSourceMode, toggleSource, disabled, hiddenButtons }: ActionToolbarProps) => React.JSX.Element;
|
|
14
|
+
export declare const ActionToolbar: ({ editor, editorState, isSourceMode, toggleSource, onFormat, disabled, hiddenButtons }: ActionToolbarProps) => React.JSX.Element;
|
|
14
15
|
export {};
|
|
15
16
|
//# sourceMappingURL=action-toolbar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-toolbar.d.ts","sourceRoot":"","sources":["../../../../../src/tiptap/components/menu-bar/action-toolbar.tsx"],"names":[],"mappings":"AAAA,OAAO,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEhE,UAAU,kBAAkB;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,WAAW,CAAC;IACzB,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;CACxC;AAYD,eAAO,MAAM,aAAa,GAAI,
|
|
1
|
+
{"version":3,"file":"action-toolbar.d.ts","sourceRoot":"","sources":["../../../../../src/tiptap/components/menu-bar/action-toolbar.tsx"],"names":[],"mappings":"AAAA,OAAO,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEhE,UAAU,kBAAkB;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,WAAW,CAAC;IACzB,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;CACxC;AAYD,eAAO,MAAM,aAAa,GAAI,wFAQ3B,kBAAkB,sBA6DpB,CAAC"}
|
|
@@ -3,7 +3,7 @@ import { Button } from '@akinon/ui-button';
|
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { i18n } from '../../../i18n';
|
|
5
5
|
import { TOOLBAR_BUTTON_IDS } from '../../constants';
|
|
6
|
-
export const ActionToolbar = ({ editor, editorState, isSourceMode, toggleSource, disabled = false, hiddenButtons = [] }) => {
|
|
6
|
+
export const ActionToolbar = ({ editor, editorState, isSourceMode, toggleSource, onFormat, disabled = false, hiddenButtons = [] }) => {
|
|
7
7
|
const activeCls = 'active';
|
|
8
8
|
const actionButtons = [
|
|
9
9
|
{
|
|
@@ -23,8 +23,16 @@ export const ActionToolbar = ({ editor, editorState, isSourceMode, toggleSource,
|
|
|
23
23
|
disabled: disabled || isSourceMode || !editorState.canRedo
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
|
-
id: TOOLBAR_BUTTON_IDS.
|
|
26
|
+
id: TOOLBAR_BUTTON_IDS.FORMAT,
|
|
27
27
|
key: 3,
|
|
28
|
+
icon: 'format-beautify',
|
|
29
|
+
tooltip: i18n.t('editor.toolbar.format'),
|
|
30
|
+
onClick: onFormat,
|
|
31
|
+
disabled: !isSourceMode
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: TOOLBAR_BUTTON_IDS.SOURCE_MODE,
|
|
35
|
+
key: 4,
|
|
28
36
|
icon: isSourceMode ? 'eye-close' : 'eye-open',
|
|
29
37
|
tooltip: isSourceMode
|
|
30
38
|
? i18n.t('editor.toolbar.normal_mode')
|
|
@@ -5,13 +5,14 @@ interface MenuBarProps {
|
|
|
5
5
|
editor: Editor;
|
|
6
6
|
isSourceMode: boolean;
|
|
7
7
|
toggleSource: () => void;
|
|
8
|
+
onFormat: () => Promise<void>;
|
|
8
9
|
onSave?: () => void;
|
|
9
10
|
className?: string;
|
|
10
11
|
toolbar?: ToolbarConfig;
|
|
11
12
|
readOnly?: boolean;
|
|
12
13
|
}
|
|
13
14
|
export declare const MenuBar: {
|
|
14
|
-
({ editor, isSourceMode, toggleSource, className, toolbar, readOnly }: MenuBarProps): React.JSX.Element;
|
|
15
|
+
({ editor, isSourceMode, toggleSource, onFormat, className, toolbar, readOnly }: MenuBarProps): React.JSX.Element;
|
|
15
16
|
displayName: string;
|
|
16
17
|
};
|
|
17
18
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/tiptap/components/menu-bar/index.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAI5C,OAAO,KAAK,MAAM,OAAO,CAAC;AAQ1B,OAAO,KAAK,EAAe,aAAa,EAAE,MAAM,aAAa,CAAC;AAS9D,UAAU,YAAY;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,OAAO;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/tiptap/components/menu-bar/index.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAI5C,OAAO,KAAK,MAAM,OAAO,CAAC;AAQ1B,OAAO,KAAK,EAAe,aAAa,EAAE,MAAM,aAAa,CAAC;AAS9D,UAAU,YAAY;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,OAAO;qFAQjB,YAAY;;CAsMd,CAAC"}
|
|
@@ -12,7 +12,7 @@ import { LinkPopover } from './link-popover';
|
|
|
12
12
|
import { ListAndBlockToolbar } from './list-and-block-toolbar';
|
|
13
13
|
import { MediaToolbar } from './media-toolbar';
|
|
14
14
|
import { TextFormattingToolbar } from './text-formatting-toolbar';
|
|
15
|
-
export const MenuBar = ({ editor, isSourceMode, toggleSource, className, toolbar, readOnly = false }) => {
|
|
15
|
+
export const MenuBar = ({ editor, isSourceMode, toggleSource, onFormat, className, toolbar, readOnly = false }) => {
|
|
16
16
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
17
17
|
const { getPrefixCls, theme } = React.useContext(ConfigProvider.ConfigContext);
|
|
18
18
|
const { token, hashId } = useToken();
|
|
@@ -126,6 +126,6 @@ export const MenuBar = ({ editor, isSourceMode, toggleSource, className, toolbar
|
|
|
126
126
|
!((_d = toolbar === null || toolbar === void 0 ? void 0 : toolbar.hiddenGroups) === null || _d === void 0 ? void 0 : _d.includes(TOOLBAR_GROUP_IDS.LINK)) && (React.createElement(LinkPopover, { editor: editor, editorState: editorState, disabled: isDisabled })),
|
|
127
127
|
!((_e = toolbar === null || toolbar === void 0 ? void 0 : toolbar.hiddenGroups) === null || _e === void 0 ? void 0 : _e.includes(TOOLBAR_GROUP_IDS.MEDIA)) && (React.createElement(MediaToolbar, { editor: editor, editorState: editorState, disabled: isDisabled, hiddenButtons: toolbar === null || toolbar === void 0 ? void 0 : toolbar.hiddenButtons })),
|
|
128
128
|
!((_f = toolbar === null || toolbar === void 0 ? void 0 : toolbar.hiddenGroups) === null || _f === void 0 ? void 0 : _f.includes(TOOLBAR_GROUP_IDS.ALIGNMENT)) && (React.createElement(AlignmentToolbar, { editor: editor, editorState: editorState, disabled: isDisabled })),
|
|
129
|
-
!((_g = toolbar === null || toolbar === void 0 ? void 0 : toolbar.hiddenGroups) === null || _g === void 0 ? void 0 : _g.includes(TOOLBAR_GROUP_IDS.HISTORY)) && (React.createElement(ActionToolbar, { editor: editor, editorState: editorState, isSourceMode: isSourceMode, toggleSource: toggleSource, disabled: readOnly, hiddenButtons: toolbar === null || toolbar === void 0 ? void 0 : toolbar.hiddenButtons })))));
|
|
129
|
+
!((_g = toolbar === null || toolbar === void 0 ? void 0 : toolbar.hiddenGroups) === null || _g === void 0 ? void 0 : _g.includes(TOOLBAR_GROUP_IDS.HISTORY)) && (React.createElement(ActionToolbar, { editor: editor, editorState: editorState, isSourceMode: isSourceMode, toggleSource: toggleSource, onFormat: onFormat, disabled: readOnly, hiddenButtons: toolbar === null || toolbar === void 0 ? void 0 : toolbar.hiddenButtons })))));
|
|
130
130
|
};
|
|
131
131
|
MenuBar.displayName = 'MenuBar';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tiptap.d.ts","sourceRoot":"","sources":["../../../../src/tiptap/components/tiptap.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAQvE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"tiptap.d.ts","sourceRoot":"","sources":["../../../../src/tiptap/components/tiptap.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAQvE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAWhD,eAAO,MAAM,MAAM,GAAI,iHAUpB,eAAe,sBAmajB,CAAC"}
|
|
@@ -8,7 +8,7 @@ import clsx from 'clsx';
|
|
|
8
8
|
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
9
9
|
import { DragHandleIcon } from '../assets/icons';
|
|
10
10
|
import { EDITOR_CONTENT_HEIGHT, getTableCellDefaults, getTableHeaderDefaults } from '../constants';
|
|
11
|
-
import { cleanDuplicateSpans, getExtensions } from '../utils';
|
|
11
|
+
import { cleanDuplicateSpans, formatHtmlWithPrettier, getExtensions } from '../utils';
|
|
12
12
|
import { FormatBubbleMenu } from './format-bubble-menu';
|
|
13
13
|
import { HtmlCodeViewer } from './html-code-viewer';
|
|
14
14
|
import { MenuBar } from './menu-bar';
|
|
@@ -47,19 +47,27 @@ export const Tiptap = ({ value, defaultValue, onChange, readOnly = false, classN
|
|
|
47
47
|
const editor = useEditor({
|
|
48
48
|
editable: !readOnly,
|
|
49
49
|
content: defaultValue !== undefined ? defaultValue : value,
|
|
50
|
-
|
|
50
|
+
extensions,
|
|
51
|
+
editorProps
|
|
52
|
+
});
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!editor)
|
|
55
|
+
return;
|
|
56
|
+
const handleUpdate = () => {
|
|
51
57
|
var _a;
|
|
52
58
|
(_a = onChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onChangeRef, {
|
|
53
59
|
html: editor.getHTML(),
|
|
54
60
|
json: editor.getJSON()
|
|
55
61
|
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
};
|
|
63
|
+
editor.on('update', handleUpdate);
|
|
64
|
+
return () => {
|
|
65
|
+
editor.off('update', handleUpdate);
|
|
66
|
+
};
|
|
67
|
+
}, [editor]);
|
|
60
68
|
useEffect(() => {
|
|
61
69
|
if (editor) {
|
|
62
|
-
editor.setEditable(!readOnly);
|
|
70
|
+
editor.setEditable(!readOnly, false);
|
|
63
71
|
}
|
|
64
72
|
}, [editor, readOnly]);
|
|
65
73
|
useEffect(() => {
|
|
@@ -67,7 +75,7 @@ export const Tiptap = ({ value, defaultValue, onChange, readOnly = false, classN
|
|
|
67
75
|
value !== undefined &&
|
|
68
76
|
value !== prevValueRef.current &&
|
|
69
77
|
value !== editor.getHTML()) {
|
|
70
|
-
editor.commands.setContent(value);
|
|
78
|
+
editor.commands.setContent(value, { emitUpdate: false });
|
|
71
79
|
if (isSourceMode) {
|
|
72
80
|
setRawHTML(value);
|
|
73
81
|
}
|
|
@@ -127,6 +135,12 @@ export const Tiptap = ({ value, defaultValue, onChange, readOnly = false, classN
|
|
|
127
135
|
}
|
|
128
136
|
};
|
|
129
137
|
}, []);
|
|
138
|
+
const handleFormat = useCallback(async () => {
|
|
139
|
+
const formatted = await formatHtmlWithPrettier(rawHTML);
|
|
140
|
+
if (formatted !== rawHTML) {
|
|
141
|
+
setRawHTML(formatted);
|
|
142
|
+
}
|
|
143
|
+
}, [rawHTML]);
|
|
130
144
|
const useStyle = useStyleRegister({
|
|
131
145
|
token: token,
|
|
132
146
|
path: ['TiptapEditor', String(contentHeight)],
|
|
@@ -330,7 +344,7 @@ export const Tiptap = ({ value, defaultValue, onChange, readOnly = false, classN
|
|
|
330
344
|
});
|
|
331
345
|
return useStyle(React.createElement("div", { className: `${baseCls} ${hashId}` },
|
|
332
346
|
editor && (React.createElement(React.Fragment, null,
|
|
333
|
-
React.createElement(MenuBar, { isSourceMode: isSourceMode, toggleSource: toggleSource, editor: editor, onSave: getCleanHtml, className: classNames === null || classNames === void 0 ? void 0 : classNames.editorToolbar, toolbar: toolbar, readOnly: readOnly }),
|
|
347
|
+
React.createElement(MenuBar, { isSourceMode: isSourceMode, toggleSource: toggleSource, onFormat: handleFormat, editor: editor, onSave: getCleanHtml, className: classNames === null || classNames === void 0 ? void 0 : classNames.editorToolbar, toolbar: toolbar, readOnly: readOnly }),
|
|
334
348
|
React.createElement(FormatBubbleMenu, { editor: editor }),
|
|
335
349
|
React.createElement(TableBubbleMenu, { editor: editor }),
|
|
336
350
|
React.createElement(DragHandle, { editor: editor },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor-config.d.ts","sourceRoot":"","sources":["../../../../src/tiptap/constants/editor-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,eAAO,MAAM,aAAa,UAqBzB,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;EAMlB,CAAC;AAEX,eAAO,MAAM,UAAU;IAErB,SAAA,CAAC,aAAa,CAAC,EAAE,CAAC,KAAI;IACtB,SAAA,CAAC,aAAa,CAAC,EAAE,CAAC,KAAI;IACtB,SAAA,CAAC,aAAa,CAAC,EAAE,CAAC,KAAI;IACtB,SAAA,CAAC,aAAa,CAAC,EAAE,CAAC,KAAI;;CACd,CAAC;AAEX,eAAO,MAAM,oBAAoB;;;;;CAKvB,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,eAAO,MAAM,kBAAkB
|
|
1
|
+
{"version":3,"file":"editor-config.d.ts","sourceRoot":"","sources":["../../../../src/tiptap/constants/editor-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,eAAO,MAAM,aAAa,UAqBzB,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;EAMlB,CAAC;AAEX,eAAO,MAAM,UAAU;IAErB,SAAA,CAAC,aAAa,CAAC,EAAE,CAAC,KAAI;IACtB,SAAA,CAAC,aAAa,CAAC,EAAE,CAAC,KAAI;IACtB,SAAA,CAAC,aAAa,CAAC,EAAE,CAAC,KAAI;IACtB,SAAA,CAAC,aAAa,CAAC,EAAE,CAAC,KAAI;;CACd,CAAC;AAEX,eAAO,MAAM,oBAAoB;;;;;CAKvB,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BrB,CAAC;AAEX,eAAO,MAAM,iBAAiB;;;;;;;;CAQpB,CAAC;AAEX,eAAO,MAAM,iBAAiB;;;;;CAK7B,CAAC;AAEF,eAAO,MAAM,mBAAmB,UAK/B,CAAC;AAEF,eAAO,MAAM,cAAc,uBAAwB,CAAC;AAEpD,eAAO,MAAM,gBAAgB,6BAG5B,CAAC;AAEF,eAAO,MAAM,WAAW;;;;sBAIE,MAAM,EAAE;yBACL,MAAM,EAAE;CACpC,CAAC;AAEF,eAAO,MAAM,qBAAqB,MAAM,CAAC"}
|
|
@@ -77,17 +77,36 @@ describe('clean-html', () => {
|
|
|
77
77
|
const result = cleanDuplicateSpans(html);
|
|
78
78
|
expect(result).toBe('<div><script>console.log("test")</script>Content</div>');
|
|
79
79
|
});
|
|
80
|
-
it('should handle mixed content with text nodes', () => {
|
|
81
|
-
// This test covers line 87: return node.textContent || '';
|
|
82
|
-
// Testing text nodes between elements
|
|
80
|
+
it('should handle mixed content with text nodes inside elements', () => {
|
|
83
81
|
const html = '<div>Start<p>Middle</p>End</div>';
|
|
84
82
|
const result = cleanDuplicateSpans(html);
|
|
85
83
|
expect(result).toBe('<div>Start<p>Middle</p>End</div>');
|
|
86
84
|
});
|
|
87
|
-
it('should handle
|
|
88
|
-
//
|
|
89
|
-
const html = '
|
|
85
|
+
it('should handle top-level text nodes (covers line 87)', () => {
|
|
86
|
+
// text nodes at the root of template.content hit line 87
|
|
87
|
+
const html = 'plain text only';
|
|
90
88
|
const result = cleanDuplicateSpans(html);
|
|
91
|
-
expect(result).toBe('
|
|
89
|
+
expect(result).toBe('plain text only');
|
|
90
|
+
});
|
|
91
|
+
it('should handle mixed top-level text nodes and elements', () => {
|
|
92
|
+
// "before " and " after" are top-level text nodes, hitting line 87
|
|
93
|
+
const html = 'before <div>element</div> after';
|
|
94
|
+
const result = cleanDuplicateSpans(html);
|
|
95
|
+
expect(result).toBe('before <div>element</div> after');
|
|
96
|
+
});
|
|
97
|
+
it("should handle empty text content fallback (|| '' branch)", () => {
|
|
98
|
+
// A whitespace-only top-level text node: textContent is ' ' (truthy)
|
|
99
|
+
// but tests the same code path; empty-string case uses the || '' fallback
|
|
100
|
+
const html = ' ';
|
|
101
|
+
const result = cleanDuplicateSpans(html);
|
|
102
|
+
expect(result).toBe(' ');
|
|
103
|
+
});
|
|
104
|
+
it("should return '' for top-level empty comment nodes (covers || '' branch on line 87)", () => {
|
|
105
|
+
// An empty HTML comment (<!---->) creates a top-level Comment node.
|
|
106
|
+
// Comment nodes are not ELEMENT_NODEs, so they hit line 87.
|
|
107
|
+
// Their textContent is '' (empty string / falsy), triggering the || '' fallback.
|
|
108
|
+
const html = '<!---->';
|
|
109
|
+
const result = cleanDuplicateSpans(html);
|
|
110
|
+
expect(result).toBe('');
|
|
92
111
|
});
|
|
93
112
|
});
|
|
@@ -112,18 +112,40 @@ describe('clean-html', () => {
|
|
|
112
112
|
);
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
-
it('should handle mixed content with text nodes', () => {
|
|
116
|
-
// This test covers line 87: return node.textContent || '';
|
|
117
|
-
// Testing text nodes between elements
|
|
115
|
+
it('should handle mixed content with text nodes inside elements', () => {
|
|
118
116
|
const html = '<div>Start<p>Middle</p>End</div>';
|
|
119
117
|
const result = cleanDuplicateSpans(html);
|
|
120
118
|
expect(result).toBe('<div>Start<p>Middle</p>End</div>');
|
|
121
119
|
});
|
|
122
120
|
|
|
123
|
-
it('should handle
|
|
124
|
-
//
|
|
125
|
-
const html = '
|
|
121
|
+
it('should handle top-level text nodes (covers line 87)', () => {
|
|
122
|
+
// text nodes at the root of template.content hit line 87
|
|
123
|
+
const html = 'plain text only';
|
|
126
124
|
const result = cleanDuplicateSpans(html);
|
|
127
|
-
expect(result).toBe('
|
|
125
|
+
expect(result).toBe('plain text only');
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should handle mixed top-level text nodes and elements', () => {
|
|
129
|
+
// "before " and " after" are top-level text nodes, hitting line 87
|
|
130
|
+
const html = 'before <div>element</div> after';
|
|
131
|
+
const result = cleanDuplicateSpans(html);
|
|
132
|
+
expect(result).toBe('before <div>element</div> after');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("should handle empty text content fallback (|| '' branch)", () => {
|
|
136
|
+
// A whitespace-only top-level text node: textContent is ' ' (truthy)
|
|
137
|
+
// but tests the same code path; empty-string case uses the || '' fallback
|
|
138
|
+
const html = ' ';
|
|
139
|
+
const result = cleanDuplicateSpans(html);
|
|
140
|
+
expect(result).toBe(' ');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("should return '' for top-level empty comment nodes (covers || '' branch on line 87)", () => {
|
|
144
|
+
// An empty HTML comment (<!---->) creates a top-level Comment node.
|
|
145
|
+
// Comment nodes are not ELEMENT_NODEs, so they hit line 87.
|
|
146
|
+
// Their textContent is '' (empty string / falsy), triggering the || '' fallback.
|
|
147
|
+
const html = '<!---->';
|
|
148
|
+
const result = cleanDuplicateSpans(html);
|
|
149
|
+
expect(result).toBe('');
|
|
128
150
|
});
|
|
129
151
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akinon/ui-editor",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7-rc.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A headless lightweight text editor for Akinon.",
|
|
6
6
|
"type": "module",
|
|
@@ -53,23 +53,23 @@
|
|
|
53
53
|
"prettier": "^3.6.2",
|
|
54
54
|
"y-protocols": "^1.0.7",
|
|
55
55
|
"yjs": "^13.6.29",
|
|
56
|
-
"@akinon/
|
|
57
|
-
"@akinon/
|
|
58
|
-
"@akinon/ui-
|
|
59
|
-
"@akinon/ui-
|
|
60
|
-
"@akinon/ui-
|
|
61
|
-
"@akinon/ui-
|
|
62
|
-
"@akinon/ui-
|
|
63
|
-
"@akinon/ui-
|
|
64
|
-
"@akinon/ui-
|
|
56
|
+
"@akinon/akilocale": "1.2.5",
|
|
57
|
+
"@akinon/ui-button": "1.4.7-rc.0",
|
|
58
|
+
"@akinon/ui-input": "1.2.5",
|
|
59
|
+
"@akinon/ui-dropdown": "1.1.5",
|
|
60
|
+
"@akinon/ui-popover": "1.1.5",
|
|
61
|
+
"@akinon/ui-color-picker": "1.1.5",
|
|
62
|
+
"@akinon/ui-select": "1.4.7-rc.0",
|
|
63
|
+
"@akinon/ui-theme": "1.2.5",
|
|
64
|
+
"@akinon/ui-upload": "1.4.7-rc.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"clean-package": "^2.2.0",
|
|
68
68
|
"copyfiles": "^2.4.1",
|
|
69
69
|
"rimraf": "^5.0.10",
|
|
70
70
|
"typescript": "*",
|
|
71
|
-
"@akinon/typescript-config": "1.1.
|
|
72
|
-
"@akinon/vitest-config": "1.1.
|
|
71
|
+
"@akinon/typescript-config": "1.1.5",
|
|
72
|
+
"@akinon/vitest-config": "1.1.5"
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|
|
75
75
|
"react": "^18 || ^19",
|