@panneau/editor 0.0.0-stage → 5.0.0-alpha.10

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 (60) hide show
  1. package/README.md +129 -2
  2. package/dist/LinkDialog.d.ts +18 -0
  3. package/dist/LinkDialog.d.ts.map +1 -0
  4. package/dist/LinkDialog.js +220 -0
  5. package/dist/LinkDialog.js.map +1 -0
  6. package/dist/RichTextField.css +257 -0
  7. package/dist/RichTextField.d.ts +43 -0
  8. package/dist/RichTextField.d.ts.map +1 -0
  9. package/dist/RichTextField.js +361 -0
  10. package/dist/RichTextField.js.map +1 -0
  11. package/dist/RichTextField.module.js +28 -0
  12. package/dist/RichTextField.module.js.map +1 -0
  13. package/dist/Toolbar.d.ts +20 -0
  14. package/dist/Toolbar.d.ts.map +1 -0
  15. package/dist/Toolbar.js +203 -0
  16. package/dist/Toolbar.js.map +1 -0
  17. package/dist/buttons.d.ts +23 -0
  18. package/dist/buttons.d.ts.map +1 -0
  19. package/dist/buttons.js +117 -0
  20. package/dist/buttons.js.map +1 -0
  21. package/dist/extensions/attributes.d.ts +44 -0
  22. package/dist/extensions/attributes.d.ts.map +1 -0
  23. package/dist/extensions/attributes.js +138 -0
  24. package/dist/extensions/attributes.js.map +1 -0
  25. package/dist/extensions/index.d.ts +19 -0
  26. package/dist/extensions/index.d.ts.map +1 -0
  27. package/dist/extensions/index.js +96 -0
  28. package/dist/extensions/index.js.map +1 -0
  29. package/dist/extensions/marks.d.ts +4 -0
  30. package/dist/extensions/marks.d.ts.map +1 -0
  31. package/dist/extensions/marks.js +62 -0
  32. package/dist/extensions/marks.js.map +1 -0
  33. package/dist/extensions/paste.d.ts +32 -0
  34. package/dist/extensions/paste.d.ts.map +1 -0
  35. package/dist/extensions/paste.js +131 -0
  36. package/dist/extensions/paste.js.map +1 -0
  37. package/dist/extensions/raw.d.ts +23 -0
  38. package/dist/extensions/raw.d.ts.map +1 -0
  39. package/dist/extensions/raw.js +269 -0
  40. package/dist/extensions/raw.js.map +1 -0
  41. package/dist/html.d.ts +21 -0
  42. package/dist/html.d.ts.map +1 -0
  43. package/dist/html.js +51 -0
  44. package/dist/html.js.map +1 -0
  45. package/dist/index.d.ts +8 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +7 -0
  48. package/dist/plugin.d.ts +26 -0
  49. package/dist/plugin.d.ts.map +1 -0
  50. package/dist/plugin.js +46 -0
  51. package/dist/plugin.js.map +1 -0
  52. package/dist/settings.d.ts +22 -0
  53. package/dist/settings.d.ts.map +1 -0
  54. package/dist/settings.js +45 -0
  55. package/dist/settings.js.map +1 -0
  56. package/dist/styles.d.ts +16 -0
  57. package/dist/styles.d.ts.map +1 -0
  58. package/dist/styles.js +86 -0
  59. package/dist/styles.js.map +1 -0
  60. package/package.json +71 -5
