@upstart.gg/vite-plugins 0.1.69 → 0.1.70

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 (28) hide show
  1. package/dist/vite-plugin-upstart-editor/runtime/array-controls.js +7 -7
  2. package/dist/vite-plugin-upstart-editor/runtime/array-controls.js.map +1 -1
  3. package/dist/vite-plugin-upstart-editor/runtime/error-handler.d.ts.map +1 -1
  4. package/dist/vite-plugin-upstart-editor/runtime/error-handler.js +4 -3
  5. package/dist/vite-plugin-upstart-editor/runtime/error-handler.js.map +1 -1
  6. package/dist/vite-plugin-upstart-editor/runtime/form-guard.js +2 -2
  7. package/dist/vite-plugin-upstart-editor/runtime/form-guard.js.map +1 -1
  8. package/dist/vite-plugin-upstart-editor/runtime/index.d.ts.map +1 -1
  9. package/dist/vite-plugin-upstart-editor/runtime/index.js +2 -1
  10. package/dist/vite-plugin-upstart-editor/runtime/index.js.map +1 -1
  11. package/dist/vite-plugin-upstart-editor/runtime/labels.d.ts +32 -0
  12. package/dist/vite-plugin-upstart-editor/runtime/labels.d.ts.map +1 -0
  13. package/dist/vite-plugin-upstart-editor/runtime/labels.js +45 -0
  14. package/dist/vite-plugin-upstart-editor/runtime/labels.js.map +1 -0
  15. package/dist/vite-plugin-upstart-editor/runtime/text-editor.d.ts.map +1 -1
  16. package/dist/vite-plugin-upstart-editor/runtime/text-editor.js +20 -14
  17. package/dist/vite-plugin-upstart-editor/runtime/text-editor.js.map +1 -1
  18. package/dist/vite-plugin-upstart-editor/runtime/types.d.ts +5 -1
  19. package/dist/vite-plugin-upstart-editor/runtime/types.d.ts.map +1 -1
  20. package/package.json +3 -3
  21. package/src/tests/editor-labels.test.ts +40 -0
  22. package/src/vite-plugin-upstart-editor/runtime/array-controls.ts +7 -7
  23. package/src/vite-plugin-upstart-editor/runtime/error-handler.ts +4 -3
  24. package/src/vite-plugin-upstart-editor/runtime/form-guard.ts +3 -2
  25. package/src/vite-plugin-upstart-editor/runtime/index.ts +3 -0
  26. package/src/vite-plugin-upstart-editor/runtime/labels.ts +77 -0
  27. package/src/vite-plugin-upstart-editor/runtime/text-editor.ts +25 -15
  28. package/src/vite-plugin-upstart-editor/runtime/types.ts +6 -1
