@dotvoid/textbit-plugins 0.0.0-stage → 0.1.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 (91) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +181 -2
  3. package/dist/Audio/audioNode.cjs +1 -0
  4. package/dist/Audio/audioNode.d.ts +8 -0
  5. package/dist/Audio/audioNode.d.ts.map +1 -0
  6. package/dist/Audio/audioNode.js +15 -0
  7. package/dist/Audio/index.cjs +1 -0
  8. package/dist/Audio/index.d.ts +22 -0
  9. package/dist/Audio/index.d.ts.map +1 -0
  10. package/dist/Audio/index.js +63 -0
  11. package/dist/Blockquote/index.cjs +1 -0
  12. package/dist/Blockquote/index.d.ts +15 -0
  13. package/dist/Blockquote/index.d.ts.map +1 -0
  14. package/dist/Blockquote/index.js +56 -0
  15. package/dist/CodeBlock/index.cjs +1 -0
  16. package/dist/CodeBlock/index.d.ts +14 -0
  17. package/dist/CodeBlock/index.d.ts.map +1 -0
  18. package/dist/CodeBlock/index.js +65 -0
  19. package/dist/Image/imageNode.cjs +1 -0
  20. package/dist/Image/imageNode.d.ts +11 -0
  21. package/dist/Image/imageNode.d.ts.map +1 -0
  22. package/dist/Image/imageNode.js +16 -0
  23. package/dist/Image/index.cjs +1 -0
  24. package/dist/Image/index.d.ts +36 -0
  25. package/dist/Image/index.d.ts.map +1 -0
  26. package/dist/Image/index.js +92 -0
  27. package/dist/Leafs/index.cjs +1 -0
  28. package/dist/Leafs/index.d.ts +13 -0
  29. package/dist/Leafs/index.d.ts.map +1 -0
  30. package/dist/Leafs/index.js +66 -0
  31. package/dist/Link/index.cjs +1 -0
  32. package/dist/Link/index.d.ts +25 -0
  33. package/dist/Link/index.d.ts.map +1 -0
  34. package/dist/Link/index.js +148 -0
  35. package/dist/Link/isValidLink.cjs +1 -0
  36. package/dist/Link/isValidLink.d.ts +3 -0
  37. package/dist/Link/isValidLink.d.ts.map +1 -0
  38. package/dist/Link/isValidLink.js +35 -0
  39. package/dist/List/index.cjs +1 -0
  40. package/dist/List/index.d.ts +17 -0
  41. package/dist/List/index.d.ts.map +1 -0
  42. package/dist/List/index.js +151 -0
  43. package/dist/LocalizedQuotationMarks/consume.cjs +1 -0
  44. package/dist/LocalizedQuotationMarks/consume.d.ts +3 -0
  45. package/dist/LocalizedQuotationMarks/consume.d.ts.map +1 -0
  46. package/dist/LocalizedQuotationMarks/consume.js +115 -0
  47. package/dist/LocalizedQuotationMarks/consumes.cjs +1 -0
  48. package/dist/LocalizedQuotationMarks/consumes.d.ts +3 -0
  49. package/dist/LocalizedQuotationMarks/consumes.d.ts.map +1 -0
  50. package/dist/LocalizedQuotationMarks/consumes.js +7 -0
  51. package/dist/LocalizedQuotationMarks/index.cjs +1 -0
  52. package/dist/LocalizedQuotationMarks/index.d.ts +9 -0
  53. package/dist/LocalizedQuotationMarks/index.d.ts.map +1 -0
  54. package/dist/LocalizedQuotationMarks/index.js +13 -0
  55. package/dist/Table/index.cjs +1 -0
  56. package/dist/Table/index.d.ts +16 -0
  57. package/dist/Table/index.d.ts.map +1 -0
  58. package/dist/Table/index.js +179 -0
  59. package/dist/Text/index.cjs +1 -0
  60. package/dist/Text/index.d.ts +25 -0
  61. package/dist/Text/index.d.ts.map +1 -0
  62. package/dist/Text/index.js +64 -0
  63. package/dist/index.cjs +1 -0
  64. package/dist/index.d.ts +13 -0
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +31 -0
  67. package/dist/shared/ChildPlaceholder.cjs +1 -0
  68. package/dist/shared/ChildPlaceholder.d.ts +12 -0
  69. package/dist/shared/ChildPlaceholder.d.ts.map +1 -0
  70. package/dist/shared/ChildPlaceholder.js +17 -0
  71. package/dist/shared/Field.cjs +1 -0
  72. package/dist/shared/Field.d.ts +14 -0
  73. package/dist/shared/Field.d.ts.map +1 -0
  74. package/dist/shared/Field.js +28 -0
  75. package/dist/shared/hotkey.cjs +1 -0
  76. package/dist/shared/hotkey.d.ts +3 -0
  77. package/dist/shared/hotkey.d.ts.map +1 -0
  78. package/dist/shared/hotkey.js +6 -0
  79. package/dist/shared/icons.cjs +1 -0
  80. package/dist/shared/icons.d.ts +62 -0
  81. package/dist/shared/icons.d.ts.map +1 -0
  82. package/dist/shared/icons.js +153 -0
  83. package/dist/shared/insertBlock.cjs +1 -0
  84. package/dist/shared/insertBlock.d.ts +5 -0
  85. package/dist/shared/insertBlock.d.ts.map +1 -0
  86. package/dist/shared/insertBlock.js +13 -0
  87. package/dist/shared/media.cjs +1 -0
  88. package/dist/shared/media.d.ts +25 -0
  89. package/dist/shared/media.d.ts.map +1 -0
  90. package/dist/shared/media.js +43 -0
  91. package/package.json +67 -4
