paris 0.19.0 → 0.20.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/package.json +17 -2
  3. package/src/stories/accordion/Accordion.test.tsx +140 -0
  4. package/src/stories/accordionselect/AccordionSelect.test.tsx +252 -0
  5. package/src/stories/avatar/Avatar.test.tsx +77 -0
  6. package/src/stories/button/Button.test.tsx +266 -0
  7. package/src/stories/callout/Callout.test.tsx +79 -0
  8. package/src/stories/card/Card.test.tsx +81 -0
  9. package/src/stories/cardbutton/CardButton.test.tsx +174 -0
  10. package/src/stories/checkbox/Checkbox.test.tsx +531 -0
  11. package/src/stories/combobox/Combobox.test.tsx +164 -0
  12. package/src/stories/dialog/Dialog.module.scss +2 -2
  13. package/src/stories/dialog/Dialog.test.tsx +244 -0
  14. package/src/stories/drawer/Drawer.module.scss +2 -2
  15. package/src/stories/drawer/Drawer.test.tsx +259 -0
  16. package/src/stories/field/Field.test.tsx +146 -0
  17. package/src/stories/icon/Icon.test.tsx +59 -0
  18. package/src/stories/informationaltooltip/InformationalTooltip.test.tsx +178 -0
  19. package/src/stories/input/Input.test.tsx +174 -0
  20. package/src/stories/markdown/Markdown.test.tsx +228 -0
  21. package/src/stories/markdowneditor/FixedToolbar.tsx +44 -14
  22. package/src/stories/markdowneditor/LinkPopover.module.scss +1 -1
  23. package/src/stories/markdowneditor/MarkdownEditor.stories.tsx +4 -1
  24. package/src/stories/markdowneditor/MarkdownEditor.test.tsx +115 -0
  25. package/src/stories/markdowneditor/MarkdownEditor.tsx +11 -1
  26. package/src/stories/markdowneditor/MarkdownEditorContext.tsx +3 -0
  27. package/src/stories/markdowneditor/index.ts +1 -0
  28. package/src/stories/menu/Menu.module.scss +1 -1
  29. package/src/stories/menu/Menu.test.tsx +211 -0
  30. package/src/stories/pagination/usePagination.test.ts +259 -0
  31. package/src/stories/popover/Popover.test.tsx +152 -0
  32. package/src/stories/select/Select.module.scss +2 -1
  33. package/src/stories/select/Select.test.tsx +233 -0
  34. package/src/stories/styledlink/StyledLink.test.tsx +59 -0
  35. package/src/stories/table/Table.test.tsx +156 -0
  36. package/src/stories/tabs/Tabs.module.scss +1 -1
  37. package/src/stories/tabs/Tabs.test.tsx +167 -0
  38. package/src/stories/tag/Tag.test.tsx +90 -0
  39. package/src/stories/text/Text.test.tsx +81 -0
  40. package/src/stories/textarea/TextArea.test.tsx +147 -0
  41. package/src/stories/theme/themes.ts +16 -0
  42. package/src/stories/tilt/Tilt.test.tsx +203 -0
  43. package/src/stories/toast/Toast.test.tsx +86 -0
  44. package/src/stories/utility/Dropdown.module.scss +1 -1
  45. package/src/stories/utility/Utility.test.tsx +96 -0
  46. package/src/test/render.tsx +20 -0
  47. package/src/test/setup.ts +32 -0
