rte-builder 2.0.7 → 2.0.9

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/index.mjs CHANGED
@@ -1528,7 +1528,10 @@ var init_Indent = __esm({
1528
1528
  },
1529
1529
  addCommands() {
1530
1530
  return {
1531
- indent: () => ({ tr, state, dispatch }) => {
1531
+ indent: () => ({ tr, state, dispatch, editor }) => {
1532
+ if (editor.isActive("listItem")) {
1533
+ return editor.chain().sinkListItem("listItem").run();
1534
+ }
1532
1535
  const { selection } = state;
1533
1536
  const { from, to } = selection;
1534
1537
  let changed = false;
@@ -1548,7 +1551,10 @@ var init_Indent = __esm({
1548
1551
  });
1549
1552
  return changed;
1550
1553
  },
1551
- outdent: () => ({ tr, state, dispatch }) => {
1554
+ outdent: () => ({ tr, state, dispatch, editor }) => {
1555
+ if (editor.isActive("listItem")) {
1556
+ return editor.chain().liftListItem("listItem").run();
1557
+ }
1552
1558
  const { selection } = state;
1553
1559
  const { from, to } = selection;
1554
1560
  let changed = false;
@@ -1574,13 +1580,13 @@ var init_Indent = __esm({
1574
1580
  return {
1575
1581
  Tab: () => {
1576
1582
  if (this.editor.isActive("listItem")) {
1577
- return false;
1583
+ return this.editor.commands.sinkListItem("listItem");
1578
1584
  }
1579
1585
  return this.editor.commands.indent();
1580
1586
  },
1581
1587
  "Shift-Tab": () => {
1582
1588
  if (this.editor.isActive("listItem")) {
1583
- return false;
1589
+ return this.editor.commands.liftListItem("listItem");
1584
1590
  }
1585
1591
  return this.editor.commands.outdent();
1586
1592
  }
@@ -1590,6 +1596,149 @@ var init_Indent = __esm({
1590
1596
  }
1591
1597
  });
1592
1598
 
1599
+ // src/utils/formatHtml.ts
1600
+ function tokenize(html) {
1601
+ const tokens = [];
1602
+ const re = /<!--[\s\S]*?-->|<!DOCTYPE[^>]*>|<\/([a-zA-Z][a-zA-Z0-9]*)\s*>|<([a-zA-Z][a-zA-Z0-9]*)(\s[^>]*)?\s*\/?>|[^<]+/gi;
1603
+ let match;
1604
+ while ((match = re.exec(html)) !== null) {
1605
+ const raw = match[0];
1606
+ if (raw.startsWith("<!--")) {
1607
+ tokens.push({ type: "comment", raw });
1608
+ } else if (raw.startsWith("<!")) {
1609
+ tokens.push({ type: "doctype", raw });
1610
+ } else if (match[1]) {
1611
+ tokens.push({ type: "close", tag: match[1].toLowerCase(), raw });
1612
+ } else if (match[2]) {
1613
+ const tag = match[2].toLowerCase();
1614
+ const isVoid = VOID_ELEMENTS.has(tag) || raw.endsWith("/>");
1615
+ tokens.push({
1616
+ type: isVoid ? "self-close" : "open",
1617
+ tag,
1618
+ raw
1619
+ });
1620
+ } else {
1621
+ const text = raw;
1622
+ if (text.trim()) {
1623
+ tokens.push({ type: "text", raw: text });
1624
+ }
1625
+ }
1626
+ }
1627
+ return tokens;
1628
+ }
1629
+ function formatHtml(html, indentStr = " ") {
1630
+ if (!html || !html.trim()) return html;
1631
+ const tokens = tokenize(html.trim());
1632
+ const lines = [];
1633
+ let depth = 0;
1634
+ for (const token of tokens) {
1635
+ const indent = indentStr.repeat(depth);
1636
+ switch (token.type) {
1637
+ case "open": {
1638
+ const isBlock = BLOCK_ELEMENTS.has(token.tag);
1639
+ if (isBlock) {
1640
+ lines.push(`${indent}${token.raw}`);
1641
+ depth++;
1642
+ } else {
1643
+ lines.push(`${indent}${token.raw}`);
1644
+ depth++;
1645
+ }
1646
+ break;
1647
+ }
1648
+ case "close": {
1649
+ depth = Math.max(0, depth - 1);
1650
+ const closeIndent = indentStr.repeat(depth);
1651
+ lines.push(`${closeIndent}${token.raw}`);
1652
+ break;
1653
+ }
1654
+ case "self-close":
1655
+ case "comment":
1656
+ case "doctype":
1657
+ lines.push(`${indent}${token.raw}`);
1658
+ break;
1659
+ case "text":
1660
+ lines.push(`${indent}${token.raw.trim()}`);
1661
+ break;
1662
+ }
1663
+ }
1664
+ return collapseInlineTags(lines.join("\n"));
1665
+ }
1666
+ function collapseInlineTags(formatted) {
1667
+ return formatted.replace(
1668
+ /^(\s*)<((?!\/)[a-zA-Z][a-zA-Z0-9]*)([^>]*)>\n\s+([^<\n]+)\n\s*<\/\2>/gm,
1669
+ (match, indent, tag, attrs, text) => {
1670
+ if (BLOCK_ELEMENTS.has(tag.toLowerCase())) return match;
1671
+ return `${indent}<${tag}${attrs}>${text.trim()}</${tag}>`;
1672
+ }
1673
+ );
1674
+ }
1675
+ var VOID_ELEMENTS, BLOCK_ELEMENTS;
1676
+ var init_formatHtml = __esm({
1677
+ "src/utils/formatHtml.ts"() {
1678
+ "use strict";
1679
+ VOID_ELEMENTS = /* @__PURE__ */ new Set([
1680
+ "area",
1681
+ "base",
1682
+ "br",
1683
+ "col",
1684
+ "embed",
1685
+ "hr",
1686
+ "img",
1687
+ "input",
1688
+ "link",
1689
+ "meta",
1690
+ "param",
1691
+ "source",
1692
+ "track",
1693
+ "wbr"
1694
+ ]);
1695
+ BLOCK_ELEMENTS = /* @__PURE__ */ new Set([
1696
+ "address",
1697
+ "article",
1698
+ "aside",
1699
+ "blockquote",
1700
+ "body",
1701
+ "details",
1702
+ "dialog",
1703
+ "dd",
1704
+ "div",
1705
+ "dl",
1706
+ "dt",
1707
+ "fieldset",
1708
+ "figcaption",
1709
+ "figure",
1710
+ "footer",
1711
+ "form",
1712
+ "h1",
1713
+ "h2",
1714
+ "h3",
1715
+ "h4",
1716
+ "h5",
1717
+ "h6",
1718
+ "head",
1719
+ "header",
1720
+ "hgroup",
1721
+ "hr",
1722
+ "html",
1723
+ "li",
1724
+ "main",
1725
+ "nav",
1726
+ "ol",
1727
+ "p",
1728
+ "pre",
1729
+ "section",
1730
+ "table",
1731
+ "tbody",
1732
+ "td",
1733
+ "tfoot",
1734
+ "th",
1735
+ "thead",
1736
+ "tr",
1737
+ "ul"
1738
+ ]);
1739
+ }
1740
+ });
1741
+
1593
1742
  // src/adapters/tiptap/TipTapToolbar.tsx
1594
1743
  import { useState, useRef, useEffect } from "react";
1595
1744
  import { CodeXml } from "lucide-react";
@@ -1599,6 +1748,7 @@ var init_TipTapToolbar = __esm({
1599
1748
  "src/adapters/tiptap/TipTapToolbar.tsx"() {
1600
1749
  "use strict";
1601
1750
  init_Emoji();
1751
+ init_formatHtml();
1602
1752
  FONT_FAMILIES = [
1603
1753
  { value: "Arial", label: "Arial" },
1604
1754
  { value: "Georgia", label: "Georgia" },
@@ -1803,12 +1953,13 @@ var init_TipTapToolbar = __esm({
1803
1953
  } else {
1804
1954
  const currentHTML = editor.getHTML();
1805
1955
  const isEmptyContent = !currentHTML || currentHTML === "<p></p>" || currentHTML.trim() === "";
1956
+ const formattedHTML = isEmptyContent ? "" : formatHtml(currentHTML);
1806
1957
  const codeBlockContent = isEmptyContent ? { type: "doc", content: [{ type: "codeBlock" }] } : {
1807
1958
  type: "doc",
1808
1959
  content: [
1809
1960
  {
1810
1961
  type: "codeBlock",
1811
- content: [{ type: "text", text: currentHTML }]
1962
+ content: [{ type: "text", text: formattedHTML }]
1812
1963
  }
1813
1964
  ]
1814
1965
  };
@@ -6020,6 +6171,7 @@ import { common as common2, createLowlight as createLowlight2 } from "lowlight";
6020
6171
 
6021
6172
  // src/components/Toolbar.tsx
6022
6173
  init_Emoji();
6174
+ init_formatHtml();
6023
6175
  import { useState as useState7, useRef as useRef7, useEffect as useEffect7 } from "react";
6024
6176
  import {
6025
6177
  Bold as Bold2,
@@ -6245,12 +6397,15 @@ var Toolbar = ({
6245
6397
  } else {
6246
6398
  const currentHTML = editor.getHTML();
6247
6399
  const isEmptyContent = !currentHTML || currentHTML === "<p></p>" || currentHTML.trim() === "";
6400
+ const formattedHTML = isEmptyContent ? "" : formatHtml(currentHTML);
6248
6401
  const codeBlockContent = isEmptyContent ? { type: "doc", content: [{ type: "codeBlock" }] } : {
6249
6402
  type: "doc",
6250
6403
  content: [
6251
6404
  {
6252
6405
  type: "codeBlock",
6253
- content: [{ type: "text", text: currentHTML }]
6406
+ content: [
6407
+ { type: "text", text: formattedHTML }
6408
+ ]
6254
6409
  }
6255
6410
  ]
6256
6411
  };