@@ -0,0 +1,92 @@
1
+ import { jsx as n, jsxs as b, Fragment as u } from "react/jsx-runtime";
2
+ import { Node as l, Element as g } from "slate";
3
+ import { useSlateStatic as x, ReactEditor as d, useSlateSelector as y } from "slate-react";
4
+ import { ImageIcon as E } from "../shared/icons.js";
5
+ import { FieldContent as p } from "../shared/Field.js";
6
+ import { uploadConsumer as v, pickFiles as w, safeMediaSrc as S } from "../shared/media.js";
7
+ import { imageNode as N } from "./imageNode.js";
8
+ const m = "base/image", k = ["image/jpeg", "image/png", "image/gif", "image/webp", "image/avif"], C = {
9
+ title: "Image",
10
+ caption: "Caption",
11
+ captionHint: "Add a caption",
12
+ alt: "Alt text",
13
+ altHint: "Describe the image for those who cannot see it",
14
+ missing: "Image not available"
15
+ }, L = (e = {}) => {
16
+ const i = { ...C, ...e.labels }, s = e.accept ?? k, a = v({
17
+ type: m,
18
+ accept: (t) => s.includes(t),
19
+ maxSize: e.maxSize,
20
+ upload: e.upload,
21
+ build: (t) => N(t)
22
+ });
23
+ return {
24
+ class: "block",
25
+ name: m,
26
+ ...a ? { consumer: a } : {},
27
+ actions: [{
28
+ name: "insert",
29
+ title: i.title,
30
+ tool: () => /* @__PURE__ */ n(E, {}),
31
+ // Only offered when there is somewhere to store the file
32
+ visibility: () => [!!a, !!a, !1],
33
+ handler: (t) => w(t, s.join(","))
34
+ }],
35
+ componentEntry: {
36
+ class: "block",
37
+ component: ({ children: t }) => /* @__PURE__ */ n("figure", { className: "tb-image", children: t }),
38
+ children: [
39
+ {
40
+ type: "content",
41
+ class: "void",
42
+ component: (t) => /* @__PURE__ */ n(I, { ...t, labels: i }),
43
+ constraints: { min: 1, max: 1 }
44
+ },
45
+ {
46
+ // A text field, not an <input>: the caret moves in and out of it like
47
+ // any other text. It sits before the caption, which must be the
48
+ // figure's first or last child.
49
+ type: "alt",
50
+ class: "text",
51
+ component: ({ children: t, element: c }) => /* @__PURE__ */ n("div", { className: "tb-field tb-image-alt", children: /* @__PURE__ */ n(p, { element: c, label: i.alt, hint: i.altHint, children: t }) }),
52
+ constraints: { allowBreak: !1, min: 1, max: 1 }
53
+ },
54
+ {
55
+ type: "caption",
56
+ class: "text",
57
+ // A figcaption must sit directly in its figure, without a wrapping <div>
58
+ asOwnElement: !0,
59
+ component: ({ children: t, element: c, attributes: o }) => /* @__PURE__ */ n("figcaption", { ...o, className: "tb-field tb-image-caption", children: /* @__PURE__ */ n(p, { element: c, label: i.caption, hint: i.captionHint, children: t }) }),
60
+ constraints: { allowBreak: !1, min: 1, max: 1 }
61
+ }
62
+ ]
63
+ }
64
+ };
65
+ };
66
+ function I({ element: e, children: i, labels: s }) {
67
+ const a = x(), t = d.findPath(a, e), c = l.get(a, t.slice(0, -1)), o = g.isElement(c) ? c.properties ?? {} : {}, r = S(o.src), f = y((h) => j(h, e));
68
+ return /* @__PURE__ */ b(u, { children: [
69
+ /* @__PURE__ */ n("div", { className: "tb-image-content", contentEditable: !1, draggable: "true", children: r ? /* @__PURE__ */ n(
70
+ "img",
71
+ {
72
+ src: r,
73
+ alt: f,
74
+ width: typeof o.width == "number" ? o.width : void 0,
75
+ height: typeof o.height == "number" ? o.height : void 0,
76
+ style: { display: "block", maxWidth: "100%", height: "auto" }
77
+ }
78
+ ) : /* @__PURE__ */ n("div", { className: "tb-image-missing", role: "img", "aria-label": s.missing, children: s.missing }) }),
79
+ i
80
+ ] });
81
+ }
82
+ function j(e, i) {
83
+ try {
84
+ const a = l.parent(e, d.findPath(e, i)).children.find((t) => g.isElement(t) && t.type === `${m}/alt`);
85
+ return a ? l.string(a) : "";
86
+ } catch {
87
+ return "";
88
+ }
89
+ }
90
+ export {
91
+ L as Image
92
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("react/jsx-runtime"),o=require("../shared/icons.cjs"),i=require("../shared/hotkey.cjs"),l=(e,n)=>i.hotkeyOption(e?.hotkey,n),a=e=>({class:"leaf",name:"base/bold",actions:[{name:"toggle-bold",title:e?.title??"Bold",tool:()=>t.jsx(o.BoldIcon,{}),hotkey:l(e,"mod+b"),handler:()=>!0}],getStyle:()=>({fontWeight:"bold"})}),r=e=>({class:"leaf",name:"base/italic",actions:[{name:"toggle-italic",title:e?.title??"Italic",tool:()=>t.jsx(o.ItalicIcon,{}),hotkey:l(e,"mod+i"),handler:()=>!0}],getStyle:()=>({fontStyle:"italic"})}),c=e=>({class:"leaf",name:"base/underline",actions:[{name:"toggle-underline",title:e?.title??"Underline",tool:()=>t.jsx(o.UnderlineIcon,{}),hotkey:l(e,"mod+u"),handler:()=>!0}],getStyle:()=>({textDecoration:"underline"})}),s=e=>({class:"leaf",name:"base/strikethrough",actions:[{name:"toggle-strikethrough",title:e?.title??"Strikethrough",tool:()=>t.jsx(o.StrikethroughIcon,{}),hotkey:l(e),handler:()=>!0}],getStyle:()=>({textDecoration:"line-through"})}),d=e=>({class:"leaf",name:"base/code",actions:[{name:"toggle-code",title:e?.title??"Code",tool:()=>t.jsx(o.CodeIcon,{}),hotkey:l(e),handler:()=>!0}],getStyle:()=>"tb-code"});exports.Bold=a;exports.Code=d;exports.Italic=r;exports.Strikethrough=s;exports.Underline=c;
@@ -0,0 +1,13 @@
1
+ import { TBPluginDefinition } from '@dotvoid/textbit';
2
+ export type LeafOptions = {
3
+ /** Replace the default shortcut, or remove it with `false` */
4
+ hotkey?: string | false;
5
+ /** The action's name in menus and for screen readers, e.g. a translation */
6
+ title?: string;
7
+ };
8
+ export declare const Bold: (options?: LeafOptions) => TBPluginDefinition;
9
+ export declare const Italic: (options?: LeafOptions) => TBPluginDefinition;
10
+ export declare const Underline: (options?: LeafOptions) => TBPluginDefinition;
11
+ export declare const Strikethrough: (options?: LeafOptions) => TBPluginDefinition;
12
+ export declare const Code: (options?: LeafOptions) => TBPluginDefinition;
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/Leafs/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAI1D,MAAM,MAAM,WAAW,GAAG;IACxB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IACvB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAQD,eAAO,MAAM,IAAI,GAAI,UAAU,WAAW,KAAG,kBAW3C,CAAA;AAEF,eAAO,MAAM,MAAM,GAAI,UAAU,WAAW,KAAG,kBAW7C,CAAA;AAEF,eAAO,MAAM,SAAS,GAAI,UAAU,WAAW,KAAG,kBAWhD,CAAA;AAEF,eAAO,MAAM,aAAa,GAAI,UAAU,WAAW,KAAG,kBAWpD,CAAA;AAEF,eAAO,MAAM,IAAI,GAAI,UAAU,WAAW,KAAG,kBAW3C,CAAA"}
@@ -0,0 +1,66 @@
1
+ import { jsx as t } from "react/jsx-runtime";
2
+ import { BoldIcon as n, ItalicIcon as a, UnderlineIcon as i, StrikethroughIcon as r, CodeIcon as c } from "../shared/icons.js";
3
+ import { hotkeyOption as d } from "../shared/hotkey.js";
4
+ const o = (e, l) => d(e?.hotkey, l), m = (e) => ({
5
+ class: "leaf",
6
+ name: "base/bold",
7
+ actions: [{
8
+ name: "toggle-bold",
9
+ title: e?.title ?? "Bold",
10
+ tool: () => /* @__PURE__ */ t(n, {}),
11
+ hotkey: o(e, "mod+b"),
12
+ handler: () => !0
13
+ }],
14
+ getStyle: () => ({ fontWeight: "bold" })
15
+ }), u = (e) => ({
16
+ class: "leaf",
17
+ name: "base/italic",
18
+ actions: [{
19
+ name: "toggle-italic",
20
+ title: e?.title ?? "Italic",
21
+ tool: () => /* @__PURE__ */ t(a, {}),
22
+ hotkey: o(e, "mod+i"),
23
+ handler: () => !0
24
+ }],
25
+ getStyle: () => ({ fontStyle: "italic" })
26
+ }), y = (e) => ({
27
+ class: "leaf",
28
+ name: "base/underline",
29
+ actions: [{
30
+ name: "toggle-underline",
31
+ title: e?.title ?? "Underline",
32
+ tool: () => /* @__PURE__ */ t(i, {}),
33
+ hotkey: o(e, "mod+u"),
34
+ handler: () => !0
35
+ }],
36
+ getStyle: () => ({ textDecoration: "underline" })
37
+ }), k = (e) => ({
38
+ class: "leaf",
39
+ name: "base/strikethrough",
40
+ actions: [{
41
+ name: "toggle-strikethrough",
42
+ title: e?.title ?? "Strikethrough",
43
+ tool: () => /* @__PURE__ */ t(r, {}),
44
+ hotkey: o(e),
45
+ handler: () => !0
46
+ }],
47
+ getStyle: () => ({ textDecoration: "line-through" })
48
+ }), b = (e) => ({
49
+ class: "leaf",
50
+ name: "base/code",
51
+ actions: [{
52
+ name: "toggle-code",
53
+ title: e?.title ?? "Code",
54
+ tool: () => /* @__PURE__ */ t(c, {}),
55
+ hotkey: o(e),
56
+ handler: () => !0
57
+ }],
58
+ getStyle: () => "tb-code"
59
+ });
60
+ export {
61
+ m as Bold,
62
+ b as Code,
63
+ u as Italic,
64
+ k as Strikethrough,
65
+ y as Underline
66
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("react/jsx-runtime"),k=require("react"),p=require("@dotvoid/textbit"),s=require("slate"),h=require("slate-react"),d=require("../shared/icons.cjs"),x=require("../shared/hotkey.cjs"),c=require("./isValidLink.cjs"),f="base/link",v={title:"Link",address:"Link address",placeholder:"https://",remove:"Remove link",open:"Open link in a new tab"},j=(t={})=>{const e={...v,...t.labels};return{class:"inline",name:f,componentEntry:{class:"inline",component:T},actions:[{name:"edit",title:e.title,tool:[()=>l.jsx(d.LinkIcon,{}),n=>l.jsx(D,{...n,labels:e})],hotkey:x.hotkeyOption(t.hotkey,"mod+k"),handler:w,visibility:n=>[!0,!0,n.type===f]}]}};function T({children:t,element:e}){const n=c.sanitizeLink(typeof e.properties?.href=="string"?e.properties.href:""),i=c.isValidLink(n);return l.jsx("a",{href:i?n:void 0,className:"tb-link",...i?{}:{"data-invalid":""},onClick:a=>{i&&(a.ctrlKey||a.metaKey)&&(a.preventDefault(),window.open(n,"_blank","noopener,noreferrer"))},children:t})}function D({entry:t,labels:e}){const n=h.useSlateStatic(),[i,a]=t||[],u=p.TextbitElement.isElement(i)&&typeof i.properties?.href=="string"?i.properties.href:"",[o,y]=k.useState(u),[b,g]=k.useState(!1);if(!p.TextbitElement.isElement(i)||!a)return null;const L=()=>{const r=c.sanitizeLink(o);r===""?E(n):s.Transforms.setNodes(n,{properties:{...i.properties,href:r}},{at:a})};return l.jsxs("div",{className:"tb-link-editor",role:"group","aria-label":e.title,children:[l.jsx("button",{type:"button",className:"tb-link-remove","aria-label":e.remove,title:e.remove,onMouseDown:r=>{r.preventDefault(),E(n)},children:l.jsx(d.LinkOffIcon,{})}),l.jsx("input",{id:i.id?m(i.id):void 0,className:"tb-link-address",type:"url",value:o,"aria-label":e.address,placeholder:e.placeholder,autoComplete:"off",onFocus:()=>g(!0),onMouseDownCapture:r=>{r.stopPropagation(),r.preventDefault(),r.currentTarget.focus()},onChange:r=>y(r.target.value),onKeyDown:r=>{(r.key==="Escape"||r.key==="Enter")&&(r.preventDefault(),r.stopPropagation(),h.ReactEditor.focus(n))},onBlur:()=>{b&&L()}}),c.isValidLink(o,!0)&&l.jsx("a",{className:"tb-link-open",href:c.sanitizeLink(o),target:"_blank",rel:"noopener noreferrer","aria-label":e.open,title:e.open,children:l.jsx(d.LinkIcon,{})})]})}function w({editor:t,type:e,event:n}){const{selection:i}=t;if(!i)return;const[a]=s.Editor.nodes(t,{at:s.Editor.unhangRange(t,i),match:o=>!s.Editor.isEditor(o)&&p.TextbitElement.isInline(o)&&o.type===e});if(a){const[o]=a;s.Element.isElement(o)&&typeof o.id=="string"&&(n?.preventDefault(),document.getElementById(m(o.id))?.focus());return}if(s.Range.isCollapsed(i))return;n?.preventDefault();const u=crypto.randomUUID();s.Editor.withoutNormalizing(t,()=>{s.Transforms.wrapNodes(t,{class:"inline",type:e,id:u,properties:{href:""},children:[{text:""}]},{split:!0})}),setTimeout(()=>document.getElementById(m(u))?.focus(),0)}function E(t){s.Transforms.unwrapNodes(t,{match:e=>!s.Editor.isEditor(e)&&s.Element.isElement(e)&&e.type===f})}function m(t){return`tb-link-${t}`}exports.Link=j;
@@ -0,0 +1,25 @@
1
+ import { TBPluginDefinition } from '@dotvoid/textbit';
2
+ export type LinkLabels = {
3
+ /** The action's name in menus and for screen readers */
4
+ title: string;
5
+ /** Name of the address field */
6
+ address: string;
7
+ /** Placeholder of the address field */
8
+ placeholder: string;
9
+ remove: string;
10
+ open: string;
11
+ };
12
+ export type LinkOptions = {
13
+ /** Replace the default shortcut, Ctrl+K / ⌘K, or remove it with `false` */
14
+ hotkey?: string | false;
15
+ /** Labels and names, e.g. translations */
16
+ labels?: Partial<LinkLabels>;
17
+ };
18
+ /**
19
+ * Links. Ctrl/⌘+K links the selection and opens the address field; Ctrl/⌘-click
20
+ * opens a link. Addresses are checked wherever a link is rendered, not only when
21
+ * typed: a `javascript:` address arriving through paste, a collaborator or stored
22
+ * data never becomes a live link.
23
+ */
24
+ export declare const Link: (options?: LinkOptions) => TBPluginDefinition;
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/Link/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAoB,kBAAkB,EAA6C,MAAM,kBAAkB,CAAA;AAUvH,MAAM,MAAM,UAAU,GAAG;IACvB,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAA;IACb,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IACvB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAA;CAC7B,CAAA;AAUD;;;;;GAKG;AACH,eAAO,MAAM,IAAI,GAAI,UAAS,WAAgB,KAAG,kBAsBhD,CAAA"}
@@ -0,0 +1,148 @@
1
+ import { jsx as a, jsxs as w } from "react/jsx-runtime";
2
+ import { useState as h } from "react";
3
+ import { TextbitElement as c } from "@dotvoid/textbit";
4
+ import { Editor as l, Element as y, Range as N, Transforms as m } from "slate";
5
+ import { useSlateStatic as I, ReactEditor as x } from "slate-react";
6
+ import { LinkIcon as E, LinkOffIcon as C } from "../shared/icons.js";
7
+ import { hotkeyOption as T } from "../shared/hotkey.js";
8
+ import { sanitizeLink as f, isValidLink as g } from "./isValidLink.js";
9
+ const u = "base/link", B = {
10
+ title: "Link",
11
+ address: "Link address",
12
+ placeholder: "https://",
13
+ remove: "Remove link",
14
+ open: "Open link in a new tab"
15
+ }, F = (t = {}) => {
16
+ const e = { ...B, ...t.labels };
17
+ return {
18
+ class: "inline",
19
+ name: u,
20
+ componentEntry: {
21
+ class: "inline",
22
+ component: R
23
+ },
24
+ actions: [{
25
+ name: "edit",
26
+ title: e.title,
27
+ tool: [
28
+ () => /* @__PURE__ */ a(E, {}),
29
+ (n) => /* @__PURE__ */ a(S, { ...n, labels: e })
30
+ ],
31
+ hotkey: T(t.hotkey, "mod+k"),
32
+ handler: K,
33
+ visibility: (n) => [!0, !0, n.type === u]
34
+ }]
35
+ };
36
+ };
37
+ function R({ children: t, element: e }) {
38
+ const n = f(typeof e.properties?.href == "string" ? e.properties.href : ""), o = g(n);
39
+ return /* @__PURE__ */ a(
40
+ "a",
41
+ {
42
+ href: o ? n : void 0,
43
+ className: "tb-link",
44
+ ...o ? {} : { "data-invalid": "" },
45
+ onClick: (s) => {
46
+ o && (s.ctrlKey || s.metaKey) && (s.preventDefault(), window.open(n, "_blank", "noopener,noreferrer"));
47
+ },
48
+ children: t
49
+ }
50
+ );
51
+ }
52
+ function S({ entry: t, labels: e }) {
53
+ const n = I(), [o, s] = t || [], p = c.isElement(o) && typeof o.properties?.href == "string" ? o.properties.href : "", [r, b] = h(p), [v, L] = h(!1);
54
+ if (!c.isElement(o) || !s)
55
+ return null;
56
+ const D = () => {
57
+ const i = f(r);
58
+ i === "" ? k(n) : m.setNodes(n, { properties: { ...o.properties, href: i } }, { at: s });
59
+ };
60
+ return /* @__PURE__ */ w("div", { className: "tb-link-editor", role: "group", "aria-label": e.title, children: [
61
+ /* @__PURE__ */ a(
62
+ "button",
63
+ {
64
+ type: "button",
65
+ className: "tb-link-remove",
66
+ "aria-label": e.remove,
67
+ title: e.remove,
68
+ onMouseDown: (i) => {
69
+ i.preventDefault(), k(n);
70
+ },
71
+ children: /* @__PURE__ */ a(C, {})
72
+ }
73
+ ),
74
+ /* @__PURE__ */ a(
75
+ "input",
76
+ {
77
+ id: o.id ? d(o.id) : void 0,
78
+ className: "tb-link-address",
79
+ type: "url",
80
+ value: r,
81
+ "aria-label": e.address,
82
+ placeholder: e.placeholder,
83
+ autoComplete: "off",
84
+ onFocus: () => L(!0),
85
+ onMouseDownCapture: (i) => {
86
+ i.stopPropagation(), i.preventDefault(), i.currentTarget.focus();
87
+ },
88
+ onChange: (i) => b(i.target.value),
89
+ onKeyDown: (i) => {
90
+ (i.key === "Escape" || i.key === "Enter") && (i.preventDefault(), i.stopPropagation(), x.focus(n));
91
+ },
92
+ onBlur: () => {
93
+ v && D();
94
+ }
95
+ }
96
+ ),
97
+ g(r, !0) && /* @__PURE__ */ a(
98
+ "a",
99
+ {
100
+ className: "tb-link-open",
101
+ href: f(r),
102
+ target: "_blank",
103
+ rel: "noopener noreferrer",
104
+ "aria-label": e.open,
105
+ title: e.open,
106
+ children: /* @__PURE__ */ a(E, {})
107
+ }
108
+ )
109
+ ] });
110
+ }
111
+ function K({ editor: t, type: e, event: n }) {
112
+ const { selection: o } = t;
113
+ if (!o)
114
+ return;
115
+ const [s] = l.nodes(t, {
116
+ at: l.unhangRange(t, o),
117
+ match: (r) => !l.isEditor(r) && c.isInline(r) && r.type === e
118
+ });
119
+ if (s) {
120
+ const [r] = s;
121
+ y.isElement(r) && typeof r.id == "string" && (n?.preventDefault(), document.getElementById(d(r.id))?.focus());
122
+ return;
123
+ }
124
+ if (N.isCollapsed(o))
125
+ return;
126
+ n?.preventDefault();
127
+ const p = crypto.randomUUID();
128
+ l.withoutNormalizing(t, () => {
129
+ m.wrapNodes(t, {
130
+ class: "inline",
131
+ type: e,
132
+ id: p,
133
+ properties: { href: "" },
134
+ children: [{ text: "" }]
135
+ }, { split: !0 });
136
+ }), setTimeout(() => document.getElementById(d(p))?.focus(), 0);
137
+ }
138
+ function k(t) {
139
+ m.unwrapNodes(t, {
140
+ match: (e) => !l.isEditor(e) && y.isElement(e) && e.type === u
141
+ });
142
+ }
143
+ function d(t) {
144
+ return `tb-link-${t}`;
145
+ }
146
+ export {
147
+ F as Link
148
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=["http:","https:","tel:","mailto:"];function o(n){const t=n.trim();if(t==="")return"";try{const r=new URL(t);return i.includes(r.protocol)?t:""}catch{return t}}function s(n,t=!1){if(typeof n!="string")return!1;const r=o(n);if(r==="")return!1;try{const e=new URL(r);return i.includes(e.protocol)}catch{if(t)return!1}try{return new URL(r,"https://localhost").protocol==="https:"}catch{return!1}}exports.isValidLink=s;exports.sanitizeLink=o;
@@ -0,0 +1,3 @@
1
+ export declare function sanitizeLink(link: string): string;
2
+ export declare function isValidLink(link: string, enforceProtocol?: boolean): boolean;
3
+ //# sourceMappingURL=isValidLink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isValidLink.d.ts","sourceRoot":"","sources":["../../lib/Link/isValidLink.ts"],"names":[],"mappings":"AAEA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAajD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,GAAE,OAAe,GAAG,OAAO,CAyBnF"}
@@ -0,0 +1,35 @@
1
+ const o = ["http:", "https:", "tel:", "mailto:"];
2
+ function s(n) {
3
+ const t = n.trim();
4
+ if (t === "")
5
+ return "";
6
+ try {
7
+ const r = new URL(t);
8
+ return o.includes(r.protocol) ? t : "";
9
+ } catch {
10
+ return t;
11
+ }
12
+ }
13
+ function c(n, t = !1) {
14
+ if (typeof n != "string")
15
+ return !1;
16
+ const r = s(n);
17
+ if (r === "")
18
+ return !1;
19
+ try {
20
+ const e = new URL(r);
21
+ return o.includes(e.protocol);
22
+ } catch {
23
+ if (t)
24
+ return !1;
25
+ }
26
+ try {
27
+ return new URL(r, "https://localhost").protocol === "https:";
28
+ } catch {
29
+ return !1;
30
+ }
31
+ }
32
+ export {
33
+ c as isValidLink,
34
+ s as sanitizeLink
35
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("react/jsx-runtime"),u=require("@dotvoid/textbit"),e=require("slate"),h=require("../shared/icons.cjs"),x=require("../shared/ChildPlaceholder.cjs"),f=require("../shared/hotkey.cjs"),E="base/unordered-list",m="base/ordered-list",d=[E,m],g=d.map(t=>`${t}/list-item`),N=(t={})=>p(E,t.title??"Bullet list",()=>c.jsx(h.ListIcon,{}),f.hotkeyOption(t.hotkey,"mod+shift+8"),t),T=(t={})=>p(m,t.title??"Numbered list",()=>c.jsx(h.OrderedListIcon,{}),f.hotkeyOption(t.hotkey,"mod+shift+7"),t);function p(t,i,l,o,s){return{class:"text",name:t,actions:[{name:"toggle",title:i,tool:l,hotkey:o,visibility:(n,r)=>{const a=r??n;return[["base/text",...d,...g].includes(a.type),!0,a.type===t||a.type===`${t}/list-item`]},handler:({editor:n})=>{L(n,t)}},{name:"enter",hotkey:"enter",when:n=>y(n,t)!==void 0,visibility:()=>[!1,!1,!1],handler:({editor:n,event:r})=>{r?.preventDefault(),P(n,t)}}],componentEntry:{class:"text",component:b,constraints:{normalizeNode:(n,r)=>O(n,r,t)},children:[{type:"list-item",class:"text",asOwnElement:!0,component:n=>c.jsx(v,{...n,placeholder:s.placeholder})}]}}}function b({element:t,children:i}){return t.type===m?c.jsx("ol",{className:"tb-list tb-ordered-list",children:i}):c.jsx("ul",{className:"tb-list tb-unordered-list",children:i})}function v({element:t,children:i,attributes:l,placeholder:o}){return c.jsxs("li",{...l,className:"tb-list-item",style:{position:"relative"},children:[c.jsx(x.ChildPlaceholder,{element:t,children:o}),i]})}function y(t,i){const{selection:l}=t;if(!l||!e.Range.isCollapsed(l))return;const[o]=e.Editor.nodes(t,{at:l,match:a=>e.Element.isElement(a)&&a.type===`${i}/list-item`});if(!o)return;const s=o[1],n=e.Path.parent(s),[r]=e.Editor.node(t,n);if(!(!e.Element.isElement(r)||s[s.length-1]!==r.children.length-1))return{itemPath:s,listPath:n,list:r}}function P(t,i){const l=y(t,i);if(!l)return;const{itemPath:o,listPath:s,list:n}=l;if(e.Editor.string(t,o)!==""){e.Transforms.splitNodes(t,{match:r=>e.Element.isElement(r)&&r.type===`${i}/list-item`,always:!0});return}e.Editor.withoutNormalizing(t,()=>{const r=n.children.length===1?s:e.Path.next(s);e.Transforms.removeNodes(t,{at:n.children.length===1?s:o}),e.Transforms.insertNodes(t,{id:crypto.randomUUID(),class:"text",type:"base/text",children:[{text:""}]},{at:r}),e.Transforms.select(t,e.Editor.start(t,r))})}function L(t,i){const{selection:l}=t;if(!l)return;const[o]=e.Editor.nodes(t,{at:e.Editor.unhangRange(t,l),match:s=>e.Element.isElement(s)&&d.includes(s.type)});if(o){const[s,n]=o,r=`${s.type}/list-item`;e.Editor.withoutNormalizing(t,()=>{s.type===i?(e.Transforms.setNodes(t,{type:"base/text",properties:{}},{at:n,match:a=>e.Element.isElement(a)&&a.type===r}),e.Transforms.unwrapNodes(t,{at:n})):(e.Transforms.setNodes(t,{type:`${i}/list-item`},{at:n,match:a=>e.Element.isElement(a)&&a.type===r}),e.Transforms.setNodes(t,{type:i},{at:n}))});return}e.Editor.withoutNormalizing(t,()=>{e.Transforms.setNodes(t,{type:`${i}/list-item`,properties:{}},{match:s=>!e.Editor.isEditor(s)&&u.TextbitElement.isElement(s)&&s.class==="text"}),e.Transforms.wrapNodes(t,{id:crypto.randomUUID(),class:"text",type:i,children:[]})})}function O(t,[i,l],o){if(e.Element.isElement(i)){if(i.children.length===0)return e.Transforms.removeNodes(t,{at:l}),!0;for(let s=0;s<i.children.length;s++){const n=i.children[s];if(u.TextbitElement.isElement(n)&&n.type!==`${o}/list-item`)return e.Transforms.setNodes(t,{type:`${o}/list-item`},{at:[...l,s]}),!0}}}exports.OrderedList=T;exports.UnorderedList=N;
@@ -0,0 +1,17 @@
1
+ import { TBPluginDefinition } from '@dotvoid/textbit';
2
+ export type ListOptions = {
3
+ /** The action's name in menus and for screen readers, e.g. a translation */
4
+ title?: string;
5
+ /** Hint in an empty list item */
6
+ placeholder?: string;
7
+ /**
8
+ * Replace the default shortcut, or remove it with `false`. Defaults, as in
9
+ * Google Docs: Ctrl/⌘+Shift+8 for bullets, Ctrl/⌘+Shift+7 for numbers.
10
+ */
11
+ hotkey?: string | false;
12
+ };
13
+ /** A bullet list. Use it with OrderedList to switch a list between the two. */
14
+ export declare const UnorderedList: (options?: ListOptions) => TBPluginDefinition;
15
+ /** A numbered list. Use it with UnorderedList to switch a list between the two. */
16
+ export declare const OrderedList: (options?: ListOptions) => TBPluginDefinition;
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/List/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgD,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAYxG,MAAM,MAAM,WAAW,GAAG;IACxB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iCAAiC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;CACxB,CAAA;AAED,+EAA+E;AAC/E,eAAO,MAAM,aAAa,GAAI,UAAS,WAAgB,KAAG,kBACuE,CAAA;AAEjI,mFAAmF;AACnF,eAAO,MAAM,WAAW,GAAI,UAAS,WAAgB,KAAG,kBACgF,CAAA"}
@@ -0,0 +1,151 @@
1
+ import { jsx as h, jsxs as x } from "react/jsx-runtime";
2
+ import { TextbitElement as f } from "@dotvoid/textbit";
3
+ import { Element as c, Transforms as a, Editor as m, Path as p, Range as b } from "slate";
4
+ import { OrderedListIcon as v, ListIcon as L } from "../shared/icons.js";
5
+ import { ChildPlaceholder as P } from "../shared/ChildPlaceholder.js";
6
+ import { hotkeyOption as E } from "../shared/hotkey.js";
7
+ const y = "base/unordered-list", u = "base/ordered-list", d = [y, u], I = d.map((t) => `${t}/list-item`), j = (t = {}) => N(y, t.title ?? "Bullet list", () => /* @__PURE__ */ h(L, {}), E(t.hotkey, "mod+shift+8"), t), Y = (t = {}) => N(u, t.title ?? "Numbered list", () => /* @__PURE__ */ h(v, {}), E(t.hotkey, "mod+shift+7"), t);
8
+ function N(t, n, l, r, e) {
9
+ return {
10
+ class: "text",
11
+ name: t,
12
+ actions: [
13
+ {
14
+ name: "toggle",
15
+ title: n,
16
+ tool: l,
17
+ hotkey: r,
18
+ visibility: (s, i) => {
19
+ const o = i ?? s;
20
+ return [
21
+ ["base/text", ...d, ...I].includes(o.type),
22
+ !0,
23
+ o.type === t || o.type === `${t}/list-item`
24
+ ];
25
+ },
26
+ handler: ({ editor: s }) => {
27
+ O(s, t);
28
+ }
29
+ },
30
+ {
31
+ // Enter on the last item: a new item, or out of the list when it is
32
+ // empty. Elsewhere in a list Slate's own Enter already does the right thing.
33
+ name: "enter",
34
+ hotkey: "enter",
35
+ when: (s) => g(s, t) !== void 0,
36
+ visibility: () => [!1, !1, !1],
37
+ handler: ({ editor: s, event: i }) => {
38
+ i?.preventDefault(), D(s, t);
39
+ }
40
+ }
41
+ ],
42
+ componentEntry: {
43
+ class: "text",
44
+ component: $,
45
+ constraints: {
46
+ normalizeNode: (s, i) => T(s, i, t)
47
+ },
48
+ children: [{
49
+ type: "list-item",
50
+ class: "text",
51
+ // Renders the <li> itself: a wrapping <div> is not allowed in a list
52
+ asOwnElement: !0,
53
+ component: (s) => /* @__PURE__ */ h(w, { ...s, placeholder: e.placeholder })
54
+ }]
55
+ }
56
+ };
57
+ }
58
+ function $({ element: t, children: n }) {
59
+ return t.type === u ? /* @__PURE__ */ h("ol", { className: "tb-list tb-ordered-list", children: n }) : /* @__PURE__ */ h("ul", { className: "tb-list tb-unordered-list", children: n });
60
+ }
61
+ function w({ element: t, children: n, attributes: l, placeholder: r }) {
62
+ return /* @__PURE__ */ x("li", { ...l, className: "tb-list-item", style: { position: "relative" }, children: [
63
+ /* @__PURE__ */ h(P, { element: t, children: r }),
64
+ n
65
+ ] });
66
+ }
67
+ function g(t, n) {
68
+ const { selection: l } = t;
69
+ if (!l || !b.isCollapsed(l))
70
+ return;
71
+ const [r] = m.nodes(t, {
72
+ at: l,
73
+ match: (o) => c.isElement(o) && o.type === `${n}/list-item`
74
+ });
75
+ if (!r)
76
+ return;
77
+ const e = r[1], s = p.parent(e), [i] = m.node(t, s);
78
+ if (!(!c.isElement(i) || e[e.length - 1] !== i.children.length - 1))
79
+ return { itemPath: e, listPath: s, list: i };
80
+ }
81
+ function D(t, n) {
82
+ const l = g(t, n);
83
+ if (!l)
84
+ return;
85
+ const { itemPath: r, listPath: e, list: s } = l;
86
+ if (m.string(t, r) !== "") {
87
+ a.splitNodes(t, {
88
+ match: (i) => c.isElement(i) && i.type === `${n}/list-item`,
89
+ always: !0
90
+ });
91
+ return;
92
+ }
93
+ m.withoutNormalizing(t, () => {
94
+ const i = s.children.length === 1 ? e : p.next(e);
95
+ a.removeNodes(t, { at: s.children.length === 1 ? e : r }), a.insertNodes(t, {
96
+ id: crypto.randomUUID(),
97
+ class: "text",
98
+ type: "base/text",
99
+ children: [{ text: "" }]
100
+ }, { at: i }), a.select(t, m.start(t, i));
101
+ });
102
+ }
103
+ function O(t, n) {
104
+ const { selection: l } = t;
105
+ if (!l)
106
+ return;
107
+ const [r] = m.nodes(t, {
108
+ at: m.unhangRange(t, l),
109
+ match: (e) => c.isElement(e) && d.includes(e.type)
110
+ });
111
+ if (r) {
112
+ const [e, s] = r, i = `${e.type}/list-item`;
113
+ m.withoutNormalizing(t, () => {
114
+ e.type === n ? (a.setNodes(
115
+ t,
116
+ { type: "base/text", properties: {} },
117
+ { at: s, match: (o) => c.isElement(o) && o.type === i }
118
+ ), a.unwrapNodes(t, { at: s })) : (a.setNodes(
119
+ t,
120
+ { type: `${n}/list-item` },
121
+ { at: s, match: (o) => c.isElement(o) && o.type === i }
122
+ ), a.setNodes(t, { type: n }, { at: s }));
123
+ });
124
+ return;
125
+ }
126
+ m.withoutNormalizing(t, () => {
127
+ a.setNodes(t, { type: `${n}/list-item`, properties: {} }, {
128
+ match: (e) => !m.isEditor(e) && f.isElement(e) && e.class === "text"
129
+ }), a.wrapNodes(t, {
130
+ id: crypto.randomUUID(),
131
+ class: "text",
132
+ type: n,
133
+ children: []
134
+ });
135
+ });
136
+ }
137
+ function T(t, [n, l], r) {
138
+ if (c.isElement(n)) {
139
+ if (n.children.length === 0)
140
+ return a.removeNodes(t, { at: l }), !0;
141
+ for (let e = 0; e < n.children.length; e++) {
142
+ const s = n.children[e];
143
+ if (f.isElement(s) && s.type !== `${r}/list-item`)
144
+ return a.setNodes(t, { type: `${r}/list-item` }, { at: [...l, e] }), !0;
145
+ }
146
+ }
147
+ }
148
+ export {
149
+ Y as OrderedList,
150
+ j as UnorderedList
151
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("slate"),E={sv:["’","’","”","”"],fi:["’","’","”","”"],hu:["’","’","„","”"],pl:["‚","’","„","”"],no:["‹","›","«","»"],en:["‘","’","“","”"],da:["„","“","„","“"],de:["‚","‘","„","“"],fr:["‹ "," ›","« "," »"]},C={sv:"–"},P=[9,32,60,33,40,41,43,44,45,46,47,58,59,60,61,62,63],b=async({editor:r,input:s})=>{const{selection:t}=r,c=r.lang.substring(0,2).toLowerCase();if(Array.isArray(s)||typeof s.data!="string"||!t||t.anchor.path.length<2)return;const{data:a}=s;if(a[0]==="-"&&C[c]&&y(r,t))return{...s,data:C[c]+a.slice(1)};if(a[0]==="-"){const{anchor:f}=t,n=e.Editor.before(r,f,{unit:"character"});if(n){const[u]=e.Editor.node(r,n.path);if(e.Text.isText(u)&&u.text[n.offset]==="-")return e.Transforms.delete(r,{at:n}),{...s,data:"–"}}}const x=e.Path.parent(t.anchor.path),d=t.anchor.path[t.anchor.path.length-1];let T=t.anchor.offset,h,p="";for(let f=d;f>=0;f--){const[n,u]=e.Editor.node(r,[...x,f]);if(e.Text.isText(n)){for(let o=T||n.text.length-1;o>=0;o--){if(h){const g=n.text[o];if(!isNaN(parseInt(g))&&P.includes(p.charCodeAt(0)))return s;f=-1;break}n.text[o]===a?h={path:u,offset:o}:p=n.text[o]}T=0}}if(!h)return s;const i=E[c]||E.en;let l=[];if(a==="'")l=[i[0],i[1]];else if(a==='"')l=[i[2],i[3]];else return s;return e.Transforms.delete(r,{at:h}),e.Transforms.insertText(r,l[0],{at:h}),{...s,data:l[1]}};function y(r,s){const{anchor:t}=s;if(t.path.length<2)return!1;const c=e.Path.parent(t.path),a=e.Node.first(r,c);if(!a)return!1;const[x,d]=a;return e.Text.isText(x)?e.Path.equals(t.path,d)&&t.offset===0:!1}exports.consume=b;
@@ -0,0 +1,3 @@
1
+ import { TBConsumeFunction } from '@dotvoid/textbit';
2
+ export declare const consume: TBConsumeFunction;
3
+ //# sourceMappingURL=consume.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consume.d.ts","sourceRoot":"","sources":["../../lib/LocalizedQuotationMarks/consume.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAuCzD,eAAO,MAAM,OAAO,EAAE,iBA8GrB,CAAA"}