@rufous/ui 0.1.91 → 0.1.93

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/main.cjs CHANGED
@@ -49678,6 +49678,12 @@ function createSpellCheckPlugin() {
49678
49678
  let viewRef = null;
49679
49679
  const runCheck = (view) => {
49680
49680
  if (!typo || !view.dom?.isConnected) return;
49681
+ if (view.state.doc.content.size <= 2) {
49682
+ const tr2 = view.state.tr.setMeta(spellCheckPluginKey, { decorations: DecorationSet.empty });
49683
+ tr2.setMeta("addToHistory", false);
49684
+ view.dispatch(tr2);
49685
+ return;
49686
+ }
49681
49687
  const { doc: doc3 } = view.state;
49682
49688
  const misspelled = findMisspelled(doc3);
49683
49689
  const decos = misspelled.map(
@@ -49702,10 +49708,17 @@ function createSpellCheckPlugin() {
49702
49708
  init() {
49703
49709
  return DecorationSet.empty;
49704
49710
  },
49705
- apply(tr, oldDecos) {
49711
+ apply(tr, oldDecos, _oldState, newState) {
49706
49712
  const meta = tr.getMeta(spellCheckPluginKey);
49707
49713
  if (meta?.decorations) return meta.decorations;
49708
- if (tr.docChanged) return oldDecos.map(tr.mapping, tr.doc);
49714
+ if (tr.docChanged) {
49715
+ if (newState.doc.content.size <= 2) return DecorationSet.empty;
49716
+ try {
49717
+ return oldDecos.map(tr.mapping, tr.doc);
49718
+ } catch {
49719
+ return DecorationSet.empty;
49720
+ }
49721
+ }
49709
49722
  return oldDecos;
49710
49723
  }
49711
49724
  },
@@ -49843,6 +49856,7 @@ var RufousTextEditor = ({
49843
49856
  onSave: onSaveProp,
49844
49857
  onExport: onExportProp,
49845
49858
  onChange,
49859
+ onBlur,
49846
49860
  onAICommand,
49847
49861
  onTranslate,
49848
49862
  onSpeechToText,
@@ -49854,6 +49868,14 @@ var RufousTextEditor = ({
49854
49868
  style
49855
49869
  }) => {
49856
49870
  const mentionSuggestion = (0, import_react60.useMemo)(() => createMentionSuggestion(mentions), [mentions]);
49871
+ const onChangeRef = (0, import_react60.useRef)(onChange);
49872
+ const onBlurRef = (0, import_react60.useRef)(onBlur);
49873
+ (0, import_react60.useEffect)(() => {
49874
+ onChangeRef.current = onChange;
49875
+ }, [onChange]);
49876
+ (0, import_react60.useEffect)(() => {
49877
+ onBlurRef.current = onBlur;
49878
+ }, [onBlur]);
49857
49879
  const editor = (0, import_react61.useEditor)({
49858
49880
  editable,
49859
49881
  extensions: [
@@ -49943,11 +49965,19 @@ var RufousTextEditor = ({
49943
49965
  },
49944
49966
  content: initialContent || "",
49945
49967
  onUpdate: ({ editor: e }) => {
49946
- if (onChange) {
49947
- onChange(e.getHTML(), e.getJSON());
49948
- }
49968
+ onChangeRef.current?.(e.getHTML(), e.getJSON());
49949
49969
  }
49950
49970
  });
49971
+ (0, import_react60.useEffect)(() => {
49972
+ if (!editor) return;
49973
+ const handler = () => {
49974
+ onBlurRef.current?.(editor.getHTML(), editor.getJSON());
49975
+ };
49976
+ editor.on("blur", handler);
49977
+ return () => {
49978
+ editor.off("blur", handler);
49979
+ };
49980
+ }, [editor]);
49951
49981
  const [linkModalOpen, setLinkModalOpen] = (0, import_react60.useState)(false);
49952
49982
  const [linkUrl, setLinkUrl] = (0, import_react60.useState)("");
49953
49983
  const [linkText, setLinkText] = (0, import_react60.useState)("");
@@ -50053,17 +50083,22 @@ var RufousTextEditor = ({
50053
50083
  onImageUpload,
50054
50084
  onClose
50055
50085
  }
50056
- ), /* @__PURE__ */ import_react60.default.createElement(import_react61.EditorContent, { editor, className: "editor-content-wrapper" }), /* @__PURE__ */ import_react60.default.createElement(ImageToolbar_default, { editor }), /* @__PURE__ */ import_react60.default.createElement(VideoToolbar_default, { editor }), /* @__PURE__ */ import_react60.default.createElement(SpellCheckTooltip, { editor }), /* @__PURE__ */ import_react60.default.createElement(
50086
+ ), /* @__PURE__ */ import_react60.default.createElement(import_react61.EditorContent, { editor, className: "editor-content-wrapper" }), /* @__PURE__ */ import_react60.default.createElement(ImageToolbar_default, { editor }), /* @__PURE__ */ import_react60.default.createElement(VideoToolbar_default, { editor }), /* @__PURE__ */ import_react60.default.createElement(SpellCheckTooltip, { editor }), editor && /* @__PURE__ */ import_react60.default.createElement(
50057
50087
  import_react61.BubbleMenu,
50058
50088
  {
50059
50089
  editor,
50060
50090
  className: "bubble-menu",
50061
50091
  shouldShow: ({ editor: e }) => {
50062
- const { selection } = e.state;
50063
- if (selection?.node?.type.name === "image") return false;
50064
- if (selection?.node?.type.name === "youtube") return false;
50065
- if (selection?.node?.type.name === "video") return false;
50066
- return !selection.empty;
50092
+ if (!e || e.isDestroyed) return false;
50093
+ try {
50094
+ const { selection } = e.state;
50095
+ if (selection?.node?.type.name === "image") return false;
50096
+ if (selection?.node?.type.name === "youtube") return false;
50097
+ if (selection?.node?.type.name === "video") return false;
50098
+ return !selection.empty;
50099
+ } catch {
50100
+ return false;
50101
+ }
50067
50102
  }
50068
50103
  },
50069
50104
  /* @__PURE__ */ import_react60.default.createElement(
@@ -50106,42 +50141,62 @@ var RufousTextEditor = ({
50106
50141
  },
50107
50142
  "\u{1F517}"
50108
50143
  )
50109
- ), /* @__PURE__ */ import_react60.default.createElement(import_react61.FloatingMenu, { editor, className: "floating-menu" }, /* @__PURE__ */ import_react60.default.createElement(
50110
- "button",
50111
- {
50112
- onClick: () => editor?.chain().focus().toggleHeading({ level: 1 }).run(),
50113
- className: editor?.isActive("heading", { level: 1 }) ? "is-active" : ""
50114
- },
50115
- "H1"
50116
- ), /* @__PURE__ */ import_react60.default.createElement(
50117
- "button",
50118
- {
50119
- onClick: () => editor?.chain().focus().toggleHeading({ level: 2 }).run(),
50120
- className: editor?.isActive("heading", { level: 2 }) ? "is-active" : ""
50121
- },
50122
- "H2"
50123
- ), /* @__PURE__ */ import_react60.default.createElement(
50124
- "button",
50125
- {
50126
- onClick: () => editor?.chain().focus().toggleBulletList().run(),
50127
- className: editor?.isActive("bulletList") ? "is-active" : ""
50128
- },
50129
- "\u2022 List"
50130
- ), /* @__PURE__ */ import_react60.default.createElement(
50131
- "button",
50144
+ ), editor && /* @__PURE__ */ import_react60.default.createElement(
50145
+ import_react61.FloatingMenu,
50132
50146
  {
50133
- onClick: () => editor?.chain().focus().toggleOrderedList().run(),
50134
- className: editor?.isActive("orderedList") ? "is-active" : ""
50135
- },
50136
- "1. List"
50137
- ), /* @__PURE__ */ import_react60.default.createElement(
50138
- "button",
50139
- {
50140
- onClick: () => editor?.chain().focus().toggleBlockquote().run(),
50141
- className: editor?.isActive("blockquote") ? "is-active" : ""
50147
+ editor,
50148
+ className: "floating-menu",
50149
+ shouldShow: ({ editor: e }) => {
50150
+ if (!e || e.isDestroyed) return false;
50151
+ try {
50152
+ const { selection } = e.state;
50153
+ return selection.empty && e.state.doc.textContent.length === 0;
50154
+ } catch {
50155
+ return false;
50156
+ }
50157
+ }
50142
50158
  },
50143
- "\u201C Quote"
50144
- )), /* @__PURE__ */ import_react60.default.createElement("div", { className: "status-bar" }, /* @__PURE__ */ import_react60.default.createElement("div", { className: "status-bar-left" }, /* @__PURE__ */ import_react60.default.createElement(
50159
+ /* @__PURE__ */ import_react60.default.createElement(
50160
+ "button",
50161
+ {
50162
+ onClick: () => editor?.chain().focus().toggleHeading({ level: 1 }).run(),
50163
+ className: editor?.isActive("heading", { level: 1 }) ? "is-active" : ""
50164
+ },
50165
+ "H1"
50166
+ ),
50167
+ /* @__PURE__ */ import_react60.default.createElement(
50168
+ "button",
50169
+ {
50170
+ onClick: () => editor?.chain().focus().toggleHeading({ level: 2 }).run(),
50171
+ className: editor?.isActive("heading", { level: 2 }) ? "is-active" : ""
50172
+ },
50173
+ "H2"
50174
+ ),
50175
+ /* @__PURE__ */ import_react60.default.createElement(
50176
+ "button",
50177
+ {
50178
+ onClick: () => editor?.chain().focus().toggleBulletList().run(),
50179
+ className: editor?.isActive("bulletList") ? "is-active" : ""
50180
+ },
50181
+ "\u2022 List"
50182
+ ),
50183
+ /* @__PURE__ */ import_react60.default.createElement(
50184
+ "button",
50185
+ {
50186
+ onClick: () => editor?.chain().focus().toggleOrderedList().run(),
50187
+ className: editor?.isActive("orderedList") ? "is-active" : ""
50188
+ },
50189
+ "1. List"
50190
+ ),
50191
+ /* @__PURE__ */ import_react60.default.createElement(
50192
+ "button",
50193
+ {
50194
+ onClick: () => editor?.chain().focus().toggleBlockquote().run(),
50195
+ className: editor?.isActive("blockquote") ? "is-active" : ""
50196
+ },
50197
+ "\u201C Quote"
50198
+ )
50199
+ ), /* @__PURE__ */ import_react60.default.createElement("div", { className: "status-bar" }, /* @__PURE__ */ import_react60.default.createElement("div", { className: "status-bar-left" }, /* @__PURE__ */ import_react60.default.createElement(
50145
50200
  "select",
50146
50201
  {
50147
50202
  value: saveFormat,
package/dist/main.d.cts CHANGED
@@ -1683,6 +1683,7 @@ interface RufousTextEditorProps {
1683
1683
  onSave?: (html: string, json: any) => void;
1684
1684
  onExport?: (html: string, json: any) => void;
1685
1685
  onChange?: (html: string, json: any) => void;
1686
+ onBlur?: (html: string, json: any) => void;
1686
1687
  onAICommand?: (prompt: string, text: string, previousResults?: string[]) => Promise<string>;
1687
1688
  onTranslate?: (text: string, sourceLang: string, targetLang: string) => Promise<string>;
1688
1689
  onSpeechToText?: (text: string) => Promise<string>;
package/dist/main.d.ts CHANGED
@@ -1683,6 +1683,7 @@ interface RufousTextEditorProps {
1683
1683
  onSave?: (html: string, json: any) => void;
1684
1684
  onExport?: (html: string, json: any) => void;
1685
1685
  onChange?: (html: string, json: any) => void;
1686
+ onBlur?: (html: string, json: any) => void;
1686
1687
  onAICommand?: (prompt: string, text: string, previousResults?: string[]) => Promise<string>;
1687
1688
  onTranslate?: (text: string, sourceLang: string, targetLang: string) => Promise<string>;
1688
1689
  onSpeechToText?: (text: string) => Promise<string>;
package/dist/main.js CHANGED
@@ -8721,7 +8721,7 @@ var PhoneField = forwardRef10(function PhoneField2(props, ref) {
8721
8721
  PhoneField.displayName = "PhoneField";
8722
8722
 
8723
8723
  // lib/RufousTextEditor/RufousTextEditor.tsx
8724
- import React117, { useMemo as useMemo4, useCallback as useCallback14, useState as useState35 } from "react";
8724
+ import React117, { useMemo as useMemo4, useCallback as useCallback14, useState as useState35, useRef as useRef31, useEffect as useEffect28 } from "react";
8725
8725
  import { useEditor, EditorContent, EditorContext, FloatingMenu, BubbleMenu } from "@tiptap/react";
8726
8726
  import StarterKit from "@tiptap/starter-kit";
8727
8727
  import Placeholder from "@tiptap/extension-placeholder";
@@ -21009,6 +21009,12 @@ function createSpellCheckPlugin() {
21009
21009
  let viewRef = null;
21010
21010
  const runCheck = (view) => {
21011
21011
  if (!typo || !view.dom?.isConnected) return;
21012
+ if (view.state.doc.content.size <= 2) {
21013
+ const tr2 = view.state.tr.setMeta(spellCheckPluginKey, { decorations: DecorationSet.empty });
21014
+ tr2.setMeta("addToHistory", false);
21015
+ view.dispatch(tr2);
21016
+ return;
21017
+ }
21012
21018
  const { doc: doc3 } = view.state;
21013
21019
  const misspelled = findMisspelled(doc3);
21014
21020
  const decos = misspelled.map(
@@ -21033,10 +21039,17 @@ function createSpellCheckPlugin() {
21033
21039
  init() {
21034
21040
  return DecorationSet.empty;
21035
21041
  },
21036
- apply(tr, oldDecos) {
21042
+ apply(tr, oldDecos, _oldState, newState) {
21037
21043
  const meta = tr.getMeta(spellCheckPluginKey);
21038
21044
  if (meta?.decorations) return meta.decorations;
21039
- if (tr.docChanged) return oldDecos.map(tr.mapping, tr.doc);
21045
+ if (tr.docChanged) {
21046
+ if (newState.doc.content.size <= 2) return DecorationSet.empty;
21047
+ try {
21048
+ return oldDecos.map(tr.mapping, tr.doc);
21049
+ } catch {
21050
+ return DecorationSet.empty;
21051
+ }
21052
+ }
21040
21053
  return oldDecos;
21041
21054
  }
21042
21055
  },
@@ -21174,6 +21187,7 @@ var RufousTextEditor = ({
21174
21187
  onSave: onSaveProp,
21175
21188
  onExport: onExportProp,
21176
21189
  onChange,
21190
+ onBlur,
21177
21191
  onAICommand,
21178
21192
  onTranslate,
21179
21193
  onSpeechToText,
@@ -21185,6 +21199,14 @@ var RufousTextEditor = ({
21185
21199
  style
21186
21200
  }) => {
21187
21201
  const mentionSuggestion = useMemo4(() => createMentionSuggestion(mentions), [mentions]);
21202
+ const onChangeRef = useRef31(onChange);
21203
+ const onBlurRef = useRef31(onBlur);
21204
+ useEffect28(() => {
21205
+ onChangeRef.current = onChange;
21206
+ }, [onChange]);
21207
+ useEffect28(() => {
21208
+ onBlurRef.current = onBlur;
21209
+ }, [onBlur]);
21188
21210
  const editor = useEditor({
21189
21211
  editable,
21190
21212
  extensions: [
@@ -21274,11 +21296,19 @@ var RufousTextEditor = ({
21274
21296
  },
21275
21297
  content: initialContent || "",
21276
21298
  onUpdate: ({ editor: e }) => {
21277
- if (onChange) {
21278
- onChange(e.getHTML(), e.getJSON());
21279
- }
21299
+ onChangeRef.current?.(e.getHTML(), e.getJSON());
21280
21300
  }
21281
21301
  });
21302
+ useEffect28(() => {
21303
+ if (!editor) return;
21304
+ const handler = () => {
21305
+ onBlurRef.current?.(editor.getHTML(), editor.getJSON());
21306
+ };
21307
+ editor.on("blur", handler);
21308
+ return () => {
21309
+ editor.off("blur", handler);
21310
+ };
21311
+ }, [editor]);
21282
21312
  const [linkModalOpen, setLinkModalOpen] = useState35(false);
21283
21313
  const [linkUrl, setLinkUrl] = useState35("");
21284
21314
  const [linkText, setLinkText] = useState35("");
@@ -21384,17 +21414,22 @@ var RufousTextEditor = ({
21384
21414
  onImageUpload,
21385
21415
  onClose
21386
21416
  }
21387
- ), /* @__PURE__ */ React117.createElement(EditorContent, { editor, className: "editor-content-wrapper" }), /* @__PURE__ */ React117.createElement(ImageToolbar_default, { editor }), /* @__PURE__ */ React117.createElement(VideoToolbar_default, { editor }), /* @__PURE__ */ React117.createElement(SpellCheckTooltip, { editor }), /* @__PURE__ */ React117.createElement(
21417
+ ), /* @__PURE__ */ React117.createElement(EditorContent, { editor, className: "editor-content-wrapper" }), /* @__PURE__ */ React117.createElement(ImageToolbar_default, { editor }), /* @__PURE__ */ React117.createElement(VideoToolbar_default, { editor }), /* @__PURE__ */ React117.createElement(SpellCheckTooltip, { editor }), editor && /* @__PURE__ */ React117.createElement(
21388
21418
  BubbleMenu,
21389
21419
  {
21390
21420
  editor,
21391
21421
  className: "bubble-menu",
21392
21422
  shouldShow: ({ editor: e }) => {
21393
- const { selection } = e.state;
21394
- if (selection?.node?.type.name === "image") return false;
21395
- if (selection?.node?.type.name === "youtube") return false;
21396
- if (selection?.node?.type.name === "video") return false;
21397
- return !selection.empty;
21423
+ if (!e || e.isDestroyed) return false;
21424
+ try {
21425
+ const { selection } = e.state;
21426
+ if (selection?.node?.type.name === "image") return false;
21427
+ if (selection?.node?.type.name === "youtube") return false;
21428
+ if (selection?.node?.type.name === "video") return false;
21429
+ return !selection.empty;
21430
+ } catch {
21431
+ return false;
21432
+ }
21398
21433
  }
21399
21434
  },
21400
21435
  /* @__PURE__ */ React117.createElement(
@@ -21437,42 +21472,62 @@ var RufousTextEditor = ({
21437
21472
  },
21438
21473
  "\u{1F517}"
21439
21474
  )
21440
- ), /* @__PURE__ */ React117.createElement(FloatingMenu, { editor, className: "floating-menu" }, /* @__PURE__ */ React117.createElement(
21441
- "button",
21442
- {
21443
- onClick: () => editor?.chain().focus().toggleHeading({ level: 1 }).run(),
21444
- className: editor?.isActive("heading", { level: 1 }) ? "is-active" : ""
21445
- },
21446
- "H1"
21447
- ), /* @__PURE__ */ React117.createElement(
21448
- "button",
21449
- {
21450
- onClick: () => editor?.chain().focus().toggleHeading({ level: 2 }).run(),
21451
- className: editor?.isActive("heading", { level: 2 }) ? "is-active" : ""
21452
- },
21453
- "H2"
21454
- ), /* @__PURE__ */ React117.createElement(
21455
- "button",
21456
- {
21457
- onClick: () => editor?.chain().focus().toggleBulletList().run(),
21458
- className: editor?.isActive("bulletList") ? "is-active" : ""
21459
- },
21460
- "\u2022 List"
21461
- ), /* @__PURE__ */ React117.createElement(
21462
- "button",
21475
+ ), editor && /* @__PURE__ */ React117.createElement(
21476
+ FloatingMenu,
21463
21477
  {
21464
- onClick: () => editor?.chain().focus().toggleOrderedList().run(),
21465
- className: editor?.isActive("orderedList") ? "is-active" : ""
21466
- },
21467
- "1. List"
21468
- ), /* @__PURE__ */ React117.createElement(
21469
- "button",
21470
- {
21471
- onClick: () => editor?.chain().focus().toggleBlockquote().run(),
21472
- className: editor?.isActive("blockquote") ? "is-active" : ""
21478
+ editor,
21479
+ className: "floating-menu",
21480
+ shouldShow: ({ editor: e }) => {
21481
+ if (!e || e.isDestroyed) return false;
21482
+ try {
21483
+ const { selection } = e.state;
21484
+ return selection.empty && e.state.doc.textContent.length === 0;
21485
+ } catch {
21486
+ return false;
21487
+ }
21488
+ }
21473
21489
  },
21474
- "\u201C Quote"
21475
- )), /* @__PURE__ */ React117.createElement("div", { className: "status-bar" }, /* @__PURE__ */ React117.createElement("div", { className: "status-bar-left" }, /* @__PURE__ */ React117.createElement(
21490
+ /* @__PURE__ */ React117.createElement(
21491
+ "button",
21492
+ {
21493
+ onClick: () => editor?.chain().focus().toggleHeading({ level: 1 }).run(),
21494
+ className: editor?.isActive("heading", { level: 1 }) ? "is-active" : ""
21495
+ },
21496
+ "H1"
21497
+ ),
21498
+ /* @__PURE__ */ React117.createElement(
21499
+ "button",
21500
+ {
21501
+ onClick: () => editor?.chain().focus().toggleHeading({ level: 2 }).run(),
21502
+ className: editor?.isActive("heading", { level: 2 }) ? "is-active" : ""
21503
+ },
21504
+ "H2"
21505
+ ),
21506
+ /* @__PURE__ */ React117.createElement(
21507
+ "button",
21508
+ {
21509
+ onClick: () => editor?.chain().focus().toggleBulletList().run(),
21510
+ className: editor?.isActive("bulletList") ? "is-active" : ""
21511
+ },
21512
+ "\u2022 List"
21513
+ ),
21514
+ /* @__PURE__ */ React117.createElement(
21515
+ "button",
21516
+ {
21517
+ onClick: () => editor?.chain().focus().toggleOrderedList().run(),
21518
+ className: editor?.isActive("orderedList") ? "is-active" : ""
21519
+ },
21520
+ "1. List"
21521
+ ),
21522
+ /* @__PURE__ */ React117.createElement(
21523
+ "button",
21524
+ {
21525
+ onClick: () => editor?.chain().focus().toggleBlockquote().run(),
21526
+ className: editor?.isActive("blockquote") ? "is-active" : ""
21527
+ },
21528
+ "\u201C Quote"
21529
+ )
21530
+ ), /* @__PURE__ */ React117.createElement("div", { className: "status-bar" }, /* @__PURE__ */ React117.createElement("div", { className: "status-bar-left" }, /* @__PURE__ */ React117.createElement(
21476
21531
  "select",
21477
21532
  {
21478
21533
  value: saveFormat,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rufous/ui",
3
3
  "private": false,
4
- "version": "0.1.91",
4
+ "version": "0.1.93",
5
5
  "type": "module",
6
6
  "description": "Experimental: A lightweight React UI component library (Beta)",
7
7
  "style": "./dist/main.css",