@@ -0,0 +1,228 @@
1
+ import { render, screen, waitFor } from '../../test/render';
2
+ import { Markdown } from './Markdown';
3
+
4
+ describe('Markdown', () => {
5
+ describe('headings', () => {
6
+ it('renders h1', async () => {
7
+ render(<Markdown>{'# Heading 1'}</Markdown>);
8
+ await waitFor(() => {
9
+ expect(screen.getByText('Heading 1')).toBeInTheDocument();
10
+ });
11
+ expect(screen.getByText('Heading 1').closest('h1')).toBeInTheDocument();
12
+ });
13
+
14
+ it('renders h2', async () => {
15
+ render(<Markdown>{'## Heading 2'}</Markdown>);
16
+ await waitFor(() => {
17
+ expect(screen.getByText('Heading 2').closest('h2')).toBeInTheDocument();
18
+ });
19
+ });
20
+
21
+ it('renders h3', async () => {
22
+ render(<Markdown>{'### Heading 3'}</Markdown>);
23
+ await waitFor(() => {
24
+ expect(screen.getByText('Heading 3').closest('h3')).toBeInTheDocument();
25
+ });
26
+ });
27
+
28
+ it('generates slug IDs for headings', async () => {
29
+ render(<Markdown>{'# Hello World'}</Markdown>);
30
+ await waitFor(() => {
31
+ expect(screen.getByText('Hello World')).toHaveAttribute('id', 'hello-world');
32
+ });
33
+ });
34
+ });
35
+
36
+ describe('paragraphs and inline text', () => {
37
+ it('renders paragraphs', async () => {
38
+ render(<Markdown>{'This is a paragraph.'}</Markdown>);
39
+ await waitFor(() => {
40
+ expect(screen.getByText('This is a paragraph.')).toBeInTheDocument();
41
+ });
42
+ });
43
+
44
+ it('renders bold text', async () => {
45
+ render(<Markdown>{'This is **bold** text.'}</Markdown>);
46
+ await waitFor(() => {
47
+ expect(screen.getByText('bold')).toBeInTheDocument();
48
+ });
49
+ });
50
+
51
+ it('renders italic text', async () => {
52
+ render(<Markdown>{'This is *italic* text.'}</Markdown>);
53
+ await waitFor(() => {
54
+ expect(screen.getByText('italic')).toBeInTheDocument();
55
+ });
56
+ });
57
+ });
58
+
59
+ describe('links', () => {
60
+ it('renders links with href', async () => {
61
+ render(<Markdown>{'[Click me](https://example.com)'}</Markdown>);
62
+ await waitFor(() => {
63
+ const link = screen.getByText('Click me');
64
+ expect(link.closest('a')).toHaveAttribute('href', 'https://example.com');
65
+ });
66
+ });
67
+
68
+ it('renders links with target="_blank"', async () => {
69
+ render(<Markdown>{'[Link](https://example.com)'}</Markdown>);
70
+ await waitFor(() => {
71
+ const link = screen.getByText('Link');
72
+ expect(link.closest('a')).toHaveAttribute('target', '_blank');
73
+ });
74
+ });
75
+ });
76
+
77
+ describe('lists', () => {
78
+ it('renders unordered lists', async () => {
79
+ render(<Markdown>{'- Item 1\n- Item 2\n- Item 3'}</Markdown>);
80
+ await waitFor(() => {
81
+ expect(screen.getByText('Item 1')).toBeInTheDocument();
82
+ expect(screen.getByText('Item 2')).toBeInTheDocument();
83
+ expect(screen.getByText('Item 3')).toBeInTheDocument();
84
+ });
85
+ });
86
+
87
+ it('renders ordered lists', async () => {
88
+ render(<Markdown>{'1. First\n2. Second\n3. Third'}</Markdown>);
89
+ await waitFor(() => {
90
+ expect(screen.getByText('First')).toBeInTheDocument();
91
+ expect(screen.getByText('Second')).toBeInTheDocument();
92
+ });
93
+ });
94
+ });
95
+
96
+ describe('code', () => {
97
+ it('renders inline code', async () => {
98
+ render(<Markdown>{'Use `console.log()` to debug.'}</Markdown>);
99
+ await waitFor(() => {
100
+ const code = screen.getByText('console.log()');
101
+ expect(code.tagName).toBe('CODE');
102
+ });
103
+ });
104
+
105
+ it('renders code blocks with language', async () => {
106
+ render(<Markdown>{'```js\nconst x = 1;\n```'}</Markdown>);
107
+ await waitFor(() => {
108
+ expect(screen.getByText('js')).toBeInTheDocument();
109
+ expect(screen.getByText('const x = 1;')).toBeInTheDocument();
110
+ });
111
+ });
112
+ });
113
+
114
+ describe('GFM extensions', () => {
115
+ it('renders strikethrough text', async () => {
116
+ render(<Markdown>{'~~deleted~~'}</Markdown>);
117
+ await waitFor(() => {
118
+ const del = screen.getByText('deleted');
119
+ expect(del.closest('span')).toHaveClass('strikethrough');
120
+ });
121
+ });
122
+
123
+ it('renders tables', async () => {
124
+ const md = '| Name | Age |\n| --- | --- |\n| Alice | 30 |';
125
+ render(<Markdown>{md}</Markdown>);
126
+ await waitFor(() => {
127
+ expect(screen.getByText('Name')).toBeInTheDocument();
128
+ expect(screen.getByText('Alice')).toBeInTheDocument();
129
+ expect(screen.getByText('30')).toBeInTheDocument();
130
+ });
131
+ });
132
+
133
+ it('renders task lists', async () => {
134
+ const md = '- [x] Done\n- [ ] Todo';
135
+ const { container } = render(<Markdown>{md}</Markdown>);
136
+ await waitFor(() => {
137
+ expect(screen.getByText('Done')).toBeInTheDocument();
138
+ expect(screen.getByText('Todo')).toBeInTheDocument();
139
+ });
140
+ const checkboxes = container.querySelectorAll('input[type="checkbox"]');
141
+ expect(checkboxes.length).toBe(2);
142
+ });
143
+ });
144
+
145
+ describe('raw HTML', () => {
146
+ it('renders kbd elements', async () => {
147
+ render(<Markdown>{'Press <kbd>Ctrl</kbd>+<kbd>C</kbd>'}</Markdown>);
148
+ await waitFor(() => {
149
+ const kbd = screen.getByText('Ctrl');
150
+ expect(kbd.tagName).toBe('KBD');
151
+ });
152
+ });
153
+
154
+ it('renders mark elements', async () => {
155
+ render(<Markdown>{'This is <mark>highlighted</mark> text.'}</Markdown>);
156
+ await waitFor(() => {
157
+ const mark = screen.getByText('highlighted');
158
+ expect(mark.tagName).toBe('MARK');
159
+ });
160
+ });
161
+
162
+ it('renders sup elements', async () => {
163
+ render(<Markdown>{'E=mc<sup>2</sup>'}</Markdown>);
164
+ await waitFor(() => {
165
+ const sup = screen.getByText('2');
166
+ expect(sup.tagName).toBe('SUP');
167
+ });
168
+ });
169
+ });
170
+
171
+ describe('blockquotes', () => {
172
+ it('renders blockquotes', async () => {
173
+ render(<Markdown>{'> This is a quote'}</Markdown>);
174
+ await waitFor(() => {
175
+ expect(screen.getByText('This is a quote')).toBeInTheDocument();
176
+ });
177
+ });
178
+ });
179
+
180
+ describe('horizontal rules', () => {
181
+ it('renders hr elements', async () => {
182
+ const { container } = render(<Markdown>{'Above\n\n---\n\nBelow'}</Markdown>);
183
+ await waitFor(() => {
184
+ expect(container.querySelector('hr')).toBeInTheDocument();
185
+ });
186
+ });
187
+ });
188
+
189
+ describe('images', () => {
190
+ it('renders images with src and alt', async () => {
191
+ render(<Markdown>{'![Alt text](https://example.com/image.png)'}</Markdown>);
192
+ await waitFor(() => {
193
+ const img = screen.getByAltText('Alt text');
194
+ expect(img).toHaveAttribute('src', 'https://example.com/image.png');
195
+ });
196
+ });
197
+ });
198
+
199
+ describe('className', () => {
200
+ it('applies custom className', () => {
201
+ const { container } = render(<Markdown className="custom-md">{'Hello'}</Markdown>);
202
+ expect(container.firstElementChild).toHaveClass('custom-md');
203
+ });
204
+
205
+ it('always applies the markdown base class', () => {
206
+ const { container } = render(<Markdown>{'Hello'}</Markdown>);
207
+ expect(container.firstElementChild).toHaveClass('markdown');
208
+ });
209
+ });
210
+
211
+ describe('size', () => {
212
+ it('sets CSS variable for base font size', () => {
213
+ const { container } = render(<Markdown size="paragraphLarge">{'Hello'}</Markdown>);
214
+ const wrapper = container.firstElementChild as HTMLElement;
215
+ expect(wrapper.style.getPropertyValue('--markdown-base-font-size')).toBe(
216
+ 'var(--pte-new-typography-styles-paragraphLarge-fontSize)',
217
+ );
218
+ });
219
+
220
+ it('defaults to paragraphSmall', () => {
221
+ const { container } = render(<Markdown>{'Hello'}</Markdown>);
222
+ const wrapper = container.firstElementChild as HTMLElement;
223
+ expect(wrapper.style.getPropertyValue('--markdown-base-font-size')).toBe(
224
+ 'var(--pte-new-typography-styles-paragraphSmall-fontSize)',
225
+ );
226
+ });
227
+ });
228
+ });
@@ -20,7 +20,7 @@ import {
20
20
  Table,
21
21
  } from 'lucide-react';
