@domternal/core 0.9.1 → 0.11.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/README.md CHANGED
@@ -21,14 +21,14 @@ See <u>[Packages & Bundle Size](https://domternal.dev/v1/packages)</u> for a ful
21
21
  - **Vue components** - composable `Domternal` component, `useEditor`/`useEditorState` composables, toolbar, bubble menu, floating menu, emoji picker, notion color picker, custom node views (Vue 3.3+)
22
22
  - **Vanilla wrapper** - framework-free class-based API for Astro, Svelte, Solid, plain HTML, and Web Components - editor, toolbar, bubble menu, floating menu, emoji picker, notion color picker
23
23
  - **Notion-style block UX** - drag-to-reorder, block context menu, slash command, smart paste, keyboard reorder, floating Table of Contents
24
- - **65+ extensions across 15 packages** - nodes, marks, and behavior extensions
25
- - **120+ chainable commands** - `editor.chain().focus().toggleBold().run()`
24
+ - **70+ extensions across 16 packages** - nodes, marks, and behavior extensions
25
+ - **125+ chainable commands** - `editor.chain().focus().toggleBold().run()`
26
26
  - **Full table support** - cell merging, column resize, row/column controls, cell toolbar, all free and MIT licensed
27
27
  - **Tree-shakeable** - import only what you use, your bundler strips the rest
28
28
  - **~44 KB gzipped** (own code), <u>[see Packages](https://domternal.dev/v1/packages)</u> for full bundle breakdown with ProseMirror
29
29
  - **TypeScript first** - 100% typed, zero `any`
30
30
  - **15,000+ tests** - 4,000+ unit and 11,000+ E2E across 230+ Playwright specs and 4 demo apps
31
- - **Light and dark theme** - 70+ CSS custom properties for full visual control
31
+ - **Light and dark theme** - 120+ CSS custom properties for full visual control
32
32
  - **Inline styles export** - `getHTML({ styled: true })` produces inline CSS ready for email clients, CMS, and Google Docs
33
33
  - **SSR helpers** - `generateHTML`, `generateJSON`, `generateText` for server-side rendering
34
34
 
package/dist/index.cjs CHANGED
@@ -201,6 +201,7 @@ function inputRulesPlugin({ rules }) {
201
201
  handleDOMEvents: {
202
202
  compositionend: (view) => {
203
203
  setTimeout(() => {
204
+ if (view.isDestroyed) return;
204
205
  const { $cursor } = view.state.selection;
205
206
  if ($cursor) {
206
207
  run(view, $cursor.pos, $cursor.pos, "", rules, plugin);
@@ -1421,26 +1422,31 @@ var insertContent = (content) => ({ state, tr, dispatch }) => {
1421
1422
  const { schema } = state;
1422
1423
  const { from, to } = tr.selection;
1423
1424
  let fragment;
1424
- if (typeof content === "string") {
1425
- if (typeof window === "undefined") {
1426
- return false;
1427
- }
1428
- const parser = model.DOMParser.fromSchema(schema);
1429
- const wrapper = document.createElement("div");
1430
- wrapper.innerHTML = content;
1431
- const parsed = parser.parse(wrapper);
1432
- fragment = parsed.content;
1433
- } else if (content && typeof content === "object") {
1434
- if (Array.isArray(content)) {
1435
- const nodes = content.map((item) => schema.nodeFromJSON(item));
1436
- fragment = model.Fragment.from(nodes);
1437
- } else if ("type" in content) {
1438
- const node = schema.nodeFromJSON(content);
1439
- fragment = node.type.name === "doc" ? node.content : model.Fragment.from(node);
1425
+ try {
1426
+ if (typeof content === "string") {
1427
+ if (typeof window === "undefined") {
1428
+ return false;
1429
+ }
1430
+ const parser = model.DOMParser.fromSchema(schema);
1431
+ const wrapper = document.createElement("div");
1432
+ wrapper.innerHTML = content;
1433
+ const parsed = parser.parse(wrapper);
1434
+ fragment = parsed.content;
1435
+ } else if (content && typeof content === "object") {
1436
+ if (Array.isArray(content)) {
1437
+ if (content.length === 0) return false;
1438
+ const nodes = content.map((item) => schema.nodeFromJSON(item));
1439
+ fragment = model.Fragment.from(nodes);
1440
+ } else if ("type" in content) {
1441
+ const node = schema.nodeFromJSON(content);
1442
+ fragment = node.type.name === "doc" ? node.content : model.Fragment.from(node);
1443
+ } else {
1444
+ return false;
1445
+ }
1440
1446
  } else {
1441
1447
  return false;
1442
1448
  }
1443
- } else {
1449
+ } catch {
1444
1450
  return false;
1445
1451
  }
1446
1452
  if (!dispatch) {
@@ -4134,6 +4140,21 @@ function copyThemeClass(view, target) {
4134
4140
  });
4135
4141
  }
4136
4142
 
4143
+ // src/utils/refocusEditorAfterCommand.ts
4144
+ function refocusEditorAfterCommand(view) {
4145
+ requestAnimationFrame(() => {
4146
+ const ae = document.activeElement;
4147
+ if (!ae) {
4148
+ view.focus();
4149
+ return;
4150
+ }
4151
+ if (ae.closest("[data-dm-editor-ui]") && !ae.closest(".dm-toolbar") && !ae.closest(".dm-bubble-menu") && !ae.closest(".dm-floating-menu") && !view.dom.contains(ae)) {
4152
+ return;
4153
+ }
4154
+ view.focus();
4155
+ });
4156
+ }
4157
+
4137
4158
  // src/utils/defaultBubbleContexts.ts
4138
4159
  var NOTION_MODE_CLASS = "dm-notion-mode";
4139
4160
  var NOTION_TEXT_CONTEXT = Object.freeze([
@@ -4142,6 +4163,7 @@ var NOTION_TEXT_CONTEXT = Object.freeze([
4142
4163
  "underline",
4143
4164
  "strike",
4144
4165
  "code",
4166
+ "mathInline",
4145
4167
  "|",
4146
4168
  "link",
4147
4169
  "|",
@@ -4153,6 +4175,7 @@ var STANDARD_TEXT_CONTEXT = Object.freeze([
4153
4175
  "underline",
4154
4176
  "strike",
4155
4177
  "code",
4178
+ "mathInline",
4156
4179
  "|",
4157
4180
  "link"
4158
4181
  ]);
@@ -5389,6 +5412,9 @@ var defaultIcons = {
5389
5412
  highlighterCircle: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M201.54,54.46A104,104,0,0,0,54.46,201.54,104,104,0,0,0,201.54,54.46ZM96,210V152h64v58a88.33,88.33,0,0,1-64,0Zm48-74H112V100.94l32-16Zm46.22,54.22A88.09,88.09,0,0,1,176,201.77V152a16,16,0,0,0-16-16V72a8,8,0,0,0-11.58-7.16l-48,24A8,8,0,0,0,96,96v40a16,16,0,0,0-16,16v49.77a88,88,0,1,1,110.22-11.55Z"/></svg>',
5390
5413
  textSubscript: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M248,208a8,8,0,0,1-8,8H192a8,8,0,0,1-6.4-12.8l43.17-57.56a16,16,0,1,0-27.86-15,8,8,0,0,1-15.09-5.34,32.18,32.18,0,0,1,4.63-8.59,32,32,0,0,1,51.11,38.52L208,200h32A8,8,0,0,1,248,208ZM149.24,50a8,8,0,0,0-11.29.81L92,103.78l-45.95-53A8,8,0,0,0,34,61.24L81.41,116,34,170.76a8,8,0,0,0,12.1,10.48l46-53,45.95,53a8,8,0,1,0,12.1-10.48L102.59,116l47.46-54.76A8,8,0,0,0,149.24,50Z"/></svg>',
5391
5414
  textSuperscript: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M248,144a8,8,0,0,1-8,8H192a8,8,0,0,1-6.4-12.8l43.17-57.55a16,16,0,1,0-27.86-15,8,8,0,0,1-15.09-5.33,32,32,0,1,1,55.74,29.92L208,136h32A8,8,0,0,1,248,144ZM149.24,74a8,8,0,0,0-11.29.8L92,127.79l-45.95-53A8,8,0,0,0,34,85.24L81.41,140,34,194.76a8,8,0,0,0,12.1,10.48l46-53,45.95,53a8,8,0,1,0,12.1-10.48L102.59,140l47.46-54.76A8,8,0,0,0,149.24,74Z"/></svg>',
5415
+ // --- Math ---
5416
+ sigma: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="none" stroke="currentColor" stroke-width="18" stroke-linecap="round" stroke-linejoin="round"><path d="M196 56H64l64 72-64 72h132"/></svg>',
5417
+ radical: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="none" stroke="currentColor" stroke-width="18" stroke-linecap="round" stroke-linejoin="round"><path d="M24 150 L66 200 L118 56 L236 56 M150 98 L204 156 M204 98 L150 156"/></svg>',
5392
5418
  link: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M240,88.23a54.43,54.43,0,0,1-16,37L189.25,160a54.27,54.27,0,0,1-38.63,16h-.05A54.63,54.63,0,0,1,96,119.84a8,8,0,0,1,16,.45A38.62,38.62,0,0,0,150.58,160h0a38.39,38.39,0,0,0,27.31-11.31l34.75-34.75a38.63,38.63,0,0,0-54.63-54.63l-11,11A8,8,0,0,1,135.7,59l11-11A54.65,54.65,0,0,1,224,48,54.86,54.86,0,0,1,240,88.23ZM109,185.66l-11,11A38.41,38.41,0,0,1,70.6,208h0a38.63,38.63,0,0,1-27.29-65.94L78,107.31A38.63,38.63,0,0,1,144,135.71a8,8,0,0,0,16,.45A54.86,54.86,0,0,0,144,96a54.65,54.65,0,0,0-77.27,0L32,130.75A54.62,54.62,0,0,0,70.56,224h0a54.28,54.28,0,0,0,38.64-16l11-11A8,8,0,0,0,109,185.66Z"/></svg>',
5393
5419
  // --- Format: Block ---
5394
5420
  paragraph: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M208,40H96a64,64,0,0,0,0,128h40v40a8,8,0,0,0,16,0V56h24V208a8,8,0,0,0,16,0V56h16a8,8,0,0,0,0-16ZM136,152H96a48,48,0,0,1,0-96h40Z"/></svg>',
@@ -5525,7 +5551,7 @@ var Heading = Node2.create({
5525
5551
  },
5526
5552
  renderHTML({ node, HTMLAttributes }) {
5527
5553
  const level = node.attrs["level"];
5528
- const validLevel = this.options.levels.includes(level) ? level : this.options.levels[0];
5554
+ const validLevel = this.options.levels.includes(level) ? level : this.options.levels[0] ?? 1;
5529
5555
  return [`h${String(validLevel)}`, { ...this.options.HTMLAttributes, ...HTMLAttributes }, 0];
5530
5556
  },
5531
5557
  addCommands() {
@@ -9409,7 +9435,7 @@ var TextColor = Extension.create({
9409
9435
  return commands.setMark("textStyle", { color, colorToken: null });
9410
9436
  },
9411
9437
  unsetTextColor: () => ({ commands }) => {
9412
- if (!commands.setMark("textStyle", { color: null })) return false;
9438
+ if (!commands.setMark("textStyle", { color: null, colorToken: null })) return false;
9413
9439
  commands.removeEmptyTextStyle();
9414
9440
  return true;
9415
9441
  },
@@ -9554,7 +9580,7 @@ var Highlight = Extension.create({
9554
9580
  return commands.setMark("textStyle", { backgroundColor: color, backgroundColorToken: null });
9555
9581
  },
9556
9582
  unsetHighlight: () => ({ commands }) => {
9557
- if (!commands.setMark("textStyle", { backgroundColor: null })) return false;
9583
+ if (!commands.setMark("textStyle", { backgroundColor: null, backgroundColorToken: null })) return false;
9558
9584
  commands.removeEmptyTextStyle();
9559
9585
  return true;
9560
9586
  },
@@ -10622,6 +10648,7 @@ exports.outdentBlockFromListItem = outdentBlockFromListItem;
10622
10648
  exports.placeholderPluginKey = placeholderPluginKey;
10623
10649
  exports.positionFloating = positionFloating;
10624
10650
  exports.positionFloatingOnce = positionFloatingOnce;
10651
+ exports.refocusEditorAfterCommand = refocusEditorAfterCommand;
10625
10652
  exports.resetAttributes = resetAttributes;
10626
10653
  exports.selectAll = selectAll;
10627
10654
  exports.selectNodeBackward = selectNodeBackward;