@@ -0,0 +1,77 @@
1
+ /**
2
+ * User-facing labels of the editor runtime. The runtime runs inside the previewed site,
3
+ * which has no access to the dashboard's i18n catalogs: the editor sends the translated
4
+ * labels through a `set-labels` message once the runtime is ready, and everything the
5
+ * runtime renders reads them lazily via {@link getLabels}. English is the fallback.
6
+ */
7
+ export interface RuntimeLabels {
8
+ newItem: string;
9
+ keepItem: string;
10
+ removeItem: string;
11
+ addItem: string;
12
+ applyChanges: string;
13
+ dragToReorder: string;
14
+ clickToEdit: string;
15
+ startTyping: string;
16
+ recoveryTitle: string;
17
+ recoveryText: string;
18
+ refresh: string;
19
+ formGuard: string;
20
+ bold: string;
21
+ italic: string;
22
+ strikethrough: string;
23
+ inlineCode: string;
24
+ heading: string;
25
+ blockquote: string;
26
+ bulletList: string;
27
+ orderedList: string;
28
+ }
29
+
30
+ export const DEFAULT_LABELS: Readonly<RuntimeLabels> = Object.freeze({
31
+ newItem: "New item",
32
+ keepItem: "Keep item",
33
+ removeItem: "Remove item",
34
+ addItem: "Add item",
35
+ applyChanges: "Apply changes",
36
+ dragToReorder: "Drag to reorder",
37
+ clickToEdit: "Click to edit...",
38
+ startTyping: "Start typing...",
39
+ recoveryTitle: "The preview needs a refresh",
40
+ recoveryText: "Your changes are saved. Refresh the preview to keep editing.",
41
+ refresh: "Refresh",
42
+ formGuard: "This action isn’t available in the editor preview",
43
+ bold: "Bold",
44
+ italic: "Italic",
45
+ strikethrough: "Strikethrough",
46
+ inlineCode: "Inline Code",
47
+ heading: "Heading",
48
+ blockquote: "Blockquote",
49
+ bulletList: "Bullet List",
50
+ orderedList: "Ordered List",
51
+ });
52
+
53
+ let labels: RuntimeLabels = { ...DEFAULT_LABELS };
54
+
55
+ /** Current labels (translated once the editor sent them, English before that). */
56
+ export function getLabels(): Readonly<RuntimeLabels> {
57
+ return labels;
58
+ }
59
+
60
+ /**
61
+ * Override labels with the ones received from the editor. Unknown keys and non-string
62
+ * values are ignored so a malformed message can never blank a control.
63
+ */
64
+ export function setLabels(input: unknown): void {
65
+ if (typeof input !== "object" || input === null) return;
66
+ const next: RuntimeLabels = { ...labels };
67
+ for (const key of Object.keys(DEFAULT_LABELS) as (keyof RuntimeLabels)[]) {
68
+ const value = (input as Record<string, unknown>)[key];
69
+ if (typeof value === "string" && value.length > 0) next[key] = value;
70
+ }
71
+ labels = next;
72
+ }
73
+
74
+ /** Back to the English defaults (used by tests). */
75
+ export function resetLabels(): void {
76
+ labels = { ...DEFAULT_LABELS };
77
+ }
@@ -4,6 +4,7 @@ import Placeholder from "@tiptap/extension-placeholder";
4
4
  import StarterKit from "@tiptap/starter-kit";
5
5
  import { sendToParent } from "./utils.js";
6
6
  import type { EditorInstance, TextEditorMode, UpstartEditorOptions } from "./types.js";
7
+ import { getLabels, type RuntimeLabels } from "./labels.js";
7
8
 
8
9
  /**
9
10
  * Custom Document node for inline elements (e.g. <a>, <span>, headings).
@@ -247,6 +248,11 @@ const styleCache = new WeakMap<
247
248
  { outline: string; outlineOffset: string; cursor: string; transition: string }
248
249
  >();
249
250
  let resolvedOptions: Required<UpstartEditorOptions> = DEFAULT_OPTIONS;
251
+
252
+ /** The site may override the placeholder; the default one follows the editor's language. */
253
+ function placeholderFor(options: Required<UpstartEditorOptions>): string {
254
+ return options.placeholder === DEFAULT_OPTIONS.placeholder ? getLabels().startTyping : options.placeholder;
255
+ }
250
256
  let shortcutsRegistered = false;
251
257
  let domObserver: MutationObserver | null = null;
252
258
  let reactivateTimer: number | null = null;
@@ -443,7 +449,7 @@ function createPlainTextEditor(element: HTMLElement, options: Required<UpstartEd
443
449
  horizontalRule: false,
444
450
  }),
445
451
  Placeholder.configure({
446
- placeholder: "Click to edit...",
452
+ placeholder: getLabels().clickToEdit,
447
453
  }),
448
454
  ],
449
455
  content,
@@ -476,7 +482,7 @@ function createRichTextEditor(element: HTMLElement, options: Required<UpstartEdi
476
482
  const extensions: Extension[] = [
477
483
  StarterKit,
478
484
  Placeholder.configure({
479
- placeholder: options.placeholder,
485
+ placeholder: placeholderFor(options),
480
486
  }),
481
487
  ];
482
488
 
@@ -536,7 +542,7 @@ function createInlineRichTextEditor(element: HTMLElement, options: Required<Upst
536
542
  horizontalRule: false,
537
543
  }),
538
544
  Placeholder.configure({
539
- placeholder: "Click to edit...",
545
+ placeholder: getLabels().clickToEdit,
540
546
  }),
541
547
  ];
542
548
 
@@ -593,7 +599,7 @@ function createDirectEditor(element: HTMLElement, options: Required<UpstartEdito
593
599
  codeBlock: false,
594
600
  horizontalRule: false,
595
601
  }),