@@ -0,0 +1,43 @@
1
+ import type { AnyExtension } from '@tiptap/core';
2
+ import { type FieldEntryProps, type FieldProps } from '@panneau/fields';
3
+ import type { RichTextStyle } from '@panneau/protocol';
4
+ import type { RichTextButton } from './buttons.js';
5
+ import { type NewTabLinks } from './settings.js';
6
+ export interface RichTextFieldProps extends FieldProps<string> {
7
+ placeholder?: string;
8
+ /**
9
+ * The toolbar, in order: `heading`, `style`, `bold`, `italic`, `underline`, `strike`,
10
+ * `superscript`, `subscript`, `code`, `link`, `bulletList`, `orderedList`, `blockquote`,
11
+ * `horizontalRule`, `clear`, `undo`, `redo`, names of `buttons`, and `|` between groups.
12
+ */
13
+ toolbar?: readonly string[];
14
+ /** The heading levels the toolbar offers. Defaults to 2, 3 and 4. */
15
+ headings?: readonly number[];
16
+ /** Block styles: a class on a paragraph, a heading, a quote or a list. */
17
+ styles?: readonly RichTextStyle[];
18
+ /** Which links open in a new tab: as the user chooses (the default), external ones, or none. */
19
+ newTab?: NewTabLinks;
20
+ /**
21
+ * TipTap extensions of the project: custom nodes such as an inline logo. One with the name of
22
+ * a built-in extension replaces it. The editor is made again when they change.
23
+ */
24
+ extensions?: readonly AnyExtension[];
25
+ /** Toolbar buttons of the project, that `toolbar` names. */
26
+ buttons?: readonly RichTextButton[];
27
+ contentClassName?: string;
28
+ }
29
+ /**
30
+ * Rich text, stored as HTML (decision 0007): an empty text is `null`. Content keeps what the
31
+ * toolbar doesn't offer (elements, attributes, embeds), and HTML written by another editor stays
32
+ * as it was until the text is edited.
33
+ */
34
+ export declare function RichTextField({ value, onChange, onBlur, placeholder, toolbar, headings, styles: blockStyles, newTab, extensions: projectExtensions, buttons, label, description, errors, disabled, readOnly, required, name, id, autoFocus, 'aria-label': ariaLabel, className, contentClassName, }: RichTextFieldProps): import("react").JSX.Element;
35
+ /**
36
+ * The `richtext` type: its toolbar, heading levels, block styles and links from `settings`
37
+ * (`RichTextSettings`), and the extensions and buttons of the editor plugin.
38
+ */
39
+ export declare function RichTextFieldEntry(props: FieldEntryProps & {
40
+ extensions?: readonly AnyExtension[];
41
+ buttons?: readonly RichTextButton[];
42
+ }): import("react").JSX.Element;
43
+ //# sourceMappingURL=RichTextField.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RichTextField.d.ts","sourceRoot":"","sources":["../src/RichTextField.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAIjD,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAiB,MAAM,iBAAiB,CAAC;AAEvF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAKvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGhD,OAAO,EAGH,KAAK,WAAW,EAEnB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAmB,SAAQ,UAAU,CAAC,MAAM,CAAC;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,0EAA0E;IAC1E,MAAM,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IAClC,gGAAgG;IAChG,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACrC,4DAA4D;IAC5D,OAAO,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IACpC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AA4BD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAC1B,KAAK,EACL,QAAQ,EACR,MAAM,EACN,WAAW,EACX,OAAyB,EACzB,QAA2B,EAC3B,MAAM,EAAE,WAAuB,EAC/B,MAAiB,EACjB,UAAU,EAAE,iBAAiC,EAC7C,OAAoB,EACpB,KAAK,EACL,WAAW,EACX,MAAkB,EAClB,QAAgB,EAChB,QAAgB,EAChB,QAAgB,EAChB,IAAI,EACJ,EAAE,EACF,SAAS,EACT,YAAY,EAAE,SAAS,EACvB,SAAS,EACT,gBAAgB,GACnB,EAAE,kBAAkB,+BA2GpB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAC9B,KAAK,EAAE,eAAe,GAAG;IACrB,UAAU,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACrC,OAAO,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;CACvC,+BAgBJ"}
@@ -0,0 +1,361 @@
1
+ import RichTextField_module_default from "./RichTextField.module.js";
2
+ import { Toolbar } from "./Toolbar.js";
3
+ import { createRichTextExtensions } from "./extensions/index.js";
4
+ import { parseRichText, serializeRichText } from "./html.js";
5
+ import { DEFAULT_HEADINGS, DEFAULT_TOOLBAR, getRichTextOptions } from "./settings.js";
6
+ import { c } from "react/compiler-runtime";
7
+ import { EditorContent, useEditor } from "@tiptap/react";
8
+ import { useEffect, useRef } from "react";
9
+ import { getFieldProps } from "@panneau/fields";
10
+ import { editorMessages } from "@panneau/intl";
11
+ import { Fieldset, usePanneauIntl } from "@panneau/ui";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
13
+ //#region src/RichTextField.tsx
14
+ /** The attributes of the editable element: a labelled, multiline `textbox`. */
15
+ function getContentAttributes(className, accessibleName, invalid, required, editable, id) {
16
+ return {
17
+ role: "textbox",
18
+ "aria-multiline": "true",
19
+ class: className,
20
+ ...accessibleName !== void 0 ? { "aria-label": accessibleName } : {},
21
+ ...invalid ? { "aria-invalid": "true" } : {},
22
+ ...required ? { "aria-required": "true" } : {},
23
+ ...!editable ? { "aria-readonly": "true" } : {},
24
+ ...id !== void 0 ? { id } : {}
25
+ };
26
+ }
27
+ var NO_EXTENSIONS = [];
28
+ var NO_BUTTONS = [];
29
+ var NO_STYLES = [];
30
+ var NO_ERRORS = [];
31
+ /**
32
+ * Rich text, stored as HTML (decision 0007): an empty text is `null`. Content keeps what the
33
+ * toolbar doesn't offer (elements, attributes, embeds), and HTML written by another editor stays
34
+ * as it was until the text is edited.
35
+ */
36
+ function RichTextField(t0) {
37
+ const $ = c(79);
38
+ const { value, onChange, onBlur, placeholder, toolbar: t1, headings: t2, styles: t3, newTab: t4, extensions: t5, buttons: t6, label, description, errors: t7, disabled: t8, readOnly: t9, required: t10, name, id, autoFocus, "aria-label": ariaLabel, className, contentClassName } = t0;
39
+ const toolbar = t1 === void 0 ? DEFAULT_TOOLBAR : t1;
40
+ const headings = t2 === void 0 ? DEFAULT_HEADINGS : t2;
41
+ const blockStyles = t3 === void 0 ? NO_STYLES : t3;
42
+ const newTab = t4 === void 0 ? "choose" : t4;
43
+ const projectExtensions = t5 === void 0 ? NO_EXTENSIONS : t5;
44
+ const buttons = t6 === void 0 ? NO_BUTTONS : t6;
45
+ const errors = t7 === void 0 ? NO_ERRORS : t7;
46
+ const disabled = t8 === void 0 ? false : t8;
47
+ const readOnly = t9 === void 0 ? false : t9;
48
+ const required = t10 === void 0 ? false : t10;
49
+ const intl = usePanneauIntl();
50
+ const editable = !disabled && !readOnly;
51
+ let t11;
52
+ if ($[0] !== intl || $[1] !== placeholder || $[2] !== projectExtensions) {
53
+ t11 = createRichTextExtensions({
54
+ extensions: projectExtensions,
55
+ ...placeholder !== void 0 ? { placeholder } : {},
56
+ html: {
57
+ label: intl.formatMessage(editorMessages.html),
58
+ className: RichTextField_module_default.html ?? ""
59
+ }
60
+ });
61
+ $[0] = intl;
62
+ $[1] = placeholder;
63
+ $[2] = projectExtensions;
64
+ $[3] = t11;
65
+ } else t11 = $[3];
66
+ const extensions = t11;
67
+ const current = useRef(value);
68
+ const accessibleName = ariaLabel ?? (typeof label === "string" ? label : void 0);
69
+ const invalid = errors.length > 0;
70
+ let t12;
71
+ if ($[4] !== contentClassName) {
72
+ t12 = [RichTextField_module_default.content, contentClassName].filter(Boolean);
73
+ $[4] = contentClassName;
74
+ $[5] = t12;
75
+ } else t12 = $[5];
76
+ const contentClass = t12.join(" ");
77
+ const t13 = autoFocus === true ? "end" : false;
78
+ let t14;
79
+ if ($[6] !== accessibleName || $[7] !== contentClass || $[8] !== editable || $[9] !== id || $[10] !== invalid || $[11] !== required) {
80
+ t14 = getContentAttributes(contentClass, accessibleName, invalid, required, editable, id);
81
+ $[6] = accessibleName;
82
+ $[7] = contentClass;
83
+ $[8] = editable;
84
+ $[9] = id;
85
+ $[10] = invalid;
86
+ $[11] = required;
87
+ $[12] = t14;
88
+ } else t14 = $[12];
89
+ let t15;
90
+ if ($[13] !== t14) {
91
+ t15 = { attributes: t14 };
92
+ $[13] = t14;
93
+ $[14] = t15;
94
+ } else t15 = $[14];
95
+ let t16;
96
+ if ($[15] !== value) {
97
+ t16 = (t17) => {
98
+ const { editor: created } = t17;
99
+ current.current = value;
100
+ created.options.content = parseRichText(value ?? null, created.schema).toJSON();
101
+ };
102
+ $[15] = value;
103
+ $[16] = t16;
104
+ } else t16 = $[16];
105
+ let t17;
106
+ if ($[17] !== onChange) {
107
+ t17 = (t18) => {
108
+ const { editor: updated } = t18;
109
+ const html = serializeRichText(updated.state.doc, updated.schema);
110
+ current.current = html;
111
+ onChange?.(html);
112
+ };
113
+ $[17] = onChange;
114
+ $[18] = t17;
115
+ } else t17 = $[18];
116
+ let t18;
117
+ if ($[19] !== onBlur) {
118
+ t18 = () => onBlur?.();
119
+ $[19] = onBlur;
120
+ $[20] = t18;
121
+ } else t18 = $[20];
122
+ let t19;
123
+ if ($[21] !== editable || $[22] !== extensions || $[23] !== t13 || $[24] !== t15 || $[25] !== t16 || $[26] !== t17 || $[27] !== t18) {
124
+ t19 = {
125
+ extensions,
126
+ editable,
127
+ autofocus: t13,
128
+ immediatelyRender: true,
129
+ shouldRerenderOnTransaction: false,
130
+ editorProps: t15,
131
+ onBeforeCreate: t16,
132
+ onUpdate: t17,
133
+ onBlur: t18
134
+ };
135
+ $[21] = editable;
136
+ $[22] = extensions;
137
+ $[23] = t13;
138
+ $[24] = t15;
139
+ $[25] = t16;
140
+ $[26] = t17;
141
+ $[27] = t18;
142
+ $[28] = t19;
143
+ } else t19 = $[28];
144
+ let t20;
145
+ if ($[29] !== placeholder || $[30] !== projectExtensions) {
146
+ t20 = [projectExtensions, placeholder];
147
+ $[29] = placeholder;
148
+ $[30] = projectExtensions;
149
+ $[31] = t20;
150
+ } else t20 = $[31];
151
+ const editor = useEditor(t19, t20);
152
+ let t21;
153
+ let t22;
154
+ if ($[32] !== editor || $[33] !== value) {
155
+ t21 = () => {
156
+ if (editor === null || value === current.current) return;
157
+ current.current = value;
158
+ editor.commands.setContent(parseRichText(value ?? null, editor.schema).toJSON(), { emitUpdate: false });
159
+ };
160
+ t22 = [editor, value];
161
+ $[32] = editor;
162
+ $[33] = value;
163
+ $[34] = t21;
164
+ $[35] = t22;
165
+ } else {
166
+ t21 = $[34];
167
+ t22 = $[35];
168
+ }
169
+ useEffect(t21, t22);
170
+ let t23;
171
+ let t24;
172
+ if ($[36] !== editable || $[37] !== editor) {
173
+ t23 = () => {
174
+ editor?.setEditable(editable, false);
175
+ };
176
+ t24 = [editor, editable];
177
+ $[36] = editable;
178
+ $[37] = editor;
179
+ $[38] = t23;
180
+ $[39] = t24;
181
+ } else {
182
+ t23 = $[38];
183
+ t24 = $[39];
184
+ }
185
+ useEffect(t23, t24);
186
+ let t25;
187
+ let t26;
188
+ if ($[40] !== accessibleName || $[41] !== contentClass || $[42] !== editable || $[43] !== editor || $[44] !== id || $[45] !== invalid || $[46] !== required) {
189
+ t25 = () => {
190
+ editor?.setOptions({ editorProps: { attributes: getContentAttributes(contentClass, accessibleName, invalid, required, editable, id) } });
191
+ };
192
+ t26 = [
193
+ editor,
194
+ contentClass,
195
+ accessibleName,
196
+ invalid,
197
+ required,
198
+ editable,
199
+ id
200
+ ];
201
+ $[40] = accessibleName;
202
+ $[41] = contentClass;
203
+ $[42] = editable;
204
+ $[43] = editor;
205
+ $[44] = id;
206
+ $[45] = invalid;
207
+ $[46] = required;
208
+ $[47] = t25;
209
+ $[48] = t26;
210
+ } else {
211
+ t25 = $[47];
212
+ t26 = $[48];
213
+ }
214
+ useEffect(t25, t26);
215
+ let t27;
216
+ if ($[49] !== className) {
217
+ t27 = [RichTextField_module_default.field, className].filter(Boolean);
218
+ $[49] = className;
219
+ $[50] = t27;
220
+ } else t27 = $[50];
221
+ const t28 = t27.join(" ");
222
+ const t29 = invalid ? true : void 0;
223
+ const t30 = disabled ? true : void 0;
224
+ const t31 = readOnly ? true : void 0;
225
+ let t32;
226
+ if ($[51] !== blockStyles || $[52] !== buttons || $[53] !== editable || $[54] !== editor || $[55] !== headings || $[56] !== newTab || $[57] !== toolbar) {
227
+ t32 = editor !== null && editable ? /* @__PURE__ */ jsx(Toolbar, {
228
+ editor,
229
+ items: toolbar,
230
+ headings,
231
+ styles: blockStyles,
232
+ newTab,
233
+ buttons
234
+ }) : null;
235
+ $[51] = blockStyles;
236
+ $[52] = buttons;
237
+ $[53] = editable;
238
+ $[54] = editor;
239
+ $[55] = headings;
240
+ $[56] = newTab;
241
+ $[57] = toolbar;
242
+ $[58] = t32;
243
+ } else t32 = $[58];
244
+ let t33;
245
+ if ($[59] !== editor) {
246
+ t33 = /* @__PURE__ */ jsx(EditorContent, { editor });
247
+ $[59] = editor;
248
+ $[60] = t33;
249
+ } else t33 = $[60];
250
+ let t34;
251
+ if ($[61] !== t29 || $[62] !== t30 || $[63] !== t31 || $[64] !== t32 || $[65] !== t33) {
252
+ t34 = /* @__PURE__ */ jsxs("div", {
253
+ className: RichTextField_module_default.editor,
254
+ "data-invalid": t29,
255
+ "data-disabled": t30,
256
+ "data-readonly": t31,
257
+ children: [t32, t33]
258
+ });
259
+ $[61] = t29;
260
+ $[62] = t30;
261
+ $[63] = t31;
262
+ $[64] = t32;
263
+ $[65] = t33;
264
+ $[66] = t34;
265
+ } else t34 = $[66];
266
+ let t35;
267
+ if ($[67] !== name || $[68] !== value) {
268
+ t35 = name !== void 0 ? /* @__PURE__ */ jsx("input", {
269
+ type: "hidden",
270
+ name,
271
+ value: value ?? ""
272
+ }) : null;
273
+ $[67] = name;
274
+ $[68] = value;
275
+ $[69] = t35;
276
+ } else t35 = $[69];
277
+ let t36;
278
+ if ($[70] !== description || $[71] !== disabled || $[72] !== errors || $[73] !== label || $[74] !== required || $[75] !== t28 || $[76] !== t34 || $[77] !== t35) {
279
+ t36 = /* @__PURE__ */ jsxs(Fieldset, {
280
+ legend: label,
281
+ description,
282
+ errors,
283
+ isRequired: required,
284
+ isDisabled: disabled,
285
+ className: t28,
286
+ children: [t34, t35]
287
+ });
288
+ $[70] = description;
289
+ $[71] = disabled;
290
+ $[72] = errors;
291
+ $[73] = label;
292
+ $[74] = required;
293
+ $[75] = t28;
294
+ $[76] = t34;
295
+ $[77] = t35;
296
+ $[78] = t36;
297
+ } else t36 = $[78];
298
+ return t36;
299
+ }
300
+ /**
301
+ * The `richtext` type: its toolbar, heading levels, block styles and links from `settings`
302
+ * (`RichTextSettings`), and the extensions and buttons of the editor plugin.
303
+ */
304
+ function RichTextFieldEntry(props) {
305
+ const $ = c(18);
306
+ let t0;
307
+ if ($[0] !== props.field) {
308
+ t0 = getRichTextOptions(props.field);
309
+ $[0] = props.field;
310
+ $[1] = t0;
311
+ } else t0 = $[1];
312
+ const options = t0;
313
+ let t1;
314
+ if ($[2] !== props) {
315
+ t1 = getFieldProps(props);
316
+ $[2] = props;
317
+ $[3] = t1;
318
+ } else t1 = $[3];
319
+ const t2 = typeof props.value === "string" ? props.value : null;
320
+ let t3;
321
+ if ($[4] !== props.extensions) {
322
+ t3 = props.extensions !== void 0 ? { extensions: props.extensions } : {};
323
+ $[4] = props.extensions;
324
+ $[5] = t3;
325
+ } else t3 = $[5];
326
+ let t4;
327
+ if ($[6] !== props.buttons) {
328
+ t4 = props.buttons !== void 0 ? { buttons: props.buttons } : {};
329
+ $[6] = props.buttons;
330
+ $[7] = t4;
331
+ } else t4 = $[7];
332
+ let t5;
333
+ if ($[8] !== options.headings || $[9] !== options.newTab || $[10] !== options.styles || $[11] !== options.toolbar || $[12] !== props.onChange || $[13] !== t1 || $[14] !== t2 || $[15] !== t3 || $[16] !== t4) {
334
+ t5 = /* @__PURE__ */ jsx(RichTextField, {
335
+ ...t1,
336
+ value: t2,
337
+ onChange: props.onChange,
338
+ toolbar: options.toolbar,
339
+ headings: options.headings,
340
+ styles: options.styles,
341
+ newTab: options.newTab,
342
+ ...t3,
343
+ ...t4
344
+ });
345
+ $[8] = options.headings;
346
+ $[9] = options.newTab;
347
+ $[10] = options.styles;
348
+ $[11] = options.toolbar;
349
+ $[12] = props.onChange;
350
+ $[13] = t1;
351
+ $[14] = t2;
352
+ $[15] = t3;
353
+ $[16] = t4;
354
+ $[17] = t5;
355
+ } else t5 = $[17];
356
+ return t5;
357
+ }
358
+ //#endregion
359
+ export { RichTextField, RichTextFieldEntry };
360
+
361
+ //# sourceMappingURL=RichTextField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RichTextField.js","names":["AnyExtension","EditorContent","useEditor","useEffect","useRef","FieldEntryProps","FieldProps","getFieldProps","editorMessages","messages","RichTextStyle","Fieldset","usePanneauIntl","styles","Toolbar","RichTextButton","createRichTextExtensions","parseRichText","serializeRichText","DEFAULT_HEADINGS","DEFAULT_TOOLBAR","NewTabLinks","getRichTextOptions","RichTextFieldProps","placeholder","toolbar","headings","newTab","extensions","buttons","contentClassName","getContentAttributes","className","accessibleName","invalid","required","editable","id","Record","role","class","undefined","NO_EXTENSIONS","NO_BUTTONS","NO_STYLES","NO_ERRORS","RichTextField","t0","$","_c","value","onChange","onBlur","t1","t2","t3","t4","t5","t6","label","description","errors","t7","disabled","t8","readOnly","t9","t10","name","autoFocus","ariaLabel","blockStyles","projectExtensions","intl","t11","html","formatMessage","current","length","t12","content","filter","Boolean","contentClass","join","t13","t14","t15","attributes","t16","t17","editor","created","options","schema","toJSON","t18","updated","state","doc","t19","autofocus","immediatelyRender","shouldRerenderOnTransaction","editorProps","onBeforeCreate","onUpdate","t20","t21","t22","commands","setContent","emitUpdate","t23","t24","setEditable","t25","t26","setOptions","t27","field","t28","t29","t30","t31","t32","t33","t34","t35","t36","RichTextFieldEntry","props","_c","messages","styles"],"sources":["../src/RichTextField.tsx"],"sourcesContent":["import type { AnyExtension } from '@tiptap/core';\nimport { EditorContent, useEditor } from '@tiptap/react';\nimport { useEffect, useRef } from 'react';\n\nimport { type FieldEntryProps, type FieldProps, getFieldProps } from '@panneau/fields';\nimport { editorMessages as messages } from '@panneau/intl';\nimport type { RichTextStyle } from '@panneau/protocol';\nimport { Fieldset, usePanneauIntl } from '@panneau/ui';\n\nimport styles from './RichTextField.module.css';\nimport { Toolbar } from './Toolbar';\nimport type { RichTextButton } from './buttons';\nimport { createRichTextExtensions } from './extensions/index';\nimport { parseRichText, serializeRichText } from './html';\nimport {\n DEFAULT_HEADINGS,\n DEFAULT_TOOLBAR,\n type NewTabLinks,\n getRichTextOptions,\n} from './settings';\n\nexport interface RichTextFieldProps extends FieldProps<string> {\n placeholder?: string;\n /**\n * The toolbar, in order: `heading`, `style`, `bold`, `italic`, `underline`, `strike`,\n * `superscript`, `subscript`, `code`, `link`, `bulletList`, `orderedList`, `blockquote`,\n * `horizontalRule`, `clear`, `undo`, `redo`, names of `buttons`, and `|` between groups.\n */\n toolbar?: readonly string[];\n /** The heading levels the toolbar offers. Defaults to 2, 3 and 4. */\n headings?: readonly number[];\n /** Block styles: a class on a paragraph, a heading, a quote or a list. */\n styles?: readonly RichTextStyle[];\n /** Which links open in a new tab: as the user chooses (the default), external ones, or none. */\n newTab?: NewTabLinks;\n /**\n * TipTap extensions of the project: custom nodes such as an inline logo. One with the name of\n * a built-in extension replaces it. The editor is made again when they change.\n */\n extensions?: readonly AnyExtension[];\n /** Toolbar buttons of the project, that `toolbar` names. */\n buttons?: readonly RichTextButton[];\n contentClassName?: string;\n}\n\n/** The attributes of the editable element: a labelled, multiline `textbox`. */\nfunction getContentAttributes(\n className: string,\n accessibleName: string | undefined,\n invalid: boolean,\n required: boolean,\n editable: boolean,\n id: string | undefined,\n): Record<string, string> {\n return {\n role: 'textbox',\n 'aria-multiline': 'true',\n class: className,\n ...(accessibleName !== undefined ? { 'aria-label': accessibleName } : {}),\n ...(invalid ? { 'aria-invalid': 'true' } : {}),\n ...(required ? { 'aria-required': 'true' } : {}),\n ...(!editable ? { 'aria-readonly': 'true' } : {}),\n ...(id !== undefined ? { id } : {}),\n };\n}\n\nconst NO_EXTENSIONS: readonly AnyExtension[] = [];\nconst NO_BUTTONS: readonly RichTextButton[] = [];\nconst NO_STYLES: readonly RichTextStyle[] = [];\nconst NO_ERRORS: readonly string[] = [];\n\n/**\n * Rich text, stored as HTML (decision 0007): an empty text is `null`. Content keeps what the\n * toolbar doesn't offer (elements, attributes, embeds), and HTML written by another editor stays\n * as it was until the text is edited.\n */\nexport function RichTextField({\n value,\n onChange,\n onBlur,\n placeholder,\n toolbar = DEFAULT_TOOLBAR,\n headings = DEFAULT_HEADINGS,\n styles: blockStyles = NO_STYLES,\n newTab = 'choose',\n extensions: projectExtensions = NO_EXTENSIONS,\n buttons = NO_BUTTONS,\n label,\n description,\n errors = NO_ERRORS,\n disabled = false,\n readOnly = false,\n required = false,\n name,\n id,\n autoFocus,\n 'aria-label': ariaLabel,\n className,\n contentClassName,\n}: RichTextFieldProps) {\n const intl = usePanneauIntl();\n const editable = !disabled && !readOnly;\n const extensions = createRichTextExtensions({\n extensions: projectExtensions,\n ...(placeholder !== undefined ? { placeholder } : {}),\n html: { label: intl.formatMessage(messages.html), className: styles.html ?? '' },\n });\n // The HTML of the editor's content: the value it was loaded from, or the last one it gave\n const current = useRef<string | null | undefined>(value);\n const accessibleName = ariaLabel ?? (typeof label === 'string' ? label : undefined);\n const invalid = errors.length > 0;\n const contentClass = [styles.content, contentClassName].filter(Boolean).join(' ');\n\n const editor = useEditor(\n {\n extensions,\n editable,\n autofocus: autoFocus === true ? 'end' : false,\n immediatelyRender: true,\n shouldRerenderOnTransaction: false,\n editorProps: {\n attributes: getContentAttributes(\n contentClass,\n accessibleName,\n invalid,\n required,\n editable,\n id,\n ),\n },\n // The value is read once the schema exists, and only when the editor is made\n onBeforeCreate: ({ editor: created }) => {\n current.current = value;\n created.options.content = parseRichText(value ?? null, created.schema).toJSON();\n },\n onUpdate: ({ editor: updated }) => {\n const html = serializeRichText(updated.state.doc, updated.schema);\n current.current = html;\n onChange?.(html);\n },\n onBlur: () => onBlur?.(),\n },\n // The schema only changes with the extensions of the project, and the placeholder\n [projectExtensions, placeholder],\n );\n\n // A value that comes from elsewhere (a reset, another user) replaces the content\n useEffect(() => {\n if (editor === null || value === current.current) {\n return;\n }\n current.current = value;\n editor.commands.setContent(parseRichText(value ?? null, editor.schema).toJSON(), {\n emitUpdate: false,\n });\n }, [editor, value]);\n\n useEffect(() => {\n editor?.setEditable(editable, false);\n }, [editor, editable]);\n\n useEffect(() => {\n editor?.setOptions({\n editorProps: {\n attributes: getContentAttributes(\n contentClass,\n accessibleName,\n invalid,\n required,\n editable,\n id,\n ),\n },\n });\n }, [editor, contentClass, accessibleName, invalid, required, editable, id]);\n\n return (\n <Fieldset\n legend={label}\n description={description}\n errors={errors}\n isRequired={required}\n isDisabled={disabled}\n className={[styles.field, className].filter(Boolean).join(' ')}\n >\n <div\n className={styles.editor}\n data-invalid={invalid ? true : undefined}\n data-disabled={disabled ? true : undefined}\n data-readonly={readOnly ? true : undefined}\n >\n {editor !== null && editable ? (\n <Toolbar\n editor={editor}\n items={toolbar}\n headings={headings}\n styles={blockStyles}\n newTab={newTab}\n buttons={buttons}\n />\n ) : null}\n <EditorContent editor={editor} />\n </div>\n {name !== undefined ? <input type=\"hidden\" name={name} value={value ?? ''} /> : null}\n </Fieldset>\n );\n}\n\n/**\n * The `richtext` type: its toolbar, heading levels, block styles and links from `settings`\n * (`RichTextSettings`), and the extensions and buttons of the editor plugin.\n */\nexport function RichTextFieldEntry(\n props: FieldEntryProps & {\n extensions?: readonly AnyExtension[];\n buttons?: readonly RichTextButton[];\n },\n) {\n const options = getRichTextOptions(props.field);\n return (\n <RichTextField\n {...getFieldProps(props)}\n value={typeof props.value === 'string' ? props.value : null}\n onChange={props.onChange}\n toolbar={options.toolbar}\n headings={options.headings}\n styles={options.styles}\n newTab={options.newTab}\n {...(props.extensions !== undefined ? { extensions: props.extensions } : {})}\n {...(props.buttons !== undefined ? { buttons: props.buttons } : {})}\n />\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import "./RichTextField.css";
2
+ //#region src/RichTextField.module.css
3
+ var field = "panneau-rich-text-field-field";
4
+ var editor = "panneau-rich-text-field-editor";
5
+ var content = "panneau-rich-text-field-content";
6
+ var toolbar = "panneau-rich-text-field-toolbar";
7
+ var separator = "panneau-rich-text-field-separator";
8
+ var button = "panneau-rich-text-field-button";
9
+ var select = "panneau-rich-text-field-select";
10
+ var html = "panneau-rich-text-field-html";
11
+ var linkForm = "panneau-rich-text-field-link-form";
12
+ var removeLink = "panneau-rich-text-field-remove-link";
13
+ var RichTextField_module_default = {
14
+ field,
15
+ editor,
16
+ content,
17
+ toolbar,
18
+ separator,
19
+ button,
20
+ select,
21
+ html,
22
+ linkForm,
23
+ removeLink
24
+ };
25
+ //#endregion
26
+ export { button, content, RichTextField_module_default as default, editor, field, html, linkForm, removeLink, select, separator, toolbar };
27
+
28
+ //# sourceMappingURL=RichTextField.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RichTextField.module.js","names":[],"sources":["../src/RichTextField.module.css"],"sourcesContent":[".field {\n min-width: 0;\n}\n\n/* The box of the field, as the other controls draw it: the toolbar over the text. */\n.editor {\n min-width: 0;\n color: var(--panneau-color-text);\n background-color: var(--panneau-input-bg, var(--panneau-color-surface));\n border: var(--panneau-input-border-width, var(--panneau-border-width)) solid\n var(--panneau-input-border-color, var(--panneau-color-border-control));\n border-radius: var(--panneau-input-radius, var(--panneau-radius-md));\n transition:\n border-color var(--panneau-duration),\n box-shadow var(--panneau-duration);\n}\n\n.editor:hover {\n border-color: var(--panneau-input-border-color-hover, var(--panneau-color-text-muted));\n}\n\n.editor:has(.content:focus) {\n border-color: var(--panneau-color-focus);\n box-shadow: 0 0 0 1px var(--panneau-color-focus);\n}\n\n.editor[data-invalid] {\n border-color: var(--panneau-color-danger);\n}\n\n.editor[data-invalid]:has(.content:focus) {\n box-shadow: 0 0 0 1px var(--panneau-color-danger);\n}\n\n.editor[data-disabled] {\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.editor[data-disabled],\n.editor[data-readonly] {\n background-color: var(--panneau-color-surface-sunken);\n}\n\n.toolbar {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--panneau-space-1);\n padding: var(--panneau-space-1);\n background-color: inherit;\n border-bottom: var(--panneau-border-width) solid var(--panneau-color-border);\n border-radius: inherit;\n border-end-start-radius: 0;\n border-end-end-radius: 0;\n}\n\n.separator {\n align-self: stretch;\n width: var(--panneau-border-width);\n margin: var(--panneau-space-1) var(--panneau-space-1);\n background-color: var(--panneau-color-border);\n border: 0;\n}\n\n.button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--panneau-control-height-sm);\n height: var(--panneau-control-height-sm);\n padding: 0;\n color: var(--panneau-color-text);\n cursor: pointer;\n background-color: transparent;\n border: 0;\n border-radius: var(--panneau-radius-sm);\n transition: background-color var(--panneau-duration);\n}\n\n.button[data-hovered] {\n background-color: color-mix(in srgb, var(--panneau-color-text) 6%, transparent);\n}\n\n.button[data-pressed],\n.button[data-selected] {\n background-color: color-mix(in srgb, var(--panneau-color-text) 12%, transparent);\n}\n\n.button[data-selected] {\n color: var(--panneau-color-accent-text);\n background-color: var(--panneau-color-accent-subtle);\n}\n\n.button[data-focus-visible] {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n outline-offset: 1px;\n}\n\n.button[data-disabled] {\n cursor: not-allowed;\n opacity: 0.45;\n}\n\n.select {\n min-width: 9rem;\n}\n\n/* The text: the elements of rich content, as `Prose` styles them. */\n.content {\n min-height: 8rem;\n padding: var(--panneau-space-3);\n font-size: var(--panneau-font-size-control);\n line-height: var(--panneau-prose-line-height, 1.6);\n overflow-wrap: break-word;\n white-space: pre-wrap;\n outline: none;\n /* Nothing of the content paints outside of it: transforms, negative margins */\n contain: paint;\n}\n\n/*\n * Styles of stored content show in the editor (a color, an alignment), but never take an element\n * out of the text to cover the admin: they are kept as they are in the value.\n */\n.content :where([style]) {\n position: static !important;\n}\n\n.content > * + * {\n margin-top: var(--panneau-prose-gap, var(--panneau-space-3));\n}\n\n.content :where(h1, h2, h3, h4, h5, h6) {\n font-family: var(--panneau-heading-font-family, var(--panneau-font-family-heading));\n font-weight: var(--panneau-font-weight-bold);\n line-height: var(--panneau-line-height-tight);\n}\n\n.content :where(h1) {\n font-size: var(--panneau-heading-1-font-size, 1.75rem);\n}\n\n.content :where(h2) {\n font-size: var(--panneau-heading-2-font-size, 1.375rem);\n}\n\n.content :where(h3) {\n font-size: var(--panneau-heading-3-font-size, 1.125rem);\n}\n\n.content :where(h4, h5, h6) {\n font-size: var(--panneau-heading-4-font-size, var(--panneau-font-size-lg));\n}\n\n.content :where(ul, ol) {\n padding-inline-start: var(--panneau-prose-list-indent, 1.5em);\n}\n\n.content :where(ul) {\n list-style: disc;\n}\n\n.content :where(ol) {\n list-style: decimal;\n}\n\n.content :where(li + li, li > ul, li > ol) {\n margin-top: var(--panneau-space-1);\n}\n\n.content :where(a) {\n color: var(--panneau-prose-link-color, var(--panneau-color-link));\n text-decoration: underline;\n}\n\n.content :where(strong, b) {\n font-weight: var(--panneau-font-weight-bold);\n}\n\n.content :where(em, i) {\n font-style: italic;\n}\n\n.content :where(blockquote) {\n padding-inline-start: var(--panneau-space-4);\n color: var(--panneau-color-text-muted);\n border-inline-start: 3px solid var(--panneau-color-border);\n}\n\n.content :where(code) {\n font-family: var(--panneau-font-family-mono);\n font-size: 0.875em;\n}\n\n.content :where(hr) {\n border: 0;\n border-top: var(--panneau-border-width) solid var(--panneau-color-border);\n}\n\n.content :global(.ProseMirror-selectednode) {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n}\n\n.content :global(.is-editor-empty:first-child)::before {\n float: inline-start;\n height: 0;\n color: var(--panneau-color-text-muted);\n pointer-events: none;\n content: attr(data-placeholder);\n}\n\n/* HTML kept as it was written: its element and what it points to, never its markup. */\n.html {\n display: flex;\n gap: var(--panneau-space-2);\n align-items: baseline;\n min-width: 0;\n padding: var(--panneau-space-2) var(--panneau-space-3);\n font-size: var(--panneau-font-size-sm);\n color: var(--panneau-color-text-muted);\n white-space: nowrap;\n background-color: var(--panneau-color-surface-sunken);\n border: var(--panneau-border-width) dashed var(--panneau-color-border);\n border-radius: var(--panneau-radius-sm);\n}\n\nspan.html {\n display: inline-flex;\n max-width: 100%;\n padding: 0 var(--panneau-space-1);\n vertical-align: baseline;\n}\n\n.html > code {\n flex: 0 0 auto;\n font-family: var(--panneau-font-family-mono);\n color: var(--panneau-color-text);\n}\n\n.html > span {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.linkForm {\n display: grid;\n gap: var(--panneau-space-3);\n}\n\n.removeLink {\n margin-inline-end: auto;\n}\n"],"mappings":""}
@@ -0,0 +1,20 @@
1
+ import type { Editor } from '@tiptap/core';
2
+ import type { RichTextStyle } from '@panneau/protocol';
3
+ import { type RichTextButton } from './buttons.js';
4
+ import type { NewTabLinks } from './settings.js';
5
+ export interface ToolbarProps {
6
+ editor: Editor;
7
+ /** The items, in order: built-in names, names of `buttons`, and `|` between groups. */
8
+ items: readonly string[];
9
+ headings: readonly number[];
10
+ styles: readonly RichTextStyle[];
11
+ newTab: NewTabLinks;
12
+ /** Buttons of plugins. One with the name of a built-in button replaces it. */
13
+ buttons: readonly RichTextButton[];
14
+ }
15
+ /**
16
+ * The toolbar of the rich text field: the text style (paragraph or a heading level), the block
17
+ * styles, marks, links, lists and the buttons of plugins, as the field's `toolbar` lists them.
18
+ */
19
+ export declare function Toolbar({ editor, items, headings, styles: blockStyles, newTab, buttons, }: ToolbarProps): import("react").JSX.Element;
20
+ //# sourceMappingURL=Toolbar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../src/Toolbar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAY3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAKvD,OAAO,EAAE,KAAK,cAAc,EAAkB,MAAM,WAAW,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C,MAAM,WAAW,YAAY;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IACjC,MAAM,EAAE,WAAW,CAAC;IACpB,8EAA8E;IAC9E,OAAO,EAAE,SAAS,cAAc,EAAE,CAAC;CACtC;AAqED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,EACpB,MAAM,EACN,KAAK,EACL,QAAQ,EACR,MAAM,EAAE,WAAW,EACnB,MAAM,EACN,OAAO,GACV,EAAE,YAAY,+BA+Kd"}