22
22
  import type { ComponentPropsWithoutRef, FC, ReactNode } from 'react';
23
- import { Fragment, useCallback, useState } from 'react';
23
+ import { Fragment, useCallback, useRef, useState } from 'react';
24
24
  import styles from './FixedToolbar.module.scss';
25
25
  import type { MarkdownEditorFeature } from './features';
26
26
  import { LinkPopover } from './LinkPopover';
@@ -56,13 +56,34 @@ const ICON_SIZE = 14;
56
56
  * Groups with no enabled features are hidden.
57
57
  */
58
58
  export const FixedToolbar: FC<FixedToolbarProps> = ({ className, overrides }) => {
59
- const { editor, features } = useMarkdownEditorContext();
59
+ const { editor, features, handleImageUpload } = useMarkdownEditorContext();
60
60
  const [showLinkPopover, setShowLinkPopover] = useState(false);
61
+ const fileInputRef = useRef<HTMLInputElement>(null);
61
62
 
62
63
  const handleLinkClick = useCallback(() => {
63
64
  setShowLinkPopover((prev) => !prev);
64
65
  }, []);
65
66
 
67
+ const handleImageClick = useCallback(() => {
68
+ fileInputRef.current?.click();
69
+ }, []);
70
+
71
+ const handleFileChange = useCallback(
72
+ async (e: React.ChangeEvent<HTMLInputElement>) => {
73
+ const file = e.target.files?.[0];
74
+ if (!file || !editor || !handleImageUpload) return;
75
+ try {
76
+ const url = await handleImageUpload(file);
77
+ editor.chain().focus().setImage({ src: url }).run();
78
+ } catch {
79
+ // Upload failed — consumer's handler should surface errors
80
+ }
81
+ // Reset so the same file can be re-selected
82
+ e.target.value = '';
83
+ },
84
+ [editor, handleImageUpload],
85
+ );
86
+
66
87
  if (!editor) return null;
67
88
 
68
89
  const inlineMarks: ToolbarItem[] = [
@@ -166,18 +187,17 @@ export const FixedToolbar: FC<FixedToolbarProps> = ({ className, overrides }) =>
166
187
  action: handleLinkClick,
167
188
  isActive: () => editor.isActive('link'),
168
189
  },
169
- {
170
- feature: 'image',
171
- label: <Image size={ICON_SIZE} />,
172
- tooltip: 'Image',
173
- action: () => {
174
- const url = window.prompt('Image URL');
175
- if (url) {
176
- editor.chain().focus().setImage({ src: url }).run();
177
- }
178
- },
179
- isActive: () => false,
180
- },
190
+ ...(handleImageUpload
191
+ ? [
192
+ {
193
+ feature: 'image' as const,
194
+ label: <Image size={ICON_SIZE} />,
195
+ tooltip: 'Image',
196
+ action: handleImageClick,
197
+ isActive: () => false,
198
+ },
199
+ ]
200
+ : []),
181
201
  {
182
202
  feature: 'table',
183
203
  label: <Table size={ICON_SIZE} />,
@@ -239,6 +259,16 @@ export const FixedToolbar: FC<FixedToolbarProps> = ({ className, overrides }) =>
239
259
  </Fragment>
240
260
  ))}