596
- Placeholder.configure({ placeholder: "Click to edit..." }),
602
+ Placeholder.configure({ placeholder: getLabels().clickToEdit }),
597
603
  ];
598
604
 
599
605
  if (options.bubbleMenu) {
@@ -629,7 +635,10 @@ function createRichPanelEditor(element: HTMLElement, options: Required<UpstartEd
629
635
  let hasChanged = false;
630
636
 
631
637
  const bubbleMenuElement = createBubbleMenuElement("inline");
632
- const extensions: Extension[] = [StarterKit, Placeholder.configure({ placeholder: options.placeholder })];
638
+ const extensions: Extension[] = [
639
+ StarterKit,
640
+ Placeholder.configure({ placeholder: placeholderFor(options) }),
641
+ ];
633
642
 
634
643
  if (options.bubbleMenu) {
635
644
  extensions.push(BubbleMenu.configure({ element: bubbleMenuElement }));
@@ -958,20 +967,20 @@ function restoreStyles(element: HTMLElement): void {
958
967
  element.style.transition = cached.transition;
959
968
  }
960
969
 
961
- const BUBBLE_MENU_GROUPS: { command: string; icon: string; title: string }[][] = [
970
+ const BUBBLE_MENU_GROUPS: { command: string; icon: string; label: keyof RuntimeLabels }[][] = [
962
971
  [
963
- { command: "bold", icon: "format-bold", title: "Bold" },
964
- { command: "italic", icon: "format-italic", title: "Italic" },
965
- { command: "strike", icon: "format-strikethrough", title: "Strikethrough" },
966
- { command: "code", icon: "code-tags", title: "Inline Code" },
972
+ { command: "bold", icon: "format-bold", label: "bold" },
973
+ { command: "italic", icon: "format-italic", label: "italic" },
974
+ { command: "strike", icon: "format-strikethrough", label: "strikethrough" },
975
+ { command: "code", icon: "code-tags", label: "inlineCode" },
967
976
  ],
968
977
  [
969
- { command: "heading", icon: "format-header-1", title: "Heading" },
970
- { command: "blockquote", icon: "format-quote-close", title: "Blockquote" },
978
+ { command: "heading", icon: "format-header-1", label: "heading" },
979
+ { command: "blockquote", icon: "format-quote-close", label: "blockquote" },
971
980
  ],
972
981
  [
973
- { command: "bulletList", icon: "format-list-bulleted", title: "Bullet List" },
974
- { command: "orderedList", icon: "format-list-numbered", title: "Ordered List" },
982
+ { command: "bulletList", icon: "format-list-bulleted", label: "bulletList" },
983
+ { command: "orderedList", icon: "format-list-numbered", label: "orderedList" },
975
984
  ],
976
985
  ];
977
986
 
@@ -996,7 +1005,8 @@ function createBubbleMenuElement(mode: "block" | "inline" = "block"): HTMLDivEle
996
1005
  menu.appendChild(separator);
997
1006
  }
998
1007
 
999
- for (const { command, icon, title } of group) {
1008
+ for (const { command, icon, label } of group) {
1009
+ const title = getLabels()[label];
1000
1010
  const button = document.createElement("button");
1001
1011
  button.type = "button";
1002
1012
  button.dataset.command = command;
@@ -6,6 +6,9 @@ import type {
6
6
  PayloadArrayItemDelete,
7
7
  PayloadArraySet,
8
8
  } from "~/upstart-editor-api";
9
+ import type { RuntimeLabels } from "./labels.js";
10
+
11
+ export type { RuntimeLabels } from "./labels.js";
9
12
 
10
13
  /**
11
14
  * Editor mode
@@ -146,7 +149,9 @@ export type ParentMessage =
146
149
  | { type: "request-scroll-position" }
147
150
  | { type: "restore-scroll-position"; x: number; y: number }
148
151
  | { type: "clear-selection" }
149
- | { type: "deselect"; key: string };
152
+ | { type: "deselect"; key: string }
153
+ /** Translated labels for the controls the runtime renders (see `runtime/labels.ts`). */
154
+ | { type: "set-labels"; labels: Partial<RuntimeLabels> };
150
155
 
151
156
  /**
152
157
  * Message wrapper sent via postMessage from iframe.