eddyter 1.3.37 → 1.3.39

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 CHANGED
@@ -298,6 +298,8 @@ Provides authentication and configuration context for the editor.
298
298
  - `children`: React nodes to render
299
299
  - `defaultFontFamilies`: Array of font names (optional)
300
300
  - `currentUser`: Current logged-in user for comments (optional) - Object with `id`, `name`, `email`, and optional `avatar`
301
+ - `enableLinkPreview`: Enable automatic link preview on hover (optional, default: `true`)
302
+ - `apiKey`: API key for authentication (optional) - Required only if you need link preview to work immediately without opening the editor first
301
303
 
302
304
  ### ConfigurableEditorWithAuth
303
305
 
@@ -439,6 +441,43 @@ function App() {
439
441
  }
440
442
  ```
441
443
 
444
+ ## Link Preview Feature
445
+
446
+ Eddyter includes automatic link preview on hover. When users hover over links in content wrapped by `EditorProvider`, a preview popup shows the link's title, description, and image.
447
+
448
+ ### How It Works
449
+
450
+ - **Inside the editor**: Link preview works automatically after authentication
451
+ - **Outside the editor** (preview mode, saved content): Link preview works if the user has opened the editor at least once in the session (authentication stores the API key)
452
+
453
+ ### Preview-Only Scenarios
454
+
455
+ If your application displays saved content without ever opening the editor (e.g., a read-only view), you need to pass `apiKey` to `EditorProvider`:
456
+
457
+ ```jsx
458
+ import React from 'react';
459
+ import { EditorProvider } from 'eddyter';
460
+ import 'eddyter/style.css';
461
+
462
+ function ContentPreviewPage({ savedHtml }) {
463
+ return (
464
+ <EditorProvider apiKey="your-api-key">
465
+ <div dangerouslySetInnerHTML={{ __html: savedHtml }} />
466
+ </EditorProvider>
467
+ );
468
+ }
469
+ ```
470
+
471
+ ### Disabling Link Preview
472
+
473
+ To disable link preview entirely:
474
+
475
+ ```jsx
476
+ <EditorProvider enableLinkPreview={false}>
477
+ {/* Your content */}
478
+ </EditorProvider>
479
+ ```
480
+
442
481
  ## License
443
482
 
444
483
  This project is licensed under the MIT License - see the LICENSE file for details.
@@ -17,11 +17,16 @@ interface EditorContextType {
17
17
  verifyKey: (apiKey: string) => Promise<void>;
18
18
  }
19
19
  export declare const useEditor: () => EditorContextType;
20
+ export declare const useEditorOptional: () => EditorContextType | undefined;
20
21
  interface EditorProviderProps {
21
22
  children: React.ReactNode;
22
23
  defaultFontFamilies?: string[];
23
24
  mentionUserList?: string[];
24
25
  currentUser?: CurrentUser;
26
+ /** Enable automatic link preview on hover for all content within provider (default: true) */
27
+ enableLinkPreview?: boolean;
28
+ /** API key for authentication - if provided, will auto-authenticate on mount */
29
+ apiKey?: string;
25
30
  }
26
31
  export declare const EditorProvider: React.FC<EditorProviderProps>;
27
32
  export {};
@@ -3,8 +3,9 @@ type AiStreamType = {
3
3
  onMessage: (message: string) => void;
4
4
  };
5
5
  export declare const AiStream: ({ content, onMessage }: AiStreamType) => Promise<void>;
6
- export declare const AiJsonResponse: ({ content }: {
6
+ export declare const AiJsonResponse: ({ content, apiKey }: {
7
7
  content: string;
8
+ apiKey?: string | undefined;
8
9
  }) => Promise<any>;
9
10
  export declare const AiImageResponse: ({ content }: {
10
11
  content: string;
@@ -959,6 +959,11 @@ video {
959
959
  height: 2rem !important;
960
960
  }
961
961
 
962
+ .\!cteditor-size-\[16px\]{
963
+ width: 16px !important;
964
+ height: 16px !important;
965
+ }
966
+
962
967
  .\!cteditor-size-\[18px\]{
963
968
  width: 18px !important;
964
969
  height: 18px !important;
@@ -1622,6 +1627,10 @@ video {
1622
1627
  align-items: flex-start;
1623
1628
  }
1624
1629
 
1630
+ .cteditor-items-end{
1631
+ align-items: flex-end;
1632
+ }
1633
+
1625
1634
  .cteditor-items-center{
1626
1635
  align-items: center;
1627
1636
  }
@@ -2159,21 +2168,11 @@ video {
2159
2168
  background-color: rgb(42 42 42 / var(--tw-bg-opacity, 1));
2160
2169
  }
2161
2170
 
2162
- .cteditor-bg-\[\#2a3a2a\]{
2163
- --tw-bg-opacity: 1;
2164
- background-color: rgb(42 58 42 / var(--tw-bg-opacity, 1));
2165
- }
2166
-
2167
2171
  .cteditor-bg-\[\#2e1a1a\]{
2168
2172
  --tw-bg-opacity: 1;
2169
2173
  background-color: rgb(46 26 26 / var(--tw-bg-opacity, 1));
2170
2174
  }
2171
2175
 
2172
- .cteditor-bg-\[\#3a2a2a\]{
2173
- --tw-bg-opacity: 1;
2174
- background-color: rgb(58 42 42 / var(--tw-bg-opacity, 1));
2175
- }
2176
-
2177
2176
  .cteditor-bg-\[hsl\(var\(--cteditorf47ac10b-popover\)\)\]{
2178
2177
  background-color: hsl(var(--cteditorf47ac10b-popover));
2179
2178
  }
@@ -4652,14 +4651,6 @@ body .EmojiPickerReact{
4652
4651
  top: 0.375rem;
4653
4652
  }
4654
4653
 
4655
- .\[\&\>button\:hover\>span\]\:cteditor-bottom-full>button:hover>span{
4656
- bottom: 100%;
4657
- }
4658
-
4659
- .\[\&\>button\:hover\>span\]\:cteditor-opacity-100>button:hover>span{
4660
- opacity: 1;
4661
- }
4662
-
4663
4654
  .\[\&\>button\>span\]\:cteditor-border>button>span{
4664
4655
  border-width: 1px;
4665
4656
  }
@@ -4669,11 +4660,6 @@ body .EmojiPickerReact{
4669
4660
  border-color: rgb(0 0 0 / var(--tw-border-opacity, 1));
4670
4661
  }
4671
4662
 
4672
- .\[\&\>button\>svg\]\:cteditor-size-4>button>svg{
4673
- width: 1rem;
4674
- height: 1rem;
4675
- }
4676
-
4677
4663
  .\[\&\>button\>svg\]\:cteditor-shrink-0>button>svg{
4678
4664
  flex-shrink: 0;
4679
4665
  }
@@ -4798,14 +4784,9 @@ body .EmojiPickerReact{
4798
4784
  height: 1rem !important;
4799
4785
  }
4800
4786
 
4801
- .\[\&\>svg\]\:\!cteditor-size-5>svg{
4802
- width: 1.25rem !important;
4803
- height: 1.25rem !important;
4804
- }
4805
-
4806
- .\[\&\>svg\]\:\!cteditor-size-6>svg{
4807
- width: 1.5rem !important;
4808
- height: 1.5rem !important;
4787
+ .\[\&\>svg\]\:cteditor-size-3\.5>svg{
4788
+ width: 0.875rem;
4789
+ height: 0.875rem;
4809
4790
  }
4810
4791
 
4811
4792
  .\[\&\>svg\]\:cteditor-size-4>svg{
@@ -4818,14 +4799,6 @@ body .EmojiPickerReact{
4818
4799
  height: 1.25rem;
4819
4800
  }
4820
4801
 
4821
- .\[\&\>svg\]\:cteditor-h-auto>svg{
4822
- height: auto;
4823
- }
4824
-
4825
- .\[\&\>svg\]\:cteditor-w-5>svg{
4826
- width: 1.25rem;
4827
- }
4828
-
4829
4802
  .\[\&\>svg\]\:cteditor-shrink-0>svg{
4830
4803
  flex-shrink: 0;
4831
4804
  }
@@ -4834,11 +4807,6 @@ body .EmojiPickerReact{
4834
4807
  pointer-events: none;
4835
4808
  }
4836
4809
 
4837
- .\[\&_svg\]\:\!cteditor-size-4 svg{
4838
- width: 1rem !important;
4839
- height: 1rem !important;
4840
- }
4841
-
4842
4810
  .\[\&_svg\]\:\!cteditor-size-5 svg{
4843
4811
  width: 1.25rem !important;
4844
4812
  height: 1.25rem !important;
@@ -5506,9 +5474,10 @@ body .EmojiPickerReact{
5506
5474
  margin-top: 0;
5507
5475
  }
5508
5476
 
5509
- /* Paragraph spacing - minimal for tight line spacing */
5510
- .PlaygroundEditorTheme__paragraph {
5511
- margin-bottom: 0;
5477
+ /* Paragraph spacing - add spacing between paragraphs for readability */
5478
+ /* This mimics standard web content spacing (like BBC, news sites, etc.) */
5479
+ .PlaygroundEditorTheme__paragraph + .PlaygroundEditorTheme__paragraph {
5480
+ margin-top: 1em;
5512
5481
  }
5513
5482
 
5514
5483
  /* Heading after paragraph needs extra space above - CKEditor style */
@@ -7140,74 +7109,7 @@ body .EmojiPickerReact{
7140
7109
  min-width: 200px;
7141
7110
  min-height: 150px;
7142
7111
  }
7143
- }.floating-enhance-button {
7144
- position: absolute;
7145
- z-index: 10;
7146
- background: linear-gradient(135deg, #1f2937 0%, #111827 100%);
7147
- border: 1px solid rgba(255, 255, 255, 0.1);
7148
- border-radius: 8px;
7149
- padding: 8px;
7150
- cursor: pointer;
7151
- display: flex;
7152
- align-items: center;
7153
- justify-content: center;
7154
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
7155
- transition: all 0.2s ease;
7156
- opacity: 0;
7157
- pointer-events: auto;
7158
- width: 32px;
7159
- height: 32px;
7160
- }
7161
-
7162
- .floating-enhance-button:hover {
7163
- transform: scale(1.1);
7164
- background: linear-gradient(135deg, #374151 0%, #1f2937 100%);
7165
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
7166
- border-color: rgba(255, 255, 255, 0.2);
7167
- }
7168
-
7169
- .floating-enhance-button:active {
7170
- transform: scale(0.95);
7171
- }
7172
-
7173
- .floating-enhance-button svg {
7174
- width: 16px;
7175
- height: 16px;
7176
- color: #a78bfa;
7177
- }
7178
-
7179
- .floating-enhance-button-tooltip {
7180
- position: absolute;
7181
- bottom: calc(100% + 8px);
7182
- left: 50%;
7183
- transform: translateX(-50%);
7184
- background-color: #1f2937;
7185
- color: white;
7186
- padding: 6px 12px;
7187
- border-radius: 6px;
7188
- font-size: 12px;
7189
- font-weight: 500;
7190
- white-space: nowrap;
7191
- opacity: 0;
7192
- pointer-events: none;
7193
- transition: opacity 0.2s ease;
7194
- }
7195
-
7196
- .floating-enhance-button:hover .floating-enhance-button-tooltip {
7197
- opacity: 1;
7198
- }
7199
-
7200
- /* Arrow for tooltip */
7201
- .floating-enhance-button-tooltip::after {
7202
- content: "";
7203
- position: absolute;
7204
- top: 100%;
7205
- left: 50%;
7206
- transform: translateX(-50%);
7207
- border: 6px solid transparent;
7208
- border-top-color: #1f2937;
7209
- }
7210
- .link-editor {
7112
+ }.link-editor {
7211
7113
  display: flex;
7212
7114
  position: absolute;
7213
7115
  top: 0;
@@ -19,6 +19,18 @@ interface ConfigurableEditorWithAuthProps {
19
19
  onBlur?: () => void;
20
20
  /** Called when editor height changes (React Native bridge) */
21
21
  onHeightChange?: (height: number) => void;
22
+ /**
23
+ * Editor mode:
24
+ * - "edit" (default): Full editor with all editing capabilities
25
+ * - "preview": Read-only preview with interactive features (link preview, etc.)
26
+ */
27
+ mode?: "edit" | "preview";
28
+ /** Additional class name for the preview container (only used in preview mode) */
29
+ previewClassName?: string;
30
+ /** Additional styles for the preview container (only used in preview mode) */
31
+ previewStyle?: React.CSSProperties;
32
+ /** Click handler for preview mode (useful for switching to edit mode) */
33
+ onPreviewClick?: () => void;
22
34
  }
23
35
  declare const ConfigurableEditorWithAuth: React.FC<ConfigurableEditorWithAuthProps>;
24
36
  export default ConfigurableEditorWithAuth;
@@ -0,0 +1,37 @@
1
+ import { default as React } from 'react';
2
+ /**
3
+ * ContentPreview - A component for displaying saved editor content with all interactive features
4
+ * (like link previews) enabled automatically.
5
+ *
6
+ * This is the recommended way to display content that was created with ConfigurableEditor.
7
+ * When used within EditorProvider, it automatically enables:
8
+ * - Link preview on hover (handled by EditorProvider)
9
+ * - Proper styling
10
+ * - All interactive features
11
+ *
12
+ * Note: Link preview is now automatically handled by EditorProvider.
13
+ * Just wrap your app with EditorProvider and link preview works everywhere!
14
+ *
15
+ * Usage:
16
+ * ```tsx
17
+ * import { ContentPreview, EditorProvider } from "@craxinno/cteditor";
18
+ *
19
+ * <EditorProvider>
20
+ * <ConfigurableEditorWithAuth apiKey={apiKey} ... />
21
+ * {/* Content preview also gets link preview automatically! *\/}
22
+ * <ContentPreview content={savedHtmlContent} />
23
+ * </EditorProvider>
24
+ * ```
25
+ */
26
+ interface ContentPreviewProps {
27
+ /** The HTML content to display (from editor's onChange) */
28
+ content: string;
29
+ /** Additional CSS class names */
30
+ className?: string;
31
+ /** Additional inline styles */
32
+ style?: React.CSSProperties;
33
+ /** Click handler for the content area */
34
+ onClick?: () => void;
35
+ }
36
+ export default function ContentPreview({ content, className, style, onClick, }: ContentPreviewProps): JSX.Element;
37
+ export type { ContentPreviewProps };
@@ -0,0 +1,40 @@
1
+ /// <reference types="react" />
2
+ /**
3
+ * LinkPreviewHover - A standalone component that provides link preview on hover
4
+ * Can be used with any HTML container (not dependent on Lexical editor)
5
+ *
6
+ * Usage:
7
+ * <LinkPreviewHover containerRef={myContainerRef} apiKey={apiKey} />
8
+ *
9
+ * Or wrap content:
10
+ * <LinkPreviewHover apiKey={apiKey}>
11
+ * <div dangerouslySetInnerHTML={{ __html: htmlContent }} />
12
+ * </LinkPreviewHover>
13
+ */
14
+ interface LinkPreviewHoverProps {
15
+ /** Reference to the container element to attach hover listeners */
16
+ containerRef?: React.RefObject<HTMLElement>;
17
+ /** Children to wrap (alternative to containerRef) */
18
+ children?: React.ReactNode;
19
+ /** API key for authentication */
20
+ apiKey?: string;
21
+ /** Delay before showing preview (ms) */
22
+ showDelay?: number;
23
+ /** Delay before hiding preview (ms) */
24
+ hideDelay?: number;
25
+ /** Enable/disable the preview */
26
+ enabled?: boolean;
27
+ }
28
+ export default function LinkPreviewHover({ containerRef, children, apiKey, showDelay, hideDelay, enabled, }: LinkPreviewHoverProps): JSX.Element;
29
+ interface LinkPreviewCardProps {
30
+ url: string;
31
+ rect: DOMRect;
32
+ apiKey?: string;
33
+ onClose: () => void;
34
+ }
35
+ declare function LinkPreviewCard({ url, rect, apiKey, onClose }: LinkPreviewCardProps): import("react/jsx-runtime").JSX.Element;
36
+ declare function TypeIcon({ type }: {
37
+ type: string;
38
+ }): import("react/jsx-runtime").JSX.Element;
39
+ export { LinkPreviewCard, TypeIcon };
40
+ export type { LinkPreviewHoverProps, LinkPreviewCardProps };
@@ -7,7 +7,7 @@ declare const SheetClose: React.ForwardRefExoticComponent<SheetPrimitive.DialogC
7
7
  declare const SheetPortal: React.FC<SheetPrimitive.DialogPortalProps>;
8
8
  declare const SheetOverlay: React.ForwardRefExoticComponent<Omit<SheetPrimitive.DialogOverlayProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
9
9
  declare const sheetVariants: (props?: ({
10
- side?: "left" | "right" | "bottom" | "top" | null | undefined;
10
+ side?: "top" | "left" | "right" | "bottom" | null | undefined;
11
11
  } & import('class-variance-authority/dist/types').ClassProp) | undefined) => string;
12
12
  interface SheetContentProps extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>, VariantProps<typeof sheetVariants> {
13
13
  }
@@ -4,7 +4,7 @@ var __publicField = (obj, key, value) => {
4
4
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
5
  return value;
6
6
  };
7
- import { g as getDefaultExportFromCjs, c as commonjsGlobal } from "./index-6717344b.js";
7
+ import { g as getDefaultExportFromCjs, c as commonjsGlobal } from "./index-a92ee4fa.js";
8
8
  function _mergeNamespaces(n, m) {
9
9
  for (var i = 0; i < m.length; i++) {
10
10
  const e = m[i];
@@ -46125,4 +46125,4 @@ const html2pdf_bundle$1 = /* @__PURE__ */ _mergeNamespaces({
46125
46125
  export {
46126
46126
  html2pdf_bundle$1 as h
46127
46127
  };
46128
- //# sourceMappingURL=html2pdf.bundle-d4225b87.js.map
46128
+ //# sourceMappingURL=html2pdf.bundle-c79c27d6.js.map