241
261
  {showLinkPopover && features.has('link') && <LinkPopover onClose={() => setShowLinkPopover(false)} />}
262
+ {handleImageUpload && (
263
+ <input
264
+ ref={fileInputRef}
265
+ type="file"
266
+ accept="image/*"
267
+ onChange={handleFileChange}
268
+ style={{ display: 'none' }}
269
+ tabIndex={-1}
270
+ />
271
+ )}
242
272
  </div>
243
273
  );
244
274
  };
@@ -2,7 +2,7 @@
2
2
  position: absolute;
3
3
  top: calc(100% + 8px);
4
4
  left: 0;
5
- z-index: 50;
5
+ z-index: var(--pte-new-layers-popover);
6
6
  background-color: var(--pte-new-colors-surfacePrimary, var(--pte-new-colors-backgroundPrimary));
7
7
  border: 1px solid var(--pte-new-colors-borderSubtle);
8
8
  border-radius: var(--pte-new-borders-radius-rounded, 8px);
@@ -53,12 +53,15 @@ That's it! The editor outputs **markdown** on every change.`;
53
53
  * Default editor with both FixedToolbar and FloatingToolbar.
54
54
  * All features enabled.
55
55
  */
56
+ // Mock upload handler — creates a local object URL for demo purposes
57
+ const mockImageUpload = async (file: File) => URL.createObjectURL(file);
58
+
56
59
  export const Default: Story = {
57
60
  render: (args) => {
58
61
  const [value, setValue] = useState(sampleMarkdown);
59
62
  return (
60
63
  <div style={{ maxWidth: 700 }}>
61
- <MarkdownEditor {...args} value={value} onChange={setValue}>
64
+ <MarkdownEditor {...args} value={value} onChange={setValue} handleImageUpload={mockImageUpload}>
62
65
  <FixedToolbar />
63
66
  <FloatingToolbar />
64
67
  </MarkdownEditor>
@@ -0,0 +1,115 @@
1
+ import { render, screen } from '../../test/render';
2
+ import { MarkdownEditor } from './MarkdownEditor';
3
+
4
+ // ProseMirror needs real DOM measurement APIs that jsdom does not provide.
5
+ const mockEditor = {
6
+ isDestroyed: false,
7
+ isEditable: true,
8
+ getMarkdown: () => 'mock',
9
+ commands: { setContent: vi.fn() },
10
+ setEditable: vi.fn(),
11
+ };
12
+
13
+ vi.mock('@tiptap/react', () => ({
14
+ useEditor: () => mockEditor,
15
+ EditorContent: ({ editor }: any) => (
16
+ <div data-testid="editor-content">{editor ? 'Editor loaded' : 'No editor'}</div>
17
+ ),
18
+ }));
19
+
20
+ describe('MarkdownEditor', () => {
21
+ it('renders without crashing', () => {
22
+ render(<MarkdownEditor value="" />);
23
+ expect(screen.getByTestId('editor-content')).toBeInTheDocument();
24
+ });
25
+
26
+ it('renders the editor content area', () => {
27
+ render(<MarkdownEditor value="" />);
28
+ expect(screen.getByText('Editor loaded')).toBeInTheDocument();
29
+ });
30
+
31
+ it('renders children (toolbar slot) inside the editor container', () => {
32
+ render(
33
+ <MarkdownEditor value="">
34
+ <div data-testid="custom-toolbar">Toolbar</div>
35
+ </MarkdownEditor>,
36
+ );
37
+ expect(screen.getByTestId('custom-toolbar')).toBeInTheDocument();
38
+ });
39
+
40
+ it('applies custom className to root element', () => {
41
+ const { container } = render(<MarkdownEditor value="" className="my-editor" />);
42
+ const root = container.firstElementChild;
43
+ expect(root).toHaveClass('my-editor');
44
+ });
45
+
46
+ it('sets data-status attribute based on status prop', () => {
47
+ const { container } = render(<MarkdownEditor value="" status="error" />);
48
+ const editorContainer = container.querySelector('[data-status]');
49
+ expect(editorContainer).toHaveAttribute('data-status', 'error');
50
+ });
51
+
52
+ it('sets data-status to success', () => {
53
+ const { container } = render(<MarkdownEditor value="" status="success" />);
54
+ const editorContainer = container.querySelector('[data-status]');
55
+ expect(editorContainer).toHaveAttribute('data-status', 'success');
56
+ });
57
+
58
+ it('sets data-status to default by default', () => {
59
+ const { container } = render(<MarkdownEditor value="" />);
60
+ const editorContainer = container.querySelector('[data-status]');
61
+ expect(editorContainer).toHaveAttribute('data-status', 'default');
62
+ });
63
+
64
+ it('sets data-disabled attribute when editable is false', () => {
65
+ const { container } = render(<MarkdownEditor value="" editable={false} />);
66
+ const editorContainer = container.querySelector('[data-disabled]');
67
+ expect(editorContainer).toHaveAttribute('data-disabled', 'true');
68
+ });
69
+
70
+ it('sets data-disabled to false when editable is true (default)', () => {
71
+ const { container } = render(<MarkdownEditor value="" />);
72
+ const editorContainer = container.querySelector('[data-disabled]');
73
+ expect(editorContainer).toHaveAttribute('data-disabled', 'false');
74
+ });
75
+
76
+ it('applies override props to root element', () => {
77
+ const { container } = render(
78
+ <MarkdownEditor
79
+ value=""
80
+ overrides={{
81
+ root: { 'data-testid': 'root-override' },
82
+ }}
83
+ />,
84
+ );
85
+ expect(screen.getByTestId('root-override')).toBeInTheDocument();
86
+ });
87
+
88
+ it('applies override props to editor container element', () => {
89
+ render(
90
+ <MarkdownEditor
91
+ value=""
92
+ overrides={{
93
+ editorContainer: { 'data-testid': 'container-override' },
94
+ }}
95
+ />,
96
+ );
97
+ expect(screen.getByTestId('container-override')).toBeInTheDocument();
98
+ });
99
+
100
+ it('sets the markdown base font size CSS variable', () => {
101
+ const { container } = render(<MarkdownEditor value="" size="paragraphMedium" />);
102
+ const editorContent = container.querySelector('[class*="editorContent"]');
103
+ expect(editorContent).toHaveStyle({
104
+ '--markdown-base-font-size': 'var(--pte-new-typography-styles-paragraphMedium-fontSize)',
105
+ });
106
+ });
107
+
108
+ it('uses paragraphSmall as the default size', () => {
109
+ const { container } = render(<MarkdownEditor value="" />);
110
+ const editorContent = container.querySelector('[class*="editorContent"]');
111
+ expect(editorContent).toHaveStyle({
112
+ '--markdown-base-font-size': 'var(--pte-new-typography-styles-paragraphSmall-fontSize)',
113
+ });
114
+ });
115
+ });
@@ -8,6 +8,7 @@ import type { MarkdownSize } from '../markdown';
8
8
  import type { MarkdownEditorFeature } from './features';
9
9
  import { ALL_FEATURES } from './features';
10
10
  import styles from './MarkdownEditor.module.scss';
11
+ import type { ImageUploadHandler } from './MarkdownEditorContext';
11
12
  import { MarkdownEditorContext } from './MarkdownEditorContext';
12
13
  import { useMarkdownEditor } from './useMarkdownEditor';
13
14
 
@@ -31,6 +32,11 @@ export type MarkdownEditorProps = {
31
32
  autofocus?: boolean;
32
33
  /** An optional CSS class name for the root wrapper. */
33
34
  className?: string;
35
+ /**
36
+ * Handler for image uploads. Receives a File, should return a Promise
37
+ * resolving to the image URL. If not provided, the image button is hidden.
38
+ */
39
+ handleImageUpload?: ImageUploadHandler;
34
40
  /** Visual status for the editor container (follows Input pattern). */
35
41
  status?: 'default' | 'error' | 'success';
36
42
  /** Prop overrides for sub-elements. */
@@ -80,6 +86,7 @@ export const MarkdownEditor: FC<MarkdownEditorProps> = ({
80
86
  size = 'paragraphSmall',
81
87
  editable = true,
82
88
  autofocus = false,
89
+ handleImageUpload,
83
90
  className,
84
91
  status = 'default',
85
92
  overrides,
@@ -94,7 +101,10 @@ export const MarkdownEditor: FC<MarkdownEditorProps> = ({
94
101
  autofocus,
95
102
  });
96
103
 
97
- const contextValue = useMemo(() => ({ editor, features: featureSet }), [editor, featureSet]);
104
+ const contextValue = useMemo(
105
+ () => ({ editor, features: featureSet, handleImageUpload }),
106
+ [editor, featureSet, handleImageUpload],
107
+ );
98
108
 
99
109
  return (
100
110
  <MarkdownEditorContext.Provider value={contextValue}>
@@ -4,9 +4,12 @@ import type { Editor } from '@tiptap/react';
4
4
  import { createContext, useContext } from 'react';
5
5
  import type { MarkdownEditorFeature } from './features';
6
6
 
7
+ export type ImageUploadHandler = (file: File) => Promise<string>;
8
+
7
9
  export type MarkdownEditorContextValue = {
8
10
  editor: Editor | null;
9
11
  features: Set<MarkdownEditorFeature>;
12
+ handleImageUpload?: ImageUploadHandler;
10
13
  };
11
14
 
12
15
  export const MarkdownEditorContext = createContext<MarkdownEditorContextValue>({
@@ -6,6 +6,7 @@ export type { MarkdownEditorFeature } from './features';
6
6
  export { ALL_FEATURES, FEATURES } from './features';
7
7
  export type { MarkdownEditorProps } from './MarkdownEditor';
8
8
  export { MarkdownEditor } from './MarkdownEditor';
9
+ export type { ImageUploadHandler } from './MarkdownEditorContext';
9
10
  export { useMarkdownEditorContext } from './MarkdownEditorContext';
10
11
  export type { ToolbarButtonProps } from './ToolbarButton';
11
12
  export { ToolbarButton } from './ToolbarButton';
@@ -19,7 +19,7 @@
19
19
  align-items: flex-start;
20
20
 
21
21
  overflow: hidden;
22
- z-index: 100;
22
+ z-index: var(--pte-new-layers-menu);
23
23
 
24
24
  transition: var(--pte-animations-interaction);
25
25
  opacity: 1;